Skip to content

Commit

Permalink
Add support for imports in workspace detection
Browse files Browse the repository at this point in the history
  • Loading branch information
pfoerster committed Apr 16, 2020
1 parent 44b45dd commit 6facbe3
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 16 deletions.
67 changes: 67 additions & 0 deletions crates/texlab_feature/src/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,16 @@ impl Snapshot {
graph.add_edge(indices_by_uri[&parent.uri], indices_by_uri[&child.uri], ());
});

table
.imports
.iter()
.flat_map(|import| import.targets.iter())
.find_map(|target| self.find(target))
.into_iter()
.for_each(|child| {
graph.add_edge(indices_by_uri[&parent.uri], indices_by_uri[&child.uri], ());
});

self.resolve_aux_targets(&parent.uri, options, current_dir, "aux")
.into_iter()
.flatten()
Expand Down Expand Up @@ -204,6 +214,18 @@ impl Snapshot {
.flatten()
.for_each(|target| unknown_targets.push(target.clone()));

table
.imports
.iter()
.filter(|import| {
import
.targets
.iter()
.all(|target| self.find(target).is_none())
})
.flat_map(|import| import.targets.iter())
.for_each(|target| unknown_targets.push(target.clone()));

self.resolve_aux_targets(&parent.uri, options, current_dir, "aux")
.into_iter()
.filter(|targets| targets.iter().all(|target| self.find(target).is_none()))
Expand Down Expand Up @@ -785,6 +807,27 @@ mod tests {
assert_eq!(actual_uris, vec![uri1, uri2]);
}

#[test]
fn relations_import() {
let uri1 = Uri::parse("http://www.example.com/foo.tex").unwrap();
let uri2 = Uri::parse("http://www.example.com/bar/baz.tex").unwrap();
let uri3 = Uri::parse("http://www.example.com/bar/qux/foo-bar.tex").unwrap();
let mut snapshot = Snapshot::new();
snapshot.0 = vec![
create_simple_document(&uri1, Language::Latex, r#"\import{bar/}{baz.tex}"#),
create_simple_document(&uri2, Language::Latex, r#"\subimport{qux/}{foo-bar}"#),
create_simple_document(&uri3, Language::Latex, r#""#),
];

let actual_uris: Vec<_> = snapshot
.relations(&uri1, &Options::default(), &env::current_dir().unwrap())
.into_iter()
.map(|doc| doc.uri.clone())
.collect();

assert_eq!(actual_uris, vec![uri1, uri2, uri3]);
}

#[test]
fn parent() {
let uri1 = Uri::parse("http://www.example.com/foo.tex").unwrap();
Expand Down Expand Up @@ -894,4 +937,28 @@ mod tests {
vec!["http://www.example.com/bar/baz.tex"]
);
}

#[test]
fn expand_import() {
let uri1 = Uri::parse("http://www.example.com/qux/foo.tex").unwrap();
let uri2 = Uri::parse("http://www.example.com/qux/baz/bar.tex").unwrap();
let mut snapshot = Snapshot::new();
snapshot.0 = vec![
create_simple_document(
&uri1,
Language::Latex,
r#"\import{.}{foo}\import{baz/}{bar}\import{baz/foo-bar/}{qux}"#,
),
create_simple_document(&uri2, Language::Latex, r#""#),
];
let expansion = snapshot.expand(&Options::default(), &env::current_dir().unwrap());
assert_eq!(
expansion
.iter()
.map(|uri| uri.as_str())
.filter(|uri| uri.ends_with(".tex"))
.collect_vec(),
vec!["http://www.example.com/qux/baz/foo-bar/qux.tex"]
)
}
}
67 changes: 51 additions & 16 deletions crates/texlab_syntax/src/latex/analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub struct SymbolTable {
pub environments: Vec<Environment>,
pub is_standalone: bool,
pub includes: Vec<Include>,
pub imports: Vec<Import>,
pub components: Vec<String>,
pub citations: Vec<Citation>,
pub command_definitions: Vec<CommandDefinition>,
Expand Down Expand Up @@ -58,6 +59,7 @@ impl SymbolTable {

let mut environments = None;
let mut includes = None;
let mut imports = None;
let mut citations = None;
let mut command_definitions = None;
let mut glossary_entries = None;
Expand All @@ -74,6 +76,7 @@ impl SymbolTable {
rayon::scope(|s| {
s.spawn(|_| environments = Some(Environment::parse(ctx)));
s.spawn(|_| includes = Some(Include::parse(ctx)));
s.spawn(|_| imports = Some(Import::parse(ctx)));
s.spawn(|_| citations = Some(Citation::parse(ctx)));
s.spawn(|_| command_definitions = Some(CommandDefinition::parse(ctx)));
s.spawn(|_| glossary_entries = Some(GlossaryEntry::parse(ctx)));
Expand Down Expand Up @@ -107,6 +110,7 @@ impl SymbolTable {
environments: environments.unwrap(),
is_standalone,
includes: includes.unwrap(),
imports: imports.unwrap(),
components,
citations: citations.unwrap(),
command_definitions: command_definitions.unwrap(),
Expand Down Expand Up @@ -320,7 +324,7 @@ impl Include {
.extract_comma_separated_words(parent, GroupKind::Group, desc.index)?;
for path in paths {
let mut targets = Vec::new();
let base_url = Self::base_url(ctx)?;
let base_url = base_url(ctx)?;
targets.push(base_url.join(path.text()).ok()?.into());

if let Some(extensions) = desc.kind.extensions() {
Expand All @@ -346,21 +350,6 @@ impl Include {
Some(include)
}

fn base_url(ctx: SymbolContext) -> Option<Uri> {
if let Some(root_directory) = ctx
.options
.latex
.as_ref()
.and_then(|opts| opts.root_directory.as_ref())
{
let file_name = ctx.uri.path_segments()?.last()?;
let path = ctx.current_dir.join(root_directory).join(file_name);
Uri::from_file_path(path).ok()
} else {
Some(ctx.uri.clone())
}
}

fn resolve_distro_file(
ctx: SymbolContext,
desc: &LatexIncludeCommand,
Expand All @@ -379,6 +368,52 @@ impl Include {
}
}

fn base_url(ctx: SymbolContext) -> Option<Uri> {
if let Some(root_directory) = ctx
.options
.latex
.as_ref()
.and_then(|opts| opts.root_directory.as_ref())
{
let file_name = ctx.uri.path_segments()?.last()?;
let path = ctx.current_dir.join(root_directory).join(file_name);
Uri::from_file_path(path).ok()
} else {
Some(ctx.uri.clone())
}
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Import {
pub parent: AstNodeIndex,
pub targets: Vec<Uri>,
}

impl Import {
fn parse(ctx: SymbolContext) -> Vec<Self> {
ctx.commands
.iter()
.filter_map(|parent| Self::parse_single(ctx, *parent))
.collect()
}

fn parse_single(ctx: SymbolContext, parent: AstNodeIndex) -> Option<Self> {
let cmd = ctx.tree.as_command(parent)?;
if cmd.name.text() != "\\import" && cmd.name.text() != "\\subimport" {
return None;
}

let dir = ctx.tree.extract_word(parent, GroupKind::Group, 0)?;
let file = ctx.tree.extract_word(parent, GroupKind::Group, 1)?;

let mut targets = Vec::new();
let base_url = base_url(ctx)?.join(dir.text()).ok()?;
targets.push(base_url.join(file.text()).ok()?.into());
targets.push(base_url.join(&format!("{}.tex", file.text())).ok()?.into());
Some(Self { parent, targets })
}
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct Citation {
parent: AstNodeIndex,
Expand Down

0 comments on commit 6facbe3

Please sign in to comment.