From cc7ae841e4db8c814f12fcd6cca263ca0e04f2d4 Mon Sep 17 00:00:00 2001 From: David Sherret Date: Thu, 9 May 2024 13:18:13 -0400 Subject: [PATCH] fix(lsp): completions for using decl identifiers (#23748) Closes #23688 --- cli/lsp/tsc.rs | 23 +++++++++++++++++++-- tests/integration/lsp_tests.rs | 37 ++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/cli/lsp/tsc.rs b/cli/lsp/tsc.rs index bed71f6d9226b7..ec1eb29fa7e889 100644 --- a/cli/lsp/tsc.rs +++ b/cli/lsp/tsc.rs @@ -1372,6 +1372,7 @@ pub enum OneOrMany { Many(Vec), } +/// Aligns with ts.ScriptElementKind #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] pub enum ScriptElementKind { #[serde(rename = "")] @@ -1400,6 +1401,10 @@ pub enum ScriptElementKind { VariableElement, #[serde(rename = "local var")] LocalVariableElement, + #[serde(rename = "using")] + VariableUsingElement, + #[serde(rename = "await using")] + VariableAwaitUsingElement, #[serde(rename = "function")] FunctionElement, #[serde(rename = "local function")] @@ -1412,6 +1417,8 @@ pub enum ScriptElementKind { MemberSetAccessorElement, #[serde(rename = "property")] MemberVariableElement, + #[serde(rename = "accessor")] + MemberAccessorVariableElement, #[serde(rename = "constructor")] ConstructorImplementationElement, #[serde(rename = "call")] @@ -1456,7 +1463,8 @@ impl Default for ScriptElementKind { } } -/// This mirrors the method `convertKind` in `completions.ts` in vscode +/// This mirrors the method `convertKind` in `completions.ts` in vscode (extensions/typescript-language-features) +/// https://github.com/microsoft/vscode/blob/bd2df940d74b51105aefb11304e028d2fb56a9dc/extensions/typescript-language-features/src/languageFeatures/completions.ts#L440 impl From for lsp::CompletionItemKind { fn from(kind: ScriptElementKind) -> Self { match kind { @@ -1502,7 +1510,18 @@ impl From for lsp::CompletionItemKind { ScriptElementKind::ScriptElement => lsp::CompletionItemKind::FILE, ScriptElementKind::Directory => lsp::CompletionItemKind::FOLDER, ScriptElementKind::String => lsp::CompletionItemKind::CONSTANT, - _ => lsp::CompletionItemKind::PROPERTY, + ScriptElementKind::LocalClassElement + | ScriptElementKind::ConstructorImplementationElement + | ScriptElementKind::TypeParameterElement + | ScriptElementKind::Label + | ScriptElementKind::JsxAttribute + | ScriptElementKind::Link + | ScriptElementKind::LinkName + | ScriptElementKind::LinkText + | ScriptElementKind::VariableUsingElement + | ScriptElementKind::VariableAwaitUsingElement + | ScriptElementKind::MemberAccessorVariableElement + | ScriptElementKind::Unknown => lsp::CompletionItemKind::PROPERTY, } } } diff --git a/tests/integration/lsp_tests.rs b/tests/integration/lsp_tests.rs index 997e89050f09e0..d254436233d823 100644 --- a/tests/integration/lsp_tests.rs +++ b/tests/integration/lsp_tests.rs @@ -7081,6 +7081,43 @@ fn lsp_npm_completions_auto_import_and_quick_fix_no_import_map() { client.shutdown(); } +#[test] +fn lsp_completions_using_decl() { + let context = TestContextBuilder::new().use_temp_cwd().build(); + let mut client = context.new_lsp_command().build(); + client.initialize_default(); + client.did_open(json!({ + "textDocument": { + "uri": "file:///a/file.ts", + "languageId": "typescript", + "version": 1, + "text": r#"function makeResource() { + return { + [Symbol.dispose]() { + }, + }; +} + +using resource = makeResource(); + +res"# + } + })); + + let list = client.get_completion_list( + "file:///a/file.ts", + (9, 3), + json!({ + "triggerKind": 2, + "triggerCharacter": "." + }), + ); + assert!(list.items.iter().any(|i| i.label == "resource")); + assert!(!list.is_incomplete); + + client.shutdown(); +} + #[test] fn lsp_npm_always_caches() { // npm specifiers should always be cached even when not specified