aboutsummaryrefslogtreecommitdiff
path: root/editors/code/src/client.ts
diff options
context:
space:
mode:
Diffstat (limited to 'editors/code/src/client.ts')
-rw-r--r--editors/code/src/client.ts98
1 files changed, 93 insertions, 5 deletions
diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts
index cffdcf11a..d64f9a3f9 100644
--- a/editors/code/src/client.ts
+++ b/editors/code/src/client.ts
@@ -31,24 +31,112 @@ 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 const groups = new Map<string, { index: number; items: vscode.CodeAction[] }>();
45 for (const item of values) {
46 if (lc.CodeAction.is(item)) {
47 const action = client.protocol2CodeConverter.asCodeAction(item);
48 const group = actionGroup(item);
49 if (isSnippetEdit(item) || group) {
50 action.command = {
51 command: "rust-analyzer.applySnippetWorkspaceEdit",
52 title: "",
53 arguments: [action.edit],
54 };
55 action.edit = undefined;
56 }
57
58 if (group) {
59 let entry = groups.get(group);
60 if (!entry) {
61 entry = { index: result.length, items: [] };
62 groups.set(group, entry);
63 result.push(action);
64 }
65 entry.items.push(action);
66 } else {
67 result.push(action);
68 }
69 } else {
70 const command = client.protocol2CodeConverter.asCommand(item);
71 result.push(command);
72 }
73 }
74 for (const [group, { index, items }] of groups) {
75 if (items.length === 1) {
76 result[index] = items[0];
77 } else {
78 const action = new vscode.CodeAction(group);
79 action.command = {
80 command: "rust-analyzer.applyActionGroup",
81 title: "",
82 arguments: [items.map((item) => {
83 return { label: item.title, edit: item.command!!.arguments!![0] };
84 })],
85 };
86 result[index] = action;
87 }
88 }
89 return result;
90 },
91 (_error) => undefined
92 );
34 } 93 }
94
35 } as any 95 } as any
36 }; 96 };
37 97
38 const res = new lc.LanguageClient( 98 const client = new lc.LanguageClient(
39 'rust-analyzer', 99 'rust-analyzer',
40 'Rust Analyzer Language Server', 100 'Rust Analyzer Language Server',
41 serverOptions, 101 serverOptions,
42 clientOptions, 102 clientOptions,
43 ); 103 );
44 104
45 // To turn on all proposed features use: res.registerProposedFeatures(); 105 // To turn on all proposed features use: client.registerProposedFeatures();
46 // Here we want to enable CallHierarchyFeature and SemanticTokensFeature 106 // Here we want to enable CallHierarchyFeature and SemanticTokensFeature
47 // since they are available on stable. 107 // since they are available on stable.
48 // Note that while these features are stable in vscode their LSP protocol 108 // Note that while these features are stable in vscode their LSP protocol
49 // implementations are still in the "proposed" category for 3.16. 109 // implementations are still in the "proposed" category for 3.16.
50 res.registerFeature(new CallHierarchyFeature(res)); 110 client.registerFeature(new CallHierarchyFeature(client));
51 res.registerFeature(new SemanticTokensFeature(res)); 111 client.registerFeature(new SemanticTokensFeature(client));
112 client.registerFeature(new ExperimentalFeatures());
113
114 return client;
115}
116
117class ExperimentalFeatures implements lc.StaticFeature {
118 fillClientCapabilities(capabilities: lc.ClientCapabilities): void {
119 const caps: any = capabilities.experimental ?? {};
120 caps.snippetTextEdit = true;
121 caps.codeActionGroup = true;
122 capabilities.experimental = caps;
123 }
124 initialize(_capabilities: lc.ServerCapabilities<any>, _documentSelector: lc.DocumentSelector | undefined): void {
125 }
126}
127
128function isSnippetEdit(action: lc.CodeAction): boolean {
129 const documentChanges = action.edit?.documentChanges ?? [];
130 for (const edit of documentChanges) {
131 if (lc.TextDocumentEdit.is(edit)) {
132 if (edit.edits.some((indel) => (indel as any).insertTextFormat === lc.InsertTextFormat.Snippet)) {
133 return true;
134 }
135 }
136 }
137 return false;
138}
52 139
53 return res; 140function actionGroup(action: lc.CodeAction): string | undefined {
141 return (action as any).group;
54} 142}