Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow users to specify open behavior for new project #360

Merged
merged 1 commit into from
May 8, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,15 @@
"type": "boolean",
"description": "%azFunc.showFuncInstallationDescription%",
"default": true
},
"azureFunctions.projectOpenBehavior": {
"type": "string",
"enum": [
"AddToWorkspace",
"OpenInNewWindow",
"OpenInCurrentWindow"
],
"description": "%azFunc.projectOpenBehaviorDescription%"
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,6 @@
"azFunc.enableRemoteDebugging": "Enable remote debugging, an experimental feature that only supports Java-based Functions Apps.",
"azFunc.deleteProxy": "Delete Proxy",
"azFunc.pickProcessTimeoutDescription": "The timeout (in seconds) to be used when searching for the Azure Functions host process. Since a build is required every time you F5, you may need to adjust this based on how long your build takes.",
"azFunc.showFuncInstallationDescription": "Show a warning to install Azure Functions Core Tools CLI when you create a new project if the CLI is not installed."
"azFunc.showFuncInstallationDescription": "Show a warning to install Azure Functions Core Tools CLI when you create a new project if the CLI is not installed.",
"azFunc.projectOpenBehaviorDescription": "The behavior to use after creating a new project. The options are \"AddToWorkspace\", \"OpenInNewWindow\", or \"OpenInCurrentWindow\"."
}
7 changes: 7 additions & 0 deletions src/commands/createFunction/createFunction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ async function promptForStringSetting(setting: ConfigSetting, defaultValue?: str
return await ext.ui.showInputBox(options);
}

// tslint:disable-next-line:max-func-body-length
export async function createFunction(
actionContext: IActionContext,
functionAppPath?: string,
Expand All @@ -85,12 +86,14 @@ export async function createFunction(
functionAppPath = await workspaceUtil.selectWorkspaceFolder(ext.ui, folderPlaceholder);
}

let isNewProject: boolean = false;
let templateFilter: TemplateFilter;
if (!await isFunctionProject(functionAppPath)) {
const message: string = localize('azFunc.notFunctionApp', 'The selected folder is not a function app project. Initialize Project?');
const result: vscode.MessageItem = await ext.ui.showWarningMessage(message, { modal: true }, DialogResponses.yes, DialogResponses.skipForNow, DialogResponses.cancel);
if (result === DialogResponses.yes) {
await createNewProject(actionContext, functionAppPath, undefined, undefined, false);
isNewProject = true;
// Get the settings used to create the project
language = <ProjectLanguage>actionContext.properties.projectLanguage;
runtime = <ProjectRuntime>actionContext.properties.projectRuntime;
Expand Down Expand Up @@ -169,6 +172,10 @@ export async function createFunction(
if (!template.functionConfig.isHttpTrigger) {
await validateAzureWebJobsStorage(actionContext, localSettingsPath);
}

if (isNewProject) {
await workspaceUtil.ensureFolderIsOpen(functionAppPath, actionContext);
}
}

async function promptForTemplate(functionAppPath: string, language: ProjectLanguage, runtime: ProjectRuntime, templateFilter: TemplateFilter): Promise<[Template, ProjectLanguage, ProjectRuntime, TemplateFilter]> {
Expand Down
6 changes: 2 additions & 4 deletions src/commands/createNewProject/createNewProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/

import * as fse from 'fs-extra';
import * as vscode from 'vscode';
import { QuickPickItem, QuickPickOptions } from 'vscode';
import { IActionContext, TelemetryProperties } from 'vscode-azureextensionui';
import { ProjectLanguage, projectLanguageSetting, ProjectRuntime } from '../../constants';
Expand Down Expand Up @@ -68,9 +67,8 @@ export async function createNewProject(
}
await validateFuncCoreToolsInstalled();

if (openFolder && !workspaceUtil.isFolderOpenInWorkspace(functionAppPath)) {
// If the selected folder is not open in a workspace, open it now. NOTE: This may restart the extension host
await vscode.commands.executeCommand('vscode.openFolder', vscode.Uri.file(functionAppPath), false);
if (openFolder) {
await workspaceUtil.ensureFolderIsOpen(functionAppPath, actionContext);
}
}

Expand Down
82 changes: 74 additions & 8 deletions src/utils/workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@
*--------------------------------------------------------------------------------------------*/

import * as path from 'path';
import { isBoolean } from 'util';
import * as vscode from 'vscode';
import { IAzureQuickPickItem, IAzureUserInput } from 'vscode-azureextensionui';
import { IActionContext, IAzureQuickPickItem, IAzureQuickPickOptions, IAzureUserInput } from 'vscode-azureextensionui';
import { ext } from '../extensionVariables';
import { localize } from '../localize';
import { getFuncExtensionSetting, updateGlobalSetting } from '../ProjectSettings';
import * as fsUtils from './fs';

export async function selectWorkspaceFolder(ui: IAzureUserInput, placeHolder: string, getSubPath?: (f: vscode.WorkspaceFolder) => string | undefined): Promise<string> {
Expand Down Expand Up @@ -66,14 +69,77 @@ export async function selectWorkspaceItem(ui: IAzureUserInput, placeHolder: stri
return folder && folder.data ? folder.data : (await ui.showOpenDialog(options))[0].fsPath;
}

export function isFolderOpenInWorkspace(fsPath: string): boolean {
if (vscode.workspace.workspaceFolders) {
const folder: vscode.WorkspaceFolder | undefined = vscode.workspace.workspaceFolders.find((f: vscode.WorkspaceFolder): boolean => {
return fsUtils.isPathEqual(f.uri.fsPath, fsPath) || fsUtils.isSubpath(f.uri.fsPath, fsPath);
});
enum OpenBehavior {
AddToWorkspace = 'AddToWorkspace',
OpenInNewWindow = 'OpenInNewWindow',
OpenInCurrentWindow = 'OpenInCurrentWindow'
}

const projectOpenBehaviorSetting: string = 'projectOpenBehavior';

/**
* If the selected folder is not open in a workspace, open it now. NOTE: This may restart the extension host
*/
export async function ensureFolderIsOpen(fsPath: string, actionContext: IActionContext): Promise<void> {
// tslint:disable-next-line:strict-boolean-expressions
const openFolders: vscode.WorkspaceFolder[] = vscode.workspace.workspaceFolders || [];
const folder: vscode.WorkspaceFolder | undefined = openFolders.find((f: vscode.WorkspaceFolder): boolean => {
return fsUtils.isPathEqual(f.uri.fsPath, fsPath);
});

return folder !== undefined;
if (folder) {
actionContext.properties.openBehavior = 'AlreadyOpen';
} else {
return false;
actionContext.properties.openBehaviorFromSetting = 'false';
const setting: string | undefined = getFuncExtensionSetting(projectOpenBehaviorSetting);
let openBehavior: OpenBehavior | undefined;
if (setting) {
for (const key of Object.keys(OpenBehavior)) {
const value: OpenBehavior = <OpenBehavior>OpenBehavior[key];
if (value.toLowerCase() === setting.toLowerCase()) {
openBehavior = value;
actionContext.properties.openBehaviorFromSetting = 'true';
break;
}
}
}

const notAlwaysPick: IAzureQuickPickItem<OpenBehavior | boolean> = { label: localize('notAlways', '$(circle-slash) Always use this choice'), description: '', data: false, suppressPersistence: true };
const alwaysPick: IAzureQuickPickItem<OpenBehavior | boolean> = { label: localize('always', '$(check) Always use this choice'), description: '', data: true, suppressPersistence: true };

const picks: IAzureQuickPickItem<OpenBehavior | boolean>[] = [
{ label: localize('AddToWorkspace', 'Add to workspace'), description: '', data: OpenBehavior.AddToWorkspace },
{ label: localize('OpenInNewWindow', 'Open in new window'), description: '', data: OpenBehavior.OpenInNewWindow },
{ label: localize('OpenInCurrentWindow', 'Open in current window'), description: '', data: OpenBehavior.OpenInCurrentWindow },
notAlwaysPick
];

const options: IAzureQuickPickOptions = { placeHolder: localize('selectOpenBehavior', 'Select how you would like to open your project'), suppressPersistence: true };

let result: OpenBehavior | boolean;
let alwaysUseThisChoice: boolean = false;
while (openBehavior === undefined) {
result = (await ext.ui.showQuickPick(picks, options)).data;
if (isBoolean(result)) {
alwaysUseThisChoice = !result; // The new value is the opposite of what the user just clicked in the quick pick
picks.pop();
picks.push(alwaysUseThisChoice ? alwaysPick : notAlwaysPick);
} else {
openBehavior = result;
}
}

actionContext.properties.openBehavior = openBehavior;

if (alwaysUseThisChoice) {
await updateGlobalSetting(projectOpenBehaviorSetting, openBehavior);
}

const uri: vscode.Uri = vscode.Uri.file(fsPath);
if (openBehavior === OpenBehavior.AddToWorkspace) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it works, but why don't you have to specify OpenInCurrentWindow here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's included in the 'else' case. The boolean I pass in with 'openBehavior === OpenBehavior.OpenInNewWindow /* forceNewWindow */ will evaluate to false and use the current window

vscode.workspace.updateWorkspaceFolders(openFolders.length, 0, { uri: uri });
} else {
await vscode.commands.executeCommand('vscode.openFolder', uri, openBehavior === OpenBehavior.OpenInNewWindow /* forceNewWindow */);
}
}
}