diff options
Diffstat (limited to 'support/texlab/crates')
30 files changed, 347 insertions, 87 deletions
diff --git a/support/texlab/crates/base-db/src/config.rs b/support/texlab/crates/base-db/src/config.rs index 455fdc2a6c..5774f2a0ec 100644 --- a/support/texlab/crates/base-db/src/config.rs +++ b/support/texlab/crates/base-db/src/config.rs @@ -68,6 +68,7 @@ pub enum Formatter { pub struct LatexIndentConfig { pub local: Option<String>, pub modify_line_breaks: bool, + pub replacement: Option<String>, } #[derive(Debug, Default)] diff --git a/support/texlab/crates/base-db/src/deps/discover.rs b/support/texlab/crates/base-db/src/deps/discover.rs index cbcab4d8fb..3039d7b0f4 100644 --- a/support/texlab/crates/base-db/src/deps/discover.rs +++ b/support/texlab/crates/base-db/src/deps/discover.rs @@ -15,7 +15,7 @@ pub fn watch( ) { let roots = workspace .iter() - .map(|document| &document.dir) + .filter_map(|document| document.dir.as_ref()) .filter(|dir| dir.scheme() == "file") .unique() .map(|dir| ProjectRoot::walk_and_find(workspace, dir)); diff --git a/support/texlab/crates/base-db/src/deps/graph.rs b/support/texlab/crates/base-db/src/deps/graph.rs index 0d8252688d..aec5cea92b 100644 --- a/support/texlab/crates/base-db/src/deps/graph.rs +++ b/support/texlab/crates/base-db/src/deps/graph.rs @@ -55,7 +55,11 @@ impl Graph { start: start.uri.clone(), }; - let root = ProjectRoot::walk_and_find(workspace, &start.dir); + let Some(start_dir) = &start.dir else { + return graph; + }; + + let root = ProjectRoot::walk_and_find(workspace, start_dir); let mut stack = vec![(start, Rc::new(root))]; let mut visited = FxHashSet::default(); @@ -135,7 +139,7 @@ impl Graph { .as_deref() .and_then(|dir| Url::from_directory_path(dir).ok()); - let working_dir = working_dir.as_ref().unwrap_or(&start.source.dir); + let working_dir = working_dir.as_ref().or(start.source.dir.as_ref())?; let new_root = Arc::new(ProjectRoot::from_config(workspace, working_dir)); for target_uri in file_list diff --git a/support/texlab/crates/base-db/src/deps/root.rs b/support/texlab/crates/base-db/src/deps/root.rs index 03fd41a9a0..aa3969353d 100644 --- a/support/texlab/crates/base-db/src/deps/root.rs +++ b/support/texlab/crates/base-db/src/deps/root.rs @@ -45,7 +45,7 @@ impl ProjectRoot { pub fn from_tectonic(workspace: &Workspace, dir: &Url) -> Option<Self> { let exists = workspace .iter() - .filter(|document| document.dir == *dir) + .filter(|document| document.dir.as_ref() == Some(dir)) .any(|document| matches!(document.data, DocumentData::Tectonic)); if !exists { @@ -77,7 +77,7 @@ impl ProjectRoot { let config = workspace.config(); let rcfile = workspace .iter() - .filter(|document| document.dir == *dir) + .filter(|document| document.dir.as_ref() == Some(dir)) .find_map(|document| document.data.as_latexmkrc())?; let compile_dir = dir.clone(); @@ -121,7 +121,7 @@ impl ProjectRoot { pub fn from_rootfile(workspace: &Workspace, dir: &Url) -> Option<Self> { let exists = workspace .iter() - .filter(|document| document.dir == *dir) + .filter(|document| document.dir.as_ref() == Some(dir)) .any(|document| matches!(document.data, DocumentData::Root)); if !exists { diff --git a/support/texlab/crates/base-db/src/document.rs b/support/texlab/crates/base-db/src/document.rs index 6fdcf30c16..0b81fa2871 100644 --- a/support/texlab/crates/base-db/src/document.rs +++ b/support/texlab/crates/base-db/src/document.rs @@ -28,7 +28,7 @@ pub struct DocumentParams<'a> { #[derive(Clone)] pub struct Document { pub uri: Url, - pub dir: Url, + pub dir: Option<Url>, pub path: Option<PathBuf>, pub text: String, pub line_index: LineIndex, @@ -42,7 +42,7 @@ impl Document { pub fn parse(params: DocumentParams) -> Self { let DocumentParams { uri, text, .. } = params; - let dir = uri.join(".").unwrap(); + let dir = uri.join(".").ok(); let path = if uri.scheme() == "file" { uri.to_file_path().ok() diff --git a/support/texlab/crates/base-db/src/semantics/auxiliary.rs b/support/texlab/crates/base-db/src/semantics/auxiliary.rs index 8c9fe012e6..bb9a2c065c 100644 --- a/support/texlab/crates/base-db/src/semantics/auxiliary.rs +++ b/support/texlab/crates/base-db/src/semantics/auxiliary.rs @@ -5,6 +5,7 @@ use syntax::latex::{self, HasCurly}; #[derive(Debug, Clone, Default)] pub struct Semantics { pub label_numbers: FxHashMap<String, String>, + pub section_numbers: FxHashMap<String, String>, } impl Semantics { @@ -18,6 +19,9 @@ impl Semantics { if let Some(label_number) = latex::LabelNumber::cast(node.clone()) { self.process_label_number(&label_number); } + if let Some(toc_line) = latex::TocContentsLine::cast(node.clone()) { + self.process_toc_line(&toc_line); + } } fn process_label_number(&mut self, label_number: &latex::LabelNumber) -> Option<()> { @@ -40,4 +44,36 @@ impl Semantics { self.label_numbers.insert(name, text); Some(()) } + + fn process_toc_line(&mut self, toc_line: &latex::TocContentsLine) -> Option<()> { + let unit = toc_line.unit().and_then(|u| u.content_text())?.to_string(); + + if [ + "part", + "chapter", + "section", + "subsection", + "subsubsection", + "paragraph", + "subparagraph", + ] + .contains(&unit.as_str()) + { + let line = toc_line.line()?; + let name = line.syntax().children().find_map(|child| { + latex::Text::cast(child.clone())?; + Some(child) + })?; + let name = name.to_string(); + + let num_line = line + .syntax() + .children() + .find_map(|child| latex::TocNumberLine::cast(child.clone()))?; + let number = num_line.number()?; + let number = number.content_text()?.replace(['{', '}'], ""); + self.section_numbers.insert(name, number); + } + Some(()) + } } diff --git a/support/texlab/crates/base-db/src/semantics/tex.rs b/support/texlab/crates/base-db/src/semantics/tex.rs index acd94b6056..7d150fc4b3 100644 --- a/support/texlab/crates/base-db/src/semantics/tex.rs +++ b/support/texlab/crates/base-db/src/semantics/tex.rs @@ -38,6 +38,7 @@ pub struct Semantics { pub can_be_root: bool, pub can_be_compiled: bool, pub diagnostic_suppressions: Vec<TextRange>, + pub bibitems: FxHashSet<Span>, } impl Semantics { @@ -49,7 +50,7 @@ impl Semantics { } latex::SyntaxElement::Token(token) => match token.kind() { latex::COMMAND_NAME => { - self.commands.push(Span::command(&token)); + self.commands.push(Span::command(&token)); } latex::COMMENT if token.text().contains("texlab: ignore") => { self.diagnostic_suppressions.push(token.text_range()); @@ -85,6 +86,8 @@ impl Semantics { self.process_theorem_definition(theorem_def); } else if let Some(graphics_path) = latex::GraphicsPath::cast(node.clone()) { self.process_graphics_path(graphics_path); + } else if let Some(bibitem) = latex::BibItem::cast(node.clone()) { + self.process_bibitem(bibitem); } } @@ -334,6 +337,16 @@ impl Semantics { self.graphics_paths.insert(path.to_string()); } } + + fn process_bibitem(&mut self, bibitem: latex::BibItem) { + if let Some(name) = bibitem.name() { + if let Some(key) = name.key() { + self.bibitems.insert( + Span::from(&key) + ); + } + } + } } #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)] diff --git a/support/texlab/crates/bibtex-utils/Cargo.toml b/support/texlab/crates/bibtex-utils/Cargo.toml index 8ab72e39d8..1271823eac 100644 --- a/support/texlab/crates/bibtex-utils/Cargo.toml +++ b/support/texlab/crates/bibtex-utils/Cargo.toml @@ -8,7 +8,7 @@ rust-version.workspace = true [dependencies] chrono = { version = "0.4.38", default-features = false, features = ["std"] } -human_name = "2.0.3" +human_name = "2.0.4" itertools.workspace = true rowan.workspace = true rustc-hash.workspace = true diff --git a/support/texlab/crates/commands/Cargo.toml b/support/texlab/crates/commands/Cargo.toml index ddd7db2991..b348ad2b87 100644 --- a/support/texlab/crates/commands/Cargo.toml +++ b/support/texlab/crates/commands/Cargo.toml @@ -12,7 +12,7 @@ base-db = { path = "../base-db" } bstr = "1.10.0" crossbeam-channel.workspace = true itertools.workspace = true -libc = "0.2.159" +libc = "0.2.161" log.workspace = true rowan.workspace = true rustc-hash.workspace = true diff --git a/support/texlab/crates/commands/src/build.rs b/support/texlab/crates/commands/src/build.rs index 34d39f26e4..23a6e16b7b 100644 --- a/support/texlab/crates/commands/src/build.rs +++ b/support/texlab/crates/commands/src/build.rs @@ -47,6 +47,10 @@ impl BuildCommand { .next() .unwrap_or(document); + let Some(document_dir) = &document.dir else { + return Err(BuildError::NotLocal(document.uri.clone())); + }; + let Some(path) = document.path.as_deref().and_then(Path::to_str) else { return Err(BuildError::NotLocal(document.uri.clone())); }; @@ -55,7 +59,7 @@ impl BuildCommand { let program = config.program.clone(); let args = replace_placeholders(&config.args, &[('f', path)]); - let root = ProjectRoot::walk_and_find(workspace, &document.dir); + let root = ProjectRoot::walk_and_find(workspace, document_dir); let Ok(working_dir) = root.compile_dir.to_file_path() else { return Err(BuildError::NotLocal(document.uri.clone())); diff --git a/support/texlab/crates/commands/src/clean.rs b/support/texlab/crates/commands/src/clean.rs index d4ec6b24f4..e429d1afa2 100644 --- a/support/texlab/crates/commands/src/clean.rs +++ b/support/texlab/crates/commands/src/clean.rs @@ -21,7 +21,11 @@ impl CleanCommand { anyhow::bail!("document '{}' is not a local file", document.uri) }; - let root = ProjectRoot::walk_and_find(workspace, &document.dir); + let Some(document_dir) = &document.dir else { + anyhow::bail!("document '{}' is not a local file", document.uri) + }; + + let root = ProjectRoot::walk_and_find(workspace, document_dir); let flag = match target { CleanTarget::Auxiliary => "-c", diff --git a/support/texlab/crates/commands/src/fwd_search.rs b/support/texlab/crates/commands/src/fwd_search.rs index f3480ef3e2..8b6227d8c2 100644 --- a/support/texlab/crates/commands/src/fwd_search.rs +++ b/support/texlab/crates/commands/src/fwd_search.rs @@ -84,7 +84,11 @@ impl ForwardSearch { } fn find_pdf(workspace: &Workspace, document: &Document) -> Result<PathBuf, ForwardSearchError> { - let root = ProjectRoot::walk_and_find(workspace, &document.dir); + let Some(document_dir) = &document.dir else { + return Err(ForwardSearchError::NotLocal(document.uri.clone())); + }; + + let root = ProjectRoot::walk_and_find(workspace, document_dir); log::debug!("[FwdSearch] root={root:#?}"); diff --git a/support/texlab/crates/completion/src/providers/include.rs b/support/texlab/crates/completion/src/providers/include.rs index d0a042252f..f3deb3a108 100644 --- a/support/texlab/crates/completion/src/providers/include.rs +++ b/support/texlab/crates/completion/src/providers/include.rs @@ -118,7 +118,7 @@ fn current_dir( .next() .map_or(params.document, Clone::clone); - let root = ProjectRoot::walk_and_find(workspace, &parent.dir); + let root = ProjectRoot::walk_and_find(workspace, parent.dir.as_ref()?); let mut path = PathBuf::new(); if let Some(graphics_path) = graphics_path { diff --git a/support/texlab/crates/diagnostics/src/chktex.rs b/support/texlab/crates/diagnostics/src/chktex.rs index a3f539440d..b7cd80d67b 100644 --- a/support/texlab/crates/diagnostics/src/chktex.rs +++ b/support/texlab/crates/diagnostics/src/chktex.rs @@ -36,7 +36,7 @@ impl Command { return None; } - let root = ProjectRoot::walk_and_find(workspace, &parent.dir); + let root = ProjectRoot::walk_and_find(workspace, parent.dir.as_ref()?); let working_dir = root.src_dir.to_file_path().ok()?; log::debug!("Calling ChkTeX from directory: {}", working_dir.display()); diff --git a/support/texlab/crates/diagnostics/src/citations.rs b/support/texlab/crates/diagnostics/src/citations.rs index 43d5f495d2..2678d7e456 100644 --- a/support/texlab/crates/diagnostics/src/citations.rs +++ b/support/texlab/crates/diagnostics/src/citations.rs @@ -18,13 +18,17 @@ pub fn detect_undefined_citations<'a>( ) -> Option<()> { let data = document.data.as_tex()?; + let bibitems: FxHashSet<&str> = data.semantics.bibitems.iter() + .map(|bib| bib.text.as_str()) + .collect(); + let entries: FxHashSet<&str> = Entry::find_all(project) .map(|(_, entry)| entry.name_text()) .collect(); for citation in &data.semantics.citations { let name = citation.name_text(); - if name != "*" && !entries.contains(name) { + if name != "*" && !entries.contains(name) && !bibitems.contains(name) { let diagnostic = Diagnostic::Tex(citation.name.range, TexError::UndefinedCitation); results .entry(document.uri.clone()) @@ -41,24 +45,38 @@ pub fn detect_unused_entries<'a>( document: &'a Document, results: &mut FxHashMap<Url, Vec<Diagnostic>>, ) -> Option<()> { - let data = document.data.as_bib()?; - - // If this is a huge bibliography, then don't bother checking for unused entries. - if data.semantics.entries.len() > MAX_UNUSED_ENTRIES { - return None; - } let citations: FxHashSet<&str> = Citation::find_all(project) .map(|(_, citation)| citation.name_text()) .collect(); - for entry in &data.semantics.entries { - if !citations.contains(entry.name.text.as_str()) { - let diagnostic = Diagnostic::Bib(entry.name.range, BibError::UnusedEntry); - results - .entry(document.uri.clone()) - .or_default() - .push(diagnostic); + if let Some(data) = document.data.as_bib() + { + // If this is a huge bibliography, then don't bother checking for unused entries. + if data.semantics.entries.len() > MAX_UNUSED_ENTRIES { + return None; + } + + for entry in &data.semantics.entries { + if !citations.contains(entry.name.text.as_str()) { + let diagnostic = Diagnostic::Bib(entry.name.range, BibError::UnusedEntry); + results + .entry(document.uri.clone()) + .or_default() + .push(diagnostic); + } + } + }; + + if let Some(tex_data) = document.data.as_tex(){ + for bibitem in &tex_data.semantics.bibitems { + if !citations.contains(bibitem.text.as_str()) { + let diagnostic = Diagnostic::Bib(bibitem.range, BibError::UnusedEntry); + results + .entry(document.uri.clone()) + .or_default() + .push(diagnostic); + } } } diff --git a/support/texlab/crates/distro/src/lib.rs b/support/texlab/crates/distro/src/lib.rs index 5c0dbe51fb..cf1420baa9 100644 --- a/support/texlab/crates/distro/src/lib.rs +++ b/support/texlab/crates/distro/src/lib.rs @@ -4,7 +4,10 @@ mod language; mod miktex; mod texlive; -use std::process::{Command, Stdio}; +use std::{ + env, + process::{Command, Stdio}, +}; use anyhow::Result; @@ -70,8 +73,14 @@ impl Distro { DistroKind::Tectonic | DistroKind::Unknown => FileNameDB::default(), }; - if let Some(bibinputs) = std::env::var_os("BIBINPUTS") { - for dir in std::env::split_paths(&bibinputs) { + Self::read_env_dir(&mut file_name_db, "TEXINPUTS"); + Self::read_env_dir(&mut file_name_db, "BIBINPUTS"); + Ok(Self { kind, file_name_db }) + } + + fn read_env_dir(file_name_db: &mut FileNameDB, env_var: &str) { + if let Some(paths) = env::var_os(env_var) { + for dir in env::split_paths(&paths) { if let Ok(entries) = std::fs::read_dir(dir) { for file in entries .flatten() @@ -83,7 +92,5 @@ impl Distro { } } } - - Ok(Self { kind, file_name_db }) } } diff --git a/support/texlab/crates/parser/Cargo.toml b/support/texlab/crates/parser/Cargo.toml index 8dd3a771f8..e1edb782c5 100644 --- a/support/texlab/crates/parser/Cargo.toml +++ b/support/texlab/crates/parser/Cargo.toml @@ -10,7 +10,7 @@ rust-version.workspace = true log.workspace = true logos = "0.14.2" once_cell.workspace = true -pathdiff = "0.2.1" +pathdiff = "0.2.2" regex.workspace = true rowan.workspace = true rustc-hash.workspace = true diff --git a/support/texlab/crates/parser/src/latex.rs b/support/texlab/crates/parser/src/latex.rs index 669ba82f99..8379d9c5ca 100644 --- a/support/texlab/crates/parser/src/latex.rs +++ b/support/texlab/crates/parser/src/latex.rs @@ -158,6 +158,9 @@ impl<'a> Parser<'a> { CommandName::EndBlockComment => self.generic_command(), CommandName::VerbatimBlock => self.verbatim_block(), CommandName::GraphicsPath => self.graphics_path(), + CommandName::BibItem => self.bibitem(), + CommandName::TocContentsLine => self.toc_contents_line(), + CommandName::TocNumberLine => self.toc_number_line(), }, } } @@ -862,7 +865,20 @@ impl<'a> Parser<'a> { } if self.lexer.peek() == Some(Token::LCurly) { - self.curly_group_word(); + self.builder.start_node(CURLY_GROUP_WORD.into()); + self.eat(); + self.trivia(); + + if self.peek() == Some(Token::Word) || self.peek() == Some(Token::Pipe) { + self.key(); + } + + if let Some(Token::CommandName(_)) = self.peek() { + self.content(ParserContext::default()); + } + + self.expect(Token::RCurly); + self.builder.finish_node(); } self.builder.finish_node(); @@ -1235,6 +1251,50 @@ impl<'a> Parser<'a> { } } } + + fn bibitem(&mut self) { + self.builder.start_node(BIBITEM.into()); + self.eat(); + self.trivia(); + + if self.lexer.peek() == Some(Token::LCurly) { + self.curly_group_word(); + } + + self.builder.finish_node(); + } + + fn toc_contents_line(&mut self) { + self.builder.start_node(TOC_CONTENTS_LINE.into()); + self.eat(); + self.trivia(); + + if self.lexer.peek() == Some(Token::LCurly) { + self.curly_group(); + } + + if self.lexer.peek() == Some(Token::LCurly) { + self.curly_group(); + } + + if self.lexer.peek() == Some(Token::LCurly) { + self.curly_group(); + } + + self.builder.finish_node(); + } + + fn toc_number_line(&mut self) { + self.builder.start_node(TOC_NUMBER_LINE.into()); + self.eat(); + self.trivia(); + + if self.lexer.peek() == Some(Token::LCurly) { + self.curly_group(); + } + + self.builder.finish_node(); + } } pub fn parse_latex(text: &str, config: &SyntaxConfig) -> GreenNode { diff --git a/support/texlab/crates/parser/src/latex/lexer/commands.rs b/support/texlab/crates/parser/src/latex/lexer/commands.rs index 4d1a7ca320..3f8b6e36ed 100644 --- a/support/texlab/crates/parser/src/latex/lexer/commands.rs +++ b/support/texlab/crates/parser/src/latex/lexer/commands.rs @@ -96,6 +96,9 @@ pub fn classify(name: &str, config: &SyntaxConfig) -> CommandName { "iffalse" => CommandName::BeginBlockComment, "fi" => CommandName::EndBlockComment, "verb" => CommandName::VerbatimBlock, + "bibitem" => CommandName::BibItem, + "contentsline" => CommandName::TocContentsLine, + "numberline" => CommandName::TocNumberLine, _ if config.citation_commands.contains(name) => CommandName::Citation, _ if config.label_definition_commands.contains(name) => CommandName::LabelDefinition, diff --git a/support/texlab/crates/parser/src/latex/lexer/types.rs b/support/texlab/crates/parser/src/latex/lexer/types.rs index 85e542792b..796378f671 100644 --- a/support/texlab/crates/parser/src/latex/lexer/types.rs +++ b/support/texlab/crates/parser/src/latex/lexer/types.rs @@ -95,6 +95,9 @@ pub enum CommandName { BeginBlockComment, EndBlockComment, VerbatimBlock, + BibItem, + TocContentsLine, + TocNumberLine, } #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)] diff --git a/support/texlab/crates/references/src/command.rs b/support/texlab/crates/references/src/command.rs index f4504641f2..cf5849a136 100644 --- a/support/texlab/crates/references/src/command.rs +++ b/support/texlab/crates/references/src/command.rs @@ -32,7 +32,9 @@ pub(super) fn find_all(context: &mut ReferenceContext) -> Option<()> { .collect(); for command in &data.semantics.commands { - if command.text == token.text()[1..] { + let command_text = command.text.trim_end_matches('*'); + let token_text = token.text()[1..].trim_end_matches('*'); + if command_text == token_text { let kind = if defs.contains(command) { ReferenceKind::Definition } else { diff --git a/support/texlab/crates/references/src/tests.rs b/support/texlab/crates/references/src/tests.rs index 845282afb0..7131480699 100644 --- a/support/texlab/crates/references/src/tests.rs +++ b/support/texlab/crates/references/src/tests.rs @@ -260,3 +260,43 @@ fn test_new_command_definition_include_decl() { true, ); } + +#[test] +fn test_new_command_definition_starred() { + check( + r#" +%! main.tex +\foo + ^^^ +\foo* + | + ^^^^ + +\NewDocumentCommand{\foo}{s m}{% + \IfBooleanTF{#1}{\textbf{#2}}{#2}% +} +"#, + false, + ); +} + +#[test] +fn test_new_command_definition_starred_include_decl() { + check( + r#" +%! main.tex +\foo + ^^^ +\foo* + | + ^^^^ + +\NewDocumentCommand{\foo}{s m}{% + ^^^ + \IfBooleanTF{#1}{\textbf{#2}}{#2}% +} + +"#, + true, + ); +} diff --git a/support/texlab/crates/symbols/src/document/tests.rs b/support/texlab/crates/symbols/src/document/tests.rs index 25450a6cc5..cf599529fb 100644 --- a/support/texlab/crates/symbols/src/document/tests.rs +++ b/support/texlab/crates/symbols/src/document/tests.rs @@ -281,44 +281,44 @@ fn test_section() { check( &fixture, expect![[r#" - [ - Symbol { - name: "Foo", - kind: Section, - label: None, - full_range: 43..56, - selection_range: 43..56, - children: [], - }, - Symbol { - name: "2 Bar", - kind: Section, - label: Some( - Span( - "sec:bar", - 71..86, + [ + Symbol { + name: "1 Foo", + kind: Section, + label: None, + full_range: 43..56, + selection_range: 43..56, + children: [], + }, + Symbol { + name: "2 Bar", + kind: Section, + label: Some( + Span( + "sec:bar", + 71..86, + ), ), - ), - full_range: 58..119, - selection_range: 71..86, - children: [ - Symbol { - name: "Baz", - kind: Section, - label: Some( - Span( - "sec:baz", - 104..119, + full_range: 58..119, + selection_range: 71..86, + children: [ + Symbol { + name: "Baz", + kind: Section, + label: Some( + Span( + "sec:baz", + 104..119, + ), ), - ), - full_range: 88..119, - selection_range: 104..119, - children: [], - }, - ], - }, - ] - "#]], + full_range: 88..119, + selection_range: 104..119, + children: [], + }, + ], + }, + ] + "#]], ); } diff --git a/support/texlab/crates/symbols/src/document/tex.rs b/support/texlab/crates/symbols/src/document/tex.rs index e0df9c85c1..734335ef0e 100644 --- a/support/texlab/crates/symbols/src/document/tex.rs +++ b/support/texlab/crates/symbols/src/document/tex.rs @@ -67,16 +67,14 @@ impl<'a> SymbolBuilder<'a> { let group_text = group.content_text()?; let kind = SymbolKind::Section; - let symbol = match self.find_label(section.syntax()) { - Some(label) => { - let name = match self.find_label_number(&label.text) { - Some(number) => format!("{number} {group_text}"), - None => group_text, - }; + let name = match self.find_section_number(&group_text) { + Some(number) => format!("{number} {group_text}"), + None => group_text, + }; - Symbol::new_label(name, kind, range, label) - } - None => Symbol::new_simple(group_text, kind, range, range), + let symbol = match self.find_label(section.syntax()) { + Some(label) => Symbol::new_label(name, kind, range, label), + None => Symbol::new_simple(name, kind, range, range) }; Some(symbol) @@ -247,6 +245,15 @@ impl<'a> SymbolBuilder<'a> { Some(Span { text, range }) } + fn find_section_number(&self, name: &str) -> Option<&str> { + self.project + .documents + .iter() + .filter_map(|document| document.data.as_aux()) + .find_map(|data| data.semantics.section_numbers.get(name)) + .map(String::as_str) + } + fn find_label_number(&self, name: &str) -> Option<&str> { self.project .documents diff --git a/support/texlab/crates/syntax/src/latex/cst.rs b/support/texlab/crates/syntax/src/latex/cst.rs index 806be2aa83..580ef6af12 100644 --- a/support/texlab/crates/syntax/src/latex/cst.rs +++ b/support/texlab/crates/syntax/src/latex/cst.rs @@ -750,3 +750,43 @@ impl GraphicsPath { self.syntax().descendants().filter_map(CurlyGroupWord::cast) } } + +cst_node!(BibItem, BIBITEM); + +impl BibItem { + pub fn command(&self) -> Option<SyntaxToken> { + self.syntax().first_token() + } + + pub fn name(&self) -> Option<CurlyGroupWord> { + self.syntax().children().find_map(CurlyGroupWord::cast) + } +} + +cst_node!(TocContentsLine, TOC_CONTENTS_LINE); + +impl TocContentsLine { + pub fn command(&self) -> Option<SyntaxToken> { + self.syntax().first_token() + } + + pub fn unit(&self) -> Option<CurlyGroup> { + self.syntax().children().find_map(CurlyGroup::cast) + } + + pub fn line(&self) -> Option<CurlyGroup> { + self.syntax().children().filter_map(CurlyGroup::cast).nth(1) + } +} + +cst_node!(TocNumberLine, TOC_NUMBER_LINE); + +impl TocNumberLine { + pub fn command(&self) -> Option<SyntaxToken> { + self.syntax().first_token() + } + + pub fn number(&self) -> Option<CurlyGroup> { + self.syntax().children().find_map(CurlyGroup::cast) + } +} diff --git a/support/texlab/crates/syntax/src/latex/kind.rs b/support/texlab/crates/syntax/src/latex/kind.rs index 362f2ea058..f67201e003 100644 --- a/support/texlab/crates/syntax/src/latex/kind.rs +++ b/support/texlab/crates/syntax/src/latex/kind.rs @@ -82,6 +82,9 @@ pub enum SyntaxKind { ENVIRONMENT_DEFINITION, GRAPHICS_PATH, BLOCK_COMMENT, + BIBITEM, + TOC_CONTENTS_LINE, + TOC_NUMBER_LINE, ROOT, } diff --git a/support/texlab/crates/texlab/Cargo.toml b/support/texlab/crates/texlab/Cargo.toml index 149b0c632f..5f73cbf024 100644 --- a/support/texlab/crates/texlab/Cargo.toml +++ b/support/texlab/crates/texlab/Cargo.toml @@ -26,7 +26,7 @@ anyhow.workspace = true base-db = { path = "../base-db" } bibfmt = { path = "../bibfmt" } citeproc = { path = "../citeproc" } -clap = { version = "4.5.19", features = ["derive"] } +clap = { version = "4.5.20", features = ["derive"] } commands = { path = "../commands" } completion = { path = "../completion" } completion-data = { path = "../completion-data" } @@ -34,7 +34,7 @@ crossbeam-channel.workspace = true definition = { path = "../definition" } diagnostics = { path = "../diagnostics" } distro = { path = "../distro" } -fern = "0.6.2" +fern = "0.7.0" folding = { path = "../folding" } highlights = { path = "../highlights" } hover = { path = "../hover" } @@ -46,7 +46,7 @@ log.workspace = true lsp-server = "0.7.7" lsp-types = "0.95.1" notify.workspace = true -notify-debouncer-full = "0.3.1" +notify-debouncer-full = "0.3.2" parking_lot = "0.12.3" parser = { path = "../parser" } references = { path = "../references" } diff --git a/support/texlab/crates/texlab/src/features/formatting/latexindent.rs b/support/texlab/crates/texlab/src/features/formatting/latexindent.rs index d3fffc2050..b956378ed5 100644 --- a/support/texlab/crates/texlab/src/features/formatting/latexindent.rs +++ b/support/texlab/crates/texlab/src/features/formatting/latexindent.rs @@ -16,7 +16,7 @@ pub fn format_with_latexindent( ) -> Option<Vec<lsp_types::TextEdit>> { let config = workspace.config(); let target_dir = tempdir().ok()?; - let root = ProjectRoot::walk_and_find(workspace, &document.dir); + let root = ProjectRoot::walk_and_find(workspace, document.dir.as_ref()?); let source_dir = root.src_dir.to_file_path().ok()?; let target_file = target_dir @@ -72,6 +72,15 @@ fn build_arguments(config: &LatexIndentConfig, target_file: &Path) -> Vec<String args.push("--modifylinebreaks".to_string()); } + match &config.replacement { + Some(replacement_flag) => { + if ["-r", "-rv", "-rr"].contains(& replacement_flag.as_str()) { + args.push(replacement_flag.clone()); + } + }, + None => {} + } + args.push(target_file.display().to_string()); args } diff --git a/support/texlab/crates/texlab/src/server/options.rs b/support/texlab/crates/texlab/src/server/options.rs index bc785c56c1..fcb8e1ec60 100644 --- a/support/texlab/crates/texlab/src/server/options.rs +++ b/support/texlab/crates/texlab/src/server/options.rs @@ -56,6 +56,7 @@ impl Default for LatexFormatter { pub struct LatexindentOptions { pub local: Option<String>, pub modify_line_breaks: bool, + pub replacement: Option<String>, } #[derive(Debug, PartialEq, Eq, Clone, Default, Serialize, Deserialize)] diff --git a/support/texlab/crates/texlab/src/util/from_proto.rs b/support/texlab/crates/texlab/src/util/from_proto.rs index 2f4fbe64c5..928b3d6d61 100644 --- a/support/texlab/crates/texlab/src/util/from_proto.rs +++ b/support/texlab/crates/texlab/src/util/from_proto.rs @@ -282,6 +282,7 @@ pub fn config(value: Options) -> Config { config.formatting.latex_indent.local = value.latexindent.local; config.formatting.latex_indent.modify_line_breaks = value.latexindent.modify_line_breaks; + config.formatting.latex_indent.replacement = value.latexindent.replacement; config.synctex = value .forward_search |