From 1ae6571762cab605a84a731e10c89d8f3f00eef8 Mon Sep 17 00:00:00 2001 From: Bernardo Date: Sat, 13 Apr 2019 22:13:21 +0200 Subject: [PATCH 1/4] cargo watch start and stop commands --- editors/code/package.json | 12 ++- editors/code/src/commands/cargo_watch.ts | 100 ++++++++++++---------- editors/code/src/commands/runnables.ts | 7 +- editors/code/src/commands/watch_status.ts | 18 ++-- editors/code/src/extension.ts | 16 +++- 5 files changed, 99 insertions(+), 54 deletions(-) diff --git a/editors/code/package.json b/editors/code/package.json index a0454191a1..c58171a719 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -119,6 +119,16 @@ "command": "rust-analyzer.reload", "title": "Restart server", "category": "Rust Analyzer" + }, + { + "command": "rust-analyzer.startCargoWatch", + "title": "Start Cargo Watch", + "category": "Rust Analyzer" + }, + { + "command": "rust-analyzer.stopCargoWatch", + "title": "Stop Cargo Watch", + "category": "Rust Analyzer" } ], "keybindings": [ @@ -253,4 +263,4 @@ } ] } -} +} \ No newline at end of file diff --git a/editors/code/src/commands/cargo_watch.ts b/editors/code/src/commands/cargo_watch.ts index 32bd38a1cc..1d939e28cc 100644 --- a/editors/code/src/commands/cargo_watch.ts +++ b/editors/code/src/commands/cargo_watch.ts @@ -7,44 +7,55 @@ import { terminate } from '../utils/processes'; import { LineBuffer } from './line_buffer'; import { StatusDisplay } from './watch_status'; -export class CargoWatchProvider { - private diagnosticCollection?: vscode.DiagnosticCollection; - private cargoProcess?: child_process.ChildProcess; - private outBuffer: string = ''; - private statusDisplay?: StatusDisplay; - private outputChannel?: vscode.OutputChannel; +export function registerCargoWatchProvider( + subscriptions: vscode.Disposable[] +): CargoWatchProvider | undefined { + let cargoExists = false; + const cargoTomlFile = path.join(vscode.workspace.rootPath!, 'Cargo.toml'); + // Check if the working directory is valid cargo root path + try { + if (fs.existsSync(cargoTomlFile)) { + cargoExists = true; + } + } catch (err) { + cargoExists = false; + } - public activate(subscriptions: vscode.Disposable[]) { - let cargoExists = false; - const cargoTomlFile = path.join( - vscode.workspace.rootPath!, - 'Cargo.toml' + if (!cargoExists) { + vscode.window.showErrorMessage( + `Couldn\'t find \'Cargo.toml\' in ${cargoTomlFile}` ); - // Check if the working directory is valid cargo root path - try { - if (fs.existsSync(cargoTomlFile)) { - cargoExists = true; - } - } catch (err) { - cargoExists = false; - } + return; + } - if (!cargoExists) { - vscode.window.showErrorMessage( - `Couldn\'t find \'Cargo.toml\' in ${cargoTomlFile}` - ); - return; - } + const provider = new CargoWatchProvider(); + subscriptions.push(provider); + return provider; +} - subscriptions.push(this); +export class CargoWatchProvider implements vscode.Disposable { + private readonly diagnosticCollection: vscode.DiagnosticCollection; + private readonly statusDisplay: StatusDisplay; + private readonly outputChannel: vscode.OutputChannel; + private cargoProcess?: child_process.ChildProcess; + + constructor() { this.diagnosticCollection = vscode.languages.createDiagnosticCollection( 'rustc' ); - - this.statusDisplay = new StatusDisplay(subscriptions); + this.statusDisplay = new StatusDisplay(); this.outputChannel = vscode.window.createOutputChannel( 'Cargo Watch Trace' ); + } + + public start() { + if (this.cargoProcess) { + vscode.window.showInformationMessage( + 'Cargo Watch is already running' + ); + return; + } let args = 'check --message-format json'; if (Server.config.cargoWatchOptions.checkArguments.length > 0) { @@ -95,25 +106,28 @@ export class CargoWatchProvider { this.logInfo('cargo-watch started.'); } - public dispose(): void { - if (this.diagnosticCollection) { - this.diagnosticCollection.clear(); - this.diagnosticCollection.dispose(); - } - + public stop() { if (this.cargoProcess) { this.cargoProcess.kill(); terminate(this.cargoProcess); + this.cargoProcess = undefined; + } else { + vscode.window.showInformationMessage('Cargo Watch is not running'); } + } - if (this.outputChannel) { - this.outputChannel.dispose(); - } + public dispose(): void { + this.stop(); + + this.diagnosticCollection.clear(); + this.diagnosticCollection.dispose(); + this.outputChannel.dispose(); + this.statusDisplay.dispose(); } private logInfo(line: string) { if (Server.config.cargoWatchOptions.trace === 'verbose') { - this.outputChannel!.append(line); + this.outputChannel.append(line); } } @@ -122,18 +136,18 @@ export class CargoWatchProvider { Server.config.cargoWatchOptions.trace === 'error' || Server.config.cargoWatchOptions.trace === 'verbose' ) { - this.outputChannel!.append(line); + this.outputChannel.append(line); } } private parseLine(line: string) { if (line.startsWith('[Running')) { - this.diagnosticCollection!.clear(); - this.statusDisplay!.show(); + this.diagnosticCollection.clear(); + this.statusDisplay.show(); } if (line.startsWith('[Finished running')) { - this.statusDisplay!.hide(); + this.statusDisplay.hide(); } function getLevel(s: string): vscode.DiagnosticSeverity { @@ -193,7 +207,7 @@ export class CargoWatchProvider { // The format of the package_id is "{name} {version} ({source_id})", // https://github.com/rust-lang/cargo/blob/37ad03f86e895bb80b474c1c088322634f4725f5/src/cargo/core/package_id.rs#L53 - this.statusDisplay!.packageName = msg.package_id.split(' ')[0]; + this.statusDisplay.packageName = msg.package_id.split(' ')[0]; } else if (data.reason === 'compiler-message') { const msg = data.message as RustDiagnostic; diff --git a/editors/code/src/commands/runnables.ts b/editors/code/src/commands/runnables.ts index c4df24c79f..5790252b74 100644 --- a/editors/code/src/commands/runnables.ts +++ b/editors/code/src/commands/runnables.ts @@ -5,7 +5,7 @@ import * as vscode from 'vscode'; import * as lc from 'vscode-languageclient'; import { Server } from '../server'; -import { CargoWatchProvider } from './cargo_watch'; +import { CargoWatchProvider, registerCargoWatchProvider } from './cargo_watch'; interface RunnablesParams { textDocument: lc.TextDocumentIdentifier; @@ -137,7 +137,7 @@ export async function handleSingle(runnable: Runnable) { */ export async function interactivelyStartCargoWatch( context: vscode.ExtensionContext -) { +): Promise { if (Server.config.cargoWatchOptions.enableOnStartup === 'disabled') { return; } @@ -197,6 +197,5 @@ export async function interactivelyStartCargoWatch( } } - const validater = new CargoWatchProvider(); - validater.activate(context.subscriptions); + return registerCargoWatchProvider(context.subscriptions); } diff --git a/editors/code/src/commands/watch_status.ts b/editors/code/src/commands/watch_status.ts index 86ae821de7..a3b0178f20 100644 --- a/editors/code/src/commands/watch_status.ts +++ b/editors/code/src/commands/watch_status.ts @@ -2,19 +2,18 @@ import * as vscode from 'vscode'; const spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']; -export class StatusDisplay { +export class StatusDisplay implements vscode.Disposable { public packageName?: string; private i = 0; private statusBarItem: vscode.StatusBarItem; private timer?: NodeJS.Timeout; - constructor(subscriptions: vscode.Disposable[]) { + constructor() { this.statusBarItem = vscode.window.createStatusBarItem( vscode.StatusBarAlignment.Left, 10 ); - subscriptions.push(this.statusBarItem); this.statusBarItem.hide(); } @@ -33,7 +32,7 @@ export class StatusDisplay { } }, 300); - this.statusBarItem!.show(); + this.statusBarItem.show(); } public hide() { @@ -42,7 +41,16 @@ export class StatusDisplay { this.timer = undefined; } - this.statusBarItem!.hide(); + this.statusBarItem.hide(); + } + + public dispose() { + if (this.timer) { + clearInterval(this.timer); + this.timer = undefined; + } + + this.statusBarItem.dispose(); } private frame() { diff --git a/editors/code/src/extension.ts b/editors/code/src/extension.ts index 1073a36a03..b48ad9b29b 100644 --- a/editors/code/src/extension.ts +++ b/editors/code/src/extension.ts @@ -2,6 +2,7 @@ import * as vscode from 'vscode'; import * as lc from 'vscode-languageclient'; import * as commands from './commands'; +import { CargoWatchProvider } from './commands/cargo_watch'; import { interactivelyStartCargoWatch } from './commands/runnables'; import { SyntaxTreeContentProvider } from './commands/syntaxTree'; import * as events from './events'; @@ -126,7 +127,20 @@ export function activate(context: vscode.ExtensionContext) { vscode.commands.registerCommand('rust-analyzer.reload', reloadCommand); // Executing `cargo watch` provides us with inline diagnostics on save - interactivelyStartCargoWatch(context); + let provider: CargoWatchProvider | undefined; + interactivelyStartCargoWatch(context).then(p => { + provider = p; + }); + registerCommand('rust-analyzer.startCargoWatch', () => { + if (provider) { + provider.start(); + } + }); + registerCommand('rust-analyzer.stopCargoWatch', () => { + if (provider) { + provider.stop(); + } + }); // Start the language server, finally! startServer(); From 3d3adabbef9290097fd890218d5d8ea6c1d8c002 Mon Sep 17 00:00:00 2001 From: Bernardo Date: Sun, 14 Apr 2019 12:45:36 +0200 Subject: [PATCH 2/4] recover rustc-watch problemMatchers --- editors/code/package.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/editors/code/package.json b/editors/code/package.json index c58171a719..dd9843241a 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -260,6 +260,18 @@ "${workspaceRoot}" ], "pattern": "$rustc" + }, + { + "name": "rustc-watch", + "fileLocation": [ + "relative", + "${workspaceRoot}" + ], + "background": { + "beginsPattern": "^\\[Running\\b", + "endsPattern": "^\\[Finished running\\b" + }, + "pattern": "$rustc" } ] } From 422f4ac080c1347421a1ba6efcbc8f5b40414f46 Mon Sep 17 00:00:00 2001 From: Bernardo Date: Fri, 19 Apr 2019 18:28:14 +0200 Subject: [PATCH 3/4] start cargo watch if not started interactively --- editors/code/package.json | 2 +- editors/code/src/commands/runnables.ts | 12 +++++++++++- editors/code/src/extension.ts | 9 ++++++++- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/editors/code/package.json b/editors/code/package.json index dd9843241a..83ceb19f73 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -275,4 +275,4 @@ } ] } -} \ No newline at end of file +} diff --git a/editors/code/src/commands/runnables.ts b/editors/code/src/commands/runnables.ts index 5790252b74..26372c1e8b 100644 --- a/editors/code/src/commands/runnables.ts +++ b/editors/code/src/commands/runnables.ts @@ -153,6 +153,12 @@ export async function interactivelyStartCargoWatch( } } + return startCargoWatch(context); +} + +export async function startCargoWatch( + context: vscode.ExtensionContext +): Promise { const execPromise = util.promisify(child_process.exec); const { stderr } = await execPromise('cargo watch --version').catch(e => e); @@ -197,5 +203,9 @@ export async function interactivelyStartCargoWatch( } } - return registerCargoWatchProvider(context.subscriptions); + const provider = await registerCargoWatchProvider(context.subscriptions); + if (provider) { + provider.start(); + } + return provider; } diff --git a/editors/code/src/extension.ts b/editors/code/src/extension.ts index b48ad9b29b..48dd2a6146 100644 --- a/editors/code/src/extension.ts +++ b/editors/code/src/extension.ts @@ -3,7 +3,10 @@ import * as lc from 'vscode-languageclient'; import * as commands from './commands'; import { CargoWatchProvider } from './commands/cargo_watch'; -import { interactivelyStartCargoWatch } from './commands/runnables'; +import { + interactivelyStartCargoWatch, + startCargoWatch +} from './commands/runnables'; import { SyntaxTreeContentProvider } from './commands/syntaxTree'; import * as events from './events'; import * as notifications from './notifications'; @@ -134,6 +137,10 @@ export function activate(context: vscode.ExtensionContext) { registerCommand('rust-analyzer.startCargoWatch', () => { if (provider) { provider.start(); + } else { + startCargoWatch(context).then(p => { + provider = p; + }); } }); registerCommand('rust-analyzer.stopCargoWatch', () => { From 4cd0a96c96870d4e9a73b92f401a8fad26f3c02a Mon Sep 17 00:00:00 2001 From: Bernardo Date: Sat, 20 Apr 2019 10:02:23 +0200 Subject: [PATCH 4/4] update user docs --- docs/user/features.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/user/features.md b/docs/user/features.md index 09a7f5a437..cffbb4c7f1 100644 --- a/docs/user/features.md +++ b/docs/user/features.md @@ -76,6 +76,14 @@ Shows internal statistic about memory usage of rust-analyzer Manually triggers GC +#### Start Cargo Watch + +Start `cargo watch` for live error highlighting. Will prompt to install if it's not already installed. + +#### Stop Cargo Watch + +Stop `cargo watch` + ### Code Actions (Assists) These are triggered in a particular context via light bulb. We use custom code on