Add symbol support for thmtools package (#897)

This commit is contained in:
Patrick Förster 2023-06-07 09:35:57 +02:00 committed by GitHub
parent 365c04050c
commit f24f35f2a6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 200 additions and 21 deletions

View file

@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Added
- Add symbol support for `thmtools` package ([#894](https://github.com/latex-lsp/texlab/issues/894))
### Changed
- Show inlay hints for labels after the command instead of inside the argument ([#890](https://github.com/latex-lsp/texlab/issues/890))

View file

@ -223,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,
});
}
}

View file

@ -138,7 +138,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(),
@ -978,8 +979,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 +1003,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();

View file

@ -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,

View file

@ -111,7 +111,8 @@ pub enum CommandName {
AcronymDefinition,
AcronymDeclaration,
AcronymReference,
TheoremDefinition,
TheoremDefinitionAmsThm,
TheoremDefinitionThmTools,
ColorReference,
ColorDefinition,
ColorSetDefinition,

View file

@ -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 "{"

View file

@ -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 "{"

View file

@ -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 "{"

View file

@ -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 "{"

View file

@ -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 "{"

View file

@ -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 "}"

View file

@ -0,0 +1 @@
\declaretheorem[style=foo, name=bar]{baz}

View file

@ -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: [],
},
]

View file

@ -138,7 +138,7 @@ fn test_section() {
}
#[test]
fn test_theorem() {
fn test_theorem_amsthm() {
let fixture = Fixture::parse(
r#"
%! main.tex
@ -177,6 +177,46 @@ fn test_theorem() {
assert_debug_snapshot!(document_symbols(&fixture.workspace, document));
}
#[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(

View file

@ -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())
}
}
}

View file

@ -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,