@@ -7,6 +7,8 @@ import type { CtxInit } from "./ctx";
7
7
import { makeDebugConfig } from "./debug" ;
8
8
import type { Config , RunnableEnvCfg , RunnableEnvCfgItem } from "./config" ;
9
9
import { unwrapUndefinable } from "./undefinable" ;
10
+ import type { LanguageClient } from "vscode-languageclient/node" ;
11
+ import type { RustEditor } from "./util" ;
10
12
11
13
const quickPickButtons = [
12
14
{ iconPath : new vscode . ThemeIcon ( "save" ) , tooltip : "Save as a launch.json configuration." } ,
@@ -21,73 +23,36 @@ export async function selectRunnable(
21
23
const editor = ctx . activeRustEditor ;
22
24
if ( ! editor ) return ;
23
25
24
- const client = ctx . client ;
25
- const textDocument : lc . TextDocumentIdentifier = {
26
- uri : editor . document . uri . toString ( ) ,
27
- } ;
28
-
29
- const runnables = await client . sendRequest ( ra . runnables , {
30
- textDocument,
31
- position : client . code2ProtocolConverter . asPosition ( editor . selection . active ) ,
32
- } ) ;
33
- const items : RunnableQuickPick [ ] = [ ] ;
34
- if ( prevRunnable ) {
35
- items . push ( prevRunnable ) ;
26
+ // show a placeholder while we get the runnables from the server
27
+ const quickPick = vscode . window . createQuickPick ( ) ;
28
+ quickPick . title = "Select Runnable" ;
29
+ if ( showButtons ) {
30
+ quickPick . buttons = quickPickButtons ;
36
31
}
37
- for ( const r of runnables ) {
38
- if ( prevRunnable && JSON . stringify ( prevRunnable . runnable ) === JSON . stringify ( r ) ) {
39
- continue ;
40
- }
32
+ quickPick . items = [ { label : "Looking for runnables..." } ] ;
33
+ quickPick . activeItems = [ ] ;
34
+ quickPick . show ( ) ;
41
35
42
- if ( debuggeeOnly && ( r . label . startsWith ( "doctest" ) || r . label . startsWith ( "cargo" ) ) ) {
43
- continue ;
44
- }
45
- items . push ( new RunnableQuickPick ( r ) ) ;
46
- }
36
+ const runnables = await getRunnables ( ctx . client , editor , prevRunnable , debuggeeOnly ) ;
47
37
48
- if ( items . length === 0 ) {
38
+ if ( runnables . length === 0 ) {
49
39
// it is the debug case, run always has at least 'cargo check ...'
50
40
// see crates\rust-analyzer\src\main_loop\handlers.rs, handle_runnables
51
41
await vscode . window . showErrorMessage ( "There's no debug target!" ) ;
42
+ quickPick . dispose ( ) ;
52
43
return ;
53
44
}
54
45
55
- return await new Promise ( ( resolve ) => {
56
- const disposables : vscode . Disposable [ ] = [ ] ;
57
- const close = ( result ?: RunnableQuickPick ) => {
58
- resolve ( result ) ;
59
- disposables . forEach ( ( d ) => d . dispose ( ) ) ;
60
- } ;
46
+ // clear the list before we hook up listeners to to avoid invoking them
47
+ // if the user happens to accept the placeholder item
48
+ quickPick . items = [ ] ;
61
49
62
- const quickPick = vscode . window . createQuickPick < RunnableQuickPick > ( ) ;
63
- quickPick . items = items ;
64
- quickPick . title = "Select Runnable" ;
65
- if ( showButtons ) {
66
- quickPick . buttons = quickPickButtons ;
67
- }
68
- disposables . push (
69
- quickPick . onDidHide ( ( ) => close ( ) ) ,
70
- quickPick . onDidAccept ( ( ) => close ( quickPick . selectedItems [ 0 ] ) ) ,
71
- quickPick . onDidTriggerButton ( async ( _button ) => {
72
- const runnable = unwrapUndefinable ( quickPick . activeItems [ 0 ] ) . runnable ;
73
- await makeDebugConfig ( ctx , runnable ) ;
74
- close ( ) ;
75
- } ) ,
76
- quickPick . onDidChangeActive ( ( activeList ) => {
77
- if ( showButtons && activeList . length > 0 ) {
78
- const active = unwrapUndefinable ( activeList [ 0 ] ) ;
79
- if ( active . label . startsWith ( "cargo" ) ) {
80
- // save button makes no sense for `cargo test` or `cargo check`
81
- quickPick . buttons = [ ] ;
82
- } else if ( quickPick . buttons . length === 0 ) {
83
- quickPick . buttons = quickPickButtons ;
84
- }
85
- }
86
- } ) ,
87
- quickPick ,
88
- ) ;
89
- quickPick . show ( ) ;
90
- } ) ;
50
+ return await populateAndGetSelection (
51
+ quickPick as vscode . QuickPick < RunnableQuickPick > ,
52
+ runnables ,
53
+ ctx ,
54
+ showButtons ,
55
+ ) ;
91
56
}
92
57
93
58
export class RunnableQuickPick implements vscode . QuickPickItem {
@@ -187,3 +152,75 @@ export function createArgs(runnable: ra.Runnable): string[] {
187
152
}
188
153
return args ;
189
154
}
155
+
156
+ async function getRunnables (
157
+ client : LanguageClient ,
158
+ editor : RustEditor ,
159
+ prevRunnable ?: RunnableQuickPick ,
160
+ debuggeeOnly = false ,
161
+ ) : Promise < RunnableQuickPick [ ] > {
162
+ const textDocument : lc . TextDocumentIdentifier = {
163
+ uri : editor . document . uri . toString ( ) ,
164
+ } ;
165
+
166
+ const runnables = await client . sendRequest ( ra . runnables , {
167
+ textDocument,
168
+ position : client . code2ProtocolConverter . asPosition ( editor . selection . active ) ,
169
+ } ) ;
170
+ const items : RunnableQuickPick [ ] = [ ] ;
171
+ if ( prevRunnable ) {
172
+ items . push ( prevRunnable ) ;
173
+ }
174
+ for ( const r of runnables ) {
175
+ if ( prevRunnable && JSON . stringify ( prevRunnable . runnable ) === JSON . stringify ( r ) ) {
176
+ continue ;
177
+ }
178
+
179
+ if ( debuggeeOnly && ( r . label . startsWith ( "doctest" ) || r . label . startsWith ( "cargo" ) ) ) {
180
+ continue ;
181
+ }
182
+ items . push ( new RunnableQuickPick ( r ) ) ;
183
+ }
184
+
185
+ return items ;
186
+ }
187
+
188
+ async function populateAndGetSelection (
189
+ quickPick : vscode . QuickPick < RunnableQuickPick > ,
190
+ runnables : RunnableQuickPick [ ] ,
191
+ ctx : CtxInit ,
192
+ showButtons : boolean ,
193
+ ) : Promise < RunnableQuickPick | undefined > {
194
+ return new Promise ( ( resolve ) => {
195
+ const disposables : vscode . Disposable [ ] = [ ] ;
196
+ const close = ( result ?: RunnableQuickPick ) => {
197
+ resolve ( result ) ;
198
+ disposables . forEach ( ( d ) => d . dispose ( ) ) ;
199
+ } ;
200
+ disposables . push (
201
+ quickPick . onDidHide ( ( ) => close ( ) ) ,
202
+ quickPick . onDidAccept ( ( ) => close ( quickPick . selectedItems [ 0 ] as RunnableQuickPick ) ) ,
203
+ quickPick . onDidTriggerButton ( async ( _button ) => {
204
+ const runnable = unwrapUndefinable (
205
+ quickPick . activeItems [ 0 ] as RunnableQuickPick ,
206
+ ) . runnable ;
207
+ await makeDebugConfig ( ctx , runnable ) ;
208
+ close ( ) ;
209
+ } ) ,
210
+ quickPick . onDidChangeActive ( ( activeList ) => {
211
+ if ( showButtons && activeList . length > 0 ) {
212
+ const active = unwrapUndefinable ( activeList [ 0 ] ) ;
213
+ if ( active . label . startsWith ( "cargo" ) ) {
214
+ // save button makes no sense for `cargo test` or `cargo check`
215
+ quickPick . buttons = [ ] ;
216
+ } else if ( quickPick . buttons . length === 0 ) {
217
+ quickPick . buttons = quickPickButtons ;
218
+ }
219
+ }
220
+ } ) ,
221
+ quickPick ,
222
+ ) ;
223
+ // populate the list with the actual runnables
224
+ quickPick . items = runnables ;
225
+ } ) ;
226
+ }
0 commit comments