Skip to content

Commit

Permalink
Add "Go To definition" support for \def-like cmds (#1084)
Browse files Browse the repository at this point in the history
  • Loading branch information
pfoerster authored Apr 20, 2024
1 parent c8f8818 commit bb8922a
Show file tree
Hide file tree
Showing 9 changed files with 166 additions and 100 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Replace tilde (`~`), environment variables, `${userHome}`, `${workspaceFolder}` in options
- Replace tidle (`~`) with home directory in `\include`-like commands
- Add "Go To Definition" support for user-defined commands with `\def` and `\let` ([#1081](https://github.com/latex-lsp/texlab/issues/1081))

## [5.14.1] - 2024-03-27

Expand Down
28 changes: 19 additions & 9 deletions crates/definition/src/command.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use base_db::DocumentData;
use rowan::ast::AstNode;
use rowan::{ast::AstNode, TextRange};
use syntax::latex;

use crate::DefinitionContext;
Expand All @@ -24,18 +24,16 @@ pub(super) fn goto_definition(context: &mut DefinitionContext) -> Option<()> {
let results = data
.root_node()
.descendants()
.filter_map(latex::CommandDefinition::cast)
.filter(|def| {
def.name()
.and_then(|name| name.command())
.map_or(false, |node| node.text() == name.text())
.filter_map(|node| {
process_old_definition(node.clone()).or_else(|| process_new_definition(node))
})
.filter_map(|def| {
.filter(|(_, command)| command.text() == name.text())
.filter_map(|(target_range, command)| {
Some(DefinitionResult {
origin_selection_range,
target: document,
target_range: latex::small_range(&def),
target_selection_range: def.name()?.command()?.text_range(),
target_range,
target_selection_range: command.text_range(),
})
});

Expand All @@ -44,3 +42,15 @@ pub(super) fn goto_definition(context: &mut DefinitionContext) -> Option<()> {

Some(())
}

fn process_old_definition(node: latex::SyntaxNode) -> Option<(TextRange, latex::SyntaxToken)> {
let node = latex::OldCommandDefinition::cast(node)?;
let name = node.name()?;
Some((latex::small_range(&node), name))
}

fn process_new_definition(node: latex::SyntaxNode) -> Option<(TextRange, latex::SyntaxToken)> {
let node = latex::NewCommandDefinition::cast(node)?;
let name = node.name()?.command()?;
Some((latex::small_range(&node), name))
}
16 changes: 15 additions & 1 deletion crates/definition/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,21 @@ fn check(input: &str) {
}

#[test]
fn test_command_definition() {
fn test_old_command_definition() {
check(
r#"
%! main.tex
\def\foo{foo}
^^^^
^^^^^^^^
\foo
|
^^^^"#,
)
}

#[test]
fn test_new_command_definition() {
check(
r#"
%! main.tex
Expand Down
20 changes: 17 additions & 3 deletions crates/parser/src/latex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,8 @@ impl<'a> Parser<'a> {
CommandName::LabelReference => self.label_reference(),
CommandName::LabelReferenceRange => self.label_reference_range(),
CommandName::LabelNumber => self.label_number(),
CommandName::CommandDefinition => self.command_definition(),
CommandName::OldCommandDefinition => self.old_command_definition(),
CommandName::NewCommandDefinition => self.new_command_definition(),
CommandName::MathOperator => self.math_operator(),
CommandName::GlossaryEntryDefinition => self.glossary_entry_definition(),
CommandName::GlossaryEntryReference => self.glossary_entry_reference(),
Expand Down Expand Up @@ -907,8 +908,21 @@ impl<'a> Parser<'a> {
self.builder.finish_node();
}

fn command_definition(&mut self) {
self.builder.start_node(COMMAND_DEFINITION.into());
fn old_command_definition(&mut self) {
self.builder.start_node(OLD_COMMAND_DEFINITION.into());
self.eat();
self.trivia();

if let Some(Token::CommandName(_)) = self.lexer.peek() {
self.eat();
self.trivia();
}

self.builder.finish_node();
}

fn new_command_definition(&mut self) {
self.builder.start_node(NEW_COMMAND_DEFINITION.into());
self.eat();
self.trivia();

Expand Down
17 changes: 13 additions & 4 deletions crates/parser/src/latex/lexer/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,19 @@ pub fn classify(name: &str, config: &SyntaxConfig) -> CommandName {
"label" => CommandName::LabelDefinition,
"crefrange" | "crefrange*" | "Crefrange" | "Crefrange*" => CommandName::LabelReferenceRange,
"newlabel" => CommandName::LabelNumber,
"newcommand" | "newcommand*" | "renewcommand" | "renewcommand*"
| "DeclareRobustCommand" | "DeclareRobustCommand*"
| "NewDocumentCommand" | "RenewDocumentCommand" | "DeclareDocumentCommand"
| "NewCommandCopy" | "RenewCommandCopy" | "DeclareCommandCopy" => CommandName::CommandDefinition,
"def" | "let" => CommandName::OldCommandDefinition,
"newcommand"
| "newcommand*"
| "renewcommand"
| "renewcommand*"
| "DeclareRobustCommand"
| "DeclareRobustCommand*"
| "NewDocumentCommand"
| "RenewDocumentCommand"
| "DeclareDocumentCommand"
| "NewCommandCopy"
| "RenewCommandCopy"
| "DeclareCommandCopy" => CommandName::NewCommandDefinition,
"DeclareMathOperator" | "DeclareMathOperator*" => CommandName::MathOperator,
"newglossaryentry" => CommandName::GlossaryEntryDefinition,
"gls" | "Gls" | "GLS" | "glspl" | "Glspl" | "GLSpl" | "glsdisp" | "glslink" | "glstext"
Expand Down
3 changes: 2 additions & 1 deletion crates/parser/src/latex/lexer/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@ pub enum CommandName {
LabelReference,
LabelReferenceRange,
LabelNumber,
CommandDefinition,
OldCommandDefinition,
NewCommandDefinition,
MathOperator,
GlossaryEntryDefinition,
GlossaryEntryReference,
Expand Down
158 changes: 79 additions & 79 deletions crates/parser/src/latex/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -560,21 +560,21 @@ fn test_command_definition_no_argc() {
check(
r#"\newcommand{\foo}{foo}"#,
expect![[r#"
ROOT@0..22
PREAMBLE@0..22
COMMAND_DEFINITION@0..22
COMMAND_NAME@0..11 "\\newcommand"
CURLY_GROUP_COMMAND@11..17
L_CURLY@11..12 "{"
COMMAND_NAME@12..16 "\\foo"
R_CURLY@16..17 "}"
CURLY_GROUP@17..22
L_CURLY@17..18 "{"
TEXT@18..21
WORD@18..21 "foo"
R_CURLY@21..22 "}"
ROOT@0..22
PREAMBLE@0..22
NEW_COMMAND_DEFINITION@0..22
COMMAND_NAME@0..11 "\\newcommand"
CURLY_GROUP_COMMAND@11..17
L_CURLY@11..12 "{"
COMMAND_NAME@12..16 "\\foo"
R_CURLY@16..17 "}"
CURLY_GROUP@17..22
L_CURLY@17..18 "{"
TEXT@18..21
WORD@18..21 "foo"
R_CURLY@21..22 "}"
"#]],
"#]],
);
}

Expand All @@ -583,16 +583,16 @@ fn test_command_definition_no_impl() {
check(
r#"\newcommand{\foo}"#,
expect![[r#"
ROOT@0..17
PREAMBLE@0..17
COMMAND_DEFINITION@0..17
COMMAND_NAME@0..11 "\\newcommand"
CURLY_GROUP_COMMAND@11..17
L_CURLY@11..12 "{"
COMMAND_NAME@12..16 "\\foo"
R_CURLY@16..17 "}"
ROOT@0..17
PREAMBLE@0..17
NEW_COMMAND_DEFINITION@0..17
COMMAND_NAME@0..11 "\\newcommand"
CURLY_GROUP_COMMAND@11..17
L_CURLY@11..12 "{"
COMMAND_NAME@12..16 "\\foo"
R_CURLY@16..17 "}"
"#]],
"#]],
);
}

Expand All @@ -601,15 +601,15 @@ fn test_command_definition_no_impl_error() {
check(
r#"\newcommand{\foo"#,
expect![[r#"
ROOT@0..16
PREAMBLE@0..16
COMMAND_DEFINITION@0..16
COMMAND_NAME@0..11 "\\newcommand"
CURLY_GROUP_COMMAND@11..16
L_CURLY@11..12 "{"
COMMAND_NAME@12..16 "\\foo"
ROOT@0..16
PREAMBLE@0..16
NEW_COMMAND_DEFINITION@0..16
COMMAND_NAME@0..11 "\\newcommand"
CURLY_GROUP_COMMAND@11..16
L_CURLY@11..12 "{"
COMMAND_NAME@12..16 "\\foo"
"#]],
"#]],
);
}

Expand All @@ -618,31 +618,31 @@ fn test_command_definition_optional() {
check(
r#"\newcommand{\foo}[1][def]{#1}"#,
expect![[r##"
ROOT@0..29
PREAMBLE@0..29
COMMAND_DEFINITION@0..29
COMMAND_NAME@0..11 "\\newcommand"
CURLY_GROUP_COMMAND@11..17
L_CURLY@11..12 "{"
COMMAND_NAME@12..16 "\\foo"
R_CURLY@16..17 "}"
BRACK_GROUP_WORD@17..20
L_BRACK@17..18 "["
KEY@18..19
WORD@18..19 "1"
R_BRACK@19..20 "]"
BRACK_GROUP@20..25
L_BRACK@20..21 "["
TEXT@21..24
WORD@21..24 "def"
R_BRACK@24..25 "]"
CURLY_GROUP@25..29
L_CURLY@25..26 "{"
TEXT@26..28
WORD@26..28 "#1"
R_CURLY@28..29 "}"
ROOT@0..29
PREAMBLE@0..29
NEW_COMMAND_DEFINITION@0..29
COMMAND_NAME@0..11 "\\newcommand"
CURLY_GROUP_COMMAND@11..17
L_CURLY@11..12 "{"
COMMAND_NAME@12..16 "\\foo"
R_CURLY@16..17 "}"
BRACK_GROUP_WORD@17..20
L_BRACK@17..18 "["
KEY@18..19
WORD@18..19 "1"
R_BRACK@19..20 "]"
BRACK_GROUP@20..25
L_BRACK@20..21 "["
TEXT@21..24
WORD@21..24 "def"
R_BRACK@24..25 "]"
CURLY_GROUP@25..29
L_CURLY@25..26 "{"
TEXT@26..28
WORD@26..28 "#1"
R_CURLY@28..29 "}"
"##]],
"##]],
);
}

Expand All @@ -651,27 +651,27 @@ fn test_command_definition_simple() {
check(
r#"\newcommand[1]{\id}{#1}"#,
expect![[r##"
ROOT@0..23
PREAMBLE@0..23
COMMAND_DEFINITION@0..19
COMMAND_NAME@0..11 "\\newcommand"
BRACK_GROUP_WORD@11..14
L_BRACK@11..12 "["
KEY@12..13
WORD@12..13 "1"
R_BRACK@13..14 "]"
CURLY_GROUP@14..19
L_CURLY@14..15 "{"
GENERIC_COMMAND@15..18
COMMAND_NAME@15..18 "\\id"
R_CURLY@18..19 "}"
CURLY_GROUP@19..23
L_CURLY@19..20 "{"
TEXT@20..22
WORD@20..22 "#1"
R_CURLY@22..23 "}"
ROOT@0..23
PREAMBLE@0..23
NEW_COMMAND_DEFINITION@0..19
COMMAND_NAME@0..11 "\\newcommand"
BRACK_GROUP_WORD@11..14
L_BRACK@11..12 "["
KEY@12..13
WORD@12..13 "1"
R_BRACK@13..14 "]"
CURLY_GROUP@14..19
L_CURLY@14..15 "{"
GENERIC_COMMAND@15..18
COMMAND_NAME@15..18 "\\id"
R_CURLY@18..19 "}"
CURLY_GROUP@19..23
L_CURLY@19..20 "{"
TEXT@20..22
WORD@20..22 "#1"
R_CURLY@22..23 "}"
"##]],
"##]],
);
}

Expand All @@ -682,7 +682,7 @@ fn test_command_definition_with_begin() {
expect![[r#"
ROOT@0..80
PREAMBLE@0..80
COMMAND_DEFINITION@0..80
NEW_COMMAND_DEFINITION@0..80
COMMAND_NAME@0..11 "\\newcommand"
CURLY_GROUP_COMMAND@11..35
L_CURLY@11..12 "{"
Expand Down Expand Up @@ -2681,15 +2681,15 @@ fn test_issue_857() {
expect![[r#"
ROOT@0..55
PREAMBLE@0..55
COMMAND_DEFINITION@0..11
NEW_COMMAND_DEFINITION@0..11
COMMAND_NAME@0..11 "\\newcommand"
GENERIC_COMMAND@11..17
COMMAND_NAME@11..14 "\\ö"
CURLY_GROUP@14..17
L_CURLY@14..15 "{"
R_CURLY@15..16 "}"
LINE_BREAK@16..17 "\n"
COMMAND_DEFINITION@17..38
NEW_COMMAND_DEFINITION@17..38
COMMAND_NAME@17..28 "\\newcommand"
CURLY_GROUP_COMMAND@28..35
L_CURLY@28..29 "{"
Expand All @@ -2699,7 +2699,7 @@ fn test_issue_857() {
L_CURLY@35..36 "{"
R_CURLY@36..37 "}"
LINE_BREAK@37..38 "\n"
COMMAND_DEFINITION@38..49
NEW_COMMAND_DEFINITION@38..49
COMMAND_NAME@38..49 "\\newcommand"
GENERIC_COMMAND@49..55
COMMAND_NAME@49..53 "\\123"
Expand Down
Loading

0 comments on commit bb8922a

Please sign in to comment.