import { getAsciiArt } from "../util/asciiArt.ts"; import { toCase } from "util/caseManagement.ts"; import { ArgParser } from "./argParser.ts"; import { colorize } from "./style.ts"; import { selectMenuInteractive } from "./selectMenu.ts"; import { TerminalBlock, TerminalLayout } from "./TerminalLayout.ts"; import { cliAlert, cliLog } from "./prompts.ts"; import type { ITool } from "../types.ts"; import { InputManager } from "./InputManager.ts"; // Register tools here (filename, no extension) const toolRegistry: [string, Promise<{ default: ITool }>][] = [ ["checkCode", import("../tools/checkCode.ts")], ["fieldRename", import("../tools/fieldRename.ts")], ["listFormFields", import("../tools/listFormFields.ts")], ["deleteFields", import("../tools/deleteFields.ts")], ["fieldVisibility", import("../tools/fieldVisibility.ts")], ]; export class PdfToolsCli { private tools: Map = new Map(); private terminalLayout = new TerminalLayout(); closeMessage?: string; private args = ArgParser.parse(Deno.args).setFlagDefs({ help: ["-h", "--help"], banana: ["-b", "--banana"], }); async importTools() { for (const [name, toolfile] of toolRegistry) { const t = await toolfile; try { if (t.default) { this.tools.set( toCase(name, "title"), t.default, ); } } catch (e) { cliLog(e + "\n", this.terminalLayout.getBlock("body")); } } } private async banana() { const asciiArt = await getAsciiArt("banana"); this.closeMessage = colorize(asciiArt, "yellow"); } private async help() { this.terminalLayout.clear(); this.ensmallenHeader("Help"); const bodyBlock = this.terminalLayout.getBlock("body"); bodyBlock.clearAll(); await cliAlert("BearMetal PDF CLI\n", bodyBlock); await this.embiggenHeader(); } public async run() { const im = InputManager.getInstance(); im.activate(); im.addEventListener("exit", () => { this.closeMessage = "Exiting..."; this.cleanup(); }); try { await this.importTools(); const titleBlock = new TerminalBlock(); this.terminalLayout.register("title", titleBlock); const bodyBlock = new TerminalBlock(); this.terminalLayout.register("body", bodyBlock); if (this.args.getFlag("banana")) { titleBlock.setFixedHeight(0); await this.banana(); return; } if (this.args.getFlag("help") && !this.args.task) { await this.help(); return; } else if (this.args.nonFlags.length === 0 || !this.args.task) { this.embiggenHeader(); await this.toolMenu(); } else { const task = this.args.task; await this.runTool(toCase(task, "title")); } } finally { this.cleanup(); Deno.exit(0); } } private cleanup() { this.terminalLayout.clearAll(); InputManager.getInstance().deactivate(); Deno.stdin.setRaw(false); if (this.closeMessage) console.log(this.closeMessage); } private async toolMenu() { const tools = this.tools.keys().toArray(); const bodyBlock = this.terminalLayout.getBlock("body"); bodyBlock.clearAll(); bodyBlock.setPreserveHistory(false); const selected = await selectMenuInteractive( "Choose a tool", tools.concat(["Help", "Exit"]), { terminalBlock: bodyBlock, }, ); if (!selected) return; if (selected === "Exit") { return; } await this.runTool(selected); await this.toolMenu(); } private async runTool(toolName: string) { if (toolName === "Help") { return await this.help(); } const tool = this.tools.get(toolName); if (tool) { this.ensmallenHeader(tool.name + " - " + tool.description); const bodyBlock = this.terminalLayout.getBlock("body"); bodyBlock.clearAll(); tool.setBlock?.(bodyBlock); if (this.args.getFlag("help")) { await tool.help?.(); } else { await tool.run(...this.args.taskArgs); await tool.done?.(); } await this.embiggenHeader(); } else { this.closeMessage = "No tool found for " + toolName; } } private ensmallenHeader(subtitle: string) { this.terminalLayout.clear(); const titleBlock = this.terminalLayout.getBlock("title"); titleBlock.clear(); titleBlock.setFixedHeight(3); titleBlock.setLines([ colorize("BearMetal PDF Tools", "porple"), colorize(subtitle, "gray"), "-=".repeat(Deno.consoleSize().columns / 2), ]); } private async embiggenHeader() { const titleBlock = this.terminalLayout.getBlock("title"); titleBlock.clear(); const lines: string[] = []; for (const t of ["bearmetal:porple", "pdftools:cyan"]) { const [name, color] = t.split(":"); const asciiArt = await getAsciiArt(name); lines.push(...colorize(asciiArt, color).split("\n")); } titleBlock.setFixedHeight(lines.length); titleBlock.setLines(lines); } }