diff --git a/crates/tinymist-analysis/src/syntax/matcher.rs b/crates/tinymist-analysis/src/syntax/matcher.rs index 9d9c3404..cf2b2852 100644 --- a/crates/tinymist-analysis/src/syntax/matcher.rs +++ b/crates/tinymist-analysis/src/syntax/matcher.rs @@ -1334,6 +1334,22 @@ fn callee_context<'a>(callee: LinkedNode<'a>, node: LinkedNode<'a>) -> Option { + 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 { diff --git a/crates/tinymist-query/src/code_action.rs b/crates/tinymist-query/src/code_action.rs index 52e52203..6626cab0 100644 --- a/crates/tinymist-query/src/code_action.rs +++ b/crates/tinymist-query/src/code_action.rs @@ -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)); }) diff --git a/crates/tinymist-query/src/fixtures/signature_help/base.typ b/crates/tinymist-query/src/fixtures/signature_help/base.typ index 72a69c53..b3435565 100644 --- a/crates/tinymist-query/src/fixtures/signature_help/base.typ +++ b/crates/tinymist-query/src/fixtures/signature_help/base.typ @@ -1,3 +1,3 @@ #let f(x) = x; -#(f(/* position */)); \ No newline at end of file +#(f(/* loc 0, 0 */)); \ No newline at end of file diff --git a/crates/tinymist-query/src/fixtures/signature_help/builtin.typ b/crates/tinymist-query/src/fixtures/signature_help/builtin.typ index 25d486a1..b5acaa5a 100644 --- a/crates/tinymist-query/src/fixtures/signature_help/builtin.typ +++ b/crates/tinymist-query/src/fixtures/signature_help/builtin.typ @@ -1 +1 @@ -#(math.underline(/* position */)); +#(math.underline(/* loc 0, 0 */)); diff --git a/crates/tinymist-query/src/fixtures/signature_help/builtin2.typ b/crates/tinymist-query/src/fixtures/signature_help/builtin2.typ index fecb2f7d..e5088264 100644 --- a/crates/tinymist-query/src/fixtures/signature_help/builtin2.typ +++ b/crates/tinymist-query/src/fixtures/signature_help/builtin2.typ @@ -1 +1 @@ -$underline(/* position */)$ +$underline(/* loc 0, 0 */)$ diff --git a/crates/tinymist-query/src/fixtures/signature_help/list_item.typ b/crates/tinymist-query/src/fixtures/signature_help/list_item.typ index fb2a2965..873c4612 100644 --- a/crates/tinymist-query/src/fixtures/signature_help/list_item.typ +++ b/crates/tinymist-query/src/fixtures/signature_help/list_item.typ @@ -1 +1 @@ -#show list.item.where(/* position */): it => it \ No newline at end of file +#show list.item.where(/* loc 0, 0 */): it => it \ No newline at end of file diff --git a/crates/tinymist-query/src/fixtures/signature_help/pos_callee.typ b/crates/tinymist-query/src/fixtures/signature_help/pos_callee.typ new file mode 100644 index 00000000..c05ee2a7 --- /dev/null +++ b/crates/tinymist-query/src/fixtures/signature_help/pos_callee.typ @@ -0,0 +1,2 @@ +/* loc 1,6 */ +#strong("") diff --git a/crates/tinymist-query/src/fixtures/signature_help/pos_callee2.typ b/crates/tinymist-query/src/fixtures/signature_help/pos_callee2.typ new file mode 100644 index 00000000..19ab073f --- /dev/null +++ b/crates/tinymist-query/src/fixtures/signature_help/pos_callee2.typ @@ -0,0 +1,2 @@ +/* loc 1,7 */ +#strong("") diff --git a/crates/tinymist-query/src/fixtures/signature_help/pos_chain_call.typ b/crates/tinymist-query/src/fixtures/signature_help/pos_chain_call.typ new file mode 100644 index 00000000..ebc8bac7 --- /dev/null +++ b/crates/tinymist-query/src/fixtures/signature_help/pos_chain_call.typ @@ -0,0 +1,4 @@ +#let cmp = l => r => l == r + +/* loc 1, 5 */ +#cmp(1)(1) diff --git a/crates/tinymist-query/src/fixtures/signature_help/pos_chain_call2.typ b/crates/tinymist-query/src/fixtures/signature_help/pos_chain_call2.typ new file mode 100644 index 00000000..c06ab8cd --- /dev/null +++ b/crates/tinymist-query/src/fixtures/signature_help/pos_chain_call2.typ @@ -0,0 +1,4 @@ +#let cmp = l => r => l == r + +/* loc 1, 8 */ +#cmp(1)(1) diff --git a/crates/tinymist-query/src/fixtures/signature_help/pos_string.typ b/crates/tinymist-query/src/fixtures/signature_help/pos_string.typ new file mode 100644 index 00000000..19004cdb --- /dev/null +++ b/crates/tinymist-query/src/fixtures/signature_help/pos_string.typ @@ -0,0 +1,2 @@ +/* loc 1,9 */ +#strong("") diff --git a/crates/tinymist-query/src/fixtures/signature_help/snaps/test@base.typ.snap b/crates/tinymist-query/src/fixtures/signature_help/snaps/test@base.typ.snap index c3fb2026..61cfecbf 100644 --- a/crates/tinymist-query/src/fixtures/signature_help/snaps/test@base.typ.snap +++ b/crates/tinymist-query/src/fixtures/signature_help/snaps/test@base.typ.snap @@ -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, diff --git a/crates/tinymist-query/src/fixtures/signature_help/snaps/test@builtin.typ.snap b/crates/tinymist-query/src/fixtures/signature_help/snaps/test@builtin.typ.snap index 323b34d8..94b02120 100644 --- a/crates/tinymist-query/src/fixtures/signature_help/snaps/test@builtin.typ.snap +++ b/crates/tinymist-query/src/fixtures/signature_help/snaps/test@builtin.typ.snap @@ -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, diff --git a/crates/tinymist-query/src/fixtures/signature_help/snaps/test@builtin2.typ.snap b/crates/tinymist-query/src/fixtures/signature_help/snaps/test@builtin2.typ.snap index 0d05c393..fd90a937 100644 --- a/crates/tinymist-query/src/fixtures/signature_help/snaps/test@builtin2.typ.snap +++ b/crates/tinymist-query/src/fixtures/signature_help/snaps/test@builtin2.typ.snap @@ -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, diff --git a/crates/tinymist-query/src/fixtures/signature_help/snaps/test@list_item.typ.snap b/crates/tinymist-query/src/fixtures/signature_help/snaps/test@list_item.typ.snap index c37fcf62..86ddf660 100644 --- a/crates/tinymist-query/src/fixtures/signature_help/snaps/test@list_item.typ.snap +++ b/crates/tinymist-query/src/fixtures/signature_help/snaps/test@list_item.typ.snap @@ -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, diff --git a/crates/tinymist-query/src/fixtures/signature_help/snaps/test@pos_callee.typ.snap b/crates/tinymist-query/src/fixtures/signature_help/snaps/test@pos_callee.typ.snap new file mode 100644 index 00000000..b633964c --- /dev/null +++ b/crates/tinymist-query/src/fixtures/signature_help/snaps/test@pos_callee.typ.snap @@ -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 diff --git a/crates/tinymist-query/src/fixtures/signature_help/snaps/test@pos_callee2.typ.snap b/crates/tinymist-query/src/fixtures/signature_help/snaps/test@pos_callee2.typ.snap new file mode 100644 index 00000000..15580c75 --- /dev/null +++ b/crates/tinymist-query/src/fixtures/signature_help/snaps/test@pos_callee2.typ.snap @@ -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:" + } + ] + } + ] +} diff --git a/crates/tinymist-query/src/fixtures/signature_help/snaps/test@pos_chain_call.typ.snap b/crates/tinymist-query/src/fixtures/signature_help/snaps/test@pos_chain_call.typ.snap new file mode 100644 index 00000000..04dd2818 --- /dev/null +++ b/crates/tinymist-query/src/fixtures/signature_help/snaps/test@pos_chain_call.typ.snap @@ -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 diff --git a/crates/tinymist-query/src/fixtures/signature_help/snaps/test@pos_chain_call2.typ.snap b/crates/tinymist-query/src/fixtures/signature_help/snaps/test@pos_chain_call2.typ.snap new file mode 100644 index 00000000..4c82e1c0 --- /dev/null +++ b/crates/tinymist-query/src/fixtures/signature_help/snaps/test@pos_chain_call2.typ.snap @@ -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 diff --git a/crates/tinymist-query/src/fixtures/signature_help/snaps/test@pos_string.typ.snap b/crates/tinymist-query/src/fixtures/signature_help/snaps/test@pos_string.typ.snap new file mode 100644 index 00000000..87aeabf8 --- /dev/null +++ b/crates/tinymist-query/src/fixtures/signature_help/snaps/test@pos_string.typ.snap @@ -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 diff --git a/crates/tinymist-query/src/fixtures/signature_help/snaps/test@where.typ.snap b/crates/tinymist-query/src/fixtures/signature_help/snaps/test@where.typ.snap index 9921286d..9948bcaf 100644 --- a/crates/tinymist-query/src/fixtures/signature_help/snaps/test@where.typ.snap +++ b/crates/tinymist-query/src/fixtures/signature_help/snaps/test@where.typ.snap @@ -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, diff --git a/crates/tinymist-query/src/fixtures/signature_help/where.typ b/crates/tinymist-query/src/fixtures/signature_help/where.typ index bdca8049..ea2629fc 100644 --- a/crates/tinymist-query/src/fixtures/signature_help/where.typ +++ b/crates/tinymist-query/src/fixtures/signature_help/where.typ @@ -1 +1 @@ -#show math.underline.where(/* position */): it => it \ No newline at end of file +#show math.underline.where(/* loc 0, 0 */): it => it \ No newline at end of file diff --git a/crates/tinymist-query/src/signature_help.rs b/crates/tinymist-query/src/signature_help.rs index 4d39a019..ebed07c6 100644 --- a/crates/tinymist-query/src/signature_help.rs +++ b/crates/tinymist-query/src/signature_help.rs @@ -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)); + }) }); } } diff --git a/crates/tinymist-query/src/tests.rs b/crates/tinymist-query/src/tests.rs index 1f9af72d..c2eb64c1 100644 --- a/crates/tinymist-query/src/tests.rs +++ b/crates/tinymist-query/src/tests.rs @@ -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 { + 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::().expect("bad loc marker"); + let column = column.trim().parse::().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::().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; diff --git a/tests/e2e/main.rs b/tests/e2e/main.rs index bf432c9e..acdac726 100644 --- a/tests/e2e/main.rs +++ b/tests/e2e/main.rs @@ -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"); } }