UNPKG

@poppinss/cliui

Version:

Opinionated UI KIT for Command Line apps

107 lines (106 loc) 3.51 kB
import stringWidth from "string-width"; import cliTruncate from "cli-truncate"; import terminalSize from "terminal-size"; //#region src/utils.ts function createWordWrapper(start, stop) { const mode = "soft"; const re = mode === "hard" ? /\b/ : /(\S+\s+)/; return function(text) { return text.toString().split(re).reduce(function(acc, x) { if (mode === "hard") for (let i = 0; i < x.length; i += stop - start) acc.push(x.slice(i, i + stop - start)); else acc.push(x); return acc; }, []).reduce(function(lines, rawChunk) { if (rawChunk === "") return lines; const chunk = rawChunk.replace(/\t/g, " "); const i = lines.length - 1; if (lines[i].length + chunk.length > stop) { lines[i] = lines[i].replace(/\s+$/, ""); chunk.split(/\n/).forEach(function(c) { lines.push(new Array(start + 1).join(" ") + c.replace(/^\s+/, "")); }); } else if (chunk.match(/\n/)) { const xs = chunk.split(/\n/); lines[i] += xs.shift(); xs.forEach(function(c) { lines.push(new Array(start + 1).join(" ") + c.replace(/^\s+/, "")); }); } else lines[i] += chunk; return lines; }, [new Array(start + 1).join(" ")]).join("\n"); }; } //#endregion //#region src/helpers.ts /** * Total number of columns for the terminal */ const TERMINAL_SIZE = terminalSize().columns; /** * Applies padding to the left or the right of the string by repeating * a given char. * * The method is not same as `padLeft` or `padRight` from JavaScript STD lib, * since it repeats a char regardless of the max width. */ function applyPadding(value, options) { if (options.paddingLeft) value = `${options.paddingChar.repeat(options.paddingLeft)}${value}`; if (options.paddingRight) value = `${value}${options.paddingChar.repeat(options.paddingRight)}`; return value; } /** * Justify the columns to have the same width by filling * the empty slots with a padding char. * * Optionally, the column can be aligned left or right. */ function justify(columns, options) { const normalizedOptions = { align: "left", paddingChar: " ", ...options }; return columns.map((column) => { const columnWidth = stringWidth(column); /** * Column is already same or greater than the maxWidth */ if (columnWidth >= normalizedOptions.maxWidth) return column; /** * Fill empty space on the right */ if (normalizedOptions.align === "left") return applyPadding(column, { paddingChar: normalizedOptions.paddingChar, paddingRight: normalizedOptions.maxWidth - columnWidth }); /** * Fill empty space on the left */ return applyPadding(column, { paddingChar: normalizedOptions.paddingChar, paddingLeft: normalizedOptions.maxWidth - columnWidth }); }); } /** * Wrap the text under the starting and the ending column. * The first line will start at 1st column. However, from * the 2nd line onwards, the columns before the start * column are filled with white space. */ function wrap(columns, options) { const wrapper = createWordWrapper(options.startColumn, options.endColumn); if (options.trimStart) return columns.map((column) => wrapper(column).trimStart()); return columns.map((column) => wrapper(column)); } /** * Truncates the text after a certain width. */ function truncate(columns, options) { return columns.map((column) => cliTruncate(column, options.maxWidth, { truncationCharacter: options.truncationChar || "…", position: options.position || "end" })); } //#endregion export { wrap as i, justify as n, truncate as r, TERMINAL_SIZE as t };