mirror of
https://github.com/Myriad-Dreamin/tinymist.git
synced 2025-07-24 13:13:43 +00:00
feat: forbid signature help in some cases (#1742)
* feat: forbid signature help in some cases * test: update snapshot
This commit is contained in:
parent
29893aa15f
commit
4ded5a624a
25 changed files with 173 additions and 56 deletions
|
@ -1334,6 +1334,22 @@ fn callee_context<'a>(callee: LinkedNode<'a>, node: LinkedNode<'a>) -> Option<Sy
|
|||
};
|
||||
let args = parent.find(args.span())?;
|
||||
|
||||
let mut parent = &node;
|
||||
loop {
|
||||
use SyntaxKind::*;
|
||||
match parent.kind() {
|
||||
ContentBlock | CodeBlock | Str | Raw | LineComment | BlockComment => {
|
||||
return Option::None
|
||||
}
|
||||
Args if parent.range() == args.range() => {
|
||||
break;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
parent = parent.parent()?;
|
||||
}
|
||||
|
||||
let is_set = parent.kind() == SyntaxKind::SetRule;
|
||||
let target = arg_context(args.clone(), node, ArgSourceKind::Call)?;
|
||||
Some(SyntaxContext::Arg {
|
||||
|
|
|
@ -99,7 +99,7 @@ mod tests {
|
|||
let result = request.request(ctx);
|
||||
|
||||
with_settings!({
|
||||
description => format!("Code Action on {})", make_range_annoation(&source)),
|
||||
description => format!("Code Action on {}", make_range_annoation(&source)),
|
||||
}, {
|
||||
assert_snapshot!(JsonRepr::new_redacted(result, &REDACT_LOC));
|
||||
})
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
#let f(x) = x;
|
||||
|
||||
#(f(/* position */));
|
||||
#(f(/* loc 0, 0 */));
|
|
@ -1 +1 @@
|
|||
#(math.underline(/* position */));
|
||||
#(math.underline(/* loc 0, 0 */));
|
||||
|
|
|
@ -1 +1 @@
|
|||
$underline(/* position */)$
|
||||
$underline(/* loc 0, 0 */)$
|
||||
|
|
|
@ -1 +1 @@
|
|||
#show list.item.where(/* position */): it => it
|
||||
#show list.item.where(/* loc 0, 0 */): it => it
|
|
@ -0,0 +1,2 @@
|
|||
/* loc 1,6 */
|
||||
#strong("")
|
|
@ -0,0 +1,2 @@
|
|||
/* loc 1,7 */
|
||||
#strong("")
|
|
@ -0,0 +1,4 @@
|
|||
#let cmp = l => r => l == r
|
||||
|
||||
/* loc 1, 5 */
|
||||
#cmp(1)(1)
|
|
@ -0,0 +1,4 @@
|
|||
#let cmp = l => r => l == r
|
||||
|
||||
/* loc 1, 8 */
|
||||
#cmp(1)(1)
|
|
@ -0,0 +1,2 @@
|
|||
/* loc 1,9 */
|
||||
#strong("")
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
source: crates/tinymist-query/src/signature_help.rs
|
||||
description: "signature help on = x;\n\n#(f(|/* loc 0, "
|
||||
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
|
||||
input_file: crates/tinymist-query/src/fixtures/signature_help/base.typ
|
||||
snapshot_kind: text
|
||||
---
|
||||
{
|
||||
"activeSignature": 0,
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
source: crates/tinymist-query/src/signature_help.rs
|
||||
description: "signature help on underline(|/* loc 0, "
|
||||
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
|
||||
input_file: crates/tinymist-query/src/fixtures/signature_help/builtin.typ
|
||||
snapshot_kind: text
|
||||
---
|
||||
{
|
||||
"activeSignature": 0,
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
source: crates/tinymist-query/src/signature_help.rs
|
||||
description: "signature help on underline(|/* loc 0, "
|
||||
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
|
||||
input_file: crates/tinymist-query/src/fixtures/signature_help/builtin2.typ
|
||||
snapshot_kind: text
|
||||
---
|
||||
{
|
||||
"activeSignature": 0,
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
source: crates/tinymist-query/src/signature_help.rs
|
||||
description: "signature help on tem.where(|/* loc 0, "
|
||||
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
|
||||
input_file: crates/tinymist-query/src/fixtures/signature_help/list_item.typ
|
||||
snapshot_kind: text
|
||||
---
|
||||
{
|
||||
"activeSignature": 0,
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
source: crates/tinymist-query/src/signature_help.rs
|
||||
description: "signature help on */\n#stron|g(\"\")\n"
|
||||
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
|
||||
input_file: crates/tinymist-query/src/fixtures/signature_help/pos_callee.typ
|
||||
---
|
||||
null
|
|
@ -0,0 +1,35 @@
|
|||
---
|
||||
source: crates/tinymist-query/src/signature_help.rs
|
||||
description: "signature help on */\n#strong|(\"\")\n"
|
||||
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
|
||||
input_file: crates/tinymist-query/src/fixtures/signature_help/pos_callee2.typ
|
||||
---
|
||||
{
|
||||
"activeSignature": 0,
|
||||
"signatures": [
|
||||
{
|
||||
"activeParameter": 0,
|
||||
"documentation": {
|
||||
"kind": "markdown",
|
||||
"value": "Strongly emphasizes content by increasing the font weight.\n\nIncreases the current font weight by a given `delta`.\n\n# Example\n```example\nThis is *strong.* \\\nThis is #strong[too.] \\\n\n#show strong: set text(red)\nAnd this is *evermore.*\n```\n\n# Syntax\nThis function also has dedicated syntax: To strongly emphasize content,\nsimply enclose it in stars/asterisks (`*`). Note that this only works at\nword boundaries. To strongly emphasize part of a word, you have to use the\nfunction."
|
||||
},
|
||||
"label": "strong(body: content, delta: int) -> strong",
|
||||
"parameters": [
|
||||
{
|
||||
"documentation": {
|
||||
"kind": "markdown",
|
||||
"value": "The content to strongly emphasize."
|
||||
},
|
||||
"label": "body:"
|
||||
},
|
||||
{
|
||||
"documentation": {
|
||||
"kind": "markdown",
|
||||
"value": "The delta to apply on the font weight.\n\n```example\n#set strong(delta: 0)\nNo *effect!*\n```"
|
||||
},
|
||||
"label": "delta:"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
source: crates/tinymist-query/src/signature_help.rs
|
||||
description: "signature help on 5 */\n#cmp(|1)(1)\n"
|
||||
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
|
||||
input_file: crates/tinymist-query/src/fixtures/signature_help/pos_chain_call.typ
|
||||
---
|
||||
null
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
source: crates/tinymist-query/src/signature_help.rs
|
||||
description: "signature help on /\n#cmp(1)(|1)\n"
|
||||
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
|
||||
input_file: crates/tinymist-query/src/fixtures/signature_help/pos_chain_call2.typ
|
||||
---
|
||||
null
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
source: crates/tinymist-query/src/signature_help.rs
|
||||
description: "signature help on \n#strong(\"|\")\n"
|
||||
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
|
||||
input_file: crates/tinymist-query/src/fixtures/signature_help/pos_string.typ
|
||||
---
|
||||
null
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
source: crates/tinymist-query/src/signature_help.rs
|
||||
description: "signature help on ine.where(|/* loc 0, "
|
||||
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
|
||||
input_file: crates/tinymist-query/src/fixtures/signature_help/where.typ
|
||||
snapshot_kind: text
|
||||
---
|
||||
{
|
||||
"activeSignature": 0,
|
||||
|
|
|
@ -1 +1 @@
|
|||
#show math.underline.where(/* position */): it => it
|
||||
#show math.underline.where(/* loc 0, 0 */): it => it
|
|
@ -141,14 +141,16 @@ mod tests {
|
|||
fn test() {
|
||||
snapshot_testing("signature_help", &|ctx, path| {
|
||||
let source = ctx.source_by_path(&path).unwrap();
|
||||
let (position, anno) = make_pos_annoation(&source);
|
||||
|
||||
let request = SignatureHelpRequest {
|
||||
path: path.clone(),
|
||||
position: find_test_position(&source),
|
||||
};
|
||||
let request = SignatureHelpRequest { path, position };
|
||||
|
||||
let result = request.request(ctx);
|
||||
assert_snapshot!(JsonRepr::new_redacted(result, &REDACT_LOC));
|
||||
with_settings!({
|
||||
description => format!("signature help on {anno}"),
|
||||
}, {
|
||||
assert_snapshot!(JsonRepr::new_redacted(result, &REDACT_LOC));
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ pub use tinymist_world::WorldComputeGraph;
|
|||
|
||||
pub use crate::syntax::find_module_level_docs;
|
||||
use crate::{analysis::Analysis, prelude::LocalContext, LspPosition, PositionEncoding};
|
||||
use crate::{to_lsp_position, CompletionFeat};
|
||||
use crate::{to_lsp_position, to_typst_position, CompletionFeat};
|
||||
|
||||
pub fn snapshot_testing(name: &str, f: &impl Fn(&mut LocalContext, PathBuf)) {
|
||||
tinymist_tests::snapshot_testing!(name, |verse, path| {
|
||||
|
@ -174,50 +174,60 @@ pub fn find_test_lsp_pos(s: &Source, offset: usize) -> LspPosition {
|
|||
}
|
||||
|
||||
pub fn find_test_typst_pos(s: &Source) -> usize {
|
||||
enum AstMatcher {
|
||||
MatchAny { prev: bool },
|
||||
MatchIdent { prev: bool },
|
||||
enum PosMatcher {
|
||||
Pos { prev: bool, ident: bool },
|
||||
LoC { line: i32, column: i32 },
|
||||
}
|
||||
use AstMatcher::*;
|
||||
use PosMatcher::*;
|
||||
|
||||
let re = s
|
||||
.text()
|
||||
.find("/* position */")
|
||||
.zip(Some(MatchAny { prev: true }));
|
||||
let re = re.or_else(|| {
|
||||
s.text()
|
||||
.find("/* position after */")
|
||||
.zip(Some(MatchAny { prev: false }))
|
||||
});
|
||||
let re = re.or_else(|| {
|
||||
s.text()
|
||||
.find("/* ident */")
|
||||
.zip(Some(MatchIdent { prev: true }))
|
||||
});
|
||||
let re = re.or_else(|| {
|
||||
s.text()
|
||||
.find("/* ident after */")
|
||||
.zip(Some(MatchIdent { prev: false }))
|
||||
});
|
||||
let (re, m) = re
|
||||
.ok_or_else(|| panic!("No position marker found in source:\n{}", s.text()))
|
||||
.unwrap();
|
||||
fn pos(prev: bool, ident: bool) -> Option<PosMatcher> {
|
||||
Some(Pos { prev, ident })
|
||||
}
|
||||
|
||||
let n = LinkedNode::new(s.root());
|
||||
let mut n = n.leaf_at_compat(re + 1).unwrap();
|
||||
let re = s.text().find("/* position */").zip(pos(true, false));
|
||||
let re = re.or_else(|| s.text().find("/* position after */").zip(pos(false, false)));
|
||||
let re = re.or_else(|| s.text().find("/* ident */").zip(pos(true, true)));
|
||||
let re = re.or_else(|| s.text().find("/* ident after */").zip(pos(false, true)));
|
||||
let re = re.or_else(|| {
|
||||
let re = s.text().find("/* loc ")?;
|
||||
let (parts, _) = s.text()[re + "/* loc ".len()..]
|
||||
.trim()
|
||||
.split_once("*/")
|
||||
.expect("bad loc marker");
|
||||
let (line, column) = parts.split_once(',').expect("bad loc marker");
|
||||
let line = line.trim().parse::<i32>().expect("bad loc marker");
|
||||
let column = column.trim().parse::<i32>().expect("bad loc marker");
|
||||
Some((re, LoC { line, column }))
|
||||
});
|
||||
|
||||
let match_prev = match &m {
|
||||
MatchAny { prev } => *prev,
|
||||
MatchIdent { prev } => *prev,
|
||||
};
|
||||
let match_ident = match m {
|
||||
MatchAny { .. } => false,
|
||||
MatchIdent { .. } => true,
|
||||
let Some((rel_offset, matcher)) = re else {
|
||||
panic!("No (or bad) position marker found in source:\n{}", s.text())
|
||||
};
|
||||
|
||||
match matcher {
|
||||
Pos { prev, ident } => {
|
||||
let node = LinkedNode::new(s.root());
|
||||
let node = node.leaf_at_compat(rel_offset + 1).unwrap();
|
||||
|
||||
match_by_pos(node, prev, ident)
|
||||
}
|
||||
LoC { line, column } => {
|
||||
let column = if line != 0 { column } else { 0 };
|
||||
|
||||
let rel_pos = to_lsp_position(rel_offset, PositionEncoding::Utf16, s);
|
||||
let pos = LspPosition {
|
||||
line: (rel_pos.line as i32 + line) as u32,
|
||||
character: (rel_pos.character as i32 + column) as u32,
|
||||
};
|
||||
to_typst_position(pos, PositionEncoding::Utf16, s).expect("invalid loc")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn match_by_pos(mut n: LinkedNode, prev: bool, ident: bool) -> usize {
|
||||
'match_loop: loop {
|
||||
if n.kind().is_trivia() || n.kind().is_error() {
|
||||
let m = if match_prev {
|
||||
let m = if prev {
|
||||
n.prev_sibling()
|
||||
} else {
|
||||
n.next_sibling()
|
||||
|
@ -226,7 +236,7 @@ pub fn find_test_typst_pos(s: &Source) -> usize {
|
|||
continue;
|
||||
}
|
||||
if matches!(n.kind(), SyntaxKind::Named) {
|
||||
if match_ident {
|
||||
if ident {
|
||||
n = n
|
||||
.children()
|
||||
.find(|n| matches!(n.kind(), SyntaxKind::Ident))
|
||||
|
@ -236,7 +246,7 @@ pub fn find_test_typst_pos(s: &Source) -> usize {
|
|||
}
|
||||
continue;
|
||||
}
|
||||
if match_ident {
|
||||
if ident {
|
||||
match n.kind() {
|
||||
SyntaxKind::Closure => {
|
||||
let closure = n.cast::<ast::Closure>().unwrap();
|
||||
|
@ -265,6 +275,18 @@ pub fn find_test_typst_pos(s: &Source) -> usize {
|
|||
n.offset()
|
||||
}
|
||||
|
||||
pub fn make_pos_annoation(source: &Source) -> (LspPosition, String) {
|
||||
let pos = find_test_typst_pos(source);
|
||||
let range_before = pos.saturating_sub(10)..pos;
|
||||
let range_after = pos..pos.saturating_add(10).min(source.text().len());
|
||||
|
||||
let window_before = &source.text()[range_before];
|
||||
let window_after = &source.text()[range_after];
|
||||
|
||||
let pos = to_lsp_position(pos, PositionEncoding::Utf16, source);
|
||||
(pos, format!("{window_before}|{window_after}"))
|
||||
}
|
||||
|
||||
pub fn make_range_annoation(source: &Source) -> String {
|
||||
let range = find_test_range_(source);
|
||||
let range_before = range.start.saturating_sub(10)..range.start;
|
||||
|
|
|
@ -388,7 +388,7 @@ fn e2e() {
|
|||
});
|
||||
|
||||
let hash = replay_log(&tinymist_binary, &root.join("vscode"));
|
||||
insta::assert_snapshot!(hash, @"siphash128_13:3cce756a8b70867a8041cfab6f4337ef");
|
||||
insta::assert_snapshot!(hash, @"siphash128_13:bc403d246654d90466ba47cf9057fee2");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue