diff --git a/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/model/PackageNode.java b/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/model/PackageNode.java index 16eae609..aa439813 100644 --- a/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/model/PackageNode.java +++ b/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/model/PackageNode.java @@ -41,6 +41,11 @@ */ public class PackageNode { + /** + * Nature Id for the IProject + */ + private static final String NATURE_ID = "NatureId"; + public final static String K_TYPE_KIND = "TypeKind"; /** @@ -146,6 +151,11 @@ public static PackageNode createNodeForProject(IJavaElement javaElement) { IProject proj = javaElement.getJavaProject().getProject(); PackageNode projectNode = new PackageNode(proj.getName(), proj.getFullPath().toPortableString(), NodeKind.PROJECT); projectNode.setUri(proj.getLocationURI().toString()); + try { + projectNode.setMetaDataValue(NATURE_ID, proj.getDescription().getNatureIds()); + } catch (CoreException e) { + // do nothing + } return projectNode; } diff --git a/package.json b/package.json index a030162b..f54b8b47 100644 --- a/package.json +++ b/package.json @@ -46,12 +46,6 @@ "category": "Java", "icon": "$(add)" }, - { - "command": "java.project.maven.addDependency", - "title": "%contributes.commands.java.project.maven.addDependency%", - "category": "Java", - "icon": "$(add)" - }, { "command": "java.project.removeLibrary", "title": "%contributes.commands.java.project.removeLibrary%", @@ -217,10 +211,6 @@ "command": "java.project.addLibraries", "when": "never" }, - { - "command": "java.project.maven.addDependency", - "when": "never" - }, { "command": "java.project.removeLibrary", "when": "never" @@ -296,52 +286,47 @@ "view/item/context": [ { "command": "java.view.package.revealFileInOS", - "when": "view == javaProjectExplorer && viewItem =~ /java:.*?\\+uri/", + "when": "view == javaProjectExplorer && viewItem =~ /java:(?=.*?\\b\\+uri\\b)/", "group": "path@10" }, { "command": "java.view.package.copyFilePath", - "when": "view == javaProjectExplorer && viewItem =~ /java:.*?\\+uri/", + "when": "view == javaProjectExplorer && viewItem =~ /java:(?=.*?\\b\\+uri\\b)/", "group": "path@20" }, { "command": "java.view.package.copyRelativeFilePath", - "when": "view == javaProjectExplorer && viewItem =~ /java:.*?\\+uri/", + "when": "view == javaProjectExplorer && viewItem =~ /java:(?=.*?\\b\\+uri\\b)/", "group": "path@25" }, { "command": "java.view.package.newJavaClass", - "when": "view == javaProjectExplorer && viewItem =~ /java:(package|packageRoot).*\\+uri/", + "when": "view == javaProjectExplorer && viewItem =~ /java:(package|packageRoot)(?=.*?\\b\\+source\\b)(?=.*?\\b\\+uri\\b)/", "group": "new@10" }, { "command": "java.view.package.newPackage", - "when": "view == javaProjectExplorer && viewItem =~ /java:(package|packageRoot).*\\+uri/", + "when": "view == javaProjectExplorer && viewItem =~ /java:(package|packageRoot)(?=.*?\\b\\+source\\b)(?=.*?\\b\\+uri\\b)/", "group": "new@20" }, { "command": "java.project.addLibraries", - "when": "view == javaProjectExplorer && viewItem =~ /java:container\/referenced-libraries$/", + "when": "view == javaProjectExplorer && viewItem =~ /java:container(?=.*?\\b\\+referencedLibrary\\b)/", "group": "inline@0" }, { "command": "java.project.removeLibrary", - "when": "view == javaProjectExplorer && viewItem =~ /java:jar\/referenced-libraries\\+uri$/", + "when": "view == javaProjectExplorer && viewItem =~ /java:jar(?=.*?\\b\\+referencedLibrary\\b)(?=.*?\\b\\+uri\\b)/", "group": "inline" }, { "command": "java.project.refreshLibraries", - "when": "view == javaProjectExplorer && viewItem =~ /java:container\/referenced-libraries$/", + "when": "view == javaProjectExplorer && viewItem =~ /java:container(?=.*?\\b\\+referencedLibrary\\b)/", "group": "inline@1" }, - { - "command": "java.project.maven.addDependency", - "when": "view == javaProjectExplorer && mavenEnabled && viewItem =~ /container\/maven-dependencies/", - "group": "inline@0" - }, { "command": "java.view.package.exportJar", - "when": "view == javaProjectExplorer && viewItem =~ /java:workspace.*?\\+uri/ && java:serverMode!= LightWeight", + "when": "view == javaProjectExplorer && viewItem =~ /java:workspace(?=.*?\\b\\+uri\\b)/ && java:serverMode!= LightWeight", "group": "inline" } ] diff --git a/package.nls.json b/package.nls.json index e96fcbb8..b74906e4 100644 --- a/package.nls.json +++ b/package.nls.json @@ -2,7 +2,6 @@ "description": "Manage Java projects in Visual Studio Code", "contributes.commands.java.project.create": "Create Java Project...", "contributes.commands.java.project.addLibraries": "Add a jar file or a folder to project classpath", - "contributes.commands.java.project.maven.addDependency": "Add a new dependency to the Maven project", "contributes.commands.java.project.removeLibrary": "Remove jar file from project classpath", "contributes.commands.java.view.package.refresh": "Refresh", "contributes.commands.java.project.build.workspace": "Build Workspace", diff --git a/package.nls.zh.json b/package.nls.zh.json index da4135d9..2cf36f5a 100644 --- a/package.nls.zh.json +++ b/package.nls.zh.json @@ -2,7 +2,6 @@ "description": "在 Visual Studio Code 中管理 Java 项目", "contributes.commands.java.project.create": "创建 Java 项目...", "contributes.commands.java.project.addLibraries": "将一个 Jar 文件或一个目录添加到 Java 项目类路径中", - "contributes.commands.java.project.maven.addDependency": "为该 Maven 项目增加依赖库", "contributes.commands.java.project.removeLibrary": "将该 Jar 文件从 Java 项目类路径中移除", "contributes.commands.java.view.package.refresh": "刷新", "contributes.commands.java.project.build.workspace": "构建工作空间", diff --git a/src/commands.ts b/src/commands.ts index 2ac3ff44..4dfa687f 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -48,8 +48,6 @@ export namespace Commands { export const JAVA_PROJECT_CLEAN_WORKSPACE = "java.project.clean.workspace"; - export const JAVA_MAVEN_PROJECT_ADD_DEPENDENCY = "java.project.maven.addDependency"; - export const JAVA_MAVEN_CREATE_PROJECT = "maven.archetype.generate"; export const JAVA_PROJECT_LIST = "java.project.list"; diff --git a/src/constants.ts b/src/constants.ts index 1425aaee..897ef5a5 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -2,10 +2,17 @@ // Licensed under the MIT license. export namespace Context { - export const MAVEN_ENABLED: string = "mavenEnabled"; export const EXTENSION_ACTIVATED: string = "extensionActivated"; } export namespace Explorer { - export const DEFAULT_PACKAGE_NAME: string = "default-package"; + export const DEFAULT_PACKAGE_NAME: string = "(default package)"; + export enum ContextValueType { + WorkspaceFolder = "workspaceFolder", + Project = "project", + Container = "container", + PackageRoot = "packageRoot", + Package = "package", + Jar = "jar", + } } diff --git a/src/controllers/libraryController.ts b/src/controllers/libraryController.ts index 52e06fe9..d0c48db7 100644 --- a/src/controllers/libraryController.ts +++ b/src/controllers/libraryController.ts @@ -25,8 +25,6 @@ export class LibraryController implements Disposable { this.removeLibrary(Uri.parse(node.uri).fsPath)), instrumentOperationAsVsCodeCommand(Commands.JAVA_PROJECT_REFRESH_LIBRARIES, () => this.refreshLibraries()), - instrumentOperationAsVsCodeCommand(Commands.JAVA_MAVEN_PROJECT_ADD_DEPENDENCY, (node: ContainerNode) => - this.addMavenDependency(node)), ); } @@ -34,15 +32,6 @@ export class LibraryController implements Disposable { this.disposable.dispose(); } - public async addMavenDependency(node: ContainerNode) { - const pomPath: string = path.join(node.projectBasePath, "pom.xml"); - if (await fse.pathExists(pomPath)) { - commands.executeCommand("maven.project.addDependency", { pomPath }); - } else { - commands.executeCommand("maven.project.addDependency"); - } - } - public async addLibraries(libraryGlobs?: string[]) { if (!libraryGlobs) { libraryGlobs = []; diff --git a/src/extension.ts b/src/extension.ts index d81fa5d9..6bb6df6f 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -53,7 +53,6 @@ async function activateExtension(_operationId: string, context: ExtensionContext Settings.initialize(context); contextManager.initialize(context); - setMavenExtensionState(); context.subscriptions.push(new ProjectController(context)); context.subscriptions.push(new LibraryController(context)); @@ -65,19 +64,6 @@ async function activateExtension(_operationId: string, context: ExtensionContext initExpService(context); } -// determine if the add dependency shortcut will show or not -function setMavenExtensionState() { - setMavenEnabledContext(); - extensions.onDidChange(() => { - setMavenEnabledContext(); - }); - - function setMavenEnabledContext() { - const mavenExt: Extension | undefined = extensions.getExtension("vscjava.vscode-maven"); - contextManager.setContextValue(Context.MAVEN_ENABLED, !!mavenExt); - } -} - // this method is called when your extension is deactivated export async function deactivate() { await disposeTelemetryWrapper(); diff --git a/src/java/nodeData.ts b/src/java/nodeData.ts index f4d884eb..7e0f9beb 100644 --- a/src/java/nodeData.ts +++ b/src/java/nodeData.ts @@ -30,5 +30,5 @@ export interface INodeData { uri?: string; kind: NodeKind; children?: any[]; - metaData?: Map; + metaData?: { [id: string]: any }; } diff --git a/src/views/containerNode.ts b/src/views/containerNode.ts index 1f1b1f1d..89c14222 100644 --- a/src/views/containerNode.ts +++ b/src/views/containerNode.ts @@ -2,6 +2,7 @@ // Licensed under the MIT license. import { ThemeIcon, Uri } from "vscode"; +import { Explorer } from "../constants"; import { Jdtls } from "../java/jdtls"; import { INodeData, NodeKind } from "../java/nodeData"; import { DataNode } from "./dataNode"; @@ -33,10 +34,36 @@ export class ContainerNode extends DataNode { } protected get contextValue(): string { - return `container/${this.name}`; + let contextValue: string = Explorer.ContextValueType.Container; + const containerType: string = getContainerType(this._nodeData.path); + if (containerType) { + contextValue += `+${containerType}`; + } + return contextValue; } protected get iconPath(): ThemeIcon { return new ThemeIcon("library"); } } + +function getContainerType(containerPath: string | undefined): string { + if (!containerPath) { + return ""; + } else if (containerPath.startsWith(ContainerPath.JRE)) { + return "jre"; + } else if (containerPath.startsWith(ContainerPath.Maven)) { + return "maven"; + } else if (containerPath.startsWith(ContainerPath.Gradle)) { + return "gradle"; + } else if (containerPath.startsWith(ContainerPath.ReferencedLibrary)) { + return "referencedLibrary"; + } +} + +const enum ContainerPath { + JRE = "org.eclipse.jdt.launching.JRE_CONTAINER", + Maven = "org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER", + Gradle = "org.eclipse.buildship.core.gradleclasspathcontainer", + ReferencedLibrary = "REFERENCED_LIBRARIES_PATH", +} diff --git a/src/views/dataNode.ts b/src/views/dataNode.ts index b150e2bc..5fc95230 100644 --- a/src/views/dataNode.ts +++ b/src/views/dataNode.ts @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. -import * as _ from "lodash"; import { ProviderResult, ThemeIcon, TreeItem, TreeItemCollapsibleState, Uri } from "vscode"; import { INodeData } from "../java/nodeData"; import { ExplorerNode } from "./explorerNode"; @@ -41,8 +40,8 @@ export abstract class DataNode extends ExplorerNode { return this._nodeData.handlerIdentifier; } - public get name() { // return name like `referenced-library` - return _.kebabCase(this._nodeData.name); + public get name() { + return this._nodeData.name; } public async revealPaths(paths: INodeData[]): Promise { diff --git a/src/views/packageNode.ts b/src/views/packageNode.ts index b9cc4db2..37e2fbcf 100644 --- a/src/views/packageNode.ts +++ b/src/views/packageNode.ts @@ -2,6 +2,7 @@ // Licensed under the MIT license. import { ThemeIcon } from "vscode"; +import { Explorer } from "../constants"; import { Jdtls } from "../java/jdtls"; import { INodeData, NodeKind } from "../java/nodeData"; import { IPackageRootNodeData, PackageRootKind } from "../java/packageRootNodeData"; @@ -49,7 +50,9 @@ export class PackageNode extends DataNode { protected get contextValue(): string { const parentData = this._rootNode.nodeData; if (parentData.entryKind === PackageRootKind.K_SOURCE) { - return `package/${this.name}`; + return `${Explorer.ContextValueType.Package}+source`; + } else if (parentData.entryKind === PackageRootKind.K_BINARY) { + return `${Explorer.ContextValueType.Package}+binary`; } } } diff --git a/src/views/packageRootNode.ts b/src/views/packageRootNode.ts index 12f2ab66..31a5428b 100644 --- a/src/views/packageRootNode.ts +++ b/src/views/packageRootNode.ts @@ -2,6 +2,7 @@ // Licensed under the MIT license. import { ThemeIcon } from "vscode"; +import { Explorer } from "../constants"; import { Jdtls } from "../java/jdtls"; import { INodeData, NodeKind } from "../java/nodeData"; import { IPackageRootNodeData, PackageRootKind } from "../java/packageRootNodeData"; @@ -62,13 +63,19 @@ export class PackageRootNode extends DataNode { protected get contextValue(): string { const data = this.nodeData; if (data.entryKind === PackageRootKind.K_BINARY) { + let contextValue: string = Explorer.ContextValueType.Jar; const parent = this.getParent(); - return `jar/${parent.name}`; - } else if (!resourceRoots.includes(this._nodeData.name)) { + if (parent.path.startsWith("REFERENCED_LIBRARIES_PATH")) { + contextValue += "+referencedLibrary"; + } + return contextValue; + } else if (resourceRoots.includes(this._nodeData.name)) { // APIs in JDT does not have a consistent result telling whether a package root // is a source root or resource root, so we hard code some common resources root // here as a workaround. - return `packageRoot/${this.name}`; + return `${Explorer.ContextValueType.PackageRoot}+resource`; + } else { + return `${Explorer.ContextValueType.PackageRoot}+source`; } } diff --git a/src/views/projectNode.ts b/src/views/projectNode.ts index 3c309ea6..68b208fe 100644 --- a/src/views/projectNode.ts +++ b/src/views/projectNode.ts @@ -2,6 +2,7 @@ // Licensed under the MIT license. import { ThemeIcon } from "vscode"; +import { Explorer } from "../constants"; import { ContainerEntryKind, IContainerNodeData } from "../java/containerNodeData"; import { Jdtls } from "../java/jdtls"; import { INodeData, NodeKind } from "../java/nodeData"; @@ -69,7 +70,52 @@ export class ProjectNode extends DataNode { protected get iconPath(): ThemeIcon { return new ThemeIcon("project"); } + protected get contextValue(): string { - return `project/${this.name}`; + let contextValue: string = Explorer.ContextValueType.Project; + const natureIds: string[] | undefined = this.nodeData.metaData[NATURE_ID]; + if (natureIds) { + const attributeString: string = getProjectTypeAttributes(natureIds); + contextValue += attributeString; + } + return contextValue; + } +} + +function getProjectTypeAttributes(natureIds: string []): string { + let attributeString: string = ""; + for (const natureId of natureIds) { + const readableNature: string = getProjectType(natureId); + if (readableNature) { + attributeString += `+${readableNature}`; + } + } + return attributeString; +} + +function getProjectType(natureId: string): string { + switch (natureId) { + case NatureId.Java: + return ReadableNature.Java; + case NatureId.Maven: + return ReadableNature.Maven; + case NatureId.Gradle: + return ReadableNature.Gradle; + default: + return ""; } } + +enum NatureId { + Maven = "org.eclipse.m2e.core.maven2Nature", + Gradle = "org.eclipse.buildship.core.gradleprojectnature", + Java = "org.eclipse.jdt.core.javanature", +} + +enum ReadableNature { + Maven = "maven", + Gradle = "gradle", + Java = "java", +} + +const NATURE_ID = "NatureId"; diff --git a/src/views/workspaceNode.ts b/src/views/workspaceNode.ts index a8826ce2..01a246bb 100644 --- a/src/views/workspaceNode.ts +++ b/src/views/workspaceNode.ts @@ -2,6 +2,7 @@ // Licensed under the MIT license. import { ThemeIcon } from "vscode"; +import { Explorer } from "../constants"; import { Jdtls } from "../java/jdtls"; import { INodeData } from "../java/nodeData"; import { DataNode } from "./dataNode"; @@ -30,7 +31,8 @@ export class WorkspaceNode extends DataNode { protected get iconPath(): ThemeIcon { return new ThemeIcon("root-folder"); } + protected get contextValue(): string { - return `workspace/${this.name}`; + return Explorer.ContextValueType.WorkspaceFolder; } } diff --git a/test/explorer/contextValue.test.ts b/test/explorer/contextValue.test.ts new file mode 100644 index 00000000..572b8b19 --- /dev/null +++ b/test/explorer/contextValue.test.ts @@ -0,0 +1,162 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +import * as assert from "assert"; +import { Uri } from "vscode"; +import { INodeData, NodeKind } from "../../src/java/nodeData"; +import { PackageRootKind } from "../../src/java/packageRootNodeData"; +import { ContainerNode } from "../../src/views/containerNode"; +import { PackageNode } from "../../src/views/packageNode"; +import { PackageRootNode } from "../../src/views/packageRootNode"; +import { ProjectNode } from "../../src/views/projectNode"; +import { WorkspaceNode } from "../../src/views/workspaceNode"; + +// tslint:disable: only-arrow-functions +// tslint:disable: no-object-literal-type-assertion +suite("Context Value Tests", () => { + + test("test workspace node", async function() { + assert.equal((await workspace.getTreeItem()).contextValue, "java:workspaceFolder+uri"); + }); + + test("test Maven project node", async function() { + assert.equal((await mavenProject.getTreeItem()).contextValue, "java:project+java+maven+uri"); + }); + + test("test Gradle project node", async function() { + assert.equal((await gradleProject.getTreeItem()).contextValue, "java:project+java+gradle+uri"); + }); + + test("test JRE container node", async function() { + assert.equal((await jreContainer.getTreeItem()).contextValue, "java:container+jre+uri"); + }); + + test("test Maven container node", async function() { + assert.equal((await mavenContainer.getTreeItem()).contextValue, "java:container+maven+uri"); + }); + + test("test Gradle container node", async function() { + assert.equal((await gradleContainer.getTreeItem()).contextValue, "java:container+gradle+uri"); + }); + + test("test Referenced Libraries container node", async function() { + assert.equal((await referencedLibrariesContainer.getTreeItem()).contextValue, "java:container+referencedLibrary+uri"); + }); + + test("test source root node", async function() { + assert.equal((await sourceRoot.getTreeItem()).contextValue, "java:packageRoot+source+uri"); + }); + + test("test resource root node", async function() { + assert.equal((await resourceRoot.getTreeItem()).contextValue, "java:packageRoot+resource+uri"); + }); + + test("test dependency jar node", async function() { + assert.equal((await dependencyJar.getTreeItem()).contextValue, "java:jar+uri"); + }); + + test("test referenced library jar node", async function() { + assert.equal((await referencedLibraryJar.getTreeItem()).contextValue, "java:jar+referencedLibrary+uri"); + }); + + test("test source package node", async function() { + assert.equal((await sourcePackage.getTreeItem()).contextValue, "java:package+source+uri"); + }); + + test("test binary package node", async function() { + assert.equal((await binaryPackage.getTreeItem()).contextValue, "java:package+binary+uri"); + }); +}); + +// below are faked nodes only for test purpose +const workspace: WorkspaceNode = new WorkspaceNode({ + name: "workspace", + uri: Uri.file(__dirname).toString(), + kind: NodeKind.Workspace, +}, null); + +const mavenProject: ProjectNode = new ProjectNode({ + name: "mavenProject", + uri: Uri.file(__dirname).toString(), + kind: NodeKind.Project, + metaData: { + NatureId: ["org.eclipse.jdt.core.javanature", "org.eclipse.m2e.core.maven2Nature"], + }, +}, workspace); + +const gradleProject: ProjectNode = new ProjectNode({ + name: "gradleProject", + uri: Uri.file(__dirname).toString(), + kind: NodeKind.Project, + metaData: { + NatureId: ["org.eclipse.jdt.core.javanature", "org.eclipse.buildship.core.gradleprojectnature"], + }, +}, workspace); + +const jreContainer: ContainerNode = new ContainerNode({ + name: "jreContainer", + uri: Uri.file(__dirname).toString(), + kind: NodeKind.Container, + path: "org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11", +}, mavenProject, mavenProject); + +const mavenContainer: ContainerNode = new ContainerNode({ + name: "mavenContainer", + uri: Uri.file(__dirname).toString(), + kind: NodeKind.Container, + path: "org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER", +}, mavenProject, mavenProject); + +const gradleContainer: ContainerNode = new ContainerNode({ + name: "gradleContainer", + uri: Uri.file(__dirname).toString(), + kind: NodeKind.Container, + path: "org.eclipse.buildship.core.gradleclasspathcontainer", +}, gradleProject, gradleProject); + +const referencedLibrariesContainer: ContainerNode = new ContainerNode({ + name: "referencedLibrariesContainer", + uri: Uri.file(__dirname).toString(), + kind: NodeKind.Container, + path: "REFERENCED_LIBRARIES_PATH", +}, mavenProject, mavenProject); + +const sourceRoot: PackageRootNode = new PackageRootNode({ + name: "src/main/java", + uri: Uri.file(__dirname).toString(), + kind: NodeKind.PackageRoot, + entryKind: PackageRootKind.K_SOURCE, +} as INodeData, mavenContainer, mavenProject); + +const resourceRoot: PackageRootNode = new PackageRootNode({ + name: "src/main/resources", + uri: Uri.file(__dirname).toString(), + kind: NodeKind.PackageRoot, + entryKind: PackageRootKind.K_SOURCE, +} as INodeData, mavenContainer, mavenProject); + +const dependencyJar: PackageRootNode = new PackageRootNode({ + name: "junit-4.12.jar", + uri: Uri.file(__dirname).toString(), + kind: NodeKind.PackageRoot, + entryKind: PackageRootKind.K_BINARY, +} as INodeData, mavenContainer, mavenProject); + +const referencedLibraryJar: PackageRootNode = new PackageRootNode({ + name: "junit-4.12.jar", + uri: Uri.file(__dirname).toString(), + kind: NodeKind.PackageRoot, + entryKind: PackageRootKind.K_BINARY, +} as INodeData, referencedLibrariesContainer, mavenProject); + +const sourcePackage: PackageNode = new PackageNode({ + name: "com.microsoft.java", + uri: Uri.file(__dirname).toString(), + kind: NodeKind.Package, +}, sourceRoot, mavenProject, sourceRoot); + +const binaryPackage: PackageNode = new PackageNode({ + name: "junit", + uri: Uri.file(__dirname).toString(), + kind: NodeKind.Package, +}, dependencyJar, mavenProject, dependencyJar);