diff options
Diffstat (limited to 'support/texlab')
49 files changed, 556 insertions, 171 deletions
diff --git a/support/texlab/CHANGELOG.md b/support/texlab/CHANGELOG.md index b165ced68e..cca502b4d3 100644 --- a/support/texlab/CHANGELOG.md +++ b/support/texlab/CHANGELOG.md @@ -5,6 +5,22 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [5.7.0] - 2023-06-07 + +### Added + +- Add symbol support for `thmtools` package ([#894](https://github.com/latex-lsp/texlab/issues/894)) +- Add `texlab.findEnvironments` command to return the list of environments containing a position ([#892](https://github.com/latex-lsp/texlab/issues/892)) + +### Changed + +- Show inlay hints for labels after the command instead of inside the argument ([#890](https://github.com/latex-lsp/texlab/issues/890)) + +### Fixed + +- Prevent adding trailing newline after formatting with `latexmk` ([#895](https://github.com/latex-lsp/texlab/issues/895)) +- Improving `\paragraph` parsing + ## [5.6.0] - 2023-05-20 ### Added diff --git a/support/texlab/Cargo.lock b/support/texlab/Cargo.lock index aceaaf083a..b69b6e82e8 100644 --- a/support/texlab/Cargo.lock +++ b/support/texlab/Cargo.lock @@ -106,17 +106,6 @@ dependencies = [ ] [[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", -] - -[[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -256,18 +245,6 @@ dependencies = [ [[package]] name = "clap" -version = "3.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" -dependencies = [ - "bitflags", - "clap_lex 0.2.4", - "indexmap", - "textwrap", -] - -[[package]] -name = "clap" version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93aae7a4192245f70fe75dd9157fc7b4a5bf53e88d30bd4396f7d8f9284d5acc" @@ -286,7 +263,7 @@ dependencies = [ "anstream", "anstyle", "bitflags", - "clap_lex 0.5.0", + "clap_lex", "strsim", ] @@ -304,15 +281,6 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" -dependencies = [ - "os_str_bytes", -] - -[[package]] -name = "clap_lex" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" @@ -331,12 +299,15 @@ dependencies = [ "base-db", "bstr", "crossbeam-channel", + "distro", + "insta", "itertools", "libc", "log", "rowan", "rustc-hash", "syntax", + "test-utils", "thiserror", "url", ] @@ -379,19 +350,19 @@ dependencies = [ [[package]] name = "criterion" -version = "0.4.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7c76e09c1aae2bc52b3d2f29e13c6572553b30c4aa1b8a49fd70de6412654cb" +checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" dependencies = [ "anes", - "atty", "cast", "ciborium", - "clap 3.2.25", + "clap", "criterion-plot", + "is-terminal", "itertools", - "lazy_static", "num-traits", + "once_cell", "oorandom", "plotters", "rayon", @@ -683,15 +654,6 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" @@ -735,16 +697,6 @@ dependencies = [ ] [[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown", -] - -[[package]] name = "inotify" version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1012,9 +964,9 @@ dependencies = [ [[package]] name = "notify" -version = "5.2.0" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "729f63e1ca555a43fe3efa4f3efdf4801c479da85b432242a7b726f353c88486" +checksum = "4d9ba6c734de18ca27c8cef5cd7058aa4ac9f63596131e4c7e41e579319032a2" dependencies = [ "bitflags", "crossbeam-channel", @@ -1076,12 +1028,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] -name = "os_str_bytes" -version = "6.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267" - -[[package]] name = "parking_lot" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1566,13 +1512,13 @@ dependencies = [ [[package]] name = "texlab" -version = "5.6.0" +version = "5.7.0" dependencies = [ "anyhow", "assert_unordered", "base-db", "citeproc", - "clap 4.3.0", + "clap", "commands", "criterion", "crossbeam-channel", @@ -1614,12 +1560,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "288cb548dbe72b652243ea797201f3d481a0609a967980fcc5b2315ea811560a" [[package]] -name = "textwrap" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" - -[[package]] name = "thiserror" version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/support/texlab/crates/base-db/Cargo.toml b/support/texlab/crates/base-db/Cargo.toml index c968cefac9..2b44acaf3c 100644 --- a/support/texlab/crates/base-db/Cargo.toml +++ b/support/texlab/crates/base-db/Cargo.toml @@ -7,15 +7,15 @@ edition.workspace = true rust-version.workspace = true [dependencies] -dirs = "5.0.0" +dirs = "5.0.1" distro = { path = "../distro" } itertools = "0.10.5" log = "0.4.17" -notify = "5.1.0" +notify = "6.0.0" once_cell = "1.17.1" parser = { path = "../parser" } percent-encoding = "2.2.0" -regex = "1.7.3" +regex = "1.8.1" rowan = "0.15.11" rustc-hash = "1.1.0" syntax = { path = "../syntax" } diff --git a/support/texlab/crates/base-db/src/diagnostics/bib.rs b/support/texlab/crates/base-db/src/diagnostics/bib.rs index f931a43c51..67fcf412ad 100644 --- a/support/texlab/crates/base-db/src/diagnostics/bib.rs +++ b/support/texlab/crates/base-db/src/diagnostics/bib.rs @@ -41,8 +41,6 @@ fn analyze_entry(document: &mut Document, entry: bibtex::Entry) { range: TextRange::empty(entry.syntax().text_range().end()), code: ErrorCode::ExpectingRCurly, }); - - return; } } @@ -63,7 +61,5 @@ fn analyze_field(document: &mut Document, field: bibtex::Field) { range: field.name_token().unwrap().text_range(), code, }); - - return; } } diff --git a/support/texlab/crates/base-db/src/graph.rs b/support/texlab/crates/base-db/src/graph.rs index b16245e011..5e727d2bd2 100644 --- a/support/texlab/crates/base-db/src/graph.rs +++ b/support/texlab/crates/base-db/src/graph.rs @@ -108,7 +108,7 @@ impl<'a> Graph<'a> { let new_base_dir = link .base_dir .as_deref() - .and_then(|path| base_dir.join(&path).ok()) + .and_then(|path| base_dir.join(path).ok()) .unwrap_or_else(|| base_dir.clone()); let weight = Some(EdgeWeight { @@ -148,7 +148,7 @@ impl<'a> Graph<'a> { path.set_extension(extension); let Some(target_uri) = path.file_name() .and_then(OsStr::to_str) - .and_then(|name| self.workspace.output_dir(base_dir).join(&name).ok()) else { return }; + .and_then(|name| self.workspace.output_dir(base_dir).join(name).ok()) else { return }; match self.workspace.lookup(&target_uri) { Some(target) => { diff --git a/support/texlab/crates/base-db/src/semantics/tex.rs b/support/texlab/crates/base-db/src/semantics/tex.rs index 46c805ba8a..1445ae12e7 100644 --- a/support/texlab/crates/base-db/src/semantics/tex.rs +++ b/support/texlab/crates/base-db/src/semantics/tex.rs @@ -105,6 +105,7 @@ impl Semantics { fn process_label_definition(&mut self, label: latex::LabelDefinition) { let Some(name) = label.name().and_then(|group| group.key()) else { return }; + let full_range = latex::small_range(&label); let mut objects = Vec::new(); for node in label.syntax().ancestors() { if let Some(section) = latex::Section::cast(node.clone()) { @@ -169,27 +170,32 @@ impl Semantics { kind: LabelKind::Definition, name: Span::from(&name), targets: objects, + full_range, }); } fn process_label_reference(&mut self, 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, }); } } fn process_label_reference_range(&mut self, 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, }); } @@ -198,6 +204,7 @@ impl Semantics { kind: LabelKind::ReferenceRange, name: Span::from(&to), targets: Vec::new(), + full_range, }); } } @@ -216,13 +223,11 @@ impl Semantics { fn process_theorem_definition(&mut self, theorem_def: latex::TheoremDefinition) { let Some(name) = theorem_def.name().and_then(|name| name.key()) else { return }; - let Some(description) = theorem_def - .heading() - .and_then(|group| group.content_text()) else { return }; + let Some(heading) = theorem_def.heading() else { return }; self.theorem_definitions.push(TheoremDefinition { name: Span::from(&name), - heading: description, + heading, }); } } @@ -265,6 +270,7 @@ pub struct Label { pub kind: LabelKind, pub name: Span, pub targets: Vec<LabelTarget>, + pub full_range: TextRange, } #[derive(Debug, Clone)] diff --git a/support/texlab/crates/base-db/src/workspace.rs b/support/texlab/crates/base-db/src/workspace.rs index 581d93cfc3..58c7567f9d 100644 --- a/support/texlab/crates/base-db/src/workspace.rs +++ b/support/texlab/crates/base-db/src/workspace.rs @@ -75,7 +75,8 @@ impl Workspace { Cow::Owned(text) => text, }; - Ok(self.open(uri, text, language, owner, LineCol { line: 0, col: 0 })) + self.open(uri, text, language, owner, LineCol { line: 0, col: 0 }); + Ok(()) } pub fn edit(&mut self, uri: &Url, delete: TextRange, insert: &str) -> Option<()> { diff --git a/support/texlab/crates/citeproc/Cargo.toml b/support/texlab/crates/citeproc/Cargo.toml index 353292c484..fb230323b0 100644 --- a/support/texlab/crates/citeproc/Cargo.toml +++ b/support/texlab/crates/citeproc/Cargo.toml @@ -8,7 +8,7 @@ rust-version.workspace = true [dependencies] chrono = { version = "0.4.24", default-features = false, features = ["std"] } -human_name = "2.0.1" +human_name = "2.0.2" isocountry = "0.3.2" itertools = "0.10.5" rowan = "0.15.11" diff --git a/support/texlab/crates/commands/Cargo.toml b/support/texlab/crates/commands/Cargo.toml index 68d034675e..1f3a1bddd9 100644 --- a/support/texlab/crates/commands/Cargo.toml +++ b/support/texlab/crates/commands/Cargo.toml @@ -7,7 +7,7 @@ edition.workspace = true rust-version.workspace = true [dependencies] -anyhow = "1.0.70" +anyhow = "1.0.71" base-db = { path = "../base-db" } bstr = "1.4.0" crossbeam-channel = "0.5.8" @@ -20,5 +20,10 @@ syntax = { path = "../syntax" } thiserror = "1.0.40" url = "2.3.1" +[dev-dependencies] +distro = { path = "../distro" } +insta = { version = "1.29.0", features = ["json"] } +test-utils = { path = "../test-utils" } + [lib] doctest = false diff --git a/support/texlab/crates/commands/src/find_envs.rs b/support/texlab/crates/commands/src/find_envs.rs new file mode 100644 index 0000000000..20b11c9e37 --- /dev/null +++ b/support/texlab/crates/commands/src/find_envs.rs @@ -0,0 +1,65 @@ +use base_db::{semantics::Span, Document, DocumentData}; +use rowan::{ast::AstNode, TextRange, TextSize}; +use syntax::latex; + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct EnvironmentMatch { + pub name: Span, + pub full_range: TextRange, +} + +pub fn find_environments(document: &Document, offset: TextSize) -> Vec<EnvironmentMatch> { + let DocumentData::Tex(data) = &document.data else { return Vec::new() }; + + let root = latex::SyntaxNode::new_root(data.green.clone()); + + let Some(token) = root.token_at_offset(offset).right_biased() else { return Vec::new() }; + + let mut results = Vec::new(); + for environment in token + .parent_ancestors() + .filter_map(latex::Environment::cast) + { + let Some(name) = environment + .begin() + .and_then(|begin| begin.name()) + .and_then(|group| group.key()) + .map(|name| Span::from(&name)) else { continue }; + + let full_range = latex::small_range(&environment); + results.push(EnvironmentMatch { name, full_range }); + } + + results.reverse(); + results +} + +#[cfg(test)] +mod tests { + use insta::assert_debug_snapshot; + use test_utils::fixture::Fixture; + + use crate::find_environments; + + #[test] + fn test() { + let fixture = Fixture::parse( + r#" +%! main.tex +\begin{a} + \begin{b} + \begin{c} + | + \end{c} + \end{b} + \begin{d} + \end{d} +\end{a}"#, + ); + + let workspace = fixture.workspace; + let document = workspace.iter().next().unwrap(); + let results = find_environments(&document, fixture.documents[0].cursor.unwrap()); + assert_debug_snapshot!(results); + } +} diff --git a/support/texlab/crates/commands/src/fwd_search.rs b/support/texlab/crates/commands/src/fwd_search.rs index fc0a130f86..55c2df59a0 100644 --- a/support/texlab/crates/commands/src/fwd_search.rs +++ b/support/texlab/crates/commands/src/fwd_search.rs @@ -75,12 +75,12 @@ impl ForwardSearch { }; if !pdf_path.exists() { - return Err(ForwardSearchError::PdfNotFound(pdf_path.clone())); + return Err(ForwardSearchError::PdfNotFound(pdf_path)); } let tex_path = tex_path.to_string_lossy().into_owned(); let pdf_path = pdf_path.to_string_lossy().into_owned(); - let line = line.unwrap_or_else(|| child.cursor.line); + let line = line.unwrap_or(child.cursor.line); let line = (line + 1).to_string(); let program = config.program.clone(); diff --git a/support/texlab/crates/commands/src/lib.rs b/support/texlab/crates/commands/src/lib.rs index bcf4c8538f..8023c8d66c 100644 --- a/support/texlab/crates/commands/src/lib.rs +++ b/support/texlab/crates/commands/src/lib.rs @@ -2,6 +2,7 @@ mod build; mod change_env; mod clean; mod dep_graph; +mod find_envs; mod fwd_search; mod placeholders; @@ -10,5 +11,6 @@ pub use self::{ change_env::{change_environment, ChangeEnvironmentResult}, clean::{CleanCommand, CleanTarget}, dep_graph::show_dependency_graph, + find_envs::find_environments, fwd_search::{ForwardSearch, ForwardSearchError}, }; diff --git a/support/texlab/crates/commands/src/placeholders.rs b/support/texlab/crates/commands/src/placeholders.rs index 913af33edf..9994420f5d 100644 --- a/support/texlab/crates/commands/src/placeholders.rs +++ b/support/texlab/crates/commands/src/placeholders.rs @@ -17,7 +17,7 @@ pub fn replace_placeholders(args: &[String], pairs: &[(char, &str)]) -> Vec<Stri if ch == '%' { match chars.next() { Some(key) => match map.get(&key) { - Some(value) => output.push_str(&value), + Some(value) => output.push_str(value), None => output.push(key), }, None => output.push('%'), diff --git a/support/texlab/crates/commands/src/snapshots/commands__find_envs__tests__test.snap b/support/texlab/crates/commands/src/snapshots/commands__find_envs__tests__test.snap new file mode 100644 index 0000000000..fa532f125a --- /dev/null +++ b/support/texlab/crates/commands/src/snapshots/commands__find_envs__tests__test.snap @@ -0,0 +1,27 @@ +--- +source: crates/commands/src/find_envs.rs +expression: results +--- +[ + EnvironmentMatch { + name: Span( + "a", + 7..8, + ), + full_range: 0..87, + }, + EnvironmentMatch { + name: Span( + "b", + 19..20, + ), + full_range: 12..57, + }, + EnvironmentMatch { + name: Span( + "c", + 33..34, + ), + full_range: 26..47, + }, +] diff --git a/support/texlab/crates/distro/Cargo.toml b/support/texlab/crates/distro/Cargo.toml index b450aa2631..d7c336a041 100644 --- a/support/texlab/crates/distro/Cargo.toml +++ b/support/texlab/crates/distro/Cargo.toml @@ -7,7 +7,7 @@ edition.workspace = true rust-version.workspace = true [dependencies] -anyhow = "1.0.70" +anyhow = "1.0.71" rustc-hash = "1.1.0" [lib] diff --git a/support/texlab/crates/parser/Cargo.toml b/support/texlab/crates/parser/Cargo.toml index 8e8b88841f..1b57d5aec1 100644 --- a/support/texlab/crates/parser/Cargo.toml +++ b/support/texlab/crates/parser/Cargo.toml @@ -9,7 +9,7 @@ rust-version.workspace = true [dependencies] logos = "0.13.0" once_cell = "1.17.1" -regex = "1.7.3" +regex = "1.8.1" rowan = "0.15.11" rustc-hash = "1.1.0" syntax = { path = "../syntax" } diff --git a/support/texlab/crates/parser/src/latex.rs b/support/texlab/crates/parser/src/latex.rs index c42031dcf1..63c160d4e2 100644 --- a/support/texlab/crates/parser/src/latex.rs +++ b/support/texlab/crates/parser/src/latex.rs @@ -6,7 +6,7 @@ use syntax::latex::SyntaxKind::{self, *}; use crate::SyntaxConfig; use self::lexer::{ - types::{CommandName, SectionLevel, Token}, + types::{CommandName, ParagraphLevel, SectionLevel, Token}, Lexer, }; @@ -114,6 +114,7 @@ impl<'a> Parser<'a> { CommandName::BeginEquation => self.equation(), CommandName::EndEquation => self.generic_command(), CommandName::Section(level) => self.section(level), + CommandName::Paragraph(level) => self.paragraph(level), CommandName::EnumItem => self.enum_item(), CommandName::Caption => self.caption(), CommandName::Citation => self.citation(), @@ -138,7 +139,8 @@ impl<'a> Parser<'a> { CommandName::AcronymDefinition => self.acronym_definition(), CommandName::AcronymDeclaration => self.acronym_declaration(), CommandName::AcronymReference => self.acronym_reference(), - CommandName::TheoremDefinition => self.theorem_definition(), + CommandName::TheoremDefinitionAmsThm => self.theorem_definition_amsthm(), + CommandName::TheoremDefinitionThmTools => self.theorem_definition_thmtools(), CommandName::ColorReference => self.color_reference(), CommandName::ColorDefinition => self.color_definition(), CommandName::ColorSetDefinition => self.color_set_definition(), @@ -559,8 +561,6 @@ impl<'a> Parser<'a> { SectionLevel::Section => SECTION, SectionLevel::Subsection => SUBSECTION, SectionLevel::Subsubsection => SUBSUBSECTION, - SectionLevel::Paragraph => PARAGRAPH, - SectionLevel::Subparagraph => SUBPARAGRAPH, }; self.builder.start_node(node_kind.into()); @@ -583,6 +583,33 @@ impl<'a> Parser<'a> { self.builder.finish_node(); } + fn paragraph(&mut self, level: ParagraphLevel) { + let node_kind = match level { + ParagraphLevel::Paragraph => PARAGRAPH, + ParagraphLevel::Subparagraph => SUBPARAGRAPH, + }; + + self.builder.start_node(node_kind.into()); + self.eat(); + self.trivia(); + + if self.peek() == Some(Token::LCurly) { + self.curly_group(); + } + + while let Some(kind) = self.peek() { + match kind { + Token::RCurly => break, + Token::CommandName(CommandName::EndEnvironment) => break, + Token::CommandName(CommandName::Section(_)) => break, + Token::CommandName(CommandName::Paragraph(nested)) if nested <= level => break, + _ => self.content(ParserContext::default()), + } + } + + self.builder.finish_node(); + } + fn enum_item(&mut self) { self.builder.start_node(ENUM_ITEM.into()); self.eat(); @@ -978,8 +1005,8 @@ impl<'a> Parser<'a> { self.builder.finish_node(); } - fn theorem_definition(&mut self) { - self.builder.start_node(THEOREM_DEFINITION.into()); + fn theorem_definition_amsthm(&mut self) { + self.builder.start_node(THEOREM_DEFINITION_AMSTHM.into()); self.eat(); self.trivia(); @@ -1002,6 +1029,22 @@ impl<'a> Parser<'a> { self.builder.finish_node(); } + fn theorem_definition_thmtools(&mut self) { + self.builder.start_node(THEOREM_DEFINITION_THMTOOLS.into()); + self.eat(); + self.trivia(); + + if self.lexer.peek() == Some(Token::LBrack) { + self.brack_group_key_value(); + } + + if self.lexer.peek() == Some(Token::LCurly) { + self.curly_group_word(); + } + + self.builder.finish_node(); + } + fn color_reference(&mut self) { self.builder.start_node(COLOR_REFERENCE.into()); self.eat(); diff --git a/support/texlab/crates/parser/src/latex/lexer/commands.rs b/support/texlab/crates/parser/src/latex/lexer/commands.rs index c5fe48e0c9..b6e1d11737 100644 --- a/support/texlab/crates/parser/src/latex/lexer/commands.rs +++ b/support/texlab/crates/parser/src/latex/lexer/commands.rs @@ -1,6 +1,6 @@ use crate::SyntaxConfig; -use super::types::{CommandName, SectionLevel}; +use super::types::{CommandName, ParagraphLevel, SectionLevel}; pub fn classify(name: &str, config: &SyntaxConfig) -> CommandName { match name { @@ -13,8 +13,8 @@ pub fn classify(name: &str, config: &SyntaxConfig) -> CommandName { "section" | "section*" => CommandName::Section(SectionLevel::Section), "subsection" | "subsection*" => CommandName::Section(SectionLevel::Subsection), "subsubsection" | "subsubsection*" => CommandName::Section(SectionLevel::Subsubsection), - "paragraph" | "paragraph*" => CommandName::Section(SectionLevel::Paragraph), - "subparagraph" | "subparagraph*" => CommandName::Section(SectionLevel::Subparagraph), + "paragraph" | "paragraph*" => CommandName::Paragraph(ParagraphLevel::Paragraph), + "subparagraph" | "subparagraph*" => CommandName::Paragraph(ParagraphLevel::Subparagraph), "item" => CommandName::EnumItem, "caption" => CommandName::Caption, "usepackage" | "RequirePackage" => CommandName::PackageInclude, @@ -67,9 +67,8 @@ pub fn classify(name: &str, config: &SyntaxConfig) -> CommandName { | "Glsentrylong" | "glsentrylongpl" | "Glsentrylongpl" | "glsentryshort" | "Glsentryshort" | "glsentryshortpl" | "Glsentryshortpl" | "glsentryfullpl" | "Glsentryfullpl" => CommandName::AcronymReference, - "newtheorem" | "newtheorem*" | "declaretheorem" | "declaretheorem*" => { - CommandName::TheoremDefinition - } + "newtheorem" | "newtheorem*" => CommandName::TheoremDefinitionAmsThm, + "declaretheorem" | "declaretheorem*" => CommandName::TheoremDefinitionThmTools, "color" | "colorbox" | "textcolor" | "pagecolor" => CommandName::ColorReference, "definecolor" => CommandName::ColorDefinition, "definecolorset" => CommandName::ColorSetDefinition, diff --git a/support/texlab/crates/parser/src/latex/lexer/types.rs b/support/texlab/crates/parser/src/latex/lexer/types.rs index eea6ea3b44..607138a448 100644 --- a/support/texlab/crates/parser/src/latex/lexer/types.rs +++ b/support/texlab/crates/parser/src/latex/lexer/types.rs @@ -58,7 +58,7 @@ fn lex_command_name(lexer: &mut logos::Lexer<Token>) -> CommandName { return CommandName::Generic; } - while let Some(c) = chars.next() { + for c in chars { match c { '*' => { lexer.bump(c.len_utf8()); @@ -87,6 +87,7 @@ pub enum CommandName { BeginEquation, EndEquation, Section(SectionLevel), + Paragraph(ParagraphLevel), EnumItem, Caption, Citation, @@ -111,7 +112,8 @@ pub enum CommandName { AcronymDefinition, AcronymDeclaration, AcronymReference, - TheoremDefinition, + TheoremDefinitionAmsThm, + TheoremDefinitionThmTools, ColorReference, ColorDefinition, ColorSetDefinition, @@ -130,6 +132,10 @@ pub enum SectionLevel { Section, Subsection, Subsubsection, +} + +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)] +pub enum ParagraphLevel { Paragraph, Subparagraph, } diff --git a/support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@structure__paragraphs.txt.snap b/support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@structure__paragraphs.txt.snap new file mode 100644 index 0000000000..7c3e7fae57 --- /dev/null +++ b/support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@structure__paragraphs.txt.snap @@ -0,0 +1,67 @@ +--- +source: crates/parser/src/latex.rs +expression: root +input_file: crates/parser/src/test_data/latex/structure/paragraphs.txt +--- +ROOT@0..134 + PREAMBLE@0..134 + SECTION@0..105 + COMMAND_NAME@0..8 "\\section" + CURLY_GROUP@8..20 + L_CURLY@8..9 "{" + TEXT@9..18 + WORD@9..16 "Section" + WHITESPACE@16..17 " " + WORD@17..18 "1" + R_CURLY@18..19 "}" + LINE_BREAK@19..20 "\n" + TEXT@20..31 + WORD@20..27 "Section" + WHITESPACE@27..28 " " + WORD@28..29 "1" + LINE_BREAK@29..31 "\n\n" + PARAGRAPH@31..68 + COMMAND_NAME@31..41 "\\paragraph" + CURLY_GROUP@41..55 + L_CURLY@41..42 "{" + TEXT@42..53 + WORD@42..51 "Paragraph" + WHITESPACE@51..52 " " + WORD@52..53 "1" + R_CURLY@53..54 "}" + LINE_BREAK@54..55 "\n" + TEXT@55..68 + WORD@55..64 "Paragraph" + WHITESPACE@64..65 " " + WORD@65..66 "1" + LINE_BREAK@66..68 "\n\n" + PARAGRAPH@68..105 + COMMAND_NAME@68..78 "\\paragraph" + CURLY_GROUP@78..92 + L_CURLY@78..79 "{" + TEXT@79..90 + WORD@79..88 "Paragraph" + WHITESPACE@88..89 " " + WORD@89..90 "2" + R_CURLY@90..91 "}" + LINE_BREAK@91..92 "\n" + TEXT@92..105 + WORD@92..101 "Paragraph" + WHITESPACE@101..102 " " + WORD@102..103 "2" + LINE_BREAK@103..105 "\n\n" + SECTION@105..134 + COMMAND_NAME@105..113 "\\section" + CURLY_GROUP@113..125 + L_CURLY@113..114 "{" + TEXT@114..123 + WORD@114..121 "Section" + WHITESPACE@121..122 " " + WORD@122..123 "2" + R_CURLY@123..124 "}" + LINE_BREAK@124..125 "\n" + TEXT@125..134 + WORD@125..132 "Section" + WHITESPACE@132..133 " " + WORD@133..134 "2" + diff --git a/support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@theorem_definition__theorem_definition_full.txt.snap b/support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@theorem_definition__theorem_definition_full.txt.snap index c21f26976e..ce42bde1d3 100644 --- a/support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@theorem_definition__theorem_definition_full.txt.snap +++ b/support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@theorem_definition__theorem_definition_full.txt.snap @@ -5,7 +5,7 @@ input_file: crates/parser/src/test_data/latex/theorem_definition/theorem_definit --- ROOT@0..31 PREAMBLE@0..31 - THEOREM_DEFINITION@0..31 + THEOREM_DEFINITION_AMSTHM@0..31 COMMAND_NAME@0..11 "\\newtheorem" CURLY_GROUP_WORD@11..16 L_CURLY@11..12 "{" diff --git a/support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@theorem_definition__theorem_definition_name_with_counter.txt.snap b/support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@theorem_definition__theorem_definition_name_with_counter.txt.snap index d4c5d787b5..c1e7ad5387 100644 --- a/support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@theorem_definition__theorem_definition_name_with_counter.txt.snap +++ b/support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@theorem_definition__theorem_definition_name_with_counter.txt.snap @@ -5,7 +5,7 @@ input_file: crates/parser/src/test_data/latex/theorem_definition/theorem_definit --- ROOT@0..21 PREAMBLE@0..21 - THEOREM_DEFINITION@0..21 + THEOREM_DEFINITION_AMSTHM@0..21 COMMAND_NAME@0..11 "\\newtheorem" CURLY_GROUP_WORD@11..16 L_CURLY@11..12 "{" diff --git a/support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@theorem_definition__theorem_definition_name_with_description.txt.snap b/support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@theorem_definition__theorem_definition_name_with_description.txt.snap index b269ac10d0..13c043c94f 100644 --- a/support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@theorem_definition__theorem_definition_name_with_description.txt.snap +++ b/support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@theorem_definition__theorem_definition_name_with_description.txt.snap @@ -5,7 +5,7 @@ input_file: crates/parser/src/test_data/latex/theorem_definition/theorem_definit --- ROOT@0..21 PREAMBLE@0..21 - THEOREM_DEFINITION@0..21 + THEOREM_DEFINITION_AMSTHM@0..21 COMMAND_NAME@0..11 "\\newtheorem" CURLY_GROUP_WORD@11..16 L_CURLY@11..12 "{" diff --git a/support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@theorem_definition__theorem_definition_name_with_description_and_counter.txt.snap b/support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@theorem_definition__theorem_definition_name_with_description_and_counter.txt.snap index 230f1fac29..57f4f7ce1b 100644 --- a/support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@theorem_definition__theorem_definition_name_with_description_and_counter.txt.snap +++ b/support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@theorem_definition__theorem_definition_name_with_description_and_counter.txt.snap @@ -5,7 +5,7 @@ input_file: crates/parser/src/test_data/latex/theorem_definition/theorem_definit --- ROOT@0..26 PREAMBLE@0..26 - THEOREM_DEFINITION@0..26 + THEOREM_DEFINITION_AMSTHM@0..26 COMMAND_NAME@0..11 "\\newtheorem" CURLY_GROUP_WORD@11..16 L_CURLY@11..12 "{" diff --git a/support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@theorem_definition__theorem_definition_only_name.txt.snap b/support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@theorem_definition__theorem_definition_only_name.txt.snap index b01de34857..22674fbbba 100644 --- a/support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@theorem_definition__theorem_definition_only_name.txt.snap +++ b/support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@theorem_definition__theorem_definition_only_name.txt.snap @@ -5,7 +5,7 @@ input_file: crates/parser/src/test_data/latex/theorem_definition/theorem_definit --- ROOT@0..16 PREAMBLE@0..16 - THEOREM_DEFINITION@0..16 + THEOREM_DEFINITION_AMSTHM@0..16 COMMAND_NAME@0..11 "\\newtheorem" CURLY_GROUP_WORD@11..16 L_CURLY@11..12 "{" diff --git a/support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@theorem_definition__theorem_definition_thmtools.txt.snap b/support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@theorem_definition__theorem_definition_thmtools.txt.snap new file mode 100644 index 0000000000..8b00bb4b59 --- /dev/null +++ b/support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@theorem_definition__theorem_definition_thmtools.txt.snap @@ -0,0 +1,35 @@ +--- +source: crates/parser/src/latex.rs +expression: root +input_file: crates/parser/src/test_data/latex/theorem_definition/theorem_definition_thmtools.txt +--- +ROOT@0..41 + PREAMBLE@0..41 + THEOREM_DEFINITION_THMTOOLS@0..41 + COMMAND_NAME@0..15 "\\declaretheorem" + BRACK_GROUP_KEY_VALUE@15..36 + L_BRACK@15..16 "[" + KEY_VALUE_BODY@16..35 + KEY_VALUE_PAIR@16..25 + KEY@16..21 + WORD@16..21 "style" + EQUALITY_SIGN@21..22 "=" + VALUE@22..25 + TEXT@22..25 + WORD@22..25 "foo" + COMMA@25..26 "," + WHITESPACE@26..27 " " + KEY_VALUE_PAIR@27..35 + KEY@27..31 + WORD@27..31 "name" + EQUALITY_SIGN@31..32 "=" + VALUE@32..35 + TEXT@32..35 + WORD@32..35 "bar" + R_BRACK@35..36 "]" + CURLY_GROUP_WORD@36..41 + L_CURLY@36..37 "{" + KEY@37..40 + WORD@37..40 "baz" + R_CURLY@40..41 "}" + diff --git a/support/texlab/crates/parser/src/test_data/latex/structure/paragraphs.txt b/support/texlab/crates/parser/src/test_data/latex/structure/paragraphs.txt new file mode 100644 index 0000000000..a7e32353bb --- /dev/null +++ b/support/texlab/crates/parser/src/test_data/latex/structure/paragraphs.txt @@ -0,0 +1,11 @@ +\section{Section 1} +Section 1 + +\paragraph{Paragraph 1} +Paragraph 1 + +\paragraph{Paragraph 2} +Paragraph 2 + +\section{Section 2} +Section 2
\ No newline at end of file diff --git a/support/texlab/crates/parser/src/test_data/latex/theorem_definition/theorem_definition_thmtools.txt b/support/texlab/crates/parser/src/test_data/latex/theorem_definition/theorem_definition_thmtools.txt new file mode 100644 index 0000000000..2662a5ca8c --- /dev/null +++ b/support/texlab/crates/parser/src/test_data/latex/theorem_definition/theorem_definition_thmtools.txt @@ -0,0 +1 @@ +\declaretheorem[style=foo, name=bar]{baz}
\ No newline at end of file diff --git a/support/texlab/crates/symbols/Cargo.toml b/support/texlab/crates/symbols/Cargo.toml index d1d5bd2d8b..b79e671597 100644 --- a/support/texlab/crates/symbols/Cargo.toml +++ b/support/texlab/crates/symbols/Cargo.toml @@ -20,5 +20,5 @@ url = "2.3.1" [dev-dependencies] insta = "1.29.0" -regex = "1.7.3" +regex = "1.8.1" test-utils = { path = "../test-utils" } diff --git a/support/texlab/crates/symbols/src/document.rs b/support/texlab/crates/symbols/src/document.rs index eb3d8d339f..b34974e019 100644 --- a/support/texlab/crates/symbols/src/document.rs +++ b/support/texlab/crates/symbols/src/document.rs @@ -37,7 +37,6 @@ fn filter_symbols(container: &mut Vec<Symbol>, config: &SymbolConfig) { while i < container.len() { let symbol = &mut container[i]; if symbol.name.is_empty() || !util::filter_regex_patterns(&symbol.name, allowed, ignored) { - drop(symbol); let mut symbol = container.remove(i); container.append(&mut symbol.children); } else { diff --git a/support/texlab/crates/symbols/src/document/snapshots/symbols__document__tests__theorem.snap b/support/texlab/crates/symbols/src/document/snapshots/symbols__document__tests__theorem_amsthm.snap index 9d897532b1..9d897532b1 100644 --- a/support/texlab/crates/symbols/src/document/snapshots/symbols__document__tests__theorem.snap +++ b/support/texlab/crates/symbols/src/document/snapshots/symbols__document__tests__theorem_amsthm.snap diff --git a/support/texlab/crates/symbols/src/document/snapshots/symbols__document__tests__theorem_thmtools.snap b/support/texlab/crates/symbols/src/document/snapshots/symbols__document__tests__theorem_thmtools.snap new file mode 100644 index 0000000000..cb5d344965 --- /dev/null +++ b/support/texlab/crates/symbols/src/document/snapshots/symbols__document__tests__theorem_thmtools.snap @@ -0,0 +1,53 @@ +--- +source: crates/symbols/src/document/tests.rs +expression: "document_symbols(&fixture.workspace, document)" +--- +[ + Symbol { + name: "Lemma 1 (Foo)", + kind: Theorem, + label: Some( + Span( + "thm:foo", + 147..162, + ), + ), + full_range: 129..182, + selection_range: 147..162, + children: [], + }, + Symbol { + name: "Lemma 2", + kind: Theorem, + label: Some( + Span( + "thm:bar", + 197..212, + ), + ), + full_range: 184..232, + selection_range: 197..212, + children: [], + }, + Symbol { + name: "Lemma", + kind: Theorem, + label: Some( + Span( + "thm:baz", + 247..262, + ), + ), + full_range: 234..282, + selection_range: 247..262, + children: [], + }, + Symbol { + name: "Lemma (Qux)", + kind: Theorem, + label: None, + full_range: 284..322, + selection_range: 284..322, + children: [], + }, +] diff --git a/support/texlab/crates/symbols/src/document/tests.rs b/support/texlab/crates/symbols/src/document/tests.rs index dcb3c17a7c..355a8a5719 100644 --- a/support/texlab/crates/symbols/src/document/tests.rs +++ b/support/texlab/crates/symbols/src/document/tests.rs @@ -138,7 +138,7 @@ fn test_section() { } #[test] -fn test_theorem() { +fn test_theorem_amsthm() { let fixture = Fixture::parse( r#" %! main.tex @@ -178,6 +178,46 @@ fn test_theorem() { } #[test] +fn test_theorem_thmtools() { + let fixture = Fixture::parse( + r#" +%! main.tex +\documentclass{article} +\declaretheoremstyle{lemmastyle} +\declaretheorem[style=lemmastyle, name=Lemma]{lemma} + +\begin{document} + +\begin{lemma}[Foo]\label{thm:foo} + Foo +\end{lemma} + +\begin{lemma}\label{thm:bar} + Bar +\end{lemma} + +\begin{lemma}\label{thm:baz} + Baz +\end{lemma} + +\begin{lemma}[Qux] + Qux +\end{lemma} + +\end{document} +| + +%! main.aux +\relax +\newlabel{thm:foo}{{1}{1}} +\newlabel{thm:bar}{{2}{1}}"#, + ); + + let document = fixture.workspace.lookup(&fixture.documents[0].uri).unwrap(); + assert_debug_snapshot!(document_symbols(&fixture.workspace, document)); +} + +#[test] fn test_allowed_patterns() { let mut fixture = Fixture::parse( r#" diff --git a/support/texlab/crates/symbols/src/types.rs b/support/texlab/crates/symbols/src/types.rs index d78f9af200..5d31c98143 100644 --- a/support/texlab/crates/symbols/src/types.rs +++ b/support/texlab/crates/symbols/src/types.rs @@ -54,7 +54,7 @@ impl Symbol { } } - pub fn keywords<'a>(&'a self) -> Vec<&'a str> { + pub fn keywords(&self) -> Vec<&str> { match self.kind { SymbolKind::Section => vec![&self.name, "latex", "section"], SymbolKind::Figure => vec![&self.name, "latex", "float", "figure"], diff --git a/support/texlab/crates/syntax/src/latex/cst.rs b/support/texlab/crates/syntax/src/latex/cst.rs index be64557886..a2945c3e7a 100644 --- a/support/texlab/crates/syntax/src/latex/cst.rs +++ b/support/texlab/crates/syntax/src/latex/cst.rs @@ -265,6 +265,15 @@ impl ToString for Key { cst_node!(Value, VALUE); +impl Value { + pub fn text(&self) -> Option<String> { + match CurlyGroup::cast(self.syntax().clone()) { + Some(group) => group.content_text(), + None => Some(self.syntax().text().to_string()), + } + } +} + cst_node!(KeyValuePair, KEY_VALUE_PAIR); impl KeyValuePair { @@ -528,7 +537,11 @@ impl LabelNumber { } } -cst_node!(TheoremDefinition, THEOREM_DEFINITION); +cst_node!( + TheoremDefinition, + THEOREM_DEFINITION_AMSTHM, + THEOREM_DEFINITION_THMTOOLS +); impl TheoremDefinition { pub fn command(&self) -> Option<SyntaxToken> { @@ -539,8 +552,25 @@ impl TheoremDefinition { self.syntax().children().find_map(CurlyGroupWord::cast) } - pub fn heading(&self) -> Option<CurlyGroup> { - self.syntax().children().find_map(CurlyGroup::cast) + pub fn heading(&self) -> Option<String> { + if self.0.kind() == THEOREM_DEFINITION_THMTOOLS { + let options = self + .syntax() + .children() + .find_map(BrackGroupKeyValue::cast) + .and_then(|group| group.body())?; + + options + .pairs() + .find(|pair| pair.key().map_or(false, |key| key.to_string() == "name")) + .and_then(|pair| pair.value()) + .and_then(|name| name.text()) + } else { + self.syntax() + .children() + .find_map(CurlyGroup::cast) + .and_then(|group| group.content_text()) + } } } diff --git a/support/texlab/crates/syntax/src/latex/kind.rs b/support/texlab/crates/syntax/src/latex/kind.rs index 3eadc90b48..39e2837932 100644 --- a/support/texlab/crates/syntax/src/latex/kind.rs +++ b/support/texlab/crates/syntax/src/latex/kind.rs @@ -73,7 +73,8 @@ pub enum SyntaxKind { ACRONYM_DEFINITION, ACRONYM_DECLARATION, ACRONYM_REFERENCE, - THEOREM_DEFINITION, + THEOREM_DEFINITION_AMSTHM, + THEOREM_DEFINITION_THMTOOLS, COLOR_REFERENCE, COLOR_DEFINITION, COLOR_SET_DEFINITION, diff --git a/support/texlab/crates/texlab/Cargo.toml b/support/texlab/crates/texlab/Cargo.toml index 821ecb9813..1f9ca98abe 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.6.0" +version = "5.7.0" license.workspace = true readme = "README.md" authors.workspace = true @@ -31,31 +31,31 @@ test = false doctest = false [dependencies] -anyhow = "1.0.70" +anyhow = "1.0.71" base-db = { path = "../base-db" } citeproc = { path = "../citeproc" } -clap = { version = "4.2.2", features = ["derive"] } +clap = { version = "4.3.0", features = ["derive"] } commands = { path = "../commands" } crossbeam-channel = "0.5.8" -dirs = "5.0.0" +dirs = "5.0.1" distro = { path = "../distro" } encoding_rs = "0.8.32" encoding_rs_io = "0.1.7" fern = "0.6.2" -flate2 = "1.0.25" +flate2 = "1.0.26" fuzzy-matcher = { version = "0.3.7", features = ["compact"] } itertools = "0.10.5" log = "0.4.17" lsp-server = "0.7.0" lsp-types = "0.94.0" -notify = "5.1.0" +notify = "6.0.0" once_cell = "1.17.1" parking_lot = "0.12.1" parser = { path = "../parser" } -regex = "1.7.3" +regex = "1.8.1" rowan = "0.15.11" rustc-hash = "1.1.0" -serde = "1.0.160" +serde = "1.0.163" serde_json = "1.0.96" serde_regex = "1.1.0" serde_repr = "0.1.12" @@ -68,8 +68,8 @@ symbols = { path = "../symbols" } [dev-dependencies] assert_unordered = "0.3.5" -criterion = { version = "0.4.0" } -insta = { version = "1.28.0", features = ["glob", "redactions", "json"] } +criterion = { version = "0.5.1" } +insta = { version = "1.29.0", features = ["glob", "redactions", "json"] } [[bench]] name = "bench_main" diff --git a/support/texlab/crates/texlab/src/features/completion/builder.rs b/support/texlab/crates/texlab/src/features/completion/builder.rs index b325cd183b..bae7ebbfb7 100644 --- a/support/texlab/crates/texlab/src/features/completion/builder.rs +++ b/support/texlab/crates/texlab/src/features/completion/builder.rs @@ -51,7 +51,7 @@ impl<'a> CompletionBuilder<'a> { ) -> Self { let items = Vec::new(); let matcher: Box<dyn Matcher> = match context.workspace.config().completion.matcher { - MatchingAlgo::Skim => Box::new(SkimMatcherV2::default()), + MatchingAlgo::Skim => Box::<SkimMatcherV2>::default(), MatchingAlgo::SkimIgnoreCase => Box::new(SkimMatcherV2::default().ignore_case()), MatchingAlgo::Prefix => Box::new(matcher::Prefix), MatchingAlgo::PrefixIgnoreCase => Box::new(matcher::PrefixIgnoreCase), @@ -290,7 +290,7 @@ impl<'a> CompletionBuilder<'a> { ) -> Option<()> { let score = self .matcher - .score(&entry_type.name, &self.text_pattern[1..])?; + .score(entry_type.name, &self.text_pattern[1..])?; self.items.push(Item { range, @@ -303,7 +303,7 @@ impl<'a> CompletionBuilder<'a> { } pub fn field(&mut self, range: TextRange, field: &'a BibtexFieldType<'a>) -> Option<()> { - let score = self.matcher.score(&field.name, &self.text_pattern)?; + let score = self.matcher.score(field.name, &self.text_pattern)?; self.items.push(Item { range, data: Data::Field { field }, @@ -750,8 +750,8 @@ enum Data<'a> { impl<'db> Data<'db> { pub fn label<'this: 'db>(&'this self) -> &'db str { match self { - Self::EntryType { entry_type } => &entry_type.name, - Self::Field { field } => &field.name, + Self::EntryType { entry_type } => entry_type.name, + Self::Field { field } => field.name, Self::Argument { name, .. } => name, Self::BeginSnippet => "begin", Self::Citation { key, .. } => key, diff --git a/support/texlab/crates/texlab/src/features/completion/label.rs b/support/texlab/crates/texlab/src/features/completion/label.rs index 800c7b7581..be6e1b9ab7 100644 --- a/support/texlab/crates/texlab/src/features/completion/label.rs +++ b/support/texlab/crates/texlab/src/features/completion/label.rs @@ -40,7 +40,7 @@ pub fn complete<'db>( let header = rendered_label.detail(); let footer = match &rendered_label.object { - RenderedObject::Float { caption, .. } => Some(caption.clone()), + RenderedObject::Float { caption, .. } => Some(*caption), _ => None, }; diff --git a/support/texlab/crates/texlab/src/features/completion/matcher.rs b/support/texlab/crates/texlab/src/features/completion/matcher.rs index a2b1a45e6a..5d5c93b2b9 100644 --- a/support/texlab/crates/texlab/src/features/completion/matcher.rs +++ b/support/texlab/crates/texlab/src/features/completion/matcher.rs @@ -37,6 +37,6 @@ impl Matcher for PrefixIgnoreCase { } } - return Some(-(choice.len() as i32)); + Some(-(choice.len() as i32)) } } diff --git a/support/texlab/crates/texlab/src/features/formatting/latexindent.rs b/support/texlab/crates/texlab/src/features/formatting/latexindent.rs index c269550b74..bf5385401b 100644 --- a/support/texlab/crates/texlab/src/features/formatting/latexindent.rs +++ b/support/texlab/crates/texlab/src/features/formatting/latexindent.rs @@ -5,8 +5,8 @@ use std::{ use base_db::{Document, LatexIndentConfig, Workspace}; use distro::Language; -use lsp_types::TextEdit; -use rowan::{TextLen, TextRange}; +use lsp_types::{Position, TextEdit}; +use rowan::TextLen; use tempfile::tempdir; use crate::util::line_index_ext::LineIndexExt; @@ -51,8 +51,10 @@ pub fn format_with_latexindent( None } else { let line_index = &document.line_index; + let start = Position::new(0, 0); + let end = line_index.line_col_lsp(old_text.text_len()); Some(vec![TextEdit { - range: line_index.line_col_lsp_range(TextRange::new(0.into(), old_text.text_len())), + range: lsp_types::Range::new(start, end), new_text, }]) } diff --git a/support/texlab/crates/texlab/src/features/inlay_hint.rs b/support/texlab/crates/texlab/src/features/inlay_hint.rs index 40e2984ab8..14a53ae21d 100644 --- a/support/texlab/crates/texlab/src/features/inlay_hint.rs +++ b/support/texlab/crates/texlab/src/features/inlay_hint.rs @@ -36,7 +36,7 @@ impl<'db> InlayHintBuilder<'db> { let position = self.document.line_index.line_col_lsp(offset); self.hints.push(InlayHint { position, - label: InlayHintLabel::String(text), + label: InlayHintLabel::String(format!(" {text} ")), kind: None, text_edits: None, tooltip: None, diff --git a/support/texlab/crates/texlab/src/features/inlay_hint/label.rs b/support/texlab/crates/texlab/src/features/inlay_hint/label.rs index dd33990f45..f73d3fd9ae 100644 --- a/support/texlab/crates/texlab/src/features/inlay_hint/label.rs +++ b/support/texlab/crates/texlab/src/features/inlay_hint/label.rs @@ -34,7 +34,7 @@ pub(super) fn find_hints(builder: &mut InlayHintBuilder) -> Option<()> { RenderedObject::EnumItem => format!("Item {}", number), }; - builder.push(label.name.range.end(), text); + builder.push(label.full_range.end(), text); } Some(()) diff --git a/support/texlab/crates/texlab/src/server.rs b/support/texlab/crates/texlab/src/server.rs index 0370f00192..2a62abe96d 100644 --- a/support/texlab/crates/texlab/src/server.rs +++ b/support/texlab/crates/texlab/src/server.rs @@ -38,8 +38,8 @@ use crate::{ use self::{ extensions::{ - BuildParams, BuildRequest, BuildResult, BuildStatus, ForwardSearchRequest, - ForwardSearchResult, ForwardSearchStatus, + BuildParams, BuildRequest, BuildResult, BuildStatus, EnvironmentLocation, + ForwardSearchRequest, ForwardSearchResult, ForwardSearchStatus, TextWithRange, }, options::{Options, StartupOptions}, progress::ProgressReporter, @@ -168,6 +168,9 @@ impl Server { "texlab.cleanAuxiliary".into(), "texlab.cleanArtifacts".into(), "texlab.changeEnvironment".into(), + "texlab.findEnvironments".into(), + "texlab.showDependencyGraph".into(), + "texlab.cancelBuild".into(), ], ..Default::default() }), @@ -384,20 +387,18 @@ impl Server { match change.range { Some(range) => { let range = document.line_index.offset_lsp_range(range); - drop(document); workspace.edit(&uri, range, &change.text); } None => { let new_line = document.cursor.line.min(change.text.lines().count() as u32); let language = document.language; - drop(document); workspace.open( uri.clone(), change.text, language, Owner::Client, LineCol { - line: new_line as u32, + line: new_line, col: 0, }, ); @@ -662,6 +663,10 @@ impl Server { client.send_request::<ApplyWorkspaceEdit>(params?) }); } + "texlab.findEnvironments" => { + let result = self.find_environments(params); + self.run_fallible(id, move || result); + } "texlab.showDependencyGraph" => { let workspace = self.workspace.read(); let dot = commands::show_dependency_graph(&workspace).unwrap(); @@ -867,7 +872,6 @@ impl Server { if let Some(document) = workspace.lookup_path(&path) { if document.owner == Owner::Server { let uri = document.uri.clone(); - drop(document); workspace.remove(&uri); changed = true; } @@ -941,6 +945,32 @@ impl Server { Ok(ApplyWorkspaceEditParams { label, edit }) } + fn find_environments(&self, params: ExecuteCommandParams) -> Result<Vec<EnvironmentLocation>> { + let workspace = self.workspace.read(); + let params = self.parse_command_params::<TextDocumentPositionParams>(params.arguments)?; + let mut uri = params.text_document.uri; + normalize_uri(&mut uri); + + let Some(document) = workspace.lookup(&uri) else { + anyhow::bail!("Document {} is not opened!", uri) + }; + + let line_index = &document.line_index; + let offset = line_index.offset_lsp(params.position); + let results = commands::find_environments(document, offset) + .into_iter() + .map(|result| EnvironmentLocation { + name: TextWithRange { + range: line_index.line_col_lsp_range(result.name.range), + text: result.name.text, + }, + full_range: line_index.line_col_lsp_range(result.full_range), + }) + .collect(); + + Ok(results) + } + fn parse_command_params<T: DeserializeOwned>( &self, params: Vec<serde_json::Value>, diff --git a/support/texlab/crates/texlab/src/server/extensions.rs b/support/texlab/crates/texlab/src/server/extensions.rs index e8a2050cff..2d9d17a5b3 100644 --- a/support/texlab/crates/texlab/src/server/extensions.rs +++ b/support/texlab/crates/texlab/src/server/extensions.rs @@ -1,5 +1,5 @@ use commands::ForwardSearchError; -use lsp_types::{Position, TextDocumentIdentifier, TextDocumentPositionParams}; +use lsp_types::{Position, Range, TextDocumentIdentifier, TextDocumentPositionParams}; use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; @@ -70,6 +70,21 @@ impl From<ForwardSearchError> for ForwardSearchStatus { } #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] pub struct ForwardSearchResult { pub status: ForwardSearchStatus, } + +#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct EnvironmentLocation { + pub name: TextWithRange, + pub full_range: Range, +} + +#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct TextWithRange { + pub text: String, + pub range: Range, +} diff --git a/support/texlab/crates/texlab/src/util/cursor.rs b/support/texlab/crates/texlab/src/util/cursor.rs index b03036386c..a39d0e7bf7 100644 --- a/support/texlab/crates/texlab/src/util/cursor.rs +++ b/support/texlab/crates/texlab/src/util/cursor.rs @@ -241,18 +241,13 @@ impl<'a, T> CursorContext<'a, T> { pub fn find_environment(&self) -> Option<(latex::Key, latex::Key)> { let token = self.cursor.as_tex()?; - - for env in token + let env = token .parent_ancestors() - .filter_map(latex::Environment::cast) - { - let beg = env.begin()?.name()?.key()?; - let end = env.end()?.name()?.key()?; - - return Some((beg, end)); - } + .find_map(latex::Environment::cast)?; - None + let beg = env.begin()?.name()?.key()?; + let end = env.end()?.name()?.key()?; + Some((beg, end)) } pub fn find_curly_group_word(&self) -> Option<(String, TextRange, latex::CurlyGroupWord)> { diff --git a/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__inlay_hint__label_definition.snap b/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__inlay_hint__label_definition.snap index b8568fd2fd..050ae5afd3 100644 --- a/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__inlay_hint__label_definition.snap +++ b/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__inlay_hint__label_definition.snap @@ -1,38 +1,38 @@ --- -source: tests/lsp/text_document/inlay_hint.rs +source: crates/texlab/tests/lsp/text_document/inlay_hint.rs expression: "find_hints(r#\"\n%! main.tex\n\\documentclass{article}\n\\usepackage{caption}\n\\begin{document}\n\\section{Foo}\\label{sec:foo}\n\\section{Bar}\\label{sec:bar}\n\\subsection{Baz}\\label{sec:baz}\n\\begin{figure}\n Test\n \\label{fig:qux}\n \\caption{Qux}\n\\end{figure}\n\\end{document}\n |\n\n%! main.aux\n\\relax \n\\providecommand*\\caption@xref[2]{\\@setref\\relax\\@undefined{#1}}\n\\newlabel{fig:qux}{{\\caption@xref {fig:qux}{ on input line 15}}{1}}\n\\@writefile{lof}{\\contentsline {figure}{\\numberline {1}{\\ignorespaces Qux\\relax }}{1}{}\\protected@file@percent }\n\\@writefile{toc}{\\contentsline {section}{\\numberline {1}Foo}{1}{}\\protected@file@percent }\n\\newlabel{sec:foo}{{1}{1}}\n\\@writefile{toc}{\\contentsline {section}{\\numberline {2}Bar}{1}{}\\protected@file@percent }\n\\newlabel{sec:bar}{{2}{1}}\n\\@writefile{toc}{\\contentsline {subsection}{\\numberline {2.1}Baz}{1}{}\\protected@file@percent }\n\\newlabel{sec:baz}{{2.1}{1}}\n\\gdef \\@abspage@last{1}\"#)" --- [ { "position": { "line": 3, - "character": 27 + "character": 28 }, - "label": "Section 1", + "label": " Section 1 ", "paddingLeft": true }, { "position": { "line": 4, - "character": 27 + "character": 28 }, - "label": "Section 2", + "label": " Section 2 ", "paddingLeft": true }, { "position": { "line": 5, - "character": 30 + "character": 31 }, - "label": "Subsection 2.1", + "label": " Subsection 2.1 ", "paddingLeft": true }, { "position": { "line": 8, - "character": 18 + "character": 19 }, - "label": "Figure fig:qux", + "label": " Figure fig:qux ", "paddingLeft": true } ] diff --git a/support/texlab/texlab.1 b/support/texlab/texlab.1 index 8d0ecbeb45..4042ae0f1e 100644 --- a/support/texlab/texlab.1 +++ b/support/texlab/texlab.1 @@ -1,7 +1,7 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.13. -.TH TEXLAB "1" "May 2023" "texlab 5.6.0" "User Commands" +.TH TEXLAB "1" "June 2023" "texlab 5.7.0" "User Commands" .SH NAME -texlab \- manual page for texlab 5.6.0 +texlab \- manual page for texlab 5.7.0 .SH SYNOPSIS .B texlab [\fI\,OPTIONS\/\fR] diff --git a/support/texlab/texlab.pdf b/support/texlab/texlab.pdf Binary files differindex a7ed8d359f..ed15c250f5 100644 --- a/support/texlab/texlab.pdf +++ b/support/texlab/texlab.pdf |