diff --git a/utils/tui.js b/utils/tui.js index 4bd72a7..59d86ee 100644 --- a/utils/tui.js +++ b/utils/tui.js @@ -4,134 +4,131 @@ * @enum {string} */ export const FrameType = { - /** - * ╔════════════╗ - * ║ Hello, TUI ║ - * ╚════════════╝ - * - * @type {string} Double-lined frame - */ - Double: "Double", + /** + * ╔════════════╗ + * ║ Hello, TUI ║ + * ╚════════════╝ + * + * @type {string} Double-lined frame + */ + Double: "Double", - /** - * ┌────────────┐ - * │ Hello, TUI │ - * └────────────┘ - * - * @type {string} Single-lined frame - */ - Single: "Single", + /** + * ┌────────────┐ + * │ Hello, TUI │ + * └────────────┘ + * + * @type {string} Single-lined frame + */ + Single: "Single", - /** - * - * Hello, TUI - * - * - * @type {string} Double-lined frame - */ - Invisible: "Invisible", + /** + * + * Hello, TUI + * + * + * @type {string} Double-lined frame + */ + Invisible: "Invisible", - /** - * ( ) - * ( Hello, TUI ) - * ( ) - * - * @type {string} Double-lined frame - */ - Parentheses: "Parentheses", + /** + * ( ) + * ( Hello, TUI ) + * ( ) + * + * @type {string} Double-lined frame + */ + Parentheses: "Parentheses", - /** - * +------------+ - * | Hello, TUI | - * +------------+ - * - * @type {string} Double-lined frame - */ - Basic: "Basic", + /** + * +------------+ + * | Hello, TUI | + * +------------+ + * + * @type {string} Double-lined frame + */ + Basic: "Basic", - /** - * @protected - * Default values for the common frame types. - * - * [north, south, east, west, northwest, northeast, southwest, southeast] - */ - values: { - Basic: "--||++++", - Double: "══║║╔╗╚╝", - Invisible: " ", - Parentheses: " () ", - Single: "──││┌┐└┘", - }, + /** + * @protected + * Default values for the common frame types. + * + * [north, south, east, west, northwest, northeast, southwest, southeast] + */ + values: { + Basic: "--||++++", + Double: "══║║╔╗╚╝", + Invisible: " ", + Parentheses: " () ", + Single: "──││┌┐└┘", + }, }; export class FramingOptions { - /** @type {number=0} Vertical Padding; number of vertical whitespace (newlines) between the text and the frame. */ - vPadding = 0; + /** @type {number=0} Vertical Padding; number of vertical whitespace (newlines) between the text and the frame. */ + vPadding = 0; - /** @type {number=0} Margin ; number of newlines to to insert before and after the framed text */ - vMargin = 0; + /** @type {number=0} Margin ; number of newlines to to insert before and after the framed text */ + vMargin = 0; - /** @type {number=0} Horizontal Padding; number of whitespace characters to insert between the text and the sides of the frame. */ - hPadding = 0; + /** @type {number=0} Horizontal Padding; number of whitespace characters to insert between the text and the sides of the frame. */ + hPadding = 0; - /** @type {number=0} Margin ; number of newlines to to insert before and after the text, but inside the frame */ - hMargin = 0; + /** @type {number=0} Margin ; number of newlines to to insert before and after the text, but inside the frame */ + hMargin = 0; - /** @type {FrameType=FrameType.Double} Type of frame to put around the text */ - frameType = FrameType.Double; + /** @type {FrameType=FrameType.Double} Type of frame to put around the text */ + frameType = FrameType.Double; - /** @type {number=0} Pad each line to become at least this long */ - minLineWidth = 0; + /** @type {number=0} Pad each line to become at least this long */ + minLineWidth = 0; - // Light block: ░ (U+2591) - // Medium block: ▒ (U+2592) - // Dark block: ▓ (U+2593) - // Solid block: █ (U+2588) - /** @type {string} Single character to use as filler inside the frame. */ - paddingChar = " "; // character used for padding inside the frame. + // Light block: ░ (U+2591) + // Medium block: ▒ (U+2592) + // Dark block: ▓ (U+2593) + // Solid block: █ (U+2588) + /** @type {string} Single character to use as filler inside the frame. */ + paddingChar = " "; - /** @type {string} Single character to use as filler outside the frame. */ - marginChar = " "; + /** @type {string} Single character to use as filler outside the frame. */ + marginChar = " "; - /** @type {string} The 8 characters that make up the frame elements */ - frameChars = FrameType.values.Double; + /** @type {string} The 8 characters that make up the frame elements */ + frameChars = FrameType.values.Double; - /** - * @param {object} o - * @returns {FramingOptions} - */ - static fromObject(o) { - const result = new FramingOptions(); + /** + * @param {object} o + * @returns {FramingOptions} + */ + static fromObject(o) { + const result = new FramingOptions(); - result.vPadding = Math.max(0, Number.parseInt(o.vPadding) || 0); - result.hPadding = Math.max(0, Number.parseInt(o.hPadding) || 0); - result.vMargin = Math.max(0, Number.parseInt(o.vMargin) || 0); - result.hMargin = Math.max(0, Number.parseInt(o.hMargin) || 0); - result.minLineWidth = Math.max(0, Number.parseInt(o.hMargin) || 0); + result.vPadding = Math.max(0, Number.parseInt(o.vPadding) || 0); + result.hPadding = Math.max(0, Number.parseInt(o.hPadding) || 0); + result.vMargin = Math.max(0, Number.parseInt(o.vMargin) || 0); + result.hMargin = Math.max(0, Number.parseInt(o.hMargin) || 0); + result.minLineWidth = Math.max(0, Number.parseInt(o.hMargin) || 0); - result.paddingChar = String(o.paddingChar || " ")[0] || " "; - result.marginChar = String(o.marginChar || " ")[0] || " "; + result.paddingChar = String(o.paddingChar || " ")[0] || " "; + result.marginChar = String(o.marginChar || " ")[0] || " "; - // - // Do we have custom and valid frame chars? - if ( - typeof o.frameChars === "string" && - o.frameChars.length === FrameType.values.Double.length - ) { - result.frameChars = o.frameChars; + // + // Do we have custom and valid frame chars? + if (typeof o.frameChars === "string" && o.frameChars.length === FrameType.values.Double.length) { + result.frameChars = o.frameChars; - // - // do we have document frame type instead ? - } else if (o.frameType && FrameType.hasOwnProperty(o.frameType)) { - result.frameChars = FrameType.values[o.frameType]; + // + // do we have document frame type instead ? + } else if (o.frameType && FrameType.hasOwnProperty(o.frameType)) { + result.frameChars = FrameType.values[o.frameType]; - // Fall back to using "Double" frame - } else { - result.frameChars = FrameType.values.Double; + // Fall back to using "Double" frame + } else { + result.frameChars = FrameType.values.Double; + } + + return result; } - - return result; - } } /** @@ -139,198 +136,187 @@ export class FramingOptions { * @param {FramingOptions} options */ export function frameText(text, options) { - if (!options) { - options = new FramingOptions(); - } + if (!options) { + options = new FramingOptions(); + } - if (!(options instanceof FramingOptions)) { - options = FramingOptions.fromObject(options); - } + if (!(options instanceof FramingOptions)) { + options = FramingOptions.fromObject(options); + } - // There is a point to this; each element in the array may contain newlines, - // so we have to combine everything into a long text and then split into - // individual lines afterwards. - if (Array.isArray(text)) { - text = text.join("\n"); - } + // There is a point to this; each element in the array may contain newlines, + // so we have to combine everything into a long text and then split into + // individual lines afterwards. + if (Array.isArray(text)) { + text = text.join("\n"); + } - if (typeof text !== "string") { - console.debug(text); - throw new Error( - `text argument was neither an array or a string, it was a ${typeof text}`, + if (typeof text !== "string") { + console.debug(text); + throw new Error(`text argument was neither an array or a string, it was a ${typeof text}`); + } + + /** @type {string[]} */ + const lines = text.split("\n"); + + const innerLineLength = Math.max( + lines.reduce((accumulator, currentLine) => { + if (currentLine.length > accumulator) { + return currentLine.length; + } + return accumulator; + }, 0), + options.minLineWidth, ); - } - /** @type {string[]} */ - const lines = text.split("\n"); + const frameThickness = 1; // always 1 for now. - const innerLineLength = Math.max( - lines.reduce((accumulator, currentLine) => { - if (currentLine.length > accumulator) { - return currentLine.length; - } - return accumulator; - }, 0), - options.minLineWidth, - ); + const outerLineLength = 0 + innerLineLength + frameThickness * 2 + options.hPadding * 2 + options.hMargin * 2; - const frameThickness = 1; // always 1 for now. + // get the frame characters from the frameType. + let [ + fNorth, // horizontal frame top lines + fSouth, // horizontal frame bottom lines + fWest, // vertical frame lines on the left side + fEast, // vertical frame lines on the right side + fNorthWest, // upper left frame corner + fNorthEast, // upper right frame corner + fSouthWest, // lower left frame corner + fSouthEast, // lower right frame corner + ] = options.frameChars.split(""); + if (fNorth === "§") { + fNorth = ""; + } + if (fSouth === "§") { + fSouth = ""; + } + if (fEast === "§") { + fEast = ""; + } + if (fWest === "§") { + fWest = ""; + } + if (fNorthEast === "§") { + fNorthEast = ""; + } + if (fSouthEast === "§") { + fSouthEast = ""; + } + if (fNorthWest === "§") { + fNorthWest = ""; + } + if (fSouthWest === "§") { + fSouthWest = ""; + } - const outerLineLength = - 0 + - innerLineLength + - frameThickness * 2 + - options.hPadding * 2 + - options.hMargin * 2; + let output = ""; - // get the frame characters from the frameType. - let [ - fNorth, // horizontal frame top lines - fSouth, // horizontal frame bottom lines - fWest, // vertical frame lines on the left side - fEast, // vertical frame lines on the right side - fNorthWest, // upper left frame corner - fNorthEast, // upper right frame corner - fSouthWest, // lower left frame corner - fSouthEast, // lower right frame corner - ] = options.frameChars.split(""); - if (fNorth === "§") { - fNorth = ""; - } - if (fSouth === "§") { - fSouth = ""; - } - if (fEast === "§") { - fEast = ""; - } - if (fWest === "§") { - fWest = ""; - } - if (fNorthEast === "§") { - fNorthEast = ""; - } - if (fSouthEast === "§") { - fSouthEast = ""; - } - if (fNorthWest === "§") { - fNorthWest = ""; - } - if (fSouthWest === "§") { - fSouthWest = ""; - } + // + // GENERATE THE MARGIN SPACE ABOVE THE FRAMED MsgType.TEXT + // + // ( we insert space characters even though ) + // ( they wouldn't normally be visible. But ) + // ( Some fonts might allow us to see blank ) + // ( space, and what if we want to nest many ) + // ( frames inside each other? ) + // + output += (options.marginChar.repeat(outerLineLength) + "\n").repeat(options.vMargin); - let output = ""; - - // - // GENERATE THE MARGIN SPACE ABOVE THE FRAMED MsgType.TEXT - // - // ( we insert space characters even though ) - // ( they wouldn't normally be visible. But ) - // ( Some fonts might allow us to see blank ) - // ( space, and what if we want to nest many ) - // ( frames inside each other? ) - // - output += (options.marginChar.repeat(outerLineLength) + "\n").repeat( - options.vMargin, - ); - - // - // GENERATE THE TOP PART OF THE FRAME - // ╔════════════╗ - // - // - output += - "" + // Make sure JS knows we're adding a string. - options.marginChar.repeat(options.hMargin) + // the margin before the frame starts - fNorthWest + // northwest frame corner - fNorth.repeat(innerLineLength + options.hPadding * 2) + // the long horizontal frame top bar - fNorthEast + // northeast frame corner - options.marginChar.repeat(options.hMargin) + // the margin after the frame ends - "\n"; - // - // GENERATE UPPER PADDING - // - // ║ ║ - // - // (the blank lines within the frame and above the text) - output += ( - options.marginChar.repeat(options.hMargin) + - fWest + - options.paddingChar.repeat(innerLineLength + options.hPadding * 2) + - fEast + - options.marginChar.repeat(options.hMargin) + - "\n" - ).repeat(options.vPadding); - - // - // GENERATE FRAMED MsgType.TEXT SEGMENT - // - // ║ My pretty ║ - // ║ text here ║ - // - // ( this could be done with a reduce() ) - // - for (const line of lines) { + // + // GENERATE THE TOP PART OF THE FRAME + // ╔════════════╗ + // + // output += - "" + // Make sure JS knows we're adding a string. - options.marginChar.repeat(options.hMargin) + // margin before frame - fWest + // vertical frame char - options.paddingChar.repeat(options.hPadding) + // padding before text - line.padEnd(innerLineLength, " ") + // The actual text. Pad it with normal space character, NOT custom space. - options.paddingChar.repeat(options.hPadding) + // padding after text - fEast + // vertical frame bar - options.marginChar.repeat(options.hMargin) + // margin after frame - "\n"; - } + "" + // Make sure JS knows we're adding a string. + options.marginChar.repeat(options.hMargin) + // the margin before the frame starts + fNorthWest + // northwest frame corner + fNorth.repeat(innerLineLength + options.hPadding * 2) + // the long horizontal frame top bar + fNorthEast + // northeast frame corner + options.marginChar.repeat(options.hMargin) + // the margin after the frame ends + "\n"; + // + // GENERATE UPPER PADDING + // + // ║ ║ + // + // (the blank lines within the frame and above the text) + output += ( + options.marginChar.repeat(options.hMargin) + + fWest + + options.paddingChar.repeat(innerLineLength + options.hPadding * 2) + + fEast + + options.marginChar.repeat(options.hMargin) + + "\n" + ).repeat(options.vPadding); - // - // GENERATE LOWER PADDING - // - // ║ ║ - // - // ( the blank lines within the ) - // ( frame and below the text ) - // - // ( this code is a direct ) - // ( repeat of the code that ) - // ( generates top padding ) - output += ( - options.marginChar.repeat(options.hMargin) + - fWest + - options.paddingChar.repeat(innerLineLength + options.hPadding * 2) + - fEast + - options.marginChar.repeat(options.hMargin) + - "\n" - ).repeat(options.vPadding); + // + // GENERATE FRAMED MsgType.TEXT SEGMENT + // + // ║ My pretty ║ + // ║ text here ║ + // + // ( this could be done with a reduce() ) + // + for (const line of lines) { + output += + "" + // Make sure JS knows we're adding a string. + options.marginChar.repeat(options.hMargin) + // margin before frame + fWest + // vertical frame char + options.paddingChar.repeat(options.hPadding) + // padding before text + line.padEnd(innerLineLength, " ") + // The actual text. Pad it with normal space character, NOT custom space. + options.paddingChar.repeat(options.hPadding) + // padding after text + fEast + // vertical frame bar + options.marginChar.repeat(options.hMargin) + // margin after frame + "\n"; + } - // - // GENERATE THE BOTTOM PART OF THE FRAME - // - // ╚════════════╝ - // - output += - "" + // Make sure JS knows we're adding a string. - options.marginChar.repeat(options.hMargin) + // the margin before the frame starts - fSouthWest + // northwest frame corner - fSouth.repeat(innerLineLength + options.hPadding * 2) + // the long horizontal frame top bar - fSouthEast + // northeast frame corner - options.marginChar.repeat(options.hMargin) + // the margin after the frame starts - "\n"; + // + // GENERATE LOWER PADDING + // + // ║ ║ + // + // ( the blank lines within the ) + // ( frame and below the text ) + // + // ( this code is a direct ) + // ( repeat of the code that ) + // ( generates top padding ) + output += ( + options.marginChar.repeat(options.hMargin) + + fWest + + options.paddingChar.repeat(innerLineLength + options.hPadding * 2) + + fEast + + options.marginChar.repeat(options.hMargin) + + "\n" + ).repeat(options.vPadding); - // - // GENERATE THE MARGIN SPACE BELOW THE FRAMED MsgType.TEXT - // - // ( we insert space characters even though ) - // ( they wouldn't normally be visible. But ) - // ( Some fonts might allow us to see blank ) - // ( space, and what if we want to nest many ) - // ( frames inside each other? ) - // - output += (options.marginChar.repeat(outerLineLength) + "\n").repeat( - options.vMargin, - ); + // + // GENERATE THE BOTTOM PART OF THE FRAME + // + // ╚════════════╝ + // + output += + "" + // Make sure JS knows we're adding a string. + options.marginChar.repeat(options.hMargin) + // the margin before the frame starts + fSouthWest + // northwest frame corner + fSouth.repeat(innerLineLength + options.hPadding * 2) + // the long horizontal frame top bar + fSouthEast + // northeast frame corner + options.marginChar.repeat(options.hMargin) + // the margin after the frame starts + "\n"; - return output; + // + // GENERATE THE MARGIN SPACE BELOW THE FRAMED MsgType.TEXT + // + // ( we insert space characters even though ) + // ( they wouldn't normally be visible. But ) + // ( Some fonts might allow us to see blank ) + // ( space, and what if we want to nest many ) + // ( frames inside each other? ) + // + output += (options.marginChar.repeat(outerLineLength) + "\n").repeat(options.vMargin); + + return output; } // Allow this script to be run directly from node as well as being included!