4
4
import * as fse from "fs-extra" ;
5
5
import * as _ from "lodash" ;
6
6
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" ;
9
9
import { Commands } from "../commands" ;
10
- import { Context } from "../constants" ;
11
- import { contextManager } from "../contextManager" ;
12
- import { getExpService } from "../ExperimentationService" ;
13
10
import { Utility } from "../utility" ;
14
11
15
12
export class ProjectController implements Disposable {
@@ -27,97 +24,173 @@ export class ProjectController implements Disposable {
27
24
}
28
25
29
26
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 ,
39
33
} ;
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 ) ) {
54
40
return ;
55
41
}
56
42
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 ) ;
71
47
}
72
48
}
49
+ }
73
50
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
+ }
85
57
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
+ }
100
64
101
- if ( ! projectName ) {
102
- return ;
103
- }
65
+ interface IProjectTypeQuickPick extends QuickPickItem {
66
+ metadata : IProjectTypeMetadata ;
67
+ }
104
68
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 ;
117
86
}
87
+
88
+ await extension . activate ( ) ;
89
+ return true ;
118
90
}
119
91
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 ) ;
123
146
}
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