diff options
Diffstat (limited to 'editors/code/src/commands')
-rw-r--r-- | editors/code/src/commands/index.ts | 22 | ||||
-rw-r--r-- | editors/code/src/commands/inlay_hints.ts | 115 | ||||
-rw-r--r-- | editors/code/src/commands/line_buffer.ts | 16 | ||||
-rw-r--r-- | editors/code/src/commands/runnables.ts | 122 | ||||
-rw-r--r-- | editors/code/src/commands/watch_status.ts | 105 |
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 @@ | |||
1 | import * as vscode from 'vscode'; | ||
2 | import * as lc from 'vscode-languageclient'; | ||
3 | |||
1 | import { Ctx, Cmd } from '../ctx'; | 4 | import { Ctx, Cmd } from '../ctx'; |
2 | 5 | ||
3 | import { analyzerStatus } from './analyzer_status'; | 6 | import { analyzerStatus } from './analyzer_status'; |
@@ -7,8 +10,7 @@ import { onEnter } from './on_enter'; | |||
7 | import { parentModule } from './parent_module'; | 10 | import { parentModule } from './parent_module'; |
8 | import { syntaxTree } from './syntax_tree'; | 11 | import { syntaxTree } from './syntax_tree'; |
9 | import { expandMacro } from './expand_macro'; | 12 | import { expandMacro } from './expand_macro'; |
10 | import * as inlayHints from './inlay_hints'; | 13 | import { run, runSingle } from './runnables'; |
11 | import * as runnables from './runnables'; | ||
12 | 14 | ||
13 | function collectGarbage(ctx: Ctx): Cmd { | 15 | function 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 | ||
21 | function 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 | |||
19 | export { | 32 | export { |
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 @@ | |||
1 | import * as vscode from 'vscode'; | ||
2 | import { Range, TextDocumentChangeEvent, TextEditor } from 'vscode'; | ||
3 | import { TextDocumentIdentifier } from 'vscode-languageclient'; | ||
4 | import { Server } from '../server'; | ||
5 | |||
6 | interface InlayHintsParams { | ||
7 | textDocument: TextDocumentIdentifier; | ||
8 | } | ||
9 | |||
10 | interface InlayHint { | ||
11 | range: Range; | ||
12 | kind: string; | ||
13 | label: string; | ||
14 | } | ||
15 | |||
16 | const typeHintDecorationType = vscode.window.createTextEditorDecorationType({ | ||
17 | after: { | ||
18 | color: new vscode.ThemeColor('ralsp.inlayHint'), | ||
19 | }, | ||
20 | }); | ||
21 | |||
22 | export 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 @@ | |||
1 | export 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 @@ | |||
1 | import * as vscode from 'vscode'; | 1 | import * as vscode from 'vscode'; |
2 | import * as lc from 'vscode-languageclient'; | 2 | import * as lc from 'vscode-languageclient'; |
3 | 3 | ||
4 | import { Server } from '../server'; | 4 | import { Ctx, Cmd } from '../ctx'; |
5 | |||
6 | export 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 | |||
49 | export 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 | ||
6 | interface RunnablesParams { | 66 | interface 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 | |||
71 | let prevRunnable: RunnableQuickPick | undefined; | ||
72 | export 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 | |||
114 | export 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 @@ | |||
1 | import * as vscode from 'vscode'; | ||
2 | |||
3 | const spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']; | ||
4 | |||
5 | export 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 | ||
89 | interface ProgressParams { | ||
90 | token: string; | ||
91 | value: WorkDoneProgress; | ||
92 | } | ||
93 | |||
94 | enum WorkDoneProgressKind { | ||
95 | Begin = 'begin', | ||
96 | Report = 'report', | ||
97 | End = 'end', | ||
98 | } | ||
99 | |||
100 | interface WorkDoneProgress { | ||
101 | kind: WorkDoneProgressKind; | ||
102 | message?: string; | ||
103 | cancelable?: boolean; | ||
104 | percentage?: string; | ||
105 | } | ||