mirror of
https://github.com/infrost/RaptorQR.git
synced 2026-08-31 23:17:57 +08:00
feat(cli): alt-buffer, top-of-screen draw, -h/--help flags
- Enter alternate screen buffer (\x1b[?1049h) before drawing and exit it (\x1b[?1049l) on cleanup. This preserves the user's terminal content when the app quits. - Clear screen once after entering alt buffer so drawing starts from the top-left. - Add -h and --help flags that print usage, stdin/file modes, and controls (q / Ctrl-C to quit). - Update tests for new alt-buffer helpers and help text. - Rebuild CLI bundle (dist/qr-terminal.js 95.4kb) and redeploy webapp.
This commit is contained in:
+43
-4
@@ -19,10 +19,40 @@ import { generateQRMatrix } from '../core/qr/qr_encode';
|
||||
import { packetize } from '../core/sender/packetizer';
|
||||
import { scheduleFrames } from '../core/sender/scheduler';
|
||||
import { QR_VERSION, ECC_LEVEL } from '../core/protocol/constants';
|
||||
import { clearScreen, hideCursor, showCursor, renderToTerminal, moveCursorUp } from './terminal_raster';
|
||||
import {
|
||||
enterAltBuffer,
|
||||
exitAltBuffer,
|
||||
clearScreen,
|
||||
hideCursor,
|
||||
showCursor,
|
||||
renderToTerminal,
|
||||
moveCursorUp,
|
||||
} from './terminal_raster';
|
||||
|
||||
const FPS_MS = 100;
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────────
|
||||
// Help text
|
||||
// ─────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
const HELP_TEXT = `
|
||||
QR Terminal Display – encode text or a file into a looping QR-code sequence.
|
||||
|
||||
Usage:
|
||||
qr-terminal [file] read from file
|
||||
echo "text" | qr-terminal read from stdin
|
||||
|
||||
Controls:
|
||||
q, Q quit
|
||||
Ctrl-C quit
|
||||
|
||||
The app uses the same V10-M QR protocol as the web transfer demo.
|
||||
`;
|
||||
|
||||
function showHelp(): void {
|
||||
console.log(HELP_TEXT.trim());
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────────
|
||||
// Argument parsing
|
||||
// ─────────────────────────────────────────────────────────────────────────────────
|
||||
@@ -62,6 +92,12 @@ function buildFrames(data: Uint8Array): Uint8Array[] {
|
||||
// ─────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
function main() {
|
||||
const args = process.argv.slice(2);
|
||||
if (args.includes('-h') || args.includes('--help')) {
|
||||
showHelp();
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
let data: Uint8Array;
|
||||
try {
|
||||
data = readInput();
|
||||
@@ -114,7 +150,6 @@ function main() {
|
||||
}
|
||||
|
||||
if (firstDraw) {
|
||||
clearScreen();
|
||||
firstDraw = false;
|
||||
} else {
|
||||
// Move cursor back to the first QR line so we overwrite in-place
|
||||
@@ -128,15 +163,19 @@ function main() {
|
||||
function cleanup() {
|
||||
running = false;
|
||||
clearInterval(interval);
|
||||
clearScreen();
|
||||
exitAltBuffer();
|
||||
showCursor();
|
||||
if (ttyFd !== null) {
|
||||
try { closeSync(ttyFd); } catch {}
|
||||
}
|
||||
process.stdout.write('QR terminal display stopped.\n');
|
||||
console.log('QR terminal display stopped.');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Switch to alternate buffer and clear it before drawing
|
||||
enterAltBuffer();
|
||||
clearScreen();
|
||||
|
||||
// Keyboard handling — try /dev/tty first so it works even when stdin is a pipe
|
||||
let ttyFd: number | null = null;
|
||||
try {
|
||||
|
||||
@@ -65,6 +65,20 @@ export function renderToTerminal(matrix: boolean[][], quietZone: number = 4): st
|
||||
return lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enter the alternate screen buffer (preserves normal buffer on exit).
|
||||
*/
|
||||
export function enterAltBuffer(): void {
|
||||
process.stdout.write('\x1b[?1049h');
|
||||
}
|
||||
|
||||
/**
|
||||
* Exit the alternate screen buffer and restore the normal buffer.
|
||||
*/
|
||||
export function exitAltBuffer(): void {
|
||||
process.stdout.write('\x1b[?1049l');
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the terminal screen and move cursor to home position.
|
||||
*/
|
||||
|
||||
@@ -148,15 +148,41 @@ describe('Terminal Rasterizer', () => {
|
||||
});
|
||||
|
||||
describe('CLI Screen Helpers', () => {
|
||||
it('should produce escape sequences', async () => {
|
||||
it('should expose clearScreen', async () => {
|
||||
const { clearScreen } = await import('@/cli/terminal_raster');
|
||||
expect(typeof clearScreen).toBe('function');
|
||||
});
|
||||
|
||||
it('should produce cursor-up sequence', async () => {
|
||||
it('should expose moveCursorUp', async () => {
|
||||
const { moveCursorUp } = await import('@/cli/terminal_raster');
|
||||
expect(typeof moveCursorUp).toBe('function');
|
||||
});
|
||||
|
||||
it('should expose alt-buffer helpers', async () => {
|
||||
const { enterAltBuffer, exitAltBuffer } = await import('@/cli/terminal_raster');
|
||||
expect(typeof enterAltBuffer).toBe('function');
|
||||
expect(typeof exitAltBuffer).toBe('function');
|
||||
});
|
||||
});
|
||||
|
||||
describe('CLI Help Flag', () => {
|
||||
it('should not throw when help text is constructed', () => {
|
||||
const helpText = `
|
||||
QR Terminal Display – encode text or a file into a looping QR-code sequence.
|
||||
|
||||
Usage:
|
||||
qr-terminal [file] read from file
|
||||
echo "text" | qr-terminal read from stdin
|
||||
|
||||
Controls:
|
||||
q, Q quit
|
||||
Ctrl-C quit
|
||||
|
||||
The app uses the same V10-M QR protocol as the web transfer demo.
|
||||
`;
|
||||
expect(helpText).toContain('Usage:');
|
||||
expect(helpText).toContain('quit');
|
||||
});
|
||||
});
|
||||
|
||||
describe('CLI Encoder Pipeline', () => {
|
||||
|
||||
Reference in New Issue
Block a user