Skip to content

Commit e73b96c

Browse files
Add optional superclass prompt (step 3) to new Class wizard
Co-authored-by: gjsjohnmurray <6726799+gjsjohnmurray@users.noreply.github.com>
1 parent 41df5f1 commit e73b96c

File tree

2 files changed

+153
-2
lines changed

2 files changed

+153
-2
lines changed

src/commands/newFile.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { DocumentContentProvider } from "../providers/DocumentContentProvider";
66
import { replaceFile, getWsFolder, handleError, displayableUri } from "../utils";
77
import { getFileName } from "./export";
88
import { getUrisForDocument } from "../utils/documentIndex";
9+
import { pickClass } from "./project";
910

1011
interface InputStepItem extends vscode.QuickPickItem {
1112
value?: string;
@@ -937,18 +938,31 @@ Parameter ENSPURGE As BOOLEAN = 1;
937938
}
938939
`;
939940
} else if (type == NewFileType.Class) {
940-
// Prompt the user
941+
// Prompt the user for the class name and description
941942
const results = await multiStepInput(inputSteps);
942943
if (!results) {
943944
return;
944945
}
945946
cls = results[0];
946947
const [, desc] = results;
947948

949+
// Prompt for an optional superclass
950+
let superclass: string | undefined;
951+
if (api) {
952+
superclass = await pickClass(api, "Pick an optional superclass. Press 'Escape' to skip.");
953+
} else {
954+
superclass = await vscode.window.showInputBox({
955+
title: "Enter an optional superclass. Press 'Escape' to skip.",
956+
ignoreFocusOut: true,
957+
placeHolder: "Package.Subpackage.Class",
958+
validateInput: (value: string) => (value ? validateClassName(value) : undefined),
959+
});
960+
}
961+
948962
// Generate the file's content
949963
clsContent = `
950964
${typeof desc == "string" ? "/// " + desc.replace(/\n/g, "\n/// ") : ""}
951-
Class ${cls}
965+
Class ${cls}${superclass ? ` Extends ${superclass}` : ""}
952966
{
953967
954968
}

src/commands/project.ts

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,143 @@ async function pickAdditions(
650650
});
651651
}
652652

653+
/**
654+
* Show an expandable QuickPick to let the user pick a single class from the server.
655+
* Packages can be expanded to reveal their classes. Only leaf class items can be accepted.
656+
* Returns the class name (without the `.cls` extension), or `undefined` if the user escapes.
657+
*/
658+
export async function pickClass(api: AtelierAPI, title: string): Promise<string | undefined> {
659+
const query = "SELECT Name, Type FROM %Library.RoutineMgr_StudioOpenDialog(?,1,1,?,0,0,?)";
660+
let sys: "0" | "1" = "0";
661+
let gen: "0" | "1" = "0";
662+
663+
return new Promise<string | undefined>((resolve) => {
664+
const quickPick = vscode.window.createQuickPick<PickAdditionsItem>();
665+
quickPick.title = title;
666+
quickPick.ignoreFocusOut = true;
667+
quickPick.keepScrollPosition = true;
668+
quickPick.matchOnDescription = true;
669+
quickPick.buttons = [
670+
{
671+
iconPath: new vscode.ThemeIcon("library"),
672+
tooltip: "System",
673+
location: vscode.QuickInputButtonLocation.Input,
674+
toggle: { checked: false },
675+
},
676+
{
677+
iconPath: new vscode.ThemeIcon("server-process"),
678+
tooltip: "Generated",
679+
location: vscode.QuickInputButtonLocation.Input,
680+
toggle: { checked: false },
681+
},
682+
];
683+
684+
const getRootItems = (): Promise<void> => {
685+
return api
686+
.actionQuery(query, ["*.cls", sys, gen])
687+
.then((data) => {
688+
quickPick.items = data.result.content.map((i) => sodItemToPickAdditionsItem(i));
689+
quickPick.busy = false;
690+
})
691+
.catch((error) => {
692+
quickPick.hide();
693+
handleError(error, "Failed to get namespace contents.");
694+
});
695+
};
696+
697+
const expandItem = (itemIdx: number): Promise<void> => {
698+
const item = quickPick.items[itemIdx];
699+
// Switch the expand button to a collapse button
700+
const newItems = [...quickPick.items];
701+
newItems[itemIdx] = {
702+
...item,
703+
buttons: [{ iconPath: new vscode.ThemeIcon("chevron-down"), tooltip: "Collapse" }],
704+
};
705+
quickPick.items = newItems;
706+
return api
707+
.actionQuery(query, [item.fullName + "/*.cls", sys, gen])
708+
.then((data) => {
709+
const insertItems: PickAdditionsItem[] = data.result.content.map((i) =>
710+
sodItemToPickAdditionsItem(i, item.fullName, item.label.search(/\S/))
711+
);
712+
const updatedItems = [...quickPick.items];
713+
updatedItems.splice(itemIdx + 1, 0, ...insertItems);
714+
quickPick.items = updatedItems;
715+
quickPick.busy = false;
716+
})
717+
.catch((error) => {
718+
quickPick.hide();
719+
handleError(error, "Failed to get namespace contents.");
720+
});
721+
};
722+
723+
quickPick.onDidTriggerButton((button) => {
724+
quickPick.busy = true;
725+
if (button.tooltip == "System") {
726+
sys = button.toggle.checked ? "1" : "0";
727+
} else {
728+
gen = button.toggle.checked ? "1" : "0";
729+
}
730+
getRootItems();
731+
});
732+
733+
quickPick.onDidTriggerItemButton((event) => {
734+
quickPick.busy = true;
735+
const itemIdx = quickPick.items.findIndex((i) => i.fullName === event.item.fullName);
736+
if (event.button.tooltip.charAt(0) == "E") {
737+
expandItem(itemIdx);
738+
} else {
739+
// Collapse: remove the button and all descendants
740+
const newItems = [...quickPick.items];
741+
newItems[itemIdx] = {
742+
...newItems[itemIdx],
743+
buttons: [{ iconPath: new vscode.ThemeIcon("chevron-right"), tooltip: "Expand" }],
744+
};
745+
quickPick.items = newItems.filter(
746+
(i, idx) => idx <= itemIdx || !i.fullName.startsWith(event.item.fullName + ".")
747+
);
748+
quickPick.busy = false;
749+
}
750+
});
751+
752+
quickPick.onDidChangeValue((filter: string) => {
753+
// Auto-expand a package when the user types its name followed by a dot
754+
if (filter.endsWith(".")) {
755+
const itemIdx = quickPick.items.findIndex(
756+
(i) => i.fullName.toLowerCase() === filter.slice(0, -1).toLowerCase()
757+
);
758+
if (
759+
itemIdx != -1 &&
760+
quickPick.items[itemIdx].buttons?.length &&
761+
quickPick.items[itemIdx].buttons[0].tooltip.charAt(0) == "E"
762+
) {
763+
quickPick.busy = true;
764+
expandItem(itemIdx);
765+
}
766+
}
767+
});
768+
769+
quickPick.onDidAccept(() => {
770+
const selected = quickPick.activeItems[0];
771+
if (selected && !selected.buttons?.length) {
772+
// Leaf class item (no expand button): strip the .cls extension and resolve
773+
const name = selected.fullName.endsWith(".cls") ? selected.fullName.slice(0, -4) : selected.fullName;
774+
resolve(name);
775+
quickPick.hide();
776+
}
777+
});
778+
779+
quickPick.onDidHide(() => {
780+
resolve(undefined);
781+
quickPick.dispose();
782+
});
783+
784+
quickPick.busy = true;
785+
quickPick.show();
786+
getRootItems();
787+
});
788+
}
789+
653790
export async function modifyProject(
654791
nodeOrUri: NodeBase | vscode.Uri | undefined,
655792
type: "add" | "remove"

0 commit comments

Comments
 (0)