Skip to content

Commit 6f489c1

Browse files
committed
Update Open InterSystems Document... command to show a flat list of documents
1 parent 87a82ee commit 6f489c1

1 file changed

Lines changed: 74 additions & 136 deletions

File tree

src/utils/documentPicker.ts

Lines changed: 74 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -53,31 +53,23 @@ function createMultiSelectItem(
5353
return result;
5454
}
5555

56-
function createSingleSelectItem(
57-
item: { Name: string; Type: number },
58-
parent?: string,
59-
delimiter?: string
60-
): DocumentPickerItem {
61-
const result: DocumentPickerItem = { label: item.Name, fullName: item.Name };
62-
// Add the icon
56+
function createSingleSelectItem(item: { Name: string; Type: number }): vscode.QuickPickItem {
57+
// Determine the icon
58+
let icon = "$(symbol-file)";
6359
if (item.Type == 0) {
6460
if (item.Name.endsWith(".inc")) {
65-
result.label = "$(file-symlink-file) " + result.label;
61+
icon = "$(file-symlink-file)";
6662
} else if (item.Name.endsWith(".int") || item.Name.endsWith(".mac")) {
67-
result.label = "$(note) " + result.label;
63+
icon = "$(note)";
6864
} else {
69-
result.label = "$(symbol-misc) " + result.label;
65+
icon = "$(symbol-misc)";
7066
}
7167
} else if (item.Type == 4) {
72-
result.label = "$(symbol-class) " + result.label;
73-
} else if (![9, 10].includes(item.Type)) {
74-
result.label = "$(symbol-file) " + result.label;
75-
}
76-
if (parent) {
77-
// Update the full name if this is a nested item
78-
result.fullName = parent + delimiter + item.Name;
68+
icon = "$(symbol-class)";
69+
} else {
70+
icon = "$(symbol-file)";
7971
}
80-
return result;
72+
return { label: `${icon} ${item.Name}` };
8173
}
8274

8375
/**
@@ -300,19 +292,12 @@ export async function pickDocument(
300292
let sys: "0" | "1" = "0";
301293
let gen: "0" | "1" = "0";
302294
let map: "0" | "1" = "1";
303-
const query = "SELECT Name, Type FROM %Library.RoutineMgr_StudioOpenDialog(?,1,1,?,0,0,?,,0,?)";
304-
const webApps = (typeSuffix ?? "csp") == "csp" ? cspAppsForApi(api) : [];
305-
const webAppRootItems = webApps.map((app: string) => {
306-
return {
307-
label: app,
308-
fullName: app,
309-
};
310-
});
295+
const query = "SELECT Name, Type FROM %Library.RoutineMgr_StudioOpenDialog(?,1,1,?,1,0,?,,0,?)";
311296

312297
return new Promise<string>((resolve) => {
313-
const quickPick = vscode.window.createQuickPick<DocumentPickerItem>();
298+
const quickPick = vscode.window.createQuickPick();
314299
quickPick.prompt =
315-
"Select a package or folder to view its contents. Selecting '..' shows the previous level's contents. You may also type a full document name into the filter box and press 'Enter' to select that document.";
300+
"You may also type a full document name with extension into the filter box and press 'Enter' to select it.";
316301
quickPick.title = `${prompt ? prompt : "Select a document"} ${numberOfSteps ? `(${step}/${numberOfSteps})` : `in namespace '${api.ns}' on server '${api.serverId}'`}`;
317302
quickPick.ignoreFocusOut = true;
318303
quickPick.buttons = [
@@ -337,32 +322,14 @@ export async function pickDocument(
337322
},
338323
];
339324

340-
const getRootItems = (): Promise<void> => {
325+
const getItems = (): Promise<void> => {
326+
quickPick.busy = true;
341327
return api
342-
.actionQuery(`${query} WHERE Type != 5 AND Type != 10`, [
343-
typeSuffix ? `*.${typeSuffix}` : "*,'*.prj",
344-
sys,
345-
gen,
346-
map,
347-
])
328+
.actionQuery(query, [typeSuffix ? `*.${typeSuffix}` : "*,'*.prj,'*.bpl,'*.dtl", sys, gen, map])
348329
.then((data) => {
349-
const rootitems: DocumentPickerItem[] = data.result.content.map((i) => createSingleSelectItem(i));
350-
const findLastIndex = (): number => {
351-
let l = rootitems.length;
352-
while (l--) {
353-
if (!rootitems[l].label.startsWith("$(")) return l;
354-
}
355-
return -1;
356-
};
357-
rootitems.splice(findLastIndex() + 1, 0, ...webAppRootItems);
358-
return rootitems;
359-
})
360-
.then((items) => {
361-
quickPick.items = items;
330+
quickPick.items = data.result.content.map((i) => createSingleSelectItem(i));
362331
quickPick.selectedItems = [];
363-
quickPick.value = "";
364332
quickPick.busy = false;
365-
quickPick.enabled = true;
366333
})
367334
.catch((error) => {
368335
quickPick.hide();
@@ -371,8 +338,6 @@ export async function pickDocument(
371338
};
372339

373340
quickPick.onDidTriggerButton((button) => {
374-
quickPick.busy = true;
375-
quickPick.enabled = false;
376341
if (button === vscode.QuickInputButtons.Back) {
377342
resolve(""); // signal "go back" to the caller
378343
quickPick.hide();
@@ -385,108 +350,81 @@ export async function pickDocument(
385350
map = button.toggle.checked ? "1" : "0";
386351
}
387352
// Refresh the items list
388-
getRootItems();
353+
getItems();
389354
});
390355
quickPick.onDidAccept(() => {
391356
quickPick.busy = true;
392357
quickPick.enabled = false;
393358
const item = quickPick.selectedItems[0];
394-
if (!item || item.label.startsWith("$(")) {
395-
let doc = item?.fullName ?? quickPick.value.trim();
396-
if (!item) {
397-
// The document name came from the value text, so validate it first
398-
// Normalize the file extension case for classes and routines
399-
doc = [".cls", ".mac", ".int", ".inc"].includes(doc.slice(-4).toLowerCase())
400-
? doc.slice(0, -3) + doc.slice(-3).toLowerCase()
401-
: doc;
402-
// Expand the short form of %Library classes to the long form
403-
doc =
404-
doc.startsWith("%") && doc.split(".").length == 2 && doc.slice(-4) == ".cls"
405-
? `%Library.${doc.slice(1)}`
406-
: doc;
407-
if (doc.endsWith(".cls")) {
408-
// Use StudioOpenDialog for classes so we don't expose Hidden ones
409-
api
410-
.actionQuery("SELECT Name, Type FROM %Library.RoutineMgr_StudioOpenDialog(?,1,1,1,1,0,1,,0,1)", [doc])
411-
.then((data) => {
412-
if (data.result.content?.length) {
413-
// doc is the name of a class that exists and is visible by the user
414-
resolve(doc);
415-
} else {
416-
vscode.window.showErrorMessage(
417-
`Class '${doc.slice(0, -4)}' does not exist, or is Hidden.`,
418-
"Dismiss"
419-
);
420-
resolve(undefined);
421-
}
422-
})
423-
.catch(() => {
424-
vscode.window.showErrorMessage(
425-
`Internal Server Error encountered trying to validate class name '${doc.slice(0, -4)}'.`,
426-
"Dismiss"
427-
);
428-
resolve(undefined);
429-
})
430-
.finally(() => quickPick.hide());
431-
} else {
432-
api
433-
.headDoc(doc)
434-
.then(() => resolve(doc))
435-
.catch((error) => {
436-
vscode.window.showErrorMessage(
437-
error?.statusCode == 400
438-
? `'${doc}' is an invalid document name.`
439-
: error?.statusCode == 404
440-
? `Document '${doc}' does not exist.`
441-
: `Internal Server Error encountered trying to validate document '${doc}'.`,
442-
"Dismiss"
443-
);
444-
resolve(undefined);
445-
})
446-
.finally(() => quickPick.hide());
447-
}
448-
} else {
449-
// The document name came from an item so no validation is required
450-
resolve(doc);
451-
quickPick.hide();
359+
let doc = item?.label.slice(item?.label.indexOf(" ") + 1) ?? quickPick.value.trim();
360+
if (!item) {
361+
if (typeSuffix && !new RegExp(`\\.${typeSuffix}$`, "i").test(doc)) {
362+
// The text the user entered does not match the required type
363+
vscode.window.showErrorMessage(
364+
`Selected document '${doc}' does not have required extension '${typeSuffix}'.`,
365+
"Dismiss"
366+
);
367+
resolve(undefined);
452368
}
453-
} else {
454-
// Replace the items with the folder's contents
455-
if (item.fullName == "") {
456-
getRootItems();
457-
} else {
369+
// The document name came from the value text, so validate it first
370+
// Normalize the file extension case for classes and routines
371+
doc = [".cls", ".mac", ".int", ".inc"].includes(doc.slice(-4).toLowerCase())
372+
? doc.slice(0, -3) + doc.slice(-3).toLowerCase()
373+
: doc;
374+
// Expand the short form of %Library classes to the long form
375+
doc =
376+
doc.startsWith("%") && doc.split(".").length == 2 && doc.slice(-4) == ".cls"
377+
? `%Library.${doc.slice(1)}`
378+
: doc;
379+
if (doc.endsWith(".cls")) {
380+
// Use StudioOpenDialog for classes so we don't expose Hidden ones
458381
api
459-
.actionQuery(query, [`${item.fullName}/*${typeSuffix ? `.${typeSuffix}` : ""}`, sys, gen, map])
382+
.actionQuery("SELECT Name, Type FROM %Library.RoutineMgr_StudioOpenDialog(?,1,1,1,1,0,1,,0,1)", [doc])
460383
.then((data) => {
461-
const delim = item.fullName.includes("/") ? "/" : ".";
462-
const newItems: DocumentPickerItem[] = data.result.content.map((i) =>
463-
createSingleSelectItem(i, item.fullName, delim)
384+
if (data.result.content?.length) {
385+
// doc is the name of a class that exists and is visible by the user
386+
resolve(doc);
387+
} else {
388+
vscode.window.showErrorMessage(`Class '${doc.slice(0, -4)}' does not exist, or is Hidden.`, "Dismiss");
389+
resolve(undefined);
390+
}
391+
})
392+
.catch(() => {
393+
vscode.window.showErrorMessage(
394+
`Internal Server Error encountered trying to validate class name '${doc.slice(0, -4)}'.`,
395+
"Dismiss"
464396
);
465-
let parentFullName =
466-
delim == "/" && webApps.includes(item.fullName)
467-
? ""
468-
: item.fullName.split(delim).slice(0, -1).join(delim);
469-
if (parentFullName == "/") parentFullName = "";
470-
quickPick.items = [{ label: "..", fullName: parentFullName }].concat(newItems);
471-
quickPick.value = "";
472-
quickPick.selectedItems = [];
473-
quickPick.busy = false;
474-
quickPick.enabled = true;
397+
resolve(undefined);
475398
})
399+
.finally(() => quickPick.hide());
400+
} else {
401+
api
402+
.headDoc(doc)
403+
.then(() => resolve(doc))
476404
.catch((error) => {
477-
quickPick.hide();
478-
handleError(error, "Failed to get namespace contents.");
479-
});
405+
vscode.window.showErrorMessage(
406+
error?.statusCode == 400
407+
? `'${doc}' is an invalid document name.`
408+
: error?.statusCode == 404
409+
? `Document '${doc}' does not exist.`
410+
: `Internal Server Error encountered trying to validate document '${doc}'.`,
411+
"Dismiss"
412+
);
413+
resolve(undefined);
414+
})
415+
.finally(() => quickPick.hide());
480416
}
417+
} else {
418+
// The document name came from an item so no validation is required
419+
resolve(doc);
420+
quickPick.hide();
481421
}
482422
});
483423
quickPick.onDidHide(() => {
484424
resolve(undefined);
485425
quickPick.dispose();
486426
});
487-
quickPick.busy = true;
488-
quickPick.enabled = false;
489427
quickPick.show();
490-
getRootItems();
428+
getItems();
491429
});
492430
}

0 commit comments

Comments
 (0)