1
1
'use strict' ;
2
2
3
- import { ExtensionContext , window , workspace , commands , Uri , ProgressLocation , ViewColumn , EventEmitter , extensions , Location , languages , CodeActionKind , TextEditor , CancellationToken } from "vscode" ;
3
+ import { ExtensionContext , window , workspace , commands , Uri , ProgressLocation , ViewColumn , EventEmitter , extensions , Location , languages , CodeActionKind , TextEditor , CancellationToken , ConfigurationTarget , Range , Position } from "vscode" ;
4
4
import { Commands } from "./commands" ;
5
5
import { serverStatus , ServerStatusKind } from "./serverStatus" ;
6
6
import { prepareExecutable , awaitServerConnection } from "./javaServerStarter" ;
7
7
import { getJavaConfig , applyWorkspaceEdit } from "./extension" ;
8
8
import { LanguageClientOptions , Position as LSPosition , Location as LSLocation , MessageType , TextDocumentPositionParams , ConfigurationRequest , ConfigurationParams } from "vscode-languageclient" ;
9
9
import { LanguageClient , StreamInfo } from "vscode-languageclient/node" ;
10
- import { CompileWorkspaceRequest , CompileWorkspaceStatus , SourceAttachmentRequest , SourceAttachmentResult , SourceAttachmentAttribute , ProjectConfigurationUpdateRequest , FeatureStatus , StatusNotification , ProgressReportNotification , ActionableNotification , ExecuteClientCommandRequest , ServerNotification , EventNotification , EventType , LinkLocation , FindLinks } from "./protocol" ;
10
+ import { CompileWorkspaceRequest , CompileWorkspaceStatus , SourceAttachmentRequest , SourceAttachmentResult , SourceAttachmentAttribute , ProjectConfigurationUpdateRequest , FeatureStatus , StatusNotification , ProgressReportNotification , ActionableNotification , ExecuteClientCommandRequest , ServerNotification , EventNotification , EventType , LinkLocation , FindLinks , GradleCompatibilityInfo } from "./protocol" ;
11
11
import { setGradleWrapperChecksum , excludeProjectSettingsFiles , ServerMode } from "./settings" ;
12
12
import { onExtensionChange , collectBuildFilePattern } from "./plugin" ;
13
13
import { activationProgressNotification , serverTaskPresenter } from "./serverTaskPresenter" ;
14
- import { RequirementsData } from "./requirements" ;
14
+ import { getJdkUrl , RequirementsData , sortJdksBySource , sortJdksByVersion } from "./requirements" ;
15
15
import * as net from 'net' ;
16
16
import * as fse from 'fs-extra' ;
17
17
import * as path from 'path' ;
@@ -32,9 +32,15 @@ import { typeHierarchyTree } from "./typeHierarchy/typeHierarchyTree";
32
32
import { TypeHierarchyDirection , TypeHierarchyItem } from "./typeHierarchy/protocol" ;
33
33
import { buildFilePatterns } from './plugin' ;
34
34
import { pomCodeActionMetadata , PomCodeActionProvider } from "./pom/pomCodeActionProvider" ;
35
+ import { findRuntimes , IJavaRuntime } from "jdk-utils" ;
35
36
36
37
const extensionName = 'Language Support for Java' ;
37
38
const GRADLE_CHECKSUM = "gradle/checksum/prompt" ;
39
+ const GET_JDK = "Get the Java Development Kit" ;
40
+ const USE_JAVA = "Use Java " ;
41
+ const AS_GRADLE_JVM = " as Gradle JVM" ;
42
+ const UPGRADE_GRADLE = "Upgrade Gradle to " ;
43
+ const GRADLE_IMPORT_JVM = "java.import.gradle.java.home" ;
38
44
39
45
export class StandardLanguageClient {
40
46
@@ -141,7 +147,7 @@ export class StandardLanguageClient {
141
147
serverTasks . updateServerTask ( progress ) ;
142
148
} ) ;
143
149
144
- this . languageClient . onNotification ( EventNotification . type , ( notification ) => {
150
+ this . languageClient . onNotification ( EventNotification . type , async ( notification ) => {
145
151
switch ( notification . eventType ) {
146
152
case EventType . ClasspathUpdated :
147
153
apiManager . fireDidClasspathUpdate ( Uri . parse ( notification . data ) ) ;
@@ -157,6 +163,23 @@ export class StandardLanguageClient {
157
163
apiManager . fireDidProjectsImport ( projectUris ) ;
158
164
}
159
165
break ;
166
+ case EventType . IncompatibleGradleJdkIssue :
167
+ const options : string [ ] = [ ] ;
168
+ const info = notification . data as GradleCompatibilityInfo ;
169
+ const highestJavaVersion = Number ( info . highestJavaVersion ) ;
170
+ let runtimes = await findRuntimes ( { checkJavac : true , withVersion : true , withTags : true } ) ;
171
+ runtimes = runtimes . filter ( runtime => {
172
+ return runtime . version . major <= highestJavaVersion ;
173
+ } ) ;
174
+ sortJdksByVersion ( runtimes ) ;
175
+ sortJdksBySource ( runtimes ) ;
176
+ options . push ( UPGRADE_GRADLE + info . recommendedGradleVersion ) ;
177
+ if ( ! runtimes . length ) {
178
+ options . push ( GET_JDK ) ;
179
+ } else {
180
+ options . push ( USE_JAVA + runtimes [ 0 ] . version . major + AS_GRADLE_JVM ) ;
181
+ }
182
+ this . showGradleCompatibilityIssueNotification ( info . message , options , info . projectUri , runtimes [ 0 ] ?. homedir ) ;
160
183
default :
161
184
break ;
162
185
}
@@ -230,6 +253,44 @@ export class StandardLanguageClient {
230
253
this . status = ClientStatus . Initialized ;
231
254
}
232
255
256
+ private showGradleCompatibilityIssueNotification ( message : string , options : string [ ] , projectUri : string , newJavaHome : string ) {
257
+ window . showErrorMessage ( message + " [Learn More](https://docs.gradle.org/current/userguide/compatibility.html)" , ...options ) . then ( async ( choice ) => {
258
+ if ( choice === GET_JDK ) {
259
+ commands . executeCommand ( Commands . OPEN_BROWSER , Uri . parse ( getJdkUrl ( ) ) ) ;
260
+ } else if ( choice . startsWith ( USE_JAVA ) ) {
261
+ await workspace . getConfiguration ( ) . update ( GRADLE_IMPORT_JVM , newJavaHome , ConfigurationTarget . Global ) ;
262
+ commands . executeCommand ( "workbench.action.openSettings" , GRADLE_IMPORT_JVM ) ;
263
+ commands . executeCommand ( Commands . IMPORT_PROJECTS ) ;
264
+ } else if ( choice . startsWith ( UPGRADE_GRADLE ) ) {
265
+ const useWrapper = workspace . getConfiguration ( ) . get < boolean > ( "java.import.gradle.wrapper.enabled" ) ;
266
+ if ( ! useWrapper ) {
267
+ await workspace . getConfiguration ( ) . update ( "java.import.gradle.wrapper.enabled" , true , ConfigurationTarget . Workspace ) ;
268
+ }
269
+ const result = await window . withProgress ( {
270
+ location : ProgressLocation . Notification ,
271
+ title : "Upgrading Gradle wrapper..." ,
272
+ cancellable : true ,
273
+ } , ( _progress , token ) => {
274
+ return commands . executeCommand ( Commands . EXECUTE_WORKSPACE_COMMAND , "java.project.upgradeGradle" , projectUri , token ) ;
275
+ } ) ;
276
+ if ( result ) {
277
+ const propertiesFile = path . join ( Uri . parse ( projectUri ) . fsPath , "gradle" , "wrapper" , "gradle-wrapper.properties" ) ;
278
+ if ( fse . pathExists ( propertiesFile ) ) {
279
+ const content = await fse . readFile ( propertiesFile ) ;
280
+ const offset = content . toString ( ) . indexOf ( "distributionUrl" ) ;
281
+ if ( offset >= 0 ) {
282
+ const document = await workspace . openTextDocument ( propertiesFile ) ;
283
+ const position = document . positionAt ( offset ) ;
284
+ const distributionUrlRange = document . getWordRangeAtPosition ( position ) ;
285
+ window . showTextDocument ( document , { selection : new Range ( distributionUrlRange . start , new Position ( distributionUrlRange . start . line + 1 , 0 ) ) } ) ;
286
+ }
287
+ }
288
+ commands . executeCommand ( Commands . IMPORT_PROJECTS ) ;
289
+ }
290
+ }
291
+ } ) ;
292
+ }
293
+
233
294
private registerCommandsForStandardServer ( context : ExtensionContext , jdtEventEmitter : EventEmitter < Uri > ) : void {
234
295
context . subscriptions . push ( commands . registerCommand ( Commands . IMPORT_PROJECTS , async ( ) => {
235
296
return await commands . executeCommand < void > ( Commands . EXECUTE_WORKSPACE_COMMAND , Commands . IMPORT_PROJECTS ) ;
0 commit comments