diff options
Diffstat (limited to 'editors/code/src/run.ts')
-rw-r--r-- | editors/code/src/run.ts | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/editors/code/src/run.ts b/editors/code/src/run.ts new file mode 100644 index 000000000..5c790741f --- /dev/null +++ b/editors/code/src/run.ts | |||
@@ -0,0 +1,146 @@ | |||
1 | import * as vscode from 'vscode'; | ||
2 | import * as lc from 'vscode-languageclient'; | ||
3 | import * as ra from './lsp_ext'; | ||
4 | import * as toolchain from "./toolchain"; | ||
5 | |||
6 | import { Ctx } from './ctx'; | ||
7 | import { makeDebugConfig } from './debug'; | ||
8 | |||
9 | const quickPickButtons = [{ iconPath: new vscode.ThemeIcon("save"), tooltip: "Save as a launch.json configurtation." }]; | ||
10 | |||
11 | export async function selectRunnable(ctx: Ctx, prevRunnable?: RunnableQuickPick, debuggeeOnly = false, showButtons: boolean = true): Promise<RunnableQuickPick | undefined> { | ||
12 | const editor = ctx.activeRustEditor; | ||
13 | const client = ctx.client; | ||
14 | if (!editor || !client) return; | ||
15 | |||
16 | const textDocument: lc.TextDocumentIdentifier = { | ||
17 | uri: editor.document.uri.toString(), | ||
18 | }; | ||
19 | |||
20 | const runnables = await client.sendRequest(ra.runnables, { | ||
21 | textDocument, | ||
22 | position: client.code2ProtocolConverter.asPosition( | ||
23 | editor.selection.active, | ||
24 | ), | ||
25 | }); | ||
26 | const items: RunnableQuickPick[] = []; | ||
27 | if (prevRunnable) { | ||
28 | items.push(prevRunnable); | ||
29 | } | ||
30 | for (const r of runnables) { | ||
31 | if ( | ||
32 | prevRunnable && | ||
33 | JSON.stringify(prevRunnable.runnable) === JSON.stringify(r) | ||
34 | ) { | ||
35 | continue; | ||
36 | } | ||
37 | |||
38 | if (debuggeeOnly && (r.label.startsWith('doctest') || r.label.startsWith('cargo'))) { | ||
39 | continue; | ||
40 | } | ||
41 | items.push(new RunnableQuickPick(r)); | ||
42 | } | ||
43 | |||
44 | if (items.length === 0) { | ||
45 | // it is the debug case, run always has at least 'cargo check ...' | ||
46 | // see crates\rust-analyzer\src\main_loop\handlers.rs, handle_runnables | ||
47 | vscode.window.showErrorMessage("There's no debug target!"); | ||
48 | return; | ||
49 | } | ||
50 | |||
51 | return await new Promise((resolve) => { | ||
52 | const disposables: vscode.Disposable[] = []; | ||
53 | const close = (result?: RunnableQuickPick) => { | ||
54 | resolve(result); | ||
55 | disposables.forEach(d => d.dispose()); | ||
56 | }; | ||
57 | |||
58 | const quickPick = vscode.window.createQuickPick<RunnableQuickPick>(); | ||
59 | quickPick.items = items; | ||
60 | quickPick.title = "Select Runnable"; | ||
61 | if (showButtons) { | ||
62 | quickPick.buttons = quickPickButtons; | ||
63 | } | ||
64 | disposables.push( | ||
65 | quickPick.onDidHide(() => close()), | ||
66 | quickPick.onDidAccept(() => close(quickPick.selectedItems[0])), | ||
67 | quickPick.onDidTriggerButton((_button) => { | ||
68 | (async () => await makeDebugConfig(ctx, quickPick.activeItems[0].runnable))(); | ||
69 | close(); | ||
70 | }), | ||
71 | quickPick.onDidChangeActive((active) => { | ||
72 | if (showButtons && active.length > 0) { | ||
73 | if (active[0].label.startsWith('cargo')) { | ||
74 | // save button makes no sense for `cargo test` or `cargo check` | ||
75 | quickPick.buttons = []; | ||
76 | } else if (quickPick.buttons.length === 0) { | ||
77 | quickPick.buttons = quickPickButtons; | ||
78 | } | ||
79 | } | ||
80 | }), | ||
81 | quickPick | ||
82 | ); | ||
83 | quickPick.show(); | ||
84 | }); | ||
85 | } | ||
86 | |||
87 | export class RunnableQuickPick implements vscode.QuickPickItem { | ||
88 | public label: string; | ||
89 | public description?: string | undefined; | ||
90 | public detail?: string | undefined; | ||
91 | public picked?: boolean | undefined; | ||
92 | |||
93 | constructor(public runnable: ra.Runnable) { | ||
94 | this.label = runnable.label; | ||
95 | } | ||
96 | } | ||
97 | |||
98 | interface CargoTaskDefinition extends vscode.TaskDefinition { | ||
99 | type: 'cargo'; | ||
100 | label: string; | ||
101 | command: string; | ||
102 | args: string[]; | ||
103 | env?: { [key: string]: string }; | ||
104 | } | ||
105 | |||
106 | export function createTask(runnable: ra.Runnable): vscode.Task { | ||
107 | const TASK_SOURCE = 'Rust'; | ||
108 | |||
109 | let command; | ||
110 | switch (runnable.kind) { | ||
111 | case "cargo": command = toolchain.getPathForExecutable("cargo"); | ||
112 | } | ||
113 | const args = runnable.args.cargoArgs; | ||
114 | if (runnable.args.executableArgs.length > 0) { | ||
115 | args.push('--', ...runnable.args.executableArgs); | ||
116 | } | ||
117 | const definition: CargoTaskDefinition = { | ||
118 | type: 'cargo', | ||
119 | label: runnable.label, | ||
120 | command, | ||
121 | args, | ||
122 | env: Object.assign({}, process.env as { [key: string]: string }, { "RUST_BACKTRACE": "short" }), | ||
123 | }; | ||
124 | |||
125 | const execOption: vscode.ShellExecutionOptions = { | ||
126 | cwd: runnable.args.workspaceRoot || '.', | ||
127 | env: definition.env, | ||
128 | }; | ||
129 | const exec = new vscode.ShellExecution( | ||
130 | definition.command, | ||
131 | definition.args, | ||
132 | execOption, | ||
133 | ); | ||
134 | |||
135 | const f = vscode.workspace.workspaceFolders![0]; | ||
136 | const t = new vscode.Task( | ||
137 | definition, | ||
138 | f, | ||
139 | definition.label, | ||
140 | TASK_SOURCE, | ||
141 | exec, | ||
142 | ['$rustc'], | ||
143 | ); | ||
144 | t.presentationOptions.clear = true; | ||
145 | return t; | ||
146 | } | ||