aboutsummaryrefslogtreecommitdiff
path: root/editors/code/src/commands
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-12-30 19:25:01 +0000
committerGitHub <[email protected]>2019-12-30 19:25:01 +0000
commit17dda0972a68dd88a766c223390317dc2cb3ea00 (patch)
tree67ef26be75ec5db5fd66761a67b65a09e42d363e /editors/code/src/commands
parent237abb85c40672e8cdafa423db6187c107369a09 (diff)
parent9ead314005afd835ca64b5db9117e1c495814e17 (diff)
Merge #2693
2693: Encapsulate inlay hints activation r=matklad a=matklad Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'editors/code/src/commands')
-rw-r--r--editors/code/src/commands/index.ts22
-rw-r--r--editors/code/src/commands/inlay_hints.ts115
-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/commands/watch_status.ts105
5 files changed, 79 insertions, 301 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/inlay_hints.ts b/editors/code/src/commands/inlay_hints.ts
deleted file mode 100644
index ac7dcce60..000000000
--- a/editors/code/src/commands/inlay_hints.ts
+++ /dev/null
@@ -1,115 +0,0 @@
1import * as vscode from 'vscode';
2import { Range, TextDocumentChangeEvent, TextEditor } from 'vscode';
3import { TextDocumentIdentifier } from 'vscode-languageclient';
4import { Server } from '../server';
5
6interface InlayHintsParams {
7 textDocument: TextDocumentIdentifier;
8}
9
10interface InlayHint {
11 range: Range;
12 kind: string;
13 label: string;
14}
15
16const typeHintDecorationType = vscode.window.createTextEditorDecorationType({
17 after: {
18 color: new vscode.ThemeColor('ralsp.inlayHint'),
19 },
20});
21
22export class HintsUpdater {
23 private displayHints = true;
24
25 public async toggleHintsDisplay(displayHints: boolean): Promise<void> {
26 if (this.displayHints !== displayHints) {
27 this.displayHints = displayHints;
28 return this.refreshVisibleEditorsHints(
29 displayHints ? undefined : [],
30 );
31 }
32 }
33
34 public async refreshHintsForVisibleEditors(
35 cause?: TextDocumentChangeEvent,
36 ): Promise<void> {
37 if (!this.displayHints) {
38 return;
39 }
40 if (
41 cause !== undefined &&
42 (cause.contentChanges.length === 0 ||
43 !this.isRustDocument(cause.document))
44 ) {
45 return;
46 }
47 return this.refreshVisibleEditorsHints();
48 }
49
50 private async refreshVisibleEditorsHints(
51 newDecorations?: vscode.DecorationOptions[],
52 ) {
53 const promises: Array<Promise<void>> = [];
54
55 for (const rustEditor of vscode.window.visibleTextEditors.filter(
56 editor => this.isRustDocument(editor.document),
57 )) {
58 if (newDecorations !== undefined) {
59 promises.push(
60 Promise.resolve(
61 rustEditor.setDecorations(
62 typeHintDecorationType,
63 newDecorations,
64 ),
65 ),
66 );
67 } else {
68 promises.push(this.updateDecorationsFromServer(rustEditor));
69 }
70 }
71
72 for (const promise of promises) {
73 await promise;
74 }
75 }
76
77 private isRustDocument(document: vscode.TextDocument): boolean {
78 return document && document.languageId === 'rust';
79 }
80
81 private async updateDecorationsFromServer(
82 editor: TextEditor,
83 ): Promise<void> {
84 const newHints = await this.queryHints(editor.document.uri.toString());
85 if (newHints !== null) {
86 const newDecorations = newHints.map(hint => ({
87 range: hint.range,
88 renderOptions: {
89 after: {
90 contentText: `: ${hint.label}`,
91 },
92 },
93 }));
94 return editor.setDecorations(
95 typeHintDecorationType,
96 newDecorations,
97 );
98 }
99 }
100
101 private async queryHints(documentUri: string): Promise<InlayHint[] | null> {
102 const request: InlayHintsParams = {
103 textDocument: { uri: documentUri },
104 };
105 const client = Server.client;
106 return client
107 .onReady()
108 .then(() =>
109 client.sendRequest<InlayHint[] | null>(
110 'rust-analyzer/inlayHints',
111 request,
112 ),
113 );
114 }
115}
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/watch_status.ts b/editors/code/src/commands/watch_status.ts
deleted file mode 100644
index 10787b510..000000000
--- a/editors/code/src/commands/watch_status.ts
+++ /dev/null
@@ -1,105 +0,0 @@
1import * as vscode from 'vscode';
2
3const spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
4
5export class StatusDisplay implements vscode.Disposable {
6 public packageName?: string;
7
8 private i = 0;
9 private statusBarItem: vscode.StatusBarItem;
10 private command: string;
11 private timer?: NodeJS.Timeout;
12
13 constructor(command: string) {
14 this.statusBarItem = vscode.window.createStatusBarItem(
15 vscode.StatusBarAlignment.Left,
16 10,
17 );
18 this.command = command;
19 this.statusBarItem.hide();
20 }
21
22 public show() {
23 this.packageName = undefined;
24
25 this.timer =
26 this.timer ||
27 setInterval(() => {
28 if (this.packageName) {
29 this.statusBarItem!.text = `cargo ${this.command} [${
30 this.packageName
31 }] ${this.frame()}`;
32 } else {
33 this.statusBarItem!.text = `cargo ${
34 this.command
35 } ${this.frame()}`;
36 }
37 }, 300);
38
39 this.statusBarItem.show();
40 }
41
42 public hide() {
43 if (this.timer) {
44 clearInterval(this.timer);
45 this.timer = undefined;
46 }
47
48 this.statusBarItem.hide();
49 }
50
51 public dispose() {
52 if (this.timer) {
53 clearInterval(this.timer);
54 this.timer = undefined;
55 }
56
57 this.statusBarItem.dispose();
58 }
59
60 public handleProgressNotification(params: ProgressParams) {
61 const { token, value } = params;
62 if (token !== 'rustAnalyzer/cargoWatcher') {
63 return;
64 }
65
66 switch (value.kind) {
67 case 'begin':
68 this.show();
69 break;
70
71 case 'report':
72 if (value.message) {
73 this.packageName = value.message;
74 }
75 break;
76
77 case 'end':
78 this.hide();
79 break;
80 }
81 }
82
83 private frame() {
84 return spinnerFrames[(this.i = ++this.i % spinnerFrames.length)];
85 }
86}
87
88// FIXME: Replace this once vscode-languageclient is updated to LSP 3.15
89interface ProgressParams {
90 token: string;
91 value: WorkDoneProgress;
92}
93
94enum WorkDoneProgressKind {
95 Begin = 'begin',
96 Report = 'report',
97 End = 'end',
98}
99
100interface WorkDoneProgress {
101 kind: WorkDoneProgressKind;
102 message?: string;
103 cancelable?: boolean;
104 percentage?: string;
105}