summaryrefslogtreecommitdiff
path: root/support/texlab/crates
diff options
context:
space:
mode:
Diffstat (limited to 'support/texlab/crates')
-rw-r--r--support/texlab/crates/base-db/Cargo.toml8
-rw-r--r--support/texlab/crates/base-db/src/config.rs54
-rw-r--r--support/texlab/crates/base-db/src/deps/graph.rs87
-rw-r--r--support/texlab/crates/base-db/src/deps/root.rs4
-rw-r--r--support/texlab/crates/base-db/src/document.rs17
-rw-r--r--support/texlab/crates/base-db/src/semantics/auxiliary.rs2
-rw-r--r--support/texlab/crates/base-db/src/semantics/tex.rs123
-rw-r--r--support/texlab/crates/base-db/src/workspace.rs2
-rw-r--r--support/texlab/crates/bibfmt/src/lib.rs6
-rw-r--r--support/texlab/crates/bibtex-utils/Cargo.toml6
-rw-r--r--support/texlab/crates/citeproc/Cargo.toml4
-rw-r--r--support/texlab/crates/commands/Cargo.toml14
-rw-r--r--support/texlab/crates/commands/src/dep_graph.rs1
-rw-r--r--support/texlab/crates/commands/src/find_envs.rs2
-rw-r--r--support/texlab/crates/commands/src/fwd_search.rs2
-rw-r--r--support/texlab/crates/commands/src/placeholders.rs2
-rw-r--r--support/texlab/crates/completion-data/Cargo.toml10
-rw-r--r--support/texlab/crates/completion/Cargo.toml3
-rw-r--r--support/texlab/crates/completion/src/lib.rs8
-rw-r--r--support/texlab/crates/completion/src/providers/argument.rs2
-rw-r--r--support/texlab/crates/completion/src/providers/color.rs2
-rw-r--r--support/texlab/crates/completion/src/providers/color_model.rs2
-rw-r--r--support/texlab/crates/completion/src/providers/command.rs4
-rw-r--r--support/texlab/crates/completion/src/providers/environment.rs6
-rw-r--r--support/texlab/crates/completion/src/providers/glossary.rs2
-rw-r--r--support/texlab/crates/completion/src/providers/import.rs8
-rw-r--r--support/texlab/crates/completion/src/providers/include.rs6
-rw-r--r--support/texlab/crates/completion/src/providers/label_ref.rs46
-rw-r--r--support/texlab/crates/completion/src/providers/tikz_library.rs2
-rw-r--r--support/texlab/crates/completion/src/tests.rs213
-rw-r--r--support/texlab/crates/definition/Cargo.toml4
-rw-r--r--support/texlab/crates/definition/src/command.rs12
-rw-r--r--support/texlab/crates/definition/src/tests.rs2
-rw-r--r--support/texlab/crates/diagnostics/Cargo.toml8
-rw-r--r--support/texlab/crates/diagnostics/src/chktex.rs2
-rw-r--r--support/texlab/crates/diagnostics/src/citations.rs6
-rw-r--r--support/texlab/crates/diagnostics/src/manager.rs10
-rw-r--r--support/texlab/crates/diagnostics/src/tests.rs4
-rw-r--r--support/texlab/crates/distro/Cargo.toml4
-rw-r--r--support/texlab/crates/distro/src/language.rs2
-rw-r--r--support/texlab/crates/highlights/src/lib.rs2
-rw-r--r--support/texlab/crates/hover/src/lib.rs12
-rw-r--r--support/texlab/crates/inlay-hints/Cargo.toml2
-rw-r--r--support/texlab/crates/inlay-hints/src/label.rs1
-rw-r--r--support/texlab/crates/ipc/Cargo.toml8
-rw-r--r--support/texlab/crates/line-index/Cargo.toml2
-rw-r--r--support/texlab/crates/parser/Cargo.toml8
-rw-r--r--support/texlab/crates/parser/src/bibtex.rs54
-rw-r--r--support/texlab/crates/parser/src/bibtex/tests.rs277
-rw-r--r--support/texlab/crates/parser/src/build_log.rs2
-rw-r--r--support/texlab/crates/parser/src/config.rs26
-rw-r--r--support/texlab/crates/parser/src/file_list.rs44
-rw-r--r--support/texlab/crates/parser/src/latex/lexer/types.rs49
-rw-r--r--support/texlab/crates/parser/src/latexmkrc.rs8
-rw-r--r--support/texlab/crates/parser/src/lib.rs6
-rw-r--r--support/texlab/crates/parser/src/util.rs52
-rw-r--r--support/texlab/crates/references/Cargo.toml2
-rw-r--r--support/texlab/crates/references/src/command.rs2
-rw-r--r--support/texlab/crates/references/src/entry.rs4
-rw-r--r--support/texlab/crates/references/src/label.rs2
-rw-r--r--support/texlab/crates/rename/Cargo.toml3
-rw-r--r--support/texlab/crates/rename/src/command.rs7
-rw-r--r--support/texlab/crates/rename/src/entry.rs4
-rw-r--r--support/texlab/crates/rename/src/label.rs47
-rw-r--r--support/texlab/crates/rename/src/lib.rs30
-rw-r--r--support/texlab/crates/rename/src/tests.rs111
-rw-r--r--support/texlab/crates/symbols/Cargo.toml4
-rw-r--r--support/texlab/crates/symbols/src/document.rs1
-rw-r--r--support/texlab/crates/syntax/Cargo.toml3
-rw-r--r--support/texlab/crates/syntax/src/file_list.rs10
-rw-r--r--support/texlab/crates/syntax/src/lib.rs1
-rw-r--r--support/texlab/crates/texlab/Cargo.toml22
-rw-r--r--support/texlab/crates/texlab/src/features/folding.rs2
-rw-r--r--support/texlab/crates/texlab/src/features/formatting.rs3
-rw-r--r--support/texlab/crates/texlab/src/features/rename.rs2
-rw-r--r--support/texlab/crates/texlab/src/main.rs1
-rw-r--r--support/texlab/crates/texlab/src/server.rs20
-rw-r--r--support/texlab/crates/texlab/src/server/extensions.rs28
-rw-r--r--support/texlab/crates/texlab/src/server/options.rs7
-rw-r--r--support/texlab/crates/texlab/src/util.rs61
-rw-r--r--support/texlab/crates/texlab/src/util/client_flags.rs6
-rw-r--r--support/texlab/crates/texlab/src/util/from_proto.rs80
-rw-r--r--support/texlab/crates/texlab/src/util/to_proto.rs11
83 files changed, 1313 insertions, 416 deletions
diff --git a/support/texlab/crates/base-db/Cargo.toml b/support/texlab/crates/base-db/Cargo.toml
index ca477c496c..547ba2ad77 100644
--- a/support/texlab/crates/base-db/Cargo.toml
+++ b/support/texlab/crates/base-db/Cargo.toml
@@ -10,16 +10,16 @@ rust-version.workspace = true
bibtex-utils = { path = "../bibtex-utils" }
dirs = "5.0.1"
distro = { path = "../distro" }
-itertools = "0.12.1"
+itertools = "0.13.0"
line-index = { path = "../line-index" }
-log = "0.4.21"
+log = "0.4.22"
notify = "6.0.1"
once_cell = "1.19.0"
parser = { path = "../parser" }
percent-encoding = "2.3.0"
-regex = "1.10.4"
+regex = "1.10.5"
rowan = "0.15.15"
-rustc-hash = "1.1.0"
+rustc-hash = "2.0.0"
shellexpand = "3.1.0"
syntax = { path = "../syntax" }
titlecase = "3.0.0"
diff --git a/support/texlab/crates/base-db/src/config.rs b/support/texlab/crates/base-db/src/config.rs
index 9814e3e674..e4c827e61c 100644
--- a/support/texlab/crates/base-db/src/config.rs
+++ b/support/texlab/crates/base-db/src/config.rs
@@ -3,9 +3,8 @@ use std::time::Duration;
use parser::SyntaxConfig;
use regex::Regex;
-#[derive(Debug)]
+#[derive(Debug, Default)]
pub struct Config {
- pub root_dir: Option<String>,
pub build: BuildConfig,
pub diagnostics: DiagnosticsConfig,
pub formatting: FormattingConfig,
@@ -36,7 +35,7 @@ pub struct DiagnosticsConfig {
pub delay: Duration,
}
-#[derive(Debug)]
+#[derive(Debug, Default)]
pub struct ChktexConfig {
pub on_open: bool,
pub on_save: bool,
@@ -65,13 +64,13 @@ pub enum Formatter {
LatexIndent,
}
-#[derive(Debug)]
+#[derive(Debug, Default)]
pub struct LatexIndentConfig {
pub local: Option<String>,
pub modify_line_breaks: bool,
}
-#[derive(Debug)]
+#[derive(Debug, Default)]
pub struct SymbolConfig {
pub allowed_patterns: Vec<Regex>,
pub ignored_patterns: Vec<Regex>,
@@ -96,22 +95,6 @@ pub enum MatchingAlgo {
PrefixIgnoreCase,
}
-impl Default for Config {
- fn default() -> Self {
- Self {
- root_dir: None,
- build: BuildConfig::default(),
- diagnostics: DiagnosticsConfig::default(),
- formatting: FormattingConfig::default(),
- synctex: None,
- symbols: SymbolConfig::default(),
- syntax: SyntaxConfig::default(),
- completion: CompletionConfig::default(),
- inlay_hints: InlayHintConfig::default(),
- }
- }
-}
-
impl Default for BuildConfig {
fn default() -> Self {
Self {
@@ -141,17 +124,6 @@ impl Default for DiagnosticsConfig {
}
}
-impl Default for ChktexConfig {
- fn default() -> Self {
- Self {
- on_open: false,
- on_save: false,
- on_edit: false,
- additional_args: Vec::new(),
- }
- }
-}
-
impl Default for FormattingConfig {
fn default() -> Self {
Self {
@@ -163,24 +135,6 @@ impl Default for FormattingConfig {
}
}
-impl Default for LatexIndentConfig {
- fn default() -> Self {
- Self {
- local: None,
- modify_line_breaks: false,
- }
- }
-}
-
-impl Default for SymbolConfig {
- fn default() -> Self {
- Self {
- allowed_patterns: Vec::new(),
- ignored_patterns: Vec::new(),
- }
- }
-}
-
impl Default for InlayHintConfig {
fn default() -> Self {
Self {
diff --git a/support/texlab/crates/base-db/src/deps/graph.rs b/support/texlab/crates/base-db/src/deps/graph.rs
index e07368d078..0d8252688d 100644
--- a/support/texlab/crates/base-db/src/deps/graph.rs
+++ b/support/texlab/crates/base-db/src/deps/graph.rs
@@ -1,4 +1,4 @@
-use std::{ffi::OsStr, path::PathBuf, rc::Rc};
+use std::{ffi::OsStr, path::PathBuf, rc::Rc, sync::Arc};
use distro::Language;
use itertools::Itertools;
@@ -22,7 +22,8 @@ pub struct Edge {
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub enum EdgeData {
- DirectLink(DirectLinkData),
+ DirectLink(Box<DirectLinkData>),
+ FileList(Arc<ProjectRoot>),
AdditionalFiles,
Artifact,
}
@@ -74,6 +75,7 @@ impl Graph {
if visited.insert(edge.target.clone()) {
let new_root = match &edge.data {
EdgeData::DirectLink(data) => data.new_root.clone(),
+ EdgeData::FileList(root) => Some(root.as_ref().clone()),
_ => None,
};
@@ -101,6 +103,10 @@ impl Graph {
self.add_direct_links(workspace, start);
self.add_artifacts(workspace, start);
self.add_additional_files(workspace, start);
+
+ if workspace.config().syntax.use_file_list {
+ self.add_file_list_links(workspace, start);
+ }
}
fn add_additional_files(&mut self, workspace: &Workspace, start: Start) {
@@ -120,6 +126,43 @@ impl Graph {
}
}
+ fn add_file_list_links(&mut self, workspace: &Workspace, start: Start) -> Option<()> {
+ let file_list = start.source.data.as_file_list()?;
+ let home_dir = HOME_DIR.as_deref();
+
+ let working_dir = file_list
+ .working_dir
+ .as_deref()
+ .and_then(|dir| Url::from_directory_path(dir).ok());
+
+ let working_dir = working_dir.as_ref().unwrap_or(&start.source.dir);
+ let new_root = Arc::new(ProjectRoot::from_config(workspace, working_dir));
+
+ for target_uri in file_list
+ .inputs
+ .iter()
+ .chain(file_list.outputs.iter())
+ .filter(|path| {
+ path.is_relative()
+ || Language::from_path(&path) == Some(Language::Bib)
+ || home_dir.map_or(false, |home_dir| path.starts_with(home_dir))
+ })
+ .filter_map(|path| working_dir.join(path.to_str()?).ok())
+ {
+ if workspace.lookup(&target_uri).is_some() {
+ self.edges.push(Edge {
+ source: start.source.uri.clone(),
+ target: target_uri,
+ data: EdgeData::FileList(Arc::clone(&new_root)),
+ });
+ } else {
+ self.missing.push(target_uri);
+ }
+ }
+
+ Some(())
+ }
+
fn add_direct_links(&mut self, workspace: &Workspace, start: Start) -> Option<()> {
let data = start.source.data.as_tex()?;
@@ -159,7 +202,7 @@ impl Graph {
for target_uri in file_names
.iter()
.flat_map(|file_name| {
- util::expand_relative_path(&file_name, &start.root.src_dir, workspace.folders())
+ util::expand_relative_path(file_name, &start.root.src_dir, workspace.folders())
})
.chain(distro_files)
{
@@ -169,7 +212,7 @@ impl Graph {
.base_dir
.as_deref()
.and_then(|path| start.root.src_dir.join(path).ok())
- .map(|dir| ProjectRoot::walk_and_find(workspace, &dir));
+ .map(|dir| ProjectRoot::from_config(workspace, &dir));
let link_data = DirectLinkData {
link: link.clone(),
@@ -179,7 +222,7 @@ impl Graph {
self.edges.push(Edge {
source: start.source.uri.clone(),
target: target.uri.clone(),
- data: EdgeData::DirectLink(link_data),
+ data: EdgeData::DirectLink(Box::new(link_data)),
});
break;
@@ -197,27 +240,33 @@ impl Graph {
}
let root = start.root;
- let relative_path = root.compile_dir.make_relative(&start.source.uri).unwrap();
-
- self.add_artifact(
- workspace,
- start.source,
- &root.aux_dir.join(&relative_path).unwrap(),
- "aux",
- );
+ self.add_artifact_group(workspace, start, &root.aux_dir, "aux");
+ self.add_artifact_group(workspace, start, &root.log_dir, "log");
+ self.add_artifact_group(workspace, start, &root.aux_dir, "fls");
+ }
- self.add_artifact(workspace, start.source, &root.aux_dir, "aux");
- self.add_artifact(workspace, start.source, &root.compile_dir, "aux");
+ fn add_artifact_group(
+ &mut self,
+ workspace: &Workspace,
+ start: Start,
+ dir: &Url,
+ extension: &str,
+ ) {
+ let relative_path = start
+ .root
+ .compile_dir
+ .make_relative(&start.source.uri)
+ .unwrap();
self.add_artifact(
workspace,
start.source,
- &root.log_dir.join(&relative_path).unwrap(),
- "log",
+ &dir.join(&relative_path).unwrap(),
+ extension,
);
- self.add_artifact(workspace, start.source, &root.log_dir, "log");
- self.add_artifact(workspace, start.source, &root.compile_dir, "log");
+ self.add_artifact(workspace, start.source, &dir, extension);
+ self.add_artifact(workspace, start.source, &start.root.compile_dir, extension);
}
fn add_artifact(
diff --git a/support/texlab/crates/base-db/src/deps/root.rs b/support/texlab/crates/base-db/src/deps/root.rs
index a8cec6604a..03fd41a9a0 100644
--- a/support/texlab/crates/base-db/src/deps/root.rs
+++ b/support/texlab/crates/base-db/src/deps/root.rs
@@ -31,11 +31,11 @@ impl ProjectRoot {
}
let Ok(parent) = current.join("..") else {
- break Self::from_config(workspace, &dir);
+ break Self::from_config(workspace, dir);
};
if current == parent || Some(&parent) == home_dir.as_ref() {
- break Self::from_config(workspace, &dir);
+ break Self::from_config(workspace, dir);
}
current = parent;
diff --git a/support/texlab/crates/base-db/src/document.rs b/support/texlab/crates/base-db/src/document.rs
index 7a388129fd..6fdcf30c16 100644
--- a/support/texlab/crates/base-db/src/document.rs
+++ b/support/texlab/crates/base-db/src/document.rs
@@ -3,7 +3,7 @@ use std::path::PathBuf;
use distro::Language;
use line_index::{LineCol, LineIndex};
use rowan::TextRange;
-use syntax::{bibtex, latex, latexmkrc::LatexmkrcData, BuildError};
+use syntax::{bibtex, file_list::FileList, latex, latexmkrc::LatexmkrcData, BuildError};
use url::Url;
use crate::{semantics, Config};
@@ -56,7 +56,10 @@ impl Document {
Language::Tex => {
let green = parser::parse_latex(&text, &params.config.syntax);
let mut semantics = semantics::tex::Semantics::default();
- semantics.process_root(&latex::SyntaxNode::new_root(green.clone()));
+ semantics.process_root(
+ &params.config.syntax,
+ &latex::SyntaxNode::new_root(green.clone()),
+ );
DocumentData::Tex(TexDocumentData { green, semantics })
}
Language::Bib => {
@@ -86,6 +89,7 @@ impl Document {
DocumentData::Latexmkrc(data)
}
Language::Tectonic => DocumentData::Tectonic,
+ Language::FileList => DocumentData::FileList(parser::parse_file_list(&text)),
};
Self {
@@ -143,6 +147,7 @@ pub enum DocumentData {
Root,
Latexmkrc(LatexmkrcData),
Tectonic,
+ FileList(FileList),
}
impl DocumentData {
@@ -185,6 +190,14 @@ impl DocumentData {
None
}
}
+
+ pub fn as_file_list(&self) -> Option<&FileList> {
+ if let DocumentData::FileList(data) = self {
+ Some(data)
+ } else {
+ None
+ }
+ }
}
#[derive(Debug, Clone)]
diff --git a/support/texlab/crates/base-db/src/semantics/auxiliary.rs b/support/texlab/crates/base-db/src/semantics/auxiliary.rs
index 489a7d1ac6..8c9fe012e6 100644
--- a/support/texlab/crates/base-db/src/semantics/auxiliary.rs
+++ b/support/texlab/crates/base-db/src/semantics/auxiliary.rs
@@ -36,7 +36,7 @@ impl Semantics {
Some(group)
})?;
- let text = group.content_text()?.replace('{', "").replace('}', "");
+ let text = group.content_text()?.replace(['{', '}'], "");
self.label_numbers.insert(name, text);
Some(())
}
diff --git a/support/texlab/crates/base-db/src/semantics/tex.rs b/support/texlab/crates/base-db/src/semantics/tex.rs
index 1ad8969a80..a1301091d4 100644
--- a/support/texlab/crates/base-db/src/semantics/tex.rs
+++ b/support/texlab/crates/base-db/src/semantics/tex.rs
@@ -3,7 +3,28 @@ use rustc_hash::FxHashSet;
use syntax::latex::{self, HasBrack, HasCurly};
use titlecase::titlecase;
+use parser::SyntaxConfig;
+
use super::Span;
+use crate::semantics::tex::latex::SyntaxToken;
+
+fn maybe_prepend_prefix(
+ map: &Vec<(String, String)>,
+ command: &Option<SyntaxToken>,
+ name: &Span,
+) -> Span {
+ match command {
+ Some(x) => Span::new(
+ map.iter()
+ .find_map(|(k, v)| if k == &x.text()[1..] { Some(v) } else { None })
+ .unwrap_or(&String::new())
+ .to_owned()
+ + &name.text,
+ name.range,
+ ),
+ None => name.clone(),
+ }
+}
#[derive(Debug, Clone, Default)]
pub struct Semantics {
@@ -19,11 +40,11 @@ pub struct Semantics {
}
impl Semantics {
- pub fn process_root(&mut self, root: &latex::SyntaxNode) {
+ pub fn process_root(&mut self, conf: &SyntaxConfig, root: &latex::SyntaxNode) {
for node in root.descendants_with_tokens() {
match node {
latex::SyntaxElement::Node(node) => {
- self.process_node(&node);
+ self.process_node(conf, &node);
}
latex::SyntaxElement::Token(token) => {
if token.kind() == latex::COMMAND_NAME {
@@ -40,17 +61,17 @@ impl Semantics {
.any(|link| link.kind == LinkKind::Cls && link.path.text == "subfiles");
}
- fn process_node(&mut self, node: &latex::SyntaxNode) {
+ fn process_node(&mut self, conf: &SyntaxConfig, node: &latex::SyntaxNode) {
if let Some(include) = latex::Include::cast(node.clone()) {
self.process_include(include);
} else if let Some(import) = latex::Import::cast(node.clone()) {
self.process_import(import);
} else if let Some(label) = latex::LabelDefinition::cast(node.clone()) {
- self.process_label_definition(label);
+ self.process_label_definition(conf, label);
} else if let Some(label) = latex::LabelReference::cast(node.clone()) {
- self.process_label_reference(label);
+ self.process_label_reference(conf, label);
} else if let Some(label) = latex::LabelReferenceRange::cast(node.clone()) {
- self.process_label_reference_range(label);
+ self.process_label_reference_range(conf, label);
} else if let Some(citation) = latex::Citation::cast(node.clone()) {
self.process_citation(citation);
} else if let Some(environment) = latex::Environment::cast(node.clone()) {
@@ -111,11 +132,16 @@ impl Semantics {
});
}
- fn process_label_definition(&mut self, label: latex::LabelDefinition) {
+ fn process_label_definition(&mut self, conf: &SyntaxConfig, label: latex::LabelDefinition) {
let Some(name) = label.name().and_then(|group| group.key()) else {
return;
};
+ let name = Span::from(&name);
+ if name.text.contains('#') {
+ return;
+ }
+
let full_range = latex::small_range(&label);
let mut objects = Vec::new();
for node in label.syntax().ancestors() {
@@ -185,46 +211,75 @@ impl Semantics {
self.labels.push(Label {
kind: LabelKind::Definition,
- name: Span::from(&name),
+ cmd: label.command().map(|x| x.text()[1..].to_string()),
+ name: maybe_prepend_prefix(&conf.label_definition_prefixes, &label.command(), &name),
targets: objects,
full_range,
});
}
- fn process_label_reference(&mut self, label: latex::LabelReference) {
+ fn process_label_reference(&mut self, conf: &SyntaxConfig, label: latex::LabelReference) {
let Some(name_list) = label.name_list() else {
return;
};
let full_range = latex::small_range(&label);
for name in name_list.keys() {
- self.labels.push(Label {
- kind: LabelKind::Reference,
- name: Span::from(&name),
- targets: Vec::new(),
- full_range,
- });
+ let name = Span::from(&name);
+ if !name.text.contains('#') {
+ self.labels.push(Label {
+ kind: LabelKind::Reference,
+ cmd: label.command().map(|x| x.text()[1..].to_string()),
+ name: maybe_prepend_prefix(
+ &conf.label_reference_prefixes,
+ &label.command(),
+ &name,
+ ),
+ targets: Vec::new(),
+ full_range,
+ });
+ }
}
}
- fn process_label_reference_range(&mut self, label: latex::LabelReferenceRange) {
+ fn process_label_reference_range(
+ &mut self,
+ conf: &SyntaxConfig,
+ label: latex::LabelReferenceRange,
+ ) {
let full_range = latex::small_range(&label);
if let Some(from) = label.from().and_then(|group| group.key()) {
- self.labels.push(Label {
- kind: LabelKind::ReferenceRange,
- name: Span::from(&from),
- targets: Vec::new(),
- full_range,
- });
+ let name = Span::from(&from);
+ if !name.text.contains('#') {
+ self.labels.push(Label {
+ kind: LabelKind::ReferenceRange,
+ cmd: label.command().map(|x| x.text()[1..].to_string()),
+ name: maybe_prepend_prefix(
+ &conf.label_reference_prefixes,
+ &label.command(),
+ &name,
+ ),
+ targets: Vec::new(),
+ full_range,
+ });
+ }
}
if let Some(to) = label.to().and_then(|group| group.key()) {
- self.labels.push(Label {
- kind: LabelKind::ReferenceRange,
- name: Span::from(&to),
- targets: Vec::new(),
- full_range,
- });
+ let name = Span::from(&to);
+ if !name.text.contains('#') {
+ self.labels.push(Label {
+ kind: LabelKind::ReferenceRange,
+ cmd: label.command().map(|x| x.text()[1..].to_string()),
+ name: maybe_prepend_prefix(
+ &conf.label_reference_prefixes,
+ &label.command(),
+ &name,
+ ),
+ targets: Vec::new(),
+ full_range,
+ });
+ }
}
}
@@ -232,10 +287,13 @@ impl Semantics {
let full_range = latex::small_range(&citation);
if let Some(list) = citation.key_list() {
for key in list.keys() {
- self.citations.push(Citation {
- name: Span::from(&key),
- full_range,
- });
+ let name = Span::from(&key);
+ if !name.text.contains('#') {
+ self.citations.push(Citation {
+ name: Span::from(&key),
+ full_range,
+ });
+ }
}
}
}
@@ -319,6 +377,7 @@ pub enum LabelKind {
#[derive(Debug, Clone)]
pub struct Label {
pub kind: LabelKind,
+ pub cmd: Option<String>,
pub name: Span,
pub targets: Vec<LabelTarget>,
pub full_range: TextRange,
diff --git a/support/texlab/crates/base-db/src/workspace.rs b/support/texlab/crates/base-db/src/workspace.rs
index 75674dcf8d..f2564ed415 100644
--- a/support/texlab/crates/base-db/src/workspace.rs
+++ b/support/texlab/crates/base-db/src/workspace.rs
@@ -99,7 +99,7 @@ impl Workspace {
Cow::Owned(text) => text,
};
- let owner = if self.distro.file_name_db.contains(&path) {
+ let owner = if self.distro.file_name_db.contains(path) {
Owner::Distro
} else {
Owner::Server
diff --git a/support/texlab/crates/bibfmt/src/lib.rs b/support/texlab/crates/bibfmt/src/lib.rs
index cfce131f2c..8840daa1c4 100644
--- a/support/texlab/crates/bibfmt/src/lib.rs
+++ b/support/texlab/crates/bibfmt/src/lib.rs
@@ -11,7 +11,7 @@ pub struct Options {
impl Options {
fn indent(&self) -> String {
if self.insert_spaces {
- std::iter::repeat(' ').take(self.tab_size).collect()
+ " ".repeat(self.tab_size)
} else {
String::from("\t")
}
@@ -126,7 +126,7 @@ impl<'a> Formatter<'a> {
}
bibtex::FIELD => {
let field = bibtex::Field::cast(parent).unwrap();
- self.output.push_str(&self.indent);
+ self.output.push_str(self.indent);
let name = field.name_token().unwrap();
self.output.push_str(name.text());
self.output.push_str(" = ");
@@ -160,7 +160,7 @@ impl<'a> Formatter<'a> {
if length + current_length + space_length > self.options.line_length {
self.output.push('\n');
self.output.push_str(self.indent.as_ref());
- for _ in 0..=align - self.options.tab_size as usize {
+ for _ in 0..=align - self.options.tab_size {
self.output.push(' ');
}
length = align;
diff --git a/support/texlab/crates/bibtex-utils/Cargo.toml b/support/texlab/crates/bibtex-utils/Cargo.toml
index 97e13517f5..88ba2d3a37 100644
--- a/support/texlab/crates/bibtex-utils/Cargo.toml
+++ b/support/texlab/crates/bibtex-utils/Cargo.toml
@@ -7,11 +7,11 @@ edition.workspace = true
rust-version.workspace = true
[dependencies]
-chrono = { version = "0.4.26", default-features = false, features = ["std"] }
+chrono = { version = "0.4.38", default-features = false, features = ["std"] }
human_name = "2.0.3"
-itertools = "0.12.1"
+itertools = "0.13.0"
rowan = "0.15.15"
-rustc-hash = "1.1.0"
+rustc-hash = "2.0.0"
syntax = { path = "../syntax" }
unicode-normalization = "0.1.23"
diff --git a/support/texlab/crates/citeproc/Cargo.toml b/support/texlab/crates/citeproc/Cargo.toml
index 9e187f88e6..c87ab14b0e 100644
--- a/support/texlab/crates/citeproc/Cargo.toml
+++ b/support/texlab/crates/citeproc/Cargo.toml
@@ -10,9 +10,9 @@ rust-version.workspace = true
bibtex-utils = { path = "../bibtex-utils" }
base-db = { path = "../base-db" }
isocountry = "0.3.2"
-itertools = "0.12.1"
+itertools = "0.13.0"
rowan = "0.15.15"
-rustc-hash = "1.1.0"
+rustc-hash = "2.0.0"
syntax = { path = "../syntax" }
titlecase = "3.0.0"
unicode-normalization = "0.1.23"
diff --git a/support/texlab/crates/commands/Cargo.toml b/support/texlab/crates/commands/Cargo.toml
index c726e5f0d5..6507efb3b8 100644
--- a/support/texlab/crates/commands/Cargo.toml
+++ b/support/texlab/crates/commands/Cargo.toml
@@ -7,17 +7,17 @@ edition.workspace = true
rust-version.workspace = true
[dependencies]
-anyhow = "1.0.82"
+anyhow = "1.0.86"
base-db = { path = "../base-db" }
bstr = "1.9.1"
-crossbeam-channel = "0.5.12"
-itertools = "0.12.1"
-libc = "0.2.153"
-log = "0.4.21"
+crossbeam-channel = "0.5.13"
+itertools = "0.13.0"
+libc = "0.2.155"
+log = "0.4.22"
rowan = "0.15.15"
-rustc-hash = "1.1.0"
+rustc-hash = "2.0.0"
syntax = { path = "../syntax" }
-thiserror = "1.0.59"
+thiserror = "1.0.61"
url = "2.5.0"
[dev-dependencies]
diff --git a/support/texlab/crates/commands/src/dep_graph.rs b/support/texlab/crates/commands/src/dep_graph.rs
index fe9ff3829c..86b49da0ac 100644
--- a/support/texlab/crates/commands/src/dep_graph.rs
+++ b/support/texlab/crates/commands/src/dep_graph.rs
@@ -48,6 +48,7 @@ pub fn show_dependency_graph(workspace: &Workspace) -> Result<String> {
base_db::deps::EdgeData::DirectLink(data) => &data.link.path.text,
base_db::deps::EdgeData::AdditionalFiles => "<project>",
base_db::deps::EdgeData::Artifact => "<artifact>",
+ base_db::deps::EdgeData::FileList(_) => "<fls>",
};
writeln!(&mut writer, "\t{source} -> {target} [label=\"{label}\"];")?;
diff --git a/support/texlab/crates/commands/src/find_envs.rs b/support/texlab/crates/commands/src/find_envs.rs
index 7a17345d80..1ea88657ab 100644
--- a/support/texlab/crates/commands/src/find_envs.rs
+++ b/support/texlab/crates/commands/src/find_envs.rs
@@ -53,7 +53,7 @@ mod tests {
let workspace = fixture.workspace;
let document = workspace.iter().next().unwrap();
let offset = fixture.documents[0].cursor.unwrap();
- let results = find_environments(&document, offset);
+ let results = find_environments(document, offset);
expect.assert_debug_eq(&results);
}
diff --git a/support/texlab/crates/commands/src/fwd_search.rs b/support/texlab/crates/commands/src/fwd_search.rs
index f1991cd48e..f3480ef3e2 100644
--- a/support/texlab/crates/commands/src/fwd_search.rs
+++ b/support/texlab/crates/commands/src/fwd_search.rs
@@ -103,7 +103,7 @@ impl ForwardSearch {
})
.ok_or_else(|| ForwardSearchError::InvalidPath(document.uri.clone()))?;
- let pdf_path = pdf_dir.join(&pdf_name);
+ let pdf_path = pdf_dir.join(pdf_name);
let pdf_exists = pdf_path.exists();
log::debug!("[FwdSearch] pdf_path={pdf_path:?}, pdf_exists={pdf_exists}");
diff --git a/support/texlab/crates/commands/src/placeholders.rs b/support/texlab/crates/commands/src/placeholders.rs
index 9994420f5d..328a95773a 100644
--- a/support/texlab/crates/commands/src/placeholders.rs
+++ b/support/texlab/crates/commands/src/placeholders.rs
@@ -45,6 +45,6 @@ mod tests {
&[('f', "foo")],
);
- assert_eq!(output, vec!["foo".into(), "%f", "%f".into(), "foobar"]);
+ assert_eq!(output, vec!["foo", "%f", "%f", "foobar"]);
}
}
diff --git a/support/texlab/crates/completion-data/Cargo.toml b/support/texlab/crates/completion-data/Cargo.toml
index 59b707e474..6dbb7d4086 100644
--- a/support/texlab/crates/completion-data/Cargo.toml
+++ b/support/texlab/crates/completion-data/Cargo.toml
@@ -7,12 +7,12 @@ edition.workspace = true
rust-version.workspace = true
[dependencies]
-flate2 = "1.0.29"
-itertools = "0.12.1"
+flate2 = "1.0.30"
+itertools = "0.13.0"
once_cell = "1.19.0"
-rustc-hash = "1.1.0"
-serde = { version = "1.0.195", features = ["derive"] }
-serde_json = "1.0.115"
+rustc-hash = "2.0.0"
+serde = { version = "1.0.203", features = ["derive"] }
+serde_json = "1.0.119"
[lib]
doctest = false
diff --git a/support/texlab/crates/completion/Cargo.toml b/support/texlab/crates/completion/Cargo.toml
index e28e04dfc7..f98f12260b 100644
--- a/support/texlab/crates/completion/Cargo.toml
+++ b/support/texlab/crates/completion/Cargo.toml
@@ -13,7 +13,7 @@ fuzzy-matcher = { version = "0.3.7", features = ["compact"] }
line-index = { path = "../line-index" }
rayon = "1.10.0"
rowan = "0.15.15"
-rustc-hash = "1.1.0"
+rustc-hash = "2.0.0"
syntax = { path = "../syntax" }
url = "2.5.0"
@@ -22,6 +22,7 @@ criterion = "0.5.1"
distro = { path = "../distro" }
expect-test = "1.5.0"
test-utils = { path = "../test-utils" }
+parser = { path = "../parser" }
[lib]
doctest = false
diff --git a/support/texlab/crates/completion/src/lib.rs b/support/texlab/crates/completion/src/lib.rs
index 7fc5bba174..5bfd94d944 100644
--- a/support/texlab/crates/completion/src/lib.rs
+++ b/support/texlab/crates/completion/src/lib.rs
@@ -72,12 +72,12 @@ impl<'a> CompletionItemData<'a> {
Self::Citation(data) => &data.entry.name.text,
Self::Environment(data) => data.name,
Self::GlossaryEntry(data) => &data.name,
- Self::Label(data) => data.name,
+ Self::Label(data) => &data.name,
Self::Color(name) => name,
Self::ColorModel(name) => name,
- Self::File(name) => &name,
- Self::Directory(name) => &name,
- Self::Argument(data) => &data.0.name,
+ Self::File(name) => name,
+ Self::Directory(name) => name,
+ Self::Argument(data) => data.0.name,
Self::Package(name) => name,
Self::DocumentClass(name) => name,
Self::EntryType(data) => data.0.name,
diff --git a/support/texlab/crates/completion/src/providers/argument.rs b/support/texlab/crates/completion/src/providers/argument.rs
index 6637cecdd6..a9c8f4304b 100644
--- a/support/texlab/crates/completion/src/providers/argument.rs
+++ b/support/texlab/crates/completion/src/providers/argument.rs
@@ -37,7 +37,7 @@ pub fn complete_arguments<'a>(
.filter(|(i, _)| *i == index)
{
for arg in &param.0 {
- if let Some(score) = builder.matcher.score(&arg.name, &cursor.text) {
+ if let Some(score) = builder.matcher.score(arg.name, &cursor.text) {
let data = CompletionItemData::Argument(ArgumentData(arg));
builder
.items
diff --git a/support/texlab/crates/completion/src/providers/color.rs b/support/texlab/crates/completion/src/providers/color.rs
index cbdd38dc32..8be1b50555 100644
--- a/support/texlab/crates/completion/src/providers/color.rs
+++ b/support/texlab/crates/completion/src/providers/color.rs
@@ -14,7 +14,7 @@ pub fn complete_colors<'a>(
latex::ColorReference::cast(group.syntax().parent()?)?;
for name in COLORS {
- if let Some(score) = builder.matcher.score(&name, &cursor.text) {
+ if let Some(score) = builder.matcher.score(name, &cursor.text) {
let data = CompletionItemData::Color(name);
builder
.items
diff --git a/support/texlab/crates/completion/src/providers/color_model.rs b/support/texlab/crates/completion/src/providers/color_model.rs
index 4b991c4807..80970b1913 100644
--- a/support/texlab/crates/completion/src/providers/color_model.rs
+++ b/support/texlab/crates/completion/src/providers/color_model.rs
@@ -14,7 +14,7 @@ pub fn complete_color_models<'a>(
let cursor = check_color_definition(params).or_else(|| check_color_definition_set(params))?;
for name in MODEL_NAMES {
- if let Some(score) = builder.matcher.score(&name, &cursor.text) {
+ if let Some(score) = builder.matcher.score(name, &cursor.text) {
let data = CompletionItemData::ColorModel(name);
builder
.items
diff --git a/support/texlab/crates/completion/src/providers/command.rs b/support/texlab/crates/completion/src/providers/command.rs
index f404d42ab3..34f8876e1f 100644
--- a/support/texlab/crates/completion/src/providers/command.rs
+++ b/support/texlab/crates/completion/src/providers/command.rs
@@ -44,7 +44,7 @@ impl<'a, 'b> Processor<'a, 'b> {
pub fn add_delimiters(&mut self) {
for (left, right) in DELIMITERS {
- let Some(score) = self.0.builder.matcher.score(&left, &self.0.cursor.text) else {
+ let Some(score) = self.0.builder.matcher.score(left, &self.0.cursor.text) else {
continue;
};
@@ -68,7 +68,7 @@ impl<'a, 'b> Processor<'a, 'b> {
let data = CompletionItemData::Command(CommandData {
name: &command.name,
glyph: command.glyph.as_deref(),
- image: command.image.as_deref(),
+ image: command.image,
package: Some(package),
});
diff --git a/support/texlab/crates/completion/src/providers/environment.rs b/support/texlab/crates/completion/src/providers/environment.rs
index 393dd100ba..b56377550e 100644
--- a/support/texlab/crates/completion/src/providers/environment.rs
+++ b/support/texlab/crates/completion/src/providers/environment.rs
@@ -21,7 +21,7 @@ pub fn complete_environments<'a>(
.and_then(|env| env.begin())
.and_then(|begin| begin.name())
.and_then(|name| name.key())
- .map_or_else(|| String::new(), |name| name.to_string());
+ .map_or_else(String::new, |name| name.to_string());
let mut proc = Processor {
inner: ProviderContext {
@@ -48,7 +48,7 @@ impl<'a, 'b> Processor<'a, 'b> {
for package in included_packages(&self.inner.params.feature) {
let envs_with_score = package.environments.iter().filter_map(|env| {
let matcher = &self.inner.builder.matcher;
- let score = matcher.score(&env, &self.inner.cursor.text)?;
+ let score = matcher.score(env, &self.inner.cursor.text)?;
Some((*env, score))
});
@@ -76,7 +76,7 @@ impl<'a, 'b> Processor<'a, 'b> {
{
let matcher = &self.inner.builder.matcher;
let name = theorem.name.text.as_str();
- if let Some(score) = matcher.score(&name, &self.inner.cursor.text) {
+ if let Some(score) = matcher.score(name, &self.inner.cursor.text) {
let data = CompletionItemData::Environment(EnvironmentData {
name,
package: None,
diff --git a/support/texlab/crates/completion/src/providers/glossary.rs b/support/texlab/crates/completion/src/providers/glossary.rs
index c22f5b5888..d01d62a511 100644
--- a/support/texlab/crates/completion/src/providers/glossary.rs
+++ b/support/texlab/crates/completion/src/providers/glossary.rs
@@ -58,7 +58,7 @@ impl<'a, 'b> Processor<'a, 'b> {
for name in data
.root_node()
.descendants()
- .filter_map(|node| extract(node))
+ .filter_map(&extract)
.filter_map(|name| name.key())
.map(|name| name.to_string())
{
diff --git a/support/texlab/crates/completion/src/providers/import.rs b/support/texlab/crates/completion/src/providers/import.rs
index c506026a99..c0f608f9d2 100644
--- a/support/texlab/crates/completion/src/providers/import.rs
+++ b/support/texlab/crates/completion/src/providers/import.rs
@@ -29,13 +29,13 @@ pub fn complete_imports<'a>(
file_names.insert(file_name);
let stem = &file_name[0..file_name.len() - 4];
if kind == latex::PACKAGE_INCLUDE {
- if let Some(score) = builder.matcher.score(&stem, &cursor.text) {
+ if let Some(score) = builder.matcher.score(stem, &cursor.text) {
let data = CompletionItemData::Package(stem);
builder
.items
.push(CompletionItem::new_simple(score, cursor.range, data));
}
- } else if let Some(score) = builder.matcher.score(&stem, &cursor.text) {
+ } else if let Some(score) = builder.matcher.score(stem, &cursor.text) {
let data = CompletionItemData::DocumentClass(stem);
builder
.items
@@ -51,13 +51,13 @@ pub fn complete_imports<'a>(
{
let stem = &file_name[0..file_name.len() - 4];
if kind == latex::PACKAGE_INCLUDE {
- if let Some(score) = builder.matcher.score(&stem, &cursor.text) {
+ if let Some(score) = builder.matcher.score(stem, &cursor.text) {
let data = CompletionItemData::Package(stem);
builder
.items
.push(CompletionItem::new_simple(score, cursor.range, data));
}
- } else if let Some(score) = builder.matcher.score(&stem, &cursor.text) {
+ } else if let Some(score) = builder.matcher.score(stem, &cursor.text) {
let data = CompletionItemData::DocumentClass(stem);
builder
.items
diff --git a/support/texlab/crates/completion/src/providers/include.rs b/support/texlab/crates/completion/src/providers/include.rs
index 60c432d097..d0a042252f 100644
--- a/support/texlab/crates/completion/src/providers/include.rs
+++ b/support/texlab/crates/completion/src/providers/include.rs
@@ -19,9 +19,7 @@ pub fn complete_includes<'a>(
params: &'a CompletionParams<'a>,
builder: &mut CompletionBuilder<'a>,
) -> Option<()> {
- if params.feature.document.path.is_none() {
- return None;
- }
+ params.feature.document.path.as_ref()?;
let (cursor, group) = find_curly_group_word_list(params)?;
@@ -115,7 +113,7 @@ fn current_dir(
graphics_path: Option<&str>,
) -> Option<PathBuf> {
let workspace = &params.workspace;
- let parent = deps::parents(&workspace, params.document)
+ let parent = deps::parents(workspace, params.document)
.iter()
.next()
.map_or(params.document, Clone::clone);
diff --git a/support/texlab/crates/completion/src/providers/label_ref.rs b/support/texlab/crates/completion/src/providers/label_ref.rs
index 6f71ae3241..8b262f13ca 100644
--- a/support/texlab/crates/completion/src/providers/label_ref.rs
+++ b/support/texlab/crates/completion/src/providers/label_ref.rs
@@ -11,12 +11,30 @@ use crate::{
CompletionItem, CompletionItemData, CompletionParams,
};
+fn trim_prefix<'a>(prefix: Option<&'a str>, text: &'a str) -> &'a str {
+ prefix
+ .and_then(|pref| text.strip_prefix(pref))
+ .unwrap_or(text)
+}
+
pub fn complete_label_references<'a>(
params: &'a CompletionParams<'a>,
builder: &mut CompletionBuilder<'a>,
) -> Option<()> {
- let FindResult { cursor, is_math } =
- find_reference(params).or_else(|| find_reference_range(params))?;
+ let FindResult {
+ cursor,
+ is_math,
+ command,
+ } = find_reference(params).or_else(|| find_reference_range(params))?;
+ let ref_pref = params
+ .feature
+ .workspace
+ .config()
+ .syntax
+ .label_reference_prefixes
+ .iter()
+ .find_map(|(k, v)| if *k == command { Some(v) } else { None })
+ .map(|x| x.as_str());
for document in &params.feature.project.documents {
let DocumentData::Tex(data) = &document.data else {
@@ -29,6 +47,10 @@ pub fn complete_label_references<'a>(
.iter()
.filter(|label| label.kind == LabelKind::Definition)
{
+ if ref_pref.map_or(false, |pref| !label.name.text.starts_with(pref)) {
+ continue;
+ }
+ let labeltext = trim_prefix(ref_pref, &label.name.text);
match render_label(params.feature.workspace, &params.feature.project, label) {
Some(rendered_label) => {
if is_math && !matches!(rendered_label.object, RenderedObject::Equation) {
@@ -41,11 +63,12 @@ pub fn complete_label_references<'a>(
_ => None,
};
- let keywords = format!("{} {}", label.name.text, rendered_label.reference());
+ let keywords = format!("{} {}", labeltext, rendered_label.reference());
if let Some(score) = builder.matcher.score(&keywords, &cursor.text) {
+ let name = trim_prefix(ref_pref, &label.name.text);
let data = CompletionItemData::Label(crate::LabelData {
- name: &label.name.text,
+ name,
header,
footer,
object: Some(rendered_label.object),
@@ -59,12 +82,13 @@ pub fn complete_label_references<'a>(
}
None => {
if let Some(score) = builder.matcher.score(&label.name.text, &cursor.text) {
+ let name = trim_prefix(ref_pref, &label.name.text);
let data = CompletionItemData::Label(crate::LabelData {
- name: &label.name.text,
+ name,
header: None,
footer: None,
object: None,
- keywords: label.name.text.clone(),
+ keywords: labeltext.to_string(),
});
builder
@@ -82,20 +106,26 @@ pub fn complete_label_references<'a>(
struct FindResult {
cursor: Span,
is_math: bool,
+ command: String,
}
fn find_reference(params: &CompletionParams) -> Option<FindResult> {
let (cursor, group) = find_curly_group_word_list(params)?;
let reference = latex::LabelReference::cast(group.syntax().parent()?)?;
let is_math = reference.command()?.text() == "\\eqref";
- Some(FindResult { cursor, is_math })
+ Some(FindResult {
+ cursor,
+ is_math,
+ command: reference.command()?.text()[1..].to_string(),
+ })
}
fn find_reference_range(params: &CompletionParams) -> Option<FindResult> {
let (cursor, group) = find_curly_group_word(params)?;
- latex::LabelReferenceRange::cast(group.syntax().parent()?)?;
+ let refrange = latex::LabelReferenceRange::cast(group.syntax().parent()?)?;
Some(FindResult {
cursor,
is_math: false,
+ command: refrange.command()?.text()[1..].to_string(),
})
}
diff --git a/support/texlab/crates/completion/src/providers/tikz_library.rs b/support/texlab/crates/completion/src/providers/tikz_library.rs
index 10a0aa44ba..4c3d7e8955 100644
--- a/support/texlab/crates/completion/src/providers/tikz_library.rs
+++ b/support/texlab/crates/completion/src/providers/tikz_library.rs
@@ -21,7 +21,7 @@ pub fn complete_tikz_libraries<'a>(
};
for name in libraries {
- if let Some(score) = builder.matcher.score(&name, &cursor.text) {
+ if let Some(score) = builder.matcher.score(name, &cursor.text) {
let data = CompletionItemData::TikzLibrary(name);
builder
.items
diff --git a/support/texlab/crates/completion/src/tests.rs b/support/texlab/crates/completion/src/tests.rs
index c6bed6e08e..8c68b71dd9 100644
--- a/support/texlab/crates/completion/src/tests.rs
+++ b/support/texlab/crates/completion/src/tests.rs
@@ -1,11 +1,17 @@
-use base_db::FeatureParams;
+use base_db::{Config, FeatureParams};
use expect_test::{expect, Expect};
+use parser::SyntaxConfig;
use rowan::TextRange;
use crate::CompletionParams;
-fn check(input: &str, expect: Expect) {
- let fixture = test_utils::fixture::Fixture::parse(input);
+fn check_with_syntax_config(config: SyntaxConfig, input: &str, expect: Expect) {
+ let mut fixture = test_utils::fixture::Fixture::parse(input);
+ fixture.workspace.set_config(Config {
+ syntax: config,
+ ..Config::default()
+ });
+ let fixture = fixture;
let (offset, spec) = fixture
.documents
@@ -37,6 +43,10 @@ fn check(input: &str, expect: Expect) {
expect.assert_debug_eq(&items);
}
+fn check(input: &str, expect: Expect) {
+ check_with_syntax_config(SyntaxConfig::default(), input, expect)
+}
+
#[test]
fn acronym_ref_simple() {
check(
@@ -2134,3 +2144,200 @@ fn issue_885() {
"#]],
);
}
+
+#[test]
+fn test_custom_label_prefix_ref() {
+ let mut config = SyntaxConfig::default();
+ config.label_definition_commands.insert("asm".to_string());
+ config
+ .label_definition_prefixes
+ .push(("asm".to_string(), "asm:".to_string()));
+
+ check_with_syntax_config(
+ config,
+ r#"
+%! main.tex
+ \begin{enumerate}\label{baz}
+ \asm{foo}{what}
+ \end{enumerate}
+
+ \ref{}
+ |
+% Comment"#,
+ expect![[r#"
+ [
+ Label(
+ LabelData {
+ name: "asm:foo",
+ header: None,
+ footer: None,
+ object: None,
+ keywords: "asm:foo",
+ },
+ ),
+ Label(
+ LabelData {
+ name: "baz",
+ header: None,
+ footer: None,
+ object: None,
+ keywords: "baz",
+ },
+ ),
+ ]
+ "#]],
+ );
+}
+
+#[test]
+fn test_custom_label_prefix_custom_ref() {
+ let mut config = SyntaxConfig::default();
+ config.label_definition_commands.insert("asm".to_string());
+ config
+ .label_definition_prefixes
+ .push(("asm".to_string(), "asm:".to_string()));
+ config.label_reference_commands.insert("asmref".to_string());
+ config
+ .label_reference_prefixes
+ .push(("asmref".to_string(), "asm:".to_string()));
+
+ check_with_syntax_config(
+ config,
+ r#"
+%! main.tex
+ \begin{enumerate}\label{baz}
+ \asm{foo}{what}
+ \end{enumerate}
+
+ \asmref{}
+ |
+% Comment"#,
+ expect![[r#"
+ [
+ Label(
+ LabelData {
+ name: "foo",
+ header: None,
+ footer: None,
+ object: None,
+ keywords: "foo",
+ },
+ ),
+ ]
+ "#]],
+ );
+}
+
+#[test]
+fn test_custom_label_multiple_prefix_custom_ref() {
+ let mut config = SyntaxConfig::default();
+ config
+ .label_definition_commands
+ .extend(vec!["asm", "goal"].into_iter().map(String::from));
+ config.label_definition_prefixes.extend(
+ vec![("asm", "asm:"), ("goal", "goal:")]
+ .into_iter()
+ .map(|(x, y)| (String::from(x), String::from(y))),
+ );
+ config
+ .label_reference_commands
+ .extend(vec!["asmref", "goalref"].into_iter().map(String::from));
+ config.label_reference_prefixes.extend(
+ vec![("asmref", "asm:"), ("goalref", "goal:")]
+ .into_iter()
+ .map(|(x, y)| (String::from(x), String::from(y))),
+ );
+
+ check_with_syntax_config(
+ config,
+ r#"
+%! main.tex
+ \begin{enumerate}\label{baz}
+ \asm{foo}{what}
+ \goal{foo}{what}
+ \end{enumerate}
+
+ \goalref{}
+ |
+% Comment"#,
+ expect![[r#"
+ [
+ Label(
+ LabelData {
+ name: "foo",
+ header: None,
+ footer: None,
+ object: None,
+ keywords: "foo",
+ },
+ ),
+ ]
+ "#]],
+ );
+}
+
+#[test]
+fn test_custom_label_multiple_prefix_ref() {
+ let mut config = SyntaxConfig::default();
+ config
+ .label_definition_commands
+ .extend(vec!["asm", "goal"].into_iter().map(String::from));
+ config.label_definition_prefixes.extend(
+ vec![("asm", "asm:"), ("goal", "goal:")]
+ .into_iter()
+ .map(|(x, y)| (String::from(x), String::from(y))),
+ );
+ config
+ .label_reference_commands
+ .extend(vec!["asmref", "goalref"].into_iter().map(String::from));
+ config.label_reference_prefixes.extend(
+ vec![("asmref", "asm:"), ("goalref", "goal:")]
+ .into_iter()
+ .map(|(x, y)| (String::from(x), String::from(y))),
+ );
+
+ check_with_syntax_config(
+ config,
+ r#"
+%! main.tex
+ \begin{enumerate}\label{baz}
+ \asm{foo}{what}
+ \goal{foo}{what}
+ \end{enumerate}
+
+ \ref{}
+ |
+% Comment"#,
+ expect![[r#"
+ [
+ Label(
+ LabelData {
+ name: "asm:foo",
+ header: None,
+ footer: None,
+ object: None,
+ keywords: "asm:foo",
+ },
+ ),
+ Label(
+ LabelData {
+ name: "baz",
+ header: None,
+ footer: None,
+ object: None,
+ keywords: "baz",
+ },
+ ),
+ Label(
+ LabelData {
+ name: "goal:foo",
+ header: None,
+ footer: None,
+ object: None,
+ keywords: "goal:foo",
+ },
+ ),
+ ]
+ "#]],
+ );
+}
diff --git a/support/texlab/crates/definition/Cargo.toml b/support/texlab/crates/definition/Cargo.toml
index 63ba15c308..254bea0314 100644
--- a/support/texlab/crates/definition/Cargo.toml
+++ b/support/texlab/crates/definition/Cargo.toml
@@ -9,11 +9,11 @@ rust-version.workspace = true
[dependencies]
base-db = { path = "../base-db" }
rowan = "0.15.15"
-rustc-hash = "1.1.0"
+rustc-hash = "2.0.0"
syntax = { path = "../syntax" }
[dev-dependencies]
-itertools = "0.12.1"
+itertools = "0.13.0"
test-utils = { path = "../test-utils" }
[lib]
diff --git a/support/texlab/crates/definition/src/command.rs b/support/texlab/crates/definition/src/command.rs
index 3681cdbaa0..ea7ef8c2c2 100644
--- a/support/texlab/crates/definition/src/command.rs
+++ b/support/texlab/crates/definition/src/command.rs
@@ -28,13 +28,11 @@ pub(super) fn goto_definition(context: &mut DefinitionContext) -> Option<()> {
process_old_definition(node.clone()).or_else(|| process_new_definition(node))
})
.filter(|(_, command)| command.text() == name.text())
- .filter_map(|(target_range, command)| {
- Some(DefinitionResult {
- origin_selection_range,
- target: document,
- target_range,
- target_selection_range: command.text_range(),
- })
+ .map(|(target_range, command)| DefinitionResult {
+ origin_selection_range,
+ target: document,
+ target_range,
+ target_selection_range: command.text_range(),
});
context.results.extend(results);
diff --git a/support/texlab/crates/definition/src/tests.rs b/support/texlab/crates/definition/src/tests.rs
index 26f7c0dc3a..0b3f7fa7cc 100644
--- a/support/texlab/crates/definition/src/tests.rs
+++ b/support/texlab/crates/definition/src/tests.rs
@@ -11,7 +11,7 @@ fn check(input: &str) {
.locations()
.filter(|location| location.document == origin_document)
.find(|location| location.range.contains_inclusive(offset))
- .map_or_else(|| TextRange::default(), |location| location.range);
+ .map_or_else(TextRange::default, |location| location.range);
let mut expected = FxHashSet::default();
for document in &fixture.documents {
diff --git a/support/texlab/crates/diagnostics/Cargo.toml b/support/texlab/crates/diagnostics/Cargo.toml
index 1cb09fdec9..37e39280ad 100644
--- a/support/texlab/crates/diagnostics/Cargo.toml
+++ b/support/texlab/crates/diagnostics/Cargo.toml
@@ -10,14 +10,14 @@ rust-version.workspace = true
base-db = { path = "../base-db" }
encoding_rs = "0.8.34"
encoding_rs_io = "0.1.7"
-itertools = "0.12.1"
+itertools = "0.13.0"
line-index = { path = "../line-index" }
-log = "0.4.21"
+log = "0.4.22"
multimap = "0.10.0"
once_cell = "1.19.0"
-regex = "1.10.4"
+regex = "1.10.5"
rowan = "0.15.15"
-rustc-hash = "1.1.0"
+rustc-hash = "2.0.0"
syntax = { path = "../syntax" }
url = "2.5.0"
diff --git a/support/texlab/crates/diagnostics/src/chktex.rs b/support/texlab/crates/diagnostics/src/chktex.rs
index 195ea968e5..a3f539440d 100644
--- a/support/texlab/crates/diagnostics/src/chktex.rs
+++ b/support/texlab/crates/diagnostics/src/chktex.rs
@@ -74,7 +74,7 @@ impl Command {
.build(stdout),
);
- for line in reader.lines().flatten() {
+ for line in reader.lines().map_while(Result::ok) {
let captures = LINE_REGEX.captures(&line).unwrap();
let line = captures[1].parse::<u32>().unwrap() - 1;
let character = captures[2].parse::<u32>().unwrap() - 1;
diff --git a/support/texlab/crates/diagnostics/src/citations.rs b/support/texlab/crates/diagnostics/src/citations.rs
index 0f09f589be..43d5f495d2 100644
--- a/support/texlab/crates/diagnostics/src/citations.rs
+++ b/support/texlab/crates/diagnostics/src/citations.rs
@@ -24,7 +24,7 @@ pub fn detect_undefined_citations<'a>(
for citation in &data.semantics.citations {
let name = citation.name_text();
- if name != "*" && !entries.contains(name) && !name.contains("#") {
+ if name != "*" && !entries.contains(name) {
let diagnostic = Diagnostic::Tex(citation.name.range, TexError::UndefinedCitation);
results
.entry(document.uri.clone())
@@ -65,8 +65,8 @@ pub fn detect_unused_entries<'a>(
Some(())
}
-pub fn detect_duplicate_entries<'a>(
- workspace: &'a Workspace,
+pub fn detect_duplicate_entries(
+ workspace: &Workspace,
results: &mut FxHashMap<Url, Vec<Diagnostic>>,
) {
for conflict in queries::Conflict::find_all::<Entry>(workspace) {
diff --git a/support/texlab/crates/diagnostics/src/manager.rs b/support/texlab/crates/diagnostics/src/manager.rs
index 3573bc40f2..500dc99c13 100644
--- a/support/texlab/crates/diagnostics/src/manager.rs
+++ b/support/texlab/crates/diagnostics/src/manager.rs
@@ -89,16 +89,12 @@ impl Manager {
let config = &workspace.config().diagnostics;
- results.retain(|uri, _| {
- workspace
- .lookup(uri)
- .map_or(false, |document| Self::is_relevant(document))
- });
+ results.retain(|uri, _| workspace.lookup(uri).map_or(false, Self::is_relevant));
- for (_, diagnostics) in &mut results {
+ for diagnostics in results.values_mut() {
diagnostics.retain(|diagnostic| {
filter_regex_patterns(
- &diagnostic.message(),
+ diagnostic.message(),
&config.allowed_patterns,
&config.ignored_patterns,
)
diff --git a/support/texlab/crates/diagnostics/src/tests.rs b/support/texlab/crates/diagnostics/src/tests.rs
index 3688abeaf4..05ad67fc8b 100644
--- a/support/texlab/crates/diagnostics/src/tests.rs
+++ b/support/texlab/crates/diagnostics/src/tests.rs
@@ -6,14 +6,14 @@ fn check(input: &str, expect: Expect) {
let mut manager = crate::Manager::default();
for document in fixture.workspace.iter() {
- manager.update_syntax(&fixture.workspace, &document);
+ manager.update_syntax(&fixture.workspace, document);
}
let results = manager.get(&fixture.workspace);
let results = results
.iter()
.filter(|(_, diags)| !diags.is_empty())
- .sorted_by(|(uri1, _), (uri2, _)| uri1.cmp(&uri2))
+ .sorted_by(|(uri1, _), (uri2, _)| uri1.cmp(uri2))
.map(|(uri, diags)| (uri.as_str(), diags))
.collect_vec();
diff --git a/support/texlab/crates/distro/Cargo.toml b/support/texlab/crates/distro/Cargo.toml
index eefcea2b49..c81288e86e 100644
--- a/support/texlab/crates/distro/Cargo.toml
+++ b/support/texlab/crates/distro/Cargo.toml
@@ -7,8 +7,8 @@ edition.workspace = true
rust-version.workspace = true
[dependencies]
-anyhow = "1.0.82"
-rustc-hash = "1.1.0"
+anyhow = "1.0.86"
+rustc-hash = "2.0.0"
[lib]
doctest = false
diff --git a/support/texlab/crates/distro/src/language.rs b/support/texlab/crates/distro/src/language.rs
index 201ed0702b..0a94a93604 100644
--- a/support/texlab/crates/distro/src/language.rs
+++ b/support/texlab/crates/distro/src/language.rs
@@ -9,6 +9,7 @@ pub enum Language {
Root,
Latexmkrc,
Tectonic,
+ FileList,
}
impl Language {
@@ -32,6 +33,7 @@ impl Language {
"bib" | "bibtex" => Some(Self::Bib),
"aux" => Some(Self::Aux),
"log" => Some(Self::Log),
+ "fls" => Some(Self::FileList),
_ => None,
}
}
diff --git a/support/texlab/crates/highlights/src/lib.rs b/support/texlab/crates/highlights/src/lib.rs
index 009dd20807..9d7a63b096 100644
--- a/support/texlab/crates/highlights/src/lib.rs
+++ b/support/texlab/crates/highlights/src/lib.rs
@@ -23,7 +23,7 @@ pub struct HighlightParams<'a> {
pub fn find_all(params: &HighlightParams) -> Vec<Highlight> {
let mut results = Vec::new();
- label::find_highlights(&params, &mut results);
+ label::find_highlights(params, &mut results);
results
}
diff --git a/support/texlab/crates/hover/src/lib.rs b/support/texlab/crates/hover/src/lib.rs
index 2d22d50b0b..dcf4d442a9 100644
--- a/support/texlab/crates/hover/src/lib.rs
+++ b/support/texlab/crates/hover/src/lib.rs
@@ -35,12 +35,12 @@ pub enum HoverData<'db> {
}
pub fn find<'a>(params: &HoverParams<'a>) -> Option<Hover<'a>> {
- 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/inlay-hints/Cargo.toml b/support/texlab/crates/inlay-hints/Cargo.toml
index ede4ca6188..94651ef4c7 100644
--- a/support/texlab/crates/inlay-hints/Cargo.toml
+++ b/support/texlab/crates/inlay-hints/Cargo.toml
@@ -9,7 +9,7 @@ rust-version.workspace = true
[dependencies]
base-db = { path = "../base-db" }
rowan = "0.15.15"
-rustc-hash = "1.1.0"
+rustc-hash = "2.0.0"
[dev-dependencies]
test-utils = { path = "../test-utils" }
diff --git a/support/texlab/crates/inlay-hints/src/label.rs b/support/texlab/crates/inlay-hints/src/label.rs
index 8db852752e..6e29c806b6 100644
--- a/support/texlab/crates/inlay-hints/src/label.rs
+++ b/support/texlab/crates/inlay-hints/src/label.rs
@@ -9,7 +9,6 @@ use crate::{InlayHint, InlayHintBuilder, InlayHintData};
pub(super) fn find_hints(builder: &mut InlayHintBuilder) -> Option<()> {
let definitions = base_db::semantics::tex::Label::find_all(&builder.params.feature.project)
- .into_iter()
.filter(|(_, label)| label.kind == LabelKind::Definition)
.map(|(_, label)| (label.name_text(), label))
.collect::<FxHashMap<_, _>>();
diff --git a/support/texlab/crates/ipc/Cargo.toml b/support/texlab/crates/ipc/Cargo.toml
index ae31dcaf55..92afbba876 100644
--- a/support/texlab/crates/ipc/Cargo.toml
+++ b/support/texlab/crates/ipc/Cargo.toml
@@ -7,10 +7,10 @@ edition.workspace = true
rust-version.workspace = true
[dependencies]
-crossbeam-channel = "0.5.12"
-serde = "1.0.199"
-serde_json = "1.0.116"
-log = "0.4.21"
+crossbeam-channel = "0.5.13"
+serde = "1.0.203"
+serde_json = "1.0.119"
+log = "0.4.22"
uds_windows = "1.1.0"
[lib]
diff --git a/support/texlab/crates/line-index/Cargo.toml b/support/texlab/crates/line-index/Cargo.toml
index 73d2766d60..58e2fa9e16 100644
--- a/support/texlab/crates/line-index/Cargo.toml
+++ b/support/texlab/crates/line-index/Cargo.toml
@@ -7,7 +7,7 @@ edition.workspace = true
rust-version.workspace = true
[dependencies]
-rustc-hash = "1.1.0"
+rustc-hash = "2.0.0"
text-size = "1.1.1"
[lib]
diff --git a/support/texlab/crates/parser/Cargo.toml b/support/texlab/crates/parser/Cargo.toml
index 39fa34ef63..2faadcb262 100644
--- a/support/texlab/crates/parser/Cargo.toml
+++ b/support/texlab/crates/parser/Cargo.toml
@@ -7,16 +7,16 @@ edition.workspace = true
rust-version.workspace = true
[dependencies]
-log = "0.4.21"
+log = "0.4.22"
logos = "0.14.0"
once_cell = "1.19.0"
pathdiff = "0.2.1"
-regex = "1.10.4"
+regex = "1.10.5"
rowan = "0.15.15"
-rustc-hash = "1.1.0"
+rustc-hash = "2.0.0"
syntax = { path = "../syntax" }
tempfile = "3.10.1"
-versions = "6.2.0"
+versions = "6.3.0"
[dev-dependencies]
expect-test = "1.5.0"
diff --git a/support/texlab/crates/parser/src/bibtex.rs b/support/texlab/crates/parser/src/bibtex.rs
index e2cde27dec..4d1e561dbe 100644
--- a/support/texlab/crates/parser/src/bibtex.rs
+++ b/support/texlab/crates/parser/src/bibtex.rs
@@ -2,6 +2,8 @@ use logos::Logos;
use rowan::{GreenNode, GreenNodeBuilder};
use syntax::bibtex::SyntaxKind::{self, *};
+use crate::util::lex_command_name;
+
pub fn parse_bibtex(input: &str) -> GreenNode {
let mut ptr = TokenPtr {
builder: GreenNodeBuilder::new(),
@@ -135,8 +137,8 @@ fn curly_group(mut ptr: TokenPtr<ContentToken>) -> TokenPtr<ContentToken> {
| ContentToken::Quote
| ContentToken::Word => ptr.bump(),
ContentToken::LCurly => ptr = curly_group(ptr),
- ContentToken::AccentName => ptr = accent(ptr),
- ContentToken::CommandName => ptr = command(ptr),
+ ContentToken::CommandName(CommandName::Accent) => ptr = accent(ptr),
+ ContentToken::CommandName(CommandName::Generic) => ptr = command(ptr),
};
}
@@ -160,8 +162,8 @@ fn quote_group(mut ptr: TokenPtr<ContentToken>) -> TokenPtr<ContentToken> {
| ContentToken::Integer
| ContentToken::Word => ptr.bump(),
ContentToken::LCurly => ptr = curly_group(ptr),
- ContentToken::AccentName => ptr = accent(ptr),
- ContentToken::CommandName => ptr = command(ptr),
+ ContentToken::CommandName(CommandName::Accent) => ptr = accent(ptr),
+ ContentToken::CommandName(CommandName::Generic) => ptr = command(ptr),
};
}
@@ -181,7 +183,7 @@ fn accent(mut ptr: TokenPtr<ContentToken>) -> TokenPtr<ContentToken> {
ptr.expect(ContentToken::Whitespace);
}
- if ptr.at(ContentToken::Word) || ptr.at(ContentToken::CommandName) {
+ if ptr.at(ContentToken::Word) || ptr.at(ContentToken::CommandName(CommandName::Generic)) {
ptr.bump();
}
@@ -355,31 +357,29 @@ enum ContentToken {
#[token(r#"~"#)]
Nbsp,
- #[token(r#"\`"#)]
- #[token(r#"\'"#)]
- #[token(r#"\^"#)]
- #[token(r#"\""#)]
- #[token(r#"\H"#)]
- #[token(r#"\~"#)]
- #[token(r#"\c"#)]
- #[token(r#"\k"#)]
- #[token(r#"\="#)]
- #[token(r#"\b"#)]
- #[token(r#"\."#)]
- #[token(r#"\d"#)]
- #[token(r#"\r"#)]
- #[token(r#"\u"#)]
- #[token(r#"\v"#)]
- #[token(r#"\t"#)]
- AccentName,
-
- #[regex(r"\\([^\r\n]|[@a-zA-Z:_]+\*?)?")]
- CommandName,
+ #[regex(r"\\", |lexer| { CommandName::from(lex_command_name(lexer)) })]
+ CommandName(CommandName),
#[regex(r#"[^\s"\{\}\\~,]+"#)]
Word,
}
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
+enum CommandName {
+ Generic,
+ Accent,
+}
+
+impl From<&str> for CommandName {
+ fn from(value: &str) -> Self {
+ match value {
+ "`" | "'" | "^" | "\"" | "H" | "~" | "c" | "k" | "=" | "b" | "." | "d" | "r" | "u"
+ | "v" | "t" => CommandName::Accent,
+ _ => CommandName::Generic,
+ }
+ }
+}
+
impl From<RootToken> for SyntaxKind {
fn from(token: RootToken) -> Self {
match token {
@@ -428,8 +428,8 @@ impl From<ContentToken> for SyntaxKind {
ContentToken::Quote => QUOTE,
ContentToken::Integer => INTEGER,
ContentToken::Nbsp => NBSP,
- ContentToken::AccentName => ACCENT_NAME,
- ContentToken::CommandName => COMMAND_NAME,
+ ContentToken::CommandName(CommandName::Accent) => ACCENT_NAME,
+ ContentToken::CommandName(CommandName::Generic) => COMMAND_NAME,
ContentToken::Word => WORD,
}
}
diff --git a/support/texlab/crates/parser/src/bibtex/tests.rs b/support/texlab/crates/parser/src/bibtex/tests.rs
index e2bb1314d8..f0872b4ca6 100644
--- a/support/texlab/crates/parser/src/bibtex/tests.rs
+++ b/support/texlab/crates/parser/src/bibtex/tests.rs
@@ -3992,3 +3992,280 @@ fn test_rivest_1978() {
"#]],
);
}
+
+#[test]
+fn test_cuesta_2002() {
+ check(
+ r#"@INPROCEEDINGS{Cuesta02,
+ author = {Cuesta, Carlos E. and de la Fuente, Pablo and Barrio-Sol\órzano, Manuel and Beato, Encarnaci\ón},
+ title = {{Coordination in a Reflective Architecture Description Language}},
+ booktitle = {{Proceedings of the 5th International Conference on Coordination Models and Languages (COORDINATION'02)}},
+ year = 2002,
+ editor = {Arbab, Fahrad and Talcott, Carolyn},
+ pages = {141--148},
+ address = {York, United Kingdom},
+ organization = {},
+ publisher = {Springer},
+ volume = {},
+ number = {},
+ series = {Lecture Notes in Computer Science 2315},
+ month = apr,
+ note = {}
+}"#,
+ expect![[r#"
+ ROOT@0..617
+ ENTRY@0..617
+ TYPE@0..14 "@INPROCEEDINGS"
+ L_DELIM@14..15 "{"
+ NAME@15..23 "Cuesta02"
+ COMMA@23..24 ","
+ WHITESPACE@24..27 "\n "
+ FIELD@27..136
+ NAME@27..33 "author"
+ WHITESPACE@33..34 " "
+ EQ@34..35 "="
+ WHITESPACE@35..36 " "
+ CURLY_GROUP@36..135
+ L_CURLY@36..37 "{"
+ WORD@37..43 "Cuesta"
+ COMMA@43..44 ","
+ WHITESPACE@44..45 " "
+ WORD@45..51 "Carlos"
+ WHITESPACE@51..52 " "
+ WORD@52..54 "E."
+ WHITESPACE@54..55 " "
+ WORD@55..58 "and"
+ WHITESPACE@58..59 " "
+ WORD@59..61 "de"
+ WHITESPACE@61..62 " "
+ WORD@62..64 "la"
+ WHITESPACE@64..65 " "
+ WORD@65..71 "Fuente"
+ COMMA@71..72 ","
+ WHITESPACE@72..73 " "
+ WORD@73..78 "Pablo"
+ WHITESPACE@78..79 " "
+ WORD@79..82 "and"
+ WHITESPACE@82..83 " "
+ WORD@83..93 "Barrio-Sol"
+ COMMAND@93..101
+ COMMAND_NAME@93..101 "\\órzano"
+ COMMA@101..102 ","
+ WHITESPACE@102..103 " "
+ WORD@103..109 "Manuel"
+ WHITESPACE@109..110 " "
+ WORD@110..113 "and"
+ WHITESPACE@113..114 " "
+ WORD@114..119 "Beato"
+ COMMA@119..120 ","
+ WHITESPACE@120..121 " "
+ WORD@121..130 "Encarnaci"
+ COMMAND@130..134
+ COMMAND_NAME@130..134 "\\ón"
+ R_CURLY@134..135 "}"
+ COMMA@135..136 ","
+ WHITESPACE@136..139 "\n "
+ FIELD@139..214
+ NAME@139..144 "title"
+ WHITESPACE@144..145 " "
+ EQ@145..146 "="
+ WHITESPACE@146..147 " "
+ CURLY_GROUP@147..213
+ L_CURLY@147..148 "{"
+ CURLY_GROUP@148..212
+ L_CURLY@148..149 "{"
+ WORD@149..161 "Coordination"
+ WHITESPACE@161..162 " "
+ WORD@162..164 "in"
+ WHITESPACE@164..165 " "
+ WORD@165..166 "a"
+ WHITESPACE@166..167 " "
+ WORD@167..177 "Reflective"
+ WHITESPACE@177..178 " "
+ WORD@178..190 "Architecture"
+ WHITESPACE@190..191 " "
+ WORD@191..202 "Description"
+ WHITESPACE@202..203 " "
+ WORD@203..211 "Language"
+ R_CURLY@211..212 "}"
+ R_CURLY@212..213 "}"
+ COMMA@213..214 ","
+ WHITESPACE@214..217 "\n "
+ FIELD@217..336
+ NAME@217..226 "booktitle"
+ WHITESPACE@226..227 " "
+ EQ@227..228 "="
+ WHITESPACE@228..229 " "
+ CURLY_GROUP@229..335
+ L_CURLY@229..230 "{"
+ CURLY_GROUP@230..334
+ L_CURLY@230..231 "{"
+ WORD@231..242 "Proceedings"
+ WHITESPACE@242..243 " "
+ WORD@243..245 "of"
+ WHITESPACE@245..246 " "
+ WORD@246..249 "the"
+ WHITESPACE@249..250 " "
+ WORD@250..253 "5th"
+ WHITESPACE@253..254 " "
+ WORD@254..267 "International"
+ WHITESPACE@267..268 " "
+ WORD@268..278 "Conference"
+ WHITESPACE@278..279 " "
+ WORD@279..281 "on"
+ WHITESPACE@281..282 " "
+ WORD@282..294 "Coordination"
+ WHITESPACE@294..295 " "
+ WORD@295..301 "Models"
+ WHITESPACE@301..302 " "
+ WORD@302..305 "and"
+ WHITESPACE@305..306 " "
+ WORD@306..315 "Languages"
+ WHITESPACE@315..316 " "
+ WORD@316..333 "(COORDINATION'02)"
+ R_CURLY@333..334 "}"
+ R_CURLY@334..335 "}"
+ COMMA@335..336 ","
+ WHITESPACE@336..339 "\n "
+ FIELD@339..351
+ NAME@339..343 "year"
+ WHITESPACE@343..344 " "
+ EQ@344..345 "="
+ WHITESPACE@345..346 " "
+ LITERAL@346..350
+ INTEGER@346..350 "2002"
+ COMMA@350..351 ","
+ WHITESPACE@351..354 "\n "
+ FIELD@354..400
+ NAME@354..360 "editor"
+ WHITESPACE@360..361 " "
+ EQ@361..362 "="
+ WHITESPACE@362..363 " "
+ CURLY_GROUP@363..399
+ L_CURLY@363..364 "{"
+ WORD@364..369 "Arbab"
+ COMMA@369..370 ","
+ WHITESPACE@370..371 " "
+ WORD@371..377 "Fahrad"
+ WHITESPACE@377..378 " "
+ WORD@378..381 "and"
+ WHITESPACE@381..382 " "
+ WORD@382..389 "Talcott"
+ COMMA@389..390 ","
+ WHITESPACE@390..391 " "
+ WORD@391..398 "Carolyn"
+ R_CURLY@398..399 "}"
+ COMMA@399..400 ","
+ WHITESPACE@400..403 "\n "
+ FIELD@403..422
+ NAME@403..408 "pages"
+ WHITESPACE@408..409 " "
+ EQ@409..410 "="
+ WHITESPACE@410..411 " "
+ CURLY_GROUP@411..421
+ L_CURLY@411..412 "{"
+ WORD@412..420 "141--148"
+ R_CURLY@420..421 "}"
+ COMMA@421..422 ","
+ WHITESPACE@422..425 "\n "
+ FIELD@425..458
+ NAME@425..432 "address"
+ WHITESPACE@432..433 " "
+ EQ@433..434 "="
+ WHITESPACE@434..435 " "
+ CURLY_GROUP@435..457
+ L_CURLY@435..436 "{"
+ WORD@436..440 "York"
+ COMMA@440..441 ","
+ WHITESPACE@441..442 " "
+ WORD@442..448 "United"
+ WHITESPACE@448..449 " "
+ WORD@449..456 "Kingdom"
+ R_CURLY@456..457 "}"
+ COMMA@457..458 ","
+ WHITESPACE@458..461 "\n "
+ FIELD@461..479
+ NAME@461..473 "organization"
+ WHITESPACE@473..474 " "
+ EQ@474..475 "="
+ WHITESPACE@475..476 " "
+ CURLY_GROUP@476..478
+ L_CURLY@476..477 "{"
+ R_CURLY@477..478 "}"
+ COMMA@478..479 ","
+ WHITESPACE@479..482 "\n "
+ FIELD@482..505
+ NAME@482..491 "publisher"
+ WHITESPACE@491..492 " "
+ EQ@492..493 "="
+ WHITESPACE@493..494 " "
+ CURLY_GROUP@494..504
+ L_CURLY@494..495 "{"
+ WORD@495..503 "Springer"
+ R_CURLY@503..504 "}"
+ COMMA@504..505 ","
+ WHITESPACE@505..508 "\n "
+ FIELD@508..520
+ NAME@508..514 "volume"
+ WHITESPACE@514..515 " "
+ EQ@515..516 "="
+ WHITESPACE@516..517 " "
+ CURLY_GROUP@517..519
+ L_CURLY@517..518 "{"
+ R_CURLY@518..519 "}"
+ COMMA@519..520 ","
+ WHITESPACE@520..523 "\n "
+ FIELD@523..535
+ NAME@523..529 "number"
+ WHITESPACE@529..530 " "
+ EQ@530..531 "="
+ WHITESPACE@531..532 " "
+ CURLY_GROUP@532..534
+ L_CURLY@532..533 "{"
+ R_CURLY@533..534 "}"
+ COMMA@534..535 ","
+ WHITESPACE@535..538 "\n "
+ FIELD@538..588
+ NAME@538..544 "series"
+ WHITESPACE@544..545 " "
+ EQ@545..546 "="
+ WHITESPACE@546..547 " "
+ CURLY_GROUP@547..587
+ L_CURLY@547..548 "{"
+ WORD@548..555 "Lecture"
+ WHITESPACE@555..556 " "
+ WORD@556..561 "Notes"
+ WHITESPACE@561..562 " "
+ WORD@562..564 "in"
+ WHITESPACE@564..565 " "
+ WORD@565..573 "Computer"
+ WHITESPACE@573..574 " "
+ WORD@574..581 "Science"
+ WHITESPACE@581..582 " "
+ INTEGER@582..586 "2315"
+ R_CURLY@586..587 "}"
+ COMMA@587..588 ","
+ WHITESPACE@588..591 "\n "
+ FIELD@591..603
+ NAME@591..596 "month"
+ WHITESPACE@596..597 " "
+ EQ@597..598 "="
+ WHITESPACE@598..599 " "
+ LITERAL@599..602
+ NAME@599..602 "apr"
+ COMMA@602..603 ","
+ WHITESPACE@603..606 "\n "
+ FIELD@606..616
+ NAME@606..610 "note"
+ WHITESPACE@610..611 " "
+ EQ@611..612 "="
+ WHITESPACE@612..613 " "
+ CURLY_GROUP@613..615
+ L_CURLY@613..614 "{"
+ R_CURLY@614..615 "}"
+ WHITESPACE@615..616 "\n"
+ R_DELIM@616..617 "}"
+
+ "#]],
+ )
+}
diff --git a/support/texlab/crates/parser/src/build_log.rs b/support/texlab/crates/parser/src/build_log.rs
index 420d2dda20..c1f59bd086 100644
--- a/support/texlab/crates/parser/src/build_log.rs
+++ b/support/texlab/crates/parser/src/build_log.rs
@@ -36,7 +36,7 @@ pub fn parse_build_log(log: &str) -> BuildLog {
let warnings = extract_matches(&log, &ranges, &WARNING_REGEX, BuildErrorLevel::Warning);
let bad_boxes = extract_matches(&log, &ranges, &BAD_BOX_REGEX, BuildErrorLevel::Warning);
- let errors = vec![tex_errors, warnings, bad_boxes].concat();
+ let errors = [tex_errors, warnings, bad_boxes].concat();
BuildLog { errors }
}
diff --git a/support/texlab/crates/parser/src/config.rs b/support/texlab/crates/parser/src/config.rs
index f81083f132..2c5380448f 100644
--- a/support/texlab/crates/parser/src/config.rs
+++ b/support/texlab/crates/parser/src/config.rs
@@ -3,12 +3,15 @@ use rustc_hash::FxHashSet;
#[derive(Debug)]
pub struct SyntaxConfig {
pub follow_package_links: bool,
+ pub use_file_list: bool,
pub math_environments: FxHashSet<String>,
pub enum_environments: FxHashSet<String>,
pub verbatim_environments: FxHashSet<String>,
pub citation_commands: FxHashSet<String>,
pub label_definition_commands: FxHashSet<String>,
+ pub label_definition_prefixes: Vec<(String, String)>,
pub label_reference_commands: FxHashSet<String>,
+ pub label_reference_prefixes: Vec<(String, String)>,
}
impl Default for SyntaxConfig {
@@ -38,19 +41,32 @@ impl Default for SyntaxConfig {
.map(ToString::to_string)
.collect();
+ let label_definition_prefixes = DEFAULT_LABEL_DEFINITION_PREFIXES
+ .iter()
+ .map(|(x, y)| (ToString::to_string(x), ToString::to_string(y)))
+ .collect();
+
let label_reference_commands = DEFAULT_LABEL_REFERENCE_COMMANDS
.iter()
.map(ToString::to_string)
.collect();
+ let label_reference_prefixes = DEFAULT_LABEL_REFERENCE_PREFIXES
+ .iter()
+ .map(|(x, y)| (ToString::to_string(x), ToString::to_string(y)))
+ .collect();
+
Self {
follow_package_links: false,
+ use_file_list: false,
math_environments,
enum_environments,
verbatim_environments,
citation_commands,
label_definition_commands,
+ label_definition_prefixes,
label_reference_commands,
+ label_reference_prefixes,
}
}
}
@@ -170,7 +186,9 @@ static DEFAULT_CITATION_COMMANDS: &[&str] = &[
"citeA*",
];
-static DEFAULT_LABEL_DEFINITION_COMMANDS: &[&str] = &["label"];
+static DEFAULT_LABEL_DEFINITION_COMMANDS: &[&str] = &["label", "zlabel"];
+
+static DEFAULT_LABEL_DEFINITION_PREFIXES: &[(&str, &str)] = &[];
static DEFAULT_LABEL_REFERENCE_COMMANDS: &[&str] = &[
"ref",
@@ -182,6 +200,10 @@ static DEFAULT_LABEL_REFERENCE_COMMANDS: &[&str] = &[
"cref*",
"Cref",
"Cref*",
+ "zcref",
+ "zcref*",
+ "zcpageref",
+ "zcpageref*",
"namecref",
"nameCref",
"lcnamecref",
@@ -192,3 +214,5 @@ static DEFAULT_LABEL_REFERENCE_COMMANDS: &[&str] = &[
"labelcpageref",
"eqref",
];
+
+static DEFAULT_LABEL_REFERENCE_PREFIXES: &[(&str, &str)] = &[];
diff --git a/support/texlab/crates/parser/src/file_list.rs b/support/texlab/crates/parser/src/file_list.rs
new file mode 100644
index 0000000000..c892ebfeef
--- /dev/null
+++ b/support/texlab/crates/parser/src/file_list.rs
@@ -0,0 +1,44 @@
+use syntax::file_list::FileList;
+
+pub fn parse_file_list(input: &str) -> FileList {
+ let mut file_list = FileList::default();
+ for line in input.lines() {
+ if let Some(working_dir) = line.strip_prefix("PWD ") {
+ file_list.working_dir = Some(working_dir.into());
+ } else if let Some(input) = line.strip_prefix("INPUT ") {
+ file_list.inputs.insert(input.into());
+ } else if let Some(output) = line.strip_prefix("OUTPUT ") {
+ file_list.outputs.insert(output.into());
+ }
+ }
+
+ file_list
+}
+
+#[cfg(test)]
+mod tests {
+ use rustc_hash::FxHashSet;
+
+ use super::*;
+
+ #[test]
+ fn test_parse_file_list() {
+ let input = r#"
+PWD /home/user
+INPUT file1.tex
+INPUT file1.tex
+OUTPUT file2.pdf"#;
+
+ let expected_file_list = FileList {
+ working_dir: Some("/home/user".into()),
+ inputs: FxHashSet::from_iter(["file1.tex".into()]),
+ outputs: FxHashSet::from_iter(["file2.pdf".into()]),
+ };
+ let actual_file_list = parse_file_list(input);
+ assert_eq!(actual_file_list, expected_file_list);
+
+ assert_eq!(actual_file_list.working_dir, Some("/home/user".into()));
+ assert_eq!(actual_file_list.inputs.len(), 1);
+ assert_eq!(actual_file_list.outputs.len(), 1);
+ }
+}
diff --git a/support/texlab/crates/parser/src/latex/lexer/types.rs b/support/texlab/crates/parser/src/latex/lexer/types.rs
index 896ce01c05..85e542792b 100644
--- a/support/texlab/crates/parser/src/latex/lexer/types.rs
+++ b/support/texlab/crates/parser/src/latex/lexer/types.rs
@@ -1,5 +1,7 @@
use logos::Logos;
+use crate::util::lex_command_name;
+
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash, Logos)]
pub enum Token {
#[regex(r"[\r\n]+", priority = 2)]
@@ -44,55 +46,10 @@ pub enum Token {
#[regex(r"\$\$?")]
Dollar,
- #[regex(r"\\", lex_command_name)]
+ #[regex(r"\\", |lexer| { lex_command_name(lexer); CommandName::Generic } )]
CommandName(CommandName),
}
-fn lex_command_name(lexer: &mut logos::Lexer<Token>) -> CommandName {
- let input = &lexer.source()[lexer.span().end..];
-
- let mut chars = input.chars().peekable();
- let Some(c) = chars.next() else {
- return CommandName::Generic;
- };
-
- if c.is_whitespace() {
- return CommandName::Generic;
- }
-
- lexer.bump(c.len_utf8());
- if !c.is_alphanumeric() && c != '@' {
- return CommandName::Generic;
- }
-
- while let Some(c) = chars.next() {
- match c {
- '*' => {
- lexer.bump(c.len_utf8());
- break;
- }
- c if c.is_alphanumeric() => {
- lexer.bump(c.len_utf8());
- }
- '_' => {
- if !matches!(chars.peek(), Some(c) if c.is_alphanumeric()) {
- break;
- }
-
- lexer.bump(c.len_utf8());
- }
- '@' | ':' => {
- lexer.bump(c.len_utf8());
- }
- _ => {
- break;
- }
- }
- }
-
- CommandName::Generic
-}
-
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
pub enum CommandName {
Generic,
diff --git a/support/texlab/crates/parser/src/latexmkrc.rs b/support/texlab/crates/parser/src/latexmkrc.rs
index 6013a5f646..58c348d01f 100644
--- a/support/texlab/crates/parser/src/latexmkrc.rs
+++ b/support/texlab/crates/parser/src/latexmkrc.rs
@@ -28,9 +28,9 @@ mod v483 {
.current_dir(temp_dir.path())
.output()?;
- let stderr = String::from_utf8_lossy(&output.stderr);
+ let stdout = String::from_utf8_lossy(&output.stdout);
- let (aux_dir, out_dir) = stderr.lines().find_map(extract_dirs).ok_or_else(|| {
+ let (aux_dir, out_dir) = stdout.lines().find_map(extract_dirs).ok_or_else(|| {
std::io::Error::new(
std::io::ErrorKind::InvalidData,
"Normalized aux and out dir were not found in latexmk output",
@@ -106,7 +106,7 @@ mod v484 {
let mut it = lines
.skip_while(|line| !line.starts_with("Latexmk: Normalized aux dir and out dirs:"))
.nth(1)?
- .split(",");
+ .split(',');
let aux_dir = it.next()?.trim().strip_prefix('\'')?.strip_suffix('\'')?;
@@ -133,7 +133,7 @@ pub fn parse_latexmkrc(input: &str, src_dir: &Path) -> std::io::Result<Latexmkrc
.as_ref()
.and_then(|line| Some((line.find("Version")?, line)))
.and_then(|(i, line)| line[i..].trim_end().strip_prefix("Version "))
- .and_then(|text| versions::Versioning::new(text));
+ .and_then(versions::Versioning::new);
let result = if version.map_or(false, |v| v >= versions::Versioning::new("4.84").unwrap()) {
v484::parse_latexmkrc(input, src_dir)
diff --git a/support/texlab/crates/parser/src/lib.rs b/support/texlab/crates/parser/src/lib.rs
index 2a4190b7e2..b3952d6ea5 100644
--- a/support/texlab/crates/parser/src/lib.rs
+++ b/support/texlab/crates/parser/src/lib.rs
@@ -1,10 +1,12 @@
mod bibtex;
mod build_log;
mod config;
+mod file_list;
mod latex;
mod latexmkrc;
+pub(crate) mod util;
pub use self::{
- bibtex::parse_bibtex, build_log::parse_build_log, config::*, latex::parse_latex,
- latexmkrc::parse_latexmkrc,
+ bibtex::parse_bibtex, build_log::parse_build_log, config::*, file_list::parse_file_list,
+ latex::parse_latex, latexmkrc::parse_latexmkrc,
};
diff --git a/support/texlab/crates/parser/src/util.rs b/support/texlab/crates/parser/src/util.rs
new file mode 100644
index 0000000000..cb147c493b
--- /dev/null
+++ b/support/texlab/crates/parser/src/util.rs
@@ -0,0 +1,52 @@
+use std::ops::{Index, Range};
+
+use logos::{Logos, Source};
+
+pub fn lex_command_name<'a, T>(lexer: &mut logos::Lexer<'a, T>) -> &'a str
+where
+ T: Logos<'a>,
+ T::Source: Index<Range<usize>, Output = str>,
+{
+ let start = lexer.span().end;
+ let input = &lexer.source()[start..lexer.source().len()];
+
+ let mut chars = input.chars().peekable();
+ let Some(c) = chars.next() else {
+ return "";
+ };
+
+ if c.is_whitespace() {
+ return "";
+ }
+
+ lexer.bump(c.len_utf8());
+
+ if c.is_alphanumeric() || c == '@' {
+ while let Some(c) = chars.next() {
+ match c {
+ '*' => {
+ lexer.bump(c.len_utf8());
+ break;
+ }
+ c if c.is_alphanumeric() => {
+ lexer.bump(c.len_utf8());
+ }
+ '_' => {
+ if !matches!(chars.peek(), Some(c) if c.is_alphanumeric()) {
+ break;
+ }
+
+ lexer.bump(c.len_utf8());
+ }
+ '@' | ':' => {
+ lexer.bump(c.len_utf8());
+ }
+ _ => {
+ break;
+ }
+ }
+ }
+ }
+
+ &lexer.source()[start..lexer.span().end]
+}
diff --git a/support/texlab/crates/references/Cargo.toml b/support/texlab/crates/references/Cargo.toml
index e78e84ea4c..8d4e3a6936 100644
--- a/support/texlab/crates/references/Cargo.toml
+++ b/support/texlab/crates/references/Cargo.toml
@@ -9,7 +9,7 @@ rust-version.workspace = true
[dependencies]
base-db = { path = "../base-db" }
rowan = "0.15.15"
-rustc-hash = "1.1.0"
+rustc-hash = "2.0.0"
syntax = { path = "../syntax" }
[dev-dependencies]
diff --git a/support/texlab/crates/references/src/command.rs b/support/texlab/crates/references/src/command.rs
index 712da20b73..f4504641f2 100644
--- a/support/texlab/crates/references/src/command.rs
+++ b/support/texlab/crates/references/src/command.rs
@@ -32,7 +32,7 @@ pub(super) fn find_all(context: &mut ReferenceContext) -> Option<()> {
.collect();
for command in &data.semantics.commands {
- if command.text == &token.text()[1..] {
+ if command.text == token.text()[1..] {
let kind = if defs.contains(command) {
ReferenceKind::Definition
} else {
diff --git a/support/texlab/crates/references/src/entry.rs b/support/texlab/crates/references/src/entry.rs
index c3926058e6..722c96fe4a 100644
--- a/support/texlab/crates/references/src/entry.rs
+++ b/support/texlab/crates/references/src/entry.rs
@@ -30,14 +30,14 @@ pub(super) fn find_all(context: &mut ReferenceContext) -> Option<()> {
};
let project = &context.params.feature.project;
- for (document, obj) in queries::objects_with_name::<tex::Citation>(&project, name) {
+ for (document, obj) in queries::objects_with_name::<tex::Citation>(project, name) {
context.results.push(Reference {
location: DocumentLocation::new(document, obj.name.range),
kind: ReferenceKind::Reference,
});
}
- for (document, obj) in queries::objects_with_name::<bib::Entry>(&project, name) {
+ for (document, obj) in queries::objects_with_name::<bib::Entry>(project, name) {
context.results.push(Reference {
location: DocumentLocation::new(document, obj.name.range),
kind: ReferenceKind::Definition,
diff --git a/support/texlab/crates/references/src/label.rs b/support/texlab/crates/references/src/label.rs
index 872ef2dd14..20fc6e0d25 100644
--- a/support/texlab/crates/references/src/label.rs
+++ b/support/texlab/crates/references/src/label.rs
@@ -14,7 +14,7 @@ pub(super) fn find_all(context: &mut ReferenceContext) -> Option<()> {
.name_text();
let project = &context.params.feature.project;
- for (document, label) in queries::objects_with_name::<tex::Label>(&project, name) {
+ for (document, label) in queries::objects_with_name::<tex::Label>(project, name) {
let kind = match label.kind {
tex::LabelKind::Definition => ReferenceKind::Definition,
tex::LabelKind::Reference | tex::LabelKind::ReferenceRange => ReferenceKind::Reference,
diff --git a/support/texlab/crates/rename/Cargo.toml b/support/texlab/crates/rename/Cargo.toml
index 1b2b91ee2a..592bafb474 100644
--- a/support/texlab/crates/rename/Cargo.toml
+++ b/support/texlab/crates/rename/Cargo.toml
@@ -9,11 +9,12 @@ rust-version.workspace = true
[dependencies]
base-db = { path = "../base-db" }
rowan = "0.15.15"
-rustc-hash = "1.1.0"
+rustc-hash = "2.0.0"
syntax = { path = "../syntax" }
[dev-dependencies]
test-utils = { path = "../test-utils" }
+parser = { path = "../parser" }
[lib]
doctest = false
diff --git a/support/texlab/crates/rename/src/command.rs b/support/texlab/crates/rename/src/command.rs
index edcf7db61e..037e09e4ca 100644
--- a/support/texlab/crates/rename/src/command.rs
+++ b/support/texlab/crates/rename/src/command.rs
@@ -19,7 +19,7 @@ pub(super) fn prepare_rename(params: &RenameParams) -> Option<Span> {
))
}
-pub(super) fn rename<'a>(builder: &mut RenameBuilder) -> Option<()> {
+pub(super) fn rename(builder: &mut RenameBuilder) -> Option<()> {
let name = prepare_rename(&builder.params)?;
for document in &builder.params.feature.project.documents {
@@ -35,7 +35,10 @@ pub(super) fn rename<'a>(builder: &mut RenameBuilder) -> Option<()> {
}
}
- builder.result.changes.insert(*document, edits);
+ builder
+ .result
+ .changes
+ .insert(*document, edits.iter().map(|&x| x.into()).collect());
}
Some(())
diff --git a/support/texlab/crates/rename/src/entry.rs b/support/texlab/crates/rename/src/entry.rs
index c0b508a506..d35d9e9e84 100644
--- a/support/texlab/crates/rename/src/entry.rs
+++ b/support/texlab/crates/rename/src/entry.rs
@@ -30,7 +30,7 @@ pub(super) fn prepare_rename(params: &RenameParams) -> Option<Span> {
}
}
-pub(super) fn rename<'a>(builder: &mut RenameBuilder) -> Option<()> {
+pub(super) fn rename(builder: &mut RenameBuilder) -> Option<()> {
let name = prepare_rename(&builder.params)?;
let project = &builder.params.feature.project;
@@ -42,7 +42,7 @@ pub(super) fn rename<'a>(builder: &mut RenameBuilder) -> Option<()> {
for (document, range) in citations.chain(entries) {
let entry = builder.result.changes.entry(document);
- entry.or_default().push(range);
+ entry.or_default().push(range.into());
}
Some(())
diff --git a/support/texlab/crates/rename/src/label.rs b/support/texlab/crates/rename/src/label.rs
index b21e1b795e..1d82f5e2b4 100644
--- a/support/texlab/crates/rename/src/label.rs
+++ b/support/texlab/crates/rename/src/label.rs
@@ -3,22 +3,65 @@ use base_db::{
util::queries::{self, Object},
};
-use crate::{RenameBuilder, RenameParams};
+use crate::{RenameBuilder, RenameInformation, RenameParams};
+
+struct PrefixInformation<'a> {
+ def_prefixes: &'a Vec<(String, String)>,
+ ref_prefixes: &'a Vec<(String, String)>,
+}
+
+fn label_has_prefix(pref_info: &PrefixInformation, label: &tex::Label) -> Option<String> {
+ match label.kind {
+ tex::LabelKind::Definition => pref_info.def_prefixes.iter(),
+ _ => pref_info.ref_prefixes.iter(),
+ }
+ .find_map(|(k, v)| {
+ if k == &label.cmd.clone().unwrap_or(String::new()) {
+ Some(v)
+ } else {
+ None
+ }
+ })
+ .cloned()
+}
+
+fn find_prefix_in_any(
+ builder: &mut RenameBuilder,
+ pref_info: &PrefixInformation,
+ name: &str,
+) -> Option<String> {
+ let project = &builder.params.feature.project;
+ queries::objects_with_name::<tex::Label>(project, name)
+ .find_map(|(_, label)| label_has_prefix(&pref_info, label))
+}
pub(super) fn prepare_rename(params: &RenameParams) -> Option<Span> {
let data = params.feature.document.data.as_tex()?;
let labels = &data.semantics.labels;
let label = queries::object_at_cursor(labels, params.offset, queries::SearchMode::Name)?;
+
Some(Span::new(label.object.name.text.clone(), label.range))
}
pub(super) fn rename(builder: &mut RenameBuilder) -> Option<()> {
let name = prepare_rename(&builder.params)?;
+ let syn = &builder.params.feature.workspace.config().syntax;
+ let pref_info = PrefixInformation {
+ def_prefixes: &syn.label_definition_prefixes,
+ ref_prefixes: &syn.label_reference_prefixes,
+ };
+ let prefix = find_prefix_in_any(builder, &pref_info, &name.text);
+
let project = &builder.params.feature.project;
for (document, label) in queries::objects_with_name::<tex::Label>(project, &name.text) {
+ let prefix = label_has_prefix(&pref_info, label).map_or(prefix.clone(), |_| None);
+
let entry = builder.result.changes.entry(document);
- entry.or_default().push(label.name_range());
+ entry.or_default().push(RenameInformation {
+ range: label.name_range(),
+ prefix: prefix.clone(),
+ });
}
Some(())
diff --git a/support/texlab/crates/rename/src/lib.rs b/support/texlab/crates/rename/src/lib.rs
index b7dd197ce0..e6c05ad268 100644
--- a/support/texlab/crates/rename/src/lib.rs
+++ b/support/texlab/crates/rename/src/lib.rs
@@ -13,8 +13,14 @@ pub struct RenameParams<'a> {
}
#[derive(Debug, Default)]
+pub struct RenameInformation {
+ pub range: TextRange,
+ pub prefix: Option<String>,
+}
+
+#[derive(Debug, Default)]
pub struct RenameResult<'a> {
- pub changes: FxHashMap<&'a Document, Vec<TextRange>>,
+ pub changes: FxHashMap<&'a Document, Vec<RenameInformation>>,
}
struct RenameBuilder<'a> {
@@ -22,14 +28,28 @@ struct RenameBuilder<'a> {
result: RenameResult<'a>,
}
+impl From<TextRange> for RenameInformation {
+ fn from(range: TextRange) -> Self {
+ RenameInformation {
+ range,
+ prefix: None,
+ }
+ }
+}
+impl PartialEq for RenameInformation {
+ fn eq(&self, other: &Self) -> bool {
+ self.range == other.range
+ }
+}
+
pub fn prepare_rename(params: &RenameParams) -> Option<TextRange> {
- command::prepare_rename(&params)
- .or_else(|| entry::prepare_rename(&params))
- .or_else(|| label::prepare_rename(&params))
+ command::prepare_rename(params)
+ .or_else(|| entry::prepare_rename(params))
+ .or_else(|| label::prepare_rename(params))
.map(|span| span.range)
}
-pub fn rename<'a>(params: RenameParams<'a>) -> RenameResult<'a> {
+pub fn rename(params: RenameParams) -> RenameResult {
let result = RenameResult::default();
let mut builder = RenameBuilder { params, result };
diff --git a/support/texlab/crates/rename/src/tests.rs b/support/texlab/crates/rename/src/tests.rs
index 0f4263033e..4da866fb08 100644
--- a/support/texlab/crates/rename/src/tests.rs
+++ b/support/texlab/crates/rename/src/tests.rs
@@ -1,23 +1,37 @@
use rustc_hash::FxHashMap;
-use crate::RenameParams;
+use base_db::Config;
+use parser::SyntaxConfig;
-fn check(input: &str) {
- let fixture = test_utils::fixture::Fixture::parse(input);
+use crate::{RenameInformation, RenameParams};
+
+fn check_with_syntax_config(config: SyntaxConfig, input: &str) {
+ let mut fixture = test_utils::fixture::Fixture::parse(input);
+ fixture.workspace.set_config(Config {
+ syntax: config,
+ ..Config::default()
+ });
+ let fixture = fixture;
- let mut expected = FxHashMap::default();
+ let mut expected: FxHashMap<_, Vec<RenameInformation>> = FxHashMap::default();
for spec in &fixture.documents {
if !spec.ranges.is_empty() {
let document = fixture.workspace.lookup(&spec.uri).unwrap();
- expected.insert(document, spec.ranges.clone());
+ expected.insert(
+ document,
+ spec.ranges.iter().map(|r| r.clone().into()).collect(),
+ );
}
}
-
let (feature, offset) = fixture.make_params().unwrap();
let actual = crate::rename(RenameParams { feature, offset });
assert_eq!(actual.changes, expected);
}
+fn check(input: &str) {
+ check_with_syntax_config(SyntaxConfig::default(), input)
+}
+
#[test]
fn test_command() {
check(
@@ -78,12 +92,97 @@ fn test_label() {
|
^^^
+%! baz.tex
+\ref{foo}
+
%! bar.tex
\ref{foo}
^^^
+"#,
+ )
+}
+
+#[test]
+fn test_custom_label_ref() {
+ let mut config = SyntaxConfig::default();
+ config
+ .label_definition_commands
+ .extend(vec!["asm", "goal"].into_iter().map(String::from));
+ config.label_definition_prefixes.extend(
+ vec![("asm", "asm:"), ("goal", "goal:")]
+ .into_iter()
+ .map(|(x, y)| (String::from(x), String::from(y))),
+ );
+ config
+ .label_reference_commands
+ .extend(vec!["asmref", "goalref"].into_iter().map(String::from));
+ config.label_reference_prefixes.extend(
+ vec![("asmref", "asm:"), ("goalref", "goal:")]
+ .into_iter()
+ .map(|(x, y)| (String::from(x), String::from(y))),
+ );
+ check_with_syntax_config(
+ config,
+ r#"
+%! foo.tex
+\goal{foo}
+
+\asm{foo}\include{bar}\include{baz}
+ |
+ ^^^
+
+%! bar.tex
+\asmref{foo}
+ ^^^
+
+%! baz.tex
+\ref{foo}
+
+\ref{asm:foo}
+ ^^^^^^^
+
+"#,
+ )
+}
+
+#[test]
+fn test_custom_label_def() {
+ let mut config = SyntaxConfig::default();
+ config
+ .label_definition_commands
+ .extend(vec!["asm", "goal"].into_iter().map(String::from));
+ config.label_definition_prefixes.extend(
+ vec![("asm", "asm:"), ("goal", "goal:")]
+ .into_iter()
+ .map(|(x, y)| (String::from(x), String::from(y))),
+ );
+ config
+ .label_reference_commands
+ .extend(vec!["asmref", "goalref"].into_iter().map(String::from));
+ config.label_reference_prefixes.extend(
+ vec![("asmref", "asm:"), ("goalref", "goal:")]
+ .into_iter()
+ .map(|(x, y)| (String::from(x), String::from(y))),
+ );
+ check_with_syntax_config(
+ config,
+ r#"
+%! foo.tex
+\goal{foo}
+
+\label{asm:foo}\include{bar}\include{baz}
+ |
+ ^^^^^^^
+
+%! bar.tex
+\asmref{foo}
+ ^^^
%! baz.tex
\ref{foo}
+
+\ref{asm:foo}
+ ^^^^^^^
"#,
)
}
diff --git a/support/texlab/crates/symbols/Cargo.toml b/support/texlab/crates/symbols/Cargo.toml
index 65db0fc0bd..c44f120153 100644
--- a/support/texlab/crates/symbols/Cargo.toml
+++ b/support/texlab/crates/symbols/Cargo.toml
@@ -12,7 +12,7 @@ doctest = false
[dependencies]
base-db = { path = "../base-db" }
distro = { path = "../distro" }
-itertools = "0.12.1"
+itertools = "0.13.0"
line-index = { path = "../line-index" }
rowan = "0.15.15"
syntax = { path = "../syntax" }
@@ -20,6 +20,6 @@ titlecase = "3.0.0"
url = "2.5.0"
[dev-dependencies]
-regex = "1.10.4"
+regex = "1.10.5"
test-utils = { path = "../test-utils" }
expect-test = "1.5.0"
diff --git a/support/texlab/crates/symbols/src/document.rs b/support/texlab/crates/symbols/src/document.rs
index 791f119919..611a7e0370 100644
--- a/support/texlab/crates/symbols/src/document.rs
+++ b/support/texlab/crates/symbols/src/document.rs
@@ -23,6 +23,7 @@ pub fn document_symbols(workspace: &Workspace, document: &Document) -> Vec<Symbo
| DocumentData::Log(_)
| DocumentData::Root
| DocumentData::Latexmkrc(_)
+ | DocumentData::FileList(_)
| DocumentData::Tectonic => Vec::new(),
};
diff --git a/support/texlab/crates/syntax/Cargo.toml b/support/texlab/crates/syntax/Cargo.toml
index a2d3d866b6..14dfffe380 100644
--- a/support/texlab/crates/syntax/Cargo.toml
+++ b/support/texlab/crates/syntax/Cargo.toml
@@ -7,8 +7,9 @@ edition.workspace = true
rust-version.workspace = true
[dependencies]
-itertools = "0.12.1"
+itertools = "0.13.0"
rowan = "0.15.15"
+rustc-hash = "2.0.0"
[lib]
doctest = false
diff --git a/support/texlab/crates/syntax/src/file_list.rs b/support/texlab/crates/syntax/src/file_list.rs
new file mode 100644
index 0000000000..cd32e787da
--- /dev/null
+++ b/support/texlab/crates/syntax/src/file_list.rs
@@ -0,0 +1,10 @@
+use std::path::PathBuf;
+
+use rustc_hash::FxHashSet;
+
+#[derive(Debug, PartialEq, Eq, Clone, Default)]
+pub struct FileList {
+ pub working_dir: Option<PathBuf>,
+ pub inputs: FxHashSet<PathBuf>,
+ pub outputs: FxHashSet<PathBuf>,
+}
diff --git a/support/texlab/crates/syntax/src/lib.rs b/support/texlab/crates/syntax/src/lib.rs
index 35f1bb8c52..d3e2098757 100644
--- a/support/texlab/crates/syntax/src/lib.rs
+++ b/support/texlab/crates/syntax/src/lib.rs
@@ -1,4 +1,5 @@
pub mod bibtex;
+pub mod file_list;
pub mod latex;
pub mod latexmkrc;
diff --git a/support/texlab/crates/texlab/Cargo.toml b/support/texlab/crates/texlab/Cargo.toml
index 4c142a2229..f4cb2d3283 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.16.0"
+version = "5.19.0"
license.workspace = true
readme = "README.md"
authors.workspace = true
@@ -22,15 +22,15 @@ test = false
doctest = false
[dependencies]
-anyhow = "1.0.82"
+anyhow = "1.0.86"
base-db = { path = "../base-db" }
bibfmt = { path = "../bibfmt" }
citeproc = { path = "../citeproc" }
-clap = { version = "4.5.4", features = ["derive"] }
+clap = { version = "4.5.8", features = ["derive"] }
commands = { path = "../commands" }
completion = { path = "../completion" }
completion-data = { path = "../completion-data" }
-crossbeam-channel = "0.5.12"
+crossbeam-channel = "0.5.13"
definition = { path = "../definition" }
diagnostics = { path = "../diagnostics" }
distro = { path = "../distro" }
@@ -42,22 +42,22 @@ inlay-hints = { path = "../inlay-hints" }
ipc = { path = "../ipc" }
line-index = { path = "../line-index" }
links = { path = "../links" }
-log = "0.4.21"
+log = "0.4.22"
lsp-server = "0.7.6"
lsp-types = "0.95.1"
notify = "6.1.1"
notify-debouncer-full = "0.3.1"
-parking_lot = "0.12.1"
+parking_lot = "0.12.3"
parser = { path = "../parser" }
references = { path = "../references" }
-regex = "1.10.4"
+regex = "1.10.5"
rename = { path = "../rename" }
rowan = "0.15.15"
-rustc-hash = "1.1.0"
-serde = "1.0.195"
-serde_json = "1.0.115"
+rustc-hash = "2.0.0"
+serde = "1.0.203"
+serde_json = "1.0.119"
serde_regex = "1.1.0"
-serde_repr = "0.1.18"
+serde_repr = "0.1.19"
symbols = { path = "../symbols" }
syntax = { path = "../syntax" }
tempfile = "3.10.1"
diff --git a/support/texlab/crates/texlab/src/features/folding.rs b/support/texlab/crates/texlab/src/features/folding.rs
index b19fa8a4da..3669021201 100644
--- a/support/texlab/crates/texlab/src/features/folding.rs
+++ b/support/texlab/crates/texlab/src/features/folding.rs
@@ -9,7 +9,7 @@ pub fn find_all(
) -> Option<Vec<serde_json::Value>> {
let params = from_proto::feature_params(workspace, params.text_document)?;
- let foldings = folding::find_all(&params.document)
+ let foldings = folding::find_all(params.document)
.into_iter()
.filter_map(|folding| {
to_proto::folding_range(folding, &params.document.line_index, client_flags)
diff --git a/support/texlab/crates/texlab/src/features/formatting.rs b/support/texlab/crates/texlab/src/features/formatting.rs
index 3fcd66e39b..9d152f6e8b 100644
--- a/support/texlab/crates/texlab/src/features/formatting.rs
+++ b/support/texlab/crates/texlab/src/features/formatting.rs
@@ -27,6 +27,7 @@ pub fn format_source_code(
| Language::Log
| Language::Root
| Language::Latexmkrc
- | Language::Tectonic => None,
+ | Language::Tectonic
+ | Language::FileList => None,
}
}
diff --git a/support/texlab/crates/texlab/src/features/rename.rs b/support/texlab/crates/texlab/src/features/rename.rs
index b905a7105b..a65f42143b 100644
--- a/support/texlab/crates/texlab/src/features/rename.rs
+++ b/support/texlab/crates/texlab/src/features/rename.rs
@@ -18,5 +18,5 @@ pub fn rename_all(
let new_name = &params.new_name;
let params = from_proto::rename_params(workspace, params.text_document_position)?;
let result = rename::rename(params);
- Some(to_proto::workspace_edit(result, &new_name))
+ Some(to_proto::workspace_edit(result, new_name))
}
diff --git a/support/texlab/crates/texlab/src/main.rs b/support/texlab/crates/texlab/src/main.rs
index ceca02b7f7..d9bf6833d8 100644
--- a/support/texlab/crates/texlab/src/main.rs
+++ b/support/texlab/crates/texlab/src/main.rs
@@ -110,6 +110,7 @@ fn setup_logger(opts: &Opts) {
OpenOptions::new()
.write(true)
.create(true)
+ .truncate(true)
.open(log_file)
.expect("failed to open log file"),
),
diff --git a/support/texlab/crates/texlab/src/server.rs b/support/texlab/crates/texlab/src/server.rs
index ef70c42c71..ff3c7904d3 100644
--- a/support/texlab/crates/texlab/src/server.rs
+++ b/support/texlab/crates/texlab/src/server.rs
@@ -46,7 +46,7 @@ use self::{
#[derive(Debug)]
enum InternalMessage {
SetDistro(Distro),
- SetOptions(Options),
+ SetOptions(Box<Options>),
FileEvent(Vec<DebouncedEvent>),
Diagnostics,
ChktexFinished(Url, Vec<diagnostics::Diagnostic>),
@@ -309,7 +309,9 @@ impl Server {
.parse_options(json.pop().expect("invalid configuration request"))
.unwrap();
- sender.send(InternalMessage::SetOptions(options)).unwrap();
+ sender
+ .send(InternalMessage::SetOptions(Box::new(options)))
+ .unwrap();
}
Err(why) => {
log::error!("Retrieving configuration failed: {}", why);
@@ -700,19 +702,19 @@ impl Server {
let status = if pending_builds.lock().remove(&pid) {
if result?.success() {
- BuildStatus::SUCCESS
+ BuildStatus::Success
} else {
- BuildStatus::ERROR
+ BuildStatus::Error
}
} else {
- BuildStatus::CANCELLED
+ BuildStatus::Cancelled
};
Ok(status)
})
.unwrap_or_else(|why| {
log::error!("Failed to compile document \"{uri}\": {why}");
- BuildStatus::FAILURE
+ BuildStatus::Failure
});
drop(progress_reporter);
@@ -723,7 +725,7 @@ impl Server {
let _ = client.send_response(lsp_server::Response::new_ok(id, result));
}
- if fwd_search_after && status != BuildStatus::CANCELLED {
+ if fwd_search_after && status != BuildStatus::Cancelled {
let _ = internal.send(InternalMessage::ForwardSearch(uri, params.position));
}
});
@@ -760,7 +762,7 @@ impl Server {
self.pool.execute(move || {
let status = match command.and_then(ForwardSearch::run) {
- Ok(()) => ForwardSearchStatus::SUCCESS,
+ Ok(()) => ForwardSearchStatus::Success,
Err(why) => {
log::error!("Failed to execute forward search: {why}");
ForwardSearchStatus::from(why)
@@ -1071,7 +1073,7 @@ impl Server {
self.workspace.write().set_distro(distro);
}
InternalMessage::SetOptions(options) => {
- self.update_options(options);
+ self.update_options(*options);
}
InternalMessage::FileEvent(events) => {
for event in events {
diff --git a/support/texlab/crates/texlab/src/server/extensions.rs b/support/texlab/crates/texlab/src/server/extensions.rs
index ce876c7892..8fa78ef3d2 100644
--- a/support/texlab/crates/texlab/src/server/extensions.rs
+++ b/support/texlab/crates/texlab/src/server/extensions.rs
@@ -33,10 +33,10 @@ pub struct BuildResult {
#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize_repr, Deserialize_repr)]
#[repr(i32)]
pub enum BuildStatus {
- SUCCESS = 0,
- ERROR = 1,
- FAILURE = 2,
- CANCELLED = 3,
+ Success = 0,
+ Error = 1,
+ Failure = 2,
+ Cancelled = 3,
}
pub struct ForwardSearchRequest;
@@ -52,21 +52,21 @@ impl lsp_types::request::Request for ForwardSearchRequest {
#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize_repr, Deserialize_repr)]
#[repr(i32)]
pub enum ForwardSearchStatus {
- SUCCESS = 0,
- ERROR = 1,
- FAILURE = 2,
- UNCONFIGURED = 3,
+ Success = 0,
+ Error = 1,
+ Failure = 2,
+ Unconfigured = 3,
}
impl From<ForwardSearchError> for ForwardSearchStatus {
fn from(why: ForwardSearchError) -> Self {
match why {
- ForwardSearchError::Unconfigured => ForwardSearchStatus::UNCONFIGURED,
- ForwardSearchError::NotLocal(_) => ForwardSearchStatus::FAILURE,
- ForwardSearchError::InvalidPath(_) => ForwardSearchStatus::ERROR,
- ForwardSearchError::TexNotFound(_) => ForwardSearchStatus::FAILURE,
- ForwardSearchError::PdfNotFound(_) => ForwardSearchStatus::ERROR,
- ForwardSearchError::LaunchViewer(_) => ForwardSearchStatus::ERROR,
+ ForwardSearchError::Unconfigured => ForwardSearchStatus::Unconfigured,
+ ForwardSearchError::NotLocal(_) => ForwardSearchStatus::Failure,
+ ForwardSearchError::InvalidPath(_) => ForwardSearchStatus::Error,
+ ForwardSearchError::TexNotFound(_) => ForwardSearchStatus::Failure,
+ ForwardSearchError::PdfNotFound(_) => ForwardSearchStatus::Error,
+ ForwardSearchError::LaunchViewer(_) => ForwardSearchStatus::Error,
}
}
}
diff --git a/support/texlab/crates/texlab/src/server/options.rs b/support/texlab/crates/texlab/src/server/options.rs
index 02200392f6..f4853d7cb9 100644
--- a/support/texlab/crates/texlab/src/server/options.rs
+++ b/support/texlab/crates/texlab/src/server/options.rs
@@ -1,11 +1,11 @@
-use regex::Regex;
use serde::{Deserialize, Serialize};
+use regex::Regex;
+
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[serde(default)]
pub struct Options {
- pub root_directory: Option<String>,
pub aux_directory: Option<String>,
pub bibtex_formatter: BibtexFormatter,
pub latex_formatter: LatexFormatter,
@@ -70,6 +70,7 @@ pub struct BuildOptions {
pub log_directory: Option<String>,
pub pdf_directory: Option<String>,
pub filename: Option<String>,
+ pub use_file_list: bool,
}
#[derive(Debug, PartialEq, Eq, Clone, Default, Serialize, Deserialize)]
@@ -126,7 +127,9 @@ pub struct ExperimentalOptions {
pub verbatim_environments: Vec<String>,
pub citation_commands: Vec<String>,
pub label_definition_commands: Vec<String>,
+ pub label_definition_prefixes: Vec<(String, String)>,
pub label_reference_commands: Vec<String>,
+ pub label_reference_prefixes: Vec<(String, String)>,
}
#[derive(Debug, PartialEq, Eq, Clone, Default, Serialize, Deserialize)]
diff --git a/support/texlab/crates/texlab/src/util.rs b/support/texlab/crates/texlab/src/util.rs
index d9ec5a2fb1..87e41a78ae 100644
--- a/support/texlab/crates/texlab/src/util.rs
+++ b/support/texlab/crates/texlab/src/util.rs
@@ -18,11 +18,30 @@ pub fn normalize_uri(uri: &mut lsp_types::Url) {
}
}
+ uri.set_path(&normalize_percent_encoding(uri.path()));
uri.set_fragment(None);
}
+fn normalize_percent_encoding(input: &str) -> String {
+ let mut output = String::new();
+ let mut i = 0;
+ for c in input.chars() {
+ if c == '%' && i == 0 {
+ output.push(c);
+ i = 2;
+ } else if i > 0 {
+ output.push(c.to_ascii_uppercase());
+ i -= 1;
+ } else {
+ output.push(c);
+ }
+ }
+
+ output
+}
+
fn fix_drive_letter(text: &str) -> Option<String> {
- if !text.is_ascii() || text.len() == 0 {
+ if !text.is_ascii() || text.is_empty() {
return None;
}
@@ -59,4 +78,44 @@ mod tests {
normalize_uri(&mut uri);
assert_eq!(uri.as_str(), "foo:///bar/baz.txt");
}
+
+ #[test]
+ #[cfg(unix)]
+ fn test_lowercase_percent_encoding_unix() {
+ let mut uri1 = Url::parse("file:///foo/%c3%a4.tex").unwrap();
+ let uri2 = Url::from_file_path("/foo/ä.tex").unwrap();
+
+ normalize_uri(&mut uri1);
+ assert_eq!(uri1, uri2);
+ }
+
+ #[test]
+ #[cfg(unix)]
+ fn test_uppercase_percent_encoding_unix() {
+ let mut uri1 = Url::parse("file:///foo/%C3%A4.tex").unwrap();
+ let uri2 = Url::from_file_path("/foo/ä.tex").unwrap();
+
+ normalize_uri(&mut uri1);
+ assert_eq!(uri1, uri2);
+ }
+
+ #[test]
+ #[cfg(windows)]
+ fn test_lowercase_percent_encoding_windows() {
+ let mut uri1 = Url::parse("file:///c%3a/foo/%c3%a4.tex").unwrap();
+ let uri2 = Url::from_file_path("C:/foo/ä.tex").unwrap();
+
+ normalize_uri(&mut uri1);
+ assert_eq!(uri1, uri2);
+ }
+
+ #[test]
+ #[cfg(windows)]
+ fn test_uppercase_percent_encoding_windows() {
+ let mut uri1 = Url::parse("file:///c%3A/foo/%C3%A4.tex").unwrap();
+ let uri2 = Url::from_file_path("C:/foo/ä.tex").unwrap();
+
+ normalize_uri(&mut uri1);
+ assert_eq!(uri1, uri2);
+ }
}
diff --git a/support/texlab/crates/texlab/src/util/client_flags.rs b/support/texlab/crates/texlab/src/util/client_flags.rs
index 842dbb1eae..2829041832 100644
--- a/support/texlab/crates/texlab/src/util/client_flags.rs
+++ b/support/texlab/crates/texlab/src/util/client_flags.rs
@@ -20,18 +20,12 @@ pub struct ClientFlags {
/// If not set, then fuzzy citation completion will not work.
pub completion_always_incomplete: bool,
- /// If `true`, the server can include markdown in hover responses.
- pub hover_markdown: bool,
-
/// If `true`, the server can pull the configuration from the client.
pub configuration_pull: bool,
/// If `true`, the client notifies the server when the configuration changes.
pub configuration_push: bool,
- /// If `true`, the client can return `LocationLink` instead of `Location`.
- pub definition_link: bool,
-
/// If `true`, the server can return custom kinds like `section`.
pub folding_custom_kinds: bool,
diff --git a/support/texlab/crates/texlab/src/util/from_proto.rs b/support/texlab/crates/texlab/src/util/from_proto.rs
index db4f3a5b39..b55e3cb0e3 100644
--- a/support/texlab/crates/texlab/src/util/from_proto.rs
+++ b/support/texlab/crates/texlab/src/util/from_proto.rs
@@ -56,15 +56,6 @@ pub fn client_flags(
let completion_always_incomplete = info.map_or(false, |info| info.name == "Visual Studio Code");
- let hover_markdown = capabilities
- .text_document
- .as_ref()
- .and_then(|cap| cap.hover.as_ref())
- .and_then(|cap| cap.content_format.as_ref())
- .map_or(false, |formats| {
- formats.contains(&lsp_types::MarkupKind::Markdown)
- });
-
let configuration_pull = capabilities
.workspace
.as_ref()
@@ -78,13 +69,6 @@ pub fn client_flags(
.and_then(|cap| cap.dynamic_registration)
.unwrap_or(false);
- let definition_link = capabilities
- .text_document
- .as_ref()
- .and_then(|cap| cap.definition)
- .and_then(|cap| cap.link_support)
- .unwrap_or(false);
-
let folding_custom_kinds = capabilities
.text_document
.as_ref()
@@ -111,30 +95,25 @@ pub fn client_flags(
completion_snippets,
completion_kinds,
completion_always_incomplete,
- hover_markdown,
configuration_pull,
configuration_push,
- definition_link,
folding_custom_kinds,
progress,
show_document,
}
}
-pub fn rename_params<'a>(
- workspace: &'a Workspace,
+pub fn rename_params(
+ workspace: &Workspace,
params: lsp_types::TextDocumentPositionParams,
-) -> Option<RenameParams<'a>> {
+) -> Option<RenameParams> {
let (feature, offset) =
feature_params_offset(workspace, params.text_document, params.position)?;
Some(RenameParams { feature, offset })
}
-pub fn hover_params<'a>(
- workspace: &'a Workspace,
- params: lsp_types::HoverParams,
-) -> Option<HoverParams<'a>> {
+pub fn hover_params(workspace: &Workspace, params: lsp_types::HoverParams) -> Option<HoverParams> {
let (feature, offset) = feature_params_offset(
workspace,
params.text_document_position_params.text_document,
@@ -144,8 +123,8 @@ pub fn hover_params<'a>(
Some(HoverParams { feature, offset })
}
-pub fn inlay_hint_params<'a>(
- workspace: &'a Workspace,
+pub fn inlay_hint_params(
+ workspace: &Workspace,
params: lsp_types::InlayHintParams,
) -> Option<InlayHintParams> {
let feature = feature_params(workspace, params.text_document)?;
@@ -153,10 +132,10 @@ pub fn inlay_hint_params<'a>(
Some(InlayHintParams { feature, range })
}
-pub fn highlight_params<'a>(
- workspace: &'a Workspace,
+pub fn highlight_params(
+ workspace: &Workspace,
params: lsp_types::DocumentHighlightParams,
-) -> Option<HighlightParams<'a>> {
+) -> Option<HighlightParams<'_>> {
let (feature, offset) = feature_params_offset(
workspace,
params.text_document_position_params.text_document,
@@ -166,10 +145,10 @@ pub fn highlight_params<'a>(
Some(HighlightParams { feature, offset })
}
-pub fn definition_params<'a>(
- workspace: &'a Workspace,
+pub fn definition_params(
+ workspace: &Workspace,
params: lsp_types::GotoDefinitionParams,
-) -> Option<DefinitionParams<'a>> {
+) -> Option<DefinitionParams> {
let (feature, offset) = feature_params_offset(
workspace,
params.text_document_position_params.text_document,
@@ -179,10 +158,10 @@ pub fn definition_params<'a>(
Some(DefinitionParams { feature, offset })
}
-pub fn completion_params<'a>(
- workspace: &'a Workspace,
+pub fn completion_params(
+ workspace: &Workspace,
params: lsp_types::CompletionParams,
-) -> Option<CompletionParams<'a>> {
+) -> Option<CompletionParams> {
let (feature, offset) = feature_params_offset(
workspace,
params.text_document_position.text_document,
@@ -192,10 +171,10 @@ pub fn completion_params<'a>(
Some(CompletionParams { feature, offset })
}
-pub fn reference_params<'a>(
- workspace: &'a Workspace,
+pub fn reference_params(
+ workspace: &Workspace,
params: lsp_types::ReferenceParams,
-) -> Option<ReferenceParams<'a>> {
+) -> Option<ReferenceParams> {
let (feature, offset) = feature_params_offset(
workspace,
params.text_document_position.text_document,
@@ -210,19 +189,19 @@ pub fn reference_params<'a>(
})
}
-pub fn feature_params<'a>(
- workspace: &'a Workspace,
+pub fn feature_params(
+ workspace: &Workspace,
text_document: lsp_types::TextDocumentIdentifier,
-) -> Option<FeatureParams<'a>> {
+) -> Option<FeatureParams> {
let document = workspace.lookup(&text_document.uri)?;
Some(FeatureParams::new(workspace, document))
}
-pub fn feature_params_offset<'a>(
- workspace: &'a Workspace,
+pub fn feature_params_offset(
+ workspace: &Workspace,
text_document: lsp_types::TextDocumentIdentifier,
position: lsp_types::Position,
-) -> Option<(FeatureParams<'a>, TextSize)> {
+) -> Option<(FeatureParams, TextSize)> {
let feature = feature_params(workspace, text_document)?;
let offset = feature.document.line_index.offset_lsp(position)?;
Some((feature, offset))
@@ -236,7 +215,6 @@ pub fn completion_resolve_info(item: &mut lsp_types::CompletionItem) -> Option<R
pub fn config(value: Options) -> Config {
let mut config = Config::default();
- config.root_dir = value.root_directory;
config.build.program = value.build.executable.unwrap_or(config.build.program);
config.build.args = value.build.args.unwrap_or(config.build.args);
@@ -362,8 +340,18 @@ pub fn config(value: Options) -> Config {
config
.syntax
+ .label_definition_prefixes
+ .extend(value.experimental.label_definition_prefixes);
+
+ config
+ .syntax
.label_reference_commands
.extend(value.experimental.label_reference_commands);
config
+ .syntax
+ .label_reference_prefixes
+ .extend(value.experimental.label_reference_prefixes);
+
+ config
}
diff --git a/support/texlab/crates/texlab/src/util/to_proto.rs b/support/texlab/crates/texlab/src/util/to_proto.rs
index f5cf2edf8b..d2c261c8fb 100644
--- a/support/texlab/crates/texlab/src/util/to_proto.rs
+++ b/support/texlab/crates/texlab/src/util/to_proto.rs
@@ -396,8 +396,15 @@ pub fn workspace_edit(result: RenameResult, new_name: &str) -> lsp_types::Worksp
let mut edits = Vec::new();
ranges
.into_iter()
- .filter_map(|range| document.line_index.line_col_lsp_range(range))
- .for_each(|range| edits.push(lsp_types::TextEdit::new(range, new_name.into())));
+ .filter_map(|info| {
+ document.line_index.line_col_lsp_range(info.range).map(|i| {
+ (
+ i,
+ info.prefix.map_or(new_name.into(), |p| p + new_name.into()),
+ )
+ })
+ })
+ .for_each(|(range, new_name)| edits.push(lsp_types::TextEdit::new(range, new_name)));
changes.insert(document.uri.clone(), edits);
}