From 48d6e828f1878436bb8633a1e7df02a6383d991a Mon Sep 17 00:00:00 2001 From: vsrs Date: Tue, 28 Apr 2020 17:30:49 +0300 Subject: ms-vscode.cpptools debugger support, initial version. --- editors/code/src/cargo.ts | 103 +++++++++++++++++++++++++++++++++ editors/code/src/commands/runnables.ts | 47 +++++++++++---- 2 files changed, 138 insertions(+), 12 deletions(-) create mode 100644 editors/code/src/cargo.ts (limited to 'editors/code/src') 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 @@ +import { window } from 'vscode'; +import * as cp from 'child_process'; +import * as readline from 'readline'; + +interface CompilationArtifact { + fileName: string; + name: string; + kind: string; + isTest: boolean; +} + +export class Cargo { + rootFolder: string; + env?: { [key: string]: string }; + + public constructor(cargoTomlFolder: string) { + this.rootFolder = cargoTomlFolder; + } + + public async artifactsFromArgs(cargoArgs: string[]): Promise { + let artifacts: CompilationArtifact[] = []; + + try { + await this.runCargo(cargoArgs, + message => { + if (message.reason == 'compiler-artifact' && message.executable) { + let isBinary = message.target.crate_types.includes('bin'); + let isBuildScript = message.target.kind.includes('custom-build'); + if ((isBinary && !isBuildScript) || message.profile.test) { + artifacts.push({ + fileName: message.executable, + name: message.target.name, + kind: message.target.kind[0], + isTest: message.profile.test + }) + } + } + }, + _stderr => { + // TODO: to output + } + ); + } + catch (err) { + // TODO: to output + throw new Error(`Cargo invocation has failed: ${err}`); + } + + return artifacts; + } + + public async executableFromArgs(cargoArgs: string[], extraArgs?: string[]): Promise { + cargoArgs.push("--message-format=json"); + if (extraArgs) { + cargoArgs.push('--'); + cargoArgs.push(...extraArgs); + } + + let artifacts = await this.artifactsFromArgs(cargoArgs); + + if (artifacts.length == 0 ) { + throw new Error('No compilation artifacts'); + } else if (artifacts.length > 1) { + throw new Error('Multiple compilation artifacts are not supported.'); + } + + return artifacts[0].fileName; + } + + runCargo( + cargoArgs: string[], + onStdoutJson: (obj: any) => void, + onStderrString: (data: string) => void + ): Promise { + return new Promise((resolve, reject) => { + let cargo = cp.spawn('cargo', cargoArgs, { + stdio: ['ignore', 'pipe', 'pipe'], + cwd: this.rootFolder, + env: this.env, + }); + + cargo.on('error', err => { + reject(new Error(`could not launch cargo: ${err}`)); + }); + cargo.stderr.on('data', chunk => { + onStderrString(chunk.toString()); + }); + + let rl = readline.createInterface({ input: cargo.stdout }); + rl.on('line', line => { + let message = JSON.parse(line); + onStdoutJson(message); + }); + + cargo.on('exit', (exitCode, _) => { + if (exitCode == 0) + resolve(exitCode); + else + reject(new Error(`exit code: ${exitCode}.`)); + }); + }); + } +} \ 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'; import * as ra from '../rust-analyzer-api'; import { Ctx, Cmd } from '../ctx'; +import { Cargo } from '../cargo'; export function run(ctx: Ctx): Cmd { let prevRunnable: RunnableQuickPick | undefined; @@ -62,25 +63,47 @@ export function runSingle(ctx: Ctx): Cmd { }; } +function getLldbDebugConfig(config: ra.Runnable) : vscode.DebugConfiguration { + return { + type: "lldb", + request: "launch", + name: config.label, + cargo: { + args: config.args, + }, + args: config.extraArgs, + cwd: config.cwd + }; +} + +async function getCppvsDebugConfig(config: ra.Runnable) : Promise { + let cargo = new Cargo(config.cwd || '.'); + let executable = await cargo.executableFromArgs(config.args, config.extraArgs); + + return { + type: "cppvsdbg", + request: "launch", + name: config.label, + program: executable, + args: config.extraArgs, + cwd: config.cwd, + }; +} + export function debugSingle(ctx: Ctx): Cmd { return async (config: ra.Runnable) => { const editor = ctx.activeRustEditor; if (!editor) return; - if (!vscode.extensions.getExtension("vadimcn.vscode-lldb")) { - vscode.window.showErrorMessage("Install `vadimcn.vscode-lldb` extension for debugging"); + + const mscpp = vscode.extensions.getExtension("ms-vscode.cpptools"); + const lldb = vscode.extensions.getExtension("vadimcn.vscode-lldb"); + + if (!(lldb || mscpp)) { + vscode.window.showErrorMessage("Install `vadimcn.vscode-lldb` or `ms-vscode.cpptools` extension for debugging"); return; } - const debugConfig = { - type: "lldb", - request: "launch", - name: config.label, - cargo: { - args: config.args, - }, - args: config.extraArgs, - cwd: config.cwd - }; + const debugConfig = lldb ? getLldbDebugConfig(config) : await getCppvsDebugConfig(config); return vscode.debug.startDebugging(undefined, debugConfig); }; -- cgit v1.2.3