UNPKG

open-linux-file-dialog

Version:

Open a file dialog window programmatically to allow the user to select one or more files. Only works on Linux. No dependencies. Supports zenity (GNOME), kdialog (KDE), yad (Yet Another Dialog), qarma (Qt-based), matedialog (MATE), rofi (window switcher wi

327 lines (326 loc) 11.7 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // index.ts var index_exports = {}; __export(index_exports, { default: () => index_default, getAvailableDialogTools: () => getAvailableDialogTools, openLinuxFileDialog: () => openLinuxFileDialog }); module.exports = __toCommonJS(index_exports); var import_node_child_process = __toESM(require("child_process")); var import_node_path = __toESM(require("path")); var import_node_util = __toESM(require("util")); var execAsync = import_node_util.default.promisify(import_node_child_process.default.exec); var FileDialogError = class extends Error { static { __name(this, "FileDialogError"); } constructor(message) { super(message); this.name = "FileDialogError"; } }; var escapeShellArg = /* @__PURE__ */ __name((arg) => { return `'${arg.replace(/'/g, "'\\''")}'`; }, "escapeShellArg"); var checkCommand = /* @__PURE__ */ __name(async (command) => { try { const { stdout } = await execAsync(`command -v ${command}`); return Boolean(stdout.trim()); } catch { return false; } }, "checkCommand"); var zenityTool = { name: "zenity", check: /* @__PURE__ */ __name(() => checkCommand("zenity"), "check"), buildCommand: /* @__PURE__ */ __name((initialDirectory, options) => { const args = ["zenity", "--file-selection"]; if (options.multiple) { args.push("--multiple", "--separator=\\n"); } if (options.title) { args.push("--title", escapeShellArg(options.title)); } if (options.fileTypes && options.fileTypes.length > 0) { for (const type of options.fileTypes) { args.push("--file-filter", escapeShellArg(type)); } } args.push("--filename", escapeShellArg(`${initialDirectory}${import_node_path.default.sep}`)); return args; }, "buildCommand") }; var kdialogTool = { name: "kdialog", check: /* @__PURE__ */ __name(() => checkCommand("kdialog"), "check"), buildCommand: /* @__PURE__ */ __name((initialDirectory, options) => { const args = ["kdialog"]; if (options.multiple) { args.push("--getopenfilenames"); } else { args.push("--getopenfilename"); } args.push(escapeShellArg(initialDirectory)); if (options.fileTypes && options.fileTypes.length > 0) { args.push(escapeShellArg(options.fileTypes.join(" "))); } if (options.title) { args.push("--title", escapeShellArg(options.title)); } return args; }, "buildCommand") }; var yad = { name: "yad", check: /* @__PURE__ */ __name(() => checkCommand("yad"), "check"), buildCommand: /* @__PURE__ */ __name((initialDirectory, options) => { const args = ["yad", "--file-selection"]; if (options.multiple) { args.push("--multiple", "--separator=\\n"); } if (options.title) { args.push("--title", escapeShellArg(options.title)); } if (options.fileTypes && options.fileTypes.length > 0) { for (const type of options.fileTypes) { args.push("--file-filter", escapeShellArg(type)); } } args.push("--filename", escapeShellArg(`${initialDirectory}${import_node_path.default.sep}`)); return args; }, "buildCommand") }; var qarma = { name: "qarma", check: /* @__PURE__ */ __name(() => checkCommand("qarma"), "check"), buildCommand: /* @__PURE__ */ __name((initialDirectory, options) => { const args = ["qarma", "--file-selection"]; if (options.multiple) { args.push("--multiple", "--separator=\\n"); } if (options.title) { args.push("--title", escapeShellArg(options.title)); } if (options.fileTypes && options.fileTypes.length > 0) { for (const type of options.fileTypes) { args.push("--file-filter", escapeShellArg(type)); } } args.push("--filename", escapeShellArg(`${initialDirectory}${import_node_path.default.sep}`)); return args; }, "buildCommand") }; var matedialog = { name: "matedialog", check: /* @__PURE__ */ __name(() => checkCommand("matedialog"), "check"), buildCommand: /* @__PURE__ */ __name((initialDirectory, options) => { const args = ["matedialog", "--file-selection"]; if (options.multiple) { args.push("--multiple", "--separator=\\n"); } if (options.title) { args.push("--title", escapeShellArg(options.title)); } args.push("--filename", escapeShellArg(`${initialDirectory}${import_node_path.default.sep}`)); return args; }, "buildCommand") }; var osascript = { name: "osascript", check: /* @__PURE__ */ __name(async () => { try { const { stdout } = await execAsync("uname -s"); return stdout.trim() === "Darwin" && await checkCommand("osascript"); } catch { return false; } }, "check"), buildCommand: /* @__PURE__ */ __name((initialDirectory, options) => { let script = 'tell application "System Events" to activate\n'; if (options.multiple) { script += `set theFiles to choose file with prompt "${options.title || "Select files"}" `; script += `default location POSIX file "${initialDirectory}" `; script += "with multiple selections allowed\n"; script += 'set output to ""\n'; script += "repeat with aFile in theFiles\n"; script += 'set output to output & POSIX path of aFile & "\n"\n'; script += "end repeat\n"; script += "return output"; } else { script += `set theFile to choose file with prompt "${options.title || "Select a file"}" `; script += `default location POSIX file "${initialDirectory}" `; script += "return POSIX path of theFile"; } return ["osascript", "-e", escapeShellArg(script)]; }, "buildCommand"), parseOutput: /* @__PURE__ */ __name((output) => { return output.trim().split("\n").filter(Boolean); }, "parseOutput") }; var rofi = { name: "rofi", check: /* @__PURE__ */ __name(() => checkCommand("rofi"), "check"), buildCommand: /* @__PURE__ */ __name((initialDirectory, options) => { const args = [ "bash", "-c", escapeShellArg( `cd ${escapeShellArg(initialDirectory)} && find . -type f | rofi -dmenu -p "${options.title || "Select file"}" -multi-select` ) ]; return args; }, "buildCommand"), parseOutput: /* @__PURE__ */ __name((output) => { return output.trim().split("\n").filter(Boolean).map((p) => { if (p.startsWith("./")) { return import_node_path.default.resolve(p); } return p; }); }, "parseOutput") }; var dmenu = { name: "dmenu", check: /* @__PURE__ */ __name(() => checkCommand("dmenu"), "check"), buildCommand: /* @__PURE__ */ __name((initialDirectory, options) => { const args = [ "bash", "-c", escapeShellArg( `cd ${escapeShellArg(initialDirectory)} && find . -type f | dmenu -p "${options.title || "Select file"}"` ) ]; return args; }, "buildCommand"), parseOutput: /* @__PURE__ */ __name((output) => { const selected = output.trim(); if (!selected) return []; if (selected.startsWith("./")) { return [import_node_path.default.resolve(selected)]; } return [selected]; }, "parseOutput") }; var fzf = { name: "fzf", check: /* @__PURE__ */ __name(() => checkCommand("fzf"), "check"), buildCommand: /* @__PURE__ */ __name((initialDirectory, options) => { const fzfOpts = ["--prompt", `"${options.title || "Select file"}> "`]; if (options.multiple) { fzfOpts.push("-m"); } const args = [ "bash", "-c", escapeShellArg(`cd ${escapeShellArg(initialDirectory)} && find . -type f | fzf ${fzfOpts.join(" ")}`) ]; return args; }, "buildCommand"), parseOutput: /* @__PURE__ */ __name((output) => { return output.trim().split("\n").filter(Boolean).map((p) => { if (p.startsWith("./")) { return import_node_path.default.resolve(p); } return p; }); }, "parseOutput") }; var tools = [zenityTool, kdialogTool, yad, qarma, matedialog, osascript, rofi, fzf, dmenu]; var openLinuxFileDialog = /* @__PURE__ */ __name(async (initialDirectory = process.cwd(), options = {}) => { if (typeof initialDirectory !== "string") { throw new FileDialogError("Filepath must be a string"); } const normalizedPath = import_node_path.default.resolve(initialDirectory); let availableTool = null; for (const tool of tools) { if (await tool.check()) { availableTool = tool; break; } } if (!availableTool) { throw new FileDialogError( "No suitable file dialog tool found. Please install one of: zenity, kdialog, yad, qarma, matedialog, rofi, fzf, or dmenu." ); } const commandArgs = availableTool.buildCommand(normalizedPath, options); const command = commandArgs.join(" "); try { const { stdout, stderr } = await execAsync(command, { shell: "/bin/bash", maxBuffer: 10 * 1024 * 1024 // 10MB buffer for large file selections }); if (stderr && !stderr.includes("Gtk-WARNING")) { console.warn(`File dialog warning: ${stderr}`); } const output = stdout.trim(); if (!output) { return []; } let filePaths; if (availableTool.parseOutput) { filePaths = availableTool.parseOutput(output); } else { filePaths = output.split("\n").filter(Boolean); } const validPaths = filePaths.filter((p) => import_node_path.default.isAbsolute(p)); if (validPaths.length !== filePaths.length) { console.warn("Some file paths were not absolute and were filtered out"); } return validPaths; } catch (error) { if (error instanceof Error && "code" in error && error.code === 1) { return []; } throw new FileDialogError( `Failed to open file dialog with ${availableTool.name}: ${error instanceof Error ? error.message : "Unknown error"}` ); } }, "openLinuxFileDialog"); var getAvailableDialogTools = /* @__PURE__ */ __name(async () => { const available = []; for (const tool of tools) { if (await tool.check()) { available.push(tool.name); } } return available; }, "getAvailableDialogTools"); var index_default = openLinuxFileDialog; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { getAvailableDialogTools, openLinuxFileDialog }); //# sourceMappingURL=index.js.map