aboutsummaryrefslogtreecommitdiff
path: root/editors/code/src/commands
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-05-15 15:29:01 +0100
committerGitHub <[email protected]>2020-05-15 15:29:01 +0100
commitd51c1f62178c383363a2d95e865131d9a7b969d0 (patch)
tree5235615134ab3798f21a167c71ce175795fc6798 /editors/code/src/commands
parent982b92f966518a0e24632fafdc18d7b5ab6928b4 (diff)
parenta4ecaa70969067c1149711dbf1f40a8a95cb5b72 (diff)
Merge #4448
4448: Generate configuration for launch.json r=vsrs a=vsrs This PR adds two new commands: `"rust-analyzer.debug"` and `"rust-analyzer.newDebugConfig"`. The former is a supplement to the existing `"rust-analyzer.run"` command and works the same way: asks for a runnable and starts new debug session. The latter allows adding a new configuration to **launch.json** (or to update an existing one). If the new option `"rust-analyzer.debug.useLaunchJson"` is set to true then `"rust-analyzer.debug"` and Debug Lens will first look for existing debug configuration in **launch.json**. That is, it has become possible to specify startup arguments, env variables, etc. `"rust-analyzer.debug.useLaunchJson"` is false by default, but it might be worth making true the default value. Personally I prefer true, but I'm not sure if it is good for all value. ---- I think that this PR also solves https://github.com/rust-analyzer/rust-analyzer/issues/3441. Both methods to update launch.json mentioned in the issue do not work: 1. Menu. It is only possible to add a launch.json configuration template via a debug adapter. And anyway it's only a template and it is impossible to specify arguments from an extension. 2. DebugConfigurationProvider. The exact opposite situation: it is possible to specify all debug session settings, but it is impossible to export these settings to launch.json. Separate `"rust-analyzer.newDebugConfig"` command looks better for me. ---- Fixes #4450 Fixes #3441 Co-authored-by: vsrs <[email protected]> Co-authored-by: vsrs <[email protected]>
Diffstat (limited to 'editors/code/src/commands')
-rw-r--r--editors/code/src/commands/runnables.ts201
1 files changed, 103 insertions, 98 deletions
diff --git a/editors/code/src/commands/runnables.ts b/editors/code/src/commands/runnables.ts
index ae328d2a4..b1d93fc34 100644
--- a/editors/code/src/commands/runnables.ts
+++ b/editors/code/src/commands/runnables.ts
@@ -1,43 +1,82 @@
1import * as vscode from 'vscode'; 1import * as vscode from 'vscode';
2import * as lc from 'vscode-languageclient'; 2import * as lc from 'vscode-languageclient';
3import * as ra from '../rust-analyzer-api'; 3import * as ra from '../rust-analyzer-api';
4import * as os from "os";
5 4
6import { Ctx, Cmd } from '../ctx'; 5import { Ctx, Cmd } from '../ctx';
7import { Cargo } from '../cargo'; 6import { startDebugSession, getDebugConfiguration } from '../debug';
8 7
9export function run(ctx: Ctx): Cmd { 8const quickPickButtons = [{ iconPath: new vscode.ThemeIcon("save"), tooltip: "Save as a launch.json configurtation." }];
10 let prevRunnable: RunnableQuickPick | undefined;
11 9
12 return async () => { 10async function selectRunnable(ctx: Ctx, prevRunnable?: RunnableQuickPick, showButtons: boolean = true): Promise<RunnableQuickPick | undefined> {
13 const editor = ctx.activeRustEditor; 11 const editor = ctx.activeRustEditor;
14 const client = ctx.client; 12 const client = ctx.client;
15 if (!editor || !client) return; 13 if (!editor || !client) return;
16 14
17 const textDocument: lc.TextDocumentIdentifier = { 15 const textDocument: lc.TextDocumentIdentifier = {
18 uri: editor.document.uri.toString(), 16 uri: editor.document.uri.toString(),
19 }; 17 };
20 18
21 const runnables = await client.sendRequest(ra.runnables, { 19 const runnables = await client.sendRequest(ra.runnables, {
22 textDocument, 20 textDocument,
23 position: client.code2ProtocolConverter.asPosition( 21 position: client.code2ProtocolConverter.asPosition(
24 editor.selection.active, 22 editor.selection.active,
25 ), 23 ),
26 }); 24 });
27 const items: RunnableQuickPick[] = []; 25 const items: RunnableQuickPick[] = [];
28 if (prevRunnable) { 26 if (prevRunnable) {
29 items.push(prevRunnable); 27 items.push(prevRunnable);
28 }
29 for (const r of runnables) {
30 if (
31 prevRunnable &&
32 JSON.stringify(prevRunnable.runnable) === JSON.stringify(r)
33 ) {
34 continue;
30 } 35 }
31 for (const r of runnables) { 36 items.push(new RunnableQuickPick(r));
32 if ( 37 }
33 prevRunnable && 38
34 JSON.stringify(prevRunnable.runnable) === JSON.stringify(r) 39 return await new Promise((resolve) => {
35 ) { 40 const disposables: vscode.Disposable[] = [];
36 continue; 41 const close = (result?: RunnableQuickPick) => {
37 } 42 resolve(result);
38 items.push(new RunnableQuickPick(r)); 43 disposables.forEach(d => d.dispose());
44 };
45
46 const quickPick = vscode.window.createQuickPick<RunnableQuickPick>();
47 quickPick.items = items;
48 quickPick.title = "Select Runnable";
49 if (showButtons) {
50 quickPick.buttons = quickPickButtons;
39 } 51 }
40 const item = await vscode.window.showQuickPick(items); 52 disposables.push(
53 quickPick.onDidHide(() => close()),
54 quickPick.onDidAccept(() => close(quickPick.selectedItems[0])),
55 quickPick.onDidTriggerButton((_button) => {
56 (async () => await makeDebugConfig(ctx, quickPick.activeItems[0]))();
57 close();
58 }),
59 quickPick.onDidChangeActive((active) => {
60 if (showButtons && active.length > 0) {
61 if (active[0].label.startsWith('cargo')) {
62 // save button makes no sense for `cargo test` or `cargo check`
63 quickPick.buttons = [];
64 } else if (quickPick.buttons.length === 0) {
65 quickPick.buttons = quickPickButtons;
66 }
67 }
68 }),
69 quickPick
70 );
71 quickPick.show();
72 });
73}
74
75export function run(ctx: Ctx): Cmd {
76 let prevRunnable: RunnableQuickPick | undefined;
77
78 return async () => {
79 const item = await selectRunnable(ctx, prevRunnable);
41 if (!item) return; 80 if (!item) return;
42 81
43 item.detail = 'rerun'; 82 item.detail = 'rerun';
@@ -64,88 +103,54 @@ export function runSingle(ctx: Ctx): Cmd {
64 }; 103 };
65} 104}
66 105
67function getLldbDebugConfig(config: ra.Runnable, executable: string, sourceFileMap?: Record<string, string>): vscode.DebugConfiguration { 106export function debug(ctx: Ctx): Cmd {
68 return { 107 let prevDebuggee: RunnableQuickPick | undefined;
69 type: "lldb", 108
70 request: "launch", 109 return async () => {
71 name: config.label, 110 const item = await selectRunnable(ctx, prevDebuggee);
72 program: executable, 111 if (!item) return;
73 args: config.extraArgs, 112
74 cwd: config.cwd, 113 item.detail = 'restart';
75 sourceMap: sourceFileMap, 114 prevDebuggee = item;
76 sourceLanguages: ["rust"] 115 return await startDebugSession(ctx, item.runnable);
77 }; 116 };
78} 117}
79 118
80function getCppvsDebugConfig(config: ra.Runnable, executable: string, sourceFileMap?: Record<string, string>): vscode.DebugConfiguration { 119export function debugSingle(ctx: Ctx): Cmd {
81 return { 120 return async (config: ra.Runnable) => {
82 type: (os.platform() === "win32") ? "cppvsdbg" : 'cppdbg', 121 await startDebugSession(ctx, config);
83 request: "launch",
84 name: config.label,
85 program: executable,
86 args: config.extraArgs,
87 cwd: config.cwd,
88 sourceFileMap: sourceFileMap,
89 }; 122 };
90} 123}
91 124
92const debugOutput = vscode.window.createOutputChannel("Debug"); 125async function makeDebugConfig(ctx: Ctx, item: RunnableQuickPick): Promise<void> {
93 126 const scope = ctx.activeRustEditor?.document.uri;
94async function getDebugExecutable(config: ra.Runnable): Promise<string> { 127 if (!scope) return;
95 const cargo = new Cargo(config.cwd || '.', debugOutput);
96 const executable = await cargo.executableFromArgs(config.args);
97
98 // if we are here, there were no compilation errors.
99 return executable;
100}
101 128
102type DebugConfigProvider = (config: ra.Runnable, executable: string, sourceFileMap?: Record<string, string>) => vscode.DebugConfiguration; 129 const debugConfig = await getDebugConfiguration(ctx, item.runnable);
130 if (!debugConfig) return;
103 131
104export function debugSingle(ctx: Ctx): Cmd { 132 const wsLaunchSection = vscode.workspace.getConfiguration("launch", scope);
105 return async (config: ra.Runnable) => { 133 const configurations = wsLaunchSection.get<any[]>("configurations") || [];
106 const editor = ctx.activeRustEditor;
107 if (!editor) return;
108 134
109 const knownEngines: Record<string, DebugConfigProvider> = { 135 const index = configurations.findIndex(c => c.name === debugConfig.name);
110 "vadimcn.vscode-lldb": getLldbDebugConfig, 136 if (index !== -1) {
111 "ms-vscode.cpptools": getCppvsDebugConfig 137 const answer = await vscode.window.showErrorMessage(`Launch configuration '${debugConfig.name}' already exists!`, 'Cancel', 'Update');
112 }; 138 if (answer === "Cancel") return;
113 const debugOptions = ctx.config.debug;
114
115 let debugEngine = null;
116 if (debugOptions.engine === "auto") {
117 for (var engineId in knownEngines) {
118 debugEngine = vscode.extensions.getExtension(engineId);
119 if (debugEngine) break;
120 }
121 }
122 else {
123 debugEngine = vscode.extensions.getExtension(debugOptions.engine);
124 }
125 139
126 if (!debugEngine) { 140 configurations[index] = debugConfig;
127 vscode.window.showErrorMessage(`Install [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb)` 141 } else {
128 + ` or [MS C++ tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools) extension for debugging.`); 142 configurations.push(debugConfig);
129 return; 143 }
130 }
131 144
132 debugOutput.clear(); 145 await wsLaunchSection.update("configurations", configurations);
133 if (ctx.config.debug.openUpDebugPane) { 146}
134 debugOutput.show(true);
135 }
136 147
137 const executable = await getDebugExecutable(config); 148export function newDebugConfig(ctx: Ctx): Cmd {
138 const debugConfig = knownEngines[debugEngine.id](config, executable, debugOptions.sourceFileMap); 149 return async () => {
139 if (debugConfig.type in debugOptions.engineSettings) { 150 const item = await selectRunnable(ctx, undefined, false);
140 const settingsMap = (debugOptions.engineSettings as any)[debugConfig.type]; 151 if (!item) return;
141 for (var key in settingsMap) {
142 debugConfig[key] = settingsMap[key];
143 }
144 }
145 152
146 debugOutput.appendLine("Launching debug configuration:"); 153 await makeDebugConfig(ctx, item);
147 debugOutput.appendLine(JSON.stringify(debugConfig, null, 2));
148 return vscode.debug.startDebugging(undefined, debugConfig);
149 }; 154 };
150} 155}
151 156