aboutsummaryrefslogtreecommitdiff
path: root/editors/code/src/debug.ts
diff options
context:
space:
mode:
Diffstat (limited to 'editors/code/src/debug.ts')
-rw-r--r--editors/code/src/debug.ts147
1 files changed, 147 insertions, 0 deletions
diff --git a/editors/code/src/debug.ts b/editors/code/src/debug.ts
new file mode 100644
index 000000000..a0c9b3ab2
--- /dev/null
+++ b/editors/code/src/debug.ts
@@ -0,0 +1,147 @@
1import * as os from "os";
2import * as vscode from 'vscode';
3import * as path from 'path';
4import * as ra from './lsp_ext';
5
6import { Cargo } from './toolchain';
7import { Ctx } from "./ctx";
8
9const debugOutput = vscode.window.createOutputChannel("Debug");
10type DebugConfigProvider = (config: ra.Runnable, executable: string, sourceFileMap?: Record<string, string>) => vscode.DebugConfiguration;
11
12export async function makeDebugConfig(ctx: Ctx, runnable: ra.Runnable): Promise<void> {
13 const scope = ctx.activeRustEditor?.document.uri;
14 if (!scope) return;
15
16 const debugConfig = await getDebugConfiguration(ctx, runnable);
17 if (!debugConfig) return;
18
19 const wsLaunchSection = vscode.workspace.getConfiguration("launch", scope);
20 const configurations = wsLaunchSection.get<any[]>("configurations") || [];
21
22 const index = configurations.findIndex(c => c.name === debugConfig.name);
23 if (index !== -1) {
24 const answer = await vscode.window.showErrorMessage(`Launch configuration '${debugConfig.name}' already exists!`, 'Cancel', 'Update');
25 if (answer === "Cancel") return;
26
27 configurations[index] = debugConfig;
28 } else {
29 configurations.push(debugConfig);
30 }
31
32 await wsLaunchSection.update("configurations", configurations);
33}
34
35export async function startDebugSession(ctx: Ctx, runnable: ra.Runnable): Promise<boolean> {
36 let debugConfig: vscode.DebugConfiguration | undefined = undefined;
37 let message = "";
38
39 const wsLaunchSection = vscode.workspace.getConfiguration("launch");
40 const configurations = wsLaunchSection.get<any[]>("configurations") || [];
41
42 const index = configurations.findIndex(c => c.name === runnable.label);
43 if (-1 !== index) {
44 debugConfig = configurations[index];
45 message = " (from launch.json)";
46 debugOutput.clear();
47 } else {
48 debugConfig = await getDebugConfiguration(ctx, runnable);
49 }
50
51 if (!debugConfig) return false;
52
53 debugOutput.appendLine(`Launching debug configuration${message}:`);
54 debugOutput.appendLine(JSON.stringify(debugConfig, null, 2));
55 return vscode.debug.startDebugging(undefined, debugConfig);
56}
57
58async function getDebugConfiguration(ctx: Ctx, runnable: ra.Runnable): Promise<vscode.DebugConfiguration | undefined> {
59 const editor = ctx.activeRustEditor;
60 if (!editor) return;
61
62 const knownEngines: Record<string, DebugConfigProvider> = {
63 "vadimcn.vscode-lldb": getLldbDebugConfig,
64 "ms-vscode.cpptools": getCppvsDebugConfig
65 };
66 const debugOptions = ctx.config.debug;
67
68 let debugEngine = null;
69 if (debugOptions.engine === "auto") {
70 for (var engineId in knownEngines) {
71 debugEngine = vscode.extensions.getExtension(engineId);
72 if (debugEngine) break;
73 }
74 } else {
75 debugEngine = vscode.extensions.getExtension(debugOptions.engine);
76 }
77
78 if (!debugEngine) {
79 vscode.window.showErrorMessage(`Install [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb)`
80 + ` or [MS C++ tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools) extension for debugging.`);
81 return;
82 }
83
84 debugOutput.clear();
85 if (ctx.config.debug.openUpDebugPane) {
86 debugOutput.show(true);
87 }
88
89 const wsFolder = path.normalize(vscode.workspace.workspaceFolders![0].uri.fsPath); // folder exists or RA is not active.
90 function simplifyPath(p: string): string {
91 return path.normalize(p).replace(wsFolder, '${workspaceRoot}');
92 }
93
94 const executable = await getDebugExecutable(runnable);
95 const debugConfig = knownEngines[debugEngine.id](runnable, simplifyPath(executable), debugOptions.sourceFileMap);
96 if (debugConfig.type in debugOptions.engineSettings) {
97 const settingsMap = (debugOptions.engineSettings as any)[debugConfig.type];
98 for (var key in settingsMap) {
99 debugConfig[key] = settingsMap[key];
100 }
101 }
102
103 if (debugConfig.name === "run binary") {
104 // The LSP side: crates\rust-analyzer\src\main_loop\handlers.rs,
105 // fn to_lsp_runnable(...) with RunnableKind::Bin
106 debugConfig.name = `run ${path.basename(executable)}`;
107 }
108
109 if (debugConfig.cwd) {
110 debugConfig.cwd = simplifyPath(debugConfig.cwd);
111 }
112
113 return debugConfig;
114}
115
116async function getDebugExecutable(runnable: ra.Runnable): Promise<string> {
117 const cargo = new Cargo(runnable.args.workspaceRoot || '.', debugOutput);
118 const executable = await cargo.executableFromArgs(runnable.args.cargoArgs);
119
120 // if we are here, there were no compilation errors.
121 return executable;
122}
123
124function getLldbDebugConfig(runnable: ra.Runnable, executable: string, sourceFileMap?: Record<string, string>): vscode.DebugConfiguration {
125 return {
126 type: "lldb",
127 request: "launch",
128 name: runnable.label,
129 program: executable,
130 args: runnable.args.executableArgs,
131 cwd: runnable.args.workspaceRoot,
132 sourceMap: sourceFileMap,
133 sourceLanguages: ["rust"]
134 };
135}
136
137function getCppvsDebugConfig(runnable: ra.Runnable, executable: string, sourceFileMap?: Record<string, string>): vscode.DebugConfiguration {
138 return {
139 type: (os.platform() === "win32") ? "cppvsdbg" : "cppdbg",
140 request: "launch",
141 name: runnable.label,
142 program: executable,
143 args: runnable.args.executableArgs,
144 cwd: runnable.args.workspaceRoot,
145 sourceFileMap: sourceFileMap,
146 };
147}