1+ /* eslint-disable @typescript-eslint/no-unsafe-return */
2+ /* eslint-disable @typescript-eslint/no-explicit-any */
3+ /* eslint-disable @typescript-eslint/no-unsafe-argument */
4+ /* eslint-disable @typescript-eslint/prefer-promise-reject-errors */
5+ /* eslint-disable @typescript-eslint/only-throw-error */
16/*---------------------------------------------------------------------------------------------
27 * Copyright (c) Microsoft Corporation. All rights reserved.
38 * Licensed under the MIT License. See License.txt in the project root for license information.
914 */
1015
1116import {
12- QuickPickItem ,
13- window ,
1417 Disposable ,
15- CancellationToken ,
16- QuickInputButton ,
1718 QuickInput ,
18- ExtensionContext ,
19+ QuickInputButton ,
1920 QuickInputButtons ,
20- Uri ,
21+ QuickPickItem ,
22+ window ,
2123} from 'vscode' ;
2224
2325// -------------------------------------------------------
2426// Helper code that wraps the API for the multi-step case.
2527// -------------------------------------------------------
2628
27- class InputFlowAction {
29+ export class InputFlowAction {
2830 static back = new InputFlowAction ( ) ;
2931 static cancel = new InputFlowAction ( ) ;
3032 static resume = new InputFlowAction ( ) ;
@@ -37,11 +39,13 @@ interface QuickPickParameters<T extends QuickPickItem> {
3739 step : number ;
3840 totalSteps : number ;
3941 items : T [ ] ;
40- activeItem ?: T ;
42+ canSelectMany ?: boolean ;
43+ activeItems ?: T | T [ ] ;
44+ selectedItems ?: T | T [ ] ;
4145 ignoreFocusOut ?: boolean ;
4246 placeholder : string ;
4347 buttons ?: QuickInputButton [ ] ;
44- shouldResume : ( ) => Thenable < boolean > ;
48+ shouldResume ? : ( ) => Thenable < boolean > ;
4549}
4650
4751interface InputBoxParameters {
@@ -50,47 +54,51 @@ interface InputBoxParameters {
5054 totalSteps : number ;
5155 value : string ;
5256 prompt : string ;
53- validate : ( value : string ) => Promise < string | undefined > ;
57+ validate : ( value : string ) => string | undefined | Promise < string | undefined > ;
5458 buttons ?: QuickInputButton [ ] ;
5559 ignoreFocusOut ?: boolean ;
5660 placeholder ?: string ;
57- shouldResume : ( ) => Thenable < boolean > ;
61+ shouldResume ? : ( ) => Thenable < boolean > ;
5862}
5963
60- class MultiStepInput {
61- static async run < T > ( start : InputStep ) {
64+ export class MultiStepInput {
65+ static async run ( start : InputStep ) {
6266 const input = new MultiStepInput ( ) ;
6367 return input . stepThrough ( start ) ;
6468 }
6569
6670 private current ?: QuickInput ;
6771 private steps : InputStep [ ] = [ ] ;
6872
69- private async stepThrough < T > ( start : InputStep ) {
70- let step : InputStep | void = start ;
71- while ( step ) {
72- this . steps . push ( step ) ;
73- if ( this . current ) {
74- this . current . enabled = false ;
75- this . current . busy = true ;
76- }
77- try {
78- step = await step ( this ) ;
79- } catch ( err ) {
80- if ( err === InputFlowAction . back ) {
81- this . steps . pop ( ) ;
82- step = this . steps . pop ( ) ;
83- } else if ( err === InputFlowAction . resume ) {
84- step = this . steps . pop ( ) ;
85- } else if ( err === InputFlowAction . cancel ) {
86- step = undefined ;
87- } else {
88- throw err ;
73+ private async stepThrough ( start : InputStep ) {
74+ try {
75+ let step : InputStep | void = start ;
76+ while ( step ) {
77+ this . steps . push ( step ) ;
78+ if ( this . current ) {
79+ this . current . enabled = false ;
80+ this . current . busy = true ;
81+ }
82+ try {
83+ step = await step ( this ) ;
84+ } catch ( err ) {
85+ if ( err === InputFlowAction . back ) {
86+ this . steps . pop ( ) ;
87+ step = this . steps . pop ( ) ;
88+ } else if ( err === InputFlowAction . resume ) {
89+ step = this . steps . pop ( ) ;
90+ } else if ( err === InputFlowAction . cancel ) {
91+ step = undefined ;
92+ throw err ;
93+ } else {
94+ throw err ;
95+ }
8996 }
9097 }
91- }
92- if ( this . current ) {
93- this . current . dispose ( ) ;
98+ } finally {
99+ if ( this . current ) {
100+ this . current . dispose ( ) ;
101+ }
94102 }
95103 }
96104
@@ -99,56 +107,83 @@ class MultiStepInput {
99107 step,
100108 totalSteps,
101109 items,
102- activeItem,
110+ canSelectMany,
111+ activeItems,
112+ selectedItems,
103113 ignoreFocusOut,
104114 placeholder,
105115 buttons,
106116 shouldResume,
107- } : P ) {
117+ } : P ) : Promise <
118+ | ( P extends { canSelectMany : boolean } ? T [ ] : T )
119+ | ( P extends { buttons : ( infer I ) [ ] } ? I : never )
120+ > {
108121 const disposables : Disposable [ ] = [ ] ;
109122 try {
110- return await new Promise < T | ( P extends { buttons : ( infer I ) [ ] } ? I : never ) > (
111- ( resolve , reject ) => {
112- const input = window . createQuickPick < T > ( ) ;
113- input . title = title ;
114- input . step = step ;
115- input . totalSteps = totalSteps ;
116- input . ignoreFocusOut = ignoreFocusOut ?? false ;
117- input . placeholder = placeholder ;
118- input . items = items ;
119- if ( activeItem ) {
120- input . activeItems = [ activeItem ] ;
123+ return await new Promise <
124+ | ( P extends { canSelectMany : boolean } ? T [ ] : T )
125+ | ( P extends { buttons : ( infer I ) [ ] } ? I : never )
126+ > ( ( resolve , reject ) => {
127+ const input = window . createQuickPick < T > ( ) ;
128+ input . title = title ;
129+ input . step = step ;
130+ input . totalSteps = totalSteps ;
131+ input . ignoreFocusOut = ignoreFocusOut ?? false ;
132+ input . placeholder = placeholder ;
133+ input . items = items ;
134+ input . canSelectMany = canSelectMany ?? false ;
135+ if ( activeItems ) {
136+ if ( activeItems instanceof Array ) {
137+ input . activeItems = activeItems ;
138+ } else {
139+ input . activeItems = [ activeItems ] ;
121140 }
122- input . buttons = [
123- ...( this . steps . length > 1 ? [ QuickInputButtons . Back ] : [ ] ) ,
124- ...( buttons || [ ] ) ,
125- ] ;
126- disposables . push (
127- input . onDidTriggerButton ( ( item ) => {
128- if ( item === QuickInputButtons . Back ) {
129- reject ( InputFlowAction . back ) ;
130- } else {
131- resolve ( < any > item ) ;
132- }
133- } ) ,
134- input . onDidChangeSelection ( ( items ) => resolve ( items [ 0 ] ) ) ,
135- input . onDidHide ( ( ) => {
136- ( async ( ) => {
137- reject (
138- shouldResume && ( await shouldResume ( ) )
139- ? InputFlowAction . resume
140- : InputFlowAction . cancel ,
141- ) ;
142- } ) ( ) . catch ( reject ) ;
143- } ) ,
144- ) ;
145- if ( this . current ) {
146- this . current . dispose ( ) ;
141+ }
142+ if ( selectedItems ) {
143+ if ( selectedItems instanceof Array ) {
144+ input . selectedItems = selectedItems ;
145+ } else {
146+ input . selectedItems = [ selectedItems ] ;
147147 }
148- this . current = input ;
149- this . current . show ( ) ;
150- } ,
151- ) ;
148+ }
149+ input . buttons = [
150+ ...( this . steps . length > 1 ? [ QuickInputButtons . Back ] : [ ] ) ,
151+ ...( buttons || [ ] ) ,
152+ ] ;
153+ disposables . push (
154+ input . onDidTriggerButton ( ( item ) => {
155+ if ( item === QuickInputButtons . Back ) {
156+ reject ( InputFlowAction . back ) ;
157+ } else {
158+ resolve ( < any > item ) ;
159+ }
160+ } ) ,
161+ input . onDidChangeSelection ( ( items ) => {
162+ if ( ! canSelectMany ) {
163+ resolve ( < any > items [ 0 ] ) ;
164+ }
165+ } ) ,
166+ input . onDidAccept ( ( ) => {
167+ if ( canSelectMany ) {
168+ resolve ( < any > input . selectedItems . concat ( ) ) ;
169+ }
170+ } ) ,
171+ input . onDidHide ( ( ) => {
172+ ( async ( ) => {
173+ reject (
174+ shouldResume && ( await shouldResume ( ) )
175+ ? InputFlowAction . resume
176+ : InputFlowAction . cancel ,
177+ ) ;
178+ } ) ( ) . catch ( reject ) ;
179+ } ) ,
180+ ) ;
181+ if ( this . current ) {
182+ this . current . dispose ( ) ;
183+ }
184+ this . current = input ;
185+ this . current . show ( ) ;
186+ } ) ;
152187 } finally {
153188 disposables . forEach ( ( d ) => d . dispose ( ) ) ;
154189 }
0 commit comments