aboutsummaryrefslogtreecommitdiff
path: root/editors/code/src/commands/runnables.ts
diff options
context:
space:
mode:
Diffstat (limited to 'editors/code/src/commands/runnables.ts')
-rw-r--r--editors/code/src/commands/runnables.ts214
1 files changed, 62 insertions, 152 deletions
diff --git a/editors/code/src/commands/runnables.ts b/editors/code/src/commands/runnables.ts
index cf980e257..7919997ce 100644
--- a/editors/code/src/commands/runnables.ts
+++ b/editors/code/src/commands/runnables.ts
@@ -1,11 +1,68 @@
1import * as child_process from 'child_process';
2
3import * as util from 'util';
4import * as vscode from 'vscode'; 1import * as vscode from 'vscode';
5import * as lc from 'vscode-languageclient'; 2import * as lc from 'vscode-languageclient';
6 3
7import { Server } from '../server'; 4import { Ctx, Cmd } from '../ctx';
8import { CargoWatchProvider, registerCargoWatchProvider } from './cargo_watch'; 5
6export function run(ctx: Ctx): Cmd {
7 let prevRunnable: RunnableQuickPick | undefined;
8
9 return async () => {
10 const editor = ctx.activeRustEditor;
11 const client = ctx.client;
12 if (!editor || !client) return;
13
14 const textDocument: lc.TextDocumentIdentifier = {
15 uri: editor.document.uri.toString(),
16 };
17 const params: RunnablesParams = {
18 textDocument,
19 position: client.code2ProtocolConverter.asPosition(
20 editor.selection.active,
21 ),
22 };
23 const runnables = await client.sendRequest<Runnable[]>(
24 'rust-analyzer/runnables',
25 params,
26 );
27 const items: RunnableQuickPick[] = [];
28 if (prevRunnable) {
29 items.push(prevRunnable);
30 }
31 for (const r of runnables) {
32 if (
33 prevRunnable &&
34 JSON.stringify(prevRunnable.runnable) === JSON.stringify(r)
35 ) {
36 continue;
37 }
38 items.push(new RunnableQuickPick(r));
39 }
40 const item = await vscode.window.showQuickPick(items);
41 if (!item) return;
42
43 item.detail = 'rerun';
44 prevRunnable = item;
45 const task = createTask(item.runnable);
46 return await vscode.tasks.executeTask(task);
47 };
48}
49
50export function runSingle(ctx: Ctx): Cmd {
51 return async (runnable: Runnable) => {
52 const editor = ctx.activeRustEditor;
53 if (!editor) return;
54
55 const task = createTask(runnable);
56 task.group = vscode.TaskGroup.Build;
57 task.presentationOptions = {
58 reveal: vscode.TaskRevealKind.Always,
59 panel: vscode.TaskPanelKind.Dedicated,
60 clear: true,
61 };
62
63 return vscode.tasks.executeTask(task);
64 };
65}
9 66
10interface RunnablesParams { 67interface RunnablesParams {
11 textDocument: lc.TextDocumentIdentifier; 68 textDocument: lc.TextDocumentIdentifier;
@@ -71,150 +128,3 @@ function createTask(spec: Runnable): vscode.Task {
71 t.presentationOptions.clear = true; 128 t.presentationOptions.clear = true;
72 return t; 129 return t;
73} 130}
74
75let prevRunnable: RunnableQuickPick | undefined;
76export async function handle(): Promise<vscode.TaskExecution | undefined> {
77 const editor = vscode.window.activeTextEditor;
78 if (editor == null || editor.document.languageId !== 'rust') {
79 return;
80 }
81 const textDocument: lc.TextDocumentIdentifier = {
82 uri: editor.document.uri.toString(),
83 };
84 const params: RunnablesParams = {
85 textDocument,
86 position: Server.client.code2ProtocolConverter.asPosition(
87 editor.selection.active,
88 ),
89 };
90 const runnables = await Server.client.sendRequest<Runnable[]>(
91 'rust-analyzer/runnables',
92 params,
93 );
94 const items: RunnableQuickPick[] = [];
95 if (prevRunnable) {
96 items.push(prevRunnable);
97 }
98 for (const r of runnables) {
99 if (
100 prevRunnable &&
101 JSON.stringify(prevRunnable.runnable) === JSON.stringify(r)
102 ) {
103 continue;
104 }
105 items.push(new RunnableQuickPick(r));
106 }
107 const item = await vscode.window.showQuickPick(items);
108 if (!item) {
109 return;
110 }
111
112 item.detail = 'rerun';
113 prevRunnable = item;
114 const task = createTask(item.runnable);
115 return await vscode.tasks.executeTask(task);
116}
117
118export async function handleSingle(runnable: Runnable) {
119 const editor = vscode.window.activeTextEditor;
120 if (editor == null || editor.document.languageId !== 'rust') {
121 return;
122 }
123
124 const task = createTask(runnable);
125 task.group = vscode.TaskGroup.Build;
126 task.presentationOptions = {
127 reveal: vscode.TaskRevealKind.Always,
128 panel: vscode.TaskPanelKind.Dedicated,
129 clear: true,
130 };
131
132 return vscode.tasks.executeTask(task);
133}
134
135/**
136 * Interactively asks the user whether we should run `cargo check` in order to
137 * provide inline diagnostics; the user is met with a series of dialog boxes
138 * that, when accepted, allow us to `cargo install cargo-watch` and then run it.
139 */
140export async function interactivelyStartCargoWatch(
141 context: vscode.ExtensionContext,
142): Promise<CargoWatchProvider | undefined> {
143 if (Server.config.cargoWatchOptions.enableOnStartup === 'disabled') {
144 return;
145 }
146
147 if (Server.config.cargoWatchOptions.enableOnStartup === 'ask') {
148 const watch = await vscode.window.showInformationMessage(
149 'Start watching changes with cargo? (Executes `cargo watch`, provides inline diagnostics)',
150 'yes',
151 'no',
152 );
153 if (watch !== 'yes') {
154 return;
155 }
156 }
157
158 return startCargoWatch(context);
159}
160
161export async function startCargoWatch(
162 context: vscode.ExtensionContext,
163): Promise<CargoWatchProvider | undefined> {
164 const execPromise = util.promisify(child_process.exec);
165
166 const { stderr, code = 0 } = await execPromise(
167 'cargo watch --version',
168 ).catch(e => e);
169
170 if (stderr.includes('no such subcommand: `watch`')) {
171 const msg =
172 'The `cargo-watch` subcommand is not installed. Install? (takes ~1-2 minutes)';
173 const install = await vscode.window.showInformationMessage(
174 msg,
175 'yes',
176 'no',
177 );
178 if (install !== 'yes') {
179 return;
180 }
181
182 const label = 'install-cargo-watch';
183 const taskFinished = new Promise((resolve, _reject) => {
184 const disposable = vscode.tasks.onDidEndTask(({ execution }) => {
185 if (execution.task.name === label) {
186 disposable.dispose();
187 resolve();
188 }
189 });
190 });
191
192 vscode.tasks.executeTask(
193 createTask({
194 label,
195 bin: 'cargo',
196 args: ['install', 'cargo-watch'],
197 env: {},
198 }),
199 );
200 await taskFinished;
201 const output = await execPromise('cargo watch --version').catch(e => e);
202 if (output.stderr !== '') {
203 vscode.window.showErrorMessage(
204 `Couldn't install \`cargo-\`watch: ${output.stderr}`,
205 );
206 return;
207 }
208 } else if (code !== 0) {
209 vscode.window.showErrorMessage(
210 `\`cargo watch\` failed with ${code}: ${stderr}`,
211 );
212 return;
213 }
214
215 const provider = await registerCargoWatchProvider(context.subscriptions);
216 if (provider) {
217 provider.start();
218 }
219 return provider;
220}