Skip to content

Commit 98fd081

Browse files
authored
Refine the command to create Java project (#252)
1 parent 27a29b1 commit 98fd081

23 files changed

+2618
-1703
lines changed

jdtls.ext/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<properties>
1010
<base.name>Java Project Manager</base.name>
1111
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
12-
<tycho-version>1.0.0</tycho-version>
12+
<tycho-version>1.5.0</tycho-version>
1313
</properties>
1414

1515
<developers>

package-lock.json

Lines changed: 2487 additions & 1416 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -274,14 +274,11 @@
274274
"@types/mocha": "^5.2.5",
275275
"@types/node": "^8.10.36",
276276
"@types/vscode": "1.44.0",
277-
"@types/xml2js": "^0.4.3",
278-
"cross-env": "^5.2.0",
279277
"glob": "^7.1.4",
280278
"gulp": "^4.0.0",
281279
"gulp-copy": "^4.0.1",
282280
"gulp-tslint": "^8.1.3",
283281
"mocha": "^7.1.1",
284-
"shelljs": "^0.8.3",
285282
"ts-loader": "^5.3.1",
286283
"tslint": "^5.11.0",
287284
"typescript": "^3.1.6",
@@ -290,11 +287,9 @@
290287
"webpack-cli": "^3.3.11"
291288
},
292289
"dependencies": {
293-
"find-java-home": "^0.2.0",
294290
"fs-extra": "^7.0.1",
295291
"lodash": "^4.17.15",
296292
"minimatch": "^3.0.4",
297-
"vscode-extension-telemetry-wrapper": "^0.4.0",
298-
"xml2js": "^0.4.19"
293+
"vscode-extension-telemetry-wrapper": "^0.4.0"
299294
}
300295
}

src/commands.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ export namespace Commands {
4040

4141
export const JAVA_MAVEN_PROJECT_ADD_DEPENDENCY = "java.project.maven.addDependency";
4242

43+
export const JAVA_MAVEN_CREATE_PROJECT = "maven.archetype.generate";
44+
4345
export const JAVA_PROJECT_LIST = "java.project.list";
4446

4547
export const JAVA_PROJECT_REFRESH_LIB_SERVER = "java.project.refreshLib";
@@ -48,4 +50,5 @@ export namespace Commands {
4850

4951
export const JAVA_RESOLVEPATH = "java.resolvePath";
5052

53+
export const VSCODE_OPEN_FOLDER = "vscode.openFolder";
5154
}

src/constants.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT license.
3+
4+
export namespace Context {
5+
export const MAVEN_ENABLED: string = "mavenEnabled";
6+
export const EXTENSION_ACTIVATED: string = "extensionActivated";
7+
}

src/contextManager.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT license.
3+
4+
import { commands, Disposable, ExtensionContext } from "vscode";
5+
6+
class ContextManager implements Disposable {
7+
private _context: ExtensionContext;
8+
private _contextValueMap: Map<string, any>;
9+
10+
public initialize(context: ExtensionContext) {
11+
this._context = context;
12+
this._contextValueMap = new Map<string, any>();
13+
}
14+
15+
public get context(): ExtensionContext {
16+
return this._context;
17+
}
18+
19+
public async setContextValue(key: string, value: any): Promise<void> {
20+
this._contextValueMap.set(key, value);
21+
await commands.executeCommand("setContext", key, value);
22+
}
23+
24+
public getContextValue<T>(key: string): T | undefined {
25+
return <T> this._contextValueMap.get(key);
26+
}
27+
28+
public dispose(): void {
29+
this._contextValueMap.clear();
30+
}
31+
}
32+
33+
export const contextManager: ContextManager = new ContextManager();

src/controllers/projectController.ts

Lines changed: 48 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44
import * as fse from "fs-extra";
55
import * as _ from "lodash";
66
import * as path from "path";
7-
import { commands, Disposable, ExtensionContext, Uri, window, workspace } from "vscode";
7+
import { commands, Disposable, ExtensionContext, QuickPickItem, Uri, window, workspace } from "vscode";
88
import { instrumentOperationAsVsCodeCommand } from "vscode-extension-telemetry-wrapper";
9-
import * as xml2js from "xml2js";
109
import { Commands } from "../commands";
10+
import { Context } from "../constants";
11+
import { contextManager } from "../contextManager";
1112
import { Utility } from "../utility";
1213

1314
export class ProjectController implements Disposable {
@@ -25,10 +26,40 @@ export class ProjectController implements Disposable {
2526
}
2627

2728
public async createJavaProject() {
28-
const javaVersion: number = await this.getJavaVersion();
29-
if (!javaVersion) {
29+
const projectKinds: QuickPickItem[] = [{
30+
label: BuildTool.None,
31+
detail: "A project without any build tools",
32+
}];
33+
if (contextManager.getContextValue(Context.MAVEN_ENABLED)) {
34+
projectKinds.push({
35+
label: BuildTool.Maven,
36+
detail: "Use Maven to manage your project",
37+
});
38+
}
39+
const choice: QuickPickItem | undefined = projectKinds.length === 1 ? projectKinds[0] :
40+
await window.showQuickPick(projectKinds, {
41+
ignoreFocusOut: true,
42+
placeHolder: "Select the project build tool",
43+
},
44+
);
45+
46+
if (!choice) {
3047
return;
3148
}
49+
50+
switch (choice.label) {
51+
case BuildTool.Maven:
52+
await commands.executeCommand(Commands.JAVA_MAVEN_CREATE_PROJECT);
53+
break;
54+
case BuildTool.None:
55+
await this.scaffoldSimpleProject();
56+
break;
57+
default:
58+
break;
59+
}
60+
}
61+
62+
private async scaffoldSimpleProject(): Promise<void> {
3263
const workspaceFolder = Utility.getDefaultWorkspaceFolder();
3364
const location: Uri[] = await window.showOpenDialog({
3465
defaultUri: workspaceFolder && workspaceFolder.uri,
@@ -39,73 +70,36 @@ export class ProjectController implements Disposable {
3970
if (!location || !location.length) {
4071
return;
4172
}
73+
4274
const basePath: string = location[0].fsPath;
4375
const projectName: string = await window.showInputBox({
4476
prompt: "Input a java project name",
45-
validateInput: (name: string): string => {
77+
ignoreFocusOut: true,
78+
validateInput: async (name: string): Promise<string> => {
4679
if (name && !name.match(/^[^*~/\\]+$/)) {
4780
return "Please input a valid project name";
4881
}
49-
if (name && fse.pathExistsSync(path.join(basePath, name))) {
82+
if (name && await fse.pathExists(path.join(basePath, name))) {
5083
return "A project with this name already exists.";
5184
}
52-
return null;
85+
return "";
5386
},
5487
});
55-
if (!projectName) {
56-
return;
57-
}
58-
if (await this.scaffoldJavaProject(basePath, projectName, javaVersion)) {
59-
const openInNewWindow = workspace && !_.isEmpty(workspace.workspaceFolders);
60-
return commands.executeCommand("vscode.openFolder", Uri.file(path.join(basePath, projectName)), openInNewWindow);
61-
}
62-
}
63-
64-
private async scaffoldJavaProject(basePath: string, projectName: string, javaVersion: number): Promise<boolean> {
6588
const projectRoot: string = path.join(basePath, projectName);
66-
const templateRoot: string = path.join(this.context.extensionPath, "templates");
67-
const projectFile: string = path.join(projectRoot, ".project");
89+
const templateRoot: string = path.join(this.context.extensionPath, "templates", "invisible-project");
6890
try {
69-
let jdkSpecificTemplateRoot: string = path.join(templateRoot, `Java${javaVersion}`);
70-
if (!await fse.pathExists(jdkSpecificTemplateRoot)) {
71-
// fall back to 8
72-
jdkSpecificTemplateRoot = path.join(templateRoot, `Java8`);
73-
}
7491
await fse.ensureDir(projectRoot);
75-
await Promise.all([
76-
fse.copy(path.join(templateRoot, "App.java.sample"), path.join(projectRoot, "src", "app", "App.java")),
77-
fse.copy(jdkSpecificTemplateRoot, projectRoot),
78-
fse.copy(path.join(templateRoot, ".project"), path.join(projectRoot, ".project")),
79-
fse.ensureDir(path.join(projectRoot, "bin")),
80-
]);
81-
82-
// replace the project name with user input project name
83-
const xml: string = await fse.readFile(projectFile, "utf8");
84-
const jsonObj: any = await Utility.parseXml(xml);
85-
jsonObj.projectDescription.name = projectName;
86-
const builder: xml2js.Builder = new xml2js.Builder();
87-
const newXml: string = builder.buildObject(jsonObj);
88-
await fse.writeFile(projectFile, newXml);
92+
await fse.copy(templateRoot, projectRoot);
8993
} catch (error) {
9094
window.showErrorMessage(error.message);
9195
return;
9296
}
93-
return true;
97+
const openInNewWindow = workspace && !_.isEmpty(workspace.workspaceFolders);
98+
await commands.executeCommand(Commands.VSCODE_OPEN_FOLDER, Uri.file(path.join(basePath, projectName)), openInNewWindow);
9499
}
100+
}
95101

96-
private async getJavaVersion(): Promise<number> {
97-
let javaVersion: number;
98-
try {
99-
const javaHome: string = await Utility.checkJavaRuntime();
100-
javaVersion = await Utility.checkJavaVersion(javaHome);
101-
} catch (error) {
102-
window.showErrorMessage(error.message, error.label).then((selection) => {
103-
if (error.label && error.label === selection && error.openUrl) {
104-
commands.executeCommand("vscode.open", error.openUrl);
105-
}
106-
});
107-
return;
108-
}
109-
return javaVersion;
110-
}
102+
enum BuildTool {
103+
Maven = "Maven",
104+
None = "No build tools",
111105
}

src/extension.ts

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

4-
import { commands, Extension, ExtensionContext, extensions } from "vscode";
4+
import { Extension, ExtensionContext, extensions } from "vscode";
55
import { dispose as disposeTelemetryWrapper, initializeFromJsonFile, instrumentOperation } from "vscode-extension-telemetry-wrapper";
6+
import { Context } from "./constants";
7+
import { contextManager } from "./contextManager";
68
import { LibraryController } from "./controllers/libraryController";
79
import { ProjectController } from "./controllers/projectController";
810
import { Settings } from "./settings";
@@ -13,23 +15,28 @@ export async function activate(context: ExtensionContext): Promise<any> {
1315
return instrumentOperation("activation", activateExtension)(context);
1416
}
1517

16-
function activateExtension(operationId: string, context: ExtensionContext) {
17-
commands.executeCommand("setContext", "extensionActivated", true);
18-
18+
function activateExtension(_operationId: string, context: ExtensionContext) {
1919
Settings.initialize(context);
20-
21-
setMavenEnabledContext();
20+
contextManager.initialize(context);
21+
setMavenExtensionState();
2222

2323
context.subscriptions.push(new ProjectController(context));
2424
context.subscriptions.push(new LibraryController(context));
2525
context.subscriptions.push(new DependencyExplorer(context));
26+
context.subscriptions.push(contextManager);
27+
contextManager.setContextValue(Context.EXTENSION_ACTIVATED, true);
2628
}
2729

2830
// determine if the add dependency shortcut will show or not
29-
function setMavenEnabledContext() {
30-
const mavenExt: Extension<any> | undefined = extensions.getExtension("vscjava.vscode-maven");
31-
if (mavenExt) {
32-
commands.executeCommand("setContext", "mavenEnabled", true);
31+
function setMavenExtensionState() {
32+
setMavenEnabledContext();
33+
extensions.onDidChange(() => {
34+
setMavenEnabledContext();
35+
});
36+
37+
function setMavenEnabledContext() {
38+
const mavenExt: Extension<any> | undefined = extensions.getExtension("vscjava.vscode-maven");
39+
contextManager.setContextValue(Context.MAVEN_ENABLED, !!mavenExt);
3340
}
3441
}
3542

0 commit comments

Comments
 (0)