@@ -12,6 +12,8 @@ import type { SideSpecsReq, SideSpecsResp } from "../../cli/src/sideprotocol"
1212import { logo } from "./assets"
1313import { sideRequest } from "./jacdac"
1414import { DeviceScriptExtensionState } from "./state"
15+ import { Utils } from "vscode-uri"
16+ import { TaggedQuickPickItem } from "./pickers"
1517
1618const HELP_URI = vscode . Uri . parse (
1719 "https://microsoft.github.io/devicescript/getting-started/vscode#setting-up-the-project"
@@ -29,12 +31,13 @@ function showTerminalError(message: string) {
2931
3032export class DeveloperToolsManager extends JDEventSource {
3133 private _connectionState : ConnectionState = ConnectionState . Disconnected
32- private _workspaceFolder : vscode . WorkspaceFolder
33- private _terminalPromise : Promise < vscode . Terminal >
34+ private _projectFolder : vscode . Uri
3435 version = ""
3536 runtimeVersion : string
3637 nodeVersion : string
3738
39+ private _terminalPromise : Promise < vscode . Terminal >
40+
3841 constructor ( readonly extensionState : DeviceScriptExtensionState ) {
3942 super ( )
4043 const { context } = this . extensionState
@@ -71,21 +74,21 @@ export class DeveloperToolsManager extends JDEventSource {
7174 this . nodeVersion = nodeVersion
7275
7376 console . log (
74- `devicescript devtools version: ${ version } , bytecode version: ${ runtimeVersion } `
77+ `devicescript devtools ${ version } , runtime ${ runtimeVersion } , node ${ nodeVersion } `
7578 )
7679
7780 this . extensionState . bus . emit ( CHANGE )
7881 return true
7982 }
8083
81- get workspaceFolder ( ) {
82- return this . _workspaceFolder
84+ get projectFolder ( ) {
85+ return this . _projectFolder
8386 }
8487
85- set workspaceFolder ( folder : vscode . WorkspaceFolder ) {
86- if ( folder !== this . _workspaceFolder ) {
87- this . kill ( )
88- this . _workspaceFolder = folder
88+ set projectFolder ( folder : vscode . Uri ) {
89+ if ( folder ?. toString ( ) !== this . _projectFolder ?. toString ( ) ) {
90+ if ( this . _projectFolder ) this . kill ( )
91+ this . _projectFolder = folder
8992 this . emit ( CHANGE )
9093 }
9194 }
@@ -94,61 +97,92 @@ export class DeveloperToolsManager extends JDEventSource {
9497 return this . _connectionState
9598 }
9699
100+ get connected ( ) {
101+ return this . connectionState === ConnectionState . Connected
102+ }
103+
97104 private set connectionState ( state : ConnectionState ) {
98105 if ( state !== this . _connectionState ) {
99106 this . _connectionState = state
100107 this . emit ( CHANGE )
101108 }
102109 }
103110
104- async start ( ) : Promise < boolean > {
105- if ( ! this . _workspaceFolder ) {
106- const ws = vscode . workspace . workspaceFolders ?. filter ( ws =>
107- checkFileExists ( ws . uri , "./devsconfig.json" )
108- ) ?. [ 0 ]
109- this . workspaceFolder = ws
111+ async pickProject ( ) {
112+ const projects = await this . findProjects ( )
113+ if ( projects . length == 0 ) return undefined
114+ else if ( projects . length == 1 ) return projects [ 0 ]
115+ else {
116+ const items = projects . map (
117+ project =>
118+ < TaggedQuickPickItem < vscode . Uri > > {
119+ data : project ,
120+ description : Utils . dirname ( project ) . fsPath ,
121+ label : Utils . basename ( project ) ,
122+ }
123+ )
124+ const res = await vscode . window . showQuickPick ( items , {
125+ title : "Choose a project" ,
126+ } )
127+ return res ?. data
128+ }
129+ }
130+
131+ private async createTerminal ( ) : Promise < vscode . Terminal > {
132+ if ( ! this . _projectFolder ) this . _projectFolder = await this . pickProject ( )
133+ if ( ! this . _projectFolder ) {
134+ showTerminalError ( "No DeviceScript project in workspace." )
135+ return undefined
136+ }
137+ try {
138+ this . connectionState = ConnectionState . Connecting
139+ const t = await this . uncachedSpawnDevTools ( )
140+ if ( ! t ) {
141+ this . clear ( )
142+ return undefined
143+ }
144+ this . connectionState = ConnectionState . Connected
145+ return t
146+ } catch ( e ) {
147+ this . clear ( )
148+ return undefined
110149 }
150+ }
111151
152+ async start ( ) : Promise < void > {
112153 return (
113154 this . _terminalPromise ||
114- ( this . _terminalPromise = ( async ( ) => {
115- try {
116- this . connectionState = ConnectionState . Connecting
117- const t = await this . uncachedSpawnDevTools ( )
118- if ( ! t ) {
119- this . clear ( )
120- return undefined
121- }
122- this . _terminalPromise = Promise . resolve ( t )
123- this . connectionState = ConnectionState . Connected
124-
125- const devToolsConfig = vscode . workspace . getConfiguration (
126- "devicescript.devtools"
127- )
128- if ( devToolsConfig . get ( "showOnStart" ) ) t . show ( )
129- return this . _terminalPromise
130- } catch ( e ) {
131- this . clear ( )
132- return undefined
133- }
134- } ) ( ) )
135- ) . then ( ( ) => this . connectionState === ConnectionState . Connected )
155+ ( this . _terminalPromise = this . createTerminal ( ) )
156+ ) . then ( ( ) => { } )
136157 }
137158
138159 dispose ( ) {
139- // not awaited
140160 this . kill ( )
141161 }
142162
163+ private async kill ( ) {
164+ const p = this . _terminalPromise
165+ this . clear ( )
166+ if ( p ) {
167+ const t = await p
168+ if ( t ) {
169+ try {
170+ t . sendText ( "\u001c" )
171+ } catch { }
172+ }
173+ }
174+ }
175+
143176 private async handleWorkspaceFoldersChange (
144177 e : vscode . WorkspaceFoldersChangeEvent
145178 ) {
146- // make sure current workspace folder still exists
147- if (
148- this . _workspaceFolder &&
149- ! vscode . workspace . workspaceFolders ?. includes ( this . _workspaceFolder )
150- )
151- this . workspaceFolder = undefined
179+ if ( e . removed && this . _projectFolder ) {
180+ const projects = ( await this . findProjects ( ) ) . map ( uri =>
181+ uri . toString ( )
182+ )
183+ if ( ! projects . includes ( this . _projectFolder ?. toString ( ) ) )
184+ this . projectFolder = undefined
185+ }
152186 }
153187
154188 private async handleCloseTerminal ( t : vscode . Terminal ) {
@@ -161,23 +195,20 @@ export class DeveloperToolsManager extends JDEventSource {
161195
162196 private clear ( ) {
163197 this . _terminalPromise = undefined
198+ this . _projectFolder = undefined
164199 this . version = undefined
165200 this . runtimeVersion = undefined
166201 this . nodeVersion = undefined
167202 this . connectionState = ConnectionState . Disconnected
168203 }
169204
170- private async kill ( ) {
171- if ( ! this . _terminalPromise ) return
172-
173- this . connectionState = ConnectionState . Disconnecting
174- try {
175- const p = this . _terminalPromise
176- const terminal = await p
177- terminal ?. dispose ( )
178- } finally {
179- this . clear ( )
180- }
205+ async findProjects ( ) {
206+ // find file marker
207+ const configs = await vscode . workspace . findFiles (
208+ "**/devsconfig.json" ,
209+ "**/node_modules/**"
210+ )
211+ return configs . map ( cfg => Utils . dirname ( cfg ) )
181212 }
182213
183214 async show ( ) {
@@ -187,11 +218,11 @@ export class DeveloperToolsManager extends JDEventSource {
187218 }
188219
189220 private async uncachedSpawnDevTools ( ) : Promise < vscode . Terminal > {
190- if ( ! this . _workspaceFolder ) {
221+ if ( ! this . _projectFolder ) {
191222 return undefined
192223 }
193224
194- const cwd = this . _workspaceFolder . uri
225+ const cwd = this . _projectFolder
195226 const devsConfig = await checkFileExists ( cwd , "./devsconfig.json" )
196227 if ( ! devsConfig ) {
197228 showTerminalError ( "Could not find file `devsconfig.json`." )
@@ -218,9 +249,8 @@ export class DeveloperToolsManager extends JDEventSource {
218249 const useShell = ! ! devToolsConfig . get ( "shell" )
219250 const nodePath = devToolsConfig . get ( "node" ) as string
220251
221- const args = [ "devtools" , "--vscode" ]
222- const cli = nodePath || cliBin
223- if ( nodePath ) args . unshift ( cliBin )
252+ const args = [ cliBin , "devtools" , "--vscode" ]
253+ const cli = nodePath || "node"
224254
225255 console . debug (
226256 `create terminal: ${
@@ -230,7 +260,7 @@ export class DeveloperToolsManager extends JDEventSource {
230260 console . debug ( `cwd: ${ cwd } ` )
231261 const options : vscode . TerminalOptions = {
232262 name : "DeviceScript" ,
233- hideFromUser : true ,
263+ hideFromUser : false ,
234264 message : "DeviceScript Development Server\n" ,
235265 isTransient : true ,
236266 shellPath : useShell ? undefined : cli ,
@@ -243,13 +273,12 @@ export class DeveloperToolsManager extends JDEventSource {
243273 t . sendText ( "" , true )
244274 t . sendText ( `${ cli } ${ args . join ( " " ) } ` , true )
245275 }
246- await delay ( 1000 )
247276 let retry = 0
248277 let inited = false
249- while ( retry ++ < 5 ) {
278+ while ( retry ++ < 20 ) {
250279 inited = await this . init ( )
251280 if ( inited ) break
252- await delay ( 1000 )
281+ await delay ( 500 )
253282 }
254283 if ( ! inited ) {
255284 this . clear ( )
0 commit comments