feat: delete fields tool

fix: field rename
fix: list fields now scrolls
This commit is contained in:
2025-06-06 10:50:27 -06:00
parent 7a3b3f2161
commit 7c19ada88b
7 changed files with 117 additions and 17 deletions

50
tools/deleteFields.ts Normal file
View File

@@ -0,0 +1,50 @@
import { forceArgs } from "../cli/forceArgs.ts";
import { cliPrompt } from "../cli/prompts.ts";
import { multiSelectMenuInteractive } from "../cli/selectMenu.ts";
import { TerminalBlock } from "../cli/TerminalLayout.ts";
import type { callback, ITool } from "../types.ts";
import { loadPdf, savePdf } from "util/saveLoadPdf.ts";
import { log } from "util/logfile.ts";
export class DeleteFormFields implements ITool {
name = "deleteFormFields";
description = "delete multiple form fields from a PDF";
block?: TerminalBlock;
async run(pdfPath: string = "") {
if (!this.block) this.block = new TerminalBlock();
[pdfPath] = await forceArgs([pdfPath], [[
"Please provide path to PDF",
(d) => d?.endsWith(".pdf"),
]], this.block);
const pdf = await loadPdf(pdfPath);
const form = pdf.getForm();
const fields = form.getFields();
let updatesMade = false;
await multiSelectMenuInteractive(
`${pdfPath}\nSelect fields to delete:`,
fields.map<[string, callback]>((
f,
) => [f.getName(), () => {
while (f.acroField.getWidgets().length) {
f.acroField.removeWidget(0);
}
form.removeField(f);
updatesMade = true;
}]),
);
if (!updatesMade) return;
const path = await cliPrompt(
"Save to path (or hit enter to keep current):",
this.block,
) || pdfPath;
await savePdf(pdf, path);
}
help?: (() => Promise<void> | void) | undefined;
done?: (() => Promise<void> | void) | undefined;
setBlock(block: TerminalBlock) {
this.block = block;
}
}
export default new DeleteFormFields();

View File

@@ -404,7 +404,7 @@ class RenameFields implements ITool {
if (!this.block) {
this.block = new TerminalBlock();
}
this.block.setPreserveHistory(true);
this.block.setPreserveHistory(false);
[pdfPath, pattern, change] = await forceArgs(
[pdfPath, pattern, change],

View File

@@ -1,8 +1,8 @@
import { forceArgs } from "../cli/forceArgs.ts";
import { cliAlert } from "../cli/prompts.ts";
import { TerminalBlock } from "../cli/TerminalLayout.ts";
import { loadPdfForm } from "util/saveLoadPdf.ts";
import type { ITool } from "../types.ts";
import { InputManager } from "../cli/InputManager.ts";
export class ListFormFields implements ITool {
name = "listformfields";
@@ -12,21 +12,48 @@ export class ListFormFields implements ITool {
if (!this.block) {
this.block = new TerminalBlock();
}
this.block.setPreserveHistory(true);
this.block.setPreserveHistory(false);
[pdfPath] = await forceArgs([pdfPath], [[
"Please provide path to PDF:",
(p) => !!p && p.endsWith(".pdf"),
]], this.block);
const lines = [pdfPath];
let rLines: string[] = [];
const form = await loadPdfForm(pdfPath);
const fields = form.getFields();
const fieldNames = fields.map((f) => f.getName());
const lines = [];
for (const fieldName of fieldNames) {
lines.push(fieldName);
}
this.block.setLines(lines, [0, 1]);
await cliAlert("", this.block);
let offset = 0;
const buildRLines = () => {
rLines = fieldNames.slice(offset, this.block!.getRenderHeight());
this.block!.setLines(lines.concat(rLines), [0, 1]);
};
buildRLines();
await new Promise<void>((res) => {
const im = InputManager.getInstance();
const up = () => {
if (fieldNames.length < this.block!.getRenderHeight() - 1) return;
offset = Math.max(0, offset - 1);
buildRLines();
};
const down = () => {
if (fieldNames.length < this.block!.getRenderHeight() - 1) return;
offset = Math.min(fieldNames.length, offset + 1);
buildRLines();
};
const enter = () => {
res();
im.removeEventListener("arrow-up", up);
im.removeEventListener("arrow-down", down);
im.removeEventListener("enter", enter);
};
im.addEventListener("arrow-up", up);
im.addEventListener("arrow-down", down);
im.addEventListener("enter", enter);
});
}
setBlock(terminalBlock: TerminalBlock) {
this.block = terminalBlock;