1
1
import * as vscode from 'vscode' ;
2
2
import * as lc from 'vscode-languageclient' ;
3
3
import * as ra from '../rust-analyzer-api' ;
4
- import * as os from "os" ;
5
4
6
5
import { Ctx , Cmd } from '../ctx' ;
7
- import { Cargo } from '../cargo ' ;
6
+ import { startDebugSession , getDebugConfiguration } from '../debug ' ;
8
7
9
- export function run ( ctx : Ctx ) : Cmd {
10
- let prevRunnable : RunnableQuickPick | undefined ;
8
+ const quickPickButtons = [ { iconPath : new vscode . ThemeIcon ( "save" ) , tooltip : "Save as a launch.json configurtation." } ] ;
11
9
12
- return async ( ) = > {
13
- const editor = ctx . activeRustEditor ;
14
- const client = ctx . client ;
15
- if ( ! editor || ! client ) return ;
10
+ async function selectRunnable ( ctx : Ctx , prevRunnable ?: RunnableQuickPick , showButtons : boolean = true ) : Promise < RunnableQuickPick | undefined > {
11
+ const editor = ctx . activeRustEditor ;
12
+ const client = ctx . client ;
13
+ if ( ! editor || ! client ) return ;
16
14
17
- const textDocument : lc . TextDocumentIdentifier = {
18
- uri : editor . document . uri . toString ( ) ,
19
- } ;
15
+ const textDocument : lc . TextDocumentIdentifier = {
16
+ uri : editor . document . uri . toString ( ) ,
17
+ } ;
20
18
21
- const runnables = await client . sendRequest ( ra . runnables , {
22
- textDocument,
23
- position : client . code2ProtocolConverter . asPosition (
24
- editor . selection . active ,
25
- ) ,
26
- } ) ;
27
- const items : RunnableQuickPick [ ] = [ ] ;
28
- if ( prevRunnable ) {
29
- items . push ( prevRunnable ) ;
19
+ const runnables = await client . sendRequest ( ra . runnables , {
20
+ textDocument,
21
+ position : client . code2ProtocolConverter . asPosition (
22
+ editor . selection . active ,
23
+ ) ,
24
+ } ) ;
25
+ const items : RunnableQuickPick [ ] = [ ] ;
26
+ if ( 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 ) {
32
- if (
33
- prevRunnable &&
34
- JSON . stringify ( prevRunnable . runnable ) === JSON . stringify ( r )
35
- ) {
36
- continue ;
37
- }
38
- items . push ( new RunnableQuickPick ( r ) ) ;
36
+ items . push ( new RunnableQuickPick ( r ) ) ;
37
+ }
38
+
39
+ return await new Promise ( ( resolve ) => {
40
+ const disposables : vscode . Disposable [ ] = [ ] ;
41
+ const close = ( result ?: RunnableQuickPick ) => {
42
+ resolve ( result ) ;
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
+
75
+ export function run ( ctx : Ctx ) : Cmd {
76
+ let prevRunnable : RunnableQuickPick | undefined ;
77
+
78
+ return async ( ) => {
79
+ const item = await selectRunnable ( ctx , prevRunnable ) ;
41
80
if ( ! item ) return ;
42
81
43
82
item . detail = 'rerun' ;
@@ -64,88 +103,54 @@ export function runSingle(ctx: Ctx): Cmd {
64
103
} ;
65
104
}
66
105
67
- function getLldbDebugConfig ( config : ra . Runnable , executable : string , sourceFileMap ?: Record < string , string > ) : vscode . DebugConfiguration {
68
- return {
69
- type : "lldb" ,
70
- request : "launch" ,
71
- name : config . label ,
72
- program : executable ,
73
- args : config . extraArgs ,
74
- cwd : config . cwd ,
75
- sourceMap : sourceFileMap ,
76
- sourceLanguages : [ "rust" ]
106
+ export function debug ( ctx : Ctx ) : Cmd {
107
+ let prevDebuggee : RunnableQuickPick | undefined ;
108
+
109
+ return async ( ) => {
110
+ const item = await selectRunnable ( ctx , prevDebuggee ) ;
111
+ if ( ! item ) return ;
112
+
113
+ item . detail = 'restart' ;
114
+ prevDebuggee = item ;
115
+ return await startDebugSession ( ctx , item . runnable ) ;
77
116
} ;
78
117
}
79
118
80
- function getCppvsDebugConfig ( config : ra . Runnable , executable : string , sourceFileMap ?: Record < string , string > ) : vscode . DebugConfiguration {
81
- return {
82
- type : ( os . platform ( ) === "win32" ) ? "cppvsdbg" : 'cppdbg' ,
83
- request : "launch" ,
84
- name : config . label ,
85
- program : executable ,
86
- args : config . extraArgs ,
87
- cwd : config . cwd ,
88
- sourceFileMap : sourceFileMap ,
119
+ export function debugSingle ( ctx : Ctx ) : Cmd {
120
+ return async ( config : ra . Runnable ) => {
121
+ await startDebugSession ( ctx , config ) ;
89
122
} ;
90
123
}
91
124
92
- const debugOutput = vscode . window . createOutputChannel ( "Debug" ) ;
93
-
94
- async function getDebugExecutable ( config : ra . Runnable ) : Promise < string > {
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
- }
125
+ async function makeDebugConfig ( ctx : Ctx , item : RunnableQuickPick ) : Promise < void > {
126
+ const scope = ctx . activeRustEditor ?. document . uri ;
127
+ if ( ! scope ) return ;
101
128
102
- type 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
104
- export function debugSingle ( ctx : Ctx ) : Cmd {
105
- return async ( config : ra . Runnable ) => {
106
- const editor = ctx . activeRustEditor ;
107
- if ( ! editor ) return ;
132
+ const wsLaunchSection = vscode . workspace . getConfiguration ( "launch" , scope ) ;
133
+ const configurations = wsLaunchSection . get < any [ ] > ( "configurations" ) || [ ] ;
108
134
109
- const knownEngines : Record < string , DebugConfigProvider > = {
110
- "vadimcn.vscode-lldb" : getLldbDebugConfig ,
111
- "ms-vscode.cpptools" : getCppvsDebugConfig
112
- } ;
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
- }
135
+ const index = configurations . findIndex ( c => c . name === debugConfig . name ) ;
136
+ if ( index !== - 1 ) {
137
+ const answer = await vscode . window . showErrorMessage ( `Launch configuration '${ debugConfig . name } ' already exists!` , 'Cancel' , 'Update' ) ;
138
+ if ( answer === "Cancel" ) return ;
125
139
126
- if ( ! debugEngine ) {
127
- vscode . window . showErrorMessage ( `Install [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb)`
128
- + ` or [MS C++ tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools) extension for debugging.` ) ;
129
- return ;
130
- }
140
+ configurations [ index ] = debugConfig ;
141
+ } else {
142
+ configurations . push ( debugConfig ) ;
143
+ }
131
144
132
- debugOutput . clear ( ) ;
133
- if ( ctx . config . debug . openUpDebugPane ) {
134
- debugOutput . show ( true ) ;
135
- }
145
+ await wsLaunchSection . update ( "configurations" , configurations ) ;
146
+ }
136
147
137
- const executable = await getDebugExecutable ( config ) ;
138
- const debugConfig = knownEngines [ debugEngine . id ] ( config , executable , debugOptions . sourceFileMap ) ;
139
- if ( debugConfig . type in debugOptions . engineSettings ) {
140
- const settingsMap = ( debugOptions . engineSettings as any ) [ debugConfig . type ] ;
141
- for ( var key in settingsMap ) {
142
- debugConfig [ key ] = settingsMap [ key ] ;
143
- }
144
- }
148
+ export function newDebugConfig ( ctx : Ctx ) : Cmd {
149
+ return async ( ) => {
150
+ const item = await selectRunnable ( ctx , undefined , false ) ;
151
+ if ( ! item ) return ;
145
152
146
- debugOutput . appendLine ( "Launching debug configuration:" ) ;
147
- debugOutput . appendLine ( JSON . stringify ( debugConfig , null , 2 ) ) ;
148
- return vscode . debug . startDebugging ( undefined , debugConfig ) ;
153
+ await makeDebugConfig ( ctx , item ) ;
149
154
} ;
150
155
}
151
156
0 commit comments