aboutsummaryrefslogtreecommitdiff
path: root/editors/code/src/commands/runnables.ts
diff options
context:
space:
mode:
Diffstat (limited to 'editors/code/src/commands/runnables.ts')
-rw-r--r--editors/code/src/commands/runnables.ts197
1 files changed, 115 insertions, 82 deletions
diff --git a/editors/code/src/commands/runnables.ts b/editors/code/src/commands/runnables.ts
index d77e8188c..0bd30fb07 100644
--- a/editors/code/src/commands/runnables.ts
+++ b/editors/code/src/commands/runnables.ts
@@ -1,43 +1,93 @@
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, debuggeeOnly = false, 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
32 if ( 37 if (debuggeeOnly && (r.label.startsWith('doctest') || r.label.startsWith('cargo'))) {
33 prevRunnable && 38 continue;
34 JSON.stringify(prevRunnable.runnable) === JSON.stringify(r)
35 ) {
36 continue;
37 }
38 items.push(new RunnableQuickPick(r));
39 } 39 }
40 const item = await vscode.window.showQuickPick(items); 40 items.push(new RunnableQuickPick(r));
41 }
42
43 if (items.length === 0) {
44 // it is the debug case, run always has at least 'cargo check ...'
45 // see crates\rust-analyzer\src\main_loop\handlers.rs, handle_runnables
46 vscode.window.showErrorMessage("There's no debug target!");
47 return;
48 }
49
50 return await new Promise((resolve) => {
51 const disposables: vscode.Disposable[] = [];
52 const close = (result?: RunnableQuickPick) => {
53 resolve(result);
54 disposables.forEach(d => d.dispose());
55 };
56
57 const quickPick = vscode.window.createQuickPick<RunnableQuickPick>();
58 quickPick.items = items;
59 quickPick.title = "Select Runnable";
60 if (showButtons) {
61 quickPick.buttons = quickPickButtons;
62 }
63 disposables.push(
64 quickPick.onDidHide(() => close()),
65 quickPick.onDidAccept(() => close(quickPick.selectedItems[0])),
66 quickPick.onDidTriggerButton((_button) => {
67 (async () => await makeDebugConfig(ctx, quickPick.activeItems[0]))();
68 close();
69 }),
70 quickPick.onDidChangeActive((active) => {
71 if (showButtons && active.length > 0) {
72 if (active[0].label.startsWith('cargo')) {
73 // save button makes no sense for `cargo test` or `cargo check`
74 quickPick.buttons = [];
75 } else if (quickPick.buttons.length === 0) {
76 quickPick.buttons = quickPickButtons;
77 }
78 }
79 }),
80 quickPick
81 );
82 quickPick.show();
83 });
84}
85
86export function run(ctx: Ctx): Cmd {
87 let prevRunnable: RunnableQuickPick | undefined;
88
89 return async () => {
90 const item = await selectRunnable(ctx, prevRunnable);
41 if (!item) return; 91 if (!item) return;
42 92
43 item.detail = 'rerun'; 93 item.detail = 'rerun';
@@ -64,71 +114,54 @@ export function runSingle(ctx: Ctx): Cmd {
64 }; 114 };
65} 115}
66 116
67function getLldbDebugConfig(config: ra.Runnable, sourceFileMap: Record<string, string>): vscode.DebugConfiguration { 117export function debug(ctx: Ctx): Cmd {
68 return { 118 let prevDebuggee: RunnableQuickPick | undefined;
69 type: "lldb",
70 request: "launch",
71 name: config.label,
72 cargo: {
73 args: config.args,
74 },
75 args: config.extraArgs,
76 cwd: config.cwd,
77 sourceMap: sourceFileMap
78 };
79}
80
81const debugOutput = vscode.window.createOutputChannel("Debug");
82 119
83async function getCppvsDebugConfig(config: ra.Runnable, sourceFileMap: Record<string, string>): Promise<vscode.DebugConfiguration> { 120 return async () => {
84 debugOutput.clear(); 121 const item = await selectRunnable(ctx, prevDebuggee, true);
85 122 if (!item) return;
86 const cargo = new Cargo(config.cwd || '.', debugOutput);
87 const executable = await cargo.executableFromArgs(config.args);
88 123
89 // if we are here, there were no compilation errors. 124 item.detail = 'restart';
90 return { 125 prevDebuggee = item;
91 type: (os.platform() === "win32") ? "cppvsdbg" : 'cppdbg', 126 return await startDebugSession(ctx, item.runnable);
92 request: "launch",
93 name: config.label,
94 program: executable,
95 args: config.extraArgs,
96 cwd: config.cwd,
97 sourceFileMap: sourceFileMap,
98 }; 127 };
99} 128}
100 129
101export function debugSingle(ctx: Ctx): Cmd { 130export function debugSingle(ctx: Ctx): Cmd {
102 return async (config: ra.Runnable) => { 131 return async (config: ra.Runnable) => {
103 const editor = ctx.activeRustEditor; 132 await startDebugSession(ctx, config);
104 if (!editor) return; 133 };
134}
105 135
106 const lldbId = "vadimcn.vscode-lldb"; 136async function makeDebugConfig(ctx: Ctx, item: RunnableQuickPick): Promise<void> {
107 const cpptoolsId = "ms-vscode.cpptools"; 137 const scope = ctx.activeRustEditor?.document.uri;
138 if (!scope) return;
108 139
109 const debugEngineId = ctx.config.debug.engine; 140 const debugConfig = await getDebugConfiguration(ctx, item.runnable);
110 let debugEngine = null; 141 if (!debugConfig) return;
111 if (debugEngineId === "auto") {
112 debugEngine = vscode.extensions.getExtension(lldbId);
113 if (!debugEngine) {
114 debugEngine = vscode.extensions.getExtension(cpptoolsId);
115 }
116 }
117 else {
118 debugEngine = vscode.extensions.getExtension(debugEngineId);
119 }
120 142
121 if (!debugEngine) { 143 const wsLaunchSection = vscode.workspace.getConfiguration("launch", scope);
122 vscode.window.showErrorMessage(`Install [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=${lldbId})` 144 const configurations = wsLaunchSection.get<any[]>("configurations") || [];
123 + ` or [MS C++ tools](https://marketplace.visualstudio.com/items?itemName=${cpptoolsId}) extension for debugging.`); 145
124 return; 146 const index = configurations.findIndex(c => c.name === debugConfig.name);
125 } 147 if (index !== -1) {
148 const answer = await vscode.window.showErrorMessage(`Launch configuration '${debugConfig.name}' already exists!`, 'Cancel', 'Update');
149 if (answer === "Cancel") return;
150
151 configurations[index] = debugConfig;
152 } else {
153 configurations.push(debugConfig);
154 }
155
156 await wsLaunchSection.update("configurations", configurations);
157}
126 158
127 const debugConfig = lldbId === debugEngine.id 159export function newDebugConfig(ctx: Ctx): Cmd {
128 ? getLldbDebugConfig(config, ctx.config.debug.sourceFileMap) 160 return async () => {
129 : await getCppvsDebugConfig(config, ctx.config.debug.sourceFileMap); 161 const item = await selectRunnable(ctx, undefined, true, false);
162 if (!item) return;
130 163
131 return vscode.debug.startDebugging(undefined, debugConfig); 164 await makeDebugConfig(ctx, item);
132 }; 165 };
133} 166}
134 167