@teaui/core
Version:
A high-level terminal UI library for Node
433 lines • 15.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Style = void 0;
const sys_1 = require("./sys");
const Color_1 = require("./Color");
const util_1 = require("./util");
class Style {
bold;
dim;
italic;
strikeout;
underline;
inverse;
blink;
invisible;
foreground;
background;
static NONE = new Style();
static underlined = new Style({ underline: true });
static bold = new Style({ bold: true });
constructor({ bold, dim, italic, strikeout, underline, inverse, blink, invisible, foreground, background, } = {}) {
this.underline = underline;
this.inverse = inverse;
this.bold = bold;
// bold and dim are mutually exclusive - bold has precedence
this.dim = bold ? undefined : dim;
this.italic = italic;
this.strikeout = strikeout;
this.blink = blink;
this.invisible = invisible;
this.foreground = foreground;
this.background = background;
(0, util_1.define)(this, 'underline', { enumerable: this.underline !== undefined });
(0, util_1.define)(this, 'inverse', { enumerable: this.inverse !== undefined });
(0, util_1.define)(this, 'bold', { enumerable: this.bold !== undefined });
(0, util_1.define)(this, 'dim', { enumerable: this.dim !== undefined });
(0, util_1.define)(this, 'italic', { enumerable: this.italic !== undefined });
(0, util_1.define)(this, 'strikeout', { enumerable: this.strikeout !== undefined });
(0, util_1.define)(this, 'blink', { enumerable: this.blink !== undefined });
(0, util_1.define)(this, 'invisible', { enumerable: this.invisible !== undefined });
(0, util_1.define)(this, 'foreground', { enumerable: this.foreground !== undefined });
(0, util_1.define)(this, 'background', { enumerable: this.background !== undefined });
}
invert() {
return this.merge({
foreground: this.background,
background: this.foreground,
});
}
merge(style) {
if (style === undefined) {
return this;
}
return new Style({
underline: style.underline ?? this.underline,
inverse: style.inverse ?? this.inverse,
// only one of bold or dim
bold: style.bold ?? (style.dim ? undefined : this.bold),
dim: style.dim ?? (style.bold ? undefined : this.dim),
italic: style.italic ?? this.italic,
strikeout: style.strikeout ?? this.strikeout,
blink: style.blink ?? this.blink,
invisible: style.invisible ?? this.invisible,
foreground: style.foreground === null
? undefined
: style.foreground === undefined
? this.foreground
: style.foreground,
background: style.background === null
? undefined
: style.background === undefined
? this.background
: style.background,
});
}
isEqual(style) {
return (this.underline === style.underline &&
this.inverse === style.inverse &&
this.bold === style.bold &&
this.dim === style.dim &&
this.italic === style.italic &&
this.strikeout === style.strikeout &&
this.blink === style.blink &&
this.invisible === style.invisible &&
this.foreground === style.foreground &&
this.background === style.background);
}
/**
* @return a more easily debuggable object
*/
toDebug() {
return [
['bold', this.bold],
['dim', this.dim],
['italic', this.italic],
['strikeout', this.strikeout],
['underline', this.underline],
['inverse', this.inverse],
['blink', this.blink],
['invisible', this.invisible],
['foreground', this.foreground],
['background', this.background],
]
.filter(([name, value]) => value !== undefined)
.reduce((o, [name, value]) => {
o[name] = value;
return o;
}, {});
}
static fromSGR(ansi, prevStyle) {
let match = ansi.match(/^\x1b\[([\d;]*)m$/);
if (!match) {
return Style.NONE;
}
ansi = match[1] + ';';
let ansiCodes = [];
let code = '';
for (const char of ansi) {
if (char === ';') {
if (code === '38' ||
code === '38;5' ||
code === '48' ||
code === '48;5') {
code += ';';
}
else {
ansiCodes.push(code);
code = '';
}
}
else {
code += char;
}
}
let styles = {};
for (const code of ansiCodes) {
if ((match = code.match(/^38;5;(\d+)$/))) {
styles.foreground = { sgr: match[1] };
continue;
}
else if ((match = code.match(/^48;5;(\d+)$/))) {
styles.background = { sgr: match[1] };
continue;
}
else if ((match = code.match(/^38;2;([\d;]+)$/))) {
const [r, g, b] = match[1]
.split(';')
.map(i => Math.max(0, Math.min(255, parseInt(i, 10))));
styles.foreground = [r, g, b];
continue;
}
else if ((match = code.match(/^48;2;([\d;]+)$/))) {
const [r, g, b] = match[1]
.split(';')
.map(i => Math.max(0, Math.min(255, parseInt(i, 10))));
styles.background = [r, g, b];
continue;
}
switch (code) {
case '':
break;
case '0':
styles.foreground = prevStyle.foreground ?? 'default';
styles.background = prevStyle.background ?? 'default';
styles.bold = prevStyle.bold ?? false;
styles.dim = prevStyle.dim ?? false;
styles.italic = prevStyle.italic ?? false;
styles.underline = prevStyle.underline ?? false;
styles.blink = prevStyle.blink ?? false;
styles.inverse = prevStyle.inverse ?? false;
styles.invisible = prevStyle.invisible ?? false;
styles.strikeout = prevStyle.strikeout ?? false;
break;
case '1':
styles.bold = true;
break;
case '2':
styles.dim = true;
break;
case '22':
styles.bold = prevStyle.bold ?? false;
styles.dim = prevStyle.dim ?? false;
break;
case '3':
styles.italic = true;
break;
case '23':
styles.italic = prevStyle.italic ?? false;
break;
case '4':
styles.underline = true;
break;
case '24':
styles.underline = prevStyle.underline ?? false;
break;
case '5':
styles.blink = true;
break;
case '25':
styles.blink = prevStyle.blink ?? false;
break;
case '7':
styles.inverse = true;
break;
case '27':
styles.inverse = prevStyle.inverse ?? false;
break;
case '8':
styles.invisible = true;
break;
case '28':
styles.invisible = prevStyle.invisible ?? false;
break;
case '9':
styles.strikeout = true;
break;
case '29':
styles.strikeout = prevStyle.strikeout ?? false;
break;
case '30':
styles.foreground = 'black';
break;
case '31':
styles.foreground = 'red';
break;
case '32':
styles.foreground = 'green';
break;
case '33':
styles.foreground = 'yellow';
break;
case '34':
styles.foreground = 'blue';
break;
case '35':
styles.foreground = 'magenta';
break;
case '36':
styles.foreground = 'cyan';
break;
case '37':
styles.foreground = 'white';
break;
case '39':
styles.foreground = 'default';
break;
case '90':
styles.foreground = 'gray';
break;
case '91':
styles.foreground = 'brightRed';
break;
case '92':
styles.foreground = 'brightGreen';
break;
case '93':
styles.foreground = 'brightYellow';
break;
case '94':
styles.foreground = 'brightBlue';
break;
case '95':
styles.foreground = 'brightMagenta';
break;
case '96':
styles.foreground = 'brightCyan';
break;
case '97':
styles.foreground = 'brightWhite';
break;
case '40':
styles.background = 'black';
break;
case '41':
styles.background = 'red';
break;
case '42':
styles.background = 'green';
break;
case '43':
styles.background = 'yellow';
break;
case '44':
styles.background = 'blue';
break;
case '45':
styles.background = 'magenta';
break;
case '46':
styles.background = 'cyan';
break;
case '47':
styles.background = 'white';
break;
case '49':
styles.background = 'default';
break;
case '100':
styles.background = 'gray';
break;
case '101':
styles.background = 'brightRed';
break;
case '102':
styles.background = 'brightGreen';
break;
case '103':
styles.background = 'brightYellow';
break;
case '104':
styles.background = 'brightBlue';
break;
case '105':
styles.background = 'brightMagenta';
break;
case '106':
styles.background = 'brightCyan';
break;
case '107':
styles.background = 'brightWhite';
break;
}
}
return new Style(styles);
}
/**
* @param prevStyle Used by the buffer to reset foreground/background colors and attrs
* @param text If provided, the text will be "wrapped" in the new codes, and
* `prevStyle` will be restored.
*/
toSGR(prevStyle, text) {
const { global: globalProgram } = sys_1.program;
if (!globalProgram) {
return '';
}
const parts = [];
const undo = [];
if (this.underline && !prevStyle.underline) {
parts.push('underline');
if (text)
undo.push('!underline');
}
else if (!this.underline && prevStyle.underline) {
parts.push('!underline');
if (text)
undo.push('underline');
}
if (this.bold && !prevStyle.bold) {
parts.push('bold');
if (text)
undo.push('!bold');
}
else if (!this.bold && prevStyle.bold) {
parts.push('!bold');
if (text)
undo.push('bold');
}
if (this.dim && !prevStyle.dim) {
parts.push('dim');
if (text)
undo.push('!dim');
}
else if (!this.dim && prevStyle.dim) {
parts.push('!dim');
if (text)
undo.push('dim');
}
if (this.italic && !prevStyle.italic) {
parts.push('italic');
if (text)
undo.push('!italic');
}
else if (!this.italic && prevStyle.italic) {
parts.push('!italic');
if (text)
undo.push('italic');
}
if (this.strikeout && !prevStyle.strikeout) {
parts.push('strikeout');
if (text)
undo.push('!strikeout');
}
else if (!this.strikeout && prevStyle.strikeout) {
parts.push('!strikeout');
if (text)
undo.push('strikeout');
}
if (this.inverse && !prevStyle.inverse) {
parts.push('inverse');
if (text)
undo.push('!inverse');
}
else if (!this.inverse && prevStyle.inverse) {
parts.push('!inverse');
if (text)
undo.push('inverse');
}
if (this.foreground) {
parts.push((0, Color_1.colorToSGR)(this.foreground, 'fg'));
if (text)
undo.push((0, Color_1.colorToSGR)(prevStyle.foreground ?? 'default', 'fg'));
}
else if (prevStyle.foreground && prevStyle.foreground !== 'default') {
parts.push((0, Color_1.colorToSGR)('default', 'fg'));
if (text)
undo.push((0, Color_1.colorToSGR)(prevStyle.foreground, 'fg'));
}
if (this.background) {
parts.push((0, Color_1.colorToSGR)(this.background, 'bg'));
if (text)
undo.push((0, Color_1.colorToSGR)(prevStyle.background ?? 'default', 'bg'));
}
else if (prevStyle.background && prevStyle.background !== 'default') {
parts.push((0, Color_1.colorToSGR)('default', 'bg'));
if (text)
undo.push((0, Color_1.colorToSGR)(prevStyle.background, 'bg'));
}
// put '!' flags in front
parts.sort();
undo.sort();
if (text !== undefined) {
return globalProgram.style(parts) + text + globalProgram.style(undo);
}
if (parts.length) {
return globalProgram.style(parts);
}
else {
return '';
}
}
}
exports.Style = Style;
//# sourceMappingURL=Style.js.map