@@ -6,6 +6,7 @@ import { DocumentContentProvider } from "../providers/DocumentContentProvider";
66import { replaceFile , getWsFolder , handleError , displayableUri } from "../utils" ;
77import { getFileName } from "./export" ;
88import { getUrisForDocument } from "../utils/documentIndex" ;
9+ import { pickDocument } from "../utils/documentPicker" ;
910
1011interface InputStepItem extends vscode . QuickPickItem {
1112 value ?: string ;
@@ -25,7 +26,13 @@ interface QuickPickStepOptions {
2526 items : InputStepItem [ ] ;
2627}
2728
28- type InputStepOptions = InputBoxStepOptions | QuickPickStepOptions ;
29+ interface ClassPickStepOptions {
30+ type : "classPick" ;
31+ title : string ;
32+ api : AtelierAPI | undefined ;
33+ }
34+
35+ type InputStepOptions = InputBoxStepOptions | QuickPickStepOptions | ClassPickStepOptions ;
2936
3037/**
3138 * Get input from the user using multiple steps.
@@ -101,6 +108,63 @@ async function multiStepInput(steps: InputStepOptions[]): Promise<string[] | und
101108 } ) ;
102109 inputBox . show ( ) ;
103110 } ) ;
111+ } else if ( stepOptions . type == "classPick" ) {
112+ // Optional step: escape = skip (store ""), back = go back one step, pick = store class name
113+ let picked : string | undefined ;
114+ if ( stepOptions . api ) {
115+ picked = await pickDocument ( stepOptions . api , stepOptions . title , "cls" , step + 1 , steps . length ) ;
116+ } else {
117+ // Fallback InputBox when there's no server connection
118+ picked = await new Promise < string | undefined > ( ( resolve ) => {
119+ let settled = false ;
120+ const settle = ( v : string | undefined ) => {
121+ if ( ! settled ) {
122+ settled = true ;
123+ resolve ( v ) ;
124+ }
125+ } ;
126+ const inputBox = vscode . window . createInputBox ( ) ;
127+ inputBox . ignoreFocusOut = true ;
128+ inputBox . step = step + 1 ;
129+ inputBox . totalSteps = steps . length ;
130+ inputBox . buttons = step > 0 ? [ vscode . QuickInputButtons . Back ] : [ ] ;
131+ inputBox . title = stepOptions . title ;
132+ inputBox . placeholder = "Package.Subpackage.Class" ;
133+ inputBox . onDidTriggerButton ( ( ) => {
134+ settle ( undefined ) ; // Back was pressed
135+ inputBox . hide ( ) ;
136+ } ) ;
137+ inputBox . onDidAccept ( ( ) => {
138+ if ( typeof inputBox . validationMessage != "string" ) {
139+ settle ( inputBox . value ) ; // "" = skip, or a valid class name
140+ inputBox . hide ( ) ;
141+ }
142+ } ) ;
143+ inputBox . onDidHide ( ( ) => {
144+ settle ( "" ) ; // Escape = skip this optional step
145+ inputBox . dispose ( ) ;
146+ } ) ;
147+ inputBox . onDidChangeValue ( ( value ) => {
148+ inputBox . validationMessage = value ? validateClassName ( value ) : undefined ;
149+ } ) ;
150+ inputBox . show ( ) ;
151+ } ) ;
152+ }
153+ if ( picked === "" ) {
154+ // Back button was pressed: go back one step
155+ step -- ;
156+ } else {
157+ // undefined = skipped, or a class name was entered/picked
158+ if ( typeof picked == "undefined" ) {
159+ picked = "" ;
160+ } else if ( picked . slice ( - 4 ) == ".cls" ) {
161+ picked = picked . slice ( 0 , - 4 ) ;
162+ }
163+ results [ step ] = picked ;
164+ step ++ ;
165+ }
166+ // This is an optional step; never cancel the wizard on escape
167+ escape = false ;
104168 } else {
105169 // Show the QuickPick
106170 escape = await new Promise < boolean > ( ( resolve ) => {
@@ -222,6 +286,7 @@ function getAdapterPrompt(adapters: InputStepItem[], type: AdapaterClassType): I
222286
223287/** The types of classes we can create */
224288export enum NewFileType {
289+ Class = "Class" ,
225290 BusinessOperation = "Business Operation" ,
226291 BusinessService = "Business Service" ,
227292 BPL = "Business Process" ,
@@ -262,7 +327,7 @@ export async function newFile(type: NewFileType): Promise<void> {
262327 api = undefined ;
263328 }
264329
265- if ( type != NewFileType . KPI ) {
330+ if ( type != NewFileType . KPI && type != NewFileType . Class ) {
266331 // Check if we're connected to an Interoperability namespace
267332 const ensemble : boolean = api
268333 ? await api . getNamespace ( ) . then ( ( data ) => data . result . content . features [ 0 ] . enabled )
@@ -402,7 +467,7 @@ export async function newFile(type: NewFileType): Promise<void> {
402467 inputSteps . push (
403468 {
404469 type : "inputBox" ,
405- title : `Enter a name for the new ${ type } class` ,
470+ title : `Enter a name for the new ${ type == NewFileType . Class ? " class" : type + " class" } ` ,
406471 placeholder : "Package.Subpackage.Class" ,
407472 validateInput : ( value : string ) => {
408473 const valid = validateClassName ( value ) ;
@@ -933,6 +998,30 @@ Parameter RESPONSECLASSNAME As CLASSNAME = "${respClass}";`
933998/// InterSystems IRIS purges message bodies based on the class when the option to purge message bodies is enabled
934999Parameter ENSPURGE As BOOLEAN = 1;
9351000
1001+ }
1002+ ` ;
1003+ } else if ( type == NewFileType . Class ) {
1004+ // Add the superclass picker as the third step
1005+ inputSteps . push ( {
1006+ type : "classPick" ,
1007+ title : "Pick an optional superclass or press 'Escape' for none" ,
1008+ api : api ,
1009+ } ) ;
1010+
1011+ // Prompt the user
1012+ const results = await multiStepInput ( inputSteps ) ;
1013+ if ( ! results ) {
1014+ return ;
1015+ }
1016+ cls = results [ 0 ] ;
1017+ const [ , desc , superclass ] = results ;
1018+
1019+ // Generate the file's content
1020+ clsContent = `
1021+ ${ typeof desc == "string" ? "/// " + desc . replace ( / \n / g, "\n/// " ) : "" }
1022+ Class ${ cls } ${ superclass ? ` Extends ${ superclass } ` : "" }
1023+ {
1024+
9361025}
9371026` ;
9381027 }
0 commit comments