@@ -26,7 +26,7 @@ import {
2626import { LanguageClientConsumer } from "./languageClientConsumer" ;
2727import { SemVer , satisfies } from "semver" ;
2828
29- export enum SessionStatus {
29+ enum SessionStatus {
3030 NotStarted = "Not Started" ,
3131 Starting = "Starting" ,
3232 Running = "Running" ,
@@ -146,11 +146,34 @@ export class SessionManager implements Middleware {
146146 }
147147
148148 // The `exeNameOverride` is used by `restartSession` to override ANY other setting.
149+ // We've made this function idempotent, so it can used to ensure the session has started.
149150 public async start ( exeNameOverride ?: string ) : Promise < void > {
150- // A simple lock because this function isn't re-entrant.
151- if ( this . sessionStatus === SessionStatus . Starting ) {
151+ switch ( this . sessionStatus ) {
152+ case SessionStatus . NotStarted :
153+ // Go ahead and start.
154+ break ;
155+ case SessionStatus . Starting :
156+ // A simple lock because this function isn't re-entrant.
152157 this . logger . writeWarning ( "Re-entered 'start' so waiting..." ) ;
153- return await this . waitUntilStarted ( ) ;
158+ return await this . waitWhileStarting ( ) ;
159+ case SessionStatus . Running :
160+ // We're started, just return.
161+ this . logger . writeVerbose ( "Already started." ) ;
162+ return ;
163+ case SessionStatus . Busy :
164+ // We're started but busy so notify and return.
165+ // TODO: Make a proper notification for this and when IntelliSense is blocked.
166+ this . logger . write ( "The Extension Terminal is currently busy, please wait for your task to finish!" ) ;
167+ return ;
168+ case SessionStatus . Stopping :
169+ // Wait until done stopping, then start.
170+ this . logger . writeVerbose ( "Still stopping." ) ;
171+ await this . waitWhileStopping ( ) ;
172+ break ;
173+ case SessionStatus . Failed :
174+ // Try to start again.
175+ this . logger . writeVerbose ( "Previously failed, starting again." ) ;
176+ break ;
154177 }
155178
156179 this . setSessionStatus ( "Starting..." , SessionStatus . Starting ) ;
@@ -220,7 +243,7 @@ export class SessionManager implements Middleware {
220243 }
221244 }
222245
223- public async stop ( ) : Promise < void > {
246+ private async stop ( ) : Promise < void > {
224247 this . setSessionStatus ( "Stopping..." , SessionStatus . Stopping ) ;
225248 // Cancel start-up if we're still waiting.
226249 this . startCancellationTokenSource ?. cancel ( ) ;
@@ -255,7 +278,7 @@ export class SessionManager implements Middleware {
255278 this . setSessionStatus ( "Not Started" , SessionStatus . NotStarted ) ;
256279 }
257280
258- public async restartSession ( exeNameOverride ?: string ) : Promise < void > {
281+ private async restartSession ( exeNameOverride ?: string ) : Promise < void > {
259282 this . logger . write ( "Restarting session..." ) ;
260283 await this . stop ( ) ;
261284
@@ -267,22 +290,18 @@ export class SessionManager implements Middleware {
267290 }
268291
269292 public getSessionDetails ( ) : IEditorServicesSessionDetails | undefined {
270- // TODO: This is used solely by the debugger and should actually just wait (with a timeout) .
293+ // This is used by the debugger which should have already called `start` .
271294 if ( this . sessionDetails === undefined ) {
272295 void this . logger . writeAndShowError ( "PowerShell session unavailable for debugging!" ) ;
273296 }
274297 return this . sessionDetails ;
275298 }
276299
277- public getSessionStatus ( ) : SessionStatus {
278- return this . sessionStatus ;
279- }
280-
281300 public getPowerShellVersionDetails ( ) : IPowerShellVersionDetails | undefined {
282301 return this . versionDetails ;
283302 }
284303
285- public getNewSessionFilePath ( ) : vscode . Uri {
304+ private getNewSessionFilePath ( ) : vscode . Uri {
286305 const uniqueId : number = Math . floor ( 100000 + Math . random ( ) * 900000 ) ;
287306 return vscode . Uri . joinPath ( this . sessionsFolder , `PSES-VSCode-${ process . env . VSCODE_PID } -${ uniqueId } .json` ) ;
288307 }
@@ -334,14 +353,12 @@ export class SessionManager implements Middleware {
334353 }
335354
336355 public async waitUntilStarted ( ) : Promise < void > {
337- while ( this . sessionStatus === SessionStatus . Starting ) {
338- if ( this . startCancellationTokenSource ?. token . isCancellationRequested ) {
339- return ;
340- }
356+ while ( this . sessionStatus !== SessionStatus . Running ) {
341357 await utils . sleep ( 300 ) ;
342358 }
343359 }
344360
361+ // TODO: Is this used by the magic of "Middleware" in the client library?
345362 public resolveCodeLens (
346363 codeLens : vscode . CodeLens ,
347364 token : vscode . CancellationToken ,
@@ -803,6 +820,21 @@ Type 'help' to get help.
803820 return languageStatusItem ;
804821 }
805822
823+ private async waitWhileStarting ( ) : Promise < void > {
824+ while ( this . sessionStatus === SessionStatus . Starting ) {
825+ if ( this . startCancellationTokenSource ?. token . isCancellationRequested ) {
826+ return ;
827+ }
828+ await utils . sleep ( 300 ) ;
829+ }
830+ }
831+
832+ private async waitWhileStopping ( ) : Promise < void > {
833+ while ( this . sessionStatus === SessionStatus . Stopping ) {
834+ await utils . sleep ( 300 ) ;
835+ }
836+ }
837+
806838 private setSessionStatus ( detail : string , status : SessionStatus ) : void {
807839 this . logger . writeVerbose ( `Session status changing from '${ this . sessionStatus } ' to '${ status } '.` ) ;
808840 this . sessionStatus = status ;
@@ -842,7 +874,6 @@ Type 'help' to get help.
842874 this . languageStatusItem . severity = vscode . LanguageStatusSeverity . Error ;
843875 break ;
844876 }
845-
846877 }
847878
848879 private setSessionRunningStatus ( ) : void {
@@ -910,7 +941,7 @@ Type 'help' to get help.
910941 }
911942
912943 // Always shows the session terminal.
913- public showSessionTerminal ( isExecute ?: boolean ) : void {
944+ private showSessionTerminal ( isExecute ?: boolean ) : void {
914945 this . languageServerProcess ?. showTerminal ( isExecute && ! this . sessionSettings . integratedConsole . focusConsoleOnExecute ) ;
915946 }
916947
0 commit comments