summaryrefslogtreecommitdiff
path: root/support/texlab/src/symbol/project_order.rs
diff options
context:
space:
mode:
Diffstat (limited to 'support/texlab/src/symbol/project_order.rs')
-rw-r--r--support/texlab/src/symbol/project_order.rs179
1 files changed, 109 insertions, 70 deletions
diff --git a/support/texlab/src/symbol/project_order.rs b/support/texlab/src/symbol/project_order.rs
index 31b71f36bb..8a2ec5f6d0 100644
--- a/support/texlab/src/symbol/project_order.rs
+++ b/support/texlab/src/symbol/project_order.rs
@@ -1,9 +1,9 @@
-use crate::syntax::*;
-use crate::workspace::*;
-use petgraph::algo::tarjan_scc;
-use petgraph::{Directed, Graph};
-use std::collections::HashSet;
-use std::sync::Arc;
+use crate::{
+ protocol::{Options, Uri},
+ workspace::{Document, DocumentContent, Snapshot},
+};
+use petgraph::{algo::tarjan_scc, Directed, Graph};
+use std::{collections::HashSet, path::Path, sync::Arc, usize};
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct ProjectOrdering {
@@ -11,27 +11,34 @@ pub struct ProjectOrdering {
}
impl ProjectOrdering {
- pub fn new(workspace: &Workspace) -> Self {
+ pub fn get(&self, uri: &Uri) -> usize {
+ self.ordering
+ .iter()
+ .position(|doc| doc.uri == *uri)
+ .unwrap_or(usize::MAX)
+ }
+
+ pub fn analyze(snapshot: &Snapshot, options: &Options, current_dir: &Path) -> Self {
let mut ordering = Vec::new();
- let connected_components = Self::connected_components(workspace);
- for connected_component in connected_components {
- let graph = Self::build_dependency_graph(&connected_component);
+ let comps = Self::connected_components(snapshot, options, current_dir);
+ for comp in comps {
+ let graph = Self::build_dependency_graph(&comp);
let mut visited = HashSet::new();
let root_index = *graph.node_weight(tarjan_scc(&graph)[0][0]).unwrap();
- let mut stack = vec![Arc::clone(&connected_component[root_index])];
+ let mut stack = vec![Arc::clone(&comp[root_index])];
- while let Some(document) = stack.pop() {
- if !visited.insert(document.uri.as_str().to_owned()) {
+ while let Some(doc) = stack.pop() {
+ if !visited.insert(doc.uri.as_str().to_owned()) {
continue;
}
- ordering.push(Arc::clone(&document));
- if let SyntaxTree::Latex(tree) = &document.tree {
+ ordering.push(Arc::clone(&doc));
+ if let DocumentContent::Latex(tree) = &doc.content {
for include in tree.includes.iter().rev() {
for targets in &include.all_targets {
for target in targets {
- if let Some(child) = workspace.find(target) {
+ if let Some(child) = snapshot.find(target) {
stack.push(child);
}
}
@@ -44,36 +51,40 @@ impl ProjectOrdering {
Self { ordering }
}
- fn connected_components(workspace: &Workspace) -> Vec<Vec<Arc<Document>>> {
- let mut components = Vec::new();
+ fn connected_components(
+ snapshot: &Snapshot,
+ options: &Options,
+ current_dir: &Path,
+ ) -> Vec<Vec<Arc<Document>>> {
+ let mut comps = Vec::new();
let mut visited = HashSet::new();
- for root in &workspace.documents {
+ for root in &snapshot.0 {
if !visited.insert(root.uri.clone()) {
continue;
}
- let component = workspace.related_documents(&root.uri);
- for document in &component {
+ let comp = snapshot.relations(&root.uri, options, current_dir);
+ for document in &comp {
visited.insert(document.uri.clone());
}
- components.push(component);
+ comps.push(comp);
}
- components
+ comps
}
- fn build_dependency_graph(documents: &[Arc<Document>]) -> Graph<usize, (), Directed> {
+ fn build_dependency_graph(docs: &[Arc<Document>]) -> Graph<usize, (), Directed> {
let mut graph = Graph::new();
- let nodes: Vec<_> = (0..documents.len()).map(|i| graph.add_node(i)).collect();
+ let nodes: Vec<_> = (0..docs.len()).map(|i| graph.add_node(i)).collect();
- for (i, document) in documents.iter().enumerate() {
- if let SyntaxTree::Latex(tree) = &document.tree {
+ for (i, doc) in docs.iter().enumerate() {
+ if let DocumentContent::Latex(tree) = &doc.content {
for targets in tree
.includes
.iter()
.flat_map(|include| &include.all_targets)
{
for target in targets {
- if let Some(j) = documents.iter().position(|doc| doc.uri == *target) {
+ if let Some(j) = docs.iter().position(|doc| doc.uri == *target) {
graph.add_edge(nodes[j], nodes[i], ());
break;
}
@@ -83,60 +94,88 @@ impl ProjectOrdering {
}
graph
}
-
- pub fn get(&self, uri: &Uri) -> usize {
- self.ordering
- .iter()
- .position(|doc| doc.uri == *uri)
- .unwrap_or(std::usize::MAX)
- }
}
#[cfg(test)]
mod tests {
use super::*;
+ use crate::{
+ tex::{Language, Resolver},
+ workspace::DocumentParams,
+ };
+ use std::env;
+
+ fn create_simple_document(uri: &Uri, language: Language, text: &str) -> Arc<Document> {
+ Arc::new(Document::open(DocumentParams {
+ uri: uri.clone(),
+ text: text.into(),
+ language,
+ resolver: &Resolver::default(),
+ options: &Options::default(),
+ current_dir: &env::current_dir().unwrap(),
+ }))
+ }
#[test]
- fn test_no_cycles() {
- let mut builder = WorkspaceBuilder::new();
- let a = builder.document("a.tex", "");
- let b = builder.document("b.tex", "");
- let c = builder.document("c.tex", "\\include{b}\\include{a}");
-
- let project_ordering = ProjectOrdering::new(&builder.workspace);
-
- assert_eq!(project_ordering.get(&a), 2);
- assert_eq!(project_ordering.get(&b), 1);
- assert_eq!(project_ordering.get(&c), 0);
+ fn no_cycles() {
+ let a = Uri::parse("http://example.com/a.tex").unwrap();
+ let b = Uri::parse("http://example.com/b.tex").unwrap();
+ let c = Uri::parse("http://example.com/c.tex").unwrap();
+ let mut snapshot = Snapshot::new();
+ snapshot.0 = vec![
+ create_simple_document(&a, Language::Latex, ""),
+ create_simple_document(&b, Language::Latex, ""),
+ create_simple_document(&c, Language::Latex, r#"\include{b}\include{a}"#),
+ ];
+
+ let current_dir = env::current_dir().unwrap();
+ let ordering = ProjectOrdering::analyze(&snapshot, &Options::default(), &current_dir);
+
+ assert_eq!(ordering.get(&a), 2);
+ assert_eq!(ordering.get(&b), 1);
+ assert_eq!(ordering.get(&c), 0);
}
#[test]
- fn test_cycles() {
- let mut builder = WorkspaceBuilder::new();
- let a = builder.document("a.tex", "\\include{b}");
- let b = builder.document("b.tex", "\\include{a}");
- let c = builder.document("c.tex", "\\include{a}");
-
- let project_ordering = ProjectOrdering::new(&builder.workspace);
-
- assert_eq!(project_ordering.get(&a), 1);
- assert_eq!(project_ordering.get(&b), 2);
- assert_eq!(project_ordering.get(&c), 0);
+ fn cycles() {
+ let a = Uri::parse("http://example.com/a.tex").unwrap();
+ let b = Uri::parse("http://example.com/b.tex").unwrap();
+ let c = Uri::parse("http://example.com/c.tex").unwrap();
+ let mut snapshot = Snapshot::new();
+ snapshot.0 = vec![
+ create_simple_document(&a, Language::Latex, r#"\include{b}"#),
+ create_simple_document(&b, Language::Latex, r#"\include{a}"#),
+ create_simple_document(&c, Language::Latex, r#"\include{a}"#),
+ ];
+
+ let current_dir = env::current_dir().unwrap();
+ let ordering = ProjectOrdering::analyze(&snapshot, &Options::default(), &current_dir);
+
+ assert_eq!(ordering.get(&a), 1);
+ assert_eq!(ordering.get(&b), 2);
+ assert_eq!(ordering.get(&c), 0);
}
#[test]
- fn test_multiple_roots() {
- let mut builder = WorkspaceBuilder::new();
- let a = builder.document("a.tex", "\\include{b}");
- let b = builder.document("b.tex", "");
- let c = builder.document("c.tex", "");
- let d = builder.document("d.tex", "\\include{c}");
-
- let project_ordering = ProjectOrdering::new(&builder.workspace);
-
- assert_eq!(project_ordering.get(&a), 0);
- assert_eq!(project_ordering.get(&b), 1);
- assert_eq!(project_ordering.get(&d), 2);
- assert_eq!(project_ordering.get(&c), 3);
+ fn multiple_roots() {
+ let a = Uri::parse("http://example.com/a.tex").unwrap();
+ let b = Uri::parse("http://example.com/b.tex").unwrap();
+ let c = Uri::parse("http://example.com/c.tex").unwrap();
+ let d = Uri::parse("http://example.com/d.tex").unwrap();
+ let mut snapshot = Snapshot::new();
+ snapshot.0 = vec![
+ create_simple_document(&a, Language::Latex, r#"\include{b}"#),
+ create_simple_document(&b, Language::Latex, ""),
+ create_simple_document(&c, Language::Latex, ""),
+ create_simple_document(&d, Language::Latex, r#"\include{c}"#),
+ ];
+
+ let current_dir = env::current_dir().unwrap();
+ let ordering = ProjectOrdering::analyze(&snapshot, &Options::default(), &current_dir);
+
+ assert_eq!(ordering.get(&a), 0);
+ assert_eq!(ordering.get(&b), 1);
+ assert_eq!(ordering.get(&d), 2);
+ assert_eq!(ordering.get(&c), 3);
}
}