From 4e9460758ffd74ed988c0bb6586a01e7c6be4c8f Mon Sep 17 00:00:00 2001 From: Myriad-Dreamin <35292584+Myriad-Dreamin@users.noreply.github.com> Date: Wed, 5 Mar 2025 14:45:53 +0800 Subject: [PATCH] feat: adjust label and ref completion range (#1444) * feat: adjust label and ref completion range * docs: comment --- .../tinymist-query/src/analysis/completion.rs | 93 ++++++++++++++----- .../snaps/test@complete_half_label.typ.snap | 3 +- .../test@complete_half_label_cite.typ.snap | 3 +- .../snaps/test@complete_purely_label.typ.snap | 3 +- .../snaps/test@completion_title.typ.snap | 5 +- .../snaps/test@completion_title2.typ.snap | 5 +- .../snaps/test@label_middle.typ.snap | 7 +- .../completion/snaps/test@ref_half.typ.snap | 2 +- .../completion/snaps/test@ref_half2.typ.snap | 4 +- .../snaps/test@ref_half_colon.typ.snap | 2 +- 10 files changed, 86 insertions(+), 41 deletions(-) diff --git a/crates/tinymist-query/src/analysis/completion.rs b/crates/tinymist-query/src/analysis/completion.rs index cd5a02c3..1f41ec36 100644 --- a/crates/tinymist-query/src/analysis/completion.rs +++ b/crates/tinymist-query/src/analysis/completion.rs @@ -157,7 +157,7 @@ pub struct CompletionCursor<'a> { /// Cache for the last lsp range conversion. last_lsp_range_pair: Option<(Range, LspRange)>, /// Cache for the ident cursor. - ident_cursor: OnceLock>>, + ident_cursor: OnceLock>>, /// Cache for the arg cursor. arg_cursor: OnceLock>, } @@ -207,16 +207,37 @@ impl<'a> CompletionCursor<'a> { matches!(self.syntax, Some(SyntaxClass::Callee(..))) } - /// Gets Identifier under cursor. - fn ident_cursor(&self) -> &Option { + /// Gets selected node under cursor. + fn selected_node(&self) -> &Option> { self.ident_cursor.get_or_init(|| { + // identifier + // ^ from let is_from_ident = matches!( self.syntax, Some(SyntaxClass::Callee(..) | SyntaxClass::VarAccess(..)) ) && is_ident_like(&self.leaf) && self.leaf.offset() == self.from; + if is_from_ident { + return Some(SelectedNode::Ident(self.leaf.clone())); + } - is_from_ident.then(|| self.leaf.clone()) + // CompletionCursor<'a> { fn lsp_item_of(&mut self, item: &Completion) -> LspCompletion { // Determine range to replace let mut snippet = item.apply.as_ref().unwrap_or(&item.label).clone(); - let replace_range = if let Some(from_ident) = self.ident_cursor() { - let mut rng = from_ident.range(); + let replace_range = match self.selected_node() { + Some(SelectedNode::Ident(from_ident)) => { + let mut rng = from_ident.range(); - // if modifying some arguments, we need to truncate and add a comma - if !self.is_callee() && self.cursor != rng.end && is_arg_like_context(from_ident) { - // extend comma - if !snippet.trim_end().ends_with(',') { - snippet.push_str(", "); + // if modifying some arguments, we need to truncate and add a comma + if !self.is_callee() && self.cursor != rng.end && is_arg_like_context(from_ident) { + // extend comma + if !snippet.trim_end().ends_with(',') { + snippet.push_str(", "); + } + + // Truncate + rng.end = self.cursor; } - // Truncate - rng.end = self.cursor; + self.lsp_range_of(rng) } + Some(SelectedNode::Label(from_label)) => { + let mut rng = from_label.range(); + if from_label.text().starts_with('<') && !snippet.starts_with('<') { + rng.start += 1; + } + if from_label.text().ends_with('>') && !snippet.ends_with('>') { + rng.end -= 1; + } - self.lsp_range_of(rng) - } else { - self.lsp_range_of(self.from..self.cursor) + self.lsp_range_of(rng) + } + Some(SelectedNode::Ref(from_ref)) => { + let mut rng = from_ref.range(); + if from_ref.text().starts_with('@') && !snippet.starts_with('@') { + rng.start += 1; + } + + self.lsp_range_of(rng) + } + None => self.lsp_range_of(self.from..self.cursor), }; let text_edit = EcoTextEdit::new(replace_range, snippet); @@ -309,6 +350,16 @@ impl<'a> CompletionCursor<'a> { /// Alias for a completion cursor, [`CompletionCursor`]. type Cursor<'a> = CompletionCursor<'a>; +/// A node selected by [`CompletionCursor`]. +enum SelectedNode<'a> { + /// Selects an identifier, e.g. `foo|` or `fo|o`. + Ident(LinkedNode<'a>), + /// Selects a label, e.g. `` or ``. + Label(LinkedNode<'a>), + /// Selects a reference, e.g. `@foo|` or `@fo|o`. + Ref(LinkedNode<'a>), +} + /// Autocomplete a cursor position in a source file. /// /// Returns the position from which the completions apply and a list of @@ -390,7 +441,7 @@ impl<'a> CompletionWorker<'a> { /// Starts the completion process. pub(crate) fn work(&mut self, cursor: &mut Cursor) -> Option<()> { - // Skip if is the let binding item *directly* + // Skips if is the let binding item *directly* if let Some(SyntaxClass::VarAccess(var)) = &cursor.syntax { let node = var.node(); match node.parent_kind() { @@ -411,7 +462,7 @@ impl<'a> CompletionWorker<'a> { } } - // Skip if an error node starts with number (e.g. `1pt`) + // Skips if an error node starts with number (e.g. `1pt`) if matches!( cursor.syntax, Some(SyntaxClass::Callee(..) | SyntaxClass::VarAccess(..) | SyntaxClass::Normal(..)) @@ -429,7 +480,7 @@ impl<'a> CompletionWorker<'a> { } } - // Exclude it self from auto completion + // Excludes it self from auto completion // e.g. `#let x = (1.);` let self_ty = cursor.leaf.cast::().and_then(|leaf| { let v = self.ctx.mini_eval(leaf)?; @@ -446,8 +497,8 @@ impl<'a> CompletionWorker<'a> { }; let _ = pair.complete_cursor(); - // Filter - if let Some(from_ident) = cursor.ident_cursor() { + // Filters + if let Some(SelectedNode::Ident(from_ident)) = cursor.selected_node() { let ident_prefix = cursor.text[from_ident.offset()..cursor.cursor].to_string(); self.completions.retain(|item| { diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@complete_half_label.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@complete_half_label.typ.snap index 41eb3e29..7fd3216d 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@complete_half_label.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@complete_half_label.typ.snap @@ -3,7 +3,6 @@ source: crates/tinymist-query/src/completion.rs description: Completion on t (44..45) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/complete_half_label.typ -snapshot_kind: text --- [ { @@ -20,7 +19,7 @@ snapshot_kind: text "newText": "test>", "range": { "end": { - "character": 2, + "character": 3, "line": 3 }, "start": { diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@complete_half_label_cite.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@complete_half_label_cite.typ.snap index f8097d1f..40c75ea8 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@complete_half_label_cite.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@complete_half_label_cite.typ.snap @@ -3,7 +3,6 @@ source: crates/tinymist-query/src/completion.rs description: Completion on t (56..57) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/complete_half_label_cite.typ -snapshot_kind: text --- [ { @@ -20,7 +19,7 @@ snapshot_kind: text "newText": "tarry>", "range": { "end": { - "character": 7, + "character": 8, "line": 3 }, "start": { diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@complete_purely_label.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@complete_purely_label.typ.snap index 84990a05..99983374 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@complete_purely_label.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@complete_purely_label.typ.snap @@ -3,7 +3,6 @@ source: crates/tinymist-query/src/completion.rs description: Completion on t (103..104) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/complete_purely_label.typ -snapshot_kind: text --- [ { @@ -20,7 +19,7 @@ snapshot_kind: text "newText": "test>", "range": { "end": { - "character": 2, + "character": 4, "line": 11 }, "start": { diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@completion_title.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@completion_title.typ.snap index c526b0a7..717b94f7 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@completion_title.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@completion_title.typ.snap @@ -3,7 +3,6 @@ source: crates/tinymist-query/src/completion.rs description: Completion on @R (135..137) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/completion_title.typ -snapshot_kind: text --- [ { @@ -23,7 +22,7 @@ snapshot_kind: text "newText": "Russell:1908", "range": { "end": { - "character": 1, + "character": 2, "line": 5 }, "start": { @@ -43,7 +42,7 @@ snapshot_kind: text "newText": "Russell:1908", "range": { "end": { - "character": 1, + "character": 2, "line": 5 }, "start": { diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@completion_title2.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@completion_title2.typ.snap index 843da38e..1d019c47 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@completion_title2.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@completion_title2.typ.snap @@ -3,7 +3,6 @@ source: crates/tinymist-query/src/completion.rs description: Completion on 9 (109..110) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/completion_title2.typ -snapshot_kind: text --- [ { @@ -20,7 +19,7 @@ snapshot_kind: text "newText": "Russell:1908>", "range": { "end": { - "character": 16, + "character": 20, "line": 3 }, "start": { @@ -41,7 +40,7 @@ snapshot_kind: text "newText": "Russell:1908>", "range": { "end": { - "character": 16, + "character": 20, "line": 3 }, "start": { diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@label_middle.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@label_middle.typ.snap index d8e7c608..e8bb67e7 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@label_middle.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@label_middle.typ.snap @@ -3,7 +3,6 @@ source: crates/tinymist-query/src/completion.rs description: Completion on e (57..58) expression: "JsonRepr::new_pure(results)" input_file: crates/tinymist-query/src/fixtures/completion/label_middle.typ -snapshot_kind: text --- [ { @@ -20,7 +19,7 @@ snapshot_kind: text "newText": "abcd>", "range": { "end": { - "character": 4, + "character": 5, "line": 3 }, "start": { @@ -41,7 +40,7 @@ snapshot_kind: text "newText": "abef>", "range": { "end": { - "character": 4, + "character": 5, "line": 3 }, "start": { @@ -62,7 +61,7 @@ snapshot_kind: text "newText": "efg>", "range": { "end": { - "character": 4, + "character": 5, "line": 3 }, "start": { diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@ref_half.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@ref_half.typ.snap index 23cb768e..fe0a209a 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@ref_half.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@ref_half.typ.snap @@ -18,7 +18,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/ref_half.typ "newText": "test", "range": { "end": { - "character": 1, + "character": 2, "line": 11 }, "start": { diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@ref_half2.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@ref_half2.typ.snap index 3377c7ac..f2293c20 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@ref_half2.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@ref_half2.typ.snap @@ -18,7 +18,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/ref_half2.typ "newText": "test", "range": { "end": { - "character": 1, + "character": 3, "line": 11 }, "start": { @@ -43,7 +43,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/ref_half2.typ "newText": "test", "range": { "end": { - "character": 2, + "character": 3, "line": 11 }, "start": { diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@ref_half_colon.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@ref_half_colon.typ.snap index b837b017..7c52124b 100644 --- a/crates/tinymist-query/src/fixtures/completion/snaps/test@ref_half_colon.typ.snap +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@ref_half_colon.typ.snap @@ -18,7 +18,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/ref_half_colon.typ "newText": "sec:it", "range": { "end": { - "character": 5, + "character": 6, "line": 13 }, "start": {