diff options
Diffstat (limited to 'support/texlab/src/db')
-rw-r--r-- | support/texlab/src/db/analysis.rs | 62 | ||||
-rw-r--r-- | support/texlab/src/db/context.rs | 18 | ||||
-rw-r--r-- | support/texlab/src/db/diagnostics.rs | 6 | ||||
-rw-r--r-- | support/texlab/src/db/diagnostics/bib.rs | 4 | ||||
-rw-r--r-- | support/texlab/src/db/diagnostics/log.rs | 4 | ||||
-rw-r--r-- | support/texlab/src/db/diagnostics/tex.rs | 38 | ||||
-rw-r--r-- | support/texlab/src/db/discovery.rs | 9 | ||||
-rw-r--r-- | support/texlab/src/db/document.rs | 41 | ||||
-rw-r--r-- | support/texlab/src/db/workspace.rs | 35 |
9 files changed, 130 insertions, 87 deletions
diff --git a/support/texlab/src/db/analysis.rs b/support/texlab/src/db/analysis.rs index 13b5bb1cb3..1f1bd508a8 100644 --- a/support/texlab/src/db/analysis.rs +++ b/support/texlab/src/db/analysis.rs @@ -1,6 +1,6 @@ pub mod label; -use rowan::{ast::AstNode, TextRange}; +use rowan::{ast::AstNode, NodeOrToken, TextRange}; use crate::{ syntax::latex::{self, HasCurly}, @@ -169,30 +169,42 @@ impl TexAnalysis { let mut command_name_ranges = Vec::new(); let mut environment_names = Vec::new(); - for node in root.descendants() { - TexLink::of_include(db, node.clone(), &mut links) - .or_else(|| TexLink::of_import(db, node.clone(), &mut links)) - .or_else(|| label::Name::of_definition(db, node.clone(), &mut labels)) - .or_else(|| label::Name::of_reference(db, node.clone(), &mut labels)) - .or_else(|| label::Name::of_reference_range(db, node.clone(), &mut labels)) - .or_else(|| label::Number::of_number(db, node.clone(), &mut label_numbers)) - .or_else(|| { - TheoremEnvironment::of_definition(db, node.clone(), &mut theorem_environments) - }) - .or_else(|| GraphicsPath::of_command(db, node.clone(), &mut graphics_paths)) - .or_else(|| { - let range = latex::GenericCommand::cast(node.clone())? - .name()? - .text_range(); - - command_name_ranges.push(range); - Some(()) - }) - .or_else(|| { - let begin = latex::Begin::cast(node.clone())?; - environment_names.push(begin.name()?.key()?.to_string()); - Some(()) - }); + for element in root.descendants_with_tokens() { + match element { + NodeOrToken::Token(token) if token.kind() == latex::COMMAND_NAME => { + command_name_ranges.push(token.text_range()); + } + NodeOrToken::Token(_) => {} + NodeOrToken::Node(node) => { + TexLink::of_include(db, node.clone(), &mut links) + .or_else(|| TexLink::of_import(db, node.clone(), &mut links)) + .or_else(|| label::Name::of_definition(db, node.clone(), &mut labels)) + .or_else(|| label::Name::of_reference(db, node.clone(), &mut labels)) + .or_else(|| label::Name::of_reference_range(db, node.clone(), &mut labels)) + .or_else(|| label::Number::of_number(db, node.clone(), &mut label_numbers)) + .or_else(|| { + TheoremEnvironment::of_definition( + db, + node.clone(), + &mut theorem_environments, + ) + }) + .or_else(|| GraphicsPath::of_command(db, node.clone(), &mut graphics_paths)) + .or_else(|| { + let range = latex::GenericCommand::cast(node.clone())? + .name()? + .text_range(); + + command_name_ranges.push(range); + Some(()) + }) + .or_else(|| { + let begin = latex::Begin::cast(node.clone())?; + environment_names.push(begin.name()?.key()?.to_string()); + Some(()) + }); + } + }; } Self::new( diff --git a/support/texlab/src/db/context.rs b/support/texlab/src/db/context.rs new file mode 100644 index 0000000000..c6277eb099 --- /dev/null +++ b/support/texlab/src/db/context.rs @@ -0,0 +1,18 @@ +use crate::Config; + +/// Contains the global context of the server throughout the application. +#[salsa::input(singleton)] +pub struct ServerContext { + /// The server configuration which is extracted from either + /// the `workspace/configuration` or `workspace/didChangeConfiguration` messages. + #[return_ref] + pub config: Config, + + /// Disable usage of `isIncomplete = false` in completion lists. + /// + /// Due to the large number of completion results, + /// the server can only send a subset of the items most of the time. + /// When the filtered list is small enough, `CompletionList.isIncomplete` can be set to `false`. + /// On VSCode, this optimization should not be done so this flag is needed. + pub always_incomplete_completion_list: bool, +} diff --git a/support/texlab/src/db/diagnostics.rs b/support/texlab/src/db/diagnostics.rs index 8abb856768..6b1a177133 100644 --- a/support/texlab/src/db/diagnostics.rs +++ b/support/texlab/src/db/diagnostics.rs @@ -131,7 +131,7 @@ pub fn collect_filtered( let all_diagnostics = collect(db, workspace); let mut all_filtered: FxHashMap<Document, Vec<lsp_types::Diagnostic>> = FxHashMap::default(); - let options = &workspace.options(db).diagnostics; + let config = &db.config().diagnostics; for document in workspace.documents(db) { let mut filtered = Vec::new(); if !matches!(document.language(db), Language::Tex | Language::Bib) { @@ -142,8 +142,8 @@ pub fn collect_filtered( for diagnostic in diagnostics.iter().filter(|diag| { util::regex_filter::filter( &diag.message, - &options.allowed_patterns, - &options.ignored_patterns, + &config.allowed_patterns, + &config.ignored_patterns, ) }) { let source = match diagnostic.code { diff --git a/support/texlab/src/db/diagnostics/bib.rs b/support/texlab/src/db/diagnostics/bib.rs index 6d0f66e960..4f5dfc55a1 100644 --- a/support/texlab/src/db/diagnostics/bib.rs +++ b/support/texlab/src/db/diagnostics/bib.rs @@ -32,7 +32,7 @@ fn analyze_entry( node: bibtex::SyntaxNode, results: &mut Vec<Diagnostic>, ) -> Option<()> { - let line_index = document.contents(db).line_index(db); + let line_index = document.line_index(db); let entry = bibtex::Entry::cast(node)?; if entry.left_delim_token().is_none() { @@ -81,7 +81,7 @@ fn analyze_field( node: bibtex::SyntaxNode, results: &mut Vec<Diagnostic>, ) -> Option<()> { - let line_index = document.contents(db).line_index(db); + let line_index = document.line_index(db); let field = bibtex::Field::cast(node)?; if field.eq_token().is_none() { diff --git a/support/texlab/src/db/diagnostics/log.rs b/support/texlab/src/db/diagnostics/log.rs index 436999259b..368fd3fdcc 100644 --- a/support/texlab/src/db/diagnostics/log.rs +++ b/support/texlab/src/db/diagnostics/log.rs @@ -81,10 +81,10 @@ fn find_range_of_hint( error: &BuildError, ) -> Option<Range> { let document = workspace.lookup_uri(db, uri)?; - let text = document.contents(db).text(db); + let text = document.text(db); let line = error.line? as usize; let hint = error.hint.as_deref()?; - let line_index = document.contents(db).line_index(db); + let line_index = document.line_index(db); let line_start = line_index.newlines.get(line).copied()?; let line_end = line_index diff --git a/support/texlab/src/db/diagnostics/tex.rs b/support/texlab/src/db/diagnostics/tex.rs index 50233f8bd6..a7b030a5bf 100644 --- a/support/texlab/src/db/diagnostics/tex.rs +++ b/support/texlab/src/db/diagnostics/tex.rs @@ -5,7 +5,7 @@ use crate::{db::document::Document, syntax::latex, util::line_index_ext::LineInd use super::{Diagnostic, DiagnosticCode, TexCode}; -#[salsa::tracked(return_ref)] +#[salsa::tracked] pub fn collect(db: &dyn Db, document: Document) -> Vec<Diagnostic> { let mut results = Vec::new(); @@ -18,10 +18,35 @@ pub fn collect(db: &dyn Db, document: Document) -> Vec<Diagnostic> { None => return results, }; - for node in data.root(db).descendants() { - analyze_environment(db, document, node.clone(), &mut results) - .or_else(|| analyze_curly_group(db, document, node.clone(), &mut results)) - .or_else(|| analyze_curly_braces(document, db, node, &mut results)); + let mut traversal = data.root(db).preorder(); + while let Some(event) = traversal.next() { + match event { + rowan::WalkEvent::Enter(node) => { + if let Some(environment) = latex::Environment::cast(node.clone()) { + if environment + .begin() + .and_then(|begin| begin.name()) + .and_then(|name| name.key()) + .map_or(false, |name| { + db.config() + .syntax + .verbatim_environments + .contains(&name.to_string()) + }) + { + traversal.skip_subtree(); + continue; + } + } + + analyze_environment(db, document, node.clone(), &mut results) + .or_else(|| analyze_curly_group(db, document, node.clone(), &mut results)) + .or_else(|| analyze_curly_braces(document, db, node, &mut results)); + } + rowan::WalkEvent::Leave(_) => { + continue; + } + }; } results @@ -41,7 +66,6 @@ fn analyze_environment( results.push(Diagnostic { severity: DiagnosticSeverity::ERROR, range: document - .contents(db) .line_index(db) .line_col_lsp_range(latex::small_range(&name1)), code: DiagnosticCode::Tex(code), @@ -89,7 +113,6 @@ fn analyze_curly_group( results.push(Diagnostic { severity: DiagnosticSeverity::ERROR, range: document - .contents(db) .line_index(db) .line_col_lsp_range(TextRange::empty(node.text_range().end())), code: DiagnosticCode::Tex(code), @@ -111,7 +134,6 @@ fn analyze_curly_braces( results.push(Diagnostic { severity: DiagnosticSeverity::ERROR, range: document - .contents(db) .line_index(db) .line_col_lsp_range(node.text_range()), code: DiagnosticCode::Tex(code), diff --git a/support/texlab/src/db/discovery.rs b/support/texlab/src/db/discovery.rs index 12338f745e..9cc5a4e807 100644 --- a/support/texlab/src/db/discovery.rs +++ b/support/texlab/src/db/discovery.rs @@ -40,8 +40,11 @@ pub fn hidden_dependencies( base_dir: Location, dependencies: &mut Vec<Dependency>, ) { - dependencies.extend(hidden_dependency(db, document, base_dir, "log")); - dependencies.extend(hidden_dependency(db, document, base_dir, "aux")); + let uri = document.location(db).uri(db).as_str(); + if document.language(db) == Language::Tex && !uri.ends_with(".aux") { + dependencies.extend(hidden_dependency(db, document, base_dir, "log")); + dependencies.extend(hidden_dependency(db, document, base_dir, "aux")); + } } #[salsa::tracked] @@ -158,7 +161,7 @@ impl DependencyGraph { } } -#[salsa::tracked] +#[salsa::tracked(return_ref)] pub fn dependency_graph(db: &dyn Db, start: Document) -> DependencyGraph { let workspace = Workspace::get(db); diff --git a/support/texlab/src/db/document.rs b/support/texlab/src/db/document.rs index 81ed22e916..40d0ab025f 100644 --- a/support/texlab/src/db/document.rs +++ b/support/texlab/src/db/document.rs @@ -48,20 +48,6 @@ impl Location { } } -#[salsa::input] -pub struct Contents { - #[return_ref] - pub text: String, -} - -#[salsa::tracked] -impl Contents { - #[salsa::tracked(return_ref)] - pub fn line_index(self, db: &dyn Db) -> LineIndex { - LineIndex::new(self.text(db)) - } -} - #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)] pub enum Owner { Client, @@ -115,19 +101,31 @@ pub struct LinterData { #[salsa::input] pub struct Document { + /// An object containing the URI of the document. pub location: Location, - pub contents: Contents, + + /// The source code. + #[return_ref] + pub text: String, + + /// The programming language. pub language: Language, + + /// The program (either server or client) which opened the document. pub owner: Owner, + + /// An estimate of the current cursor position. pub cursor: TextSize, + + /// The diagnostics reported from external linters such as ChkTeX. pub linter: LinterData, } impl Document { pub fn edit(self, db: &mut dyn Db, range: TextRange, replace_with: &str) { - let mut text = self.contents(db).set_text(db).to(String::new()); + let mut text = self.set_text(db).to(String::new()); text.replace_range(std::ops::Range::<usize>::from(range), replace_with); - self.contents(db).set_text(db).to(text); + self.set_text(db).to(text); self.set_cursor(db).to(range.start()); } @@ -149,7 +147,7 @@ impl Document { impl Document { #[salsa::tracked] pub fn parse(self, db: &dyn Db) -> DocumentData { - let text = self.contents(db).text(db); + let text = self.text(db); match self.language(db) { Language::Tex => { let data = TexDocumentData::new(db, parse_latex(text)); @@ -179,7 +177,7 @@ impl Document { self.parse(db).as_tex().map_or(false, |data| { let analysis = data.analyze(db); analysis.has_document_environment(db) - || !analysis + && !analysis .links(db) .iter() .filter(|link| link.kind(db) == TexLinkKind::Cls) @@ -193,4 +191,9 @@ impl Document { .as_tex() .map_or(false, |data| data.analyze(db).has_document_environment(db)) } + + #[salsa::tracked(return_ref)] + pub fn line_index(self, db: &dyn Db) -> LineIndex { + LineIndex::new(self.text(db)) + } } diff --git a/support/texlab/src/db/workspace.rs b/support/texlab/src/db/workspace.rs index 123d415fd9..67c99792a2 100644 --- a/support/texlab/src/db/workspace.rs +++ b/support/texlab/src/db/workspace.rs @@ -4,19 +4,19 @@ use std::{ }; use itertools::Itertools; -use lsp_types::{ClientCapabilities, ClientInfo, Url}; +use lsp_types::{ClientCapabilities, Url}; use rowan::TextSize; use rustc_hash::FxHashSet; use crate::{ db::document::{Document, Location}, distro::FileNameDB, - Db, Options, + Db, }; use super::{ dependency_graph, - document::{Contents, Language, LinterData, Owner}, + document::{Language, LinterData, Owner}, Word, }; @@ -26,15 +26,9 @@ pub struct Workspace { pub documents: FxHashSet<Document>, #[return_ref] - pub options: Options, - - #[return_ref] pub client_capabilities: ClientCapabilities, #[return_ref] - pub client_info: Option<ClientInfo>, - - #[return_ref] pub root_dirs: Vec<Location>, #[return_ref] @@ -79,11 +73,10 @@ impl Workspace { owner: Owner, ) -> Document { let location = Location::new(db, uri); - let contents = Contents::new(db, text); let cursor = TextSize::from(0); match self.lookup(db, location) { Some(document) => { - document.set_contents(db).to(contents); + document.set_text(db).to(text); document.set_language(db).to(language); document.set_owner(db).to(owner); document.set_cursor(db).to(cursor); @@ -93,7 +86,7 @@ impl Workspace { let document = Document::new( db, location, - contents, + text, language, owner, cursor, @@ -157,11 +150,10 @@ impl Workspace { impl Workspace { #[salsa::tracked] pub fn working_dir(self, db: &dyn Db, base_dir: Location) -> Location { - if let Some(dir) = self - .options(db) - .root_directory - .as_deref() - .and_then(|path| path.to_str()) + if let Some(dir) = db + .config() + .root_dir + .as_ref() .and_then(|path| base_dir.join(db, path)) { return dir; @@ -182,14 +174,7 @@ impl Workspace { #[salsa::tracked] pub fn output_dir(self, db: &dyn Db, base_dir: Location) -> Location { - let mut path = self - .options(db) - .aux_directory - .as_deref() - .and_then(|path| path.to_str()) - .unwrap_or(".") - .to_string(); - + let mut path = db.config().build.output_dir.clone(); if !path.ends_with('/') { path.push('/'); } |