11import * as vscode from 'vscode' ;
22import * as lc from 'vscode-languageclient' ;
33import * as ra from '../rust-analyzer-api' ;
4- import * as os from "os" ;
54
65import { Ctx , Cmd } from '../ctx' ;
7- import { Cargo } from '../cargo ' ;
6+ import { startDebugSession , getDebugConfiguration } from '../debug ' ;
87
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." } ] ;
119
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 ;
1614
17- const textDocument : lc . TextDocumentIdentifier = {
18- uri : editor . document . uri . toString ( ) ,
19- } ;
15+ const textDocument : lc . TextDocumentIdentifier = {
16+ uri : editor . document . uri . toString ( ) ,
17+ } ;
2018
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 ;
3035 }
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 ;
3951 }
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 ) ;
4180 if ( ! item ) return ;
4281
4382 item . detail = 'rerun' ;
@@ -64,88 +103,54 @@ export function runSingle(ctx: Ctx): Cmd {
64103 } ;
65104}
66105
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 ) ;
77116 } ;
78117}
79118
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 ) ;
89122 } ;
90123}
91124
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 ;
101128
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 ;
103131
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" ) || [ ] ;
108134
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 ;
125139
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+ }
131144
132- debugOutput . clear ( ) ;
133- if ( ctx . config . debug . openUpDebugPane ) {
134- debugOutput . show ( true ) ;
135- }
145+ await wsLaunchSection . update ( "configurations" , configurations ) ;
146+ }
136147
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 ;
145152
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 ) ;
149154 } ;
150155}
151156
0 commit comments