Skip to content

Commit e6559fd

Browse files
committed
Add support for new project creation using Plaster
This change adds a new command called "Create New Project from Plaster Template" which allows the user to select a Plaster template and go through the template creation process. Once the project is created, a new window is opened for the new project's path.
1 parent 8a96bab commit e6559fd

File tree

3 files changed

+223
-5
lines changed

3 files changed

+223
-5
lines changed

package.json

+7-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
},
2727
"main": "./out/main",
2828
"activationEvents": [
29-
"onLanguage:powershell"
29+
"onLanguage:powershell",
30+
"onCommand:PowerShell.NewProjectFromTemplate"
3031
],
3132
"dependencies": {
3233
"vscode-languageclient": "1.3.1"
@@ -133,6 +134,11 @@
133134
"command": "PowerShell.ShowSessionOutput",
134135
"title": "Show Session Output",
135136
"category": "PowerShell"
137+
},
138+
{
139+
"command": "PowerShell.NewProjectFromTemplate",
140+
"title": "Create New Project from Plaster Template",
141+
"category": "PowerShell"
136142
}
137143
],
138144
"snippets": [

src/features/NewFileOrProject.ts

+210
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
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+
}

src/main.ts

+6-4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { SessionManager } from './session';
1111
import { PowerShellLanguageId } from './utils';
1212
import { ConsoleFeature } from './features/Console';
1313
import { OpenInISEFeature } from './features/OpenInISE';
14+
import { NewFileOrProjectFeature } from './features/NewFileOrProject';
1415
import { ExpandAliasFeature } from './features/ExpandAlias';
1516
import { ShowHelpFeature } from './features/ShowOnlineHelp';
1617
import { FindModuleFeature } from './features/PowerShellFindModule';
@@ -93,7 +94,8 @@ export function activate(context: vscode.ExtensionContext): void {
9394
new FindModuleFeature(),
9495
new ExtensionCommandsFeature(),
9596
new SelectPSSARulesFeature(),
96-
new CodeActionsFeature()
97+
new CodeActionsFeature(),
98+
new NewFileOrProjectFeature()
9799
];
98100

99101
sessionManager =
@@ -106,14 +108,14 @@ export function activate(context: vscode.ExtensionContext): void {
106108
}
107109

108110
export function deactivate(): void {
109-
// Finish the logger
110-
logger.dispose();
111-
112111
// Clean up all extension features
113112
extensionFeatures.forEach(feature => {
114113
feature.dispose();
115114
});
116115

117116
// Dispose of the current session
118117
sessionManager.dispose();
118+
119+
// Dispose of the logger
120+
logger.dispose();
119121
}

0 commit comments

Comments
 (0)