aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--editors/code/src/commands/analyzer_status.ts51
-rw-r--r--editors/code/src/commands/expand_macro.ts66
-rw-r--r--editors/code/src/commands/index.ts257
-rw-r--r--editors/code/src/commands/join_lines.ts22
-rw-r--r--editors/code/src/commands/matching_brace.ts27
-rw-r--r--editors/code/src/commands/on_enter.ts35
-rw-r--r--editors/code/src/commands/parent_module.ts29
-rw-r--r--editors/code/src/commands/server_version.ts15
-rw-r--r--editors/code/src/commands/ssr.ts30
-rw-r--r--editors/code/src/commands/toggle_inlay_hints.ts11
10 files changed, 242 insertions, 301 deletions
diff --git a/editors/code/src/commands/analyzer_status.ts b/editors/code/src/commands/analyzer_status.ts
deleted file mode 100644
index 09daa3402..000000000
--- a/editors/code/src/commands/analyzer_status.ts
+++ /dev/null
@@ -1,51 +0,0 @@
1import * as vscode from 'vscode';
2
3import * as ra from '../rust-analyzer-api';
4import { Ctx, Cmd } from '../ctx';
5
6// Shows status of rust-analyzer (for debugging)
7export function analyzerStatus(ctx: Ctx): Cmd {
8 let poller: NodeJS.Timer | undefined = undefined;
9 const tdcp = new TextDocumentContentProvider(ctx);
10
11 ctx.pushCleanup(
12 vscode.workspace.registerTextDocumentContentProvider(
13 'rust-analyzer-status',
14 tdcp,
15 ),
16 );
17
18 ctx.pushCleanup({
19 dispose() {
20 if (poller !== undefined) {
21 clearInterval(poller);
22 }
23 },
24 });
25
26 return async () => {
27 if (poller === undefined) {
28 poller = setInterval(() => tdcp.eventEmitter.fire(tdcp.uri), 1000);
29 }
30 const document = await vscode.workspace.openTextDocument(tdcp.uri);
31 return vscode.window.showTextDocument(document, vscode.ViewColumn.Two, true);
32 };
33}
34
35class TextDocumentContentProvider implements vscode.TextDocumentContentProvider {
36 readonly uri = vscode.Uri.parse('rust-analyzer-status://status');
37 readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
38
39 constructor(private readonly ctx: Ctx) {
40 }
41
42 provideTextDocumentContent(_uri: vscode.Uri): vscode.ProviderResult<string> {
43 if (!vscode.window.activeTextEditor) return '';
44
45 return this.ctx.client.sendRequest(ra.analyzerStatus, null);
46 }
47
48 get onDidChange(): vscode.Event<vscode.Uri> {
49 return this.eventEmitter.event;
50 }
51}
diff --git a/editors/code/src/commands/expand_macro.ts b/editors/code/src/commands/expand_macro.ts
deleted file mode 100644
index 23f2ef1d5..000000000
--- a/editors/code/src/commands/expand_macro.ts
+++ /dev/null
@@ -1,66 +0,0 @@
1import * as vscode from 'vscode';
2import * as ra from '../rust-analyzer-api';
3
4import { Ctx, Cmd } from '../ctx';
5
6// Opens the virtual file that will show the syntax tree
7//
8// The contents of the file come from the `TextDocumentContentProvider`
9export function expandMacro(ctx: Ctx): Cmd {
10 const tdcp = new TextDocumentContentProvider(ctx);
11 ctx.pushCleanup(
12 vscode.workspace.registerTextDocumentContentProvider(
13 'rust-analyzer',
14 tdcp,
15 ),
16 );
17
18 return async () => {
19 const document = await vscode.workspace.openTextDocument(tdcp.uri);
20 tdcp.eventEmitter.fire(tdcp.uri);
21 return vscode.window.showTextDocument(
22 document,
23 vscode.ViewColumn.Two,
24 true,
25 );
26 };
27}
28
29function codeFormat(expanded: ra.ExpandedMacro): string {
30 let result = `// Recursive expansion of ${expanded.name}! macro\n`;
31 result += '// ' + '='.repeat(result.length - 3);
32 result += '\n\n';
33 result += expanded.expansion;
34
35 return result;
36}
37
38class TextDocumentContentProvider
39 implements vscode.TextDocumentContentProvider {
40 uri = vscode.Uri.parse('rust-analyzer://expandMacro/[EXPANSION].rs');
41 eventEmitter = new vscode.EventEmitter<vscode.Uri>();
42
43 constructor(private readonly ctx: Ctx) {
44 }
45
46 async provideTextDocumentContent(_uri: vscode.Uri): Promise<string> {
47 const editor = vscode.window.activeTextEditor;
48 const client = this.ctx.client;
49 if (!editor || !client) return '';
50
51 const position = editor.selection.active;
52
53 const expanded = await client.sendRequest(ra.expandMacro, {
54 textDocument: { uri: editor.document.uri.toString() },
55 position,
56 });
57
58 if (expanded == null) return 'Not available';
59
60 return codeFormat(expanded);
61 }
62
63 get onDidChange(): vscode.Event<vscode.Uri> {
64 return this.eventEmitter.event;
65 }
66}
diff --git a/editors/code/src/commands/index.ts b/editors/code/src/commands/index.ts
index 1ed8258d8..1585912a2 100644
--- a/editors/code/src/commands/index.ts
+++ b/editors/code/src/commands/index.ts
@@ -4,18 +4,251 @@ import * as ra from '../rust-analyzer-api';
4 4
5import { Ctx, Cmd } from '../ctx'; 5import { Ctx, Cmd } from '../ctx';
6import { applySnippetWorkspaceEdit } from '../snippets'; 6import { applySnippetWorkspaceEdit } from '../snippets';
7import { spawnSync } from 'child_process';
7 8
8export * from './analyzer_status';
9export * from './matching_brace';
10export * from './join_lines';
11export * from './on_enter';
12export * from './parent_module';
13export * from './syntax_tree'; 9export * from './syntax_tree';
14export * from './expand_macro';
15export * from './runnables'; 10export * from './runnables';
16export * from './ssr'; 11
17export * from './server_version'; 12export function analyzerStatus(ctx: Ctx): Cmd {
18export * from './toggle_inlay_hints'; 13 const tdcp = new class implements vscode.TextDocumentContentProvider {
14 readonly uri = vscode.Uri.parse('rust-analyzer-status://status');
15 readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
16
17 provideTextDocumentContent(_uri: vscode.Uri): vscode.ProviderResult<string> {
18 if (!vscode.window.activeTextEditor) return '';
19
20 return ctx.client.sendRequest(ra.analyzerStatus, null);
21 }
22
23 get onDidChange(): vscode.Event<vscode.Uri> {
24 return this.eventEmitter.event;
25 }
26 }();
27
28 let poller: NodeJS.Timer | undefined = undefined;
29
30 ctx.pushCleanup(
31 vscode.workspace.registerTextDocumentContentProvider(
32 'rust-analyzer-status',
33 tdcp,
34 ),
35 );
36
37 ctx.pushCleanup({
38 dispose() {
39 if (poller !== undefined) {
40 clearInterval(poller);
41 }
42 },
43 });
44
45 return async () => {
46 if (poller === undefined) {
47 poller = setInterval(() => tdcp.eventEmitter.fire(tdcp.uri), 1000);
48 }
49 const document = await vscode.workspace.openTextDocument(tdcp.uri);
50 return vscode.window.showTextDocument(document, vscode.ViewColumn.Two, true);
51 };
52}
53
54export function matchingBrace(ctx: Ctx): Cmd {
55 return async () => {
56 const editor = ctx.activeRustEditor;
57 const client = ctx.client;
58 if (!editor || !client) return;
59
60 const response = await client.sendRequest(ra.matchingBrace, {
61 textDocument: { uri: editor.document.uri.toString() },
62 positions: editor.selections.map(s =>
63 client.code2ProtocolConverter.asPosition(s.active),
64 ),
65 });
66 editor.selections = editor.selections.map((sel, idx) => {
67 const active = client.protocol2CodeConverter.asPosition(
68 response[idx],
69 );
70 const anchor = sel.isEmpty ? active : sel.anchor;
71 return new vscode.Selection(anchor, active);
72 });
73 editor.revealRange(editor.selection);
74 };
75}
76
77export function joinLines(ctx: Ctx): Cmd {
78 return async () => {
79 const editor = ctx.activeRustEditor;
80 const client = ctx.client;
81 if (!editor || !client) return;
82
83 const items: lc.TextEdit[] = await client.sendRequest(ra.joinLines, {
84 ranges: editor.selections.map((it) => client.code2ProtocolConverter.asRange(it)),
85 textDocument: { uri: editor.document.uri.toString() },
86 });
87 editor.edit((builder) => {
88 client.protocol2CodeConverter.asTextEdits(items).forEach((edit) => {
89 builder.replace(edit.range, edit.newText);
90 });
91 });
92 };
93}
94
95export function onEnter(ctx: Ctx): Cmd {
96 async function handleKeypress() {
97 const editor = ctx.activeRustEditor;
98 const client = ctx.client;
99
100 if (!editor || !client) return false;
101
102 const change = await client.sendRequest(ra.onEnter, {
103 textDocument: { uri: editor.document.uri.toString() },
104 position: client.code2ProtocolConverter.asPosition(
105 editor.selection.active,
106 ),
107 }).catch(_error => {
108 // client.logFailedRequest(OnEnterRequest.type, error);
109 return null;
110 });
111 if (!change) return false;
112
113 const workspaceEdit = client.protocol2CodeConverter.asWorkspaceEdit(change);
114 await applySnippetWorkspaceEdit(workspaceEdit);
115 return true;
116 }
117
118 return async () => {
119 if (await handleKeypress()) return;
120
121 await vscode.commands.executeCommand('default:type', { text: '\n' });
122 };
123}
124
125export function parentModule(ctx: Ctx): Cmd {
126 return async () => {
127 const editor = ctx.activeRustEditor;
128 const client = ctx.client;
129 if (!editor || !client) return;
130
131 const response = await client.sendRequest(ra.parentModule, {
132 textDocument: { uri: editor.document.uri.toString() },
133 position: client.code2ProtocolConverter.asPosition(
134 editor.selection.active,
135 ),
136 });
137 const loc = response[0];
138 if (loc == null) return;
139
140 const uri = client.protocol2CodeConverter.asUri(loc.uri);
141 const range = client.protocol2CodeConverter.asRange(loc.range);
142
143 const doc = await vscode.workspace.openTextDocument(uri);
144 const e = await vscode.window.showTextDocument(doc);
145 e.selection = new vscode.Selection(range.start, range.start);
146 e.revealRange(range, vscode.TextEditorRevealType.InCenter);
147 };
148}
149
150export function ssr(ctx: Ctx): Cmd {
151 return async () => {
152 const client = ctx.client;
153 if (!client) return;
154
155 const options: vscode.InputBoxOptions = {
156 value: "() ==>> ()",
157 prompt: "Enter request, for example 'Foo($a:expr) ==> Foo::new($a)' ",
158 validateInput: async (x: string) => {
159 try {
160 await client.sendRequest(ra.ssr, { query: x, parseOnly: true });
161 } catch (e) {
162 return e.toString();
163 }
164 return null;
165 }
166 };
167 const request = await vscode.window.showInputBox(options);
168 if (!request) return;
169
170 const edit = await client.sendRequest(ra.ssr, { query: request, parseOnly: false });
171
172 await vscode.workspace.applyEdit(client.protocol2CodeConverter.asWorkspaceEdit(edit));
173 };
174}
175
176export function serverVersion(ctx: Ctx): Cmd {
177 return async () => {
178 const { stdout } = spawnSync(ctx.serverPath, ["--version"], { encoding: "utf8" });
179 const commitHash = stdout.slice(`rust-analyzer `.length).trim();
180 const { releaseTag } = ctx.config.package;
181
182 void vscode.window.showInformationMessage(
183 `rust-analyzer version: ${releaseTag ?? "unreleased"} (${commitHash})`
184 );
185 };
186}
187
188export function toggleInlayHints(ctx: Ctx): Cmd {
189 return async () => {
190 await vscode
191 .workspace
192 .getConfiguration(`${ctx.config.rootSection}.inlayHints`)
193 .update('enable', !ctx.config.inlayHints.enable, vscode.ConfigurationTarget.Workspace);
194 };
195}
196
197// Opens the virtual file that will show the syntax tree
198//
199// The contents of the file come from the `TextDocumentContentProvider`
200export function expandMacro(ctx: Ctx): Cmd {
201 function codeFormat(expanded: ra.ExpandedMacro): string {
202 let result = `// Recursive expansion of ${expanded.name}! macro\n`;
203 result += '// ' + '='.repeat(result.length - 3);
204 result += '\n\n';
205 result += expanded.expansion;
206
207 return result;
208 }
209
210 const tdcp = new class implements vscode.TextDocumentContentProvider {
211 uri = vscode.Uri.parse('rust-analyzer://expandMacro/[EXPANSION].rs');
212 eventEmitter = new vscode.EventEmitter<vscode.Uri>();
213 async provideTextDocumentContent(_uri: vscode.Uri): Promise<string> {
214 const editor = vscode.window.activeTextEditor;
215 const client = ctx.client;
216 if (!editor || !client) return '';
217
218 const position = editor.selection.active;
219
220 const expanded = await client.sendRequest(ra.expandMacro, {
221 textDocument: { uri: editor.document.uri.toString() },
222 position,
223 });
224
225 if (expanded == null) return 'Not available';
226
227 return codeFormat(expanded);
228 }
229
230 get onDidChange(): vscode.Event<vscode.Uri> {
231 return this.eventEmitter.event;
232 }
233 }();
234
235 ctx.pushCleanup(
236 vscode.workspace.registerTextDocumentContentProvider(
237 'rust-analyzer',
238 tdcp,
239 ),
240 );
241
242 return async () => {
243 const document = await vscode.workspace.openTextDocument(tdcp.uri);
244 tdcp.eventEmitter.fire(tdcp.uri);
245 return vscode.window.showTextDocument(
246 document,
247 vscode.ViewColumn.Two,
248 true,
249 );
250 };
251}
19 252
20export function collectGarbage(ctx: Ctx): Cmd { 253export function collectGarbage(ctx: Ctx): Cmd {
21 return async () => ctx.client.sendRequest(ra.collectGarbage, null); 254 return async () => ctx.client.sendRequest(ra.collectGarbage, null);
@@ -35,12 +268,6 @@ export function showReferences(ctx: Ctx): Cmd {
35 }; 268 };
36} 269}
37 270
38export function applySourceChange(ctx: Ctx): Cmd {
39 return async (change: ra.SourceChange) => {
40 await sourceChange.applySourceChange(ctx, change);
41 };
42}
43
44export function applyActionGroup(_ctx: Ctx): Cmd { 271export function applyActionGroup(_ctx: Ctx): Cmd {
45 return async (actions: { label: string; edit: vscode.WorkspaceEdit }[]) => { 272 return async (actions: { label: string; edit: vscode.WorkspaceEdit }[]) => {
46 const selectedAction = await vscode.window.showQuickPick(actions); 273 const selectedAction = await vscode.window.showQuickPick(actions);
diff --git a/editors/code/src/commands/join_lines.ts b/editors/code/src/commands/join_lines.ts
deleted file mode 100644
index 0bf1ee6e6..000000000
--- a/editors/code/src/commands/join_lines.ts
+++ /dev/null
@@ -1,22 +0,0 @@
1import * as ra from '../rust-analyzer-api';
2import * as lc from 'vscode-languageclient';
3
4import { Ctx, Cmd } from '../ctx';
5
6export function joinLines(ctx: Ctx): Cmd {
7 return async () => {
8 const editor = ctx.activeRustEditor;
9 const client = ctx.client;
10 if (!editor || !client) return;
11
12 const items: lc.TextEdit[] = await client.sendRequest(ra.joinLines, {
13 ranges: editor.selections.map((it) => client.code2ProtocolConverter.asRange(it)),
14 textDocument: { uri: editor.document.uri.toString() },
15 });
16 editor.edit((builder) => {
17 client.protocol2CodeConverter.asTextEdits(items).forEach((edit) => {
18 builder.replace(edit.range, edit.newText);
19 });
20 });
21 };
22}
diff --git a/editors/code/src/commands/matching_brace.ts b/editors/code/src/commands/matching_brace.ts
deleted file mode 100644
index 9c418b887..000000000
--- a/editors/code/src/commands/matching_brace.ts
+++ /dev/null
@@ -1,27 +0,0 @@
1import * as vscode from 'vscode';
2import * as ra from '../rust-analyzer-api';
3
4import { Ctx, Cmd } from '../ctx';
5
6export function matchingBrace(ctx: Ctx): Cmd {
7 return async () => {
8 const editor = ctx.activeRustEditor;
9 const client = ctx.client;
10 if (!editor || !client) return;
11
12 const response = await client.sendRequest(ra.matchingBrace, {
13 textDocument: { uri: editor.document.uri.toString() },
14 positions: editor.selections.map(s =>
15 client.code2ProtocolConverter.asPosition(s.active),
16 ),
17 });
18 editor.selections = editor.selections.map((sel, idx) => {
19 const active = client.protocol2CodeConverter.asPosition(
20 response[idx],
21 );
22 const anchor = sel.isEmpty ? active : sel.anchor;
23 return new vscode.Selection(anchor, active);
24 });
25 editor.revealRange(editor.selection);
26 };
27}
diff --git a/editors/code/src/commands/on_enter.ts b/editors/code/src/commands/on_enter.ts
deleted file mode 100644
index 0e4769633..000000000
--- a/editors/code/src/commands/on_enter.ts
+++ /dev/null
@@ -1,35 +0,0 @@
1import * as vscode from 'vscode';
2import * as ra from '../rust-analyzer-api';
3
4import { Cmd, Ctx } from '../ctx';
5import { applySnippetWorkspaceEdit } from '../snippets';
6
7async function handleKeypress(ctx: Ctx) {
8 const editor = ctx.activeRustEditor;
9 const client = ctx.client;
10
11 if (!editor || !client) return false;
12
13 const change = await client.sendRequest(ra.onEnter, {
14 textDocument: { uri: editor.document.uri.toString() },
15 position: client.code2ProtocolConverter.asPosition(
16 editor.selection.active,
17 ),
18 }).catch(_error => {
19 // client.logFailedRequest(OnEnterRequest.type, error);
20 return null;
21 });
22 if (!change) return false;
23
24 const workspaceEdit = client.protocol2CodeConverter.asWorkspaceEdit(change);
25 await applySnippetWorkspaceEdit(workspaceEdit);
26 return true;
27}
28
29export function onEnter(ctx: Ctx): Cmd {
30 return async () => {
31 if (await handleKeypress(ctx)) return;
32
33 await vscode.commands.executeCommand('default:type', { text: '\n' });
34 };
35}
diff --git a/editors/code/src/commands/parent_module.ts b/editors/code/src/commands/parent_module.ts
deleted file mode 100644
index 8f78ddd71..000000000
--- a/editors/code/src/commands/parent_module.ts
+++ /dev/null
@@ -1,29 +0,0 @@
1import * as vscode from 'vscode';
2import * as ra from '../rust-analyzer-api';
3
4import { Ctx, Cmd } from '../ctx';
5
6export function parentModule(ctx: Ctx): Cmd {
7 return async () => {
8 const editor = ctx.activeRustEditor;
9 const client = ctx.client;
10 if (!editor || !client) return;
11
12 const response = await client.sendRequest(ra.parentModule, {
13 textDocument: { uri: editor.document.uri.toString() },
14 position: client.code2ProtocolConverter.asPosition(
15 editor.selection.active,
16 ),
17 });
18 const loc = response[0];
19 if (loc == null) return;
20
21 const uri = client.protocol2CodeConverter.asUri(loc.uri);
22 const range = client.protocol2CodeConverter.asRange(loc.range);
23
24 const doc = await vscode.workspace.openTextDocument(uri);
25 const e = await vscode.window.showTextDocument(doc);
26 e.selection = new vscode.Selection(range.start, range.start);
27 e.revealRange(range, vscode.TextEditorRevealType.InCenter);
28 };
29}
diff --git a/editors/code/src/commands/server_version.ts b/editors/code/src/commands/server_version.ts
deleted file mode 100644
index d64ac726e..000000000
--- a/editors/code/src/commands/server_version.ts
+++ /dev/null
@@ -1,15 +0,0 @@
1import * as vscode from "vscode";
2import { spawnSync } from "child_process";
3import { Ctx, Cmd } from '../ctx';
4
5export function serverVersion(ctx: Ctx): Cmd {
6 return async () => {
7 const { stdout } = spawnSync(ctx.serverPath, ["--version"], { encoding: "utf8" });
8 const commitHash = stdout.slice(`rust-analyzer `.length).trim();
9 const { releaseTag } = ctx.config.package;
10
11 void vscode.window.showInformationMessage(
12 `rust-analyzer version: ${releaseTag ?? "unreleased"} (${commitHash})`
13 );
14 };
15}
diff --git a/editors/code/src/commands/ssr.ts b/editors/code/src/commands/ssr.ts
deleted file mode 100644
index 5d40a64d2..000000000
--- a/editors/code/src/commands/ssr.ts
+++ /dev/null
@@ -1,30 +0,0 @@
1import * as vscode from 'vscode';
2import * as ra from "../rust-analyzer-api";
3
4import { Ctx, Cmd } from '../ctx';
5
6export function ssr(ctx: Ctx): Cmd {
7 return async () => {
8 const client = ctx.client;
9 if (!client) return;
10
11 const options: vscode.InputBoxOptions = {
12 value: "() ==>> ()",
13 prompt: "Enter request, for example 'Foo($a:expr) ==> Foo::new($a)' ",
14 validateInput: async (x: string) => {
15 try {
16 await client.sendRequest(ra.ssr, { query: x, parseOnly: true });
17 } catch (e) {
18 return e.toString();
19 }
20 return null;
21 }
22 };
23 const request = await vscode.window.showInputBox(options);
24 if (!request) return;
25
26 const edit = await client.sendRequest(ra.ssr, { query: request, parseOnly: false });
27
28 await vscode.workspace.applyEdit(client.protocol2CodeConverter.asWorkspaceEdit(edit));
29 };
30}
diff --git a/editors/code/src/commands/toggle_inlay_hints.ts b/editors/code/src/commands/toggle_inlay_hints.ts
deleted file mode 100644
index 7606af8d0..000000000
--- a/editors/code/src/commands/toggle_inlay_hints.ts
+++ /dev/null
@@ -1,11 +0,0 @@
1import * as vscode from 'vscode';
2import { Ctx, Cmd } from '../ctx';
3
4export function toggleInlayHints(ctx: Ctx): Cmd {
5 return async () => {
6 await vscode
7 .workspace
8 .getConfiguration(`${ctx.config.rootSection}.inlayHints`)
9 .update('enable', !ctx.config.inlayHints.enable, vscode.ConfigurationTarget.Workspace);
10 };
11}