1 import * as child_process from 'child_process';
3 import * as util from 'util';
4 import * as vscode from 'vscode';
5 import * as lc from 'vscode-languageclient';
7 import { Server } from '../server';
8 import { CargoWatchProvider, registerCargoWatchProvider } from './cargo_watch';
10 interface RunnablesParams {
11 textDocument: lc.TextDocumentIdentifier;
12 position?: lc.Position;
19 env: { [index: string]: string };
23 class RunnableQuickPick implements vscode.QuickPickItem {
25 public description?: string | undefined;
26 public detail?: string | undefined;
27 public picked?: boolean | undefined;
29 constructor(public runnable: Runnable) {
30 this.label = runnable.label;
34 interface CargoTaskDefinition extends vscode.TaskDefinition {
39 env?: { [key: string]: string };
42 function createTask(spec: Runnable): vscode.Task {
43 const TASK_SOURCE = 'Rust';
44 const definition: CargoTaskDefinition = {
52 const execOption: vscode.ShellExecutionOptions = {
56 const exec = new vscode.ShellExecution(
62 const f = vscode.workspace.workspaceFolders![0];
63 const t = new vscode.Task(
71 t.presentationOptions.clear = true;
75 let prevRunnable: RunnableQuickPick | undefined;
76 export async function handle() {
77 const editor = vscode.window.activeTextEditor;
78 if (editor == null || editor.document.languageId !== 'rust') {
81 const textDocument: lc.TextDocumentIdentifier = {
82 uri: editor.document.uri.toString()
84 const params: RunnablesParams = {
86 position: Server.client.code2ProtocolConverter.asPosition(
87 editor.selection.active
90 const runnables = await Server.client.sendRequest<Runnable[]>(
91 'rust-analyzer/runnables',
94 const items: RunnableQuickPick[] = [];
96 items.push(prevRunnable);
98 for (const r of runnables) {
101 JSON.stringify(prevRunnable.runnable) === JSON.stringify(r)
105 items.push(new RunnableQuickPick(r));
107 const item = await vscode.window.showQuickPick(items);
109 item.detail = 'rerun';
111 const task = createTask(item.runnable);
112 return await vscode.tasks.executeTask(task);
116 export async function handleSingle(runnable: Runnable) {
117 const editor = vscode.window.activeTextEditor;
118 if (editor == null || editor.document.languageId !== 'rust') {
122 const task = createTask(runnable);
123 task.group = vscode.TaskGroup.Build;
124 task.presentationOptions = {
125 reveal: vscode.TaskRevealKind.Always,
126 panel: vscode.TaskPanelKind.Dedicated,
130 return vscode.tasks.executeTask(task);
134 * Interactively asks the user whether we should run `cargo check` in order to
135 * provide inline diagnostics; the user is met with a series of dialog boxes
136 * that, when accepted, allow us to `cargo install cargo-watch` and then run it.
138 export async function interactivelyStartCargoWatch(
139 context: vscode.ExtensionContext
140 ): Promise<CargoWatchProvider | undefined> {
141 if (Server.config.cargoWatchOptions.enableOnStartup === 'disabled') {
145 if (Server.config.cargoWatchOptions.enableOnStartup === 'ask') {
146 const watch = await vscode.window.showInformationMessage(
147 'Start watching changes with cargo? (Executes `cargo watch`, provides inline diagnostics)',
151 if (watch !== 'yes') {
156 return startCargoWatch(context);
159 export async function startCargoWatch(
160 context: vscode.ExtensionContext
161 ): Promise<CargoWatchProvider | undefined> {
162 const execPromise = util.promisify(child_process.exec);
164 const { stderr } = await execPromise('cargo watch --version').catch(e => e);
166 if (stderr.includes('no such subcommand: `watch`')) {
168 'The `cargo-watch` subcommand is not installed. Install? (takes ~1-2 minutes)';
169 const install = await vscode.window.showInformationMessage(
174 if (install !== 'yes') {
178 const label = 'install-cargo-watch';
179 const taskFinished = new Promise((resolve, reject) => {
180 const disposable = vscode.tasks.onDidEndTask(({ execution }) => {
181 if (execution.task.name === label) {
182 disposable.dispose();
188 vscode.tasks.executeTask(
192 args: ['install', 'cargo-watch'],
197 const output = await execPromise('cargo watch --version').catch(e => e);
198 if (output.stderr !== '') {
199 vscode.window.showErrorMessage(
200 `Couldn't install \`cargo-\`watch: ${output.stderr}`
204 } else if (stderr !== '') {
205 vscode.window.showErrorMessage(
206 `Couldn't run \`cargo watch\`: ${stderr}`
211 const provider = await registerCargoWatchProvider(context.subscriptions);