summaryrefslogtreecommitdiff
path: root/support/texlab/src/workspace/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'support/texlab/src/workspace/mod.rs')
-rw-r--r--support/texlab/src/workspace/mod.rs417
1 files changed, 0 insertions, 417 deletions
diff --git a/support/texlab/src/workspace/mod.rs b/support/texlab/src/workspace/mod.rs
deleted file mode 100644
index 5ad2c21bf2..0000000000
--- a/support/texlab/src/workspace/mod.rs
+++ /dev/null
@@ -1,417 +0,0 @@
-mod feature;
-mod outline;
-mod uri;
-
-pub use self::feature::*;
-pub use self::outline::*;
-pub use self::uri::*;
-use crate::completion::DATABASE;
-use crate::syntax::*;
-use log::*;
-use lsp_types::*;
-use std::ffi::OsStr;
-use std::fs;
-use std::path::{Path, PathBuf};
-use std::sync::{Arc, Mutex};
-use std::time::SystemTime;
-use tex::Language;
-
-#[derive(Debug, PartialEq, Eq, Clone)]
-pub struct Document {
- pub uri: Uri,
- pub text: String,
- pub tree: SyntaxTree,
- pub modified: SystemTime,
-}
-
-impl Document {
- pub fn new(uri: Uri, text: String, tree: SyntaxTree) -> Self {
- Self {
- uri,
- text,
- tree,
- modified: SystemTime::now(),
- }
- }
-
- pub fn parse(uri: Uri, text: String, language: Language) -> Self {
- let tree = SyntaxTree::parse(&uri, &text, language);
- Self::new(uri, text, tree)
- }
-
- pub fn is_file(&self) -> bool {
- self.uri.scheme() == "file"
- }
-}
-
-#[derive(Debug, PartialEq, Eq, Clone, Default)]
-pub struct Workspace {
- pub documents: Vec<Arc<Document>>,
-}
-
-impl Workspace {
- pub fn new() -> Self {
- Workspace {
- documents: Vec::new(),
- }
- }
-
- pub fn find(&self, uri: &Uri) -> Option<Arc<Document>> {
- self.documents
- .iter()
- .find(|document| &document.uri == uri)
- .map(|document| Arc::clone(&document))
- }
-
- pub fn related_documents(&self, uri: &Uri) -> Vec<Arc<Document>> {
- let edges = self.build_dependency_graph();
- let mut results = Vec::new();
- if let Some(start) = self.find(uri) {
- let mut visited: Vec<Arc<Document>> = Vec::new();
- let mut stack = vec![start];
- while let Some(current) = stack.pop() {
- if visited.contains(&current) {
- continue;
- }
- visited.push(Arc::clone(&current));
-
- results.push(Arc::clone(&current));
- for edge in &edges {
- if edge.0 == current {
- stack.push(Arc::clone(&edge.1));
- }
- }
- }
- }
- results
- }
-
- fn build_dependency_graph(&self) -> Vec<(Arc<Document>, Arc<Document>)> {
- let mut edges: Vec<(Arc<Document>, Arc<Document>)> = Vec::new();
- for parent in self.documents.iter().filter(|document| document.is_file()) {
- if let SyntaxTree::Latex(tree) = &parent.tree {
- for include in &tree.includes {
- for targets in &include.all_targets {
- for target in targets {
- if let Some(ref child) = self.find(target) {
- edges.push((Arc::clone(&parent), Arc::clone(&child)));
- edges.push((Arc::clone(&child), Arc::clone(&parent)));
- }
- }
- }
- }
-
- let tex_path = parent.uri.to_file_path().unwrap();
- let aux_path = tex_path.with_extension("aux");
- if let Some(child) = self.find(&Uri::from_file_path(aux_path).unwrap()) {
- edges.push((Arc::clone(&parent), Arc::clone(&child)));
- edges.push((Arc::clone(&child), Arc::clone(&parent)));
- }
- }
- }
- edges
- }
-
- pub fn find_parent(&self, uri: &Uri) -> Option<Arc<Document>> {
- for document in self.related_documents(uri) {
- if let SyntaxTree::Latex(tree) = &document.tree {
- if tree.env.is_standalone {
- return Some(document);
- }
- }
- }
- None
- }
-
- pub fn unresolved_includes(&self) -> Vec<PathBuf> {
- let mut includes = Vec::new();
- for document in &self.documents {
- if let SyntaxTree::Latex(tree) = &document.tree {
- for include in &tree.includes {
- match include.kind {
- LatexIncludeKind::Bibliography | LatexIncludeKind::Latex => (),
- LatexIncludeKind::Everything
- | LatexIncludeKind::Image
- | LatexIncludeKind::Pdf
- | LatexIncludeKind::Svg => continue,
- LatexIncludeKind::Package | LatexIncludeKind::Class => {
- if include
- .paths()
- .iter()
- .all(|name| DATABASE.contains(name.text()))
- {
- continue;
- }
- }
- }
-
- for targets in &include.all_targets {
- if targets.iter().any(|target| self.find(target).is_some()) {
- continue;
- }
-
- for target in targets {
- let path = target.to_file_path().unwrap();
- if path.exists() {
- includes.push(path);
- }
- }
- }
- }
-
- let aux_path = document.uri.to_file_path().unwrap().with_extension("aux");
- if self
- .find(&Uri::from_file_path(&aux_path).unwrap())
- .is_none()
- {
- includes.push(aux_path);
- }
- }
- }
- includes
- }
-}
-
-#[derive(Debug, PartialEq, Eq, Clone)]
-pub struct DocumentView {
- pub workspace: Arc<Workspace>,
- pub document: Arc<Document>,
- pub related_documents: Vec<Arc<Document>>,
-}
-
-impl DocumentView {
- pub fn new(workspace: Arc<Workspace>, document: Arc<Document>) -> Self {
- let related_documents = workspace.related_documents(&document.uri);
- Self {
- workspace,
- document,
- related_documents,
- }
- }
-}
-
-#[derive(Debug)]
-pub enum LoadError {
- UnknownLanguage,
- InvalidPath,
- IO(std::io::Error),
-}
-
-#[derive(Debug, Default)]
-pub struct WorkspaceManager {
- workspace: Mutex<Arc<Workspace>>,
-}
-
-impl WorkspaceManager {
- pub fn get(&self) -> Arc<Workspace> {
- let workspace = self.workspace.lock().unwrap();
- Arc::clone(&workspace)
- }
-
- pub fn add(&self, document: TextDocumentItem) {
- let language = match Language::by_language_id(&document.language_id) {
- Some(language) => language,
- None => {
- error!("Invalid language id: {}", &document.language_id);
- return;
- }
- };
-
- let mut workspace = self.workspace.lock().unwrap();
- *workspace = Self::add_or_update(&workspace, document.uri.into(), document.text, language);
- }
-
- pub fn load(&self, path: &Path) -> Result<(), LoadError> {
- let language = match path
- .extension()
- .and_then(OsStr::to_str)
- .and_then(Language::by_extension)
- {
- Some(language) => language,
- None => {
- warn!("Could not determine language: {}", path.to_string_lossy());
- return Err(LoadError::UnknownLanguage);
- }
- };
-
- let uri = match Uri::from_file_path(path) {
- Ok(uri) => uri,
- Err(_) => {
- error!("Invalid path: {}", path.to_string_lossy());
- return Err(LoadError::InvalidPath);
- }
- };
-
- let text = match fs::read_to_string(path) {
- Ok(text) => text,
- Err(why) => {
- warn!("Could not open file: {}", path.to_string_lossy());
- return Err(LoadError::IO(why));
- }
- };
-
- let mut workspace = self.workspace.lock().unwrap();
- *workspace = Self::add_or_update(&workspace, uri, text, language);
- Ok(())
- }
-
- pub fn update(&self, uri: Uri, text: String) {
- let mut workspace = self.workspace.lock().unwrap();
-
- let old_document = match workspace.documents.iter().find(|x| x.uri == uri) {
- Some(document) => document,
- None => {
- warn!("Document not found: {}", uri);
- return;
- }
- };
-
- let language = match old_document.tree {
- SyntaxTree::Latex(_) => Language::Latex,
- SyntaxTree::Bibtex(_) => Language::Bibtex,
- };
-
- *workspace = Self::add_or_update(&workspace, uri, text, language);
- }
-
- fn add_or_update(
- workspace: &Workspace,
- uri: Uri,
- text: String,
- language: Language,
- ) -> Arc<Workspace> {
- let document = Document::parse(uri, text, language);
- let mut documents: Vec<Arc<Document>> = workspace
- .documents
- .iter()
- .filter(|x| x.uri != document.uri)
- .cloned()
- .collect();
-
- documents.push(Arc::new(document));
- Arc::new(Workspace { documents })
- }
-}
-
-#[derive(Debug, Default)]
-pub struct WorkspaceBuilder {
- pub workspace: Workspace,
-}
-
-impl WorkspaceBuilder {
- pub fn new() -> Self {
- Self::default()
- }
-
- pub fn document(&mut self, name: &str, text: &str) -> Uri {
- let path = std::env::temp_dir().join(name);
- let language = Language::by_extension(path.extension().unwrap().to_str().unwrap()).unwrap();
- let uri = Uri::from_file_path(path).unwrap();
- let document = Document::parse(uri.clone(), text.to_owned(), language);
- self.workspace.documents.push(Arc::new(document));
- uri
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- fn verify_documents(expected: Vec<Uri>, actual: Vec<Arc<Document>>) {
- assert_eq!(expected.len(), actual.len());
- for i in 0..expected.len() {
- assert_eq!(expected[i], actual[i].uri);
- }
- }
-
- #[test]
- fn test_related_documents_append_extensions() {
- let mut builder = WorkspaceBuilder::new();
- let uri1 = builder.document("foo.tex", "\\include{bar/baz}");
- let uri2 = builder.document("bar/baz.tex", "");
- let documents = builder.workspace.related_documents(&uri1);
- verify_documents(vec![uri1, uri2], documents);
- }
-
- #[test]
- fn test_related_documents_relative_path() {
- let mut builder = WorkspaceBuilder::new();
- let uri1 = builder.document("foo.tex", "");
- let uri2 = builder.document("bar/baz.tex", "\\input{../foo.tex}");
- let documents = builder.workspace.related_documents(&uri1);
- verify_documents(vec![uri1, uri2], documents);
- }
-
- #[test]
- fn test_related_documents_invalid_includes() {
- let mut builder = WorkspaceBuilder::new();
- let uri = builder.document("foo.tex", "\\include{<foo>?|bar|:}\n\\include{}");
- let documents = builder.workspace.related_documents(&uri);
- verify_documents(vec![uri], documents);
- }
-
- #[test]
- fn test_related_documents_bibliographies() {
- let mut builder = WorkspaceBuilder::new();
- let uri1 = builder.document("foo.tex", "\\addbibresource{bar.bib}");
- let uri2 = builder.document("bar.bib", "");
- let documents = builder.workspace.related_documents(&uri2);
- verify_documents(vec![uri2, uri1], documents);
- }
-
- #[test]
- fn test_related_documents_unresolvable_include() {
- let mut builder = WorkspaceBuilder::new();
- let uri = builder.document("foo.tex", "\\include{bar.tex}");
- builder.document("baz.tex", "");
- let documents = builder.workspace.related_documents(&uri);
- verify_documents(vec![uri], documents);
- }
-
- #[test]
- fn test_related_documents_include_cycles() {
- let mut builder = WorkspaceBuilder::new();
- let uri1 = builder.document("foo.tex", "\\input{bar.tex}");
- let uri2 = builder.document("bar.tex", "\\input{foo.tex}");
- let documents = builder.workspace.related_documents(&uri1);
- verify_documents(vec![uri1, uri2], documents);
- }
-
- #[test]
- fn test_related_documents_same_parent() {
- let mut builder = WorkspaceBuilder::new();
- let uri1 = builder.document("test.tex", "\\include{test1}\\include{test2}");
- let uri2 = builder.document("test1.tex", "\\label{foo}");
- let uri3 = builder.document("test2.tex", "\\ref{foo}");
- let documents = builder.workspace.related_documents(&uri3);
- verify_documents(vec![uri3, uri1, uri2], documents);
- }
-
- #[test]
- fn test_related_documents_aux_file() {
- let mut builder = WorkspaceBuilder::new();
- let uri1 = builder.document("foo.tex", "\\include{bar}");
- let uri2 = builder.document("bar.tex", "");
- let uri3 = builder.document("foo.aux", "");
- let documents = builder.workspace.related_documents(&uri2);
- verify_documents(vec![uri2, uri1, uri3], documents);
- }
-
- #[test]
- fn test_find_parent() {
- let mut builder = WorkspaceBuilder::new();
- let uri1 = builder.document("foo.tex", "");
- let uri2 = builder.document("bar.tex", "\\begin{document}\\include{foo}\\end{document}");
- let document = builder.workspace.find_parent(&uri1).unwrap();
- assert_eq!(uri2, document.uri);
- }
-
- #[test]
- fn test_find_parent_no_parent() {
- let mut builder = WorkspaceBuilder::new();
- let uri = builder.document("foo.tex", "");
- builder.document("bar.tex", "\\begin{document}\\end{document}");
- let document = builder.workspace.find_parent(&uri);
- assert_eq!(None, document);
- }
-}