diff options
Diffstat (limited to 'editors/code/src/client.ts')
-rw-r--r-- | editors/code/src/client.ts | 65 |
1 files changed, 60 insertions, 5 deletions
diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index cffdcf11a..fac1a0be3 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts | |||
@@ -31,24 +31,79 @@ export function createClient(serverPath: string, cwd: string): lc.LanguageClient | |||
31 | const res = await next(document, token); | 31 | const res = await next(document, token); |
32 | if (res === undefined) throw new Error('busy'); | 32 | if (res === undefined) throw new Error('busy'); |
33 | return res; | 33 | return res; |
34 | }, | ||
35 | async provideCodeActions(document: vscode.TextDocument, range: vscode.Range, context: vscode.CodeActionContext, token: vscode.CancellationToken, _next: lc.ProvideCodeActionsSignature) { | ||
36 | const params: lc.CodeActionParams = { | ||
37 | textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document), | ||
38 | range: client.code2ProtocolConverter.asRange(range), | ||
39 | context: client.code2ProtocolConverter.asCodeActionContext(context) | ||
40 | }; | ||
41 | return client.sendRequest(lc.CodeActionRequest.type, params, token).then((values) => { | ||
42 | if (values === null) return undefined; | ||
43 | const result: (vscode.CodeAction | vscode.Command)[] = []; | ||
44 | for (const item of values) { | ||
45 | if (lc.CodeAction.is(item)) { | ||
46 | const action = client.protocol2CodeConverter.asCodeAction(item); | ||
47 | if (isSnippetEdit(item)) { | ||
48 | action.command = { | ||
49 | command: "rust-analyzer.applySnippetWorkspaceEdit", | ||
50 | title: "", | ||
51 | arguments: [action.edit], | ||
52 | }; | ||
53 | action.edit = undefined; | ||
54 | } | ||
55 | result.push(action); | ||
56 | } else { | ||
57 | const command = client.protocol2CodeConverter.asCommand(item); | ||
58 | result.push(command); | ||
59 | } | ||
60 | } | ||
61 | return result; | ||
62 | }, | ||
63 | (_error) => undefined | ||
64 | ); | ||
34 | } | 65 | } |
66 | |||
35 | } as any | 67 | } as any |
36 | }; | 68 | }; |
37 | 69 | ||
38 | const res = new lc.LanguageClient( | 70 | const client = new lc.LanguageClient( |
39 | 'rust-analyzer', | 71 | 'rust-analyzer', |
40 | 'Rust Analyzer Language Server', | 72 | 'Rust Analyzer Language Server', |
41 | serverOptions, | 73 | serverOptions, |
42 | clientOptions, | 74 | clientOptions, |
43 | ); | 75 | ); |
44 | 76 | ||
45 | // To turn on all proposed features use: res.registerProposedFeatures(); | 77 | // To turn on all proposed features use: client.registerProposedFeatures(); |
46 | // Here we want to enable CallHierarchyFeature and SemanticTokensFeature | 78 | // Here we want to enable CallHierarchyFeature and SemanticTokensFeature |
47 | // since they are available on stable. | 79 | // since they are available on stable. |
48 | // Note that while these features are stable in vscode their LSP protocol | 80 | // Note that while these features are stable in vscode their LSP protocol |
49 | // implementations are still in the "proposed" category for 3.16. | 81 | // implementations are still in the "proposed" category for 3.16. |
50 | res.registerFeature(new CallHierarchyFeature(res)); | 82 | client.registerFeature(new CallHierarchyFeature(client)); |
51 | res.registerFeature(new SemanticTokensFeature(res)); | 83 | client.registerFeature(new SemanticTokensFeature(client)); |
84 | client.registerFeature(new SnippetTextEditFeature()); | ||
85 | |||
86 | return client; | ||
87 | } | ||
52 | 88 | ||
53 | return res; | 89 | class SnippetTextEditFeature implements lc.StaticFeature { |
90 | fillClientCapabilities(capabilities: lc.ClientCapabilities): void { | ||
91 | const caps: any = capabilities.experimental ?? {}; | ||
92 | caps.snippetTextEdit = true; | ||
93 | capabilities.experimental = caps; | ||
94 | } | ||
95 | initialize(_capabilities: lc.ServerCapabilities<any>, _documentSelector: lc.DocumentSelector | undefined): void { | ||
96 | } | ||
97 | } | ||
98 | |||
99 | function isSnippetEdit(action: lc.CodeAction): boolean { | ||
100 | const documentChanges = action.edit?.documentChanges ?? []; | ||
101 | for (const edit of documentChanges) { | ||
102 | if (lc.TextDocumentEdit.is(edit)) { | ||
103 | if (edit.edits.some((indel) => (indel as any).insertTextFormat === lc.InsertTextFormat.Snippet)) { | ||
104 | return true; | ||
105 | } | ||
106 | } | ||
107 | } | ||
108 | return false; | ||
54 | } | 109 | } |