aboutsummaryrefslogtreecommitdiff
path: root/editors/code/src
diff options
context:
space:
mode:
Diffstat (limited to 'editors/code/src')
-rw-r--r--editors/code/src/client.ts23
-rw-r--r--editors/code/src/commands.ts32
-rw-r--r--editors/code/src/lsp_ext.ts12
-rw-r--r--editors/code/src/main.ts1
-rw-r--r--editors/code/src/snippets.ts23
5 files changed, 66 insertions, 25 deletions
diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts
index d032b45b7..63ab82dde 100644
--- a/editors/code/src/client.ts
+++ b/editors/code/src/client.ts
@@ -4,6 +4,7 @@ import * as ra from '../src/lsp_ext';
4import * as Is from 'vscode-languageclient/lib/common/utils/is'; 4import * as Is from 'vscode-languageclient/lib/common/utils/is';
5import { DocumentSemanticsTokensSignature, DocumentSemanticsTokensEditsSignature, DocumentRangeSemanticTokensSignature } from 'vscode-languageclient/lib/common/semanticTokens'; 5import { DocumentSemanticsTokensSignature, DocumentSemanticsTokensEditsSignature, DocumentRangeSemanticTokensSignature } from 'vscode-languageclient/lib/common/semanticTokens';
6import { assert } from './util'; 6import { assert } from './util';
7import { WorkspaceEdit } from 'vscode';
7 8
8function renderCommand(cmd: ra.CommandLink) { 9function renderCommand(cmd: ra.CommandLink) {
9 return `[${cmd.title}](command:${cmd.command}?${encodeURIComponent(JSON.stringify(cmd.arguments))} '${cmd.tooltip!}')`; 10 return `[${cmd.title}](command:${cmd.command}?${encodeURIComponent(JSON.stringify(cmd.arguments))} '${cmd.tooltip!}')`;
@@ -75,8 +76,8 @@ export function createClient(serverPath: string, cwd: string): lc.LanguageClient
75 return Promise.resolve(null); 76 return Promise.resolve(null);
76 }); 77 });
77 }, 78 },
78 // Using custom handling of CodeActions where each code action is resolved lazily 79 // Using custom handling of CodeActions to support action groups and snippet edits.
79 // That's why we are not waiting for any command or edits 80 // Note that this means we have to re-implement lazy edit resolving ourselves as well.
80 async provideCodeActions(document: vscode.TextDocument, range: vscode.Range, context: vscode.CodeActionContext, token: vscode.CancellationToken, _next: lc.ProvideCodeActionsSignature) { 81 async provideCodeActions(document: vscode.TextDocument, range: vscode.Range, context: vscode.CodeActionContext, token: vscode.CancellationToken, _next: lc.ProvideCodeActionsSignature) {
81 const params: lc.CodeActionParams = { 82 const params: lc.CodeActionParams = {
82 textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document), 83 textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document),
@@ -99,16 +100,15 @@ export function createClient(serverPath: string, cwd: string): lc.LanguageClient
99 const kind = client.protocol2CodeConverter.asCodeActionKind((item as any).kind); 100 const kind = client.protocol2CodeConverter.asCodeActionKind((item as any).kind);
100 const action = new vscode.CodeAction(item.title, kind); 101 const action = new vscode.CodeAction(item.title, kind);
101 const group = (item as any).group; 102 const group = (item as any).group;
102 const id = (item as any).id;
103 const resolveParams: ra.ResolveCodeActionParams = {
104 id: id,
105 codeActionParams: params
106 };
107 action.command = { 103 action.command = {
108 command: "rust-analyzer.resolveCodeAction", 104 command: "rust-analyzer.resolveCodeAction",
109 title: item.title, 105 title: item.title,
110 arguments: [resolveParams], 106 arguments: [item],
111 }; 107 };
108
109 // Set a dummy edit, so that VS Code doesn't try to resolve this.
110 action.edit = new WorkspaceEdit();
111
112 if (group) { 112 if (group) {
113 let entry = groups.get(group); 113 let entry = groups.get(group);
114 if (!entry) { 114 if (!entry) {
@@ -134,6 +134,10 @@ export function createClient(serverPath: string, cwd: string): lc.LanguageClient
134 return { label: item.title, arguments: item.command!!.arguments!![0] }; 134 return { label: item.title, arguments: item.command!!.arguments!![0] };
135 })], 135 })],
136 }; 136 };
137
138 // Set a dummy edit, so that VS Code doesn't try to resolve this.
139 action.edit = new WorkspaceEdit();
140
137 result[index] = action; 141 result[index] = action;
138 } 142 }
139 } 143 }
@@ -164,13 +168,14 @@ class ExperimentalFeatures implements lc.StaticFeature {
164 const caps: any = capabilities.experimental ?? {}; 168 const caps: any = capabilities.experimental ?? {};
165 caps.snippetTextEdit = true; 169 caps.snippetTextEdit = true;
166 caps.codeActionGroup = true; 170 caps.codeActionGroup = true;
167 caps.resolveCodeAction = true;
168 caps.hoverActions = true; 171 caps.hoverActions = true;
169 caps.statusNotification = true; 172 caps.statusNotification = true;
170 capabilities.experimental = caps; 173 capabilities.experimental = caps;
171 } 174 }
172 initialize(_capabilities: lc.ServerCapabilities<any>, _documentSelector: lc.DocumentSelector | undefined): void { 175 initialize(_capabilities: lc.ServerCapabilities<any>, _documentSelector: lc.DocumentSelector | undefined): void {
173 } 176 }
177 dispose(): void {
178 }
174} 179}
175 180
176function isCodeActionWithoutEditsAndCommands(value: any): boolean { 181function isCodeActionWithoutEditsAndCommands(value: any): boolean {
diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts
index 22509e874..92bc4d7f7 100644
--- a/editors/code/src/commands.ts
+++ b/editors/code/src/commands.ts
@@ -188,6 +188,27 @@ export function parentModule(ctx: Ctx): Cmd {
188 }; 188 };
189} 189}
190 190
191export function openCargoToml(ctx: Ctx): Cmd {
192 return async () => {
193 const editor = ctx.activeRustEditor;
194 const client = ctx.client;
195 if (!editor || !client) return;
196
197 const response = await client.sendRequest(ra.openCargoToml, {
198 textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document),
199 });
200 if (!response) return;
201
202 const uri = client.protocol2CodeConverter.asUri(response.uri);
203 const range = client.protocol2CodeConverter.asRange(response.range);
204
205 const doc = await vscode.workspace.openTextDocument(uri);
206 const e = await vscode.window.showTextDocument(doc);
207 e.selection = new vscode.Selection(range.start, range.start);
208 e.revealRange(range, vscode.TextEditorRevealType.InCenter);
209 };
210}
211
191export function ssr(ctx: Ctx): Cmd { 212export function ssr(ctx: Ctx): Cmd {
192 return async () => { 213 return async () => {
193 const editor = vscode.window.activeTextEditor; 214 const editor = vscode.window.activeTextEditor;
@@ -395,7 +416,7 @@ export function showReferences(ctx: Ctx): Cmd {
395} 416}
396 417
397export function applyActionGroup(_ctx: Ctx): Cmd { 418export function applyActionGroup(_ctx: Ctx): Cmd {
398 return async (actions: { label: string; arguments: ra.ResolveCodeActionParams }[]) => { 419 return async (actions: { label: string; arguments: lc.CodeAction }[]) => {
399 const selectedAction = await vscode.window.showQuickPick(actions); 420 const selectedAction = await vscode.window.showQuickPick(actions);
400 if (!selectedAction) return; 421 if (!selectedAction) return;
401 vscode.commands.executeCommand( 422 vscode.commands.executeCommand(
@@ -442,12 +463,13 @@ export function openDocs(ctx: Ctx): Cmd {
442 463
443export function resolveCodeAction(ctx: Ctx): Cmd { 464export function resolveCodeAction(ctx: Ctx): Cmd {
444 const client = ctx.client; 465 const client = ctx.client;
445 return async (params: ra.ResolveCodeActionParams) => { 466 return async (params: lc.CodeAction) => {
446 const item: lc.WorkspaceEdit = await client.sendRequest(ra.resolveCodeAction, params); 467 params.command = undefined;
447 if (!item) { 468 const item = await client.sendRequest(lc.CodeActionResolveRequest.type, params);
469 if (!item.edit) {
448 return; 470 return;
449 } 471 }
450 const edit = client.protocol2CodeConverter.asWorkspaceEdit(item); 472 const edit = client.protocol2CodeConverter.asWorkspaceEdit(item.edit);
451 await applySnippetWorkspaceEdit(edit); 473 await applySnippetWorkspaceEdit(edit);
452 }; 474 };
453} 475}
diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts
index fc8e120b3..5e877ce65 100644
--- a/editors/code/src/lsp_ext.ts
+++ b/editors/code/src/lsp_ext.ts
@@ -43,12 +43,6 @@ export const matchingBrace = new lc.RequestType<MatchingBraceParams, lc.Position
43 43
44export const parentModule = new lc.RequestType<lc.TextDocumentPositionParams, lc.LocationLink[], void>("experimental/parentModule"); 44export const parentModule = new lc.RequestType<lc.TextDocumentPositionParams, lc.LocationLink[], void>("experimental/parentModule");
45 45
46export interface ResolveCodeActionParams {
47 id: string;
48 codeActionParams: lc.CodeActionParams;
49}
50export const resolveCodeAction = new lc.RequestType<ResolveCodeActionParams, lc.WorkspaceEdit, unknown>('experimental/resolveCodeAction');
51
52export interface JoinLinesParams { 46export interface JoinLinesParams {
53 textDocument: lc.TextDocumentIdentifier; 47 textDocument: lc.TextDocumentIdentifier;
54 ranges: lc.Range[]; 48 ranges: lc.Range[];
@@ -120,3 +114,9 @@ export interface CommandLinkGroup {
120} 114}
121 115
122export const openDocs = new lc.RequestType<lc.TextDocumentPositionParams, string | void, void>('experimental/externalDocs'); 116export const openDocs = new lc.RequestType<lc.TextDocumentPositionParams, string | void, void>('experimental/externalDocs');
117
118export const openCargoToml = new lc.RequestType<OpenCargoTomlParams, lc.Location, void>("experimental/openCargoToml");
119
120export interface OpenCargoTomlParams {
121 textDocument: lc.TextDocumentIdentifier;
122}
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts
index 09543e348..2f3dde8ac 100644
--- a/editors/code/src/main.ts
+++ b/editors/code/src/main.ts
@@ -111,6 +111,7 @@ async function tryActivate(context: vscode.ExtensionContext) {
111 ctx.registerCommand('debug', commands.debug); 111 ctx.registerCommand('debug', commands.debug);
112 ctx.registerCommand('newDebugConfig', commands.newDebugConfig); 112 ctx.registerCommand('newDebugConfig', commands.newDebugConfig);
113 ctx.registerCommand('openDocs', commands.openDocs); 113 ctx.registerCommand('openDocs', commands.openDocs);
114 ctx.registerCommand('openCargoToml', commands.openCargoToml);
114 115
115 defaultOnEnter.dispose(); 116 defaultOnEnter.dispose();
116 ctx.registerCommand('onEnter', commands.onEnter); 117 ctx.registerCommand('onEnter', commands.onEnter);
diff --git a/editors/code/src/snippets.ts b/editors/code/src/snippets.ts
index 258b49982..fee736e7d 100644
--- a/editors/code/src/snippets.ts
+++ b/editors/code/src/snippets.ts
@@ -3,16 +3,29 @@ import * as vscode from 'vscode';
3import { assert } from './util'; 3import { assert } from './util';
4 4
5export async function applySnippetWorkspaceEdit(edit: vscode.WorkspaceEdit) { 5export async function applySnippetWorkspaceEdit(edit: vscode.WorkspaceEdit) {
6 assert(edit.entries().length === 1, `bad ws edit: ${JSON.stringify(edit)}`); 6 if (edit.entries().length === 1) {
7 const [uri, edits] = edit.entries()[0]; 7 const [uri, edits] = edit.entries()[0];
8 const editor = await editorFromUri(uri);
9 if (editor) await applySnippetTextEdits(editor, edits);
10 return;
11 }
12 for (const [uri, edits] of edit.entries()) {
13 const editor = await editorFromUri(uri);
14 if (editor) await editor.edit((builder) => {
15 for (const indel of edits) {
16 assert(!parseSnippet(indel.newText), `bad ws edit: snippet received with multiple edits: ${JSON.stringify(edit)}`);
17 builder.replace(indel.range, indel.newText);
18 }
19 });
20 }
21}
8 22
23async function editorFromUri(uri: vscode.Uri): Promise<vscode.TextEditor | undefined> {
9 if (vscode.window.activeTextEditor?.document.uri !== uri) { 24 if (vscode.window.activeTextEditor?.document.uri !== uri) {
10 // `vscode.window.visibleTextEditors` only contains editors whose contents are being displayed 25 // `vscode.window.visibleTextEditors` only contains editors whose contents are being displayed
11 await vscode.window.showTextDocument(uri, {}); 26 await vscode.window.showTextDocument(uri, {});
12 } 27 }
13 const editor = vscode.window.visibleTextEditors.find((it) => it.document.uri.toString() === uri.toString()); 28 return vscode.window.visibleTextEditors.find((it) => it.document.uri.toString() === uri.toString());
14 if (!editor) return;
15 await applySnippetTextEdits(editor, edits);
16} 29}
17 30
18export async function applySnippetTextEdits(editor: vscode.TextEditor, edits: vscode.TextEdit[]) { 31export async function applySnippetTextEdits(editor: vscode.TextEditor, edits: vscode.TextEdit[]) {