aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--editors/code/src/cargo.ts103
-rw-r--r--editors/code/src/commands/runnables.ts47
2 files changed, 138 insertions, 12 deletions
diff --git a/editors/code/src/cargo.ts b/editors/code/src/cargo.ts
new file mode 100644
index 000000000..d119b6225
--- /dev/null
+++ b/editors/code/src/cargo.ts
@@ -0,0 +1,103 @@
1import { window } from 'vscode';
2import * as cp from 'child_process';
3import * as readline from 'readline';
4
5interface CompilationArtifact {
6 fileName: string;
7 name: string;
8 kind: string;
9 isTest: boolean;
10}
11
12export class Cargo {
13 rootFolder: string;
14 env?: { [key: string]: string };
15
16 public constructor(cargoTomlFolder: string) {
17 this.rootFolder = cargoTomlFolder;
18 }
19
20 public async artifactsFromArgs(cargoArgs: string[]): Promise<CompilationArtifact[]> {
21 let artifacts: CompilationArtifact[] = [];
22
23 try {
24 await this.runCargo(cargoArgs,
25 message => {
26 if (message.reason == 'compiler-artifact' && message.executable) {
27 let isBinary = message.target.crate_types.includes('bin');
28 let isBuildScript = message.target.kind.includes('custom-build');
29 if ((isBinary && !isBuildScript) || message.profile.test) {
30 artifacts.push({
31 fileName: message.executable,
32 name: message.target.name,
33 kind: message.target.kind[0],
34 isTest: message.profile.test
35 })
36 }
37 }
38 },
39 _stderr => {
40 // TODO: to output
41 }
42 );
43 }
44 catch (err) {
45 // TODO: to output
46 throw new Error(`Cargo invocation has failed: ${err}`);
47 }
48
49 return artifacts;
50 }
51
52 public async executableFromArgs(cargoArgs: string[], extraArgs?: string[]): Promise<string> {
53 cargoArgs.push("--message-format=json");
54 if (extraArgs) {
55 cargoArgs.push('--');
56 cargoArgs.push(...extraArgs);
57 }
58
59 let artifacts = await this.artifactsFromArgs(cargoArgs);
60
61 if (artifacts.length == 0 ) {
62 throw new Error('No compilation artifacts');
63 } else if (artifacts.length > 1) {
64 throw new Error('Multiple compilation artifacts are not supported.');
65 }
66
67 return artifacts[0].fileName;
68 }
69
70 runCargo(
71 cargoArgs: string[],
72 onStdoutJson: (obj: any) => void,
73 onStderrString: (data: string) => void
74 ): Promise<number> {
75 return new Promise<number>((resolve, reject) => {
76 let cargo = cp.spawn('cargo', cargoArgs, {
77 stdio: ['ignore', 'pipe', 'pipe'],
78 cwd: this.rootFolder,
79 env: this.env,
80 });
81
82 cargo.on('error', err => {
83 reject(new Error(`could not launch cargo: ${err}`));
84 });
85 cargo.stderr.on('data', chunk => {
86 onStderrString(chunk.toString());
87 });
88
89 let rl = readline.createInterface({ input: cargo.stdout });
90 rl.on('line', line => {
91 let message = JSON.parse(line);
92 onStdoutJson(message);
93 });
94
95 cargo.on('exit', (exitCode, _) => {
96 if (exitCode == 0)
97 resolve(exitCode);
98 else
99 reject(new Error(`exit code: ${exitCode}.`));
100 });
101 });
102 }
103} \ No newline at end of file
diff --git a/editors/code/src/commands/runnables.ts b/editors/code/src/commands/runnables.ts
index 2635a1440..26db18156 100644
--- a/editors/code/src/commands/runnables.ts
+++ b/editors/code/src/commands/runnables.ts
@@ -3,6 +3,7 @@ import * as lc from 'vscode-languageclient';
3import * as ra from '../rust-analyzer-api'; 3import * as ra from '../rust-analyzer-api';
4 4
5import { Ctx, Cmd } from '../ctx'; 5import { Ctx, Cmd } from '../ctx';
6import { Cargo } from '../cargo';
6 7
7export function run(ctx: Ctx): Cmd { 8export function run(ctx: Ctx): Cmd {
8 let prevRunnable: RunnableQuickPick | undefined; 9 let prevRunnable: RunnableQuickPick | undefined;
@@ -62,25 +63,47 @@ export function runSingle(ctx: Ctx): Cmd {
62 }; 63 };
63} 64}
64 65
66function getLldbDebugConfig(config: ra.Runnable) : vscode.DebugConfiguration {
67 return {
68 type: "lldb",
69 request: "launch",
70 name: config.label,
71 cargo: {
72 args: config.args,
73 },
74 args: config.extraArgs,
75 cwd: config.cwd
76 };
77}
78
79async function getCppvsDebugConfig(config: ra.Runnable) : Promise<vscode.DebugConfiguration> {
80 let cargo = new Cargo(config.cwd || '.');
81 let executable = await cargo.executableFromArgs(config.args, config.extraArgs);
82
83 return {
84 type: "cppvsdbg",
85 request: "launch",
86 name: config.label,
87 program: executable,
88 args: config.extraArgs,
89 cwd: config.cwd,
90 };
91}
92
65export function debugSingle(ctx: Ctx): Cmd { 93export function debugSingle(ctx: Ctx): Cmd {
66 return async (config: ra.Runnable) => { 94 return async (config: ra.Runnable) => {
67 const editor = ctx.activeRustEditor; 95 const editor = ctx.activeRustEditor;
68 if (!editor) return; 96 if (!editor) return;
69 if (!vscode.extensions.getExtension("vadimcn.vscode-lldb")) { 97
70 vscode.window.showErrorMessage("Install `vadimcn.vscode-lldb` extension for debugging"); 98 const mscpp = vscode.extensions.getExtension("ms-vscode.cpptools");
99 const lldb = vscode.extensions.getExtension("vadimcn.vscode-lldb");
100
101 if (!(lldb || mscpp)) {
102 vscode.window.showErrorMessage("Install `vadimcn.vscode-lldb` or `ms-vscode.cpptools` extension for debugging");
71 return; 103 return;
72 } 104 }
73 105
74 const debugConfig = { 106 const debugConfig = lldb ? getLldbDebugConfig(config) : await getCppvsDebugConfig(config);
75 type: "lldb",
76 request: "launch",
77 name: config.label,
78 cargo: {
79 args: config.args,
80 },
81 args: config.extraArgs,
82 cwd: config.cwd
83 };
84 107
85 return vscode.debug.startDebugging(undefined, debugConfig); 108 return vscode.debug.startDebugging(undefined, debugConfig);
86 }; 109 };