UNPKG

@muxik/md-viewer

Version:

A CLI tool for rendering Markdown files with syntax highlighting and pagination, optimized for AI output content display

162 lines 6.72 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Pager = void 0; const readline_1 = require("readline"); const process_1 = require("process"); const chalk_1 = __importDefault(require("chalk")); class Pager { constructor(lines, options) { this.currentLine = 0; this.lines = lines; this.theme = options.theme; this.title = options.title; this.showLineNumbers = options.showLineNumbers || false; this.terminalHeight = process.stdout.rows || 24; this.terminalWidth = process.stdout.columns || 80; this.rl = (0, readline_1.createInterface)({ input: process_1.stdin, output: process_1.stdout, terminal: true }); } async show() { return new Promise((resolve) => { this.setupTerminal(); this.render(); this.rl.input.setRawMode(true); this.rl.input.resume(); this.rl.input.on('keypress', (str, key) => { this.handleKeyPress(key, resolve); }); }); } setupTerminal() { process.stdout.write('\x1B[?1049h'); process.stdout.write('\x1B[2J'); process.stdout.write('\x1B[H'); process.on('SIGWINCH', () => { this.terminalHeight = process.stdout.rows || 24; this.terminalWidth = process.stdout.columns || 80; this.render(); }); } render() { const contentHeight = this.terminalHeight - 2; const visibleLines = this.lines.slice(this.currentLine, this.currentLine + contentHeight); process.stdout.write('\x1B[2J'); process.stdout.write('\x1B[H'); this.renderHeader(); this.renderContent(visibleLines); this.renderFooter(); } renderHeader() { const headerBg = this.theme.colors.accent; const headerText = this.theme.colors.background; let header = this.title || 'mdview'; if (header.length > this.terminalWidth - 4) { header = header.substring(0, this.terminalWidth - 7) + '...'; } const padding = this.terminalWidth - header.length; const paddedHeader = header + ' '.repeat(Math.max(0, padding)); process.stdout.write(chalk_1.default.hex(headerText).bgHex(headerBg)(paddedHeader)); process.stdout.write('\n'); } renderContent(visibleLines) { const startLineNumber = this.currentLine + 1; visibleLines.forEach((line, index) => { let displayLine = line; if (this.showLineNumbers) { const lineNumber = startLineNumber + index; const lineNumberStr = lineNumber.toString().padStart(4, ' '); const lineNumberColor = this.theme.colors.accent; displayLine = `${chalk_1.default.hex(lineNumberColor)(lineNumberStr)} │ ${line}`; } if (displayLine.length > this.terminalWidth) { displayLine = displayLine.substring(0, this.terminalWidth - 3) + '...'; } process.stdout.write(displayLine); process.stdout.write('\n'); }); } renderFooter() { const footerBg = this.theme.colors.border; const footerText = this.theme.colors.text; const totalLines = this.lines.length; const currentPage = Math.floor(this.currentLine / (this.terminalHeight - 2)) + 1; const totalPages = Math.ceil(totalLines / (this.terminalHeight - 2)); const progress = totalLines > 0 ? Math.round((this.currentLine + this.terminalHeight - 2) / totalLines * 100) : 100; const progressStr = progress > 100 ? '100%' : `${progress}%`; const leftStatus = `Line ${this.currentLine + 1}/${totalLines}`; const rightStatus = `${progressStr} | Page ${currentPage}/${totalPages}`; const helpText = 'q:quit ↑/↓:scroll PgUp/PgDn:page g/G:top/bottom'; const availableWidth = this.terminalWidth - leftStatus.length - rightStatus.length; const centeredHelp = availableWidth > helpText.length ? helpText.padStart((availableWidth + helpText.length) / 2).padEnd(availableWidth) : helpText.substring(0, availableWidth); const footer = leftStatus + centeredHelp + rightStatus; const paddedFooter = footer.padEnd(this.terminalWidth); process.stdout.write(chalk_1.default.hex(footerText).bgHex(footerBg)(paddedFooter)); } handleKeyPress(key, resolve) { const contentHeight = this.terminalHeight - 2; switch (key.name) { case 'q': case 'escape': this.cleanup(); resolve(); break; case 'up': if (this.currentLine > 0) { this.currentLine--; this.render(); } break; case 'down': if (this.currentLine < this.lines.length - 1) { this.currentLine++; this.render(); } break; case 'pageup': this.currentLine = Math.max(0, this.currentLine - contentHeight); this.render(); break; case 'pagedown': this.currentLine = Math.min(this.lines.length - 1, this.currentLine + contentHeight); this.render(); break; case 'g': this.currentLine = 0; this.render(); break; case 'G': this.currentLine = Math.max(0, this.lines.length - contentHeight); this.render(); break; case 'home': this.currentLine = 0; this.render(); break; case 'end': this.currentLine = Math.max(0, this.lines.length - contentHeight); this.render(); break; default: if (key.ctrl && key.name === 'c') { this.cleanup(); process.exit(0); } break; } } cleanup() { process.stdout.write('\x1B[?1049l'); this.rl.input.setRawMode(false); this.rl.close(); } } exports.Pager = Pager; //# sourceMappingURL=pager.js.map