@@ -7,9 +7,11 @@ import {
77 ExtensionContext ,
88 FileType ,
99 OutputChannel ,
10+ ProgressLocation ,
1011 Selection ,
1112 Uri ,
1213 WorkspaceConfiguration ,
14+ commands ,
1315 extensions ,
1416 languages ,
1517 window ,
@@ -20,7 +22,7 @@ import * as Crypto from 'crypto';
2022import PortFinder from 'portfinder' ;
2123import * as Net from 'net' ;
2224import * as CommonsCommands from './commands' ;
23- import { RequestType , LanguageClientOptions , Position } from 'vscode-languageclient' ;
25+ import { RequestType , LanguageClientOptions , Position , State } from 'vscode-languageclient' ;
2426import { LanguageClient , StreamInfo , ServerOptions , ExecutableOptions , Executable } from 'vscode-languageclient/node' ;
2527import { Trace , NotificationType } from 'vscode-jsonrpc' ;
2628import * as P2C from 'vscode-languageclient/lib/common/protocolConverter' ;
@@ -185,11 +187,6 @@ async function prepareCdsArgs(options: ActivatorOptions, context: ExtensionConte
185187 } else {
186188 options . clientOptions . outputChannel . appendLine ( `CDS: No AOT cache found, will record cache on this run: ${ aotCachePath } ` ) ;
187189 cdsArgs . push ( `-XX:AOTCacheOutput=${ aotCachePath } ` ) ;
188- window . showInformationMessage (
189- 'Language Server: CDS training run in progress. ' +
190- 'To ensure the AOT cache is saved correctly, please exit VS Code normally when done rather than using "Reload Window".' ,
191- 'Got it'
192- ) ;
193190 }
194191
195192 if ( ! useSocket ) {
@@ -261,11 +258,62 @@ export async function activate(options: ActivatorOptions, context: ExtensionCont
261258 const useSocket = ! ! process . env [ 'SPRING_LS_USE_SOCKET' ] ;
262259 const cdsResult = await prepareCdsArgs ( options , context , jvm , useSocket ) ;
263260
261+ let client : LanguageClient ;
264262 if ( useSocket ) {
265- return setupLanguageClient ( context , await createServerOptionsForPortComm ( options , context , jvm , cdsResult ) , options , cdsResult ) ;
263+ client = await setupLanguageClient ( context , await createServerOptionsForPortComm ( options , context , jvm , cdsResult ) , options ) ;
266264 } else {
267- return setupLanguageClient ( context , await createServerOptions ( options , context , jvm , undefined , cdsResult ) , options , cdsResult ) ;
265+ client = await setupLanguageClient ( context , await createServerOptions ( options , context , jvm , undefined , cdsResult ) , options ) ;
266+ }
267+
268+ if ( cdsResult . isTrainingRun ) {
269+ handleCdsTrainingRun ( client , context , jvm ) ;
270+ }
271+
272+ return client ;
273+ }
274+
275+ function handleCdsTrainingRun ( client : LanguageClient , context : ExtensionContext , jvm : JVM ) {
276+ const disposable = client . onDidChangeState ( async e => {
277+ if ( e . newState === State . Running ) {
278+ disposable . dispose ( ) ;
279+ window . showInformationMessage (
280+ 'Language Server: CDS training run in progress. ' +
281+ 'To ensure the AOT cache is saved correctly, please exit VS Code normally when done rather than using "Reload Window".' ,
282+ 'Got it' , 'Finish Training Run'
283+ ) . then ( selection => {
284+ if ( selection === 'Finish Training Run' ) {
285+ window . withProgress ( {
286+ location : ProgressLocation . Notification ,
287+ title : 'Language Server: CDS' ,
288+ cancellable : false
289+ } , async progress => {
290+ progress . report ( { message : 'Stopping Language Server...' } ) ;
291+ await client . stop ( ) ;
292+ await waitForAotCache ( getAotCachePath ( context . extensionPath , jvm ) , progress ) ;
293+ commands . executeCommand ( 'workbench.action.reloadWindow' ) ;
294+ } ) ;
295+ }
296+ } ) ;
297+ }
298+ } ) ;
299+ context . subscriptions . push ( disposable ) ;
300+ return disposable ;
301+ }
302+
303+ async function waitForAotCache ( aotCachePath : string , progress : { report ( value : { message ?: string } ) : void } ) : Promise < void > {
304+ const maxWaitMs = 30000 ;
305+ const intervalMs = 1000 ;
306+ let waited = 0 ;
307+ while ( waited < maxWaitMs ) {
308+ if ( await fileExists ( aotCachePath ) ) {
309+ progress . report ( { message : 'AOT cache ready, reloading window...' } ) ;
310+ return ;
311+ }
312+ waited += intervalMs ;
313+ progress . report ( { message : `Waiting for AOT cache... (${ waited / 1000 } s)` } ) ;
314+ await new Promise ( resolve => setTimeout ( resolve , intervalMs ) ) ;
268315 }
316+ progress . report ( { message : 'Timed out waiting for AOT cache.' } ) ;
269317}
270318
271319async function createServerOptions ( options : ActivatorOptions , context : ExtensionContext , jvm : JVM , port ?: number , cdsResult ?: CdsResult ) : Promise < Executable > {
@@ -441,7 +489,7 @@ function connectToLS(context: ExtensionContext, options: ActivatorOptions): Prom
441489 return setupLanguageClient ( context , serverOptions , options ) ;
442490}
443491
444- function setupLanguageClient ( context : ExtensionContext , createServer : ServerOptions , options : ActivatorOptions , cdsResult ?: CdsResult ) : Promise < LanguageClient > {
492+ function setupLanguageClient ( context : ExtensionContext , createServer : ServerOptions , options : ActivatorOptions ) : Promise < LanguageClient > {
445493 // Create the language client and start the client.
446494 const client = new LanguageClient ( options . extensionId , options . extensionId ,
447495 createServer , options . clientOptions
@@ -463,7 +511,7 @@ function setupLanguageClient(context: ExtensionContext, createServer: ServerOpti
463511
464512 CommonsCommands . registerCommands ( context ) ;
465513
466- context . subscriptions . push ( { dispose : ( ) => cdsResult ?. isTrainingRun ? client . stop ( 10000 ) : client . stop ( ) } ) ;
514+ context . subscriptions . push ( { dispose : ( ) => client . stop ( ) } ) ;
467515 context . subscriptions . push ( highlightService ) ;
468516
469517 function toggleHighlightCodeLens ( ) {
0 commit comments