mirror of
https://github.com/Myriad-Dreamin/tinymist.git
synced 2025-07-24 05:05:00 +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 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 is_set = parent.kind() == SyntaxKind::SetRule;
|
||||||
let target = arg_context(args.clone(), node, ArgSourceKind::Call)?;
|
let target = arg_context(args.clone(), node, ArgSourceKind::Call)?;
|
||||||
Some(SyntaxContext::Arg {
|
Some(SyntaxContext::Arg {
|
||||||
|
|
|
@ -99,7 +99,7 @@ mod tests {
|
||||||
let result = request.request(ctx);
|
let result = request.request(ctx);
|
||||||
|
|
||||||
with_settings!({
|
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));
|
assert_snapshot!(JsonRepr::new_redacted(result, &REDACT_LOC));
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
#let f(x) = x;
|
#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
|
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)"
|
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
|
||||||
input_file: crates/tinymist-query/src/fixtures/signature_help/base.typ
|
input_file: crates/tinymist-query/src/fixtures/signature_help/base.typ
|
||||||
snapshot_kind: text
|
|
||||||
---
|
---
|
||||||
{
|
{
|
||||||
"activeSignature": 0,
|
"activeSignature": 0,
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
---
|
---
|
||||||
source: crates/tinymist-query/src/signature_help.rs
|
source: crates/tinymist-query/src/signature_help.rs
|
||||||
|
description: "signature help on underline(|/* loc 0, "
|
||||||
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
|
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
|
||||||
input_file: crates/tinymist-query/src/fixtures/signature_help/builtin.typ
|
input_file: crates/tinymist-query/src/fixtures/signature_help/builtin.typ
|
||||||
snapshot_kind: text
|
|
||||||
---
|
---
|
||||||
{
|
{
|
||||||
"activeSignature": 0,
|
"activeSignature": 0,
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
---
|
---
|
||||||
source: crates/tinymist-query/src/signature_help.rs
|
source: crates/tinymist-query/src/signature_help.rs
|
||||||
|
description: "signature help on underline(|/* loc 0, "
|
||||||
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
|
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
|
||||||
input_file: crates/tinymist-query/src/fixtures/signature_help/builtin2.typ
|
input_file: crates/tinymist-query/src/fixtures/signature_help/builtin2.typ
|
||||||
snapshot_kind: text
|
|
||||||
---
|
---
|
||||||
{
|
{
|
||||||
"activeSignature": 0,
|
"activeSignature": 0,
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
---
|
---
|
||||||
source: crates/tinymist-query/src/signature_help.rs
|
source: crates/tinymist-query/src/signature_help.rs
|
||||||
|
description: "signature help on tem.where(|/* loc 0, "
|
||||||
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
|
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
|
||||||
input_file: crates/tinymist-query/src/fixtures/signature_help/list_item.typ
|
input_file: crates/tinymist-query/src/fixtures/signature_help/list_item.typ
|
||||||
snapshot_kind: text
|
|
||||||
---
|
---
|
||||||
{
|
{
|
||||||
"activeSignature": 0,
|
"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
|
source: crates/tinymist-query/src/signature_help.rs
|
||||||
|
description: "signature help on ine.where(|/* loc 0, "
|
||||||
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
|
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
|
||||||
input_file: crates/tinymist-query/src/fixtures/signature_help/where.typ
|
input_file: crates/tinymist-query/src/fixtures/signature_help/where.typ
|
||||||
snapshot_kind: text
|
|
||||||
---
|
---
|
||||||
{
|
{
|
||||||
"activeSignature": 0,
|
"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() {
|
fn test() {
|
||||||
snapshot_testing("signature_help", &|ctx, path| {
|
snapshot_testing("signature_help", &|ctx, path| {
|
||||||
let source = ctx.source_by_path(&path).unwrap();
|
let source = ctx.source_by_path(&path).unwrap();
|
||||||
|
let (position, anno) = make_pos_annoation(&source);
|
||||||
|
|
||||||
let request = SignatureHelpRequest {
|
let request = SignatureHelpRequest { path, position };
|
||||||
path: path.clone(),
|
|
||||||
position: find_test_position(&source),
|
|
||||||
};
|
|
||||||
|
|
||||||
let result = request.request(ctx);
|
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;
|
pub use crate::syntax::find_module_level_docs;
|
||||||
use crate::{analysis::Analysis, prelude::LocalContext, LspPosition, PositionEncoding};
|
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)) {
|
pub fn snapshot_testing(name: &str, f: &impl Fn(&mut LocalContext, PathBuf)) {
|
||||||
tinymist_tests::snapshot_testing!(name, |verse, path| {
|
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 {
|
pub fn find_test_typst_pos(s: &Source) -> usize {
|
||||||
enum AstMatcher {
|
enum PosMatcher {
|
||||||
MatchAny { prev: bool },
|
Pos { prev: bool, ident: bool },
|
||||||
MatchIdent { prev: bool },
|
LoC { line: i32, column: i32 },
|
||||||
}
|
}
|
||||||
use AstMatcher::*;
|
use PosMatcher::*;
|
||||||
|
|
||||||
let re = s
|
fn pos(prev: bool, ident: bool) -> Option<PosMatcher> {
|
||||||
.text()
|
Some(Pos { prev, ident })
|
||||||
.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();
|
|
||||||
|
|
||||||
let n = LinkedNode::new(s.root());
|
let re = s.text().find("/* position */").zip(pos(true, false));
|
||||||
let mut n = n.leaf_at_compat(re + 1).unwrap();
|
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 {
|
let Some((rel_offset, matcher)) = re else {
|
||||||
MatchAny { prev } => *prev,
|
panic!("No (or bad) position marker found in source:\n{}", s.text())
|
||||||
MatchIdent { prev } => *prev,
|
|
||||||
};
|
|
||||||
let match_ident = match m {
|
|
||||||
MatchAny { .. } => false,
|
|
||||||
MatchIdent { .. } => true,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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 {
|
'match_loop: loop {
|
||||||
if n.kind().is_trivia() || n.kind().is_error() {
|
if n.kind().is_trivia() || n.kind().is_error() {
|
||||||
let m = if match_prev {
|
let m = if prev {
|
||||||
n.prev_sibling()
|
n.prev_sibling()
|
||||||
} else {
|
} else {
|
||||||
n.next_sibling()
|
n.next_sibling()
|
||||||
|
@ -226,7 +236,7 @@ pub fn find_test_typst_pos(s: &Source) -> usize {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if matches!(n.kind(), SyntaxKind::Named) {
|
if matches!(n.kind(), SyntaxKind::Named) {
|
||||||
if match_ident {
|
if ident {
|
||||||
n = n
|
n = n
|
||||||
.children()
|
.children()
|
||||||
.find(|n| matches!(n.kind(), SyntaxKind::Ident))
|
.find(|n| matches!(n.kind(), SyntaxKind::Ident))
|
||||||
|
@ -236,7 +246,7 @@ pub fn find_test_typst_pos(s: &Source) -> usize {
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if match_ident {
|
if ident {
|
||||||
match n.kind() {
|
match n.kind() {
|
||||||
SyntaxKind::Closure => {
|
SyntaxKind::Closure => {
|
||||||
let closure = n.cast::<ast::Closure>().unwrap();
|
let closure = n.cast::<ast::Closure>().unwrap();
|
||||||
|
@ -265,6 +275,18 @@ pub fn find_test_typst_pos(s: &Source) -> usize {
|
||||||
n.offset()
|
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 {
|
pub fn make_range_annoation(source: &Source) -> String {
|
||||||
let range = find_test_range_(source);
|
let range = find_test_range_(source);
|
||||||
let range_before = range.start.saturating_sub(10)..range.start;
|
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"));
|
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