From 02e450f354ccd978c90425929c635139210843a3 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Tue, 2 Apr 2019 14:43:02 +0800 Subject: Add cargo-watch.check-arguments --- docs/user/README.md | 2 + editors/code/package.json | 10 ++++ editors/code/src/commands/cargo_watch.ts | 78 ++++++++++++++++++++------------ editors/code/src/commands/line_buffer.ts | 16 +++++++ editors/code/src/config.ts | 39 ++++++++++------ editors/code/src/utils/processes.ts | 68 +++++++++++++++------------- 6 files changed, 139 insertions(+), 74 deletions(-) create mode 100644 editors/code/src/commands/line_buffer.ts diff --git a/docs/user/README.md b/docs/user/README.md index 722a86c9b..33dd4f995 100644 --- a/docs/user/README.md +++ b/docs/user/README.md @@ -59,6 +59,8 @@ for details. * `rust-analyzer.raLspServerPath`: path to `ra_lsp_server` executable * `rust-analyzer.enableCargoWatchOnStartup`: prompt to install & enable `cargo watch` for live error highlighting (note, this **does not** use rust-analyzer) +* `rust-analyzer.cargo-watch.check-arguments`: cargo-watch check arguments. + (e.g: `--features="shumway,pdf"` will run as `cargo watch -x "check --features="shumway,pdf""` ) * `rust-analyzer.trace.server`: enables internal logging * `rust-analyzer.trace.cargo-watch`: enables cargo-watch logging diff --git a/editors/code/package.json b/editors/code/package.json index cc364d478..1c8caaa60 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -184,6 +184,11 @@ ], "description": "Whether to run `cargo watch` on startup" }, + "rust-analyzer.cargo-watch.check-arguments": { + "type": "string", + "description": "`cargo-watch` check arguments. (e.g: `--features=\"shumway,pdf\"` will run as `cargo watch -x \"check --features=\"shumway,pdf\"\"` )", + "default": "" + }, "rust-analyzer.trace.server": { "type": "string", "scope": "window", @@ -192,6 +197,11 @@ "messages", "verbose" ], + "enumDescriptions": [ + "No traces", + "Error only", + "Full log" + ], "default": "off", "description": "Trace requests to the ra_lsp_server" }, diff --git a/editors/code/src/commands/cargo_watch.ts b/editors/code/src/commands/cargo_watch.ts index 9864ce01a..fb8fcaeb3 100644 --- a/editors/code/src/commands/cargo_watch.ts +++ b/editors/code/src/commands/cargo_watch.ts @@ -3,9 +3,9 @@ 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'; - export class CargoWatchProvider { private diagnosticCollection?: vscode.DiagnosticCollection; private cargoProcess?: child_process.ChildProcess; @@ -23,33 +23,44 @@ export class CargoWatchProvider { this.outputChannel = vscode.window.createOutputChannel( 'Cargo Watch Trace' ); - + + let args = '"check --message-format json'; + if (Server.config.cargoWatchOptions.checkArguments.length > 0) { + // Excape the double quote string: + args += ' ' + Server.config.cargoWatchOptions.checkArguments; + } + args += '"'; + // Start the cargo watch with json message this.cargoProcess = child_process.spawn( 'cargo', - ['watch', '-x', '\"check --message-format json\"'], + ['watch', '-x', args], { stdio: ['ignore', 'pipe', 'pipe'], cwd: vscode.workspace.rootPath, - windowsVerbatimArguments: true, + windowsVerbatimArguments: true } ); + const stdoutData = new LineBuffer(); this.cargoProcess.stdout.on('data', (s: string) => { - this.processOutput(s, (line) => { + stdoutData.processOutput(s, line => { this.logInfo(line); this.parseLine(line); }); }); + const stderrData = new LineBuffer(); this.cargoProcess.stderr.on('data', (s: string) => { - this.processOutput(s, (line) => { - this.logError('Error on cargo-watch : {\n' + line + '}\n' ); + 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.logError( + 'Error on cargo-watch process : {\n' + err.message + '}\n' + ); }); this.logInfo('cargo-watch started.'); @@ -66,7 +77,7 @@ export class CargoWatchProvider { terminate(this.cargoProcess); } - if(this.outputChannel) { + if (this.outputChannel) { this.outputChannel.dispose(); } } @@ -74,13 +85,16 @@ export class CargoWatchProvider { 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' ) { + if ( + Server.config.cargoWatchOptions.trace === 'error' || + Server.config.cargoWatchOptions.trace === 'verbose' + ) { this.outputChannel!.append(line); - } + } } private parseLine(line: string) { @@ -105,12 +119,32 @@ export class CargoWatchProvider { return vscode.DiagnosticSeverity.Information; } + interface ErrorSpan { + line_start: number; + line_end: number; + column_start: number; + column_end: number; + } + + interface ErrorMessage { + reason: string; + message: { + spans: ErrorSpan[]; + rendered: string; + level: string; + code?: { + code: string; + }; + }; + } + // cargo-watch itself output non json format // Ignore these lines - let data = null; + let data: ErrorMessage; try { data = JSON.parse(line.trim()); } catch (error) { + this.logError(`Fail to pass to json : { ${error} }`); return; } @@ -137,7 +171,9 @@ export class CargoWatchProvider { const diagnostic = new vscode.Diagnostic(range, rendered, level); diagnostic.source = 'rustc'; - diagnostic.code = data.message.code.code; + diagnostic.code = data.message.code + ? data.message.code.code + : undefined; diagnostic.relatedInformation = []; const fileUrl = vscode.Uri.file(fileName!); @@ -150,18 +186,4 @@ export class CargoWatchProvider { this.diagnosticCollection!.set(fileUrl, diagnostics); } } - - private processOutput(chunk: string, cb: (line: string) => void ) { - // The stdout is not line based, convert it to line based for proceess. - this.outBuffer += chunk; - let eolIndex = this.outBuffer.indexOf('\n'); - while (eolIndex >= 0) { - // line includes the EOL - const line = this.outBuffer.slice(0, eolIndex + 1); - cb(line); - this.outBuffer = this.outBuffer.slice(eolIndex + 1); - - eolIndex = this.outBuffer.indexOf('\n'); - } - } } diff --git a/editors/code/src/commands/line_buffer.ts b/editors/code/src/commands/line_buffer.ts new file mode 100644 index 000000000..fb5b9f7f2 --- /dev/null +++ b/editors/code/src/commands/line_buffer.ts @@ -0,0 +1,16 @@ +export class LineBuffer { + private outBuffer: string = ''; + + public processOutput(chunk: string, cb: (line: string) => void) { + this.outBuffer += chunk; + let eolIndex = this.outBuffer.indexOf('\n'); + while (eolIndex >= 0) { + // line includes the EOL + const line = this.outBuffer.slice(0, eolIndex + 1); + cb(line); + this.outBuffer = this.outBuffer.slice(eolIndex + 1); + + eolIndex = this.outBuffer.indexOf('\n'); + } + } +} diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index c95d13878..481a5e5f1 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts @@ -8,16 +8,21 @@ export type CargoWatchStartupOptions = 'ask' | 'enabled' | 'disabled'; export type CargoWatchTraceOptions = 'off' | 'error' | 'verbose'; export interface CargoWatchOptions { - enableOnStartup: CargoWatchStartupOptions, - trace: CargoWatchTraceOptions, -}; + enableOnStartup: CargoWatchStartupOptions; + checkArguments: string; + trace: CargoWatchTraceOptions; +} export class Config { public highlightingOn = true; public enableEnhancedTyping = true; public raLspServerPath = RA_LSP_DEBUG || 'ra_lsp_server'; public showWorkspaceLoadedNotification = true; - public cargoWatchOptions: CargoWatchOptions = { enableOnStartup: 'ask', trace: 'off' }; + public cargoWatchOptions: CargoWatchOptions = { + enableOnStartup: 'ask', + trace: 'off', + checkArguments: '' + }; private prevEnhancedTyping: null | boolean = null; @@ -79,17 +84,23 @@ export class Config { } if (config.has('enableCargoWatchOnStartup')) { - this.cargoWatchOptions.enableOnStartup = - config.get( - 'enableCargoWatchOnStartup', - 'ask' - ); - this.cargoWatchOptions.trace = - config.get( - 'trace.cargo-watch', - 'off' - ); + this.cargoWatchOptions.enableOnStartup = config.get< + CargoWatchStartupOptions + >('enableCargoWatchOnStartup', 'ask'); + } + + if (config.has('trace.cargo-watch')) { + this.cargoWatchOptions.trace = config.get( + 'trace.cargo-watch', + 'off' + ); + } + if (config.has('cargo-watch.check-arguments')) { + this.cargoWatchOptions.checkArguments = config.get( + 'cargo-watch.check-arguments', + '' + ); } } } diff --git a/editors/code/src/utils/processes.ts b/editors/code/src/utils/processes.ts index 09fdf6e24..d4c2c8778 100644 --- a/editors/code/src/utils/processes.ts +++ b/editors/code/src/utils/processes.ts @@ -5,36 +5,40 @@ import ChildProcess = cp.ChildProcess; import { join } from 'path'; -const isWindows = (process.platform === 'win32'); -const isMacintosh = (process.platform === 'darwin'); -const isLinux = (process.platform === 'linux'); +const isWindows = process.platform === 'win32'; +const isMacintosh = process.platform === 'darwin'; +const isLinux = process.platform === 'linux'; export function terminate(process: ChildProcess, cwd?: string): boolean { - if (isWindows) { - try { - // This we run in Atom execFileSync is available. - // Ignore stderr since this is otherwise piped to parent.stderr - // which might be already closed. - const options: any = { - stdio: ['pipe', 'pipe', 'ignore'] - }; - if (cwd) { - options.cwd = cwd - } - (cp).execFileSync('taskkill', ['/T', '/F', '/PID', process.pid.toString()], options); - return true; - } catch (err) { - return false; - } - } else if (isLinux || isMacintosh) { - try { - const cmd = join(__dirname, 'terminateProcess.sh'); - const result = cp.spawnSync(cmd, [process.pid.toString()]); - return result.error ? false : true; - } catch (err) { - return false; - } - } else { - process.kill('SIGKILL'); - return true; - } -} \ No newline at end of file + if (isWindows) { + try { + // This we run in Atom execFileSync is available. + // Ignore stderr since this is otherwise piped to parent.stderr + // which might be already closed. + const options: any = { + stdio: ['pipe', 'pipe', 'ignore'] + }; + if (cwd) { + options.cwd = cwd; + } + cp.execFileSync( + 'taskkill', + ['/T', '/F', '/PID', process.pid.toString()], + options + ); + return true; + } catch (err) { + return false; + } + } else if (isLinux || isMacintosh) { + try { + const cmd = join(__dirname, 'terminateProcess.sh'); + const result = cp.spawnSync(cmd, [process.pid.toString()]); + return result.error ? false : true; + } catch (err) { + return false; + } + } else { + process.kill('SIGKILL'); + return true; + } +} -- cgit v1.2.3