editor: Adjust scope for prefer label for snippet workaround (#32515)

Smit Barmase , Michael Sloan , and Michael Sloan created

Closes #32159

This PR refines the scope to match just the function name with **the
type argument** instead of the whole call expression.

Matching to whole call expression prevented methods from expanding
inside the function argument. For example, `const foo =
bar(someMethod(2)^);` instead of `const foo = bar(someMethod^)`;

Follow-up for https://github.com/zed-industries/zed/pull/30312,
https://github.com/zed-industries/zed/pull/30351. Mistakenly regressed
since https://github.com/zed-industries/zed/pull/31872 when we stopped
receiving `insert_range` for this particular case and fallback to
`replace_range`.

Release Notes:

- Fixed issue where code completion in TypeScript function arguments
sometimes omitted the dot separator, for example resulting in
`NumberparseInt` instead of `Number.parseInt(string)`.

---------

Co-authored-by: Michael Sloan <michael@zed.dev>
Co-authored-by: Michael Sloan <mgsloan@gmail.com>

Change summary

crates/editor/src/editor.rs                   | 7 ++++++-
crates/languages/src/tsx/config.toml          | 2 +-
crates/languages/src/tsx/overrides.scm        | 4 +++-
crates/languages/src/typescript/config.toml   | 2 +-
crates/languages/src/typescript/overrides.scm | 4 +++-
5 files changed, 14 insertions(+), 5 deletions(-)

Detailed changes

crates/editor/src/editor.rs 🔗

@@ -20074,8 +20074,13 @@ fn process_completion_for_edit(
     let buffer = buffer.read(cx);
     let buffer_snapshot = buffer.snapshot();
     let (snippet, new_text) = if completion.is_snippet() {
+        // Workaround for typescript language server issues so that methods don't expand within
+        // strings and functions with type expressions. The previous point is used because the query
+        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
         let mut snippet_source = completion.new_text.clone();
-        if let Some(scope) = buffer_snapshot.language_scope_at(cursor_position) {
+        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
+        previous_point.column = previous_point.column.saturating_sub(1);
+        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
             if scope.prefers_label_for_snippet_in_completion() {
                 if let Some(label) = completion.label() {
                     if matches!(

crates/languages/src/tsx/config.toml 🔗

@@ -38,5 +38,5 @@ completion_query_characters = ["-", "."]
 opt_into_language_servers = ["tailwindcss-language-server"]
 prefer_label_for_snippet = true
 
-[overrides.call_expression]
+[overrides.function_name_before_type_arguments]
 prefer_label_for_snippet = true

crates/languages/src/tsx/overrides.scm 🔗

@@ -14,4 +14,6 @@
   (jsx_expression)
 ] @default
 
-(_ value: (call_expression) @call_expression)
+(_ value: (call_expression
+  function: (identifier) @function_name_before_type_arguments
+  type_arguments: (type_arguments)))

crates/languages/src/typescript/config.toml 🔗

@@ -25,5 +25,5 @@ documentation = { start = "/**", end = "*/", prefix = "* ", tab_size = 1 }
 completion_query_characters = ["."]
 prefer_label_for_snippet = true
 
-[overrides.call_expression]
+[overrides.function_name_before_type_arguments]
 prefer_label_for_snippet = true

crates/languages/src/typescript/overrides.scm 🔗

@@ -1,4 +1,6 @@
 (comment) @comment.inclusive
 (string) @string
 
-(_ value: (call_expression) @call_expression)
+(_ value: (call_expression
+  function: (identifier) @function_name_before_type_arguments
+  type_arguments: (type_arguments)))