Add cargo-watch.check-arguments

This commit is contained in:
Edwin Cheng 2019-04-02 14:43:02 +08:00
parent ee05eafe6c
commit 02e450f354
6 changed files with 139 additions and 74 deletions

View file

@ -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

View file

@ -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"
},

View file

@ -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;
@ -24,32 +24,43 @@ export class CargoWatchProvider {
'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) => {
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.');
@ -78,7 +89,10 @@ export class CargoWatchProvider {
}
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);
}
}
@ -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');
}
}
}

View file

@ -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');
}
}
}

View file

@ -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<CargoWatchStartupOptions>(
'enableCargoWatchOnStartup',
'ask'
);
this.cargoWatchOptions.trace =
config.get<CargoWatchTraceOptions>(
this.cargoWatchOptions.enableOnStartup = config.get<
CargoWatchStartupOptions
>('enableCargoWatchOnStartup', 'ask');
}
if (config.has('trace.cargo-watch')) {
this.cargoWatchOptions.trace = config.get<CargoWatchTraceOptions>(
'trace.cargo-watch',
'off'
);
}
if (config.has('cargo-watch.check-arguments')) {
this.cargoWatchOptions.checkArguments = config.get<string>(
'cargo-watch.check-arguments',
''
);
}
}
}

View file

@ -5,9 +5,9 @@ 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 {
@ -18,9 +18,13 @@ export function terminate(process: ChildProcess, cwd?: string): boolean {
stdio: ['pipe', 'pipe', 'ignore']
};
if (cwd) {
options.cwd = cwd
options.cwd = cwd;
}
(cp).execFileSync('taskkill', ['/T', '/F', '/PID', process.pid.toString()], options);
cp.execFileSync(
'taskkill',
['/T', '/F', '/PID', process.pid.toString()],
options
);
return true;
} catch (err) {
return false;