mirror of
https://github.com/microsoft/vscode-extension-samples.git
synced 2026-04-27 16:55:44 +08:00
Run format on repo
This commit is contained in:
@ -1,34 +1,34 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { window } from 'vscode';
|
||||
|
||||
/**
|
||||
* Shows a pick list using window.showQuickPick().
|
||||
*/
|
||||
export async function showQuickPick() {
|
||||
let i = 0;
|
||||
const result = await window.showQuickPick(['eins', 'zwei', 'drei'], {
|
||||
placeHolder: 'eins, zwei or drei',
|
||||
onDidSelectItem: item => window.showInformationMessage(`Focus ${++i}: ${item}`)
|
||||
});
|
||||
window.showInformationMessage(`Got: ${result}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows an input box using window.showInputBox().
|
||||
*/
|
||||
export async function showInputBox() {
|
||||
const result = await window.showInputBox({
|
||||
value: 'abcdef',
|
||||
valueSelection: [2, 4],
|
||||
placeHolder: 'For example: fedcba. But not: 123',
|
||||
validateInput: text => {
|
||||
window.showInformationMessage(`Validating: ${text}`);
|
||||
return text === '123' ? 'Not 123!' : null;
|
||||
}
|
||||
});
|
||||
window.showInformationMessage(`Got: ${result}`);
|
||||
}
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { window } from 'vscode';
|
||||
|
||||
/**
|
||||
* Shows a pick list using window.showQuickPick().
|
||||
*/
|
||||
export async function showQuickPick() {
|
||||
let i = 0;
|
||||
const result = await window.showQuickPick(['eins', 'zwei', 'drei'], {
|
||||
placeHolder: 'eins, zwei or drei',
|
||||
onDidSelectItem: item => window.showInformationMessage(`Focus ${++i}: ${item}`)
|
||||
});
|
||||
window.showInformationMessage(`Got: ${result}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows an input box using window.showInputBox().
|
||||
*/
|
||||
export async function showInputBox() {
|
||||
const result = await window.showInputBox({
|
||||
value: 'abcdef',
|
||||
valueSelection: [2, 4],
|
||||
placeHolder: 'For example: fedcba. But not: 123',
|
||||
validateInput: text => {
|
||||
window.showInformationMessage(`Validating: ${text}`);
|
||||
return text === '123' ? 'Not 123!' : null;
|
||||
}
|
||||
});
|
||||
window.showInformationMessage(`Got: ${result}`);
|
||||
}
|
||||
|
||||
@ -1,30 +1,30 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { window, commands, ExtensionContext } from 'vscode';
|
||||
import { showQuickPick, showInputBox } from './basicInput';
|
||||
import { multiStepInput } from './multiStepInput';
|
||||
import { quickOpen } from './quickOpen';
|
||||
|
||||
export function activate(context: ExtensionContext) {
|
||||
context.subscriptions.push(commands.registerCommand('samples.quickInput', async () => {
|
||||
const options: { [key: string]: (context: ExtensionContext) => Promise<void> } = {
|
||||
showQuickPick,
|
||||
showInputBox,
|
||||
multiStepInput,
|
||||
quickOpen,
|
||||
};
|
||||
const quickPick = window.createQuickPick();
|
||||
quickPick.items = Object.keys(options).map(label => ({ label }));
|
||||
quickPick.onDidChangeSelection(selection => {
|
||||
if (selection[0]) {
|
||||
options[selection[0].label](context)
|
||||
.catch(console.error);
|
||||
}
|
||||
});
|
||||
quickPick.onDidHide(() => quickPick.dispose());
|
||||
quickPick.show();
|
||||
}));
|
||||
}
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { window, commands, ExtensionContext } from 'vscode';
|
||||
import { showQuickPick, showInputBox } from './basicInput';
|
||||
import { multiStepInput } from './multiStepInput';
|
||||
import { quickOpen } from './quickOpen';
|
||||
|
||||
export function activate(context: ExtensionContext) {
|
||||
context.subscriptions.push(commands.registerCommand('samples.quickInput', async () => {
|
||||
const options: { [key: string]: (context: ExtensionContext) => Promise<void> } = {
|
||||
showQuickPick,
|
||||
showInputBox,
|
||||
multiStepInput,
|
||||
quickOpen,
|
||||
};
|
||||
const quickPick = window.createQuickPick();
|
||||
quickPick.items = Object.keys(options).map(label => ({ label }));
|
||||
quickPick.onDidChangeSelection(selection => {
|
||||
if (selection[0]) {
|
||||
options[selection[0].label](context)
|
||||
.catch(console.error);
|
||||
}
|
||||
});
|
||||
quickPick.onDidHide(() => quickPick.dispose());
|
||||
quickPick.show();
|
||||
}));
|
||||
}
|
||||
|
||||
@ -1,306 +1,306 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { QuickPickItem, window, Disposable, CancellationToken, QuickInputButton, QuickInput, ExtensionContext, QuickInputButtons, Uri } from 'vscode';
|
||||
|
||||
/**
|
||||
* A multi-step input using window.createQuickPick() and window.createInputBox().
|
||||
*
|
||||
* This first part uses the helper class `MultiStepInput` that wraps the API for the multi-step case.
|
||||
*/
|
||||
export async function multiStepInput(context: ExtensionContext) {
|
||||
|
||||
class MyButton implements QuickInputButton {
|
||||
constructor(public iconPath: { light: Uri; dark: Uri; }, public tooltip: string) { }
|
||||
}
|
||||
|
||||
const createResourceGroupButton = new MyButton({
|
||||
dark: Uri.file(context.asAbsolutePath('resources/dark/add.svg')),
|
||||
light: Uri.file(context.asAbsolutePath('resources/light/add.svg')),
|
||||
}, 'Create Resource Group');
|
||||
|
||||
const resourceGroups: QuickPickItem[] = ['vscode-data-function', 'vscode-appservice-microservices', 'vscode-appservice-monitor', 'vscode-appservice-preview', 'vscode-appservice-prod']
|
||||
.map(label => ({ label }));
|
||||
|
||||
|
||||
interface State {
|
||||
title: string;
|
||||
step: number;
|
||||
totalSteps: number;
|
||||
resourceGroup: QuickPickItem | string;
|
||||
name: string;
|
||||
runtime: QuickPickItem;
|
||||
}
|
||||
|
||||
async function collectInputs() {
|
||||
const state = {} as Partial<State>;
|
||||
await MultiStepInput.run(input => pickResourceGroup(input, state));
|
||||
return state as State;
|
||||
}
|
||||
|
||||
const title = 'Create Application Service';
|
||||
|
||||
async function pickResourceGroup(input: MultiStepInput, state: Partial<State>) {
|
||||
const pick = await input.showQuickPick({
|
||||
title,
|
||||
step: 1,
|
||||
totalSteps: 3,
|
||||
placeholder: 'Pick a resource group',
|
||||
items: resourceGroups,
|
||||
activeItem: typeof state.resourceGroup !== 'string' ? state.resourceGroup : undefined,
|
||||
buttons: [createResourceGroupButton],
|
||||
shouldResume: shouldResume
|
||||
});
|
||||
if (pick instanceof MyButton) {
|
||||
return (input: MultiStepInput) => inputResourceGroupName(input, state);
|
||||
}
|
||||
state.resourceGroup = pick;
|
||||
return (input: MultiStepInput) => inputName(input, state);
|
||||
}
|
||||
|
||||
async function inputResourceGroupName(input: MultiStepInput, state: Partial<State>) {
|
||||
state.resourceGroup = await input.showInputBox({
|
||||
title,
|
||||
step: 2,
|
||||
totalSteps: 4,
|
||||
value: typeof state.resourceGroup === 'string' ? state.resourceGroup : '',
|
||||
prompt: 'Choose a unique name for the resource group',
|
||||
validate: validateNameIsUnique,
|
||||
shouldResume: shouldResume
|
||||
});
|
||||
return (input: MultiStepInput) => inputName(input, state);
|
||||
}
|
||||
|
||||
async function inputName(input: MultiStepInput, state: Partial<State>) {
|
||||
const additionalSteps = typeof state.resourceGroup === 'string' ? 1 : 0;
|
||||
// TODO: Remember current value when navigating back.
|
||||
state.name = await input.showInputBox({
|
||||
title,
|
||||
step: 2 + additionalSteps,
|
||||
totalSteps: 3 + additionalSteps,
|
||||
value: state.name || '',
|
||||
prompt: 'Choose a unique name for the Application Service',
|
||||
validate: validateNameIsUnique,
|
||||
shouldResume: shouldResume
|
||||
});
|
||||
return (input: MultiStepInput) => pickRuntime(input, state);
|
||||
}
|
||||
|
||||
async function pickRuntime(input: MultiStepInput, state: Partial<State>) {
|
||||
const additionalSteps = typeof state.resourceGroup === 'string' ? 1 : 0;
|
||||
const runtimes = await getAvailableRuntimes(state.resourceGroup!, undefined /* TODO: token */);
|
||||
// TODO: Remember currently active item when navigating back.
|
||||
state.runtime = await input.showQuickPick({
|
||||
title,
|
||||
step: 3 + additionalSteps,
|
||||
totalSteps: 3 + additionalSteps,
|
||||
placeholder: 'Pick a runtime',
|
||||
items: runtimes,
|
||||
activeItem: state.runtime,
|
||||
shouldResume: shouldResume
|
||||
});
|
||||
}
|
||||
|
||||
function shouldResume() {
|
||||
// Could show a notification with the option to resume.
|
||||
return new Promise<boolean>((resolve, reject) => {
|
||||
// noop
|
||||
});
|
||||
}
|
||||
|
||||
async function validateNameIsUnique(name: string) {
|
||||
// ...validate...
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
return name === 'vscode' ? 'Name not unique' : undefined;
|
||||
}
|
||||
|
||||
async function getAvailableRuntimes(resourceGroup: QuickPickItem | string, token?: CancellationToken): Promise<QuickPickItem[]> {
|
||||
// ...retrieve...
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
return ['Node 8.9', 'Node 6.11', 'Node 4.5']
|
||||
.map(label => ({ label }));
|
||||
}
|
||||
|
||||
const state = await collectInputs();
|
||||
window.showInformationMessage(`Creating Application Service '${state.name}'`);
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------
|
||||
// Helper code that wraps the API for the multi-step case.
|
||||
// -------------------------------------------------------
|
||||
|
||||
|
||||
class InputFlowAction {
|
||||
static back = new InputFlowAction();
|
||||
static cancel = new InputFlowAction();
|
||||
static resume = new InputFlowAction();
|
||||
}
|
||||
|
||||
type InputStep = (input: MultiStepInput) => Thenable<InputStep | void>;
|
||||
|
||||
interface QuickPickParameters<T extends QuickPickItem> {
|
||||
title: string;
|
||||
step: number;
|
||||
totalSteps: number;
|
||||
items: T[];
|
||||
activeItem?: T;
|
||||
placeholder: string;
|
||||
buttons?: QuickInputButton[];
|
||||
shouldResume: () => Thenable<boolean>;
|
||||
}
|
||||
|
||||
interface InputBoxParameters {
|
||||
title: string;
|
||||
step: number;
|
||||
totalSteps: number;
|
||||
value: string;
|
||||
prompt: string;
|
||||
validate: (value: string) => Promise<string | undefined>;
|
||||
buttons?: QuickInputButton[];
|
||||
shouldResume: () => Thenable<boolean>;
|
||||
}
|
||||
|
||||
class MultiStepInput {
|
||||
|
||||
static async run<T>(start: InputStep) {
|
||||
const input = new MultiStepInput();
|
||||
return input.stepThrough(start);
|
||||
}
|
||||
|
||||
private current?: QuickInput;
|
||||
private steps: InputStep[] = [];
|
||||
|
||||
private async stepThrough<T>(start: InputStep) {
|
||||
let step: InputStep | void = start;
|
||||
while (step) {
|
||||
this.steps.push(step);
|
||||
if (this.current) {
|
||||
this.current.enabled = false;
|
||||
this.current.busy = true;
|
||||
}
|
||||
try {
|
||||
step = await step(this);
|
||||
} catch (err) {
|
||||
if (err === InputFlowAction.back) {
|
||||
this.steps.pop();
|
||||
step = this.steps.pop();
|
||||
} else if (err === InputFlowAction.resume) {
|
||||
step = this.steps.pop();
|
||||
} else if (err === InputFlowAction.cancel) {
|
||||
step = undefined;
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.current) {
|
||||
this.current.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
async showQuickPick<T extends QuickPickItem, P extends QuickPickParameters<T>>({ title, step, totalSteps, items, activeItem, placeholder, buttons, shouldResume }: P) {
|
||||
const disposables: Disposable[] = [];
|
||||
try {
|
||||
return await new Promise<T | (P extends { buttons: (infer I)[] } ? I : never)>((resolve, reject) => {
|
||||
const input = window.createQuickPick<T>();
|
||||
input.title = title;
|
||||
input.step = step;
|
||||
input.totalSteps = totalSteps;
|
||||
input.placeholder = placeholder;
|
||||
input.items = items;
|
||||
if (activeItem) {
|
||||
input.activeItems = [activeItem];
|
||||
}
|
||||
input.buttons = [
|
||||
...(this.steps.length > 1 ? [QuickInputButtons.Back] : []),
|
||||
...(buttons || [])
|
||||
];
|
||||
disposables.push(
|
||||
input.onDidTriggerButton(item => {
|
||||
if (item === QuickInputButtons.Back) {
|
||||
reject(InputFlowAction.back);
|
||||
} else {
|
||||
resolve(<any>item);
|
||||
}
|
||||
}),
|
||||
input.onDidChangeSelection(items => resolve(items[0])),
|
||||
input.onDidHide(() => {
|
||||
(async () => {
|
||||
reject(shouldResume && await shouldResume() ? InputFlowAction.resume : InputFlowAction.cancel);
|
||||
})()
|
||||
.catch(reject);
|
||||
})
|
||||
);
|
||||
if (this.current) {
|
||||
this.current.dispose();
|
||||
}
|
||||
this.current = input;
|
||||
this.current.show();
|
||||
});
|
||||
} finally {
|
||||
disposables.forEach(d => d.dispose());
|
||||
}
|
||||
}
|
||||
|
||||
async showInputBox<P extends InputBoxParameters>({ title, step, totalSteps, value, prompt, validate, buttons, shouldResume }: P) {
|
||||
const disposables: Disposable[] = [];
|
||||
try {
|
||||
return await new Promise<string | (P extends { buttons: (infer I)[] } ? I : never)>((resolve, reject) => {
|
||||
const input = window.createInputBox();
|
||||
input.title = title;
|
||||
input.step = step;
|
||||
input.totalSteps = totalSteps;
|
||||
input.value = value || '';
|
||||
input.prompt = prompt;
|
||||
input.buttons = [
|
||||
...(this.steps.length > 1 ? [QuickInputButtons.Back] : []),
|
||||
...(buttons || [])
|
||||
];
|
||||
let validating = validate('');
|
||||
disposables.push(
|
||||
input.onDidTriggerButton(item => {
|
||||
if (item === QuickInputButtons.Back) {
|
||||
reject(InputFlowAction.back);
|
||||
} else {
|
||||
resolve(<any>item);
|
||||
}
|
||||
}),
|
||||
input.onDidAccept(async () => {
|
||||
const value = input.value;
|
||||
input.enabled = false;
|
||||
input.busy = true;
|
||||
if (!(await validate(value))) {
|
||||
resolve(value);
|
||||
}
|
||||
input.enabled = true;
|
||||
input.busy = false;
|
||||
}),
|
||||
input.onDidChangeValue(async text => {
|
||||
const current = validate(text);
|
||||
validating = current;
|
||||
const validationMessage = await current;
|
||||
if (current === validating) {
|
||||
input.validationMessage = validationMessage;
|
||||
}
|
||||
}),
|
||||
input.onDidHide(() => {
|
||||
(async () => {
|
||||
reject(shouldResume && await shouldResume() ? InputFlowAction.resume : InputFlowAction.cancel);
|
||||
})()
|
||||
.catch(reject);
|
||||
})
|
||||
);
|
||||
if (this.current) {
|
||||
this.current.dispose();
|
||||
}
|
||||
this.current = input;
|
||||
this.current.show();
|
||||
});
|
||||
} finally {
|
||||
disposables.forEach(d => d.dispose());
|
||||
}
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { QuickPickItem, window, Disposable, CancellationToken, QuickInputButton, QuickInput, ExtensionContext, QuickInputButtons, Uri } from 'vscode';
|
||||
|
||||
/**
|
||||
* A multi-step input using window.createQuickPick() and window.createInputBox().
|
||||
*
|
||||
* This first part uses the helper class `MultiStepInput` that wraps the API for the multi-step case.
|
||||
*/
|
||||
export async function multiStepInput(context: ExtensionContext) {
|
||||
|
||||
class MyButton implements QuickInputButton {
|
||||
constructor(public iconPath: { light: Uri; dark: Uri; }, public tooltip: string) { }
|
||||
}
|
||||
|
||||
const createResourceGroupButton = new MyButton({
|
||||
dark: Uri.file(context.asAbsolutePath('resources/dark/add.svg')),
|
||||
light: Uri.file(context.asAbsolutePath('resources/light/add.svg')),
|
||||
}, 'Create Resource Group');
|
||||
|
||||
const resourceGroups: QuickPickItem[] = ['vscode-data-function', 'vscode-appservice-microservices', 'vscode-appservice-monitor', 'vscode-appservice-preview', 'vscode-appservice-prod']
|
||||
.map(label => ({ label }));
|
||||
|
||||
|
||||
interface State {
|
||||
title: string;
|
||||
step: number;
|
||||
totalSteps: number;
|
||||
resourceGroup: QuickPickItem | string;
|
||||
name: string;
|
||||
runtime: QuickPickItem;
|
||||
}
|
||||
|
||||
async function collectInputs() {
|
||||
const state = {} as Partial<State>;
|
||||
await MultiStepInput.run(input => pickResourceGroup(input, state));
|
||||
return state as State;
|
||||
}
|
||||
|
||||
const title = 'Create Application Service';
|
||||
|
||||
async function pickResourceGroup(input: MultiStepInput, state: Partial<State>) {
|
||||
const pick = await input.showQuickPick({
|
||||
title,
|
||||
step: 1,
|
||||
totalSteps: 3,
|
||||
placeholder: 'Pick a resource group',
|
||||
items: resourceGroups,
|
||||
activeItem: typeof state.resourceGroup !== 'string' ? state.resourceGroup : undefined,
|
||||
buttons: [createResourceGroupButton],
|
||||
shouldResume: shouldResume
|
||||
});
|
||||
if (pick instanceof MyButton) {
|
||||
return (input: MultiStepInput) => inputResourceGroupName(input, state);
|
||||
}
|
||||
state.resourceGroup = pick;
|
||||
return (input: MultiStepInput) => inputName(input, state);
|
||||
}
|
||||
|
||||
async function inputResourceGroupName(input: MultiStepInput, state: Partial<State>) {
|
||||
state.resourceGroup = await input.showInputBox({
|
||||
title,
|
||||
step: 2,
|
||||
totalSteps: 4,
|
||||
value: typeof state.resourceGroup === 'string' ? state.resourceGroup : '',
|
||||
prompt: 'Choose a unique name for the resource group',
|
||||
validate: validateNameIsUnique,
|
||||
shouldResume: shouldResume
|
||||
});
|
||||
return (input: MultiStepInput) => inputName(input, state);
|
||||
}
|
||||
|
||||
async function inputName(input: MultiStepInput, state: Partial<State>) {
|
||||
const additionalSteps = typeof state.resourceGroup === 'string' ? 1 : 0;
|
||||
// TODO: Remember current value when navigating back.
|
||||
state.name = await input.showInputBox({
|
||||
title,
|
||||
step: 2 + additionalSteps,
|
||||
totalSteps: 3 + additionalSteps,
|
||||
value: state.name || '',
|
||||
prompt: 'Choose a unique name for the Application Service',
|
||||
validate: validateNameIsUnique,
|
||||
shouldResume: shouldResume
|
||||
});
|
||||
return (input: MultiStepInput) => pickRuntime(input, state);
|
||||
}
|
||||
|
||||
async function pickRuntime(input: MultiStepInput, state: Partial<State>) {
|
||||
const additionalSteps = typeof state.resourceGroup === 'string' ? 1 : 0;
|
||||
const runtimes = await getAvailableRuntimes(state.resourceGroup!, undefined /* TODO: token */);
|
||||
// TODO: Remember currently active item when navigating back.
|
||||
state.runtime = await input.showQuickPick({
|
||||
title,
|
||||
step: 3 + additionalSteps,
|
||||
totalSteps: 3 + additionalSteps,
|
||||
placeholder: 'Pick a runtime',
|
||||
items: runtimes,
|
||||
activeItem: state.runtime,
|
||||
shouldResume: shouldResume
|
||||
});
|
||||
}
|
||||
|
||||
function shouldResume() {
|
||||
// Could show a notification with the option to resume.
|
||||
return new Promise<boolean>((resolve, reject) => {
|
||||
// noop
|
||||
});
|
||||
}
|
||||
|
||||
async function validateNameIsUnique(name: string) {
|
||||
// ...validate...
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
return name === 'vscode' ? 'Name not unique' : undefined;
|
||||
}
|
||||
|
||||
async function getAvailableRuntimes(resourceGroup: QuickPickItem | string, token?: CancellationToken): Promise<QuickPickItem[]> {
|
||||
// ...retrieve...
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
return ['Node 8.9', 'Node 6.11', 'Node 4.5']
|
||||
.map(label => ({ label }));
|
||||
}
|
||||
|
||||
const state = await collectInputs();
|
||||
window.showInformationMessage(`Creating Application Service '${state.name}'`);
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------
|
||||
// Helper code that wraps the API for the multi-step case.
|
||||
// -------------------------------------------------------
|
||||
|
||||
|
||||
class InputFlowAction {
|
||||
static back = new InputFlowAction();
|
||||
static cancel = new InputFlowAction();
|
||||
static resume = new InputFlowAction();
|
||||
}
|
||||
|
||||
type InputStep = (input: MultiStepInput) => Thenable<InputStep | void>;
|
||||
|
||||
interface QuickPickParameters<T extends QuickPickItem> {
|
||||
title: string;
|
||||
step: number;
|
||||
totalSteps: number;
|
||||
items: T[];
|
||||
activeItem?: T;
|
||||
placeholder: string;
|
||||
buttons?: QuickInputButton[];
|
||||
shouldResume: () => Thenable<boolean>;
|
||||
}
|
||||
|
||||
interface InputBoxParameters {
|
||||
title: string;
|
||||
step: number;
|
||||
totalSteps: number;
|
||||
value: string;
|
||||
prompt: string;
|
||||
validate: (value: string) => Promise<string | undefined>;
|
||||
buttons?: QuickInputButton[];
|
||||
shouldResume: () => Thenable<boolean>;
|
||||
}
|
||||
|
||||
class MultiStepInput {
|
||||
|
||||
static async run<T>(start: InputStep) {
|
||||
const input = new MultiStepInput();
|
||||
return input.stepThrough(start);
|
||||
}
|
||||
|
||||
private current?: QuickInput;
|
||||
private steps: InputStep[] = [];
|
||||
|
||||
private async stepThrough<T>(start: InputStep) {
|
||||
let step: InputStep | void = start;
|
||||
while (step) {
|
||||
this.steps.push(step);
|
||||
if (this.current) {
|
||||
this.current.enabled = false;
|
||||
this.current.busy = true;
|
||||
}
|
||||
try {
|
||||
step = await step(this);
|
||||
} catch (err) {
|
||||
if (err === InputFlowAction.back) {
|
||||
this.steps.pop();
|
||||
step = this.steps.pop();
|
||||
} else if (err === InputFlowAction.resume) {
|
||||
step = this.steps.pop();
|
||||
} else if (err === InputFlowAction.cancel) {
|
||||
step = undefined;
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.current) {
|
||||
this.current.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
async showQuickPick<T extends QuickPickItem, P extends QuickPickParameters<T>>({ title, step, totalSteps, items, activeItem, placeholder, buttons, shouldResume }: P) {
|
||||
const disposables: Disposable[] = [];
|
||||
try {
|
||||
return await new Promise<T | (P extends { buttons: (infer I)[] } ? I : never)>((resolve, reject) => {
|
||||
const input = window.createQuickPick<T>();
|
||||
input.title = title;
|
||||
input.step = step;
|
||||
input.totalSteps = totalSteps;
|
||||
input.placeholder = placeholder;
|
||||
input.items = items;
|
||||
if (activeItem) {
|
||||
input.activeItems = [activeItem];
|
||||
}
|
||||
input.buttons = [
|
||||
...(this.steps.length > 1 ? [QuickInputButtons.Back] : []),
|
||||
...(buttons || [])
|
||||
];
|
||||
disposables.push(
|
||||
input.onDidTriggerButton(item => {
|
||||
if (item === QuickInputButtons.Back) {
|
||||
reject(InputFlowAction.back);
|
||||
} else {
|
||||
resolve(<any>item);
|
||||
}
|
||||
}),
|
||||
input.onDidChangeSelection(items => resolve(items[0])),
|
||||
input.onDidHide(() => {
|
||||
(async () => {
|
||||
reject(shouldResume && await shouldResume() ? InputFlowAction.resume : InputFlowAction.cancel);
|
||||
})()
|
||||
.catch(reject);
|
||||
})
|
||||
);
|
||||
if (this.current) {
|
||||
this.current.dispose();
|
||||
}
|
||||
this.current = input;
|
||||
this.current.show();
|
||||
});
|
||||
} finally {
|
||||
disposables.forEach(d => d.dispose());
|
||||
}
|
||||
}
|
||||
|
||||
async showInputBox<P extends InputBoxParameters>({ title, step, totalSteps, value, prompt, validate, buttons, shouldResume }: P) {
|
||||
const disposables: Disposable[] = [];
|
||||
try {
|
||||
return await new Promise<string | (P extends { buttons: (infer I)[] } ? I : never)>((resolve, reject) => {
|
||||
const input = window.createInputBox();
|
||||
input.title = title;
|
||||
input.step = step;
|
||||
input.totalSteps = totalSteps;
|
||||
input.value = value || '';
|
||||
input.prompt = prompt;
|
||||
input.buttons = [
|
||||
...(this.steps.length > 1 ? [QuickInputButtons.Back] : []),
|
||||
...(buttons || [])
|
||||
];
|
||||
let validating = validate('');
|
||||
disposables.push(
|
||||
input.onDidTriggerButton(item => {
|
||||
if (item === QuickInputButtons.Back) {
|
||||
reject(InputFlowAction.back);
|
||||
} else {
|
||||
resolve(<any>item);
|
||||
}
|
||||
}),
|
||||
input.onDidAccept(async () => {
|
||||
const value = input.value;
|
||||
input.enabled = false;
|
||||
input.busy = true;
|
||||
if (!(await validate(value))) {
|
||||
resolve(value);
|
||||
}
|
||||
input.enabled = true;
|
||||
input.busy = false;
|
||||
}),
|
||||
input.onDidChangeValue(async text => {
|
||||
const current = validate(text);
|
||||
validating = current;
|
||||
const validationMessage = await current;
|
||||
if (current === validating) {
|
||||
input.validationMessage = validationMessage;
|
||||
}
|
||||
}),
|
||||
input.onDidHide(() => {
|
||||
(async () => {
|
||||
reject(shouldResume && await shouldResume() ? InputFlowAction.resume : InputFlowAction.cancel);
|
||||
})()
|
||||
.catch(reject);
|
||||
})
|
||||
);
|
||||
if (this.current) {
|
||||
this.current.dispose();
|
||||
}
|
||||
this.current = input;
|
||||
this.current.show();
|
||||
});
|
||||
} finally {
|
||||
disposables.forEach(d => d.dispose());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,112 +1,112 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as path from 'path';
|
||||
import * as cp from 'child_process';
|
||||
import { Uri, window, Disposable } from 'vscode';
|
||||
import { QuickPickItem } from 'vscode';
|
||||
import { workspace } from 'vscode';
|
||||
|
||||
/**
|
||||
* A file opener using window.createQuickPick().
|
||||
*
|
||||
* It shows how the list of items can be dynamically updated based on
|
||||
* the user's input in the filter field.
|
||||
*/
|
||||
export async function quickOpen() {
|
||||
const uri = await pickFile();
|
||||
if (uri) {
|
||||
const document = await workspace.openTextDocument(uri);
|
||||
await window.showTextDocument(document);
|
||||
}
|
||||
}
|
||||
|
||||
class FileItem implements QuickPickItem {
|
||||
|
||||
label: string;
|
||||
description: string;
|
||||
|
||||
constructor(public base: Uri, public uri: Uri) {
|
||||
this.label = path.basename(uri.fsPath);
|
||||
this.description = path.dirname(path.relative(base.fsPath, uri.fsPath));
|
||||
}
|
||||
}
|
||||
|
||||
class MessageItem implements QuickPickItem {
|
||||
|
||||
label: string;
|
||||
description = '';
|
||||
detail: string;
|
||||
|
||||
constructor(public base: Uri, public message: string) {
|
||||
this.label = message.replace(/\r?\n/g, ' ');
|
||||
this.detail = base.fsPath;
|
||||
}
|
||||
}
|
||||
|
||||
async function pickFile() {
|
||||
const disposables: Disposable[] = [];
|
||||
try {
|
||||
return await new Promise<Uri | undefined>((resolve, reject) => {
|
||||
const input = window.createQuickPick<FileItem | MessageItem>();
|
||||
input.placeholder = 'Type to search for files';
|
||||
let rgs: cp.ChildProcess[] = [];
|
||||
disposables.push(
|
||||
input.onDidChangeValue(value => {
|
||||
rgs.forEach(rg => rg.kill());
|
||||
if (!value) {
|
||||
input.items = [];
|
||||
return;
|
||||
}
|
||||
input.busy = true;
|
||||
const cwds = workspace.workspaceFolders ? workspace.workspaceFolders.map(f => f.uri.fsPath) : [process.cwd()];
|
||||
const q = process.platform === 'win32' ? '"' : '\'';
|
||||
rgs = cwds.map(cwd => {
|
||||
const rg = cp.exec(`rg --files -g ${q}*${value}*${q}`, { cwd }, (err, stdout) => {
|
||||
const i = rgs.indexOf(rg);
|
||||
if (i !== -1) {
|
||||
if (rgs.length === cwds.length) {
|
||||
input.items = [];
|
||||
}
|
||||
if (!err) {
|
||||
input.items = input.items.concat(
|
||||
stdout
|
||||
.split('\n').slice(0, 50)
|
||||
.map(relative => new FileItem(Uri.file(cwd), Uri.file(path.join(cwd, relative))))
|
||||
);
|
||||
}
|
||||
if (err && !(<any>err).killed && (<any>err).code !== 1 && err.message) {
|
||||
input.items = input.items.concat([
|
||||
new MessageItem(Uri.file(cwd), err.message)
|
||||
]);
|
||||
}
|
||||
rgs.splice(i, 1);
|
||||
if (!rgs.length) {
|
||||
input.busy = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
return rg;
|
||||
});
|
||||
}),
|
||||
input.onDidChangeSelection(items => {
|
||||
const item = items[0];
|
||||
if (item instanceof FileItem) {
|
||||
resolve(item.uri);
|
||||
input.hide();
|
||||
}
|
||||
}),
|
||||
input.onDidHide(() => {
|
||||
rgs.forEach(rg => rg.kill());
|
||||
resolve(undefined);
|
||||
input.dispose();
|
||||
})
|
||||
);
|
||||
input.show();
|
||||
});
|
||||
} finally {
|
||||
disposables.forEach(d => d.dispose());
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as path from 'path';
|
||||
import * as cp from 'child_process';
|
||||
import { Uri, window, Disposable } from 'vscode';
|
||||
import { QuickPickItem } from 'vscode';
|
||||
import { workspace } from 'vscode';
|
||||
|
||||
/**
|
||||
* A file opener using window.createQuickPick().
|
||||
*
|
||||
* It shows how the list of items can be dynamically updated based on
|
||||
* the user's input in the filter field.
|
||||
*/
|
||||
export async function quickOpen() {
|
||||
const uri = await pickFile();
|
||||
if (uri) {
|
||||
const document = await workspace.openTextDocument(uri);
|
||||
await window.showTextDocument(document);
|
||||
}
|
||||
}
|
||||
|
||||
class FileItem implements QuickPickItem {
|
||||
|
||||
label: string;
|
||||
description: string;
|
||||
|
||||
constructor(public base: Uri, public uri: Uri) {
|
||||
this.label = path.basename(uri.fsPath);
|
||||
this.description = path.dirname(path.relative(base.fsPath, uri.fsPath));
|
||||
}
|
||||
}
|
||||
|
||||
class MessageItem implements QuickPickItem {
|
||||
|
||||
label: string;
|
||||
description = '';
|
||||
detail: string;
|
||||
|
||||
constructor(public base: Uri, public message: string) {
|
||||
this.label = message.replace(/\r?\n/g, ' ');
|
||||
this.detail = base.fsPath;
|
||||
}
|
||||
}
|
||||
|
||||
async function pickFile() {
|
||||
const disposables: Disposable[] = [];
|
||||
try {
|
||||
return await new Promise<Uri | undefined>((resolve, reject) => {
|
||||
const input = window.createQuickPick<FileItem | MessageItem>();
|
||||
input.placeholder = 'Type to search for files';
|
||||
let rgs: cp.ChildProcess[] = [];
|
||||
disposables.push(
|
||||
input.onDidChangeValue(value => {
|
||||
rgs.forEach(rg => rg.kill());
|
||||
if (!value) {
|
||||
input.items = [];
|
||||
return;
|
||||
}
|
||||
input.busy = true;
|
||||
const cwds = workspace.workspaceFolders ? workspace.workspaceFolders.map(f => f.uri.fsPath) : [process.cwd()];
|
||||
const q = process.platform === 'win32' ? '"' : '\'';
|
||||
rgs = cwds.map(cwd => {
|
||||
const rg = cp.exec(`rg --files -g ${q}*${value}*${q}`, { cwd }, (err, stdout) => {
|
||||
const i = rgs.indexOf(rg);
|
||||
if (i !== -1) {
|
||||
if (rgs.length === cwds.length) {
|
||||
input.items = [];
|
||||
}
|
||||
if (!err) {
|
||||
input.items = input.items.concat(
|
||||
stdout
|
||||
.split('\n').slice(0, 50)
|
||||
.map(relative => new FileItem(Uri.file(cwd), Uri.file(path.join(cwd, relative))))
|
||||
);
|
||||
}
|
||||
if (err && !(<any>err).killed && (<any>err).code !== 1 && err.message) {
|
||||
input.items = input.items.concat([
|
||||
new MessageItem(Uri.file(cwd), err.message)
|
||||
]);
|
||||
}
|
||||
rgs.splice(i, 1);
|
||||
if (!rgs.length) {
|
||||
input.busy = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
return rg;
|
||||
});
|
||||
}),
|
||||
input.onDidChangeSelection(items => {
|
||||
const item = items[0];
|
||||
if (item instanceof FileItem) {
|
||||
resolve(item.uri);
|
||||
input.hide();
|
||||
}
|
||||
}),
|
||||
input.onDidHide(() => {
|
||||
rgs.forEach(rg => rg.kill());
|
||||
resolve(undefined);
|
||||
input.dispose();
|
||||
})
|
||||
);
|
||||
input.show();
|
||||
});
|
||||
} finally {
|
||||
disposables.forEach(d => d.dispose());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user