]> git.lizzy.rs Git - rust.git/blob - editors/code/src/debug.ts
Merge #4602 #4603
[rust.git] / editors / code / src / debug.ts
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 './cargo';
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 function getLldbDebugConfig(config: ra.Runnable, executable: string, sourceFileMap?: Record<string, string>): vscode.DebugConfiguration {
13     return {
14         type: "lldb",
15         request: "launch",
16         name: config.label,
17         program: executable,
18         args: config.extraArgs,
19         cwd: config.cwd,
20         sourceMap: sourceFileMap,
21         sourceLanguages: ["rust"]
22     };
23 }
24
25 function getCppvsDebugConfig(config: ra.Runnable, executable: string, sourceFileMap?: Record<string, string>): vscode.DebugConfiguration {
26     return {
27         type: (os.platform() === "win32") ? "cppvsdbg" : "cppdbg",
28         request: "launch",
29         name: config.label,
30         program: executable,
31         args: config.extraArgs,
32         cwd: config.cwd,
33         sourceFileMap: sourceFileMap,
34     };
35 }
36
37 async function getDebugExecutable(config: ra.Runnable): Promise<string> {
38     const cargo = new Cargo(config.cwd || '.', debugOutput);
39     const executable = await cargo.executableFromArgs(config.args);
40
41     // if we are here, there were no compilation errors.
42     return executable;
43 }
44
45 export async function getDebugConfiguration(ctx: Ctx, config: ra.Runnable): Promise<vscode.DebugConfiguration | undefined> {
46     const editor = ctx.activeRustEditor;
47     if (!editor) return;
48
49     const knownEngines: Record<string, DebugConfigProvider> = {
50         "vadimcn.vscode-lldb": getLldbDebugConfig,
51         "ms-vscode.cpptools": getCppvsDebugConfig
52     };
53     const debugOptions = ctx.config.debug;
54
55     let debugEngine = null;
56     if (debugOptions.engine === "auto") {
57         for (var engineId in knownEngines) {
58             debugEngine = vscode.extensions.getExtension(engineId);
59             if (debugEngine) break;
60         }
61     } else {
62         debugEngine = vscode.extensions.getExtension(debugOptions.engine);
63     }
64
65     if (!debugEngine) {
66         vscode.window.showErrorMessage(`Install [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb)`
67             + ` or [MS C++ tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools) extension for debugging.`);
68         return;
69     }
70
71     debugOutput.clear();
72     if (ctx.config.debug.openUpDebugPane) {
73         debugOutput.show(true);
74     }
75
76     const wsFolder = path.normalize(vscode.workspace.workspaceFolders![0].uri.fsPath); // folder exists or RA is not active.
77     function simplifyPath(p: string): string {
78         return path.normalize(p).replace(wsFolder, '${workspaceRoot}');
79     }
80
81     const executable = await getDebugExecutable(config);
82     const debugConfig = knownEngines[debugEngine.id](config, simplifyPath(executable), debugOptions.sourceFileMap);
83     if (debugConfig.type in debugOptions.engineSettings) {
84         const settingsMap = (debugOptions.engineSettings as any)[debugConfig.type];
85         for (var key in settingsMap) {
86             debugConfig[key] = settingsMap[key];
87         }
88     }
89
90     if (debugConfig.name === "run binary") {
91         // The LSP side: crates\rust-analyzer\src\main_loop\handlers.rs,
92         // fn to_lsp_runnable(...) with RunnableKind::Bin
93         debugConfig.name = `run ${path.basename(executable)}`;
94     }
95
96     if (debugConfig.cwd) {
97         debugConfig.cwd = simplifyPath(debugConfig.cwd);
98     }
99
100     return debugConfig;
101 }
102
103 export async function startDebugSession(ctx: Ctx, config: ra.Runnable): Promise<boolean> {
104     let debugConfig: vscode.DebugConfiguration | undefined = undefined;
105     let message = "";
106
107     const wsLaunchSection = vscode.workspace.getConfiguration("launch");
108     const configurations = wsLaunchSection.get<any[]>("configurations") || [];
109
110     const index = configurations.findIndex(c => c.name === config.label);
111     if (-1 !== index) {
112         debugConfig = configurations[index];
113         message = " (from launch.json)";
114         debugOutput.clear();
115     } else {
116         debugConfig = await getDebugConfiguration(ctx, config);
117     }
118
119     if (!debugConfig) return false;
120
121     debugOutput.appendLine(`Launching debug configuration${message}:`);
122     debugOutput.appendLine(JSON.stringify(debugConfig, null, 2));
123     return vscode.debug.startDebugging(undefined, debugConfig);
124 }