summaryrefslogtreecommitdiff
path: root/support/texlab
diff options
context:
space:
mode:
Diffstat (limited to 'support/texlab')
-rw-r--r--support/texlab/CHANGELOG.md8
-rw-r--r--support/texlab/Cargo.lock46
-rw-r--r--support/texlab/crates/base-db/Cargo.toml1
-rw-r--r--support/texlab/crates/base-db/src/semantics/bib.rs23
-rw-r--r--support/texlab/crates/base-db/src/workspace.rs6
-rw-r--r--support/texlab/crates/bibtex-utils/Cargo.toml23
-rw-r--r--support/texlab/crates/bibtex-utils/src/field.rs (renamed from support/texlab/crates/citeproc/src/field.rs)0
-rw-r--r--support/texlab/crates/bibtex-utils/src/field/author.rs (renamed from support/texlab/crates/citeproc/src/field/author.rs)0
-rw-r--r--support/texlab/crates/bibtex-utils/src/field/date.rs (renamed from support/texlab/crates/citeproc/src/field/date.rs)0
-rw-r--r--support/texlab/crates/bibtex-utils/src/field/number.rs (renamed from support/texlab/crates/citeproc/src/field/number.rs)0
-rw-r--r--support/texlab/crates/bibtex-utils/src/field/text.rs (renamed from support/texlab/crates/citeproc/src/field/text.rs)0
-rw-r--r--support/texlab/crates/bibtex-utils/src/lib.rs1
-rw-r--r--support/texlab/crates/citeproc/Cargo.toml3
-rw-r--r--support/texlab/crates/citeproc/src/driver.rs12
-rw-r--r--support/texlab/crates/citeproc/src/entry.rs7
-rw-r--r--support/texlab/crates/citeproc/src/lib.rs1
-rw-r--r--support/texlab/crates/completion-data/src/lib.rs2
-rw-r--r--support/texlab/crates/definition/src/citation.rs2
-rw-r--r--support/texlab/crates/definition/src/command.rs2
-rw-r--r--support/texlab/crates/definition/src/include.rs2
-rw-r--r--support/texlab/crates/definition/src/label.rs2
-rw-r--r--support/texlab/crates/definition/src/lib.rs2
-rw-r--r--support/texlab/crates/definition/src/string_ref.rs2
-rw-r--r--support/texlab/crates/diagnostics/src/build_log.rs26
-rw-r--r--support/texlab/crates/diagnostics/src/citations.rs27
-rw-r--r--support/texlab/crates/diagnostics/src/lib.rs18
-rw-r--r--support/texlab/crates/hover/Cargo.toml1
-rw-r--r--support/texlab/crates/hover/src/citation.rs2
-rw-r--r--support/texlab/crates/hover/src/label.rs2
-rw-r--r--support/texlab/crates/hover/src/lib.rs12
-rw-r--r--support/texlab/crates/hover/src/string_ref.rs2
-rw-r--r--support/texlab/crates/references/src/entry.rs2
-rw-r--r--support/texlab/crates/references/src/label.rs2
-rw-r--r--support/texlab/crates/references/src/string_def.rs2
-rw-r--r--support/texlab/crates/syntax/src/bibtex.rs299
-rw-r--r--support/texlab/crates/syntax/src/bibtex/cst.rs244
-rw-r--r--support/texlab/crates/syntax/src/bibtex/kind.rs43
-rw-r--r--support/texlab/crates/syntax/src/lib.rs13
-rw-r--r--support/texlab/crates/texlab/Cargo.toml4
-rw-r--r--support/texlab/crates/texlab/benches/bench_main.rs35
-rw-r--r--support/texlab/crates/texlab/src/features/completion/argument.rs2
-rw-r--r--support/texlab/crates/texlab/src/features/completion/builder.rs92
-rw-r--r--support/texlab/crates/texlab/src/features/completion/citation.rs10
-rw-r--r--support/texlab/crates/texlab/src/features/completion/component_command.rs2
-rw-r--r--support/texlab/crates/texlab/src/features/completion/matcher.rs10
-rw-r--r--support/texlab/crates/texlab/src/server.rs21
-rw-r--r--support/texlab/crates/texlab/src/server/options.rs2
-rw-r--r--support/texlab/crates/texlab/src/util/diagnostics.rs3
-rw-r--r--support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__citation.snap6
-rw-r--r--support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__citation_acronym.snap4
-rw-r--r--support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__citation_open_brace.snap4
-rw-r--r--support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__citation_open_brace_multiple.snap4
-rw-r--r--support/texlab/texlab.14
-rw-r--r--support/texlab/texlab.pdfbin26643 -> 26559 bytes
54 files changed, 599 insertions, 444 deletions
diff --git a/support/texlab/CHANGELOG.md b/support/texlab/CHANGELOG.md
index 0301227cd1..1f0666306e 100644
--- a/support/texlab/CHANGELOG.md
+++ b/support/texlab/CHANGELOG.md
@@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [5.9.1] - 2023-08-11
+
+### Fixed
+
+- Improve performance when completing BibTeX entries ([#493](https://github.com/latex-lsp/texlab/issues/493))
+- Don't report unused entries for very large bibliographies
+- Avoid redundant reparses after saving documents
+
## [5.9.0] - 2023-08-06
### Added
diff --git a/support/texlab/Cargo.lock b/support/texlab/Cargo.lock
index f25cc7c01c..d0dfd6e75d 100644
--- a/support/texlab/Cargo.lock
+++ b/support/texlab/Cargo.lock
@@ -121,6 +121,7 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
name = "base-db"
version = "0.0.0"
dependencies = [
+ "bibtex-utils",
"dirs",
"distro",
"itertools 0.11.0",
@@ -144,6 +145,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1"
[[package]]
+name = "bibtex-utils"
+version = "0.0.0"
+dependencies = [
+ "chrono",
+ "expect-test",
+ "human_name",
+ "itertools 0.11.0",
+ "parser",
+ "rowan",
+ "rustc-hash",
+ "syntax",
+ "unicode-normalization",
+]
+
+[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -234,9 +250,8 @@ dependencies = [
name = "citeproc"
version = "0.0.0"
dependencies = [
- "chrono",
+ "bibtex-utils",
"expect-test",
- "human_name",
"isocountry",
"itertools 0.11.0",
"parser",
@@ -602,6 +617,15 @@ dependencies = [
]
[[package]]
+name = "file-id"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e13be71e6ca82e91bc0cb862bebaac0b2d1924a5a1d970c822b2f98b63fda8c3"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
name = "filetime"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -728,6 +752,7 @@ name = "hover"
version = "0.0.0"
dependencies = [
"base-db",
+ "bibtex-utils",
"citeproc",
"completion-data",
"expect-test",
@@ -1056,6 +1081,19 @@ dependencies = [
]
[[package]]
+name = "notify-debouncer-full"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "416969970ec751a5d702a88c6cd19ac1332abe997fce43f96db0418550426241"
+dependencies = [
+ "crossbeam-channel",
+ "file-id",
+ "notify",
+ "parking_lot",
+ "walkdir",
+]
+
+[[package]]
name = "num-traits"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1584,7 +1622,7 @@ dependencies = [
[[package]]
name = "texlab"
-version = "5.9.0"
+version = "5.9.1"
dependencies = [
"anyhow",
"assert_unordered",
@@ -1610,9 +1648,11 @@ dependencies = [
"lsp-server",
"lsp-types",
"notify",
+ "notify-debouncer-full",
"once_cell",
"parking_lot",
"parser",
+ "rayon",
"references",
"regex",
"rowan",
diff --git a/support/texlab/crates/base-db/Cargo.toml b/support/texlab/crates/base-db/Cargo.toml
index fa015b24cc..0ae198db7b 100644
--- a/support/texlab/crates/base-db/Cargo.toml
+++ b/support/texlab/crates/base-db/Cargo.toml
@@ -21,6 +21,7 @@ rustc-hash = "1.1.0"
syntax = { path = "../syntax" }
text-size = "1.1.1"
url = "=2.3.1"
+bibtex-utils = { path = "../bibtex-utils" }
[lib]
doctest = false
diff --git a/support/texlab/crates/base-db/src/semantics/bib.rs b/support/texlab/crates/base-db/src/semantics/bib.rs
index 22017d3c03..29f9477896 100644
--- a/support/texlab/crates/base-db/src/semantics/bib.rs
+++ b/support/texlab/crates/base-db/src/semantics/bib.rs
@@ -1,7 +1,11 @@
+use bibtex_utils::field::text::TextFieldData;
+use itertools::Itertools;
use rowan::ast::AstNode;
-use syntax::bibtex::{self, HasName};
+use syntax::bibtex::{self, HasName, HasType, HasValue};
use text_size::TextRange;
+use crate::data::{BibtexEntryType, BibtexEntryTypeCategory};
+
use super::Span;
#[derive(Debug, Clone, Default)]
@@ -23,12 +27,27 @@ impl Semantics {
fn process_entry(&mut self, entry: bibtex::Entry) {
if let Some(name) = entry.name_token() {
+ let type_token = entry.type_token().unwrap();
+ let category = BibtexEntryType::find(&type_token.text()[1..])
+ .map_or(BibtexEntryTypeCategory::Misc, |ty| ty.category);
+
+ let field_values = entry
+ .fields()
+ .filter_map(|field| Some(TextFieldData::parse(&field.value()?)?.text));
+
+ let keywords = [name.text().into(), type_token.text().into()]
+ .into_iter()
+ .chain(field_values)
+ .join(" ");
+
self.entries.push(Entry {
name: Span {
range: name.text_range(),
text: name.text().into(),
},
full_range: entry.syntax().text_range(),
+ category,
+ keywords,
});
}
}
@@ -50,6 +69,8 @@ impl Semantics {
pub struct Entry {
pub name: Span,
pub full_range: TextRange,
+ pub keywords: String,
+ pub category: BibtexEntryTypeCategory,
}
#[derive(Debug, Clone)]
diff --git a/support/texlab/crates/base-db/src/workspace.rs b/support/texlab/crates/base-db/src/workspace.rs
index 9308c2401d..35e3904d75 100644
--- a/support/texlab/crates/base-db/src/workspace.rs
+++ b/support/texlab/crates/base-db/src/workspace.rs
@@ -75,6 +75,12 @@ impl Workspace {
Cow::Owned(text) => text,
};
+ if let Some(document) = self.lookup_path(path) {
+ if document.text == text {
+ return Ok(());
+ }
+ }
+
self.open(uri, text, language, owner, LineCol { line: 0, col: 0 });
Ok(())
}
diff --git a/support/texlab/crates/bibtex-utils/Cargo.toml b/support/texlab/crates/bibtex-utils/Cargo.toml
new file mode 100644
index 0000000000..7dd75ff738
--- /dev/null
+++ b/support/texlab/crates/bibtex-utils/Cargo.toml
@@ -0,0 +1,23 @@
+[package]
+name = "bibtex-utils"
+version = "0.0.0"
+license.workspace = true
+authors.workspace = true
+edition.workspace = true
+rust-version.workspace = true
+
+[dependencies]
+chrono = { version = "0.4.26", default-features = false, features = ["std"] }
+human_name = "2.0.2"
+itertools = "0.11.0"
+rowan = "0.15.11"
+rustc-hash = "1.1.0"
+syntax = { path = "../syntax" }
+unicode-normalization = "0.1.22"
+
+[lib]
+doctest = false
+
+[dev-dependencies]
+expect-test = "1.4.1"
+parser = { path = "../parser" }
diff --git a/support/texlab/crates/citeproc/src/field.rs b/support/texlab/crates/bibtex-utils/src/field.rs
index d9f3adacab..d9f3adacab 100644
--- a/support/texlab/crates/citeproc/src/field.rs
+++ b/support/texlab/crates/bibtex-utils/src/field.rs
diff --git a/support/texlab/crates/citeproc/src/field/author.rs b/support/texlab/crates/bibtex-utils/src/field/author.rs
index d8576cbaa4..d8576cbaa4 100644
--- a/support/texlab/crates/citeproc/src/field/author.rs
+++ b/support/texlab/crates/bibtex-utils/src/field/author.rs
diff --git a/support/texlab/crates/citeproc/src/field/date.rs b/support/texlab/crates/bibtex-utils/src/field/date.rs
index 8e2c0b7d72..8e2c0b7d72 100644
--- a/support/texlab/crates/citeproc/src/field/date.rs
+++ b/support/texlab/crates/bibtex-utils/src/field/date.rs
diff --git a/support/texlab/crates/citeproc/src/field/number.rs b/support/texlab/crates/bibtex-utils/src/field/number.rs
index 227f3d5b75..227f3d5b75 100644
--- a/support/texlab/crates/citeproc/src/field/number.rs
+++ b/support/texlab/crates/bibtex-utils/src/field/number.rs
diff --git a/support/texlab/crates/citeproc/src/field/text.rs b/support/texlab/crates/bibtex-utils/src/field/text.rs
index 9689264779..9689264779 100644
--- a/support/texlab/crates/citeproc/src/field/text.rs
+++ b/support/texlab/crates/bibtex-utils/src/field/text.rs
diff --git a/support/texlab/crates/bibtex-utils/src/lib.rs b/support/texlab/crates/bibtex-utils/src/lib.rs
new file mode 100644
index 0000000000..5b8f2df9f4
--- /dev/null
+++ b/support/texlab/crates/bibtex-utils/src/lib.rs
@@ -0,0 +1 @@
+pub mod field;
diff --git a/support/texlab/crates/citeproc/Cargo.toml b/support/texlab/crates/citeproc/Cargo.toml
index ff1af00c97..c298c6f7d1 100644
--- a/support/texlab/crates/citeproc/Cargo.toml
+++ b/support/texlab/crates/citeproc/Cargo.toml
@@ -7,8 +7,7 @@ edition.workspace = true
rust-version.workspace = true
[dependencies]
-chrono = { version = "0.4.26", default-features = false, features = ["std"] }
-human_name = "2.0.2"
+bibtex-utils = { path = "../bibtex-utils" }
isocountry = "0.3.2"
itertools = "0.11.0"
rowan = "0.15.11"
diff --git a/support/texlab/crates/citeproc/src/driver.rs b/support/texlab/crates/citeproc/src/driver.rs
index af09b9ed32..778e2539b5 100644
--- a/support/texlab/crates/citeproc/src/driver.rs
+++ b/support/texlab/crates/citeproc/src/driver.rs
@@ -1,3 +1,9 @@
+use bibtex_utils::field::{
+ author::AuthorField,
+ date::DateField,
+ number::{NumberField, NumberFieldData},
+ text::TextField,
+};
use isocountry::CountryCode;
use itertools::Itertools;
use syntax::bibtex;
@@ -6,12 +12,6 @@ use url::Url;
use super::{
entry::{EntryData, EntryKind},
- field::{
- author::AuthorField,
- date::DateField,
- number::{NumberField, NumberFieldData},
- text::TextField,
- },
output::{Inline, InlineBuilder, Punct},
};
diff --git a/support/texlab/crates/citeproc/src/entry.rs b/support/texlab/crates/citeproc/src/entry.rs
index e29864e2c2..243908da95 100644
--- a/support/texlab/crates/citeproc/src/entry.rs
+++ b/support/texlab/crates/citeproc/src/entry.rs
@@ -1,12 +1,11 @@
-use rustc_hash::FxHashMap;
-use syntax::bibtex::{Entry, Field, HasName, HasType, HasValue, Value};
-
-use super::field::{
+use bibtex_utils::field::{
author::{AuthorField, AuthorFieldData},
date::{DateField, DateFieldData},
number::{NumberField, NumberFieldData},
text::{TextField, TextFieldData},
};
+use rustc_hash::FxHashMap;
+use syntax::bibtex::{Entry, Field, HasName, HasType, HasValue, Value};
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
pub enum EntryKind {
diff --git a/support/texlab/crates/citeproc/src/lib.rs b/support/texlab/crates/citeproc/src/lib.rs
index 1e0ac6b070..de24306583 100644
--- a/support/texlab/crates/citeproc/src/lib.rs
+++ b/support/texlab/crates/citeproc/src/lib.rs
@@ -1,6 +1,5 @@
mod driver;
mod entry;
-pub mod field;
mod output;
use syntax::bibtex;
diff --git a/support/texlab/crates/completion-data/src/lib.rs b/support/texlab/crates/completion-data/src/lib.rs
index c63564a58f..9bfdf71e48 100644
--- a/support/texlab/crates/completion-data/src/lib.rs
+++ b/support/texlab/crates/completion-data/src/lib.rs
@@ -107,7 +107,7 @@ const JSON_GZ: &[u8] = include_bytes!("../data/completion.json.gz");
pub static DATABASE: Lazy<Database<'static>> = Lazy::new(|| {
let mut decoder = GzDecoder::new(JSON_GZ);
- let json = Box::leak(Box::new(String::new()));
+ let json = Box::leak(Box::default());
decoder.read_to_string(json).unwrap();
let mut db: Database = serde_json::from_str(json).unwrap();
db.lookup_packages = db
diff --git a/support/texlab/crates/definition/src/citation.rs b/support/texlab/crates/definition/src/citation.rs
index 1497711cf6..51550a585d 100644
--- a/support/texlab/crates/definition/src/citation.rs
+++ b/support/texlab/crates/definition/src/citation.rs
@@ -7,7 +7,7 @@ use crate::DefinitionContext;
use super::DefinitionResult;
-pub(super) fn goto_definition<'db>(context: &mut DefinitionContext<'db>) -> Option<()> {
+pub(super) fn goto_definition(context: &mut DefinitionContext) -> Option<()> {
let data = context.params.document.data.as_tex()?;
let citation = queries::object_at_cursor(
diff --git a/support/texlab/crates/definition/src/command.rs b/support/texlab/crates/definition/src/command.rs
index 0a367beb14..661f953212 100644
--- a/support/texlab/crates/definition/src/command.rs
+++ b/support/texlab/crates/definition/src/command.rs
@@ -6,7 +6,7 @@ use crate::DefinitionContext;
use super::DefinitionResult;
-pub(super) fn goto_definition<'db>(context: &mut DefinitionContext<'db>) -> Option<()> {
+pub(super) fn goto_definition(context: &mut DefinitionContext) -> Option<()> {
let data = context.params.document.data.as_tex()?;
let root = data.root_node();
let name = root
diff --git a/support/texlab/crates/definition/src/include.rs b/support/texlab/crates/definition/src/include.rs
index 2c24f05321..df2c5c763c 100644
--- a/support/texlab/crates/definition/src/include.rs
+++ b/support/texlab/crates/definition/src/include.rs
@@ -4,7 +4,7 @@ use crate::DefinitionContext;
use super::DefinitionResult;
-pub(super) fn goto_definition<'db>(context: &mut DefinitionContext<'db>) -> Option<()> {
+pub(super) fn goto_definition(context: &mut DefinitionContext) -> Option<()> {
let start = context.params.document;
let parents = context.params.workspace.parents(start);
let results = parents
diff --git a/support/texlab/crates/definition/src/label.rs b/support/texlab/crates/definition/src/label.rs
index 127f6ff497..3c8c922059 100644
--- a/support/texlab/crates/definition/src/label.rs
+++ b/support/texlab/crates/definition/src/label.rs
@@ -10,7 +10,7 @@ use crate::DefinitionContext;
use super::DefinitionResult;
-pub(super) fn goto_definition<'db>(context: &mut DefinitionContext<'db>) -> Option<()> {
+pub(super) fn goto_definition(context: &mut DefinitionContext) -> Option<()> {
let data = context.params.document.data.as_tex()?;
let reference = queries::object_at_cursor(
&data.semantics.labels,
diff --git a/support/texlab/crates/definition/src/lib.rs b/support/texlab/crates/definition/src/lib.rs
index b96c48ed3f..8678bb0016 100644
--- a/support/texlab/crates/definition/src/lib.rs
+++ b/support/texlab/crates/definition/src/lib.rs
@@ -29,7 +29,7 @@ struct DefinitionContext<'db> {
results: Vec<DefinitionResult<'db>>,
}
-pub fn goto_definition<'db>(params: DefinitionParams<'db>) -> Vec<DefinitionResult<'db>> {
+pub fn goto_definition(params: DefinitionParams) -> Vec<DefinitionResult> {
let project = params.workspace.project(params.document);
let mut context = DefinitionContext {
params,
diff --git a/support/texlab/crates/definition/src/string_ref.rs b/support/texlab/crates/definition/src/string_ref.rs
index 124cc33c7c..883b126cc0 100644
--- a/support/texlab/crates/definition/src/string_ref.rs
+++ b/support/texlab/crates/definition/src/string_ref.rs
@@ -5,7 +5,7 @@ use crate::DefinitionContext;
use super::DefinitionResult;
-pub(super) fn goto_definition<'db>(context: &mut DefinitionContext<'db>) -> Option<()> {
+pub(super) fn goto_definition(context: &mut DefinitionContext) -> Option<()> {
let data = context.params.document.data.as_bib()?;
let root = data.root_node();
let name = root
diff --git a/support/texlab/crates/diagnostics/src/build_log.rs b/support/texlab/crates/diagnostics/src/build_log.rs
index f5770c90fb..525bd982ff 100644
--- a/support/texlab/crates/diagnostics/src/build_log.rs
+++ b/support/texlab/crates/diagnostics/src/build_log.rs
@@ -25,19 +25,24 @@ impl DiagnosticSource for BuildErrors {
fn update(&mut self, workspace: &Workspace, log_document: &Document) {
let mut errors: FxHashMap<Url, Vec<Diagnostic>> = FxHashMap::default();
- let Some(data) = log_document.data.as_log() else { return };
+ let Some(data) = log_document.data.as_log() else {
+ return;
+ };
let parents = workspace.parents(log_document);
- let Some(root_document) = parents.iter().next() else { return };
+ let Some(root_document) = parents.iter().next() else {
+ return;
+ };
- let Some(base_path) = root_document
- .path
- .as_deref()
- .and_then(|path| path.parent()) else { return };
+ let Some(base_path) = root_document.path.as_deref().and_then(|path| path.parent()) else {
+ return;
+ };
for error in &data.errors {
let full_path = base_path.join(&error.relative_path);
- let Ok(full_path_uri) = Url::from_file_path(&full_path) else { continue };
+ let Ok(full_path_uri) = Url::from_file_path(&full_path) else {
+ continue;
+ };
let tex_document = workspace.lookup(&full_path_uri).unwrap_or(root_document);
let range = find_range_of_hint(tex_document, error).unwrap_or_else(|| {
@@ -74,9 +79,12 @@ impl DiagnosticSource for BuildErrors {
self.logs.retain(|uri, _| workspace.lookup(uri).is_some());
for document in workspace.iter() {
- let Some(log) = self.logs.get(&document.uri) else { continue };
+ let Some(log) = self.logs.get(&document.uri) else {
+ continue;
+ };
+
for (uri, errors) in &log.errors {
- builder.push_many(&uri, errors.iter().map(Cow::Borrowed));
+ builder.push_many(uri, errors.iter().map(Cow::Borrowed));
}
}
}
diff --git a/support/texlab/crates/diagnostics/src/citations.rs b/support/texlab/crates/diagnostics/src/citations.rs
index e6b4d1022a..1ab7b6db30 100644
--- a/support/texlab/crates/diagnostics/src/citations.rs
+++ b/support/texlab/crates/diagnostics/src/citations.rs
@@ -3,7 +3,7 @@ use std::borrow::Cow;
use base_db::{
semantics::{bib::Entry, tex::Citation},
util::queries::{self, Object},
- BibDocumentData, Document, DocumentData, Project, TexDocumentData, Workspace,
+ Document, Project, Workspace,
};
use rustc_hash::FxHashSet;
@@ -12,6 +12,8 @@ use crate::{
DiagnosticBuilder, DiagnosticSource,
};
+const MAX_UNUSED_ENTRIES: usize = 1000;
+
#[derive(Default)]
pub struct CitationErrors;
@@ -23,12 +25,8 @@ impl DiagnosticSource for CitationErrors {
) {
for document in workspace.iter() {
let project = workspace.project(document);
-
- if let DocumentData::Tex(data) = &document.data {
- detect_undefined_citations(&project, document, data, builder);
- } else if let DocumentData::Bib(data) = &document.data {
- detect_unused_entries(&project, document, data, builder);
- }
+ detect_undefined_citations(&project, document, builder);
+ detect_unused_entries(&project, document, builder);
}
detect_duplicate_entries(workspace, builder);
@@ -38,9 +36,12 @@ impl DiagnosticSource for CitationErrors {
fn detect_undefined_citations<'db>(
project: &Project<'db>,
document: &'db Document,
- data: &TexDocumentData,
builder: &mut DiagnosticBuilder<'db>,
) {
+ let Some(data) = document.data.as_tex() else {
+ return;
+ };
+
let entries: FxHashSet<&str> = Entry::find_all(project)
.map(|(_, entry)| entry.name_text())
.collect();
@@ -60,9 +61,17 @@ fn detect_undefined_citations<'db>(
fn detect_unused_entries<'db>(
project: &Project<'db>,
document: &'db Document,
- data: &BibDocumentData,
builder: &mut DiagnosticBuilder<'db>,
) {
+ let Some(data) = document.data.as_bib() else {
+ return;
+ };
+
+ // If this is a huge bibliography, then don't bother checking for unused entries.
+ if data.semantics.entries.len() > MAX_UNUSED_ENTRIES {
+ return;
+ }
+
let citations: FxHashSet<&str> = Citation::find_all(project)
.map(|(_, citation)| citation.name_text())
.collect();
diff --git a/support/texlab/crates/diagnostics/src/lib.rs b/support/texlab/crates/diagnostics/src/lib.rs
index e55ecb78e6..d0be31a0ba 100644
--- a/support/texlab/crates/diagnostics/src/lib.rs
+++ b/support/texlab/crates/diagnostics/src/lib.rs
@@ -23,7 +23,7 @@ pub struct DiagnosticBuilder<'db> {
impl<'db> DiagnosticBuilder<'db> {
pub fn push(&mut self, uri: &'db Url, diagnostic: Cow<'db, Diagnostic>) {
- self.inner.entry(&uri).or_default().push(diagnostic);
+ self.inner.entry(uri).or_default().push(diagnostic);
}
pub fn push_many(
@@ -31,7 +31,7 @@ impl<'db> DiagnosticBuilder<'db> {
uri: &'db Url,
diagnostics: impl Iterator<Item = Cow<'db, Diagnostic>>,
) {
- self.inner.entry(&uri).or_default().extend(diagnostics);
+ self.inner.entry(uri).or_default().extend(diagnostics);
}
pub fn iter(&self) -> impl Iterator<Item = (&'db Url, impl Iterator<Item = &Diagnostic>)> {
@@ -54,12 +54,14 @@ pub struct DiagnosticManager {
impl Default for DiagnosticManager {
fn default() -> Self {
- let mut sources: Vec<Box<dyn DiagnosticSource>> = Vec::new();
- sources.push(Box::new(TexSyntaxErrors::default()));
- sources.push(Box::new(BibSyntaxErrors::default()));
- sources.push(Box::new(BuildErrors::default()));
- sources.push(Box::new(LabelErrors::default()));
- sources.push(Box::new(CitationErrors::default()));
+ let sources: Vec<Box<dyn DiagnosticSource>> = vec![
+ Box::<TexSyntaxErrors>::default(),
+ Box::<BibSyntaxErrors>::default(),
+ Box::<BuildErrors>::default(),
+ Box::<LabelErrors>::default(),
+ Box::<CitationErrors>::default(),
+ ];
+
Self { sources }
}
}
diff --git a/support/texlab/crates/hover/Cargo.toml b/support/texlab/crates/hover/Cargo.toml
index f92939dd24..0db19b8189 100644
--- a/support/texlab/crates/hover/Cargo.toml
+++ b/support/texlab/crates/hover/Cargo.toml
@@ -8,6 +8,7 @@ rust-version.workspace = true
[dependencies]
base-db = { path = "../base-db" }
+bibtex-utils = { path = "../bibtex-utils" }
citeproc = { path = "../citeproc" }
completion-data = { path = "../completion-data" }
rowan = "0.15.11"
diff --git a/support/texlab/crates/hover/src/citation.rs b/support/texlab/crates/hover/src/citation.rs
index d36370e709..49e5359bba 100644
--- a/support/texlab/crates/hover/src/citation.rs
+++ b/support/texlab/crates/hover/src/citation.rs
@@ -30,7 +30,7 @@ pub(super) fn find_hover<'db>(params: &HoverParams<'db>) -> Option<Hover<'db>> {
let text = params.project.documents.iter().find_map(|document| {
let data = document.data.as_bib()?;
let root = bibtex::Root::cast(data.root_node())?;
- let entry = root.find_entry(&name)?;
+ let entry = root.find_entry(name)?;
citeproc::render(&entry)
})?;
diff --git a/support/texlab/crates/hover/src/label.rs b/support/texlab/crates/hover/src/label.rs
index c5f72a287e..fc9694fc6c 100644
--- a/support/texlab/crates/hover/src/label.rs
+++ b/support/texlab/crates/hover/src/label.rs
@@ -20,7 +20,7 @@ pub(super) fn find_hover<'db>(params: &'db HoverParams<'db>) -> Option<Hover<'db
.filter(|(_, label)| label.kind == tex::LabelKind::Definition)
.find(|(_, label)| label.name_text() == cursor.object.name_text())?;
- let label = render_label(&params.workspace, &params.project, definition)?;
+ let label = render_label(params.workspace, &params.project, definition)?;
Some(Hover {
range: cursor.range,
data: HoverData::Label(label),
diff --git a/support/texlab/crates/hover/src/lib.rs b/support/texlab/crates/hover/src/lib.rs
index 4b06111603..88be3b919a 100644
--- a/support/texlab/crates/hover/src/lib.rs
+++ b/support/texlab/crates/hover/src/lib.rs
@@ -49,12 +49,12 @@ pub enum HoverData<'db> {
}
pub fn find<'db>(params: &'db HoverParams<'db>) -> Option<Hover<'db>> {
- citation::find_hover(&params)
- .or_else(|| package::find_hover(&params))
- .or_else(|| entry_type::find_hover(&params))
- .or_else(|| field_type::find_hover(&params))
- .or_else(|| label::find_hover(&params))
- .or_else(|| string_ref::find_hover(&params))
+ citation::find_hover(params)
+ .or_else(|| package::find_hover(params))
+ .or_else(|| entry_type::find_hover(params))
+ .or_else(|| field_type::find_hover(params))
+ .or_else(|| label::find_hover(params))
+ .or_else(|| string_ref::find_hover(params))
}
#[cfg(test)]
diff --git a/support/texlab/crates/hover/src/string_ref.rs b/support/texlab/crates/hover/src/string_ref.rs
index 64449909d7..7ea84113e0 100644
--- a/support/texlab/crates/hover/src/string_ref.rs
+++ b/support/texlab/crates/hover/src/string_ref.rs
@@ -1,4 +1,4 @@
-use citeproc::field::text::TextFieldData;
+use bibtex_utils::field::text::TextFieldData;
use rowan::ast::AstNode;
use syntax::bibtex::{self, HasName, HasValue};
diff --git a/support/texlab/crates/references/src/entry.rs b/support/texlab/crates/references/src/entry.rs
index 3e6b7d7a6e..617ff86304 100644
--- a/support/texlab/crates/references/src/entry.rs
+++ b/support/texlab/crates/references/src/entry.rs
@@ -6,7 +6,7 @@ use base_db::{
use crate::{Reference, ReferenceContext, ReferenceKind};
-pub(super) fn find_all<'db>(context: &mut ReferenceContext<'db>) -> Option<()> {
+pub(super) fn find_all(context: &mut ReferenceContext) -> Option<()> {
let offset = context.params.offset;
let name = match &context.params.document.data {
diff --git a/support/texlab/crates/references/src/label.rs b/support/texlab/crates/references/src/label.rs
index 8e7c17d6a7..5ed8096c5c 100644
--- a/support/texlab/crates/references/src/label.rs
+++ b/support/texlab/crates/references/src/label.rs
@@ -5,7 +5,7 @@ use base_db::{
use crate::{Reference, ReferenceContext, ReferenceKind};
-pub(super) fn find_all<'db>(context: &mut ReferenceContext<'db>) -> Option<()> {
+pub(super) fn find_all(context: &mut ReferenceContext) -> Option<()> {
let data = context.params.document.data.as_tex()?;
let mode = queries::SearchMode::Full;
let name = queries::object_at_cursor(&data.semantics.labels, context.params.offset, mode)?
diff --git a/support/texlab/crates/references/src/string_def.rs b/support/texlab/crates/references/src/string_def.rs
index 8f64a71e36..9657686079 100644
--- a/support/texlab/crates/references/src/string_def.rs
+++ b/support/texlab/crates/references/src/string_def.rs
@@ -3,7 +3,7 @@ use syntax::bibtex;
use crate::{Reference, ReferenceContext, ReferenceKind};
-pub(super) fn find_all<'db>(context: &mut ReferenceContext<'db>) -> Option<()> {
+pub(super) fn find_all(context: &mut ReferenceContext) -> Option<()> {
let document = context.params.document;
let data = document.data.as_bib()?;
let root = data.root_node();
diff --git a/support/texlab/crates/syntax/src/bibtex.rs b/support/texlab/crates/syntax/src/bibtex.rs
index b568fbf8e8..97ff6f6150 100644
--- a/support/texlab/crates/syntax/src/bibtex.rs
+++ b/support/texlab/crates/syntax/src/bibtex.rs
@@ -1,57 +1,19 @@
-use rowan::{ast::AstNode, NodeOrToken};
+mod cst;
+mod kind;
-#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
-#[allow(non_camel_case_types)]
-#[repr(u16)]
-pub enum SyntaxKind {
- WHITESPACE,
- JUNK,
- L_DELIM,
- R_DELIM,
- L_CURLY,
- R_CURLY,
- COMMA,
- POUND,
- QUOTE,
- EQ,
- TYPE,
- WORD,
- NAME,
- INTEGER,
- NBSP,
- ACCENT_NAME,
- COMMAND_NAME,
-
- PREAMBLE,
- STRING,
- ENTRY,
- FIELD,
- VALUE,
- LITERAL,
- JOIN,
- ACCENT,
- COMMAND,
- CURLY_GROUP,
- QUOTE_GROUP,
- ROOT,
-}
-
-pub use SyntaxKind::*;
-
-impl From<SyntaxKind> for rowan::SyntaxKind {
- fn from(kind: SyntaxKind) -> Self {
- Self(kind as u16)
- }
-}
+pub use self::{
+ cst::*,
+ kind::SyntaxKind::{self, *},
+};
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
-pub enum Lang {}
+pub enum BibtexLanguage {}
-impl rowan::Language for Lang {
+impl rowan::Language for BibtexLanguage {
type Kind = SyntaxKind;
fn kind_from_raw(raw: rowan::SyntaxKind) -> Self::Kind {
- assert!(raw.0 <= SyntaxKind::ROOT as u16);
+ assert!(raw.0 <= ROOT as u16);
unsafe { std::mem::transmute::<u16, SyntaxKind>(raw.0) }
}
@@ -60,245 +22,8 @@ impl rowan::Language for Lang {
}
}
-pub type SyntaxNode = rowan::SyntaxNode<Lang>;
-
-pub type SyntaxToken = rowan::SyntaxToken<Lang>;
-
-pub type SyntaxElement = rowan::SyntaxElement<Lang>;
-
-macro_rules! ast_node {
- (name: $name:ident, kinds: [$($kind:pat),+], traits: [$($trait: ident),*]) => {
- #[derive(Clone)]
- pub struct $name {
- node: SyntaxNode,
- }
-
- impl AstNode for $name {
- type Language = Lang;
-
- fn can_cast(kind: SyntaxKind) -> bool {
- match kind {
- $($kind => true,)+
- _ => false,
- }
- }
-
- fn cast(node: SyntaxNode) -> Option<Self>
- where
- Self: Sized,
- {
- match node.kind() {
- $($kind => Some(Self { node}),)+
- _ => None,
- }
- }
-
- fn syntax(&self) -> &SyntaxNode {
- &self.node
- }
- }
-
- $(
- impl $trait for $name { }
- )*
- };
-}
-
-macro_rules! ast_node_enum {
- (name: $name:ident, variants: [$($variant:ident),+]) => {
- #[derive(Clone)]
- pub enum $name {
- $($variant($variant),)*
- }
-
- impl AstNode for $name {
- type Language = Lang;
-
- fn can_cast(kind: SyntaxKind) -> bool {
- false $(|| $variant::can_cast(kind))+
- }
-
- fn cast(node: SyntaxNode) -> Option<Self>
- where
- Self: Sized,
- {
- None $(.or_else(|| $variant::cast(node.clone()).map(Self::$variant)))*
- }
-
- fn syntax(&self) -> &SyntaxNode {
- match self {
- $(Self::$variant(node) => node.syntax(),)*
- }
- }
- }
-
- $(
- impl From<$variant> for $name {
- fn from(node: $variant) -> Self {
- Self::$variant(node)
- }
- }
- )*
- };
-}
-
-pub trait HasType: AstNode<Language = Lang> {
- fn type_token(&self) -> Option<SyntaxToken> {
- self.syntax()
- .children_with_tokens()
- .filter_map(NodeOrToken::into_token)
- .find(|token| token.kind() == TYPE)
- }
-}
-
-pub trait HasDelims: AstNode<Language = Lang> {
- fn left_delim_token(&self) -> Option<SyntaxToken> {
- self.syntax()
- .children_with_tokens()
- .filter_map(NodeOrToken::into_token)
- .find(|token| token.kind() == L_DELIM)
- }
-
- fn right_delim_token(&self) -> Option<SyntaxToken> {
- self.syntax()
- .children_with_tokens()
- .filter_map(NodeOrToken::into_token)
- .find(|token| token.kind() == R_DELIM)
- }
-}
-
-pub trait HasName: AstNode<Language = Lang> {
- fn name_token(&self) -> Option<SyntaxToken> {
- self.syntax()
- .children_with_tokens()
- .filter_map(NodeOrToken::into_token)
- .find(|token| token.kind() == NAME)
- }
-}
-
-pub trait HasEq: AstNode<Language = Lang> {
- fn eq_token(&self) -> Option<SyntaxToken> {
- self.syntax()
- .children_with_tokens()
- .filter_map(NodeOrToken::into_token)
- .find(|token| token.kind() == EQ)
- }
-}
-
-pub trait HasComma: AstNode<Language = Lang> {
- fn comma_token(&self) -> Option<SyntaxToken> {
- self.syntax()
- .children_with_tokens()
- .filter_map(NodeOrToken::into_token)
- .find(|token| token.kind() == COMMA)
- }
-}
-
-pub trait HasPound: AstNode<Language = Lang> {
- fn pound_token(&self) -> Option<SyntaxToken> {
- self.syntax()
- .children_with_tokens()
- .filter_map(NodeOrToken::into_token)
- .find(|token| token.kind() == POUND)
- }
-}
-
-pub trait HasInteger: AstNode<Language = Lang> {
- fn integer_token(&self) -> Option<SyntaxToken> {
- self.syntax()
- .children_with_tokens()
- .filter_map(NodeOrToken::into_token)
- .find(|token| token.kind() == INTEGER)
- }
-}
-
-pub trait HasCommandName: AstNode<Language = Lang> {
- fn command_name_token(&self) -> Option<SyntaxToken> {
- self.syntax()
- .children_with_tokens()
- .filter_map(NodeOrToken::into_token)
- .find(|token| token.kind() == COMMAND_NAME)
- }
-}
-
-pub trait HasAccentName: AstNode<Language = Lang> {
- fn accent_name_token(&self) -> Option<SyntaxToken> {
- self.syntax()
- .children_with_tokens()
- .filter_map(NodeOrToken::into_token)
- .find(|token| token.kind() == ACCENT_NAME)
- }
-}
-
-pub trait HasWord: AstNode<Language = Lang> {
- fn word_token(&self) -> Option<SyntaxToken> {
- self.syntax()
- .children_with_tokens()
- .filter_map(NodeOrToken::into_token)
- .find(|token| token.kind() == WORD)
- }
-}
-
-pub trait HasValue: AstNode<Language = Lang> {
- fn value(&self) -> Option<Value> {
- self.syntax().children().find_map(Value::cast)
- }
-}
-
-ast_node!(name: Root, kinds: [ROOT], traits: []);
-
-impl Root {
- pub fn strings(&self) -> impl Iterator<Item = StringDef> {
- self.syntax().children().filter_map(StringDef::cast)
- }
-
- pub fn entries(&self) -> impl Iterator<Item = Entry> {
- self.syntax().children().filter_map(Entry::cast)
- }
-
- pub fn find_entry(&self, name: &str) -> Option<Entry> {
- self.entries().find(|entry| {
- entry
- .name_token()
- .map_or(false, |token| token.text() == name)
- })
- }
-}
-
-ast_node!(name: Preamble, kinds: [PREAMBLE], traits: [HasType, HasDelims, HasValue]);
-
-ast_node!(name: StringDef, kinds: [STRING], traits: [HasType, HasDelims, HasName, HasEq, HasValue]);
-
-ast_node!(name: Entry, kinds: [ENTRY], traits: [HasType, HasDelims, HasName, HasComma]);
-
-impl Entry {
- pub fn fields(&self) -> impl Iterator<Item = Field> {
- self.syntax().children().filter_map(Field::cast)
- }
-}
-
-ast_node!(name: Field, kinds: [FIELD], traits: [HasName, HasEq, HasValue, HasComma]);
-
-ast_node_enum!(name: Value, variants: [Literal, CurlyGroup, QuoteGroup, Join, Accent, Command]);
-
-ast_node!(name: Literal, kinds: [LITERAL], traits: [HasName, HasInteger]);
-
-ast_node!(name: CurlyGroup, kinds: [CURLY_GROUP], traits: []);
-
-ast_node!(name: QuoteGroup, kinds: [QUOTE_GROUP], traits: []);
-
-ast_node!(name: Join, kinds: [JOIN], traits: [HasPound]);
-
-impl Join {
- pub fn left_value(&self) -> Option<Value> {
- self.syntax().children().find_map(Value::cast)
- }
-
- pub fn right_value(&self) -> Option<Value> {
- self.syntax().children().filter_map(Value::cast).nth(1)
- }
-}
+pub type SyntaxNode = rowan::SyntaxNode<BibtexLanguage>;
-ast_node!(name: Accent, kinds: [ACCENT], traits: [HasAccentName, HasWord]);
+pub type SyntaxToken = rowan::SyntaxToken<BibtexLanguage>;
-ast_node!(name: Command, kinds: [COMMAND], traits: [HasCommandName]);
+pub type SyntaxElement = rowan::SyntaxElement<BibtexLanguage>;
diff --git a/support/texlab/crates/syntax/src/bibtex/cst.rs b/support/texlab/crates/syntax/src/bibtex/cst.rs
new file mode 100644
index 0000000000..eb67fdb0d7
--- /dev/null
+++ b/support/texlab/crates/syntax/src/bibtex/cst.rs
@@ -0,0 +1,244 @@
+use rowan::{ast::AstNode, NodeOrToken};
+
+use super::{
+ BibtexLanguage,
+ SyntaxKind::{self, *},
+ SyntaxNode, SyntaxToken,
+};
+
+macro_rules! cst_node {
+ (name: $name:ident, kinds: [$($kind:pat),+], traits: [$($trait: ident),*]) => {
+ #[derive(Clone)]
+ pub struct $name {
+ node: SyntaxNode,
+ }
+
+ impl AstNode for $name {
+ type Language = BibtexLanguage;
+
+ fn can_cast(kind: SyntaxKind) -> bool {
+ match kind {
+ $($kind => true,)+
+ _ => false,
+ }
+ }
+
+ fn cast(node: SyntaxNode) -> Option<Self>
+ where
+ Self: Sized,
+ {
+ match node.kind() {
+ $($kind => Some(Self { node}),)+
+ _ => None,
+ }
+ }
+
+ fn syntax(&self) -> &SyntaxNode {
+ &self.node
+ }
+ }
+
+ $(
+ impl $trait for $name { }
+ )*
+ };
+}
+
+macro_rules! cst_node_enum {
+ (name: $name:ident, variants: [$($variant:ident),+]) => {
+ #[derive(Clone)]
+ pub enum $name {
+ $($variant($variant),)*
+ }
+
+ impl AstNode for $name {
+ type Language = BibtexLanguage;
+
+ fn can_cast(kind: SyntaxKind) -> bool {
+ false $(|| $variant::can_cast(kind))+
+ }
+
+ fn cast(node: SyntaxNode) -> Option<Self>
+ where
+ Self: Sized,
+ {
+ None $(.or_else(|| $variant::cast(node.clone()).map(Self::$variant)))*
+ }
+
+ fn syntax(&self) -> &SyntaxNode {
+ match self {
+ $(Self::$variant(node) => node.syntax(),)*
+ }
+ }
+ }
+
+ $(
+ impl From<$variant> for $name {
+ fn from(node: $variant) -> Self {
+ Self::$variant(node)
+ }
+ }
+ )*
+ };
+}
+
+pub trait HasType: AstNode<Language = BibtexLanguage> {
+ fn type_token(&self) -> Option<SyntaxToken> {
+ self.syntax()
+ .children_with_tokens()
+ .filter_map(NodeOrToken::into_token)
+ .find(|token| token.kind() == TYPE)
+ }
+}
+
+pub trait HasDelims: AstNode<Language = BibtexLanguage> {
+ fn left_delim_token(&self) -> Option<SyntaxToken> {
+ self.syntax()
+ .children_with_tokens()
+ .filter_map(NodeOrToken::into_token)
+ .find(|token| token.kind() == L_DELIM)
+ }
+
+ fn right_delim_token(&self) -> Option<SyntaxToken> {
+ self.syntax()
+ .children_with_tokens()
+ .filter_map(NodeOrToken::into_token)
+ .find(|token| token.kind() == R_DELIM)
+ }
+}
+
+pub trait HasName: AstNode<Language = BibtexLanguage> {
+ fn name_token(&self) -> Option<SyntaxToken> {
+ self.syntax()
+ .children_with_tokens()
+ .filter_map(NodeOrToken::into_token)
+ .find(|token| token.kind() == NAME)
+ }
+}
+
+pub trait HasEq: AstNode<Language = BibtexLanguage> {
+ fn eq_token(&self) -> Option<SyntaxToken> {
+ self.syntax()
+ .children_with_tokens()
+ .filter_map(NodeOrToken::into_token)
+ .find(|token| token.kind() == EQ)
+ }
+}
+
+pub trait HasComma: AstNode<Language = BibtexLanguage> {
+ fn comma_token(&self) -> Option<SyntaxToken> {
+ self.syntax()
+ .children_with_tokens()
+ .filter_map(NodeOrToken::into_token)
+ .find(|token| token.kind() == COMMA)
+ }
+}
+
+pub trait HasPound: AstNode<Language = BibtexLanguage> {
+ fn pound_token(&self) -> Option<SyntaxToken> {
+ self.syntax()
+ .children_with_tokens()
+ .filter_map(NodeOrToken::into_token)
+ .find(|token| token.kind() == POUND)
+ }
+}
+
+pub trait HasInteger: AstNode<Language = BibtexLanguage> {
+ fn integer_token(&self) -> Option<SyntaxToken> {
+ self.syntax()
+ .children_with_tokens()
+ .filter_map(NodeOrToken::into_token)
+ .find(|token| token.kind() == INTEGER)
+ }
+}
+
+pub trait HasCommandName: AstNode<Language = BibtexLanguage> {
+ fn command_name_token(&self) -> Option<SyntaxToken> {
+ self.syntax()
+ .children_with_tokens()
+ .filter_map(NodeOrToken::into_token)
+ .find(|token| token.kind() == COMMAND_NAME)
+ }
+}
+
+pub trait HasAccentName: AstNode<Language = BibtexLanguage> {
+ fn accent_name_token(&self) -> Option<SyntaxToken> {
+ self.syntax()
+ .children_with_tokens()
+ .filter_map(NodeOrToken::into_token)
+ .find(|token| token.kind() == ACCENT_NAME)
+ }
+}
+
+pub trait HasWord: AstNode<Language = BibtexLanguage> {
+ fn word_token(&self) -> Option<SyntaxToken> {
+ self.syntax()
+ .children_with_tokens()
+ .filter_map(NodeOrToken::into_token)
+ .find(|token| token.kind() == WORD)
+ }
+}
+
+pub trait HasValue: AstNode<Language = BibtexLanguage> {
+ fn value(&self) -> Option<Value> {
+ self.syntax().children().find_map(Value::cast)
+ }
+}
+
+cst_node!(name: Root, kinds: [ROOT], traits: []);
+
+impl Root {
+ pub fn strings(&self) -> impl Iterator<Item = StringDef> {
+ self.syntax().children().filter_map(StringDef::cast)
+ }
+
+ pub fn entries(&self) -> impl Iterator<Item = Entry> {
+ self.syntax().children().filter_map(Entry::cast)
+ }
+
+ pub fn find_entry(&self, name: &str) -> Option<Entry> {
+ self.entries().find(|entry| {
+ entry
+ .name_token()
+ .map_or(false, |token| token.text() == name)
+ })
+ }
+}
+
+cst_node!(name: Preamble, kinds: [PREAMBLE], traits: [HasType, HasDelims, HasValue]);
+
+cst_node!(name: StringDef, kinds: [STRING], traits: [HasType, HasDelims, HasName, HasEq, HasValue]);
+
+cst_node!(name: Entry, kinds: [ENTRY], traits: [HasType, HasDelims, HasName, HasComma]);
+
+impl Entry {
+ pub fn fields(&self) -> impl Iterator<Item = Field> {
+ self.syntax().children().filter_map(Field::cast)
+ }
+}
+
+cst_node!(name: Field, kinds: [FIELD], traits: [HasName, HasEq, HasValue, HasComma]);
+
+cst_node_enum!(name: Value, variants: [Literal, CurlyGroup, QuoteGroup, Join, Accent, Command]);
+
+cst_node!(name: Literal, kinds: [LITERAL], traits: [HasName, HasInteger]);
+
+cst_node!(name: CurlyGroup, kinds: [CURLY_GROUP], traits: []);
+
+cst_node!(name: QuoteGroup, kinds: [QUOTE_GROUP], traits: []);
+
+cst_node!(name: Join, kinds: [JOIN], traits: [HasPound]);
+
+impl Join {
+ pub fn left_value(&self) -> Option<Value> {
+ self.syntax().children().find_map(Value::cast)
+ }
+
+ pub fn right_value(&self) -> Option<Value> {
+ self.syntax().children().filter_map(Value::cast).nth(1)
+ }
+}
+
+cst_node!(name: Accent, kinds: [ACCENT], traits: [HasAccentName, HasWord]);
+
+cst_node!(name: Command, kinds: [COMMAND], traits: [HasCommandName]);
diff --git a/support/texlab/crates/syntax/src/bibtex/kind.rs b/support/texlab/crates/syntax/src/bibtex/kind.rs
new file mode 100644
index 0000000000..7817f47495
--- /dev/null
+++ b/support/texlab/crates/syntax/src/bibtex/kind.rs
@@ -0,0 +1,43 @@
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
+#[allow(non_camel_case_types)]
+#[repr(u16)]
+pub enum SyntaxKind {
+ WHITESPACE,
+ JUNK,
+ L_DELIM,
+ R_DELIM,
+ L_CURLY,
+ R_CURLY,
+ COMMA,
+ POUND,
+ QUOTE,
+ EQ,
+ TYPE,
+ WORD,
+ NAME,
+ INTEGER,
+ NBSP,
+ ACCENT_NAME,
+ COMMAND_NAME,
+
+ PREAMBLE,
+ STRING,
+ ENTRY,
+ FIELD,
+ VALUE,
+ LITERAL,
+ JOIN,
+ ACCENT,
+ COMMAND,
+ CURLY_GROUP,
+ QUOTE_GROUP,
+ ROOT,
+}
+
+pub use SyntaxKind::*;
+
+impl From<SyntaxKind> for rowan::SyntaxKind {
+ fn from(kind: SyntaxKind) -> Self {
+ Self(kind as u16)
+ }
+}
diff --git a/support/texlab/crates/syntax/src/lib.rs b/support/texlab/crates/syntax/src/lib.rs
index c2c0552652..dc8761b73d 100644
--- a/support/texlab/crates/syntax/src/lib.rs
+++ b/support/texlab/crates/syntax/src/lib.rs
@@ -20,16 +20,3 @@ pub struct BuildError {
pub struct BuildLog {
pub errors: Vec<BuildError>,
}
-
-#[macro_export]
-macro_rules! match_ast {
- (match $node:ident { $($tt:tt)* }) => { $crate::match_ast!(match ($node) { $($tt)* }) };
-
- (match ($node:expr) {
- $( $( $path:ident )::+ ($it:pat) => $res:expr, )*
- _ => $catch_all:expr $(,)?
- }) => {{
- $( if let Some($it) = $($path::)+cast($node.clone()) { $res } else )*
- { $catch_all }
- }};
-}
diff --git a/support/texlab/crates/texlab/Cargo.toml b/support/texlab/crates/texlab/Cargo.toml
index 65752a4e60..98771a3900 100644
--- a/support/texlab/crates/texlab/Cargo.toml
+++ b/support/texlab/crates/texlab/Cargo.toml
@@ -1,7 +1,7 @@
[package]
name = "texlab"
description = "LaTeX Language Server"
-version = "5.9.0"
+version = "5.9.1"
license.workspace = true
readme = "README.md"
authors.workspace = true
@@ -43,9 +43,11 @@ log = "0.4.19"
lsp-server = "0.7.2"
lsp-types = "0.94.0"
notify = "6.0.1"
+notify-debouncer-full = "0.2.0"
once_cell = "1.18.0"
parking_lot = "0.12.1"
parser = { path = "../parser" }
+rayon = "1.7.0"
references = { path = "../references" }
regex = "1.9.1"
rowan = "0.15.11"
diff --git a/support/texlab/crates/texlab/benches/bench_main.rs b/support/texlab/crates/texlab/benches/bench_main.rs
index 47b302e313..7fc6d8fc95 100644
--- a/support/texlab/crates/texlab/benches/bench_main.rs
+++ b/support/texlab/crates/texlab/benches/bench_main.rs
@@ -36,6 +36,41 @@ fn criterion_benchmark(c: &mut Criterion) {
)
});
});
+
+ c.bench_function("BibTeX/Cite", |b| {
+ let uri1 = Url::parse("http://example.com/texlab.tex").unwrap();
+ let uri2 = Url::parse("http://example.com/rht.bib").unwrap();
+ let text1 = r#"\cite{a}\addbibresource{rht.bib}"#.to_string();
+ let text2 = include_str!("/home/paddy/texlab-testing/rht.bib").to_string();
+ let mut workspace = Workspace::default();
+ workspace.open(
+ uri1.clone(),
+ text1,
+ Language::Tex,
+ Owner::Client,
+ LineCol { line: 0, col: 0 },
+ );
+
+ workspace.open(
+ uri2.clone(),
+ text2,
+ Language::Bib,
+ Owner::Client,
+ LineCol { line: 0, col: 6 },
+ );
+
+ let client_capabilities = ClientCapabilities::default();
+
+ b.iter(|| {
+ texlab::features::completion::complete(
+ &workspace,
+ &uri1,
+ Position::new(0, 7),
+ &client_capabilities,
+ None,
+ )
+ });
+ });
}
criterion_group!(benches, criterion_benchmark);
diff --git a/support/texlab/crates/texlab/src/features/completion/argument.rs b/support/texlab/crates/texlab/src/features/completion/argument.rs
index 2481685ea5..842ce7cab7 100644
--- a/support/texlab/crates/texlab/src/features/completion/argument.rs
+++ b/support/texlab/crates/texlab/src/features/completion/argument.rs
@@ -47,7 +47,7 @@ pub fn complete<'a>(context: &'a CursorContext, builder: &mut CompletionBuilder<
.filter(|(i, _)| *i == index)
{
for arg in &param.0 {
- builder.generic_argument(range, &arg.name, arg.image.as_deref());
+ builder.generic_argument(range, arg.name, arg.image);
}
}
}
diff --git a/support/texlab/crates/texlab/src/features/completion/builder.rs b/support/texlab/crates/texlab/src/features/completion/builder.rs
index fede7aeaf9..8457c276fe 100644
--- a/support/texlab/crates/texlab/src/features/completion/builder.rs
+++ b/support/texlab/crates/texlab/src/features/completion/builder.rs
@@ -1,5 +1,6 @@
use base_db::{
data::{BibtexEntryType, BibtexEntryTypeCategory, BibtexFieldType},
+ semantics::bib,
Document, MatchingAlgo,
};
use fuzzy_matcher::skim::SkimMatcherV2;
@@ -8,14 +9,10 @@ use lsp_types::{
ClientCapabilities, ClientInfo, CompletionItem, CompletionItemKind, CompletionList,
CompletionTextEdit, Documentation, InsertTextFormat, MarkupContent, MarkupKind, TextEdit, Url,
};
-use once_cell::sync::Lazy;
-use regex::Regex;
+use rayon::prelude::{IntoParallelRefIterator, ParallelExtend, ParallelIterator};
use rowan::{ast::AstNode, TextRange, TextSize};
use serde::{Deserialize, Serialize};
-use syntax::{
- bibtex::{self, HasName, HasType},
- latex,
-};
+use syntax::{bibtex, latex};
use crate::util::{
capabilities::ClientCapabilitiesExt,
@@ -176,33 +173,51 @@ impl<'a> CompletionBuilder<'a> {
Some(())
}
+ pub fn citations(&mut self, range: TextRange, document: &'a Document) {
+ let Some(data) = document.data.as_bib() else {
+ return;
+ };
+
+ let iter = data
+ .semantics
+ .entries
+ .par_iter()
+ .filter_map(|entry| {
+ let score = self.matcher.score(&entry.keywords, &self.text_pattern)?;
+ Some((entry, score))
+ })
+ .map(|(entry, score)| {
+ let data = Data::Citation {
+ document,
+ key: &entry.name.text,
+ filter_text: &entry.keywords,
+ category: entry.category,
+ };
+
+ Item {
+ range,
+ data,
+ preselect: false,
+ score,
+ }
+ });
+
+ self.items.par_extend(iter);
+ }
+
pub fn citation(
&mut self,
range: TextRange,
document: &'a Document,
- entry: &bibtex::Entry,
+ entry: &'a bib::Entry,
) -> Option<()> {
- let key = entry.name_token()?.to_string();
-
- let category = BibtexEntryType::find(&entry.type_token()?.text()[1..])
- .map_or(BibtexEntryTypeCategory::Misc, |ty| ty.category);
-
- let code = entry.syntax().text().to_string();
- let filter_text = format!(
- "{} {}",
- key,
- WHITESPACE_REGEX
- .replace_all(&code.replace(['{', '}', ',', '='], " "), " ")
- .trim(),
- );
-
- let score = self.matcher.score(&filter_text, &self.text_pattern)?;
+ let score = self.matcher.score(&entry.keywords, &self.text_pattern)?;
let data = Data::Citation {
document,
- key,
- filter_text,
- category,
+ key: &entry.name.text,
+ filter_text: &entry.keywords,
+ category: entry.category,
};
self.items.push(Item {
@@ -509,18 +524,17 @@ impl<'a> CompletionBuilder<'a> {
filter_text,
category,
} => CompletionItem {
- label: key.clone(),
+ label: key.into(),
kind: Some(Structure::Entry(category).completion_kind()),
- filter_text: Some(filter_text.clone()),
- sort_text: Some(filter_text),
+ filter_text: Some(filter_text.into()),
data: Some(
serde_json::to_value(CompletionItemData::Citation {
uri: document.uri.clone(),
- key: key.clone(),
+ key: key.into(),
})
.unwrap(),
),
- text_edit: Some(TextEdit::new(range, key).into()),
+ text_edit: Some(TextEdit::new(range, key.into()).into()),
..CompletionItem::default()
},
Data::ComponentCommand {
@@ -599,7 +613,6 @@ impl<'a> CompletionBuilder<'a> {
kind: Some(kind.completion_kind()),
detail: header,
documentation: footer.map(|footer| Documentation::String(footer.into())),
- sort_text: Some(text.clone()),
filter_text: Some(text),
text_edit: Some(TextEdit::new(range, name.into()).into()),
..CompletionItem::default()
@@ -634,16 +647,7 @@ impl<'a> CompletionBuilder<'a> {
item.kind = Some(CompletionItemKind::TEXT);
}
- let sort_prefix = format!("{:0>2}", index);
- match &item.sort_text {
- Some(sort_text) => {
- item.sort_text = Some(format!("{} {}", sort_prefix, sort_text));
- }
- None => {
- item.sort_text = Some(sort_prefix);
- }
- };
-
+ item.sort_text = Some(format!("{:0>2}", index));
item
}
@@ -693,8 +697,8 @@ enum Data<'a> {
BeginSnippet,
Citation {
document: &'a Document,
- key: String,
- filter_text: String,
+ key: &'a str,
+ filter_text: &'a str,
category: BibtexEntryTypeCategory,
},
ComponentCommand {
@@ -778,5 +782,3 @@ pub(crate) enum CompletionItemData {
Class,
Citation { uri: Url, key: String },
}
-
-static WHITESPACE_REGEX: Lazy<Regex> = Lazy::new(|| Regex::new("\\s+").unwrap());
diff --git a/support/texlab/crates/texlab/src/features/completion/citation.rs b/support/texlab/crates/texlab/src/features/completion/citation.rs
index 01afa5c28e..b22f361f36 100644
--- a/support/texlab/crates/texlab/src/features/completion/citation.rs
+++ b/support/texlab/crates/texlab/src/features/completion/citation.rs
@@ -1,6 +1,5 @@
-use base_db::DocumentData;
use rowan::{ast::AstNode, TextRange};
-use syntax::{bibtex, latex};
+use syntax::latex;
use crate::util::cursor::CursorContext;
@@ -26,12 +25,9 @@ pub fn complete<'db>(
};
check_citation(context).or_else(|| check_acronym(context))?;
- for document in &context.project.documents {
- let DocumentData::Bib(data) = &document.data else { continue };
- for entry in data.root_node().children().filter_map(bibtex::Entry::cast) {
- builder.citation(range, document, &entry);
- }
+ for document in &context.project.documents {
+ builder.citations(range, document);
}
Some(())
diff --git a/support/texlab/crates/texlab/src/features/completion/component_command.rs b/support/texlab/crates/texlab/src/features/completion/component_command.rs
index fd7ad5f9f4..3810224a38 100644
--- a/support/texlab/crates/texlab/src/features/completion/component_command.rs
+++ b/support/texlab/crates/texlab/src/features/completion/component_command.rs
@@ -13,7 +13,7 @@ pub fn complete<'db>(
builder.component_command(
range,
&command.name,
- command.image.as_deref(),
+ command.image,
command.glyph.as_deref(),
&package.file_names,
);
diff --git a/support/texlab/crates/texlab/src/features/completion/matcher.rs b/support/texlab/crates/texlab/src/features/completion/matcher.rs
index 5d5c93b2b9..fb53d1c032 100644
--- a/support/texlab/crates/texlab/src/features/completion/matcher.rs
+++ b/support/texlab/crates/texlab/src/features/completion/matcher.rs
@@ -1,9 +1,9 @@
-pub trait Matcher {
- fn score(&mut self, choice: &str, pattern: &str) -> Option<i32>;
+pub trait Matcher: Send + Sync {
+ fn score(&self, choice: &str, pattern: &str) -> Option<i32>;
}
impl<T: fuzzy_matcher::FuzzyMatcher> Matcher for T {
- fn score(&mut self, choice: &str, pattern: &str) -> Option<i32> {
+ fn score(&self, choice: &str, pattern: &str) -> Option<i32> {
fuzzy_matcher::FuzzyMatcher::fuzzy_match(self, choice, pattern)
}
}
@@ -12,7 +12,7 @@ impl<T: fuzzy_matcher::FuzzyMatcher> Matcher for T {
pub struct Prefix;
impl Matcher for Prefix {
- fn score(&mut self, choice: &str, pattern: &str) -> Option<i32> {
+ fn score(&self, choice: &str, pattern: &str) -> Option<i32> {
if choice.starts_with(pattern) {
Some(-(choice.len() as i32))
} else {
@@ -25,7 +25,7 @@ impl Matcher for Prefix {
pub struct PrefixIgnoreCase;
impl Matcher for PrefixIgnoreCase {
- fn score(&mut self, choice: &str, pattern: &str) -> Option<i32> {
+ fn score(&self, choice: &str, pattern: &str) -> Option<i32> {
if pattern.len() > choice.len() {
return None;
}
diff --git a/support/texlab/crates/texlab/src/server.rs b/support/texlab/crates/texlab/src/server.rs
index ef919bab74..5d3fc4a2b4 100644
--- a/support/texlab/crates/texlab/src/server.rs
+++ b/support/texlab/crates/texlab/src/server.rs
@@ -7,6 +7,7 @@ use std::{
collections::HashMap,
path::PathBuf,
sync::{atomic::AtomicI32, Arc},
+ time::Duration,
};
use anyhow::Result;
@@ -17,6 +18,7 @@ use diagnostics::{DiagnosticManager, DiagnosticSource};
use distro::{Distro, Language};
use lsp_server::{Connection, ErrorCode, Message, RequestId};
use lsp_types::{notification::*, request::*, *};
+use notify_debouncer_full::{DebouncedEvent, Debouncer, FileIdMap};
use parking_lot::{Mutex, RwLock};
use rowan::ast::AstNode;
use rustc_hash::{FxHashMap, FxHashSet};
@@ -49,7 +51,7 @@ use self::{
enum InternalMessage {
SetDistro(Distro),
SetOptions(Options),
- FileEvent(notify::Event),
+ FileEvent(Vec<DebouncedEvent>),
Diagnostics,
ChktexResult(Url, Vec<lsp_types::Diagnostic>),
ForwardSearch(Url, Option<Position>),
@@ -887,7 +889,8 @@ impl Server {
Ok(())
}
- fn handle_file_event(&mut self, event: notify::Event) {
+ fn handle_file_event(&mut self, debounced_event: DebouncedEvent) {
+ let event = debounced_event.event;
let mut changed = false;
let mut workspace = self.workspace.write();
@@ -1115,8 +1118,10 @@ impl Server {
InternalMessage::SetOptions(options) => {
self.update_options(options);
}
- InternalMessage::FileEvent(event) => {
- self.handle_file_event(event);
+ InternalMessage::FileEvent(events) => {
+ for event in events {
+ self.handle_file_event(event);
+ }
}
InternalMessage::Diagnostics => {
self.publish_diagnostics()?;
@@ -1143,7 +1148,7 @@ impl Server {
}
struct FileWatcher {
- watcher: notify::RecommendedWatcher,
+ watcher: Debouncer<notify::RecommendedWatcher, FileIdMap>,
watched_dirs: FxHashSet<PathBuf>,
}
@@ -1151,17 +1156,17 @@ impl FileWatcher {
pub fn new(sender: Sender<InternalMessage>) -> Result<Self> {
let handle = move |event| {
if let Ok(event) = event {
- sender.send(InternalMessage::FileEvent(event)).unwrap();
+ let _ = sender.send(InternalMessage::FileEvent(event));
}
};
Ok(Self {
- watcher: notify::recommended_watcher(handle)?,
+ watcher: notify_debouncer_full::new_debouncer(Duration::from_secs(1), None, handle)?,
watched_dirs: FxHashSet::default(),
})
}
pub fn watch(&mut self, workspace: &mut Workspace) {
- workspace.watch(&mut self.watcher, &mut self.watched_dirs);
+ workspace.watch(self.watcher.watcher(), &mut self.watched_dirs);
}
}
diff --git a/support/texlab/crates/texlab/src/server/options.rs b/support/texlab/crates/texlab/src/server/options.rs
index a602e5d792..30eff447d7 100644
--- a/support/texlab/crates/texlab/src/server/options.rs
+++ b/support/texlab/crates/texlab/src/server/options.rs
@@ -168,7 +168,7 @@ impl From<Options> for Config {
config.build.pdf_dir = value
.build
.pdf_directory
- .or_else(|| value.aux_directory)
+ .or(value.aux_directory)
.unwrap_or_else(|| String::from("."));
config.build.log_dir = value
diff --git a/support/texlab/crates/texlab/src/util/diagnostics.rs b/support/texlab/crates/texlab/src/util/diagnostics.rs
index 4a26765897..89d33060a1 100644
--- a/support/texlab/crates/texlab/src/util/diagnostics.rs
+++ b/support/texlab/crates/texlab/src/util/diagnostics.rs
@@ -17,12 +17,11 @@ pub fn collect<'db>(
source.publish(workspace, &mut builder);
builder
.iter()
- .into_iter()
.filter_map(|(uri, diags)| workspace.lookup(uri).map(|document| (document, diags)))
.map(|(document, diags)| {
let diags = diags
.into_iter()
- .map(|diag| create_diagnostic(workspace, document, &diag))
+ .map(|diag| create_diagnostic(workspace, document, diag))
.collect::<Vec<_>>();
(document, diags)
diff --git a/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__citation.snap b/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__citation.snap
index b8755fdef0..db26e6125d 100644
--- a/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__citation.snap
+++ b/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__citation.snap
@@ -1,16 +1,16 @@
---
-source: tests/lsp/text_document/completion.rs
+source: crates/texlab/tests/lsp/text_document/completion.rs
expression: "complete(r#\"\n%! main.tex\n\\documentclass{article}\n\\bibliography{main}\n\\begin{document}\n\\cite{\n |\n\\end{document}\n\n%! main.bib\n@article{foo:2019,\n author = {Foo Bar},\n title = {Baz Qux},\n year = {2019},\n}\n\n@article{bar:2005,}\"#)"
---
[
{
"label": "bar:2005",
"preselect": false,
- "filterText": "bar:2005 @article bar:2005"
+ "filterText": "bar:2005 @article"
},
{
"label": "foo:2019",
"preselect": false,
- "filterText": "foo:2019 @article foo:2019 author Foo Bar title Baz Qux year 2019"
+ "filterText": "foo:2019 @article Foo Bar Baz Qux 2019"
}
]
diff --git a/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__citation_acronym.snap b/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__citation_acronym.snap
index 36478c45c8..242d5d2a0b 100644
--- a/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__citation_acronym.snap
+++ b/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__citation_acronym.snap
@@ -1,11 +1,11 @@
---
-source: tests/lsp/text_document/completion.rs
+source: crates/texlab/tests/lsp/text_document/completion.rs
expression: "complete(r#\"\n%! main.tex\n\\addbibresource{main.bib}\n\\DeclareAcronym{foo}{cite={}}\n |\n\n%! main.bib\n@article{foo,}\"#)"
---
[
{
"label": "foo",
"preselect": false,
- "filterText": "foo @article foo"
+ "filterText": "foo @article"
}
]
diff --git a/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__citation_open_brace.snap b/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__citation_open_brace.snap
index 41a1d9ced3..b205903a04 100644
--- a/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__citation_open_brace.snap
+++ b/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__citation_open_brace.snap
@@ -1,11 +1,11 @@
---
-source: tests/lsp/text_document/completion.rs
+source: crates/texlab/tests/lsp/text_document/completion.rs
expression: "complete(r#\"\n%! main.tex\n\\addbibresource{main.bib}\n\\cite{\n |\n\n%! main.bib\n@article{foo,}\"#)"
---
[
{
"label": "foo",
"preselect": false,
- "filterText": "foo @article foo"
+ "filterText": "foo @article"
}
]
diff --git a/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__citation_open_brace_multiple.snap b/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__citation_open_brace_multiple.snap
index 8ef509b463..519fa60fa6 100644
--- a/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__citation_open_brace_multiple.snap
+++ b/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__citation_open_brace_multiple.snap
@@ -1,11 +1,11 @@
---
-source: tests/lsp/text_document/completion.rs
+source: crates/texlab/tests/lsp/text_document/completion.rs
expression: "complete(r#\"\n%! main.tex\n\\addbibresource{main.bib}\n\\cite{foo,a\n |\n ^\n\n%! main.bib\n@article{foo,}\"#)"
---
[
{
"label": "foo",
"preselect": false,
- "filterText": "foo @article foo"
+ "filterText": "foo @article"
}
]
diff --git a/support/texlab/texlab.1 b/support/texlab/texlab.1
index 7d5e82cd43..9910cd0bb8 100644
--- a/support/texlab/texlab.1
+++ b/support/texlab/texlab.1
@@ -1,7 +1,7 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.13.
-.TH TEXLAB "1" "August 2023" "texlab 5.9.0" "User Commands"
+.TH TEXLAB "1" "August 2023" "texlab 5.9.1" "User Commands"
.SH NAME
-texlab \- manual page for texlab 5.9.0
+texlab \- manual page for texlab 5.9.1
.SH SYNOPSIS
.B texlab
[\fI\,OPTIONS\/\fR]
diff --git a/support/texlab/texlab.pdf b/support/texlab/texlab.pdf
index 71e172b73b..74092ac147 100644
--- a/support/texlab/texlab.pdf
+++ b/support/texlab/texlab.pdf
Binary files differ