Improve cargo-watch usage
This commit is contained in:
parent
c2912892ef
commit
b3683df0cd
@ -223,18 +223,6 @@
|
|||||||
"${workspaceRoot}"
|
"${workspaceRoot}"
|
||||||
],
|
],
|
||||||
"pattern": "$rustc"
|
"pattern": "$rustc"
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "rustc-watch",
|
|
||||||
"fileLocation": [
|
|
||||||
"relative",
|
|
||||||
"${workspaceRoot}"
|
|
||||||
],
|
|
||||||
"background": {
|
|
||||||
"beginsPattern": "^\\[Running\\b",
|
|
||||||
"endsPattern": "^\\[Finished running\\b"
|
|
||||||
},
|
|
||||||
"pattern": "$rustc"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
168
editors/code/src/commands/cargo_watch.ts
Normal file
168
editors/code/src/commands/cargo_watch.ts
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,9 +1,11 @@
|
|||||||
import * as child_process from 'child_process';
|
import * as child_process from 'child_process';
|
||||||
|
|
||||||
import * as util from 'util';
|
import * as util from 'util';
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import * as lc from 'vscode-languageclient';
|
import * as lc from 'vscode-languageclient';
|
||||||
|
|
||||||
import { Server } from '../server';
|
import { Server } from '../server';
|
||||||
|
import { CargoWatchProvider } from './cargo_watch';
|
||||||
|
|
||||||
interface RunnablesParams {
|
interface RunnablesParams {
|
||||||
textDocument: lc.TextDocumentIdentifier;
|
textDocument: lc.TextDocumentIdentifier;
|
||||||
@ -127,32 +129,13 @@ export async function handleSingle(runnable: Runnable) {
|
|||||||
return vscode.tasks.executeTask(task);
|
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
|
* 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
|
* 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.
|
* 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') {
|
if (Server.config.enableCargoWatchOnStartup === 'disabled') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -212,5 +195,7 @@ export async function interactivelyStartCargoWatch() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vscode.tasks.executeTask(autoCargoWatchTask);
|
|
||||||
|
let validater = new CargoWatchProvider();
|
||||||
|
validater.activate(context.subscriptions);
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ import * as vscode from 'vscode';
|
|||||||
import * as lc from 'vscode-languageclient';
|
import * as lc from 'vscode-languageclient';
|
||||||
|
|
||||||
import * as commands from './commands';
|
import * as commands from './commands';
|
||||||
import { interactivelyStartCargoWatch } from './commands/runnables';
|
import { interactivelyStartCargoWatch} from './commands/runnables';
|
||||||
import { SyntaxTreeContentProvider } from './commands/syntaxTree';
|
import { SyntaxTreeContentProvider } from './commands/syntaxTree';
|
||||||
import * as events from './events';
|
import * as events from './events';
|
||||||
import * as notifications from './notifications';
|
import * as notifications from './notifications';
|
||||||
@ -121,7 +121,7 @@ export function activate(context: vscode.ExtensionContext) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Executing `cargo watch` provides us with inline diagnostics on save
|
// Executing `cargo watch` provides us with inline diagnostics on save
|
||||||
interactivelyStartCargoWatch();
|
interactivelyStartCargoWatch(context);
|
||||||
|
|
||||||
// Start the language server, finally!
|
// Start the language server, finally!
|
||||||
Server.start(allNotifications);
|
Server.start(allNotifications);
|
||||||
|
Loading…
Reference in New Issue
Block a user