Compare commits
3 Commits
da80c4690b
...
c0ce69af6f
Author | SHA1 | Date | |
---|---|---|---|
c0ce69af6f | |||
041129dc83 | |||
89a3df17e6 |
@ -44,7 +44,9 @@ export class TerminalLayout {
|
||||
clearTimeout(this.debounceTimer);
|
||||
}
|
||||
this.debounceTimer = setTimeout(
|
||||
() => this.renderLayout(),
|
||||
() => {
|
||||
this.renderLayout();
|
||||
},
|
||||
this.debounceDelay,
|
||||
);
|
||||
}
|
||||
@ -76,6 +78,10 @@ export class TerminalLayout {
|
||||
block.renderInternal(usedLines + 1);
|
||||
usedLines += lines.length;
|
||||
}
|
||||
for (const name of this.layoutOrder) {
|
||||
const block = this.blocks[name];
|
||||
block.runPostRenderAction?.();
|
||||
}
|
||||
}
|
||||
|
||||
clearAll() {
|
||||
@ -217,7 +223,9 @@ export class TerminalBlock {
|
||||
const baseRow = startRow ?? this.lastRenderRow;
|
||||
const excessLines = this.renderHeight - this.renderLines.length;
|
||||
for (let i = 0; i < excessLines; i++) {
|
||||
const moveToLine = `[${baseRow + this.renderLines.length + i};1H[2K`;
|
||||
const moveToLine = `\x1b[${
|
||||
baseRow + this.renderLines.length + i
|
||||
};1H\x1b[2K`;
|
||||
Deno.stdout.writeSync(new TextEncoder().encode(moveToLine));
|
||||
}
|
||||
|
||||
@ -254,6 +262,17 @@ export class TerminalBlock {
|
||||
return this.fixedHeight ?? 0;
|
||||
}
|
||||
|
||||
private _postRenderAction?: () => void;
|
||||
setPostRenderAction(action: (this: TerminalBlock) => void) {
|
||||
this._postRenderAction = action;
|
||||
}
|
||||
runPostRenderAction() {
|
||||
if (this._postRenderAction) {
|
||||
this._postRenderAction.call(this);
|
||||
this._postRenderAction = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
get lineCount() {
|
||||
return this.renderLines.length;
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
// deno-lint-disable-must-await-calls
|
||||
import { log } from "util/logfile.ts";
|
||||
import { Cursor } from "./cursor.ts";
|
||||
import { colorize } from "./style.ts";
|
||||
import { TerminalBlock, TerminalLayout } from "./TerminalLayout.ts";
|
||||
@ -9,6 +10,7 @@ export async function cliPrompt(
|
||||
): Promise<string> {
|
||||
const encoder = new TextEncoder();
|
||||
const input: string[] = [];
|
||||
let cursorPos = 0;
|
||||
|
||||
await Deno.stdin.setRaw(true);
|
||||
|
||||
@ -22,33 +24,61 @@ export async function cliPrompt(
|
||||
Deno.stdout.writeSync(encoder.encode(message + " "));
|
||||
}
|
||||
|
||||
const buf = new Uint8Array(1);
|
||||
const render = () => {
|
||||
const line = message + " " + input.join("");
|
||||
const moveTo = `\x1b[${message.length + 2 + cursorPos}G`;
|
||||
|
||||
if (block) {
|
||||
block.setPostRenderAction(function () {
|
||||
Deno.stdout.writeSync(
|
||||
encoder.encode(`\x1b[${this["lastRenderRow"]};1H`),
|
||||
);
|
||||
Deno.stdout.writeSync(encoder.encode(moveTo));
|
||||
});
|
||||
range = block.setLines([line], range);
|
||||
} else {
|
||||
Deno.stdout.writeSync(encoder.encode("\x1b[K" + line + moveTo));
|
||||
}
|
||||
};
|
||||
|
||||
render();
|
||||
|
||||
const buf = new Uint8Array(6); // 6 bytes is enough for all the keys
|
||||
while (true) {
|
||||
const n = await Deno.stdin.read(buf);
|
||||
if (n === null) break;
|
||||
const byte = buf[0];
|
||||
const [a, b, c] = buf;
|
||||
|
||||
if (byte === 3) { // Ctrl+C
|
||||
Deno.stdin.setRaw(false);
|
||||
block?.["layout"]?.clearAll();
|
||||
if (a === 3) { // Ctrl+C
|
||||
block?.clear();
|
||||
block?.["layout"]?.clearAll();
|
||||
Deno.stdin.setRaw(false);
|
||||
Deno.exit(130);
|
||||
}
|
||||
|
||||
if (byte === 13) { // Enter
|
||||
if (a === 13) { // Enter
|
||||
break;
|
||||
} else if (byte === 127 || byte === 8) { // Backspace
|
||||
input.pop();
|
||||
} else if (byte >= 32 && byte <= 126) { // Printable chars
|
||||
input.push(String.fromCharCode(byte));
|
||||
} else if (a === 127 || a === 8) { // Backspace
|
||||
if (cursorPos > 0) {
|
||||
input.splice(cursorPos - 1, 1);
|
||||
cursorPos--;
|
||||
}
|
||||
} else if (a === 46) { // Delete
|
||||
if (cursorPos < input.length) {
|
||||
input.splice(cursorPos, 1);
|
||||
}
|
||||
} else if (a === 27 && b === 91) { // Arrow keys
|
||||
if (c === 51 && cursorPos < input.length) { // delete
|
||||
input.splice(cursorPos, 1);
|
||||
}
|
||||
if (c === 68 && cursorPos > 0) cursorPos--; // Left
|
||||
if (c === 67 && cursorPos < input.length) cursorPos++; // Right
|
||||
} else if (a >= 32 && a <= 126) { // Printable ASCII
|
||||
input.splice(cursorPos, 0, String.fromCharCode(a));
|
||||
cursorPos++;
|
||||
}
|
||||
|
||||
const line = message + " " + input.join("");
|
||||
if (block) {
|
||||
range = block.setLines([line], range);
|
||||
} else {
|
||||
Deno.stdout.writeSync(encoder.encode("\r\x1b[K" + line));
|
||||
}
|
||||
render();
|
||||
}
|
||||
|
||||
await Deno.stdin.setRaw(false);
|
||||
@ -92,13 +122,18 @@ if (import.meta.main) {
|
||||
const layout = new TerminalLayout();
|
||||
const title = new TerminalBlock();
|
||||
const block = new TerminalBlock();
|
||||
const footer = new TerminalBlock();
|
||||
block.setPreserveHistory(true);
|
||||
// ScrollManager.enable(block);
|
||||
title.setLines(["Hello, World!"]);
|
||||
title.setFixedHeight(1);
|
||||
|
||||
footer.setLines(["Press Ctrl+C to exit"]);
|
||||
footer.setFixedHeight(1);
|
||||
|
||||
layout.register("title", title);
|
||||
layout.register("block", block);
|
||||
layout.register("footer", footer);
|
||||
|
||||
Deno.addSignalListener("SIGINT", () => {
|
||||
layout.clearAll();
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@bearmetal/pdf-tools",
|
||||
"version": "1.0.3",
|
||||
"version": "1.0.4",
|
||||
"license": "GPL 3.0",
|
||||
"tasks": {
|
||||
"dev": "deno run -A --env-file=.env main.ts",
|
||||
|
@ -153,6 +153,7 @@ class RenameFields implements ITool {
|
||||
const fields = form.getFields();
|
||||
|
||||
const foundUpdates: [string, callback][] = [];
|
||||
let changesMade = false;
|
||||
|
||||
for (const field of fields) {
|
||||
const name = field.getName();
|
||||
@ -164,6 +165,7 @@ class RenameFields implements ITool {
|
||||
`${colorize(name, "red")} -> ${colorize(preview, "green")}`,
|
||||
() => {
|
||||
applyRename(field, name, patternRegex, toChange);
|
||||
changesMade = true;
|
||||
},
|
||||
]);
|
||||
}
|
||||
@ -178,11 +180,15 @@ class RenameFields implements ITool {
|
||||
);
|
||||
}
|
||||
|
||||
const path = await cliPrompt(
|
||||
"Save to path (or hit enter to keep current):",
|
||||
this.block,
|
||||
);
|
||||
await savePdf(pdf, path || pdfPath);
|
||||
if (changesMade) {
|
||||
const path = await cliPrompt(
|
||||
"Save to path (or hit enter to keep current):",
|
||||
this.block,
|
||||
);
|
||||
await savePdf(pdf, path || pdfPath);
|
||||
} else {
|
||||
cliLog("No changes made, skipping", this.block);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user