From b3683df0cd67ca97c83f5a7ea58a780dbe4e1b8e Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Sun, 31 Mar 2019 20:00:50 +0800 Subject: Improve cargo-watch usage --- editors/code/src/commands/cargo_watch.ts | 168 +++++++++++++++++++++++++++++++ editors/code/src/commands/runnables.ts | 29 ++---- 2 files changed, 175 insertions(+), 22 deletions(-) create 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 new file mode 100644 index 000000000..55a1909cb --- /dev/null +++ b/editors/code/src/commands/cargo_watch.ts @@ -0,0 +1,168 @@ +import * as child_process from 'child_process'; +import * as path from 'path'; +import * as vscode from 'vscode'; +import { setInterval } from 'timers'; + +const spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']; + +class StatusDisplay { + private i = 0; + private statusBarItem: vscode.StatusBarItem; + private timer?: NodeJS.Timeout; + + constructor(subscriptions: vscode.Disposable[]) { + this.statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 10); + subscriptions.push(this.statusBarItem); + this.statusBarItem.hide(); + } + + public show() { + this.timer = this.timer || setInterval(() => { + this.statusBarItem!.text = "cargo check " + this.frame(); + }, 300); + + this.statusBarItem!.show(); + } + + public hide() { + if(this.timer) { + clearInterval(this.timer); + this.timer = undefined; + } + + this.statusBarItem!.hide(); + } + + frame() { + return spinnerFrames[this.i = ++this.i % spinnerFrames.length]; + } +} + +export class CargoWatchProvider { + private diagnosticCollection?: vscode.DiagnosticCollection; + private cargoProcess?: child_process.ChildProcess; + private outBuffer: string = ""; + private statusDisplay? : StatusDisplay; + + constructor() { + } + + public activate(subscriptions: vscode.Disposable[]) { + subscriptions.push(this); + this.diagnosticCollection = vscode.languages.createDiagnosticCollection("rustc"); + + this.statusDisplay = new StatusDisplay(subscriptions); + + // Start the cargo watch with json message + this.cargoProcess = child_process.spawn('cargo', + ["watch", "-x", "\"check --message-format json\""], + { + // stdio: ['ignore', 'pipe', 'ignore'], + shell: true, + cwd: vscode.workspace.rootPath, + }); + + + this.cargoProcess.stdout.on('data', (s: string) => { + this.processOutput(s); + }); + + this.cargoProcess.stderr.on('data', (s: string) => { + console.error('Error on cargo watch : ' + s); + }); + + this.cargoProcess.on('error', (err: Error) => { + console.error('Error on spawn cargo process : ' + err); + }); + } + + public dispose(): void { + if (this.diagnosticCollection) { + this.diagnosticCollection.clear(); + this.diagnosticCollection.dispose(); + } + + if (this.cargoProcess) { + this.cargoProcess.kill(); + } + } + + parseLine(line: string) { + if (line.startsWith("[Running")) { + this.diagnosticCollection!.clear(); + this.statusDisplay!.show(); + } + + if (line.startsWith("[Finished running")) { + this.statusDisplay!.hide(); + } + + function getLevel(s: string): vscode.DiagnosticSeverity { + if (s === "error") + return vscode.DiagnosticSeverity.Error; + + if (s.startsWith("warn")) + return vscode.DiagnosticSeverity.Warning; + + return vscode.DiagnosticSeverity.Information; + } + + // cargo-watch itself output non json format + // Ignore these lines + let data = null; + try { + data = JSON.parse(line.trim()); + } catch (error) { + return; + } + + // Only handle compiler-message now + if (data.reason !== "compiler-message") { + return; + } + + let spans: any[] = data.message.spans; + spans = spans.filter(o => o.is_primary); + let file_name = null; + + // We only handle primary span right now. + if (spans.length > 0) { + let o = spans[0]; + + console.log("o", o); + let rendered = data.message.rendered; + let level = getLevel(data.message.level); + let range = new vscode.Range( + new vscode.Position(o.line_start - 1, o.column_start - 1), + new vscode.Position(o.line_end - 1, o.column_end - 1) + ); + + file_name = path.join(vscode.workspace.rootPath!, o.file_name); + const diagnostic = new vscode.Diagnostic(range, rendered, level); + + diagnostic.source = 'rustc'; + diagnostic.code = data.message.code.code; + diagnostic.relatedInformation = []; + + let fileUrl = vscode.Uri.file(file_name!); + + let diagnostics: vscode.Diagnostic[] = [...(this.diagnosticCollection!.get(fileUrl) || [])]; + diagnostics.push(diagnostic); + + this.diagnosticCollection!.set(fileUrl, diagnostics); + } + } + + processOutput(chunk: string) { + // The stdout is not line based, convert it to line based for proceess. + this.outBuffer += chunk; + let eolIndex; + while ((eolIndex = this.outBuffer.indexOf('\n')) >= 0) { + // line includes the EOL + const line = this.outBuffer.slice(0, eolIndex + 1); + this.parseLine(line); + this.outBuffer = this.outBuffer.slice(eolIndex + 1); + } + } + +} diff --git a/editors/code/src/commands/runnables.ts b/editors/code/src/commands/runnables.ts index 4187ef4d1..722db158a 100644 --- a/editors/code/src/commands/runnables.ts +++ b/editors/code/src/commands/runnables.ts @@ -1,9 +1,11 @@ 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 } from './cargo_watch'; interface RunnablesParams { textDocument: lc.TextDocumentIdentifier; @@ -127,32 +129,13 @@ export async function handleSingle(runnable: Runnable) { return vscode.tasks.executeTask(task); } -export const autoCargoWatchTask: vscode.Task = { - name: 'cargo watch', - source: 'rust-analyzer', - definition: { - type: 'watch' - }, - execution: new vscode.ShellExecution('cargo', ['watch'], { cwd: '.' }), - - isBackground: true, - problemMatchers: ['$rustc-watch'], - presentationOptions: { - clear: true - }, - // Not yet exposed in the vscode.d.ts - // https://github.com/Microsoft/vscode/blob/ea7c31d770e04b51d586b0d3944f3a7feb03afb9/src/vs/workbench/contrib/tasks/common/tasks.ts#L444-L456 - runOptions: ({ - runOn: 2 // RunOnOptions.folderOpen - } as unknown) as vscode.RunOptions -}; - /** * 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() { +export async function interactivelyStartCargoWatch(context: vscode.ExtensionContext) { + if (Server.config.enableCargoWatchOnStartup === 'disabled') { return; } @@ -212,5 +195,7 @@ export async function interactivelyStartCargoWatch() { } } - vscode.tasks.executeTask(autoCargoWatchTask); + + let validater = new CargoWatchProvider(); + validater.activate(context.subscriptions); } -- cgit v1.2.3 From ac8f35019bd6224a0c2b085381dde2efc8888dc1 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Sun, 31 Mar 2019 20:51:17 +0800 Subject: Fix tslint error --- editors/code/src/commands/cargo_watch.ts | 91 ++++++++++--------------------- editors/code/src/commands/watch_status.ts | 37 +++++++++++++ 2 files changed, 65 insertions(+), 63 deletions(-) create mode 100644 editors/code/src/commands/watch_status.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 index 55a1909cb..c6ce6ba06 100644 --- a/editors/code/src/commands/cargo_watch.ts +++ b/editors/code/src/commands/cargo_watch.ts @@ -1,61 +1,24 @@ import * as child_process from 'child_process'; import * as path from 'path'; +import * as timers from 'timers'; import * as vscode from 'vscode'; -import { setInterval } from 'timers'; - -const spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']; - -class StatusDisplay { - private i = 0; - private statusBarItem: vscode.StatusBarItem; - private timer?: NodeJS.Timeout; - - constructor(subscriptions: vscode.Disposable[]) { - this.statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 10); - subscriptions.push(this.statusBarItem); - this.statusBarItem.hide(); - } - - public show() { - this.timer = this.timer || setInterval(() => { - this.statusBarItem!.text = "cargo check " + this.frame(); - }, 300); - - this.statusBarItem!.show(); - } - - public hide() { - if(this.timer) { - clearInterval(this.timer); - this.timer = undefined; - } - - this.statusBarItem!.hide(); - } - - frame() { - return spinnerFrames[this.i = ++this.i % spinnerFrames.length]; - } -} +import {StatusDisplay} from './watch_status'; export class CargoWatchProvider { private diagnosticCollection?: vscode.DiagnosticCollection; private cargoProcess?: child_process.ChildProcess; - private outBuffer: string = ""; - private statusDisplay? : StatusDisplay; - - constructor() { - } + private outBuffer: string = ''; + private statusDisplay?: StatusDisplay; public activate(subscriptions: vscode.Disposable[]) { subscriptions.push(this); - this.diagnosticCollection = vscode.languages.createDiagnosticCollection("rustc"); + this.diagnosticCollection = vscode.languages.createDiagnosticCollection('rustc'); this.statusDisplay = new StatusDisplay(subscriptions); // Start the cargo watch with json message this.cargoProcess = child_process.spawn('cargo', - ["watch", "-x", "\"check --message-format json\""], + ['watch', '-x', '\"check --message-format json\"'], { // stdio: ['ignore', 'pipe', 'ignore'], shell: true, @@ -68,11 +31,11 @@ export class CargoWatchProvider { }); this.cargoProcess.stderr.on('data', (s: string) => { - console.error('Error on cargo watch : ' + s); + // console.error('Error on cargo watch : ' + s); }); this.cargoProcess.on('error', (err: Error) => { - console.error('Error on spawn cargo process : ' + err); + // console.error('Error on spawn cargo process : ' + err); }); } @@ -87,22 +50,24 @@ export class CargoWatchProvider { } } - parseLine(line: string) { - if (line.startsWith("[Running")) { + private parseLine(line: string) { + if (line.startsWith('[Running')) { this.diagnosticCollection!.clear(); this.statusDisplay!.show(); } - if (line.startsWith("[Finished running")) { + if (line.startsWith('[Finished running')) { this.statusDisplay!.hide(); } function getLevel(s: string): vscode.DiagnosticSeverity { - if (s === "error") + if (s === 'error') { return vscode.DiagnosticSeverity.Error; + } - if (s.startsWith("warn")) + if (s.startsWith('warn')) { return vscode.DiagnosticSeverity.Warning; + } return vscode.DiagnosticSeverity.Information; } @@ -117,51 +82,51 @@ export class CargoWatchProvider { } // Only handle compiler-message now - if (data.reason !== "compiler-message") { + if (data.reason !== 'compiler-message') { return; } let spans: any[] = data.message.spans; spans = spans.filter(o => o.is_primary); - let file_name = null; // We only handle primary span right now. if (spans.length > 0) { - let o = spans[0]; + const o = spans[0]; - console.log("o", o); - let rendered = data.message.rendered; - let level = getLevel(data.message.level); - let range = new vscode.Range( + const rendered = data.message.rendered; + const level = getLevel(data.message.level); + const range = new vscode.Range( new vscode.Position(o.line_start - 1, o.column_start - 1), new vscode.Position(o.line_end - 1, o.column_end - 1) ); - file_name = path.join(vscode.workspace.rootPath!, o.file_name); + const fileName = path.join(vscode.workspace.rootPath!, o.file_name); const diagnostic = new vscode.Diagnostic(range, rendered, level); diagnostic.source = 'rustc'; diagnostic.code = data.message.code.code; diagnostic.relatedInformation = []; - let fileUrl = vscode.Uri.file(file_name!); + const fileUrl = vscode.Uri.file(fileName!); - let diagnostics: vscode.Diagnostic[] = [...(this.diagnosticCollection!.get(fileUrl) || [])]; + const diagnostics: vscode.Diagnostic[] = [...(this.diagnosticCollection!.get(fileUrl) || [])]; diagnostics.push(diagnostic); this.diagnosticCollection!.set(fileUrl, diagnostics); } } - processOutput(chunk: string) { + private processOutput(chunk: string) { // The stdout is not line based, convert it to line based for proceess. this.outBuffer += chunk; - let eolIndex; - while ((eolIndex = this.outBuffer.indexOf('\n')) >= 0) { + let eolIndex = this.outBuffer.indexOf('\n'); + while (eolIndex >= 0) { // line includes the EOL const line = this.outBuffer.slice(0, eolIndex + 1); this.parseLine(line); this.outBuffer = this.outBuffer.slice(eolIndex + 1); + + eolIndex = this.outBuffer.indexOf('\n'); } } diff --git a/editors/code/src/commands/watch_status.ts b/editors/code/src/commands/watch_status.ts new file mode 100644 index 000000000..0943e8533 --- /dev/null +++ b/editors/code/src/commands/watch_status.ts @@ -0,0 +1,37 @@ +import * as timers from 'timers'; +import * as vscode from 'vscode'; + +const spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']; + +export class StatusDisplay { + private i = 0; + private statusBarItem: vscode.StatusBarItem; + private timer?: NodeJS.Timeout; + + constructor(subscriptions: vscode.Disposable[]) { + this.statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 10); + subscriptions.push(this.statusBarItem); + this.statusBarItem.hide(); + } + + public show() { + this.timer = this.timer || setInterval(() => { + this.statusBarItem!.text = 'cargo check ' + this.frame(); + }, 300); + + this.statusBarItem!.show(); + } + + public hide() { + if (this.timer) { + clearInterval(this.timer); + this.timer = undefined; + } + + this.statusBarItem!.hide(); + } + + private frame() { + return spinnerFrames[this.i = ++this.i % spinnerFrames.length]; + } +} \ No newline at end of file -- cgit v1.2.3 From 6971c7f1185fb7c1c0ce5f19867b999de71b5937 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Sun, 31 Mar 2019 21:01:51 +0800 Subject: Fixed tslint error --- editors/code/src/commands/runnables.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'editors/code/src/commands') diff --git a/editors/code/src/commands/runnables.ts b/editors/code/src/commands/runnables.ts index 722db158a..0adb85d5f 100644 --- a/editors/code/src/commands/runnables.ts +++ b/editors/code/src/commands/runnables.ts @@ -196,6 +196,6 @@ export async function interactivelyStartCargoWatch(context: vscode.ExtensionCont } - let validater = new CargoWatchProvider(); + const validater = new CargoWatchProvider(); validater.activate(context.subscriptions); } -- cgit v1.2.3 From c894a3e19b0e658622a03a7d0539a78a433b42ae Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Sun, 31 Mar 2019 21:21:14 +0800 Subject: Fix prettier error --- editors/code/src/commands/cargo_watch.ts | 26 +++++++++++++++----------- editors/code/src/commands/runnables.ts | 8 ++++---- editors/code/src/commands/watch_status.ts | 17 +++++++++++------ 3 files changed, 30 insertions(+), 21 deletions(-) (limited to 'editors/code/src/commands') diff --git a/editors/code/src/commands/cargo_watch.ts b/editors/code/src/commands/cargo_watch.ts index c6ce6ba06..037f1e302 100644 --- a/editors/code/src/commands/cargo_watch.ts +++ b/editors/code/src/commands/cargo_watch.ts @@ -2,7 +2,7 @@ import * as child_process from 'child_process'; import * as path from 'path'; import * as timers from 'timers'; import * as vscode from 'vscode'; -import {StatusDisplay} from './watch_status'; +import { StatusDisplay } from './watch_status'; export class CargoWatchProvider { private diagnosticCollection?: vscode.DiagnosticCollection; @@ -12,19 +12,22 @@ export class CargoWatchProvider { public activate(subscriptions: vscode.Disposable[]) { subscriptions.push(this); - this.diagnosticCollection = vscode.languages.createDiagnosticCollection('rustc'); + this.diagnosticCollection = vscode.languages.createDiagnosticCollection( + 'rustc' + ); this.statusDisplay = new StatusDisplay(subscriptions); - // Start the cargo watch with json message - this.cargoProcess = child_process.spawn('cargo', - ['watch', '-x', '\"check --message-format json\"'], + // Start the cargo watch with json message + this.cargoProcess = child_process.spawn( + 'cargo', + ['watch', '-x', '"check --message-format json"'], { - // stdio: ['ignore', 'pipe', 'ignore'], + // stdio: ['ignore', 'pipe', 'ignore'], shell: true, - cwd: vscode.workspace.rootPath, - }); - + cwd: vscode.workspace.rootPath + } + ); this.cargoProcess.stdout.on('data', (s: string) => { this.processOutput(s); @@ -109,7 +112,9 @@ export class CargoWatchProvider { const fileUrl = vscode.Uri.file(fileName!); - const diagnostics: vscode.Diagnostic[] = [...(this.diagnosticCollection!.get(fileUrl) || [])]; + const diagnostics: vscode.Diagnostic[] = [ + ...(this.diagnosticCollection!.get(fileUrl) || []) + ]; diagnostics.push(diagnostic); this.diagnosticCollection!.set(fileUrl, diagnostics); @@ -129,5 +134,4 @@ export class CargoWatchProvider { eolIndex = this.outBuffer.indexOf('\n'); } } - } diff --git a/editors/code/src/commands/runnables.ts b/editors/code/src/commands/runnables.ts index 0adb85d5f..7bba6f9cb 100644 --- a/editors/code/src/commands/runnables.ts +++ b/editors/code/src/commands/runnables.ts @@ -134,8 +134,9 @@ export async function handleSingle(runnable: Runnable) { * 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) { - +export async function interactivelyStartCargoWatch( + context: vscode.ExtensionContext +) { if (Server.config.enableCargoWatchOnStartup === 'disabled') { return; } @@ -195,7 +196,6 @@ export async function interactivelyStartCargoWatch(context: vscode.ExtensionCont } } - const validater = new CargoWatchProvider(); - validater.activate(context.subscriptions); + validater.activate(context.subscriptions); } diff --git a/editors/code/src/commands/watch_status.ts b/editors/code/src/commands/watch_status.ts index 0943e8533..1b0611ce3 100644 --- a/editors/code/src/commands/watch_status.ts +++ b/editors/code/src/commands/watch_status.ts @@ -9,15 +9,20 @@ export class StatusDisplay { private timer?: NodeJS.Timeout; constructor(subscriptions: vscode.Disposable[]) { - this.statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 10); + this.statusBarItem = vscode.window.createStatusBarItem( + vscode.StatusBarAlignment.Left, + 10 + ); subscriptions.push(this.statusBarItem); this.statusBarItem.hide(); } public show() { - this.timer = this.timer || setInterval(() => { - this.statusBarItem!.text = 'cargo check ' + this.frame(); - }, 300); + this.timer = + this.timer || + setInterval(() => { + this.statusBarItem!.text = 'cargo check ' + this.frame(); + }, 300); this.statusBarItem!.show(); } @@ -32,6 +37,6 @@ export class StatusDisplay { } private frame() { - return spinnerFrames[this.i = ++this.i % spinnerFrames.length]; + return spinnerFrames[(this.i = ++this.i % spinnerFrames.length)]; } -} \ No newline at end of file +} -- cgit v1.2.3 From b84d0fc1a307f6103ea2c2620a106db821696434 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Tue, 2 Apr 2019 01:11:22 +0800 Subject: Add proper process teminate method --- editors/code/src/commands/cargo_watch.ts | 17 ++++++++++------- editors/code/src/commands/watch_status.ts | 1 - 2 files changed, 10 insertions(+), 8 deletions(-) (limited to 'editors/code/src/commands') diff --git a/editors/code/src/commands/cargo_watch.ts b/editors/code/src/commands/cargo_watch.ts index 037f1e302..e51cac78a 100644 --- a/editors/code/src/commands/cargo_watch.ts +++ b/editors/code/src/commands/cargo_watch.ts @@ -1,9 +1,10 @@ import * as child_process from 'child_process'; import * as path from 'path'; -import * as timers from 'timers'; import * as vscode from 'vscode'; +import { terminate } from '../utils/processes'; import { StatusDisplay } from './watch_status'; + export class CargoWatchProvider { private diagnosticCollection?: vscode.DiagnosticCollection; private cargoProcess?: child_process.ChildProcess; @@ -21,24 +22,25 @@ export class CargoWatchProvider { // Start the cargo watch with json message this.cargoProcess = child_process.spawn( 'cargo', - ['watch', '-x', '"check --message-format json"'], + ['watch', '-x', '\"check --message-format json\"'], { - // stdio: ['ignore', 'pipe', 'ignore'], - shell: true, - cwd: vscode.workspace.rootPath + stdio: ['ignore', 'pipe', 'pipe'], + cwd: vscode.workspace.rootPath, + windowsVerbatimArguments: true, } ); this.cargoProcess.stdout.on('data', (s: string) => { this.processOutput(s); + console.log(s); }); this.cargoProcess.stderr.on('data', (s: string) => { - // console.error('Error on cargo watch : ' + s); + console.error('Error on cargo watch : ' + s); }); this.cargoProcess.on('error', (err: Error) => { - // console.error('Error on spawn cargo process : ' + err); + console.error('Error on spawn cargo process : ' + err); }); } @@ -50,6 +52,7 @@ export class CargoWatchProvider { if (this.cargoProcess) { this.cargoProcess.kill(); + terminate(this.cargoProcess); } } diff --git a/editors/code/src/commands/watch_status.ts b/editors/code/src/commands/watch_status.ts index 1b0611ce3..f027d7bbc 100644 --- a/editors/code/src/commands/watch_status.ts +++ b/editors/code/src/commands/watch_status.ts @@ -1,4 +1,3 @@ -import * as timers from 'timers'; import * as vscode from 'vscode'; const spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']; -- cgit v1.2.3 From ee05eafe6c657c3d3710655e11d88d61bc5febf0 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Tue, 2 Apr 2019 13:07:40 +0800 Subject: Add config for cargo-watch trace --- editors/code/src/commands/cargo_watch.ts | 41 ++++++++++++++++++++++++++------ editors/code/src/commands/runnables.ts | 4 ++-- 2 files changed, 36 insertions(+), 9 deletions(-) (limited to 'editors/code/src/commands') diff --git a/editors/code/src/commands/cargo_watch.ts b/editors/code/src/commands/cargo_watch.ts index e51cac78a..9864ce01a 100644 --- a/editors/code/src/commands/cargo_watch.ts +++ b/editors/code/src/commands/cargo_watch.ts @@ -1,6 +1,7 @@ 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 { StatusDisplay } from './watch_status'; @@ -10,6 +11,7 @@ export class CargoWatchProvider { private cargoProcess?: child_process.ChildProcess; private outBuffer: string = ''; private statusDisplay?: StatusDisplay; + private outputChannel?: vscode.OutputChannel; public activate(subscriptions: vscode.Disposable[]) { subscriptions.push(this); @@ -18,7 +20,10 @@ export class CargoWatchProvider { ); this.statusDisplay = new StatusDisplay(subscriptions); - + this.outputChannel = vscode.window.createOutputChannel( + 'Cargo Watch Trace' + ); + // Start the cargo watch with json message this.cargoProcess = child_process.spawn( 'cargo', @@ -31,17 +36,23 @@ export class CargoWatchProvider { ); this.cargoProcess.stdout.on('data', (s: string) => { - this.processOutput(s); - console.log(s); + this.processOutput(s, (line) => { + this.logInfo(line); + this.parseLine(line); + }); }); this.cargoProcess.stderr.on('data', (s: string) => { - console.error('Error on cargo watch : ' + s); + this.processOutput(s, (line) => { + this.logError('Error on cargo-watch : {\n' + line + '}\n' ); + }); }); this.cargoProcess.on('error', (err: Error) => { - console.error('Error on spawn cargo process : ' + err); + this.logError('Error on cargo-watch process : {\n' + err.message + '}\n'); }); + + this.logInfo('cargo-watch started.'); } public dispose(): void { @@ -54,6 +65,22 @@ export class CargoWatchProvider { this.cargoProcess.kill(); terminate(this.cargoProcess); } + + if(this.outputChannel) { + this.outputChannel.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) { @@ -124,14 +151,14 @@ export class CargoWatchProvider { } } - private processOutput(chunk: string) { + 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); - this.parseLine(line); + cb(line); this.outBuffer = this.outBuffer.slice(eolIndex + 1); eolIndex = this.outBuffer.indexOf('\n'); diff --git a/editors/code/src/commands/runnables.ts b/editors/code/src/commands/runnables.ts index 7bba6f9cb..3589edcee 100644 --- a/editors/code/src/commands/runnables.ts +++ b/editors/code/src/commands/runnables.ts @@ -137,11 +137,11 @@ export async function handleSingle(runnable: Runnable) { export async function interactivelyStartCargoWatch( context: vscode.ExtensionContext ) { - if (Server.config.enableCargoWatchOnStartup === 'disabled') { + if (Server.config.cargoWatchOptions.enableOnStartup === 'disabled') { return; } - if (Server.config.enableCargoWatchOnStartup === 'ask') { + if (Server.config.cargoWatchOptions.enableOnStartup === 'ask') { const watch = await vscode.window.showInformationMessage( 'Start watching changes with cargo? (Executes `cargo watch`, provides inline diagnostics)', 'yes', -- cgit v1.2.3 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 --- editors/code/src/commands/cargo_watch.ts | 78 ++++++++++++++++++++------------ editors/code/src/commands/line_buffer.ts | 16 +++++++ 2 files changed, 66 insertions(+), 28 deletions(-) create mode 100644 editors/code/src/commands/line_buffer.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 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'); + } + } +} -- cgit v1.2.3 From 06053a0a7636b620d36d49678a5d73424e0010e9 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Tue, 2 Apr 2019 14:58:58 +0800 Subject: Add Cargo.toml file check before cargo watch start --- editors/code/src/commands/cargo_watch.ts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'editors/code/src/commands') diff --git a/editors/code/src/commands/cargo_watch.ts b/editors/code/src/commands/cargo_watch.ts index fb8fcaeb3..6d8e4d885 100644 --- a/editors/code/src/commands/cargo_watch.ts +++ b/editors/code/src/commands/cargo_watch.ts @@ -1,4 +1,5 @@ import * as child_process from 'child_process'; +import * as fs from 'fs'; import * as path from 'path'; import * as vscode from 'vscode'; import { Server } from '../server'; @@ -14,6 +15,27 @@ export class CargoWatchProvider { private outputChannel?: vscode.OutputChannel; public activate(subscriptions: vscode.Disposable[]) { + 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; + } + + if (!cargoExists) { + vscode.window.showErrorMessage( + `Couldn\'t find \'Cargo.toml\' in ${cargoTomlFile}` + ); + return; + } + subscriptions.push(this); this.diagnosticCollection = vscode.languages.createDiagnosticCollection( 'rustc' -- cgit v1.2.3