chipmunkbot3/util/chat/stringify/ansi.js

101 lines
3 KiB
JavaScript
Raw Permalink Normal View History

const { colors, formatting, reset } = require('../formatting.json')
const { normalize, intToRgb, getChangedFormatting } = require('../utility')
const colormap = Object.fromEntries(colors.map(color => [color.name, color.ansi]))
const formatmap = Object.fromEntries(formatting.map(format => [format.name, format.ansi]))
const colorcodemap = Object.fromEntries(colors.map(color => [color.code, color.ansi]))
const formatcodemap = Object.fromEntries(formatting.map(format => [format.code, format.ansi]))
const baseColors = colors.map(color => intToRgb(color.rgb))
function ansiStringify (text, { lang = {}, previousText, parent } = {}) {
text = normalize(text)
let string = getFormatting(text, previousText, parent)
if (text.text != null) string += preprocessText(text.text)
else if (text.translate != null) {
let format
if (Object.hasOwn(lang, text.translate)) format = lang[text.translate]
else if (text.fallback != null) format = text.fallback
else format = text.translate
const _with = text.with || []
let i = 0
string += preprocessText(format).replace(/%(?:(\d+)\$)?(s|%)/g, (g0, g1) => {
if (g0 === '%%') return '%'
const idx = g1 ? parseInt(g1) : i++
if (_with[idx]) {
return ansiStringify(_with[idx], { lang, previousText: text, parent: text }) + getFormatting(text, _with[idx], parent)
}
return ''
})
}
else if (text.selector != null) string += preprocessText(text.selector)
else if (text.keybind) {
// TODO
}
if (text.extra) {
let previousChild = text
for (const child of text.extra) {
string += ansiStringify(child, { lang, previousText: previousChild, parent: text })
previousChild = child
}
}
return string
}
function getFormatting (text, previousText, parent) {
const format = getChangedFormatting(text, previousText, parent)
let string = ''
if ('color' in format) {
if (format.color && format.color[0] === '#') {
const rgb = parseInt(format.color.substring(1), 16) & 0xffffff
const [r, g, b] = intToRgb(rgb)
string += `\x1b[38;2;${r};${g};${b}m`
}
else if (colormap[format.color]) string += colormap[format.color]
else if (parent) string += reset.ansi
}
if (format.bold) string += formatmap.bold
if (format.italic) string += formatmap.italic
if (format.underlined) string += formatmap.underlined
if (format.strikethrough) string += formatmap.strikethrough
if (format.obfuscated) string += formatmap.obfuscated
return string
}
function preprocessText (input) {
let string = ''
for (let i = 0; i < input.length; i++) {
const c = input[i]
if (c === '§') {
if ((i + 1) >= input.length) break
const code = input.substring(i, i + 2)
i++
if (colorcodemap[code]) string += colorcodemap[code]
else if (formatcodemap[code]) string += formatcodemap[code]
else if (code === reset.code) string += reset.ansi
continue
}
else string += c
}
return string
}
module.exports = ansiStringify