UNPKG

@sarahisweird/hmoog

Version:

Out-of-game automation for Hackmud

89 lines (88 loc) 3.07 kB
import { NodeVisitor } from './types.js'; import { ColorDepth, defaultTextColorHex, defaultTextColorRgba, vgaTranslationTable } from './colors.js'; import { corruptionCharReplacements, isCorruptionChar } from './corruption.js'; import { ShellParser } from './parsing.js'; export class AnsiConverter extends NodeVisitor { colorDepth; replaceCorruption; corruptionReplacements; colorStack = []; result = ''; constructor(options) { super(); const defaultedOptions = { colorDepth: ColorDepth.TRUE_COLOR, replaceCorruption: true, corruptionReplacements: corruptionCharReplacements, ...options }; this.colorDepth = defaultedOptions.colorDepth; this.replaceCorruption = defaultedOptions.replaceCorruption; this.corruptionReplacements = defaultedOptions.corruptionReplacements; const defaultColor = this.makeAnsiColor({ colorHex: defaultTextColorHex, colorRgba: defaultTextColorRgba }); this.colorStack.push(defaultColor); this.result += defaultColor; } static convert(nodes, options) { const converter = new AnsiConverter(options); converter.visitAll(nodes); return converter.getResult(); } static convertFromShellText(input, options) { const nodes = ShellParser.parse(input); return this.convert(nodes, options); } getResult() { if (this.colorDepth !== ColorDepth.NONE) { this.result += '\x1b[0m'; } return this.result; } visitColor(node) { const prevColor = this.colorStack[this.colorStack.length - 1]; const newColor = this.makeAnsiColor(node); this.result += newColor; this.colorStack.push(newColor); this.visitAll(node.children); this.colorStack.pop(); this.result += prevColor; } visitText(node) { const text = this.replaceCorruption ? this.convertCorruption(node.text) : node.text; this.result += text; } convertCorruption(text) { let newText = ''; for (const char of text) { if (isCorruptionChar(char)) { newText += this.corruptionReplacements[char]; } else { newText += char; } } return newText; } makeAnsiColor(node) { switch (this.colorDepth) { case ColorDepth.NONE: return ''; case ColorDepth.EIGHT_BIT: return this.makeEightBitColor(node); case ColorDepth.TRUE_COLOR: return this.makeTrueColor(node); } } makeEightBitColor(node) { const vgaColor = vgaTranslationTable[node.colorHex.substring(0, 6)]; if (!vgaColor) throw new Error(`Unknown color: ${node.colorHex}!`); return `\x1b[${vgaColor}m`; } makeTrueColor(node) { const color = node.colorRgba; return `\x1b[38;2;${color[0]};${color[1]};${color[2]}m`; } }