diff options
Diffstat (limited to 'editors/code/src/debug.ts')
-rw-r--r-- | editors/code/src/debug.ts | 147 |
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 @@ | |||
1 | import * as os from "os"; | ||
2 | import * as vscode from 'vscode'; | ||
3 | import * as path from 'path'; | ||
4 | import * as ra from './lsp_ext'; | ||
5 | |||
6 | import { Cargo } from './toolchain'; | ||
7 | import { Ctx } from "./ctx"; | ||
8 | |||
9 | const debugOutput = vscode.window.createOutputChannel("Debug"); | ||
10 | type DebugConfigProvider = (config: ra.Runnable, executable: string, sourceFileMap?: Record<string, string>) => vscode.DebugConfiguration; | ||
11 | |||
12 | export 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 | |||
35 | export 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 | |||
58 | async 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 | |||
116 | async 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 | |||
124 | function 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 | |||
137 | function 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 | } | ||