@@ -101,30 +101,67 @@ const versionRegex = /(\d+\.\d+\.?\d*)/g;
101101
102102export class MILanguageClient {
103103 private static _instances : Map < string , MILanguageClient > = new Map ( ) ;
104- private static lsChannelCache : Map < string , vscode . OutputChannel > = new Map ( ) ;
105- public languageClient : ExtendedLanguageClient | undefined ;
104+ private static lsChannels : Map < string , vscode . OutputChannel > = new Map ( ) ;
105+ private static stopTimers : Map < string , NodeJS . Timeout > = new Map ( ) ;
106+ private static stoppingInstances : Set < string > = new Set ( ) ;
107+ private static readonly STOP_DEBOUNCE_MS = 30000 ; // 30 seconds
108+ private languageClient : ExtendedLanguageClient | undefined ;
106109
107110 // eslint-disable-next-line @typescript-eslint/naming-convention
108111 private COMPATIBLE_JDK_VERSION = "11" ; // Minimum JDK version required to run the language server
109112 private _errorStack : ErrorType [ ] = [ ] ;
110113
111114 constructor ( private projectUri : string ) { }
112115
113- public static async getInstance ( projectUri : string ) : Promise < MILanguageClient > {
116+ public static async getInstance ( projectUri : string ) : Promise < ExtendedLanguageClient > {
117+ // Cancel any pending stop operation for this project
118+ const existingTimer = this . stopTimers . get ( projectUri ) ;
119+ if ( existingTimer ) {
120+ clearTimeout ( existingTimer ) ;
121+ this . stopTimers . delete ( projectUri ) ;
122+ }
123+
124+ // If instance is currently stopping, wait for it to complete and create a new one
125+ if ( this . stoppingInstances . has ( projectUri ) ) {
126+ // Wait a bit for the stop operation to complete
127+ await new Promise ( resolve => setTimeout ( resolve , 100 ) ) ;
128+ this . stoppingInstances . delete ( projectUri ) ;
129+ }
130+
114131 if ( ! this . _instances . has ( projectUri ) ) {
115132 const instance = new MILanguageClient ( projectUri ) ;
116133 await instance . launch ( projectUri ) ;
117134 this . _instances . set ( projectUri , instance ) ;
118135 }
119- return this . _instances . get ( projectUri ) ! ;
136+ const languageClient = this . _instances . get ( projectUri ) ! . languageClient ;
137+ if ( ! languageClient ) {
138+ const errorMessage = "Language client failed to initialize" ;
139+ window . showErrorMessage ( errorMessage ) ;
140+ throw new Error ( errorMessage ) ;
141+ }
142+ return languageClient ;
120143 }
121144
122145 public static async stopInstance ( projectUri : string ) {
123- const instance = this . _instances . get ( projectUri ) ;
124- if ( instance ) {
125- await instance . stop ( ) ;
126- this . _instances . delete ( projectUri ) ;
146+ // Cancel any existing timer for this project
147+ const existingTimer = this . stopTimers . get ( projectUri ) ;
148+ if ( existingTimer ) {
149+ clearTimeout ( existingTimer ) ;
127150 }
151+
152+ // Schedule the stop operation with debounce
153+ const timer = setTimeout ( async ( ) => {
154+ this . stoppingInstances . add ( projectUri ) ;
155+ const instance = this . _instances . get ( projectUri ) ;
156+ if ( instance ) {
157+ await instance . stop ( ) ;
158+ this . _instances . delete ( projectUri ) ;
159+ }
160+ this . stopTimers . delete ( projectUri ) ;
161+ this . stoppingInstances . delete ( projectUri ) ;
162+ } , this . STOP_DEBOUNCE_MS ) ;
163+
164+ this . stopTimers . set ( projectUri , timer ) ;
128165 }
129166
130167 public static async getAllInstances ( ) : Promise < MILanguageClient [ ] > {
@@ -136,10 +173,10 @@ export class MILanguageClient {
136173 }
137174
138175 public static getOrCreateOutputChannel ( projectUri : string ) : vscode . OutputChannel {
139- let channel = this . lsChannelCache . get ( projectUri ) ;
176+ let channel = this . lsChannels . get ( projectUri ) ;
140177 if ( ! channel ) {
141178 channel = vscode . window . createOutputChannel ( `Synapse Language Server - ${ path . basename ( projectUri ) } ` ) ;
142- this . lsChannelCache . set ( projectUri , channel ) ;
179+ this . lsChannels . set ( projectUri , channel ) ;
143180 }
144181 return channel ;
145182 }
0 commit comments