Skip to content

Commit

Permalink
Add more project types for creation and expose the command in explorer (
Browse files Browse the repository at this point in the history
  • Loading branch information
jdneo committed Jul 20, 2020
1 parent 0e79ba1 commit d2d70f0
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 93 deletions.
18 changes: 12 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@
{
"command": "java.project.create",
"title": "%contributes.commands.java.project.create%",
"category": "Java"
"category": "Java",
"icon": "$(add)"
},
{
"command": "java.project.addLibraries",
Expand Down Expand Up @@ -205,27 +206,32 @@
{
"command": "java.view.package.refresh",
"when": "view == javaProjectExplorer && java:serverMode!= LightWeight",
"group": "navigation@2"
"group": "navigation@40"
},
{
"command": "java.view.package.changeToHierarchicalPackageView",
"when": "view == javaProjectExplorer && config.java.dependency.packagePresentation == flat && java:serverMode!= LightWeight",
"group": "navigation@1"
"group": "navigation@30"
},
{
"command": "java.view.package.changeToFlatPackageView",
"when": "view == javaProjectExplorer && config.java.dependency.packagePresentation != flat && java:serverMode!= LightWeight",
"group": "navigation@1"
"group": "navigation@30"
},
{
"command": "java.view.package.linkWithFolderExplorer",
"when": "view == javaProjectExplorer && config.java.dependency.syncWithFolderExplorer != true && java:serverMode!= LightWeight",
"group": "navigation@0"
"group": "navigation@20"
},
{
"command": "java.view.package.unlinkWithFolderExplorer",
"when": "view == javaProjectExplorer && config.java.dependency.syncWithFolderExplorer == true && java:serverMode!= LightWeight",
"group": "navigation@0"
"group": "navigation@20"
},
{
"command": "java.project.create",
"when": "view == javaProjectExplorer",
"group": "navigation@10"
}
],
"view/item/context": [
Expand Down
2 changes: 1 addition & 1 deletion package.nls.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"description": "Manage Java projects in Visual Studio Code",
"contributes.commands.java.project.create": "Create Java Project",
"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",
Expand Down
2 changes: 1 addition & 1 deletion package.nls.zh.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"description": "在 Visual Studio Code 中管理 Java 项目",
"contributes.commands.java.project.create": "创建 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 项目类路径中移除",
Expand Down
243 changes: 158 additions & 85 deletions src/controllers/projectController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,9 @@
import * as fse from "fs-extra";
import * as _ from "lodash";
import * as path from "path";
import { commands, Disposable, ExtensionContext, QuickPickItem, Uri, window, workspace } from "vscode";
import { instrumentOperationAsVsCodeCommand, sendInfo } from "vscode-extension-telemetry-wrapper";
import { commands, Disposable, Extension, ExtensionContext, extensions, QuickPickItem, Uri, window, workspace } from "vscode";
import { instrumentOperationAsVsCodeCommand } from "vscode-extension-telemetry-wrapper";
import { Commands } from "../commands";
import { Context } from "../constants";
import { contextManager } from "../contextManager";
import { getExpService } from "../ExperimentationService";
import { Utility } from "../utility";

export class ProjectController implements Disposable {
Expand All @@ -27,97 +24,173 @@ export class ProjectController implements Disposable {
}

public async createJavaProject() {
const projectKinds: QuickPickItem[] = [{
label: BuildTool.None,
detail: "A project without any build tools",
}];
if (contextManager.getContextValue(Context.MAVEN_ENABLED)) {
const isMavenDefault: boolean = await getExpService()?.isCachedFlightEnabled("defaultMaven") || false;
const mavenItem: QuickPickItem = {
label: BuildTool.Maven,
detail: "Use Maven to manage your project",
const items: IProjectTypeQuickPick[] = projectTypes.map((type: IProjectType) => {
return {
label: type.displayName,
description: type.description,
detail: type.metadata.extensionName ? `Provided by $(extensions) ${type.metadata.extensionName}` : type.detail,
metadata: type.metadata,
};
if (isMavenDefault) {
projectKinds.unshift(mavenItem);
} else {
projectKinds.push(mavenItem);
}
}
const choice: QuickPickItem | undefined = projectKinds.length === 1 ? projectKinds[0] :
await window.showQuickPick(projectKinds, {
ignoreFocusOut: true,
placeHolder: "Select the project build tool",
},
);

if (!choice) {
});
const choice = await window.showQuickPick(items, {
ignoreFocusOut: true,
placeHolder: "Select the project type",
});
if (!choice || !await ensureExtension(choice.label, choice.metadata)) {
return;
}

if (projectKinds.length > 1) {
const chooseDefault: boolean = choice.label === projectKinds[0].label;
sendInfo("", {"project.create.chooseDefault": `${chooseDefault}`});
}

switch (choice.label) {
case BuildTool.Maven:
await commands.executeCommand(Commands.JAVA_MAVEN_CREATE_PROJECT);
break;
case BuildTool.None:
await this.scaffoldSimpleProject();
break;
default:
break;
if (choice.metadata.type === ProjectType.NoBuildTool) {
await scaffoldSimpleProject();
} else if (choice.metadata.createCommandId) {
await commands.executeCommand(choice.metadata.createCommandId);
}
}
}

private async scaffoldSimpleProject(): Promise<void> {
const workspaceFolder = Utility.getDefaultWorkspaceFolder();
const location: Uri[] | undefined = await window.showOpenDialog({
defaultUri: workspaceFolder && workspaceFolder.uri,
canSelectFiles: false,
canSelectFolders: true,
openLabel: "Select the location",
});
if (!location || !location.length) {
return;
}
interface IProjectType {
displayName: string;
description?: string;
detail?: string;
metadata: IProjectTypeMetadata;
}

const basePath: string = location[0].fsPath;
const projectName: string | undefined = await window.showInputBox({
prompt: "Input a java project name",
ignoreFocusOut: true,
validateInput: async (name: string): Promise<string> => {
if (name && !name.match(/^[^*~/\\]+$/)) {
return "Please input a valid project name";
}
if (name && await fse.pathExists(path.join(basePath, name))) {
return "A project with this name already exists.";
}
return "";
},
});
interface IProjectTypeMetadata {
type: ProjectType;
extensionId: string;
extensionName: string;
createCommandId: string;
}

if (!projectName) {
return;
}
interface IProjectTypeQuickPick extends QuickPickItem {
metadata: IProjectTypeMetadata;
}

const projectRoot: string = path.join(basePath, projectName);
const templateRoot: string = path.join(this.context.extensionPath, "templates", "invisible-project");
try {
await fse.ensureDir(projectRoot);
await fse.copy(templateRoot, projectRoot);
await fse.ensureDir(path.join(projectRoot, "lib"));
} catch (error) {
window.showErrorMessage(error.message);
return;
}
const openInNewWindow = workspace && !_.isEmpty(workspace.workspaceFolders);
await commands.executeCommand(Commands.VSCODE_OPEN_FOLDER, Uri.file(path.join(basePath, projectName)), openInNewWindow);
enum ProjectType {
NoBuildTool = "NoBuildTool",
Maven = "Maven",
SpringBoot = "SpringBoot",
Quarkus = "Quarkus",
MicroProfile = "MicroProfile",
}

async function ensureExtension(typeName: string, metaData: IProjectTypeMetadata): Promise<boolean> {
if (!metaData.extensionId) {
return true;
}

const extension: Extension<any> | undefined = extensions.getExtension(metaData.extensionId);
if (extension === undefined) {
await promptInstallExtension(typeName, metaData);
return false;
}

await extension.activate();
return true;
}

enum BuildTool {
Maven = "Maven",
None = "No build tools",
async function promptInstallExtension(projectType: string, metaData: IProjectTypeMetadata): Promise<void> {
const choice: string | undefined = await window.showInformationMessage(`${metaData.extensionName} is required to create ${projectType} projects. Please re-run the command 'Java: Create Java Project...' after the extension is installed.`, "Install");
if (choice === "Install") {
commands.executeCommand("workbench.extensions.installExtension", metaData.extensionId);
// So far there is no API to query the extension's state, so we open the extension's homepage
// here, where users can check the state: installing, disabled, installed, etc...
// See: https://github.com/microsoft/vscode/issues/14444
commands.executeCommand("extension.open", metaData.extensionId);
}
}

async function scaffoldSimpleProject(): Promise<void> {
const workspaceFolder = Utility.getDefaultWorkspaceFolder();
const location: Uri[] | undefined = await window.showOpenDialog({
defaultUri: workspaceFolder && workspaceFolder.uri,
canSelectFiles: false,
canSelectFolders: true,
openLabel: "Select the project location",
});
if (!location || !location.length) {
return;
}

const basePath: string = location[0].fsPath;
const projectName: string | undefined = await window.showInputBox({
prompt: "Input a Java project name",
ignoreFocusOut: true,
validateInput: async (name: string): Promise<string> => {
if (name && !name.match(/^[^*~/\\]+$/)) {
return "Please input a valid project name";
}
if (name && await fse.pathExists(path.join(basePath, name))) {
return "A project with this name already exists";
}
return "";
},
});

if (!projectName) {
return;
}

const projectRoot: string = path.join(basePath, projectName);
const templateRoot: string = path.join(this.context.extensionPath, "templates", "invisible-project");
try {
await fse.ensureDir(projectRoot);
await fse.copy(templateRoot, projectRoot);
await fse.ensureDir(path.join(projectRoot, "lib"));
} catch (error) {
window.showErrorMessage(error.message);
return;
}
const openInNewWindow = workspace && !_.isEmpty(workspace.workspaceFolders);
await commands.executeCommand(Commands.VSCODE_OPEN_FOLDER, Uri.file(path.join(basePath, projectName)), openInNewWindow);
}

const projectTypes: IProjectType[] = [
{
displayName: "No build tools",
detail: "Create a project without any build tools",
metadata: {
type: ProjectType.NoBuildTool,
extensionId: "",
extensionName: "",
createCommandId: "",
},
},
{
displayName: "Maven",
description: "create from archetype",
metadata: {
type: ProjectType.Maven,
extensionId: "vscjava.vscode-maven",
extensionName: "Maven for Java",
createCommandId: "maven.archetype.generate",
},
},
{
displayName: "Spring Boot",
metadata: {
type: ProjectType.SpringBoot,
extensionId: "vscjava.vscode-spring-initializr",
extensionName: "Spring Initializr Java Support",
createCommandId: "spring.initializr.createProject",
},
},
{
displayName: "Quarkus",
metadata: {
type: ProjectType.Quarkus,
extensionId: "redhat.vscode-quarkus",
extensionName: "Quarkus",
createCommandId: "quarkusTools.createProject",
},
},
{
displayName: "MicroProfile",
metadata: {
type: ProjectType.MicroProfile,
extensionId: "microprofile-community.mp-starter-vscode-ext",
extensionName: "MicroProfile Starter",
createCommandId: "extension.microProfileStarter",
},
},
];

0 comments on commit d2d70f0

Please sign in to comment.