From 41a1ec723ce2ea3fa78ae468830f0a77e5658307 Mon Sep 17 00:00:00 2001 From: Emil Lauridsen Date: Wed, 25 Dec 2019 16:44:42 +0100 Subject: Remove cargo-watch from vscode extension. Still keeps tests around for reference when porting them to rust --- editors/code/src/commands/cargo_watch.ts | 264 ------------------------------- editors/code/src/commands/runnables.ts | 91 ----------- 2 files changed, 355 deletions(-) delete mode 100644 editors/code/src/commands/cargo_watch.ts (limited to 'editors/code/src/commands') diff --git a/editors/code/src/commands/cargo_watch.ts b/editors/code/src/commands/cargo_watch.ts deleted file mode 100644 index ac62bdd48..000000000 --- a/editors/code/src/commands/cargo_watch.ts +++ /dev/null @@ -1,264 +0,0 @@ -import * as child_process from 'child_process'; -import * as path from 'path'; -import * as vscode from 'vscode'; - -import { Server } from '../server'; -import { terminate } from '../utils/processes'; -import { LineBuffer } from './line_buffer'; -import { StatusDisplay } from './watch_status'; - -import { - mapRustDiagnosticToVsCode, - RustDiagnostic, -} from '../utils/diagnostics/rust'; -import SuggestedFixCollection from '../utils/diagnostics/SuggestedFixCollection'; -import { areDiagnosticsEqual } from '../utils/diagnostics/vscode'; - -export async function registerCargoWatchProvider( - subscriptions: vscode.Disposable[], -): Promise { - let cargoExists = false; - - // Check if the working directory is valid cargo root path - const cargoTomlPath = path.join(vscode.workspace.rootPath!, 'Cargo.toml'); - const cargoTomlUri = vscode.Uri.file(cargoTomlPath); - const cargoTomlFileInfo = await vscode.workspace.fs.stat(cargoTomlUri); - - if (cargoTomlFileInfo) { - cargoExists = true; - } - - if (!cargoExists) { - vscode.window.showErrorMessage( - `Couldn\'t find \'Cargo.toml\' at ${cargoTomlPath}`, - ); - return; - } - - const provider = new CargoWatchProvider(); - subscriptions.push(provider); - return provider; -} - -export class CargoWatchProvider implements vscode.Disposable { - private readonly diagnosticCollection: vscode.DiagnosticCollection; - private readonly statusDisplay: StatusDisplay; - private readonly outputChannel: vscode.OutputChannel; - - private suggestedFixCollection: SuggestedFixCollection; - private codeActionDispose: vscode.Disposable; - - private cargoProcess?: child_process.ChildProcess; - - constructor() { - this.diagnosticCollection = vscode.languages.createDiagnosticCollection( - 'rustc', - ); - this.statusDisplay = new StatusDisplay( - Server.config.cargoWatchOptions.command, - ); - this.outputChannel = vscode.window.createOutputChannel( - 'Cargo Watch Trace', - ); - - // Track `rustc`'s suggested fixes so we can convert them to code actions - this.suggestedFixCollection = new SuggestedFixCollection(); - this.codeActionDispose = vscode.languages.registerCodeActionsProvider( - [{ scheme: 'file', language: 'rust' }], - this.suggestedFixCollection, - { - providedCodeActionKinds: - SuggestedFixCollection.PROVIDED_CODE_ACTION_KINDS, - }, - ); - } - - public start() { - if (this.cargoProcess) { - vscode.window.showInformationMessage( - 'Cargo Watch is already running', - ); - return; - } - - let args = - Server.config.cargoWatchOptions.command + ' --message-format json'; - if (Server.config.cargoWatchOptions.allTargets) { - args += ' --all-targets'; - } - if (Server.config.cargoWatchOptions.command.length > 0) { - // Excape the double quote string: - args += ' ' + Server.config.cargoWatchOptions.arguments; - } - // Windows handles arguments differently than the unix-likes, so we need to wrap the args in double quotes - if (process.platform === 'win32') { - args = '"' + args + '"'; - } - - const ignoreFlags = Server.config.cargoWatchOptions.ignore.reduce( - (flags, pattern) => [...flags, '--ignore', pattern], - [] as string[], - ); - - // Start the cargo watch with json message - this.cargoProcess = child_process.spawn( - 'cargo', - ['watch', '-x', args, ...ignoreFlags], - { - stdio: ['ignore', 'pipe', 'pipe'], - cwd: vscode.workspace.rootPath, - windowsVerbatimArguments: true, - }, - ); - - if (!this.cargoProcess) { - vscode.window.showErrorMessage('Cargo Watch failed to start'); - return; - } - - const stdoutData = new LineBuffer(); - this.cargoProcess.stdout?.on('data', (s: string) => { - stdoutData.processOutput(s, line => { - this.logInfo(line); - try { - this.parseLine(line); - } catch (err) { - this.logError(`Failed to parse: ${err}, content : ${line}`); - } - }); - }); - - const stderrData = new LineBuffer(); - this.cargoProcess.stderr?.on('data', (s: string) => { - stderrData.processOutput(s, line => { - this.logError('Error on cargo-watch : {\n' + line + '}\n'); - }); - }); - - this.cargoProcess.on('error', (err: Error) => { - this.logError( - 'Error on cargo-watch process : {\n' + err.message + '}\n', - ); - }); - - this.logInfo('cargo-watch started.'); - } - - public stop() { - if (this.cargoProcess) { - this.cargoProcess.kill(); - terminate(this.cargoProcess); - this.cargoProcess = undefined; - } else { - vscode.window.showInformationMessage('Cargo Watch is not running'); - } - } - - public dispose(): void { - this.stop(); - - this.diagnosticCollection.clear(); - this.diagnosticCollection.dispose(); - this.outputChannel.dispose(); - this.statusDisplay.dispose(); - this.codeActionDispose.dispose(); - } - - private logInfo(line: string) { - if (Server.config.cargoWatchOptions.trace === 'verbose') { - this.outputChannel.append(line); - } - } - - private logError(line: string) { - if ( - Server.config.cargoWatchOptions.trace === 'error' || - Server.config.cargoWatchOptions.trace === 'verbose' - ) { - this.outputChannel.append(line); - } - } - - private parseLine(line: string) { - if (line.startsWith('[Running')) { - this.diagnosticCollection.clear(); - this.suggestedFixCollection.clear(); - this.statusDisplay.show(); - } - - if (line.startsWith('[Finished running')) { - this.statusDisplay.hide(); - } - - interface CargoArtifact { - reason: string; - package_id: string; - } - - // https://github.com/rust-lang/cargo/blob/master/src/cargo/util/machine_message.rs - interface CargoMessage { - reason: string; - package_id: string; - message: RustDiagnostic; - } - - // cargo-watch itself output non json format - // Ignore these lines - let data: CargoMessage; - try { - data = JSON.parse(line.trim()); - } catch (error) { - this.logError(`Fail to parse to json : { ${error} }`); - return; - } - - if (data.reason === 'compiler-artifact') { - const msg = data as CargoArtifact; - - // 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]; - } else if (data.reason === 'compiler-message') { - const msg = data.message as RustDiagnostic; - - const mapResult = mapRustDiagnosticToVsCode(msg); - if (!mapResult) { - return; - } - - const { location, diagnostic, suggestedFixes } = mapResult; - const fileUri = location.uri; - - const diagnostics: vscode.Diagnostic[] = [ - ...(this.diagnosticCollection!.get(fileUri) || []), - ]; - - // If we're building multiple targets it's possible we've already seen this diagnostic - const isDuplicate = diagnostics.some(d => - areDiagnosticsEqual(d, diagnostic), - ); - if (isDuplicate) { - return; - } - - diagnostics.push(diagnostic); - this.diagnosticCollection!.set(fileUri, diagnostics); - - if (suggestedFixes.length) { - for (const suggestedFix of suggestedFixes) { - this.suggestedFixCollection.addSuggestedFixForDiagnostic( - suggestedFix, - diagnostic, - ); - } - - // Have VsCode query us for the code actions - vscode.commands.executeCommand( - 'vscode.executeCodeActionProvider', - fileUri, - diagnostic.range, - ); - } - } - } -} diff --git a/editors/code/src/commands/runnables.ts b/editors/code/src/commands/runnables.ts index cf980e257..7728541de 100644 --- a/editors/code/src/commands/runnables.ts +++ b/editors/code/src/commands/runnables.ts @@ -1,11 +1,7 @@ -import * as child_process from 'child_process'; - -import * as util from 'util'; import * as vscode from 'vscode'; import * as lc from 'vscode-languageclient'; import { Server } from '../server'; -import { CargoWatchProvider, registerCargoWatchProvider } from './cargo_watch'; interface RunnablesParams { textDocument: lc.TextDocumentIdentifier; @@ -131,90 +127,3 @@ export async function handleSingle(runnable: Runnable) { return vscode.tasks.executeTask(task); } - -/** - * Interactively asks the user whether we should run `cargo check` in order to - * provide inline diagnostics; the user is met with a series of dialog boxes - * that, when accepted, allow us to `cargo install cargo-watch` and then run it. - */ -export async function interactivelyStartCargoWatch( - context: vscode.ExtensionContext, -): Promise { - if (Server.config.cargoWatchOptions.enableOnStartup === 'disabled') { - return; - } - - if (Server.config.cargoWatchOptions.enableOnStartup === 'ask') { - const watch = await vscode.window.showInformationMessage( - 'Start watching changes with cargo? (Executes `cargo watch`, provides inline diagnostics)', - 'yes', - 'no', - ); - if (watch !== 'yes') { - return; - } - } - - return startCargoWatch(context); -} - -export async function startCargoWatch( - context: vscode.ExtensionContext, -): Promise { - const execPromise = util.promisify(child_process.exec); - - const { stderr, code = 0 } = await execPromise( - 'cargo watch --version', - ).catch(e => e); - - if (stderr.includes('no such subcommand: `watch`')) { - const msg = - 'The `cargo-watch` subcommand is not installed. Install? (takes ~1-2 minutes)'; - const install = await vscode.window.showInformationMessage( - msg, - 'yes', - 'no', - ); - if (install !== 'yes') { - return; - } - - const label = 'install-cargo-watch'; - const taskFinished = new Promise((resolve, _reject) => { - const disposable = vscode.tasks.onDidEndTask(({ execution }) => { - if (execution.task.name === label) { - disposable.dispose(); - resolve(); - } - }); - }); - - vscode.tasks.executeTask( - createTask({ - label, - bin: 'cargo', - args: ['install', 'cargo-watch'], - env: {}, - }), - ); - await taskFinished; - const output = await execPromise('cargo watch --version').catch(e => e); - if (output.stderr !== '') { - vscode.window.showErrorMessage( - `Couldn't install \`cargo-\`watch: ${output.stderr}`, - ); - return; - } - } else if (code !== 0) { - vscode.window.showErrorMessage( - `\`cargo watch\` failed with ${code}: ${stderr}`, - ); - return; - } - - const provider = await registerCargoWatchProvider(context.subscriptions); - if (provider) { - provider.start(); - } - return provider; -} -- cgit v1.2.3 From 178c23f50549298aad0dc0f098f8ed510a57f9d6 Mon Sep 17 00:00:00 2001 From: Emil Lauridsen Date: Wed, 25 Dec 2019 19:08:44 +0100 Subject: Re-implement status display using LSP 3.15 progress event --- editors/code/src/commands/watch_status.ts | 43 +++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) (limited to 'editors/code/src/commands') diff --git a/editors/code/src/commands/watch_status.ts b/editors/code/src/commands/watch_status.ts index 8d64394c7..2404c3f16 100644 --- a/editors/code/src/commands/watch_status.ts +++ b/editors/code/src/commands/watch_status.ts @@ -57,7 +57,50 @@ export class StatusDisplay implements vscode.Disposable { this.statusBarItem.dispose(); } + public handleProgressNotification(params: ProgressParams) { + const { token, value } = params; + if (token !== "rustAnalyzer/cargoWatcher") { + return; + } + + console.log("Got progress notification", token, value) + switch (value.kind) { + case "begin": + this.show(); + break; + + case "report": + if (value.message) { + this.packageName = value.message; + } + break; + + case "end": + this.hide(); + break; + } + } + private frame() { return spinnerFrames[(this.i = ++this.i % spinnerFrames.length)]; } } + +// FIXME: Replace this once vscode-languageclient is updated to LSP 3.15 +interface ProgressParams { + token: string + value: WorkDoneProgress +} + +enum WorkDoneProgressKind { + Begin = "begin", + Report = "report", + End = "end" +} + +interface WorkDoneProgress { + kind: WorkDoneProgressKind, + message?: string + cancelable?: boolean + percentage?: string +} \ No newline at end of file -- cgit v1.2.3 From b9c10ed97f22d665b75895a387c633dfa412ed2b Mon Sep 17 00:00:00 2001 From: Emil Lauridsen Date: Wed, 25 Dec 2019 19:10:30 +0100 Subject: Re-format VSCode extension changes --- editors/code/src/commands/watch_status.ts | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) (limited to 'editors/code/src/commands') diff --git a/editors/code/src/commands/watch_status.ts b/editors/code/src/commands/watch_status.ts index 2404c3f16..10787b510 100644 --- a/editors/code/src/commands/watch_status.ts +++ b/editors/code/src/commands/watch_status.ts @@ -59,23 +59,22 @@ export class StatusDisplay implements vscode.Disposable { public handleProgressNotification(params: ProgressParams) { const { token, value } = params; - if (token !== "rustAnalyzer/cargoWatcher") { + if (token !== 'rustAnalyzer/cargoWatcher') { return; } - console.log("Got progress notification", token, value) switch (value.kind) { - case "begin": + case 'begin': this.show(); break; - case "report": + case 'report': if (value.message) { this.packageName = value.message; } break; - case "end": + case 'end': this.hide(); break; } @@ -88,19 +87,19 @@ export class StatusDisplay implements vscode.Disposable { // FIXME: Replace this once vscode-languageclient is updated to LSP 3.15 interface ProgressParams { - token: string - value: WorkDoneProgress + token: string; + value: WorkDoneProgress; } enum WorkDoneProgressKind { - Begin = "begin", - Report = "report", - End = "end" + Begin = 'begin', + Report = 'report', + End = 'end', } interface WorkDoneProgress { - kind: WorkDoneProgressKind, - message?: string - cancelable?: boolean - percentage?: string -} \ No newline at end of file + kind: WorkDoneProgressKind; + message?: string; + cancelable?: boolean; + percentage?: string; +} -- cgit v1.2.3