open-finder-dialog
Version:
Open a finder dialog window (finder prompt) programmatically. Only works on MacOS.
100 lines (92 loc) • 3.54 kB
JavaScript
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
// index.ts
import cp from "node:child_process";
import { detectTerminal } from "detect-terminal";
var escapeQuotedPath = /* @__PURE__ */ __name((input) => {
return input.replace(/(?<!\\(?<!\\))"/g, "\\$&");
}, "escapeQuotedPath");
var isCanceled = /* @__PURE__ */ __name((v) => /cancell?ed/i.test(v), "isCanceled");
var buildCommand = /* @__PURE__ */ __name((allowMultiple, filters) => {
const base = "choose file";
const withPrompt = ' with prompt "Select files to open"';
const ofType = filters.length > 0 ? ` of type {${filters.map((f) => `"${f}"`).join(", ")}}` : "";
const multi = allowMultiple ? " with multiple selections allowed" : "";
return base + withPrompt + ofType + multi;
}, "buildCommand");
var openFinderDialog = /* @__PURE__ */ __name(async (initialDirectory = process.cwd(), options = {}) => {
return new Promise((resolve, reject) => {
const { filters = [], terminal = detectTerminal(), limit = 100 } = options;
const maxFiles = Math.max(1, limit);
const command = buildCommand(limit > 1, filters);
const escapedPath = escapeQuotedPath(initialDirectory);
const pathSeparator = "<__PATH_SEPARATOR__>";
const appleScript = `
set defaultPath to POSIX file "${escapedPath}"
set limit to ${maxFiles}
try
-- Open the file dialog within SystemUIServer to bring it to focus
tell application "SystemUIServer"
activate
delay 0.2 -- Allow SystemUIServer to activate
set file_list to ${command} default location defaultPath
if limit = 1 then
set file_list to {file_list}
end if
end tell
-- Apply the maximum-files rule
if limit > 0 and (count of file_list) > limit then
set file_list to items 1 thru limit of file_list
end if
-- Process the selected files
set posixPaths to {}
repeat with aFile in file_list
set end of posixPaths to POSIX path of aFile & "${pathSeparator}"
end repeat
-- Return focus to ${terminal}
tell application "${terminal}"
activate
end tell
set text item delimiters to ""
set posixPathsString to posixPaths as string
return posixPathsString
on error
-- Return focus to terminal app even if the dialog is canceled
tell application "${terminal}"
activate
end tell
return "CANCELLED"
end try
`;
const child = cp.spawn("osascript", ["-"]);
let stdoutData = "";
let stderrData = "";
child.stdout.on("data", (data) => {
stdoutData += data.toString();
});
child.stderr.on("data", (data) => {
stderrData += data.toString();
});
child.on("close", (code) => {
if (code !== 0 && stderrData) {
reject(new Error(stderrData.trim()));
return;
}
const output = stdoutData.trim();
if (isCanceled(output)) {
resolve({ files: [], canceled: true });
return;
}
const files = output.split(pathSeparator).map((s) => s.trim()).filter((s) => s !== "");
resolve({ files, canceled: false });
});
child.stdin.write(appleScript);
child.stdin.end();
});
}, "openFinderDialog");
var open_finder_dialog_default = openFinderDialog;
export {
open_finder_dialog_default as default,
openFinderDialog
};
//# sourceMappingURL=index.mjs.map