11'use strict' ;
22
3- import { ExtensionContext , window , workspace , commands , Uri , ProgressLocation , ViewColumn , EventEmitter , extensions , Location , languages , CodeActionKind , TextEditor , CancellationToken , ConfigurationTarget , Range , Position , QuickPickItem } from "vscode" ;
3+ import { ExtensionContext , window , workspace , commands , Uri , ProgressLocation , ViewColumn , EventEmitter , extensions , Location , languages , CodeActionKind , TextEditor , CancellationToken , ConfigurationTarget , Range , Position , QuickPickItem , QuickPickItemKind } from "vscode" ;
44import { Commands } from "./commands" ;
55import { serverStatus , ServerStatusKind } from "./serverStatus" ;
66import { prepareExecutable , awaitServerConnection } from "./javaServerStarter" ;
77import { getJavaConfig , applyWorkspaceEdit } from "./extension" ;
88import { LanguageClientOptions , Position as LSPosition , Location as LSLocation , MessageType , TextDocumentPositionParams , ConfigurationRequest , ConfigurationParams } from "vscode-languageclient" ;
99import { LanguageClient , StreamInfo } from "vscode-languageclient/node" ;
10- import { CompileWorkspaceRequest , CompileWorkspaceStatus , SourceAttachmentRequest , SourceAttachmentResult , SourceAttachmentAttribute , ProjectConfigurationUpdateRequest , FeatureStatus , StatusNotification , ProgressReportNotification , ActionableNotification , ExecuteClientCommandRequest , ServerNotification , EventNotification , EventType , LinkLocation , FindLinks , GradleCompatibilityInfo , UpgradeGradleWrapperInfo } from "./protocol" ;
10+ import { CompileWorkspaceRequest , CompileWorkspaceStatus , SourceAttachmentRequest , SourceAttachmentResult , SourceAttachmentAttribute , ProjectConfigurationUpdateRequest , FeatureStatus , StatusNotification , ProgressReportNotification , ActionableNotification , ExecuteClientCommandRequest , ServerNotification , EventNotification , EventType , LinkLocation , FindLinks , GradleCompatibilityInfo , UpgradeGradleWrapperInfo , BuildProjectRequest , BuildProjectParams } from "./protocol" ;
1111import { setGradleWrapperChecksum , excludeProjectSettingsFiles , ServerMode } from "./settings" ;
1212import { onExtensionChange , collectBuildFilePattern } from "./plugin" ;
1313import { activationProgressNotification , serverTaskPresenter } from "./serverTaskPresenter" ;
@@ -395,6 +395,62 @@ export class StandardLanguageClient {
395395 typeHierarchyTree . changeBaseItem ( item ) ;
396396 } ) ) ;
397397
398+ context . subscriptions . push ( commands . registerCommand ( Commands . BUILD_PROJECT , async ( uris : Uri [ ] | Uri , isFullBuild : boolean , token : CancellationToken ) => {
399+ let resources : Uri [ ] = [ ] ;
400+ if ( uris instanceof Uri ) {
401+ resources . push ( uris ) ;
402+ } else if ( Array . isArray ( uris ) ) {
403+ for ( const uri of uris ) {
404+ if ( uri instanceof Uri ) {
405+ resources . push ( uri ) ;
406+ }
407+ }
408+ }
409+
410+ if ( ! resources . length ) {
411+ resources = await askForProjects (
412+ window . activeTextEditor ?. document . uri ,
413+ "Please select the project(s) to rebuild." ,
414+ ) ;
415+ if ( ! resources ?. length ) {
416+ return ;
417+ }
418+ }
419+
420+ const params : BuildProjectParams = {
421+ identifiers : resources . map ( ( u => {
422+ return { uri : u . toString ( ) } ;
423+ } ) ) ,
424+ // we can consider expose 'isFullBuild' according to users' feedback,
425+ // currently set it to true by default.
426+ isFullBuild : isFullBuild === undefined ? true : isFullBuild ,
427+ } ;
428+
429+ return window . withProgress ( { location : ProgressLocation . Window } , async p => {
430+ p . report ( { message : 'Rebuilding projects...' } ) ;
431+ return new Promise ( async ( resolve , reject ) => {
432+ const start = new Date ( ) . getTime ( ) ;
433+
434+ let res : CompileWorkspaceStatus ;
435+ try {
436+ res = token ? await this . languageClient . sendRequest ( BuildProjectRequest . type , params , token ) :
437+ await this . languageClient . sendRequest ( BuildProjectRequest . type , params ) ;
438+ } catch ( error ) {
439+ if ( error && error . code === - 32800 ) { // Check if the request is cancelled.
440+ res = CompileWorkspaceStatus . CANCELLED ;
441+ }
442+ reject ( error ) ;
443+ }
444+
445+ const elapsed = new Date ( ) . getTime ( ) - start ;
446+ const humanVisibleDelay = elapsed < 1000 ? 1000 : 0 ;
447+ setTimeout ( ( ) => { // set a timeout so user would still see the message when build time is short
448+ resolve ( res ) ;
449+ } , humanVisibleDelay ) ;
450+ } ) ;
451+ } ) ;
452+ } ) ) ;
453+
398454 context . subscriptions . push ( commands . registerCommand ( Commands . COMPILE_WORKSPACE , ( isFullCompile : boolean , token ?: CancellationToken ) => {
399455 return window . withProgress ( { location : ProgressLocation . Window } , async p => {
400456 if ( typeof isFullCompile !== 'boolean' ) {
@@ -588,7 +644,13 @@ function setIncompleteClasspathSeverity(severity: string) {
588644async function projectConfigurationUpdate ( languageClient : LanguageClient , uris ?: Uri | Uri [ ] ) {
589645 let resources = [ ] ;
590646 if ( ! uris ) {
591- resources = await askForProjectToUpdate ( ) ;
647+ const activeFileUri : Uri | undefined = window . activeTextEditor ?. document . uri ;
648+
649+ if ( activeFileUri && isJavaConfigFile ( activeFileUri . fsPath ) ) {
650+ resources = [ activeFileUri ] ;
651+ } else {
652+ resources = await askForProjects ( activeFileUri , "Please select the project(s) to update." ) ;
653+ }
592654 } else if ( uris instanceof Uri ) {
593655 resources . push ( uris ) ;
594656 } else if ( Array . isArray ( uris ) ) {
@@ -611,21 +673,44 @@ async function projectConfigurationUpdate(languageClient: LanguageClient, uris?:
611673 }
612674}
613675
614- async function askForProjectToUpdate ( ) : Promise < Uri [ ] > {
615- let uriCandidate : Uri ;
616- if ( window . activeTextEditor ) {
617- uriCandidate = window . activeTextEditor . document . uri ;
618- }
676+ /**
677+ * Ask user to select projects and return the selected projects' uris.
678+ * @param activeFileUri the uri of the active file.
679+ * @param placeHolder message to be shown in quick pick.
680+ */
681+ async function askForProjects ( activeFileUri : Uri | undefined , placeHolder : string ) : Promise < Uri [ ] > {
682+ const projectPicks : QuickPickItem [ ] = await generateProjectPicks ( activeFileUri ) ;
683+ if ( ! projectPicks ?. length ) {
684+ return [ ] ;
685+ } else if ( projectPicks . length === 1 ) {
686+ return [ Uri . file ( projectPicks [ 0 ] . detail ) ] ;
687+ } else {
688+ const choices : QuickPickItem [ ] | undefined = await window . showQuickPick ( projectPicks , {
689+ matchOnDetail : true ,
690+ placeHolder : placeHolder ,
691+ ignoreFocusOut : true ,
692+ canPickMany : true ,
693+ } ) ;
619694
620- if ( uriCandidate && isJavaConfigFile ( uriCandidate . fsPath ) ) {
621- return [ uriCandidate ] ;
695+ if ( choices ?. length ) {
696+ return choices . map ( c => Uri . file ( c . detail ) ) ;
697+ }
622698 }
623699
700+ return [ ] ;
701+ }
702+
703+ /**
704+ * Generate the quick picks for projects selection. An `undefined` value will be return if
705+ * it's failed to generate picks.
706+ * @param activeFileUri the uri of the active document.
707+ */
708+ async function generateProjectPicks ( activeFileUri : Uri | undefined ) : Promise < QuickPickItem [ ] | undefined > {
624709 let projectUriStrings : string [ ] ;
625710 try {
626711 projectUriStrings = await commands . executeCommand < string [ ] > ( Commands . EXECUTE_WORKSPACE_COMMAND , Commands . GET_ALL_JAVA_PROJECTS ) ;
627712 } catch ( e ) {
628- return uriCandidate ? [ uriCandidate ] : [ ] ;
713+ return undefined ;
629714 }
630715
631716 const projectPicks : QuickPickItem [ ] = projectUriStrings . map ( uriString => {
@@ -640,40 +725,24 @@ async function askForProjectToUpdate(): Promise<Uri[]> {
640725 } ;
641726 } ) . filter ( Boolean ) ;
642727
643- if ( projectPicks . length === 0 ) {
644- return [ ] ;
645- } else if ( projectPicks . length === 1 ) {
646- return [ Uri . file ( projectPicks [ 0 ] . detail ) ] ;
647- } else {
648- // pre-select an active project based on the uri candidate.
649- if ( uriCandidate ) {
650- const candidatePath = uriCandidate . fsPath ;
651- let belongingIndex = - 1 ;
652- for ( let i = 0 ; i < projectPicks . length ; i ++ ) {
653- if ( candidatePath . startsWith ( projectPicks [ i ] . detail ) ) {
654- if ( belongingIndex < 0
655- || projectPicks [ i ] . detail . length > projectPicks [ belongingIndex ] . detail . length ) {
656- belongingIndex = i ;
657- }
728+ // pre-select an active project based on the uri candidate.
729+ if ( activeFileUri ?. scheme === "file" ) {
730+ const candidatePath = activeFileUri . fsPath ;
731+ let belongingIndex = - 1 ;
732+ for ( let i = 0 ; i < projectPicks . length ; i ++ ) {
733+ if ( candidatePath . startsWith ( projectPicks [ i ] . detail ) ) {
734+ if ( belongingIndex < 0
735+ || projectPicks [ i ] . detail . length > projectPicks [ belongingIndex ] . detail . length ) {
736+ belongingIndex = i ;
658737 }
659738 }
660- if ( belongingIndex >= 0 ) {
661- projectPicks [ belongingIndex ] . picked = true ;
662- }
663739 }
664-
665- const choices : QuickPickItem [ ] | undefined = await window . showQuickPick ( projectPicks , {
666- matchOnDetail : true ,
667- placeHolder : "Please select the project(s) to update." ,
668- ignoreFocusOut : true ,
669- canPickMany : true ,
670- } ) ;
671- if ( choices && choices . length ) {
672- return choices . map ( c => Uri . file ( c . detail ) ) ;
740+ if ( belongingIndex >= 0 ) {
741+ projectPicks [ belongingIndex ] . picked = true ;
673742 }
674743 }
675744
676- return [ ] ;
745+ return projectPicks ;
677746}
678747
679748function isJavaConfigFile ( filePath : string ) {
0 commit comments