Skip to content

Commit e1fe563

Browse files
authored
fix: Show the hints in Java Projects explorer properly (#547)
1 parent ed3f478 commit e1fe563

File tree

10 files changed

+102
-109
lines changed

10 files changed

+102
-109
lines changed

package.json

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,16 @@
2727
}
2828
},
2929
"activationEvents": [
30+
"onLanguage:java",
31+
"workspaceContains:pom.xml",
32+
"workspaceContains:build.gradle",
33+
"workspaceContains:settings.gradle",
34+
"workspaceContains:build.gradle.kts",
35+
"workspaceContains:settings.gradle.kts",
36+
"workspaceContains:.classpath",
3037
"onCommand:_java.project.open",
3138
"onCommand:java.project.create",
32-
"onCommand:java.view.package.exportJar",
33-
"onCommand:java.view.package.revealInProjectExplorer",
34-
"onCommand:java.view.package.newJavaClass",
35-
"onView:javaProjectExplorer"
39+
"onCommand:java.view.package.newJavaClass"
3640
],
3741
"license": "MIT",
3842
"main": "./main.js",
@@ -266,7 +270,7 @@
266270
"commandPalette": [
267271
{
268272
"command": "java.view.package.exportJar",
269-
"when": "java:serverMode == Standard"
273+
"when": "java:serverMode == Standard && !java:noJavaProjects"
270274
},
271275
{
272276
"command": "java.view.package.refresh",
@@ -348,7 +352,7 @@
348352
"explorer/context": [
349353
{
350354
"command": "java.view.package.revealInProjectExplorer",
351-
"when": "resourceFilename in java:supportedBuildFiles && java:serverMode == Standard",
355+
"when": "resourceFilename =~ /(.*\\.gradle)|(.*\\.gradle\\.kts)|(pom\\.xml)$/ && java:serverMode == Standard",
352356
"group": "navigation@100"
353357
},
354358
{
@@ -360,7 +364,7 @@
360364
"editor/title/context": [
361365
{
362366
"command": "java.view.package.revealInProjectExplorer",
363-
"when": "resourceFilename in java:supportedBuildFiles && java:serverMode == Standard",
367+
"when": "resourceFilename =~ /(.*\\.gradle)|(.*\\.gradle\\.kts)|(pom\\.xml)$/ && java:serverMode == Standard",
364368
"group": "2_files@100"
365369
},
366370
{
@@ -372,7 +376,7 @@
372376
"view/title": [
373377
{
374378
"command": "java.project.create",
375-
"when": "view == javaProjectExplorer && java:serverMode == Standard",
379+
"when": "view == javaProjectExplorer",
376380
"group": "navigation@10"
377381
},
378382
{
@@ -515,9 +519,9 @@
515519
{
516520
"id": "javaProjectExplorer",
517521
"name": "Java Projects",
518-
"when": "java:serverMode",
519522
"contextualTitle": "Java Projects",
520-
"icon": "$(project)"
523+
"icon": "$(project)",
524+
"when": "resourceLangId == java || java:workspaceContainsBuildFiles || java:serverMode"
521525
}
522526
]
523527
},
@@ -536,6 +540,11 @@
536540
"view": "javaProjectExplorer",
537541
"contents": "%viewsWelcome.workbench.inLightWeightMode%",
538542
"when": "java:serverMode == LightWeight"
543+
},
544+
{
545+
"view": "javaProjectExplorer",
546+
"contents": "%viewsWelcome.workbench.installLanguageSupport%",
547+
"when": "java:projectManagerActivated && !java:languageSupportInstalled"
539548
}
540549
],
541550
"taskDefinitions": [

package.nls.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
"taskDefinitions.java.project.exportJar.dependencies": "The artifact dependencies in the runtime scope.",
3939
"taskDefinitions.java.project.exportJar.testDependencies": "The artifact dependencies in the test scope.",
4040
"viewsWelcome.workbench.createNewJavaProject": "You can also [open a Java project](command:_java.project.open), or create a new Java project by clicking the button below.\n[Create Java Project](command:java.project.create)",
41-
"viewsWelcome.workbench.noJavaProject": "No Java projects found in the current workspace. You can [open a Java project](command:_java.project.open), or create a new Java project by clicking the button below.\n[Create Java Project](command:java.project.create)",
42-
"viewsWelcome.workbench.inLightWeightMode": "No projects are listed because the Java Language Server is currently running in [LightWeight Mode](https://aka.ms/vscode-java-lightweight). To show projects, click on the button to switch to Standard Mode.\n[Switch to Standard Mode](command:java.server.mode.switch?%5B%22Standard%22,true%5D)"
41+
"viewsWelcome.workbench.noJavaProject": "No Java projects found in the current workspace. You can [open a Java project folder](command:_java.project.open), or create a new Java project by clicking the button below.\n[Create Java Project](command:java.project.create)",
42+
"viewsWelcome.workbench.inLightWeightMode": "To view the projects, you can import the projects into workspace.\n[Import Projects](command:java.server.mode.switch?%5B%22Standard%22,true%5D)",
43+
"viewsWelcome.workbench.installLanguageSupport": "The Java Projects explorer requires [Language Support for Java(TM) by Red Hat](command:extension.open?%5B%22redhat.java%22%5D) to provide full features.\n[Install](command:workbench.extensions.installExtension?%5B%22redhat.java%22%5D)"
4344
}

package.nls.zh.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
"taskDefinitions.java.project.exportJar.dependencies": "在 runtime scope 内的依赖。",
3939
"taskDefinitions.java.project.exportJar.testDependencies": "在 test scope 内的依赖。",
4040
"viewsWelcome.workbench.createNewJavaProject": "您也可以[打开一个 Java 项目](command:_java.project.open),或点击下方按钮创建一个新的 Java 项目。\n[创建 Java 项目](command:java.project.create)",
41-
"viewsWelcome.workbench.noJavaProject": "当前工作空间未发现 Java 项目,您可以[打开一个 Java 项目](command:_java.project.open),或点击下方按钮创建一个新的 Java 项目。\n[创建 Java 项目](command:java.project.create)",
42-
"viewsWelcome.workbench.inLightWeightMode": "由于 Java 语言服务正运行在 [LightWeight 模式](https://aka.ms/vscode-java-lightweight)下,因此项目将不会展示在该视图中。如果您需要展示项目信息,可以点击下方按钮将 Java 语言服务切换至 Standard 模式。\n[切换至 Standard 模式](command:java.server.mode.switch?%5B%22Standard%22,true%5D)"
41+
"viewsWelcome.workbench.noJavaProject": "当前工作空间未发现 Java 项目,您可以[打开一个 Java 项目目录](command:_java.project.open),或点击下方按钮创建一个新的 Java 项目。\n[创建 Java 项目](command:java.project.create)",
42+
"viewsWelcome.workbench.inLightWeightMode": "要浏览项目信息,你可以将项目导入到工作空间中。\n[导入项目](command:java.server.mode.switch?%5B%22Standard%22,true%5D)",
43+
"viewsWelcome.workbench.installLanguageSupport": "Java 项目视图需要安装并激活 [Language Support for Java(TM) by Red Hat](command:extension.open?%5B%22redhat.java%22%5D) 以提供完整的功能。\n[安装](command:workbench.extensions.installExtension?%5B%22redhat.java%22%5D)"
4344
}

src/constants.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33

44
export namespace Context {
55
export const EXTENSION_ACTIVATED: string = "java:projectManagerActivated";
6-
export const SUPPORTED_BUILD_FILES: string = "java:supportedBuildFiles";
7-
export const NO_JAVA_PEOJECT: string = "java:noJavaProjects";
6+
export const LANGUAGE_SUPPORT_INSTALLED: string = "java:languageSupportInstalled";
7+
export const NO_JAVA_PROJECT: string = "java:noJavaProjects";
8+
export const WORKSPACE_CONTAINS_BUILD_FILES: string = "java:workspaceContainsBuildFiles";
89
}
910

1011
export namespace Explorer {
@@ -21,10 +22,6 @@ export namespace Explorer {
2122
}
2223
}
2324

24-
export namespace Build {
25-
export const FILE_NAMES: string[] = ["pom.xml", "build.gradle"];
26-
}
27-
2825
export namespace ExtensionName {
2926
export const JAVA_LANGUAGE_SUPPORT: string = "redhat.java";
3027
}

src/exportJarSteps/ExportJarTaskProvider.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export async function executeExportJarTask(node?: INodeData): Promise<void> {
4040
// save the workspace first
4141
await workspace.saveAll(false /*includeUntitled*/);
4242

43-
if (!await languageServerApiManager.isStandardServerReady() || isExportingJar || await buildWorkspace() === false) {
43+
if (!await languageServerApiManager.ready() || isExportingJar || await buildWorkspace() === false) {
4444
return;
4545
}
4646
isExportingJar = true;

src/extension.ts

Lines changed: 12 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT license.
33

4-
import { Event, Extension, ExtensionContext, extensions, tasks, Uri } from "vscode";
4+
import { ExtensionContext, tasks, Uri, workspace } from "vscode";
55
import { dispose as disposeTelemetryWrapper, initializeFromJsonFile, instrumentOperation, sendInfo } from "vscode-extension-telemetry-wrapper";
66
import { contextManager } from "../extension.bundle";
7-
import { Build, Context, ExtensionName } from "./constants";
7+
import { Context } from "./constants";
88
import { LibraryController } from "./controllers/libraryController";
99
import { ProjectController } from "./controllers/projectController";
1010
import { init as initExpService } from "./ExperimentationService";
1111
import { ExportJarTaskProvider } from "./exportJarSteps/ExportJarTaskProvider";
12+
import { languageServerApiManager } from "./languageServerApi/languageServerApiManager";
1213
import { Settings } from "./settings";
1314
import { syncHandler } from "./syncHandler";
1415
import { EventCounter } from "./utility";
@@ -19,53 +20,26 @@ export async function activate(context: ExtensionContext): Promise<void> {
1920
await initializeFromJsonFile(context.asAbsolutePath("./package.json"), { firstParty: true });
2021
await initExpService(context);
2122
await instrumentOperation("activation", activateExtension)(context);
23+
languageServerApiManager.initializeJavaLanguageServerApi(false);
24+
// the when clause does not support 'workspaceContains' we used for activation event,
25+
// so we manually find the target files and set it to a context value.
26+
workspace.findFiles("{*.gradle,*.gradle.kts,pom.xml,.classpath}", undefined, 1).then((uris: Uri[]) => {
27+
if (uris && uris.length) {
28+
contextManager.setContextValue(Context.WORKSPACE_CONTAINS_BUILD_FILES, true);
29+
}
30+
});
2231
contextManager.setContextValue(Context.EXTENSION_ACTIVATED, true);
23-
contextManager.setContextValue(Context.SUPPORTED_BUILD_FILES, Build.FILE_NAMES);
2432
}
2533

2634
async function activateExtension(_operationId: string, context: ExtensionContext): Promise<void> {
35+
context.subscriptions.push(languageServerApiManager);
2736
context.subscriptions.push(new ProjectController(context));
2837
Settings.initialize(context);
2938
context.subscriptions.push(new LibraryController(context));
3039
context.subscriptions.push(DependencyExplorer.getInstance(context));
3140
context.subscriptions.push(contextManager);
3241
context.subscriptions.push(syncHandler);
3342
context.subscriptions.push(tasks.registerTaskProvider(ExportJarTaskProvider.exportJarType, new ExportJarTaskProvider()));
34-
35-
const pollingJLS = () => {
36-
const javaLanguageSupport: Extension<any> | undefined = extensions.getExtension(ExtensionName.JAVA_LANGUAGE_SUPPORT);
37-
if (!javaLanguageSupport) {
38-
return;
39-
}
40-
41-
if (javaLanguageSupport.isActive) {
42-
const extensionApi: any = javaLanguageSupport.exports;
43-
if (!extensionApi) {
44-
return;
45-
}
46-
47-
if (extensionApi.onDidClasspathUpdate) {
48-
const onDidClasspathUpdate: Event<Uri> = extensionApi.onDidClasspathUpdate;
49-
context.subscriptions.push(onDidClasspathUpdate(async () => {
50-
syncHandler.updateFileWatcher(Settings.autoRefresh());
51-
}));
52-
}
53-
54-
if (extensionApi.serverMode === "Standard") {
55-
syncHandler.updateFileWatcher(Settings.autoRefresh());
56-
} else {
57-
if (extensionApi.onDidServerModeChange) {
58-
const onDidServerModeChange: Event<string> = extensionApi.onDidServerModeChange;
59-
context.subscriptions.push(onDidServerModeChange(async () => {
60-
syncHandler.updateFileWatcher(Settings.autoRefresh());
61-
}));
62-
}
63-
}
64-
} else {
65-
setTimeout(pollingJLS, 3 * 1000 /*ms*/);
66-
}
67-
};
68-
pollingJLS();
6943
}
7044

7145
// this method is called when your extension is deactivated
Lines changed: 57 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,94 +1,114 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT license.
33

4-
import { commands, Event, Extension, extensions, Uri } from "vscode";
4+
import { commands, Disposable, Event, Extension, extensions, Uri } from "vscode";
55
import { Commands } from "../commands";
6+
import { Context, ExtensionName } from "../constants";
67
import { contextManager } from "../contextManager";
8+
import { Settings } from "../settings";
9+
import { syncHandler } from "../syncHandler";
710
import { LanguageServerMode } from "./LanguageServerMode";
811

9-
class LanguageServerApiManager {
12+
class LanguageServerApiManager implements Disposable {
13+
/**
14+
* undefined means a legacy version language server
15+
* null means the JDT.LS is not activated
16+
*/
1017
private serverMode: LanguageServerMode | null | undefined = null;
1118

12-
public async isStandardServerReady(): Promise<boolean> {
19+
private extensionChangeListener: Disposable;
20+
21+
public async ready(): Promise<boolean> {
1322
await this.checkServerMode();
14-
// undefined serverMode indicates an older version language server
15-
if (this.serverMode === undefined) {
16-
return true;
17-
}
1823

19-
if (this.serverMode !== LanguageServerMode.Standard) {
24+
if (this.serverMode === null || this.serverMode === LanguageServerMode.LightWeight) {
2025
return false;
2126
}
2227

23-
return true;
24-
}
25-
26-
public async isLightWeightMode(): Promise<boolean> {
27-
await this.checkServerMode();
28-
return this.serverMode === LanguageServerMode.LightWeight;
29-
}
30-
31-
public async awaitSwitchingServerFinished(): Promise<void> {
32-
await this.checkServerMode();
3328
if (this.serverMode === LanguageServerMode.Hybrid) {
3429
await new Promise<void>((resolve: () => void): void => {
3530
extensions.getExtension("redhat.java")!.exports.onDidServerModeChange(resolve);
3631
});
3732
}
38-
}
3933

40-
private async checkServerMode(): Promise<void> {
41-
if (this.serverMode === null) {
42-
await this.initializeJavaLanguageServerApi();
43-
}
34+
return true;
4435
}
4536

46-
private async initializeJavaLanguageServerApi(): Promise<void> {
47-
if (this.serverMode !== null) {
37+
public async initializeJavaLanguageServerApi(forceActivate: boolean = true): Promise<void> {
38+
if (this.isLanguageServerActivated()) {
4839
return;
4940
}
50-
const extension: Extension<any> | undefined = extensions.getExtension("redhat.java");
41+
42+
if (!this.extensionChangeListener) {
43+
this.extensionChangeListener = extensions.onDidChange(() => {
44+
if (this.serverMode === null) {
45+
commands.executeCommand(Commands.VIEW_PACKAGE_REFRESH, /* debounce = */false);
46+
}
47+
});
48+
}
49+
50+
const extension: Extension<any> | undefined = extensions.getExtension(ExtensionName.JAVA_LANGUAGE_SUPPORT);
5151
if (extension) {
52+
contextManager.setContextValue(Context.LANGUAGE_SUPPORT_INSTALLED, true);
53+
if (!forceActivate) {
54+
return;
55+
}
5256
await extension.activate();
5357
const extensionApi: any = extension.exports;
5458
if (!extensionApi) {
5559
return;
5660
}
5761

5862
this.serverMode = extensionApi.serverMode;
63+
if (this.serverMode === LanguageServerMode.Standard) {
64+
syncHandler.updateFileWatcher(Settings.autoRefresh());
65+
}
5966

6067
if (extensionApi.onDidClasspathUpdate) {
6168
const onDidClasspathUpdate: Event<Uri> = extensionApi.onDidClasspathUpdate;
62-
contextManager.context.subscriptions.push(onDidClasspathUpdate(async () => {
63-
await commands.executeCommand(Commands.VIEW_PACKAGE_REFRESH, /* debounce = */true);
69+
contextManager.context.subscriptions.push(onDidClasspathUpdate(() => {
70+
commands.executeCommand(Commands.VIEW_PACKAGE_REFRESH, /* debounce = */true);
71+
syncHandler.updateFileWatcher(Settings.autoRefresh());
6472
}));
6573
}
6674

6775
if (extensionApi.onDidServerModeChange) {
6876
const onDidServerModeChange: Event<string> = extensionApi.onDidServerModeChange;
69-
contextManager.context.subscriptions.push(onDidServerModeChange(async (mode: LanguageServerMode) => {
77+
contextManager.context.subscriptions.push(onDidServerModeChange((mode: LanguageServerMode) => {
7078
if (this.serverMode !== mode) {
71-
let needRefresh: boolean = true;
72-
if (this.serverMode === "Hybrid") {
73-
// Explorer will await when JLS is in Hybrid mode (activating),
74-
needRefresh = false;
75-
}
76-
this.serverMode = mode;
77-
if (needRefresh) {
79+
if (mode === LanguageServerMode.Hybrid) {
7880
commands.executeCommand(Commands.VIEW_PACKAGE_REFRESH, /* debounce = */false);
81+
} else if (mode === LanguageServerMode.Standard) {
82+
syncHandler.updateFileWatcher(Settings.autoRefresh());
7983
}
84+
this.serverMode = mode;
8085
}
8186
}));
8287
}
8388

8489
if (extensionApi.onDidProjectsImport) {
8590
const onDidProjectsImport: Event<Uri[]> = extensionApi.onDidProjectsImport;
86-
contextManager.context.subscriptions.push(onDidProjectsImport(async () => {
91+
contextManager.context.subscriptions.push(onDidProjectsImport(() => {
8792
commands.executeCommand(Commands.VIEW_PACKAGE_REFRESH, /* debounce = */true);
93+
syncHandler.updateFileWatcher(Settings.autoRefresh());
8894
}));
8995
}
9096
}
9197
}
98+
99+
public dispose() {
100+
this.extensionChangeListener.dispose();
101+
}
102+
103+
private isLanguageServerActivated(): boolean {
104+
return this.serverMode !== null;
105+
}
106+
107+
private async checkServerMode(): Promise<void> {
108+
if (!this.isLanguageServerActivated()) {
109+
await this.initializeJavaLanguageServerApi();
110+
}
111+
}
92112
}
93113

94114
export const languageServerApiManager: LanguageServerApiManager = new LanguageServerApiManager();

src/utility.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,8 @@ export class Utility {
3131
return false;
3232
}
3333

34-
await languageServerApiManager.awaitSwitchingServerFinished();
35-
if (!await languageServerApiManager.isStandardServerReady()) {
36-
return false;
37-
}
38-
return true;
34+
return languageServerApiManager.ready();
3935
}
40-
4136
}
4237

4338
export class EventCounter {

0 commit comments

Comments
 (0)