aboutsummaryrefslogtreecommitdiff
path: root/editors/code
diff options
context:
space:
mode:
Diffstat (limited to 'editors/code')
-rw-r--r--editors/code/package.json22
-rw-r--r--editors/code/src/commands/cargo_watch.ts102
-rw-r--r--editors/code/src/commands/runnables.ts17
-rw-r--r--editors/code/src/commands/watch_status.ts18
-rw-r--r--editors/code/src/extension.ts25
5 files changed, 129 insertions, 55 deletions
diff --git a/editors/code/package.json b/editors/code/package.json
index a0454191a..83ceb19f7 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -119,6 +119,16 @@
119 "command": "rust-analyzer.reload", 119 "command": "rust-analyzer.reload",
120 "title": "Restart server", 120 "title": "Restart server",
121 "category": "Rust Analyzer" 121 "category": "Rust Analyzer"
122 },
123 {
124 "command": "rust-analyzer.startCargoWatch",
125 "title": "Start Cargo Watch",
126 "category": "Rust Analyzer"
127 },
128 {
129 "command": "rust-analyzer.stopCargoWatch",
130 "title": "Stop Cargo Watch",
131 "category": "Rust Analyzer"
122 } 132 }
123 ], 133 ],
124 "keybindings": [ 134 "keybindings": [
@@ -250,6 +260,18 @@
250 "${workspaceRoot}" 260 "${workspaceRoot}"
251 ], 261 ],
252 "pattern": "$rustc" 262 "pattern": "$rustc"
263 },
264 {
265 "name": "rustc-watch",
266 "fileLocation": [
267 "relative",
268 "${workspaceRoot}"
269 ],
270 "background": {
271 "beginsPattern": "^\\[Running\\b",
272 "endsPattern": "^\\[Finished running\\b"
273 },
274 "pattern": "$rustc"
253 } 275 }
254 ] 276 ]
255 } 277 }
diff --git a/editors/code/src/commands/cargo_watch.ts b/editors/code/src/commands/cargo_watch.ts
index 32bd38a1c..1d939e28c 100644
--- a/editors/code/src/commands/cargo_watch.ts
+++ b/editors/code/src/commands/cargo_watch.ts
@@ -7,44 +7,55 @@ import { terminate } from '../utils/processes';
7import { LineBuffer } from './line_buffer'; 7import { LineBuffer } from './line_buffer';
8import { StatusDisplay } from './watch_status'; 8import { StatusDisplay } from './watch_status';
9 9
10export class CargoWatchProvider { 10export function registerCargoWatchProvider(
11 private diagnosticCollection?: vscode.DiagnosticCollection; 11 subscriptions: vscode.Disposable[]
12 private cargoProcess?: child_process.ChildProcess; 12): CargoWatchProvider | undefined {
13 private outBuffer: string = ''; 13 let cargoExists = false;
14 private statusDisplay?: StatusDisplay; 14 const cargoTomlFile = path.join(vscode.workspace.rootPath!, 'Cargo.toml');
15 private outputChannel?: vscode.OutputChannel; 15 // Check if the working directory is valid cargo root path
16 16 try {
17 public activate(subscriptions: vscode.Disposable[]) { 17 if (fs.existsSync(cargoTomlFile)) {
18 let cargoExists = false; 18 cargoExists = true;
19 const cargoTomlFile = path.join( 19 }
20 vscode.workspace.rootPath!, 20 } catch (err) {
21 'Cargo.toml' 21 cargoExists = false;
22 }
23
24 if (!cargoExists) {
25 vscode.window.showErrorMessage(
26 `Couldn\'t find \'Cargo.toml\' in ${cargoTomlFile}`
22 ); 27 );
23 // Check if the working directory is valid cargo root path 28 return;
24 try { 29 }
25 if (fs.existsSync(cargoTomlFile)) {
26 cargoExists = true;
27 }
28 } catch (err) {
29 cargoExists = false;
30 }
31 30
32 if (!cargoExists) { 31 const provider = new CargoWatchProvider();
33 vscode.window.showErrorMessage( 32 subscriptions.push(provider);
34 `Couldn\'t find \'Cargo.toml\' in ${cargoTomlFile}` 33 return provider;
35 ); 34}
36 return;
37 }
38 35
39 subscriptions.push(this); 36export class CargoWatchProvider implements vscode.Disposable {
37 private readonly diagnosticCollection: vscode.DiagnosticCollection;
38 private readonly statusDisplay: StatusDisplay;
39 private readonly outputChannel: vscode.OutputChannel;
40 private cargoProcess?: child_process.ChildProcess;
41
42 constructor() {
40 this.diagnosticCollection = vscode.languages.createDiagnosticCollection( 43 this.diagnosticCollection = vscode.languages.createDiagnosticCollection(
41 'rustc' 44 'rustc'
42 ); 45 );
43 46 this.statusDisplay = new StatusDisplay();
44 this.statusDisplay = new StatusDisplay(subscriptions);
45 this.outputChannel = vscode.window.createOutputChannel( 47 this.outputChannel = vscode.window.createOutputChannel(
46 'Cargo Watch Trace' 48 'Cargo Watch Trace'
47 ); 49 );
50 }
51
52 public start() {
53 if (this.cargoProcess) {
54 vscode.window.showInformationMessage(
55 'Cargo Watch is already running'
56 );
57 return;
58 }
48 59
49 let args = 'check --message-format json'; 60 let args = 'check --message-format json';
50 if (Server.config.cargoWatchOptions.checkArguments.length > 0) { 61 if (Server.config.cargoWatchOptions.checkArguments.length > 0) {
@@ -95,25 +106,28 @@ export class CargoWatchProvider {
95 this.logInfo('cargo-watch started.'); 106 this.logInfo('cargo-watch started.');
96 } 107 }
97 108
98 public dispose(): void { 109 public stop() {
99 if (this.diagnosticCollection) {
100 this.diagnosticCollection.clear();
101 this.diagnosticCollection.dispose();
102 }
103
104 if (this.cargoProcess) { 110 if (this.cargoProcess) {
105 this.cargoProcess.kill(); 111 this.cargoProcess.kill();
106 terminate(this.cargoProcess); 112 terminate(this.cargoProcess);
113 this.cargoProcess = undefined;
114 } else {
115 vscode.window.showInformationMessage('Cargo Watch is not running');
107 } 116 }
117 }
108 118
109 if (this.outputChannel) { 119 public dispose(): void {
110 this.outputChannel.dispose(); 120 this.stop();
111 } 121
122 this.diagnosticCollection.clear();
123 this.diagnosticCollection.dispose();
124 this.outputChannel.dispose();
125 this.statusDisplay.dispose();
112 } 126 }
113 127
114 private logInfo(line: string) { 128 private logInfo(line: string) {
115 if (Server.config.cargoWatchOptions.trace === 'verbose') { 129 if (Server.config.cargoWatchOptions.trace === 'verbose') {
116 this.outputChannel!.append(line); 130 this.outputChannel.append(line);
117 } 131 }
118 } 132 }
119 133
@@ -122,18 +136,18 @@ export class CargoWatchProvider {
122 Server.config.cargoWatchOptions.trace === 'error' || 136 Server.config.cargoWatchOptions.trace === 'error' ||
123 Server.config.cargoWatchOptions.trace === 'verbose' 137 Server.config.cargoWatchOptions.trace === 'verbose'
124 ) { 138 ) {
125 this.outputChannel!.append(line); 139 this.outputChannel.append(line);
126 } 140 }
127 } 141 }
128 142
129 private parseLine(line: string) { 143 private parseLine(line: string) {
130 if (line.startsWith('[Running')) { 144 if (line.startsWith('[Running')) {
131 this.diagnosticCollection!.clear(); 145 this.diagnosticCollection.clear();
132 this.statusDisplay!.show(); 146 this.statusDisplay.show();
133 } 147 }
134 148
135 if (line.startsWith('[Finished running')) { 149 if (line.startsWith('[Finished running')) {
136 this.statusDisplay!.hide(); 150 this.statusDisplay.hide();
137 } 151 }
138 152
139 function getLevel(s: string): vscode.DiagnosticSeverity { 153 function getLevel(s: string): vscode.DiagnosticSeverity {
@@ -193,7 +207,7 @@ export class CargoWatchProvider {
193 207
194 // The format of the package_id is "{name} {version} ({source_id})", 208 // The format of the package_id is "{name} {version} ({source_id})",
195 // https://github.com/rust-lang/cargo/blob/37ad03f86e895bb80b474c1c088322634f4725f5/src/cargo/core/package_id.rs#L53 209 // https://github.com/rust-lang/cargo/blob/37ad03f86e895bb80b474c1c088322634f4725f5/src/cargo/core/package_id.rs#L53
196 this.statusDisplay!.packageName = msg.package_id.split(' ')[0]; 210 this.statusDisplay.packageName = msg.package_id.split(' ')[0];
197 } else if (data.reason === 'compiler-message') { 211 } else if (data.reason === 'compiler-message') {
198 const msg = data.message as RustDiagnostic; 212 const msg = data.message as RustDiagnostic;
199 213
diff --git a/editors/code/src/commands/runnables.ts b/editors/code/src/commands/runnables.ts
index c4df24c79..26372c1e8 100644
--- a/editors/code/src/commands/runnables.ts
+++ b/editors/code/src/commands/runnables.ts
@@ -5,7 +5,7 @@ import * as vscode from 'vscode';
5import * as lc from 'vscode-languageclient'; 5import * as lc from 'vscode-languageclient';
6 6
7import { Server } from '../server'; 7import { Server } from '../server';
8import { CargoWatchProvider } from './cargo_watch'; 8import { CargoWatchProvider, registerCargoWatchProvider } from './cargo_watch';
9 9
10interface RunnablesParams { 10interface RunnablesParams {
11 textDocument: lc.TextDocumentIdentifier; 11 textDocument: lc.TextDocumentIdentifier;
@@ -137,7 +137,7 @@ export async function handleSingle(runnable: Runnable) {
137 */ 137 */
138export async function interactivelyStartCargoWatch( 138export async function interactivelyStartCargoWatch(
139 context: vscode.ExtensionContext 139 context: vscode.ExtensionContext
140) { 140): Promise<CargoWatchProvider | undefined> {
141 if (Server.config.cargoWatchOptions.enableOnStartup === 'disabled') { 141 if (Server.config.cargoWatchOptions.enableOnStartup === 'disabled') {
142 return; 142 return;
143 } 143 }
@@ -153,6 +153,12 @@ export async function interactivelyStartCargoWatch(
153 } 153 }
154 } 154 }
155 155
156 return startCargoWatch(context);
157}
158
159export async function startCargoWatch(
160 context: vscode.ExtensionContext
161): Promise<CargoWatchProvider | undefined> {
156 const execPromise = util.promisify(child_process.exec); 162 const execPromise = util.promisify(child_process.exec);
157 163
158 const { stderr } = await execPromise('cargo watch --version').catch(e => e); 164 const { stderr } = await execPromise('cargo watch --version').catch(e => e);
@@ -197,6 +203,9 @@ export async function interactivelyStartCargoWatch(
197 } 203 }
198 } 204 }
199 205
200 const validater = new CargoWatchProvider(); 206 const provider = await registerCargoWatchProvider(context.subscriptions);
201 validater.activate(context.subscriptions); 207 if (provider) {
208 provider.start();
209 }
210 return provider;
202} 211}
diff --git a/editors/code/src/commands/watch_status.ts b/editors/code/src/commands/watch_status.ts
index 86ae821de..a3b0178f2 100644
--- a/editors/code/src/commands/watch_status.ts
+++ b/editors/code/src/commands/watch_status.ts
@@ -2,19 +2,18 @@ import * as vscode from 'vscode';
2 2
3const spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']; 3const spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
4 4
5export class StatusDisplay { 5export class StatusDisplay implements vscode.Disposable {
6 public packageName?: string; 6 public packageName?: string;
7 7
8 private i = 0; 8 private i = 0;
9 private statusBarItem: vscode.StatusBarItem; 9 private statusBarItem: vscode.StatusBarItem;
10 private timer?: NodeJS.Timeout; 10 private timer?: NodeJS.Timeout;
11 11
12 constructor(subscriptions: vscode.Disposable[]) { 12 constructor() {
13 this.statusBarItem = vscode.window.createStatusBarItem( 13 this.statusBarItem = vscode.window.createStatusBarItem(
14 vscode.StatusBarAlignment.Left, 14 vscode.StatusBarAlignment.Left,
15 10 15 10
16 ); 16 );
17 subscriptions.push(this.statusBarItem);
18 this.statusBarItem.hide(); 17 this.statusBarItem.hide();
19 } 18 }
20 19
@@ -33,7 +32,7 @@ export class StatusDisplay {
33 } 32 }
34 }, 300); 33 }, 300);
35 34
36 this.statusBarItem!.show(); 35 this.statusBarItem.show();
37 } 36 }
38 37
39 public hide() { 38 public hide() {
@@ -42,7 +41,16 @@ export class StatusDisplay {
42 this.timer = undefined; 41 this.timer = undefined;
43 } 42 }
44 43
45 this.statusBarItem!.hide(); 44 this.statusBarItem.hide();
45 }
46
47 public dispose() {
48 if (this.timer) {
49 clearInterval(this.timer);
50 this.timer = undefined;
51 }
52
53 this.statusBarItem.dispose();
46 } 54 }
47 55
48 private frame() { 56 private frame() {
diff --git a/editors/code/src/extension.ts b/editors/code/src/extension.ts
index 1073a36a0..48dd2a614 100644
--- a/editors/code/src/extension.ts
+++ b/editors/code/src/extension.ts
@@ -2,7 +2,11 @@ import * as vscode from 'vscode';
2import * as lc from 'vscode-languageclient'; 2import * as lc from 'vscode-languageclient';
3 3
4import * as commands from './commands'; 4import * as commands from './commands';
5import { interactivelyStartCargoWatch } from './commands/runnables'; 5import { CargoWatchProvider } from './commands/cargo_watch';
6import {
7 interactivelyStartCargoWatch,
8 startCargoWatch
9} from './commands/runnables';
6import { SyntaxTreeContentProvider } from './commands/syntaxTree'; 10import { SyntaxTreeContentProvider } from './commands/syntaxTree';
7import * as events from './events'; 11import * as events from './events';
8import * as notifications from './notifications'; 12import * as notifications from './notifications';
@@ -126,7 +130,24 @@ export function activate(context: vscode.ExtensionContext) {
126 vscode.commands.registerCommand('rust-analyzer.reload', reloadCommand); 130 vscode.commands.registerCommand('rust-analyzer.reload', reloadCommand);
127 131
128 // Executing `cargo watch` provides us with inline diagnostics on save 132 // Executing `cargo watch` provides us with inline diagnostics on save
129 interactivelyStartCargoWatch(context); 133 let provider: CargoWatchProvider | undefined;
134 interactivelyStartCargoWatch(context).then(p => {
135 provider = p;
136 });
137 registerCommand('rust-analyzer.startCargoWatch', () => {
138 if (provider) {
139 provider.start();
140 } else {
141 startCargoWatch(context).then(p => {
142 provider = p;
143 });
144 }
145 });
146 registerCommand('rust-analyzer.stopCargoWatch', () => {
147 if (provider) {
148 provider.stop();
149 }
150 });
130 151
131 // Start the language server, finally! 152 // Start the language server, finally!
132 startServer(); 153 startServer();