Merge #1079
1079: Improve cargo-watch usage in vscode plugin r=matklad a=edwin0cheng *This PR try to improve current cargo-watch usage in VSCode :* 1. Add Multi-lines error support : ![multilines-error](https://i.imgur.com/gbLEwMG.gif) 2. Add cargo-watch status animation : ![cargo-watch-status](https://i.imgur.com/GbHwzjj.gif) *Implementation Details* * Current VSCode `ProblemMatcher` still do not support multiple line parsing. * However we can, spawn a cargo watch process instead of using vscode.Task to allow more control. * Use `cargo-check --message-format json` to get json format of compiler-message. * Use `vscode.DiagnosticCollection` to manage the problems directly, which allow multiple lines diagnostic. However, * VSCode use non mono-space font for problems, at this moment i cannot find a good solution about it. * I am not so good in typescript, please let me know if anything is bad in this PR. Co-authored-by: Edwin Cheng <edwin0cheng@gmail.com> Co-authored-by: Edwin Cheng <edwin@m-inverse.com>
This commit is contained in:
commit
bb3b159fb7
@ -59,7 +59,10 @@ 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
|
||||
|
||||
|
||||
## Emacs
|
||||
|
51
editors/code/package-lock.json
generated
51
editors/code/package-lock.json
generated
@ -607,6 +607,12 @@
|
||||
"integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==",
|
||||
"dev": true
|
||||
},
|
||||
"es6-object-assign": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz",
|
||||
"integrity": "sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw=",
|
||||
"dev": true
|
||||
},
|
||||
"escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
@ -1121,6 +1127,12 @@
|
||||
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
|
||||
"dev": true
|
||||
},
|
||||
"interpret": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz",
|
||||
"integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==",
|
||||
"dev": true
|
||||
},
|
||||
"is": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/is/-/is-3.3.0.tgz",
|
||||
@ -1791,6 +1803,15 @@
|
||||
"util-deprecate": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"rechoir": {
|
||||
"version": "0.6.2",
|
||||
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
|
||||
"integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"resolve": "^1.1.6"
|
||||
}
|
||||
},
|
||||
"remove-bom-buffer": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz",
|
||||
@ -1902,6 +1923,36 @@
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
|
||||
"integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg=="
|
||||
},
|
||||
"shelljs": {
|
||||
"version": "0.8.3",
|
||||
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.3.tgz",
|
||||
"integrity": "sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"glob": "^7.0.0",
|
||||
"interpret": "^1.0.0",
|
||||
"rechoir": "^0.6.2"
|
||||
}
|
||||
},
|
||||
"shx": {
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/shx/-/shx-0.3.2.tgz",
|
||||
"integrity": "sha512-aS0mWtW3T2sHAenrSrip2XGv39O9dXIFUqxAEWHEOS1ePtGIBavdPJY1kE2IHl14V/4iCbUiNDPGdyYTtmhSoA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"es6-object-assign": "^1.0.3",
|
||||
"minimist": "^1.2.0",
|
||||
"shelljs": "^0.8.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"minimist": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
|
||||
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
|
@ -18,7 +18,7 @@
|
||||
"scripts": {
|
||||
"vscode:prepublish": "npm run compile",
|
||||
"package": "vsce package",
|
||||
"compile": "tsc -p ./",
|
||||
"compile": "tsc -p ./ && shx cp src/utils/terminateProcess.sh out/utils/terminateProcess.sh",
|
||||
"watch": "tsc -watch -p ./",
|
||||
"postinstall": "node ./node_modules/vscode/bin/install",
|
||||
"fix": "prettier **/*.{json,ts} --write && tslint --project . --fix",
|
||||
@ -41,7 +41,8 @@
|
||||
"tslint-config-prettier": "^1.18.0",
|
||||
"typescript": "^3.3.1",
|
||||
"vsce": "^1.57.0",
|
||||
"vscode": "^1.1.29"
|
||||
"vscode": "^1.1.29",
|
||||
"shx": "^0.3.1"
|
||||
},
|
||||
"activationEvents": [
|
||||
"onLanguage:rust",
|
||||
@ -183,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",
|
||||
@ -191,8 +197,24 @@
|
||||
"messages",
|
||||
"verbose"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"No traces",
|
||||
"Error only",
|
||||
"Full log"
|
||||
],
|
||||
"default": "off",
|
||||
"description": "Trace requests to the ra_lsp_server"
|
||||
},
|
||||
"rust-analyzer.trace.cargo-watch": {
|
||||
"type": "string",
|
||||
"scope": "window",
|
||||
"enum": [
|
||||
"off",
|
||||
"error",
|
||||
"verbose"
|
||||
],
|
||||
"default": "off",
|
||||
"description": "Trace output of cargo-watch"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -223,18 +245,6 @@
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"pattern": "$rustc"
|
||||
},
|
||||
{
|
||||
"name": "rustc-watch",
|
||||
"fileLocation": [
|
||||
"relative",
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"background": {
|
||||
"beginsPattern": "^\\[Running\\b",
|
||||
"endsPattern": "^\\[Finished running\\b"
|
||||
},
|
||||
"pattern": "$rustc"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
211
editors/code/src/commands/cargo_watch.ts
Normal file
211
editors/code/src/commands/cargo_watch.ts
Normal file
@ -0,0 +1,211 @@
|
||||
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';
|
||||
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;
|
||||
|
||||
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'
|
||||
);
|
||||
|
||||
this.statusDisplay = new StatusDisplay(subscriptions);
|
||||
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', args],
|
||||
{
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
cwd: vscode.workspace.rootPath,
|
||||
windowsVerbatimArguments: true
|
||||
}
|
||||
);
|
||||
|
||||
const stdoutData = new LineBuffer();
|
||||
this.cargoProcess.stdout.on('data', (s: string) => {
|
||||
stdoutData.processOutput(s, line => {
|
||||
this.logInfo(line);
|
||||
this.parseLine(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 dispose(): void {
|
||||
if (this.diagnosticCollection) {
|
||||
this.diagnosticCollection.clear();
|
||||
this.diagnosticCollection.dispose();
|
||||
}
|
||||
|
||||
if (this.cargoProcess) {
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
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: ErrorMessage;
|
||||
try {
|
||||
data = JSON.parse(line.trim());
|
||||
} catch (error) {
|
||||
this.logError(`Fail to pass to json : { ${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);
|
||||
|
||||
// We only handle primary span right now.
|
||||
if (spans.length > 0) {
|
||||
const o = spans[0];
|
||||
|
||||
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)
|
||||
);
|
||||
|
||||
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
|
||||
? data.message.code.code
|
||||
: undefined;
|
||||
diagnostic.relatedInformation = [];
|
||||
|
||||
const fileUrl = vscode.Uri.file(fileName!);
|
||||
|
||||
const diagnostics: vscode.Diagnostic[] = [
|
||||
...(this.diagnosticCollection!.get(fileUrl) || [])
|
||||
];
|
||||
diagnostics.push(diagnostic);
|
||||
|
||||
this.diagnosticCollection!.set(fileUrl, diagnostics);
|
||||
}
|
||||
}
|
||||
}
|
16
editors/code/src/commands/line_buffer.ts
Normal file
16
editors/code/src/commands/line_buffer.ts
Normal 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');
|
||||
}
|
||||
}
|
||||
}
|
@ -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,37 +129,19 @@ 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() {
|
||||
if (Server.config.enableCargoWatchOnStartup === 'disabled') {
|
||||
export async function interactivelyStartCargoWatch(
|
||||
context: vscode.ExtensionContext
|
||||
) {
|
||||
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',
|
||||
@ -212,5 +196,6 @@ export async function interactivelyStartCargoWatch() {
|
||||
}
|
||||
}
|
||||
|
||||
vscode.tasks.executeTask(autoCargoWatchTask);
|
||||
const validater = new CargoWatchProvider();
|
||||
validater.activate(context.subscriptions);
|
||||
}
|
||||
|
41
editors/code/src/commands/watch_status.ts
Normal file
41
editors/code/src/commands/watch_status.ts
Normal file
@ -0,0 +1,41 @@
|
||||
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)];
|
||||
}
|
||||
}
|
@ -4,14 +4,25 @@ import { Server } from './server';
|
||||
|
||||
const RA_LSP_DEBUG = process.env.__RA_LSP_SERVER_DEBUG;
|
||||
|
||||
export type CargoWatchOptions = 'ask' | 'enabled' | 'disabled';
|
||||
export type CargoWatchStartupOptions = 'ask' | 'enabled' | 'disabled';
|
||||
export type CargoWatchTraceOptions = 'off' | 'error' | 'verbose';
|
||||
|
||||
export interface CargoWatchOptions {
|
||||
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 enableCargoWatchOnStartup: CargoWatchOptions = 'ask';
|
||||
public cargoWatchOptions: CargoWatchOptions = {
|
||||
enableOnStartup: 'ask',
|
||||
trace: 'off',
|
||||
checkArguments: ''
|
||||
};
|
||||
|
||||
private prevEnhancedTyping: null | boolean = null;
|
||||
|
||||
@ -73,9 +84,22 @@ export class Config {
|
||||
}
|
||||
|
||||
if (config.has('enableCargoWatchOnStartup')) {
|
||||
this.enableCargoWatchOnStartup = config.get<CargoWatchOptions>(
|
||||
'enableCargoWatchOnStartup',
|
||||
'ask'
|
||||
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',
|
||||
''
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -121,7 +121,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
);
|
||||
|
||||
// Executing `cargo watch` provides us with inline diagnostics on save
|
||||
interactivelyStartCargoWatch();
|
||||
interactivelyStartCargoWatch(context);
|
||||
|
||||
// Start the language server, finally!
|
||||
Server.start(allNotifications);
|
||||
|
51
editors/code/src/utils/processes.ts
Normal file
51
editors/code/src/utils/processes.ts
Normal file
@ -0,0 +1,51 @@
|
||||
'use strict';
|
||||
|
||||
import * as cp from 'child_process';
|
||||
import ChildProcess = cp.ChildProcess;
|
||||
|
||||
import { join } from 'path';
|
||||
|
||||
const isWindows = process.platform === 'win32';
|
||||
const isMacintosh = process.platform === 'darwin';
|
||||
const isLinux = process.platform === 'linux';
|
||||
|
||||
// this is very complex, but is basically copy-pased from VSCode implementation here:
|
||||
// https://github.com/Microsoft/vscode-languageserver-node/blob/dbfd37e35953ad0ee14c4eeced8cfbc41697b47e/client/src/utils/processes.ts#L15
|
||||
|
||||
// And see discussion at
|
||||
// https://github.com/rust-analyzer/rust-analyzer/pull/1079#issuecomment-478908109
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
12
editors/code/src/utils/terminateProcess.sh
Normal file
12
editors/code/src/utils/terminateProcess.sh
Normal file
@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
terminateTree() {
|
||||
for cpid in $(pgrep -P $1); do
|
||||
terminateTree $cpid
|
||||
done
|
||||
kill -9 $1 > /dev/null 2>&1
|
||||
}
|
||||
|
||||
for pid in $*; do
|
||||
terminateTree $pid
|
||||
done
|
Loading…
Reference in New Issue
Block a user