microsoft/vscode-react-native

Public

mirrored from https://github.com/microsoft/vscode-react-nativeAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
960a6ec47eafad42cd52a36af455604d4650cfff

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

src/extension/debuggingConfiguration/multiStepInput.ts

263lines · modeblame

5471436aRedMickey5 years ago1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for details.
3
4import {
5Disposable,
6QuickInput,
7QuickInputButton,
8QuickInputButtons,
9QuickPickItem,
10window,
11} from "vscode";
12
13export type InputStep<T extends any> = (
14input: MultiStepInput<T>,
15state: T,
16) => Promise<InputStep<T> | void>;
17
18export class InputFlowAction {
19public static back = new InputFlowAction();
20public static cancel = new InputFlowAction();
21public static resume = new InputFlowAction();
22}
23
24export interface IQuickPickParameters<T extends QuickPickItem> {
25title?: string;
26step?: number;
27totalSteps?: number;
28canGoBack?: boolean;
29items: ReadonlyArray<T>;
30activeItem?: T;
31placeholder: string;
32buttons?: QuickInputButton[];
33matchOnDescription?: boolean;
34matchOnDetail?: boolean;
35acceptFilterBoxTextAsSelection?: boolean;
36shouldResume?(): Promise<boolean>;
37}
38
39export interface InputBoxParameters {
40title: string;
41password?: boolean;
42step?: number;
43totalSteps?: number;
44value: string;
45prompt: string;
46buttons?: QuickInputButton[];
47validate(value: string): Promise<string | undefined>;
48shouldResume?(): Promise<boolean>;
49}
50
51type MultiStepInputQuickPicResponseType<T, P> =
52| T
53| (P extends { buttons: (infer I)[] } ? I : never);
54type MultiStepInputInputBoxResponseType<P> =
55| string
56| (P extends { buttons: (infer I)[] } ? I : never);
57export interface IMultiStepInput<S> {
58run(start: InputStep<S>, state: S): Promise<void>;
59showQuickPick<T extends QuickPickItem, P extends IQuickPickParameters<T>>({
60title,
61step,
62totalSteps,
63items,
64activeItem,
65placeholder,
66buttons,
67shouldResume,
68}: P): Promise<MultiStepInputQuickPicResponseType<T, P>>;
69showInputBox<P extends InputBoxParameters>({
70title,
71step,
72totalSteps,
73value,
74prompt,
75validate,
76buttons,
77shouldResume,
78}: P): Promise<MultiStepInputInputBoxResponseType<P>>;
79}
80
81export class MultiStepInput<S> implements IMultiStepInput<S> {
82private current?: QuickInput;
83private steps: InputStep<S>[] = [];
84
228fed39RedMickey5 years ago85public run(start: InputStep<S>, state: S): Promise<void> {
5471436aRedMickey5 years ago86return this.stepThrough(start, state);
87}
88
89public async showQuickPick<T extends QuickPickItem, P extends IQuickPickParameters<T>>({
90title,
91step,
92totalSteps,
93items,
94activeItem,
95placeholder,
96buttons,
97shouldResume,
98matchOnDescription,
99matchOnDetail,
100acceptFilterBoxTextAsSelection,
101}: P): Promise<MultiStepInputQuickPicResponseType<T, P>> {
102const disposables: Disposable[] = [];
103try {
104return await new Promise<MultiStepInputQuickPicResponseType<T, P>>(
105(resolve, reject) => {
106const input = window.createQuickPick<T>();
107input.title = title;
108input.step = step;
109input.totalSteps = totalSteps;
110input.placeholder = placeholder;
111input.ignoreFocusOut = true;
112input.items = items;
113input.matchOnDescription = matchOnDescription || false;
114input.matchOnDetail = matchOnDetail || false;
115if (activeItem) {
116input.activeItems = [activeItem];
117} else {
118input.activeItems = [];
119}
120input.buttons = [
121...(this.steps.length > 1 ? [QuickInputButtons.Back] : []),
122...(buttons || []),
123];
124disposables.push(
125input.onDidTriggerButton(item => {
126if (item === QuickInputButtons.Back) {
127reject(InputFlowAction.back);
128} else {
129resolve(<any>item);
130}
131}),
132input.onDidChangeSelection(selectedItems => resolve(selectedItems[0])),
133input.onDidHide(() => {
134(async () => {
135reject(
136shouldResume && (await shouldResume())
137? InputFlowAction.resume
138: InputFlowAction.cancel,
139);
140})().catch(reject);
141}),
142);
143if (acceptFilterBoxTextAsSelection) {
144disposables.push(
145input.onDidAccept(() => {
146resolve(<any>input.value);
147}),
148);
149}
150if (this.current) {
151this.current.dispose();
152}
153this.current = input;
154this.current.show();
155},
156);
157} finally {
158disposables.forEach(d => d.dispose());
159}
160}
161
162public async showInputBox<P extends InputBoxParameters>({
163title,
164step,
165totalSteps,
166value,
167prompt,
168validate,
169password,
170buttons,
171shouldResume,
172}: P): Promise<MultiStepInputInputBoxResponseType<P>> {
173const disposables: Disposable[] = [];
174try {
175return await new Promise<MultiStepInputInputBoxResponseType<P>>((resolve, reject) => {
176const input = window.createInputBox();
177input.title = title;
178input.step = step;
179input.totalSteps = totalSteps;
180input.password = password ? true : false;
181input.value = value || "";
182input.prompt = prompt;
183input.ignoreFocusOut = true;
184input.buttons = [
185...(this.steps.length > 1 ? [QuickInputButtons.Back] : []),
186...(buttons || []),
187];
188let validating = validate("");
189disposables.push(
190input.onDidTriggerButton(item => {
191if (item === QuickInputButtons.Back) {
192reject(InputFlowAction.back);
193} else {
194resolve(<any>item);
195}
196}),
197input.onDidAccept(async () => {
198const inputValue = input.value;
199input.enabled = false;
200input.busy = true;
201if (!(await validate(inputValue))) {
202resolve(inputValue);
203}
204input.enabled = true;
205input.busy = false;
206}),
207input.onDidChangeValue(async text => {
208const current = validate(text);
209validating = current;
210const validationMessage = await current;
211if (current === validating) {
212input.validationMessage = validationMessage;
213}
214}),
215input.onDidHide(() => {
216(async () => {
217reject(
218shouldResume && (await shouldResume())
219? InputFlowAction.resume
220: InputFlowAction.cancel,
221);
222})().catch(reject);
223}),
224);
225if (this.current) {
226this.current.dispose();
227}
228this.current = input;
229this.current.show();
230});
231} finally {
232disposables.forEach(d => d.dispose());
233}
234}
235
236private async stepThrough(start: InputStep<S>, state: S) {
237let step: InputStep<S> | void = start;
238while (step) {
239this.steps.push(step);
240if (this.current) {
241this.current.enabled = false;
242this.current.busy = true;
243}
244try {
245step = await step(this, state);
246} catch (err) {
247if (err === InputFlowAction.back) {
248this.steps.pop();
249step = this.steps.pop();
250} else if (err === InputFlowAction.resume) {
251step = this.steps.pop();
252} else if (err === InputFlowAction.cancel) {
253step = undefined;
254} else {
255throw err;
256}
257}
258}
259if (this.current) {
260this.current.dispose();
261}
262}
263}