summaryrefslogtreecommitdiff
path: root/support/texlab/src/db
diff options
context:
space:
mode:
Diffstat (limited to 'support/texlab/src/db')
-rw-r--r--support/texlab/src/db/analysis.rs62
-rw-r--r--support/texlab/src/db/context.rs18
-rw-r--r--support/texlab/src/db/diagnostics.rs6
-rw-r--r--support/texlab/src/db/diagnostics/bib.rs4
-rw-r--r--support/texlab/src/db/diagnostics/log.rs4
-rw-r--r--support/texlab/src/db/diagnostics/tex.rs38
-rw-r--r--support/texlab/src/db/discovery.rs9
-rw-r--r--support/texlab/src/db/document.rs41
-rw-r--r--support/texlab/src/db/workspace.rs35
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('/');
}