UNPKG

less-pager-mini

Version:

A scrollable terminal pager for Node.js CLI apps (terminal only)

245 lines (244 loc) 9.62 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.lineForward = lineForward; exports.lineBackward = lineBackward; exports.windowForward = windowForward; exports.windowBackward = windowBackward; exports.setWindowForward = setWindowForward; exports.setWindowBackward = setWindowBackward; exports.setHalfWindowForward = setHalfWindowForward; exports.setHalfWindowBackward = setHalfWindowBackward; exports.setHalfScreenRight = setHalfScreenRight; exports.setHalfScreenLeft = setHalfScreenLeft; const helpers_1 = require("../helpers"); const config_1 = require("../config"); /** * Moves forward by a given offset through content lines or subrows. * * @param content - Full content lines. * @param offset - Number of lines/subrows to move forward. * @param ignoreEOF - If true, ignores EOF clamp (optional). */ function lineForward(content, offset, ignoreEOF = false) { let currSubRowMax = (0, helpers_1.maxSubRow)(content[config_1.config.row]); if (isEndPosition(ignoreEOF, content.length, currSubRowMax)) { (0, helpers_1.ringBell)(); return; } if (config_1.config.chopLongLines || config_1.config.col) { const maxRow = ignoreEOF ? content.length - 1 : Math.max(content.length - config_1.config.window + 1, 0); config_1.config.row = Math.min(config_1.config.row + offset, maxRow); return; } const rowEnd = ignoreEOF ? null : getEndPosition(content); const maxRow = rowEnd ? rowEnd.maxRow : content.length - 1; while (offset > 0 && config_1.config.row <= maxRow) { currSubRowMax = (0, helpers_1.maxSubRow)(content[config_1.config.row]); if (config_1.config.row === maxRow && rowEnd) currSubRowMax = rowEnd.subRow; if (config_1.config.subRow + offset <= currSubRowMax) { config_1.config.subRow += offset; return; } offset -= currSubRowMax - config_1.config.subRow + 1; config_1.config.row++; config_1.config.subRow = 0; } if (rowEnd && config_1.config.row > rowEnd.maxRow) { config_1.config.row = rowEnd.maxRow; config_1.config.subRow = rowEnd.subRow; } else if (config_1.config.row === content.length) { config_1.config.row = content.length - 1; config_1.config.subRow = currSubRowMax; } } /** * Scroll backward by the given offset. * * - Stops and rings bell at BOF, also disables `mode.INIT`. * - In chopped mode, moves by whole lines. * - In wrapped mode, moves by sub-rows within a line. * * @param content - Full content lines. * @param offset - Lines or sub-rows to scroll backward. */ function lineBackward(content, offset) { if (!config_1.config.row && !config_1.config.subRow) { if (config_1.mode.INIT) config_1.mode.INIT = false; (0, helpers_1.ringBell)(); return; } if (config_1.config.chopLongLines || config_1.config.col) { config_1.config.row = Math.max(config_1.config.row - offset, 0); return; } while (offset > 0 && config_1.config.row >= 0) { if (config_1.config.subRow >= offset) { config_1.config.subRow -= offset; return; } if (config_1.config.row === 0) { config_1.config.subRow = 0; return; } offset -= config_1.config.subRow + 1; config_1.config.row--; config_1.config.subRow = (0, helpers_1.maxSubRow)(content[config_1.config.row]); } } /** * Scrolls the view forward by a window size. * * - If `buffer` is a valid number, it overrides the default window size. * - Falls back to `config.setWindow` or `config.window - 1` if `buffer` is * invalid. * - If `ignoreEOF` is `true`, allows scrolling beyond (END) without clamping. * * @param content - The full content to paginate. * @param buffer - A string array that represents the number of lines to scroll. * @param ignoreEOF - Whether to bypass EOF constraints during scrolling. */ function windowForward(content, buffer, ignoreEOF = false) { lineForward(content, (0, helpers_1.bufferToNum)(buffer) || config_1.config.setWindow || config_1.config.window - 1, ignoreEOF); } /** * Moves the view backward by one window. * * - If `buffer` is a valid number, uses it as the offset. * - Otherwise, uses `config.setWindow` if set, or defaults to * `config.window - 1`. * * @param content - The full content as an array of lines. * @param buffer - A string array that represents the number of lines to scroll. */ function windowBackward(content, buffer) { lineBackward(content, (0, helpers_1.bufferToNum)(buffer) || config_1.config.setWindow || config_1.config.window - 1); } /** * Sets a custom window size using the given `buffer`, and scrolls forward. * * - If `buffer` is a valid number, updates `config.setWindow` with it. * - Then scrolls forward by `config.setWindow` or falls back to * `config.window - 1`. * * @param content - The full content as an array of lines. * @param buffer - A string array that represents the number of lines to scroll. */ function setWindowForward(content, buffer) { config_1.config.setWindow = (0, helpers_1.bufferToNum)(buffer) || config_1.config.setWindow; lineForward(content, config_1.config.setWindow || config_1.config.window - 1); } /** * Sets a custom window size using the given `buffer`, and scrolls backward. * * - If `buffer` is a valid number, updates `config.setWindow` with it. * - Then scrolls backward by `config.setWindow` or falls back to * `config.window - 1`. * * @param content - The full content as an array of lines. * @param buffer - A string array that represents the number of lines to scroll. */ function setWindowBackward(content, buffer) { config_1.config.setWindow = (0, helpers_1.bufferToNum)(buffer) || config_1.config.setWindow; lineBackward(content, config_1.config.setWindow || config_1.config.window - 1); } /** * Sets a custom half-window size using the given `buffer`, and scrolls forward. * * - If `buffer` is a valid number, updates `config.setHalfWindow` with it. * - Then scrolls forward by `config.setHalfWindow` or falls back to * `config.halfWindow`. * * @param content - The full content as an array of lines. * @param buffer - A string array that represents the number of lines to scroll. */ function setHalfWindowForward(content, buffer) { config_1.config.setHalfWindow = (0, helpers_1.bufferToNum)(buffer) || config_1.config.setHalfWindow; lineForward(content, config_1.config.setHalfWindow || config_1.config.halfWindow); } /** * Sets a custom half-window size using the given `buffer`, and scrolls * backward. * * - If `buffer` is a valid number, updates `config.setHalfWindow` with it. * - Then scrolls backward by `config.setHalfWindow` or falls back to * `config.halfWindow`. * * @param content - The full content as an array of lines. * @param buffer - A string array that represents the number of lines to scroll. */ function setHalfWindowBackward(content, buffer) { config_1.config.setHalfWindow = (0, helpers_1.bufferToNum)(buffer) || config_1.config.setHalfWindow; lineBackward(content, config_1.config.setHalfWindow || config_1.config.halfWindow); } /** * Scrolls right by buffer value or half screen width. * * @param buffer - Buffer containing scroll offset. */ function setHalfScreenRight(buffer) { if (config_1.mode.INIT) config_1.mode.INIT = false; config_1.config.setCol = (0, helpers_1.bufferToNum)(buffer) || config_1.config.setCol; config_1.config.col += config_1.config.setCol || config_1.config.halfScreenWidth; } /** * Scrolls left by buffer value or half screen width. * * @param buffer - Buffer containing scroll offset. */ function setHalfScreenLeft(buffer) { if (config_1.mode.INIT) config_1.mode.INIT = false; config_1.config.setCol = (0, helpers_1.bufferToNum)(buffer) || config_1.config.setCol; config_1.config.col -= config_1.config.setCol || config_1.config.halfScreenWidth; if (config_1.config.col < 0) config_1.config.col = 0; } /** * Determines whether the current viewport position is at the end of the * content. * * This check accounts for both EOF mode and the final row/subRow position * based on whether EOF should be ignored. * * @param ignoreEOF - If `true`, skips EOF check and only uses position * comparison. * @param contentLength - Total number of content rows. * @param currSubRowMax - The final sub-row index to compare against. * @returns `true` if the current position is at the end; otherwise, `false`. */ function isEndPosition(ignoreEOF, contentLength, currSubRowMax) { return ((!ignoreEOF && config_1.mode.EOF) || (config_1.config.row === contentLength - 1 && config_1.config.subRow === currSubRowMax)); } /** * Calculates the last visible row and subrow for window clamping. * * @param content - Full content lines. * @returns Object with `maxRow` and `subRow` for the end position. */ function getEndPosition(content) { let maxRow = content.length - 1; let subRow = 0; let rowCount = 0; while (maxRow >= 0) { const subRows = (0, helpers_1.maxSubRow)(content[maxRow]) + 1; const rowSum = rowCount + subRows; if (rowSum >= config_1.config.window - 1) { subRow = rowSum - config_1.config.window + 1; break; } rowCount = rowSum; maxRow--; } if (maxRow < 0) { maxRow = 0; subRow = 0; } return { maxRow, subRow }; }