1+ import  {  window ,  Disposable ,  QuickInput ,  QuickInputButtons ,  ExtensionContext  }  from  'vscode' ; 
2+ 
3+ export  async  function  newResourceInput ( context : ExtensionContext )  { 
4+ 
5+ 
6+ 	interface  State  { 
7+ 		title : string ; 
8+ 		step : number ; 
9+ 		totalSteps : number ; 
10+ 		key : string ; 
11+ 		value : string ; 
12+         comment : string  |  string ; 
13+ 	} 
14+ 
15+ 	async  function  collectInputs ( )  { 
16+ 		const  state  =  { }  as  Partial < State > ; 
17+ 		await  MultiStepInput . run ( input  =>  inputKey ( input ,  state ) ) ; 
18+ 		return  state  as  State ; 
19+ 	} 
20+ 
21+ 	const  title  =  'Add new resource' ; 
22+ 
23+ 	async  function  inputKey ( input : MultiStepInput ,  state : Partial < State > )  { 
24+         state . key  =  await  input . showInputBox ( { 
25+             title, 
26+             step : 1 , 
27+             totalSteps : 3 , 
28+             value : state . key  ||  '' , 
29+             prompt : 'Provide a Key for the resource' , 
30+             validate : validateNotNull , 
31+             shouldResume : shouldResume 
32+         } ) ; 
33+         return  ( input : MultiStepInput )  =>  inputValue ( input ,  state ) ; 
34+     } 
35+ 
36+     async  function  inputValue ( input : MultiStepInput ,  state : Partial < State > )  { 
37+         state . value  =  await  input . showInputBox ( { 
38+             title, 
39+             step : 2 , 
40+             totalSteps : 3 , 
41+             value : state . value  ||  '' , 
42+             prompt : 'Provide a Value for the resource' , 
43+             validate : validateNotNull , 
44+             shouldResume : shouldResume 
45+         } ) ; 
46+         return  ( input : MultiStepInput )  =>  inputComment ( input ,  state ) ; 
47+     } 
48+ 
49+     async  function  inputComment ( input : MultiStepInput ,  state : Partial < State > )  { 
50+         state . comment  =  await  input . showInputBox ( { 
51+             title, 
52+             step : 3 , 
53+             totalSteps : 3 , 
54+             value : state . comment  ||  '' , 
55+             prompt : 'Provide a Comment for the resource' , 
56+             validate : validateNotNull , 
57+             shouldResume : shouldResume 
58+         } ) ; 
59+     } 
60+ 
61+ 	function  shouldResume ( )  { 
62+ 		// Could show a notification with the option to resume. 
63+ 		return  new  Promise < boolean > ( ( resolve ,  reject )  =>  { 
64+ 			// noop 
65+ 		} ) ; 
66+ 	} 
67+ 
68+ 	async  function  validateNotNull ( name : string )  { 
69+ 		await  new  Promise ( resolve  =>  setTimeout ( resolve ,  1000 ) ) ; 
70+ 		return  name  ===  ''  ? 'Must not be empty'  : undefined ; 
71+ 	} 
72+ 
73+ 	const  state  =  await  collectInputs ( ) ; 
74+ 	
75+ 	return  state ; 
76+ } 
77+ 
78+ 
79+ // ------------------------------------------------------- 
80+ // Helper code that wraps the API for the multi-step case. 
81+ // ------------------------------------------------------- 
82+ 
83+ 
84+ class  InputFlowAction  { 
85+ 	static  back  =  new  InputFlowAction ( ) ; 
86+ 	static  cancel  =  new  InputFlowAction ( ) ; 
87+ 	static  resume  =  new  InputFlowAction ( ) ; 
88+ } 
89+ 
90+ type  InputStep  =  ( input : MultiStepInput )  =>  Thenable < InputStep  |  void > ; 
91+ 
92+ interface  InputBoxParameters  { 
93+ 	title : string ; 
94+ 	step : number ; 
95+ 	totalSteps : number ; 
96+ 	value : string ; 
97+ 	prompt : string ; 
98+ 	placeholder ?: string ; 
99+ 	validate : ( value : string )  =>  Promise < string  |  undefined > ; 
100+ 	shouldResume : ( )  =>  Thenable < boolean > ; 
101+ } 
102+ 
103+ class  MultiStepInput  { 
104+ 
105+ 	static  async  run < T > ( start : InputStep )  { 
106+ 		const  input  =  new  MultiStepInput ( ) ; 
107+ 		return  input . stepThrough ( start ) ; 
108+ 	} 
109+ 
110+ 	private  current ?: QuickInput ; 
111+ 	private  steps : InputStep [ ]  =  [ ] ; 
112+ 
113+ 	private  async  stepThrough < T > ( start : InputStep )  { 
114+ 		let  step : InputStep  |  void   =  start ; 
115+ 		while  ( step )  { 
116+ 			this . steps . push ( step ) ; 
117+ 			if  ( this . current )  { 
118+ 				this . current . enabled  =  false ; 
119+ 				this . current . busy  =  true ; 
120+ 			} 
121+ 			try  { 
122+ 				step  =  await  step ( this ) ; 
123+ 			}  catch  ( err )  { 
124+ 				if  ( err  ===  InputFlowAction . back )  { 
125+ 					this . steps . pop ( ) ; 
126+ 					step  =  this . steps . pop ( ) ; 
127+ 				}  else  if  ( err  ===  InputFlowAction . resume )  { 
128+ 					step  =  this . steps . pop ( ) ; 
129+ 				}  else  if  ( err  ===  InputFlowAction . cancel )  { 
130+ 					step  =  undefined ; 
131+ 				}  else  { 
132+ 					throw  err ; 
133+ 				} 
134+ 			} 
135+ 		} 
136+ 		if  ( this . current )  { 
137+ 			this . current . dispose ( ) ; 
138+ 		} 
139+ 	} 
140+ 
141+ 	async  showInputBox < P  extends  InputBoxParameters > ( {  title,  step,  totalSteps,  value,  prompt,  validate,  buttons,  shouldResume,  placeholder } : P )  { 
142+ 		const  disposables : Disposable [ ]  =  [ ] ; 
143+ 		try  { 
144+ 			return  await  new  Promise < string  |  ( P  extends  {  buttons : ( infer I ) [ ]  }  ? I  : never ) > ( ( resolve ,  reject )  =>  { 
145+ 				const  input  =  window . createInputBox ( ) ; 
146+ 				input . title  =  title ; 
147+ 				input . step  =  step ; 
148+ 				input . totalSteps  =  totalSteps ; 
149+ 				input . value  =  value  ||  '' ; 
150+ 				input . prompt  =  prompt ; 
151+ 				input . buttons  =  [ 
152+ 					...( this . steps . length  >  1  ? [ QuickInputButtons . Back ]  : [ ] ) , 
153+ 					...( buttons  ||  [ ] ) 
154+ 				] ; 
155+ 				input . placeholder  =  placeholder ; 
156+ 				let  validating  =  validate ( '' ) ; 
157+ 				disposables . push ( 
158+ 					input . onDidTriggerButton ( item  =>  { 
159+ 						if  ( item  ===  QuickInputButtons . Back )  { 
160+ 							reject ( InputFlowAction . back ) ; 
161+ 						}  else  { 
162+ 							resolve ( < any > item ) ; 
163+ 						} 
164+ 					} ) , 
165+ 					input . onDidAccept ( async  ( )  =>  { 
166+ 						const  value  =  input . value ; 
167+ 						input . enabled  =  false ; 
168+ 						input . busy  =  true ; 
169+ 						if  ( ! ( await  validate ( value ) ) )  { 
170+ 							resolve ( value ) ; 
171+ 						} 
172+ 						input . enabled  =  true ; 
173+ 						input . busy  =  false ; 
174+ 					} ) , 
175+ 					input . onDidChangeValue ( async  text  =>  { 
176+ 						const  current  =  validate ( text ) ; 
177+ 						validating  =  current ; 
178+ 						const  validationMessage  =  await  current ; 
179+ 						if  ( current  ===  validating )  { 
180+ 							input . validationMessage  =  validationMessage ; 
181+ 						} 
182+ 					} ) , 
183+ 					input . onDidHide ( ( )  =>  { 
184+ 						( async  ( )  =>  { 
185+ 							reject ( shouldResume  &&  await  shouldResume ( )  ? InputFlowAction . resume  : InputFlowAction . cancel ) ; 
186+ 						} ) ( ) 
187+ 							. catch ( reject ) ; 
188+ 					} ) 
189+ 				) ; 
190+ 				if  ( this . current )  { 
191+ 					this . current . dispose ( ) ; 
192+ 				} 
193+ 				this . current  =  input ; 
194+ 				this . current . show ( ) ; 
195+ 			} ) ; 
196+ 		}  finally  { 
197+ 			disposables . forEach ( d  =>  d . dispose ( ) ) ; 
198+ 		} 
199+ 	} 
200+ } 
0 commit comments