aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--editors/code/src/commands/index.ts22
-rw-r--r--editors/code/src/commands/line_buffer.ts16
-rw-r--r--editors/code/src/commands/runnables.ts122
-rw-r--r--editors/code/src/inlay_hints.ts (renamed from editors/code/src/commands/inlay_hints.ts)56
-rw-r--r--editors/code/src/main.ts68
-rw-r--r--editors/code/src/status_display.ts (renamed from editors/code/src/commands/watch_status.ts)10
6 files changed, 139 insertions, 155 deletions
diff --git a/editors/code/src/commands/index.ts b/editors/code/src/commands/index.ts
index 325ae3da8..89af4be90 100644
--- a/editors/code/src/commands/index.ts
+++ b/editors/code/src/commands/index.ts
@@ -1,3 +1,6 @@
1import * as vscode from 'vscode';
2import * as lc from 'vscode-languageclient';
3
1import { Ctx, Cmd } from '../ctx'; 4import { Ctx, Cmd } from '../ctx';
2 5
3import { analyzerStatus } from './analyzer_status'; 6import { analyzerStatus } from './analyzer_status';
@@ -7,8 +10,7 @@ import { onEnter } from './on_enter';
7import { parentModule } from './parent_module'; 10import { parentModule } from './parent_module';
8import { syntaxTree } from './syntax_tree'; 11import { syntaxTree } from './syntax_tree';
9import { expandMacro } from './expand_macro'; 12import { expandMacro } from './expand_macro';
10import * as inlayHints from './inlay_hints'; 13import { run, runSingle } from './runnables';
11import * as runnables from './runnables';
12 14
13function collectGarbage(ctx: Ctx): Cmd { 15function collectGarbage(ctx: Ctx): Cmd {
14 return async () => { 16 return async () => {
@@ -16,15 +18,27 @@ function collectGarbage(ctx: Ctx): Cmd {
16 }; 18 };
17} 19}
18 20
21function showReferences(ctx: Ctx): Cmd {
22 return (uri: string, position: lc.Position, locations: lc.Location[]) => {
23 vscode.commands.executeCommand(
24 'editor.action.showReferences',
25 vscode.Uri.parse(uri),
26 ctx.client.protocol2CodeConverter.asPosition(position),
27 locations.map(ctx.client.protocol2CodeConverter.asLocation),
28 );
29 };
30}
31
19export { 32export {
20 analyzerStatus, 33 analyzerStatus,
21 expandMacro, 34 expandMacro,
22 joinLines, 35 joinLines,
23 matchingBrace, 36 matchingBrace,
24 parentModule, 37 parentModule,
25 runnables,
26 syntaxTree, 38 syntaxTree,
27 onEnter, 39 onEnter,
28 inlayHints,
29 collectGarbage, 40 collectGarbage,
41 run,
42 runSingle,
43 showReferences,
30}; 44};
diff --git a/editors/code/src/commands/line_buffer.ts b/editors/code/src/commands/line_buffer.ts
deleted file mode 100644
index fb5b9f7f2..000000000
--- a/editors/code/src/commands/line_buffer.ts
+++ /dev/null
@@ -1,16 +0,0 @@
1export class LineBuffer {
2 private outBuffer: string = '';
3
4 public processOutput(chunk: string, cb: (line: string) => void) {
5 this.outBuffer += chunk;
6 let eolIndex = this.outBuffer.indexOf('\n');
7 while (eolIndex >= 0) {
8 // line includes the EOL
9 const line = this.outBuffer.slice(0, eolIndex + 1);
10 cb(line);
11 this.outBuffer = this.outBuffer.slice(eolIndex + 1);
12
13 eolIndex = this.outBuffer.indexOf('\n');
14 }
15 }
16}
diff --git a/editors/code/src/commands/runnables.ts b/editors/code/src/commands/runnables.ts
index 7728541de..8cd86c21e 100644
--- a/editors/code/src/commands/runnables.ts
+++ b/editors/code/src/commands/runnables.ts
@@ -1,7 +1,67 @@
1import * as vscode from 'vscode'; 1import * as vscode from 'vscode';
2import * as lc from 'vscode-languageclient'; 2import * as lc from 'vscode-languageclient';
3 3
4import { Server } from '../server'; 4import { Ctx, Cmd } from '../ctx';
5
6export function run(ctx: Ctx): Cmd {
7 let prevRunnable: RunnableQuickPick | undefined;
8
9 return async () => {
10 const editor = ctx.activeRustEditor;
11 if (!editor) return;
12
13 const textDocument: lc.TextDocumentIdentifier = {
14 uri: editor.document.uri.toString(),
15 };
16 const params: RunnablesParams = {
17 textDocument,
18 position: ctx.client.code2ProtocolConverter.asPosition(
19 editor.selection.active,
20 ),
21 };
22 const runnables = await ctx.client.sendRequest<Runnable[]>(
23 'rust-analyzer/runnables',
24 params,
25 );
26 const items: RunnableQuickPick[] = [];
27 if (prevRunnable) {
28 items.push(prevRunnable);
29 }
30 for (const r of runnables) {
31 if (
32 prevRunnable &&
33 JSON.stringify(prevRunnable.runnable) === JSON.stringify(r)
34 ) {
35 continue;
36 }
37 items.push(new RunnableQuickPick(r));
38 }
39 const item = await vscode.window.showQuickPick(items);
40 if (!item) return;
41
42 item.detail = 'rerun';
43 prevRunnable = item;
44 const task = createTask(item.runnable);
45 return await vscode.tasks.executeTask(task);
46 };
47}
48
49export function runSingle(ctx: Ctx): Cmd {
50 return async (runnable: Runnable) => {
51 const editor = ctx.activeRustEditor;
52 if (!editor) return;
53
54 const task = createTask(runnable);
55 task.group = vscode.TaskGroup.Build;
56 task.presentationOptions = {
57 reveal: vscode.TaskRevealKind.Always,
58 panel: vscode.TaskPanelKind.Dedicated,
59 clear: true,
60 };
61
62 return vscode.tasks.executeTask(task);
63 };
64}
5 65
6interface RunnablesParams { 66interface RunnablesParams {
7 textDocument: lc.TextDocumentIdentifier; 67 textDocument: lc.TextDocumentIdentifier;
@@ -67,63 +127,3 @@ function createTask(spec: Runnable): vscode.Task {
67 t.presentationOptions.clear = true; 127 t.presentationOptions.clear = true;
68 return t; 128 return t;
69} 129}
70
71let prevRunnable: RunnableQuickPick | undefined;
72export async function handle(): Promise<vscode.TaskExecution | undefined> {
73 const editor = vscode.window.activeTextEditor;
74 if (editor == null || editor.document.languageId !== 'rust') {
75 return;
76 }
77 const textDocument: lc.TextDocumentIdentifier = {
78 uri: editor.document.uri.toString(),
79 };
80 const params: RunnablesParams = {
81 textDocument,
82 position: Server.client.code2ProtocolConverter.asPosition(
83 editor.selection.active,
84 ),
85 };
86 const runnables = await Server.client.sendRequest<Runnable[]>(
87 'rust-analyzer/runnables',
88 params,
89 );
90 const items: RunnableQuickPick[] = [];
91 if (prevRunnable) {
92 items.push(prevRunnable);
93 }
94 for (const r of runnables) {
95 if (
96 prevRunnable &&
97 JSON.stringify(prevRunnable.runnable) === JSON.stringify(r)
98 ) {
99 continue;
100 }
101 items.push(new RunnableQuickPick(r));
102 }
103 const item = await vscode.window.showQuickPick(items);
104 if (!item) {
105 return;
106 }
107
108 item.detail = 'rerun';
109 prevRunnable = item;
110 const task = createTask(item.runnable);
111 return await vscode.tasks.executeTask(task);
112}
113
114export async function handleSingle(runnable: Runnable) {
115 const editor = vscode.window.activeTextEditor;
116 if (editor == null || editor.document.languageId !== 'rust') {
117 return;
118 }
119
120 const task = createTask(runnable);
121 task.group = vscode.TaskGroup.Build;
122 task.presentationOptions = {
123 reveal: vscode.TaskRevealKind.Always,
124 panel: vscode.TaskPanelKind.Dedicated,
125 clear: true,
126 };
127
128 return vscode.tasks.executeTask(task);
129}
diff --git a/editors/code/src/commands/inlay_hints.ts b/editors/code/src/inlay_hints.ts
index ac7dcce60..4581e2278 100644
--- a/editors/code/src/commands/inlay_hints.ts
+++ b/editors/code/src/inlay_hints.ts
@@ -1,14 +1,49 @@
1import * as vscode from 'vscode'; 1import * as vscode from 'vscode';
2import { Range, TextDocumentChangeEvent, TextEditor } from 'vscode'; 2import * as lc from 'vscode-languageclient';
3import { TextDocumentIdentifier } from 'vscode-languageclient'; 3import { Server } from './server';
4import { Server } from '../server'; 4import { Ctx } from './ctx';
5
6export function activateInlayHints(ctx: Ctx) {
7 const hintsUpdater = new HintsUpdater();
8 hintsUpdater.refreshHintsForVisibleEditors().then(() => {
9 // vscode may ignore top level hintsUpdater.refreshHintsForVisibleEditors()
10 // so update the hints once when the focus changes to guarantee their presence
11 let editorChangeDisposable: vscode.Disposable | null = null;
12 editorChangeDisposable = vscode.window.onDidChangeActiveTextEditor(
13 _ => {
14 if (editorChangeDisposable !== null) {
15 editorChangeDisposable.dispose();
16 }
17 return hintsUpdater.refreshHintsForVisibleEditors();
18 },
19 );
20
21 ctx.pushCleanup(
22 vscode.window.onDidChangeVisibleTextEditors(_ =>
23 hintsUpdater.refreshHintsForVisibleEditors(),
24 ),
25 );
26 ctx.pushCleanup(
27 vscode.workspace.onDidChangeTextDocument(e =>
28 hintsUpdater.refreshHintsForVisibleEditors(e),
29 ),
30 );
31 ctx.pushCleanup(
32 vscode.workspace.onDidChangeConfiguration(_ =>
33 hintsUpdater.toggleHintsDisplay(
34 Server.config.displayInlayHints,
35 ),
36 ),
37 );
38 });
39}
5 40
6interface InlayHintsParams { 41interface InlayHintsParams {
7 textDocument: TextDocumentIdentifier; 42 textDocument: lc.TextDocumentIdentifier;
8} 43}
9 44
10interface InlayHint { 45interface InlayHint {
11 range: Range; 46 range: vscode.Range;
12 kind: string; 47 kind: string;
13 label: string; 48 label: string;
14} 49}
@@ -19,7 +54,7 @@ const typeHintDecorationType = vscode.window.createTextEditorDecorationType({
19 }, 54 },
20}); 55});
21 56
22export class HintsUpdater { 57class HintsUpdater {
23 private displayHints = true; 58 private displayHints = true;
24 59
25 public async toggleHintsDisplay(displayHints: boolean): Promise<void> { 60 public async toggleHintsDisplay(displayHints: boolean): Promise<void> {
@@ -32,11 +67,10 @@ export class HintsUpdater {
32 } 67 }
33 68
34 public async refreshHintsForVisibleEditors( 69 public async refreshHintsForVisibleEditors(
35 cause?: TextDocumentChangeEvent, 70 cause?: vscode.TextDocumentChangeEvent,
36 ): Promise<void> { 71 ): Promise<void> {
37 if (!this.displayHints) { 72 if (!this.displayHints) return;
38 return; 73
39 }
40 if ( 74 if (
41 cause !== undefined && 75 cause !== undefined &&
42 (cause.contentChanges.length === 0 || 76 (cause.contentChanges.length === 0 ||
@@ -79,7 +113,7 @@ export class HintsUpdater {
79 } 113 }
80 114
81 private async updateDecorationsFromServer( 115 private async updateDecorationsFromServer(
82 editor: TextEditor, 116 editor: vscode.TextEditor,
83 ): Promise<void> { 117 ): Promise<void> {
84 const newHints = await this.queryHints(editor.document.uri.toString()); 118 const newHints = await this.queryHints(editor.document.uri.toString());
85 if (newHints !== null) { 119 if (newHints !== null) {
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts
index b8e3396a6..7e63a9cac 100644
--- a/editors/code/src/main.ts
+++ b/editors/code/src/main.ts
@@ -2,8 +2,8 @@ import * as vscode from 'vscode';
2import * as lc from 'vscode-languageclient'; 2import * as lc from 'vscode-languageclient';
3 3
4import * as commands from './commands'; 4import * as commands from './commands';
5import { HintsUpdater } from './commands/inlay_hints'; 5import { activateInlayHints } from './inlay_hints';
6import { StatusDisplay } from './commands/watch_status'; 6import { StatusDisplay } from './status_display';
7import * as events from './events'; 7import * as events from './events';
8import * as notifications from './notifications'; 8import * as notifications from './notifications';
9import { Server } from './server'; 9import { Server } from './server';
@@ -13,6 +13,8 @@ let ctx!: Ctx;
13 13
14export async function activate(context: vscode.ExtensionContext) { 14export async function activate(context: vscode.ExtensionContext) {
15 ctx = new Ctx(context); 15 ctx = new Ctx(context);
16
17 // Commands which invokes manually via command pallet, shortcut, etc.
16 ctx.registerCommand('analyzerStatus', commands.analyzerStatus); 18 ctx.registerCommand('analyzerStatus', commands.analyzerStatus);
17 ctx.registerCommand('collectGarbage', commands.collectGarbage); 19 ctx.registerCommand('collectGarbage', commands.collectGarbage);
18 ctx.registerCommand('matchingBrace', commands.matchingBrace); 20 ctx.registerCommand('matchingBrace', commands.matchingBrace);
@@ -20,30 +22,11 @@ export async function activate(context: vscode.ExtensionContext) {
20 ctx.registerCommand('parentModule', commands.parentModule); 22 ctx.registerCommand('parentModule', commands.parentModule);
21 ctx.registerCommand('syntaxTree', commands.syntaxTree); 23 ctx.registerCommand('syntaxTree', commands.syntaxTree);
22 ctx.registerCommand('expandMacro', commands.expandMacro); 24 ctx.registerCommand('expandMacro', commands.expandMacro);
25 ctx.registerCommand('run', commands.run);
23 26
24 function disposeOnDeactivation(disposable: vscode.Disposable) { 27 // Internal commands which are invoked by the server.
25 context.subscriptions.push(disposable); 28 ctx.registerCommand('runSingle', commands.runSingle);
26 } 29 ctx.registerCommand('showReferences', commands.showReferences);
27
28 function registerCommand(name: string, f: any) {
29 disposeOnDeactivation(vscode.commands.registerCommand(name, f));
30 }
31
32 // Commands are requests from vscode to the language server
33 registerCommand('rust-analyzer.run', commands.runnables.handle);
34 // Unlike the above this does not send requests to the language server
35 registerCommand('rust-analyzer.runSingle', commands.runnables.handleSingle);
36 registerCommand(
37 'rust-analyzer.showReferences',
38 (uri: string, position: lc.Position, locations: lc.Location[]) => {
39 vscode.commands.executeCommand(
40 'editor.action.showReferences',
41 vscode.Uri.parse(uri),
42 Server.client.protocol2CodeConverter.asPosition(position),
43 locations.map(Server.client.protocol2CodeConverter.asLocation),
44 );
45 },
46 );
47 30
48 if (Server.config.enableEnhancedTyping) { 31 if (Server.config.enableEnhancedTyping) {
49 ctx.overrideCommand('type', commands.onEnter); 32 ctx.overrideCommand('type', commands.onEnter);
@@ -52,7 +35,7 @@ export async function activate(context: vscode.ExtensionContext) {
52 const watchStatus = new StatusDisplay( 35 const watchStatus = new StatusDisplay(
53 Server.config.cargoWatchOptions.command, 36 Server.config.cargoWatchOptions.command,
54 ); 37 );
55 disposeOnDeactivation(watchStatus); 38 ctx.pushCleanup(watchStatus);
56 39
57 // Notifications are events triggered by the language server 40 // Notifications are events triggered by the language server
58 const allNotifications: [string, lc.GenericNotificationHandler][] = [ 41 const allNotifications: [string, lc.GenericNotificationHandler][] = [
@@ -84,38 +67,7 @@ export async function activate(context: vscode.ExtensionContext) {
84 } 67 }
85 68
86 if (Server.config.displayInlayHints) { 69 if (Server.config.displayInlayHints) {
87 const hintsUpdater = new HintsUpdater(); 70 activateInlayHints(ctx);
88 hintsUpdater.refreshHintsForVisibleEditors().then(() => {
89 // vscode may ignore top level hintsUpdater.refreshHintsForVisibleEditors()
90 // so update the hints once when the focus changes to guarantee their presence
91 let editorChangeDisposable: vscode.Disposable | null = null;
92 editorChangeDisposable = vscode.window.onDidChangeActiveTextEditor(
93 _ => {
94 if (editorChangeDisposable !== null) {
95 editorChangeDisposable.dispose();
96 }
97 return hintsUpdater.refreshHintsForVisibleEditors();
98 },
99 );
100
101 disposeOnDeactivation(
102 vscode.window.onDidChangeVisibleTextEditors(_ =>
103 hintsUpdater.refreshHintsForVisibleEditors(),
104 ),
105 );
106 disposeOnDeactivation(
107 vscode.workspace.onDidChangeTextDocument(e =>
108 hintsUpdater.refreshHintsForVisibleEditors(e),
109 ),
110 );
111 disposeOnDeactivation(
112 vscode.workspace.onDidChangeConfiguration(_ =>
113 hintsUpdater.toggleHintsDisplay(
114 Server.config.displayInlayHints,
115 ),
116 ),
117 );
118 });
119 } 71 }
120} 72}
121 73
diff --git a/editors/code/src/commands/watch_status.ts b/editors/code/src/status_display.ts
index 10787b510..ed8573f02 100644
--- a/editors/code/src/commands/watch_status.ts
+++ b/editors/code/src/status_display.ts
@@ -3,7 +3,7 @@ import * as vscode from 'vscode';
3const spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']; 3const spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
4 4
5export class StatusDisplay implements vscode.Disposable { 5export class StatusDisplay implements vscode.Disposable {
6 public packageName?: string; 6 packageName?: string;
7 7
8 private i = 0; 8 private i = 0;
9 private statusBarItem: vscode.StatusBarItem; 9 private statusBarItem: vscode.StatusBarItem;
@@ -19,7 +19,7 @@ export class StatusDisplay implements vscode.Disposable {
19 this.statusBarItem.hide(); 19 this.statusBarItem.hide();
20 } 20 }
21 21
22 public show() { 22 show() {
23 this.packageName = undefined; 23 this.packageName = undefined;
24 24
25 this.timer = 25 this.timer =
@@ -39,7 +39,7 @@ export class StatusDisplay implements vscode.Disposable {
39 this.statusBarItem.show(); 39 this.statusBarItem.show();
40 } 40 }
41 41
42 public hide() { 42 hide() {
43 if (this.timer) { 43 if (this.timer) {
44 clearInterval(this.timer); 44 clearInterval(this.timer);
45 this.timer = undefined; 45 this.timer = undefined;
@@ -48,7 +48,7 @@ export class StatusDisplay implements vscode.Disposable {
48 this.statusBarItem.hide(); 48 this.statusBarItem.hide();
49 } 49 }
50 50
51 public dispose() { 51 dispose() {
52 if (this.timer) { 52 if (this.timer) {
53 clearInterval(this.timer); 53 clearInterval(this.timer);
54 this.timer = undefined; 54 this.timer = undefined;
@@ -57,7 +57,7 @@ export class StatusDisplay implements vscode.Disposable {
57 this.statusBarItem.dispose(); 57 this.statusBarItem.dispose();
58 } 58 }
59 59
60 public handleProgressNotification(params: ProgressParams) { 60 handleProgressNotification(params: ProgressParams) {
61 const { token, value } = params; 61 const { token, value } = params;
62 if (token !== 'rustAnalyzer/cargoWatcher') { 62 if (token !== 'rustAnalyzer/cargoWatcher') {
63 return; 63 return;