@sarahisweird/hmoog
Version:
Out-of-game automation for Hackmud
89 lines (88 loc) • 3.07 kB
JavaScript
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`;
}
}