microsoft/vscode-react-native

Public

mirrored fromhttps://github.com/microsoft/vscode-react-nativeAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
4cd259621ddfbd348fade892a2f3ee87fd1924c5

Branches

Tags

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

Clone

HTTPS

Download ZIP

src/extension/debuggingConfiguration/multiStepInput.ts

263lines · modecode

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