Skip to content

Commit d2d70f0

Browse files
authored
Add more project types for creation and expose the command in explorer (#276)
1 parent 0e79ba1 commit d2d70f0

File tree

4 files changed

+172
-93
lines changed

4 files changed

+172
-93
lines changed

package.json

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@
3737
{
3838
"command": "java.project.create",
3939
"title": "%contributes.commands.java.project.create%",
40-
"category": "Java"
40+
"category": "Java",
41+
"icon": "$(add)"
4142
},
4243
{
4344
"command": "java.project.addLibraries",
@@ -205,27 +206,32 @@
205206
{
206207
"command": "java.view.package.refresh",
207208
"when": "view == javaProjectExplorer && java:serverMode!= LightWeight",
208-
"group": "navigation@2"
209+
"group": "navigation@40"
209210
},
210211
{
211212
"command": "java.view.package.changeToHierarchicalPackageView",
212213
"when": "view == javaProjectExplorer && config.java.dependency.packagePresentation == flat && java:serverMode!= LightWeight",
213-
"group": "navigation@1"
214+
"group": "navigation@30"
214215
},
215216
{
216217
"command": "java.view.package.changeToFlatPackageView",
217218
"when": "view == javaProjectExplorer && config.java.dependency.packagePresentation != flat && java:serverMode!= LightWeight",
218-
"group": "navigation@1"
219+
"group": "navigation@30"
219220
},
220221
{
221222
"command": "java.view.package.linkWithFolderExplorer",
222223
"when": "view == javaProjectExplorer && config.java.dependency.syncWithFolderExplorer != true && java:serverMode!= LightWeight",
223-
"group": "navigation@0"
224+
"group": "navigation@20"
224225
},
225226
{
226227
"command": "java.view.package.unlinkWithFolderExplorer",
227228
"when": "view == javaProjectExplorer && config.java.dependency.syncWithFolderExplorer == true && java:serverMode!= LightWeight",
228-
"group": "navigation@0"
229+
"group": "navigation@20"
230+
},
231+
{
232+
"command": "java.project.create",
233+
"when": "view == javaProjectExplorer",
234+
"group": "navigation@10"
229235
}
230236
],
231237
"view/item/context": [

package.nls.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"description": "Manage Java projects in Visual Studio Code",
3-
"contributes.commands.java.project.create": "Create Java Project",
3+
"contributes.commands.java.project.create": "Create Java Project...",
44
"contributes.commands.java.project.addLibraries": "Add a jar file or a folder to project classpath",
55
"contributes.commands.java.project.maven.addDependency": "Add a new dependency to the Maven project",
66
"contributes.commands.java.project.removeLibrary": "Remove jar file from project classpath",

package.nls.zh.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"description": "在 Visual Studio Code 中管理 Java 项目",
3-
"contributes.commands.java.project.create": "创建 Java 项目",
3+
"contributes.commands.java.project.create": "创建 Java 项目...",
44
"contributes.commands.java.project.addLibraries": "将一个 Jar 文件或一个目录添加到 Java 项目类路径中",
55
"contributes.commands.java.project.maven.addDependency": "为该 Maven 项目增加依赖库",
66
"contributes.commands.java.project.removeLibrary": "将该 Jar 文件从 Java 项目类路径中移除",

src/controllers/projectController.ts

Lines changed: 158 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,9 @@
44
import * as fse from "fs-extra";
55
import * as _ from "lodash";
66
import * as path from "path";
7-
import { commands, Disposable, ExtensionContext, QuickPickItem, Uri, window, workspace } from "vscode";
8-
import { instrumentOperationAsVsCodeCommand, sendInfo } from "vscode-extension-telemetry-wrapper";
7+
import { commands, Disposable, Extension, ExtensionContext, extensions, QuickPickItem, Uri, window, workspace } from "vscode";
8+
import { instrumentOperationAsVsCodeCommand } from "vscode-extension-telemetry-wrapper";
99
import { Commands } from "../commands";
10-
import { Context } from "../constants";
11-
import { contextManager } from "../contextManager";
12-
import { getExpService } from "../ExperimentationService";
1310
import { Utility } from "../utility";
1411

1512
export class ProjectController implements Disposable {
@@ -27,97 +24,173 @@ export class ProjectController implements Disposable {
2724
}
2825

2926
public async createJavaProject() {
30-
const projectKinds: QuickPickItem[] = [{
31-
label: BuildTool.None,
32-
detail: "A project without any build tools",
33-
}];
34-
if (contextManager.getContextValue(Context.MAVEN_ENABLED)) {
35-
const isMavenDefault: boolean = await getExpService()?.isCachedFlightEnabled("defaultMaven") || false;
36-
const mavenItem: QuickPickItem = {
37-
label: BuildTool.Maven,
38-
detail: "Use Maven to manage your project",
27+
const items: IProjectTypeQuickPick[] = projectTypes.map((type: IProjectType) => {
28+
return {
29+
label: type.displayName,
30+
description: type.description,
31+
detail: type.metadata.extensionName ? `Provided by $(extensions) ${type.metadata.extensionName}` : type.detail,
32+
metadata: type.metadata,
3933
};
40-
if (isMavenDefault) {
41-
projectKinds.unshift(mavenItem);
42-
} else {
43-
projectKinds.push(mavenItem);
44-
}
45-
}
46-
const choice: QuickPickItem | undefined = projectKinds.length === 1 ? projectKinds[0] :
47-
await window.showQuickPick(projectKinds, {
48-
ignoreFocusOut: true,
49-
placeHolder: "Select the project build tool",
50-
},
51-
);
52-
53-
if (!choice) {
34+
});
35+
const choice = await window.showQuickPick(items, {
36+
ignoreFocusOut: true,
37+
placeHolder: "Select the project type",
38+
});
39+
if (!choice || !await ensureExtension(choice.label, choice.metadata)) {
5440
return;
5541
}
5642

57-
if (projectKinds.length > 1) {
58-
const chooseDefault: boolean = choice.label === projectKinds[0].label;
59-
sendInfo("", {"project.create.chooseDefault": `${chooseDefault}`});
60-
}
61-
62-
switch (choice.label) {
63-
case BuildTool.Maven:
64-
await commands.executeCommand(Commands.JAVA_MAVEN_CREATE_PROJECT);
65-
break;
66-
case BuildTool.None:
67-
await this.scaffoldSimpleProject();
68-
break;
69-
default:
70-
break;
43+
if (choice.metadata.type === ProjectType.NoBuildTool) {
44+
await scaffoldSimpleProject();
45+
} else if (choice.metadata.createCommandId) {
46+
await commands.executeCommand(choice.metadata.createCommandId);
7147
}
7248
}
49+
}
7350

74-
private async scaffoldSimpleProject(): Promise<void> {
75-
const workspaceFolder = Utility.getDefaultWorkspaceFolder();
76-
const location: Uri[] | undefined = await window.showOpenDialog({
77-
defaultUri: workspaceFolder && workspaceFolder.uri,
78-
canSelectFiles: false,
79-
canSelectFolders: true,
80-
openLabel: "Select the location",
81-
});
82-
if (!location || !location.length) {
83-
return;
84-
}
51+
interface IProjectType {
52+
displayName: string;
53+
description?: string;
54+
detail?: string;
55+
metadata: IProjectTypeMetadata;
56+
}
8557

86-
const basePath: string = location[0].fsPath;
87-
const projectName: string | undefined = await window.showInputBox({
88-
prompt: "Input a java project name",
89-
ignoreFocusOut: true,
90-
validateInput: async (name: string): Promise<string> => {
91-
if (name && !name.match(/^[^*~/\\]+$/)) {
92-
return "Please input a valid project name";
93-
}
94-
if (name && await fse.pathExists(path.join(basePath, name))) {
95-
return "A project with this name already exists.";
96-
}
97-
return "";
98-
},
99-
});
58+
interface IProjectTypeMetadata {
59+
type: ProjectType;
60+
extensionId: string;
61+
extensionName: string;
62+
createCommandId: string;
63+
}
10064

101-
if (!projectName) {
102-
return;
103-
}
65+
interface IProjectTypeQuickPick extends QuickPickItem {
66+
metadata: IProjectTypeMetadata;
67+
}
10468

105-
const projectRoot: string = path.join(basePath, projectName);
106-
const templateRoot: string = path.join(this.context.extensionPath, "templates", "invisible-project");
107-
try {
108-
await fse.ensureDir(projectRoot);
109-
await fse.copy(templateRoot, projectRoot);
110-
await fse.ensureDir(path.join(projectRoot, "lib"));
111-
} catch (error) {
112-
window.showErrorMessage(error.message);
113-
return;
114-
}
115-
const openInNewWindow = workspace && !_.isEmpty(workspace.workspaceFolders);
116-
await commands.executeCommand(Commands.VSCODE_OPEN_FOLDER, Uri.file(path.join(basePath, projectName)), openInNewWindow);
69+
enum ProjectType {
70+
NoBuildTool = "NoBuildTool",
71+
Maven = "Maven",
72+
SpringBoot = "SpringBoot",
73+
Quarkus = "Quarkus",
74+
MicroProfile = "MicroProfile",
75+
}
76+
77+
async function ensureExtension(typeName: string, metaData: IProjectTypeMetadata): Promise<boolean> {
78+
if (!metaData.extensionId) {
79+
return true;
80+
}
81+
82+
const extension: Extension<any> | undefined = extensions.getExtension(metaData.extensionId);
83+
if (extension === undefined) {
84+
await promptInstallExtension(typeName, metaData);
85+
return false;
11786
}
87+
88+
await extension.activate();
89+
return true;
11890
}
11991

120-
enum BuildTool {
121-
Maven = "Maven",
122-
None = "No build tools",
92+
async function promptInstallExtension(projectType: string, metaData: IProjectTypeMetadata): Promise<void> {
93+
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");
94+
if (choice === "Install") {
95+
commands.executeCommand("workbench.extensions.installExtension", metaData.extensionId);
96+
// So far there is no API to query the extension's state, so we open the extension's homepage
97+
// here, where users can check the state: installing, disabled, installed, etc...
98+
// See: https://github.com/microsoft/vscode/issues/14444
99+
commands.executeCommand("extension.open", metaData.extensionId);
100+
}
101+
}
102+
103+
async function scaffoldSimpleProject(): Promise<void> {
104+
const workspaceFolder = Utility.getDefaultWorkspaceFolder();
105+
const location: Uri[] | undefined = await window.showOpenDialog({
106+
defaultUri: workspaceFolder && workspaceFolder.uri,
107+
canSelectFiles: false,
108+
canSelectFolders: true,
109+
openLabel: "Select the project location",
110+
});
111+
if (!location || !location.length) {
112+
return;
113+
}
114+
115+
const basePath: string = location[0].fsPath;
116+
const projectName: string | undefined = await window.showInputBox({
117+
prompt: "Input a Java project name",
118+
ignoreFocusOut: true,
119+
validateInput: async (name: string): Promise<string> => {
120+
if (name && !name.match(/^[^*~/\\]+$/)) {
121+
return "Please input a valid project name";
122+
}
123+
if (name && await fse.pathExists(path.join(basePath, name))) {
124+
return "A project with this name already exists";
125+
}
126+
return "";
127+
},
128+
});
129+
130+
if (!projectName) {
131+
return;
132+
}
133+
134+
const projectRoot: string = path.join(basePath, projectName);
135+
const templateRoot: string = path.join(this.context.extensionPath, "templates", "invisible-project");
136+
try {
137+
await fse.ensureDir(projectRoot);
138+
await fse.copy(templateRoot, projectRoot);
139+
await fse.ensureDir(path.join(projectRoot, "lib"));
140+
} catch (error) {
141+
window.showErrorMessage(error.message);
142+
return;
143+
}
144+
const openInNewWindow = workspace && !_.isEmpty(workspace.workspaceFolders);
145+
await commands.executeCommand(Commands.VSCODE_OPEN_FOLDER, Uri.file(path.join(basePath, projectName)), openInNewWindow);
123146
}
147+
148+
const projectTypes: IProjectType[] = [
149+
{
150+
displayName: "No build tools",
151+
detail: "Create a project without any build tools",
152+
metadata: {
153+
type: ProjectType.NoBuildTool,
154+
extensionId: "",
155+
extensionName: "",
156+
createCommandId: "",
157+
},
158+
},
159+
{
160+
displayName: "Maven",
161+
description: "create from archetype",
162+
metadata: {
163+
type: ProjectType.Maven,
164+
extensionId: "vscjava.vscode-maven",
165+
extensionName: "Maven for Java",
166+
createCommandId: "maven.archetype.generate",
167+
},
168+
},
169+
{
170+
displayName: "Spring Boot",
171+
metadata: {
172+
type: ProjectType.SpringBoot,
173+
extensionId: "vscjava.vscode-spring-initializr",
174+
extensionName: "Spring Initializr Java Support",
175+
createCommandId: "spring.initializr.createProject",
176+
},
177+
},
178+
{
179+
displayName: "Quarkus",
180+
metadata: {
181+
type: ProjectType.Quarkus,
182+
extensionId: "redhat.vscode-quarkus",
183+
extensionName: "Quarkus",
184+
createCommandId: "quarkusTools.createProject",
185+
},
186+
},
187+
{
188+
displayName: "MicroProfile",
189+
metadata: {
190+
type: ProjectType.MicroProfile,
191+
extensionId: "microprofile-community.mp-starter-vscode-ext",
192+
extensionName: "MicroProfile Starter",
193+
createCommandId: "extension.microProfileStarter",
194+
},
195+
},
196+
];

0 commit comments

Comments
 (0)