1
+ /*---------------------------------------------------------
2
+ * Copyright (C) Microsoft Corporation. All rights reserved.
3
+ *--------------------------------------------------------*/
4
+
5
+ import vscode = require( 'vscode' ) ;
6
+ import { IFeature } from '../feature' ;
7
+ import { LanguageClient , RequestType , NotificationType } from 'vscode-languageclient' ;
8
+
9
+ export class NewFileOrProjectFeature implements IFeature {
10
+
11
+ private readonly loadIcon = " $(sync) " ;
12
+ private command : vscode . Disposable ;
13
+ private languageClient : LanguageClient ;
14
+ private waitingForClientToken : vscode . CancellationTokenSource ;
15
+
16
+ constructor ( ) {
17
+ this . command =
18
+ vscode . commands . registerCommand ( 'PowerShell.NewProjectFromTemplate' , ( ) => {
19
+
20
+ if ( ! this . languageClient && ! this . waitingForClientToken ) {
21
+
22
+ // If PowerShell isn't finished loading yet, show a loading message
23
+ // until the LanguageClient is passed on to us
24
+ this . waitingForClientToken = new vscode . CancellationTokenSource ( ) ;
25
+ vscode . window
26
+ . showQuickPick (
27
+ [ "Cancel" ] ,
28
+ { placeHolder : "New Project: Please wait, starting PowerShell..." } ,
29
+ this . waitingForClientToken . token )
30
+ . then ( response => { if ( response === "Cancel" ) { this . clearWaitingToken ( ) ; } } ) ;
31
+
32
+ // Cancel the loading prompt after 60 seconds
33
+ setTimeout ( ( ) => {
34
+ if ( this . waitingForClientToken ) {
35
+ this . clearWaitingToken ( ) ;
36
+
37
+ vscode . window . showErrorMessage (
38
+ "New Project: PowerShell session took too long to start." ) ;
39
+ }
40
+ } , 60000 ) ;
41
+ }
42
+ else {
43
+ this . showProjectTemplates ( ) ;
44
+ }
45
+ } ) ;
46
+ }
47
+
48
+ public setLanguageClient ( languageClient : LanguageClient ) {
49
+ this . languageClient = languageClient ;
50
+
51
+ if ( this . waitingForClientToken ) {
52
+ this . clearWaitingToken ( ) ;
53
+ this . showProjectTemplates ( ) ;
54
+ }
55
+ }
56
+
57
+ public dispose ( ) {
58
+ this . command . dispose ( ) ;
59
+ }
60
+
61
+ private showProjectTemplates ( includeInstalledModules : boolean = false ) : void {
62
+ vscode . window
63
+ . showQuickPick (
64
+ this . getProjectTemplates ( includeInstalledModules ) ,
65
+ { placeHolder : "Choose a template to create a new project" ,
66
+ ignoreFocusOut : true } )
67
+ . then ( template => {
68
+ if ( template . label . startsWith ( this . loadIcon ) ) {
69
+ this . showProjectTemplates ( true ) ;
70
+ }
71
+ else {
72
+ this . createProjectFromTemplate ( template . template ) ;
73
+ }
74
+ } ) ;
75
+ }
76
+
77
+ private getProjectTemplates ( includeInstalledModules : boolean ) : Thenable < TemplateQuickPickItem [ ] > {
78
+ return this . languageClient
79
+ . sendRequest (
80
+ GetProjectTemplatesRequest . type ,
81
+ { includeInstalledModules : includeInstalledModules } )
82
+ . then ( response => {
83
+ if ( response . needsModuleInstall ) {
84
+ // TODO: Offer to install Plaster
85
+ vscode . window . showErrorMessage ( "Plaster is not installed!" ) ;
86
+ return Promise . reject < TemplateQuickPickItem [ ] > ( "Plaster needs to be installed" ) ;
87
+ }
88
+ else {
89
+ var templates = response . templates . map < TemplateQuickPickItem > (
90
+ template => {
91
+ return {
92
+ label : template . title ,
93
+ description : `v${ template . version } by ${ template . author } , tags: ${ template . tags } ` ,
94
+ detail : template . description ,
95
+ template : template
96
+ }
97
+ } ) ;
98
+
99
+ if ( ! includeInstalledModules ) {
100
+ templates =
101
+ [ { label : this . loadIcon , description : "Load additional templates from installed modules" , template : undefined } ]
102
+ . concat ( templates )
103
+ }
104
+ else {
105
+ templates =
106
+ [ { label : this . loadIcon , description : "Refresh template list" , template : undefined } ]
107
+ . concat ( templates )
108
+ }
109
+
110
+ return templates ;
111
+ }
112
+ } ) ;
113
+ }
114
+
115
+ private createProjectFromTemplate ( template : TemplateDetails ) : void {
116
+ vscode . window
117
+ . showInputBox (
118
+ { placeHolder : "Enter an absolute path to the folder where the project should be created" ,
119
+ ignoreFocusOut : true } )
120
+ . then ( destinationPath => {
121
+
122
+ if ( destinationPath ) {
123
+ // Show the PowerShell session output in case an error occurred
124
+ vscode . commands . executeCommand ( "PowerShell.ShowSessionOutput" ) ;
125
+
126
+ this . languageClient
127
+ . sendRequest (
128
+ NewProjectFromTemplateRequest . type ,
129
+ { templatePath : template . templatePath , destinationPath : destinationPath } )
130
+ . then ( result => {
131
+ if ( result . creationSuccessful ) {
132
+ this . openWorkspacePath ( destinationPath ) ;
133
+ }
134
+ else {
135
+ vscode . window . showErrorMessage (
136
+ "Project creation failed, read the Output window for more details." ) ;
137
+ }
138
+ } ) ;
139
+ }
140
+ else {
141
+ vscode . window
142
+ . showErrorMessage (
143
+ "New Project: You must enter an absolute folder path to continue. Try again?" ,
144
+ "Yes" , "No" )
145
+ . then (
146
+ response => {
147
+ if ( response === "Yes" ) {
148
+ this . createProjectFromTemplate ( template ) ;
149
+ }
150
+ } ) ;
151
+ }
152
+ } ) ;
153
+ }
154
+
155
+ private openWorkspacePath ( workspacePath : string ) {
156
+ // Open the created project in a new window
157
+ vscode . commands . executeCommand (
158
+ "vscode.openFolder" ,
159
+ vscode . Uri . file ( workspacePath ) ,
160
+ true ) ;
161
+ }
162
+
163
+ private clearWaitingToken ( ) {
164
+ if ( this . waitingForClientToken ) {
165
+ this . waitingForClientToken . dispose ( ) ;
166
+ this . waitingForClientToken = undefined ;
167
+ }
168
+ }
169
+ }
170
+
171
+ interface TemplateQuickPickItem extends vscode . QuickPickItem {
172
+ template : TemplateDetails
173
+ }
174
+
175
+ interface TemplateDetails {
176
+ title : string ;
177
+ version : string ;
178
+ author : string ;
179
+ description : string ;
180
+ tags : string ;
181
+ templatePath : string ;
182
+ }
183
+
184
+ namespace GetProjectTemplatesRequest {
185
+ export const type : RequestType < GetProjectTemplatesRequestArgs , GetProjectTemplatesResponseBody , string > =
186
+ { get method ( ) { return 'powerShell/getProjectTemplates' ; } } ;
187
+ }
188
+
189
+ interface GetProjectTemplatesRequestArgs {
190
+ includeInstalledModules : boolean ;
191
+ }
192
+
193
+ interface GetProjectTemplatesResponseBody {
194
+ needsModuleInstall : boolean ;
195
+ templates : TemplateDetails [ ] ;
196
+ }
197
+
198
+ namespace NewProjectFromTemplateRequest {
199
+ export const type : RequestType < any , NewProjectFromTemplateResponseBody , string > =
200
+ { get method ( ) { return 'powerShell/newProjectFromTemplate' ; } } ;
201
+ }
202
+
203
+ interface NewProjectFromTemplateRequestArgs {
204
+ destinationPath : string ;
205
+ templatePath : string ;
206
+ }
207
+
208
+ interface NewProjectFromTemplateResponseBody {
209
+ creationSuccessful : boolean ;
210
+ }
0 commit comments