11'use strict' ;
22
3- import { StatusBarItem , window , StatusBarAlignment , TextEditor , Uri , commands , workspace , version } from "vscode" ;
3+ import * as fse from "fs-extra" ;
4+ import { StatusBarItem , window , StatusBarAlignment , TextEditor , Uri , commands , workspace , version , languages , Command , ExtensionContext } from "vscode" ;
45import { Commands } from "./commands" ;
56import { Disposable } from "vscode-languageclient" ;
67import * as path from "path" ;
78import { apiManager } from "./apiManager" ;
89import * as semver from "semver" ;
10+ import { ACTIVE_BUILD_TOOL_STATE } from "./settings" ;
11+ import { BuildFileStatusItemFactory , RuntimeStatusItemFactory , StatusCommands , supportsLanguageStatus } from "./languageStatusItemFactory" ;
12+ import { getJavaConfiguration } from "./utils" ;
13+ import { hasBuildToolConflicts } from "./extension" ;
914
1015class RuntimeStatusBarProvider implements Disposable {
1116 private statusBarItem : StatusBarItem ;
17+ private runtimeStatusItem : any ;
18+ private buildFileStatusItem : any ;
1219 private javaProjects : Map < string , IProjectInfo > ;
1320 private fileProjectMapping : Map < string , string > ;
1421 private storagePath : string | undefined ;
@@ -24,17 +31,20 @@ class RuntimeStatusBarProvider implements Disposable {
2431 this . isAdvancedStatusBarItem = semver . gte ( version , "1.57.0" ) ;
2532 }
2633
27- public async initialize ( storagePath ?: string ) : Promise < void > {
34+ public async initialize ( context : ExtensionContext ) : Promise < void > {
2835 // ignore the hash part to make it compatible in debug mode.
36+ const storagePath = context . storagePath ;
2937 if ( storagePath ) {
3038 this . storagePath = Uri . file ( path . join ( storagePath , ".." , ".." ) ) . fsPath ;
3139 }
3240
33- if ( this . isAdvancedStatusBarItem ) {
34- this . statusBarItem = ( window . createStatusBarItem as any ) ( "java.runtimeStatus" , StatusBarAlignment . Right , 0 ) ;
35- ( this . statusBarItem as any ) . name = "Java Runtime Configuration" ;
36- } else {
37- this . statusBarItem = window . createStatusBarItem ( StatusBarAlignment . Right , 0 ) ;
41+ if ( ! supportsLanguageStatus ( ) ) {
42+ if ( this . isAdvancedStatusBarItem ) {
43+ this . statusBarItem = ( window . createStatusBarItem as any ) ( "java.runtimeStatus" , StatusBarAlignment . Right , 0 ) ;
44+ ( this . statusBarItem as any ) . name = "Java Runtime Configuration" ;
45+ } else {
46+ this . statusBarItem = window . createStatusBarItem ( StatusBarAlignment . Right , 0 ) ;
47+ }
3848 }
3949
4050 let projectUriStrings : string [ ] ;
@@ -48,38 +58,48 @@ class RuntimeStatusBarProvider implements Disposable {
4858 this . javaProjects . set ( Uri . parse ( uri ) . fsPath , undefined ) ;
4959 }
5060
51- this . statusBarItem . command = {
52- title : "Configure Java Runtime" ,
53- command : "workbench.action.openSettings" ,
54- arguments : [ "java.configuration.runtimes" ] ,
55- } ;
61+ if ( ! supportsLanguageStatus ( ) ) {
62+ this . statusBarItem . command = StatusCommands . configureJavaRuntimeCommand ;
63+ }
5664
5765 this . disposables . push ( window . onDidChangeActiveTextEditor ( ( textEditor ) => {
58- this . updateItem ( textEditor ) ;
66+ this . updateItem ( context , textEditor ) ;
5967 } ) ) ;
6068
6169 this . disposables . push ( apiManager . getApiInstance ( ) . onDidProjectsImport ( async ( uris : Uri [ ] ) => {
6270 for ( const uri of uris ) {
6371 this . javaProjects . set ( uri . fsPath , this . javaProjects . get ( uri . fsPath ) ) ;
6472 }
65- await this . updateItem ( window . activeTextEditor ) ;
73+ await this . updateItem ( context , window . activeTextEditor ) ;
6674 } ) ) ;
6775
6876 this . disposables . push ( apiManager . getApiInstance ( ) . onDidClasspathUpdate ( async ( e : Uri ) => {
6977 for ( const projectPath of this . javaProjects . keys ( ) ) {
7078 if ( path . relative ( projectPath , e . fsPath ) === '' ) {
7179 this . javaProjects . set ( projectPath , undefined ) ;
72- await this . updateItem ( window . activeTextEditor ) ;
80+ await this . updateItem ( context , window . activeTextEditor ) ;
7381 return ;
7482 }
7583 }
7684 } ) ) ;
7785
78- await this . updateItem ( window . activeTextEditor ) ;
86+ await this . updateItem ( context , window . activeTextEditor ) ;
87+ }
88+
89+ private hideRuntimeStatusItem ( ) : void {
90+ this . runtimeStatusItem ?. dispose ( ) ;
91+ this . runtimeStatusItem = undefined ;
92+ }
93+
94+ private hideBuildFileStatusItem ( ) : void {
95+ this . buildFileStatusItem ?. dispose ( ) ;
96+ this . buildFileStatusItem = undefined ;
7997 }
8098
8199 public dispose ( ) : void {
82- this . statusBarItem . dispose ( ) ;
100+ this . statusBarItem ?. dispose ( ) ;
101+ this . runtimeStatusItem ?. dispose ( ) ;
102+ this . buildFileStatusItem ?. dispose ( ) ;
83103 for ( const disposable of this . disposables ) {
84104 disposable . dispose ( ) ;
85105 }
@@ -140,28 +160,54 @@ class RuntimeStatusBarProvider implements Disposable {
140160 return undefined ;
141161 }
142162
143- private async updateItem ( textEditor : TextEditor ) : Promise < void > {
144- if ( ! textEditor || path . extname ( textEditor . document . fileName ) !== ".java" ) {
145- this . statusBarItem . hide ( ) ;
163+ private async updateItem ( context : ExtensionContext , textEditor : TextEditor ) : Promise < void > {
164+ if ( ! textEditor || path . extname ( textEditor . document . fileName ) !== ".java" && ! supportsLanguageStatus ( ) ) {
165+ this . statusBarItem ? .hide ( ) ;
146166 return ;
147167 }
148168
149169 const uri : Uri = textEditor . document . uri ;
150170 const projectPath : string = this . findOwnerProject ( uri ) ;
151171 if ( ! projectPath ) {
152- this . statusBarItem . hide ( ) ;
172+ if ( supportsLanguageStatus ( ) ) {
173+ this . hideRuntimeStatusItem ( ) ;
174+ this . hideBuildFileStatusItem ( ) ;
175+ } else {
176+ this . statusBarItem ?. hide ( ) ;
177+ }
153178 return ;
154179 }
155180
156181 const projectInfo : IProjectInfo = await this . getProjectInfo ( projectPath ) ;
157182 if ( ! projectInfo ) {
158- this . statusBarItem . hide ( ) ;
183+ if ( supportsLanguageStatus ( ) ) {
184+ this . hideRuntimeStatusItem ( ) ;
185+ this . hideBuildFileStatusItem ( ) ;
186+ } else {
187+ this . statusBarItem ?. hide ( ) ;
188+ }
159189 return ;
160190 }
161191
162- this . statusBarItem . text = this . getJavaRuntimeFromVersion ( projectInfo . sourceLevel ) ;
163- this . statusBarItem . tooltip = projectInfo . vmInstallPath ? `Language Level: ${ this . statusBarItem . text } <${ projectInfo . vmInstallPath } >` : "Configure Java Runtime" ;
164- this . statusBarItem . show ( ) ;
192+ const text = this . getJavaRuntimeFromVersion ( projectInfo . sourceLevel ) ;
193+ if ( supportsLanguageStatus ( ) ) {
194+ const buildFilePath = await this . getBuildFilePath ( context , projectPath ) ;
195+ if ( ! this . runtimeStatusItem ) {
196+ this . runtimeStatusItem = RuntimeStatusItemFactory . create ( text , projectInfo . vmInstallPath ) ;
197+ if ( buildFilePath ) {
198+ this . buildFileStatusItem = BuildFileStatusItemFactory . create ( buildFilePath ) ;
199+ }
200+ } else {
201+ RuntimeStatusItemFactory . update ( this . runtimeStatusItem , text , projectInfo . vmInstallPath ) ;
202+ if ( buildFilePath ) {
203+ BuildFileStatusItemFactory . update ( this . buildFileStatusItem , buildFilePath ) ;
204+ }
205+ }
206+ } else {
207+ this . statusBarItem . text = text ;
208+ this . statusBarItem . tooltip = projectInfo . vmInstallPath ? `Language Level: ${ this . statusBarItem . text } <${ projectInfo . vmInstallPath } >` : "Configure Java Runtime" ;
209+ this . statusBarItem . show ( ) ;
210+ }
165211 }
166212
167213 private isDefaultProjectPath ( fsPath : string ) {
@@ -181,6 +227,45 @@ class RuntimeStatusBarProvider implements Disposable {
181227
182228 return `JavaSE-${ ver } ` ;
183229 }
230+
231+ private async getBuildFilePath ( context : ExtensionContext , projectPath : string ) : Promise < string | undefined > {
232+ const isMavenEnabled : boolean = getJavaConfiguration ( ) . get < boolean > ( "import.maven.enabled" ) ;
233+ const isGradleEnabled : boolean = getJavaConfiguration ( ) . get < boolean > ( "import.gradle.enabled" ) ;
234+ if ( isMavenEnabled && isGradleEnabled ) {
235+ let buildFilePath : string | undefined ;
236+ const activeBuildTool : string | undefined = context . workspaceState . get ( ACTIVE_BUILD_TOOL_STATE ) ;
237+ if ( ! activeBuildTool ) {
238+ if ( ! hasBuildToolConflicts ( ) ) {
239+ // only one build tool exists in the project
240+ buildFilePath = await this . getBuildFilePathFromNames ( projectPath , [ "pom.xml" , "build.gradle" , "build.gradle.kts" , "settings.gradle" , "settings.gradle.kts" ] ) ;
241+ } else {
242+ // the user has not resolved build conflicts yet
243+ return undefined ;
244+ }
245+ } else if ( activeBuildTool . toLocaleLowerCase ( ) . includes ( "maven" ) ) {
246+ buildFilePath = await this . getBuildFilePathFromNames ( projectPath , [ "pom.xml" ] ) ;
247+ } else if ( activeBuildTool . toLocaleLowerCase ( ) . includes ( "gradle" ) ) {
248+ buildFilePath = await this . getBuildFilePathFromNames ( projectPath , [ "build.gradle" , "build.gradle.kts" , "settings.gradle" , "settings.gradle.kts" ] ) ;
249+ }
250+ return buildFilePath ;
251+ } else if ( isMavenEnabled ) {
252+ return this . getBuildFilePathFromNames ( projectPath , [ "pom.xml" ] ) ;
253+ } else if ( isGradleEnabled ) {
254+ return this . getBuildFilePathFromNames ( projectPath , [ "build.gradle" , "build.gradle.kts" , "settings.gradle" , "settings.gradle.kts" ] ) ;
255+ } else {
256+ return undefined ;
257+ }
258+ }
259+
260+ private async getBuildFilePathFromNames ( projectPath : string , buildFileNames : string [ ] ) : Promise < string > {
261+ for ( const buildFileName of buildFileNames ) {
262+ const buildFilePath = path . join ( projectPath , buildFileName ) ;
263+ if ( await fse . pathExists ( buildFilePath ) ) {
264+ return buildFilePath ;
265+ }
266+ }
267+ return undefined ;
268+ }
184269}
185270
186271interface IProjectInfo {
0 commit comments