From 1737d580fae637bb676359f5e10b0a5f1342b669 Mon Sep 17 00:00:00 2001 From: Kitson Kelly Date: Thu, 1 Apr 2021 17:31:47 +1100 Subject: [PATCH] fix(lsp): ensure insert_text is passed back on completions --- cli/dts/config.d.ts | 50 +++++++++++++++ cli/lsp/language_server.rs | 62 +++++++++++++++++++ cli/lsp/tsc.rs | 5 +- .../lsp/completion_request_optional.json | 18 ++++++ .../completion_resolve_request_optional.json | 20 ++++++ ...open_notification_completion_optional.json | 12 ++++ 6 files changed, 165 insertions(+), 2 deletions(-) create mode 100644 cli/dts/config.d.ts create mode 100644 cli/tests/lsp/completion_request_optional.json create mode 100644 cli/tests/lsp/completion_resolve_request_optional.json create mode 100644 cli/tests/lsp/did_open_notification_completion_optional.json diff --git a/cli/dts/config.d.ts b/cli/dts/config.d.ts new file mode 100644 index 00000000000000..ab850e9656dc42 --- /dev/null +++ b/cli/dts/config.d.ts @@ -0,0 +1,50 @@ +interface DenoCompilerOptions { + // +} + +interface DenoPermissions { + /** Allow all permissions. */ + all?: boolean; + /** Allow environment access. */ + env?: boolean; + /** Allow high resolution time measurement. */ + hrtime?: boolean; + /** Allow network access. If an array of strings, only those hosts specified + * will be allowed access to + */ + net?: boolean | string[]; + plugin?: boolean; + read?: boolean | string[]; + write?: boolean | string[]; +} + +interface DenoSettings { + cachedOnly?: boolean; + cert?: string; + noCheck?: boolean; + noRemote?: boolean; + location?: string; + lock?: string; + logLevel?: "debug" | "info"; + quiet?: boolean; + tsconfig?: string; + unstable?: boolean; + v8Flags?: string[]; + watch?: boolean; +} + +interface DenoInspector { + host?: string; + port?: number; + breakOnStart?: boolean; +} + +interface DenoConfiguration { + allow?: DenoPermissions; + compilerOptions?: DenoCompilerOptions; + imports?: Record; + inspector?: boolean | DenoInspector; + root?: string; + scopes?: Record>; + settings?: DenoSettings; +} diff --git a/cli/lsp/language_server.rs b/cli/lsp/language_server.rs index 74dcf213622b9b..b55c38189a946f 100644 --- a/cli/lsp/language_server.rs +++ b/cli/lsp/language_server.rs @@ -3025,6 +3025,68 @@ mod tests { harness.run().await; } + #[tokio::test] + async fn test_completions_optional() { + let mut harness = LspTestHarness::new(vec![ + ("initialize_request.json", LspResponse::RequestAny), + ("initialized_notification.json", LspResponse::None), + ( + "did_open_notification_completion_optional.json", + LspResponse::None, + ), + ( + "completion_request_optional.json", + LspResponse::Request( + 2, + json!({ + "isIncomplete": false, + "items": [ + { + "label": "b?", + "kind": 5, + "sortText": "1", + "filterText": "b", + "insertText": "b", + "data": { + "tsc": { + "specifier": "file:///a/file.ts", + "position": 79, + "name": "b", + "useCodeSnippet": false + } + } + } + ] + }), + ), + ), + ( + "completion_resolve_request_optional.json", + LspResponse::Request( + 4, + json!({ + "label": "b?", + "kind": 5, + "detail": "(property) A.b?: string | undefined", + "documentation": { + "kind": "markdown", + "value": "" + }, + "sortText": "1", + "filterText": "b", + "insertText": "b" + }), + ), + ), + ( + "shutdown_request.json", + LspResponse::Request(3, json!(null)), + ), + ("exit_notification.json", LspResponse::None), + ]); + harness.run().await; + } + #[derive(Deserialize)] struct PerformanceAverages { averages: Vec, diff --git a/cli/lsp/tsc.rs b/cli/lsp/tsc.rs index 1e7ae6f895e72b..7b7f791d082086 100644 --- a/cli/lsp/tsc.rs +++ b/cli/lsp/tsc.rs @@ -1188,10 +1188,10 @@ impl CompletionEntry { } let text_edit = - if let (Some(text_span), Some(new_text)) = (range, insert_text) { + if let (Some(text_span), Some(new_text)) = (range, &insert_text) { let range = text_span.to_range(line_index); let insert_replace_edit = lsp::InsertReplaceEdit { - new_text, + new_text: new_text.clone(), insert: range, replace: range, }; @@ -1216,6 +1216,7 @@ impl CompletionEntry { preselect, text_edit, filter_text, + insert_text, detail, tags, data: Some(json!({ diff --git a/cli/tests/lsp/completion_request_optional.json b/cli/tests/lsp/completion_request_optional.json new file mode 100644 index 00000000000000..5e86c33ff661d0 --- /dev/null +++ b/cli/tests/lsp/completion_request_optional.json @@ -0,0 +1,18 @@ +{ + "jsonrpc": "2.0", + "id": 2, + "method": "textDocument/completion", + "params": { + "textDocument": { + "uri": "file:///a/file.ts" + }, + "position": { + "line": 8, + "character": 4 + }, + "context": { + "triggerKind": 2, + "triggerCharacter": "." + } + } +} diff --git a/cli/tests/lsp/completion_resolve_request_optional.json b/cli/tests/lsp/completion_resolve_request_optional.json new file mode 100644 index 00000000000000..ffa60b919761f9 --- /dev/null +++ b/cli/tests/lsp/completion_resolve_request_optional.json @@ -0,0 +1,20 @@ +{ + "jsonrpc": "2.0", + "id": 4, + "method": "completionItem/resolve", + "params": { + "label": "b?", + "kind": 5, + "sortText": "1", + "filterText": "b", + "insertText": "b", + "data": { + "tsc": { + "specifier": "file:///a/file.ts", + "position": 79, + "name": "b", + "useCodeSnippet": false + } + } + } +} diff --git a/cli/tests/lsp/did_open_notification_completion_optional.json b/cli/tests/lsp/did_open_notification_completion_optional.json new file mode 100644 index 00000000000000..5e919c80ab9972 --- /dev/null +++ b/cli/tests/lsp/did_open_notification_completion_optional.json @@ -0,0 +1,12 @@ +{ + "jsonrpc": "2.0", + "method": "textDocument/didOpen", + "params": { + "textDocument": { + "uri": "file:///a/file.ts", + "languageId": "typescript", + "version": 1, + "text": "interface A {\n b?: string;\n}\n\nconst o: A = {};\n\nfunction c(s: string) {}\n\nc(o.)" + } + } +}