141 lines
4.6 KiB
TypeScript
141 lines
4.6 KiB
TypeScript
/**
|
|
* Copyright (c) 2017 The xterm.js authors. All rights reserved.
|
|
* @license MIT
|
|
*/
|
|
|
|
import { IColorSet, IColorManager } from './Types';
|
|
import { ITheme } from 'xterm';
|
|
|
|
const DEFAULT_FOREGROUND = '#ffffff';
|
|
const DEFAULT_BACKGROUND = '#000000';
|
|
const DEFAULT_CURSOR = '#ffffff';
|
|
const DEFAULT_CURSOR_ACCENT = '#000000';
|
|
const DEFAULT_SELECTION = 'rgba(255, 255, 255, 0.3)';
|
|
export const DEFAULT_ANSI_COLORS = [
|
|
// dark:
|
|
'#2e3436',
|
|
'#cc0000',
|
|
'#4e9a06',
|
|
'#c4a000',
|
|
'#3465a4',
|
|
'#75507b',
|
|
'#06989a',
|
|
'#d3d7cf',
|
|
// bright:
|
|
'#555753',
|
|
'#ef2929',
|
|
'#8ae234',
|
|
'#fce94f',
|
|
'#729fcf',
|
|
'#ad7fa8',
|
|
'#34e2e2',
|
|
'#eeeeec'
|
|
];
|
|
|
|
/**
|
|
* Fills an existing 16 length string with the remaining 240 ANSI colors.
|
|
* @param first16Colors The first 16 ANSI colors.
|
|
*/
|
|
function generate256Colors(first16Colors: string[]): string[] {
|
|
let colors = first16Colors.slice();
|
|
|
|
// Generate colors (16-231)
|
|
let v = [0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff];
|
|
for (let i = 0; i < 216; i++) {
|
|
const r = toPaddedHex(v[(i / 36) % 6 | 0]);
|
|
const g = toPaddedHex(v[(i / 6) % 6 | 0]);
|
|
const b = toPaddedHex(v[i % 6]);
|
|
colors.push(`#${r}${g}${b}`);
|
|
}
|
|
|
|
// Generate greys (232-255)
|
|
for (let i = 0; i < 24; i++) {
|
|
const c = toPaddedHex(8 + i * 10);
|
|
colors.push(`#${c}${c}${c}`);
|
|
}
|
|
|
|
return colors;
|
|
}
|
|
|
|
function toPaddedHex(c: number): string {
|
|
let s = c.toString(16);
|
|
return s.length < 2 ? '0' + s : s;
|
|
}
|
|
|
|
/**
|
|
* Manages the source of truth for a terminal's colors.
|
|
*/
|
|
export class ColorManager implements IColorManager {
|
|
public colors: IColorSet;
|
|
private _document: Document;
|
|
|
|
constructor(document: Document) {
|
|
this._document = document;
|
|
this.colors = {
|
|
foreground: DEFAULT_FOREGROUND,
|
|
background: DEFAULT_BACKGROUND,
|
|
cursor: DEFAULT_CURSOR,
|
|
cursorAccent: DEFAULT_CURSOR_ACCENT,
|
|
selection: DEFAULT_SELECTION,
|
|
ansi: generate256Colors(DEFAULT_ANSI_COLORS)
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Sets the terminal's theme.
|
|
* @param theme The theme to use. If a partial theme is provided then default
|
|
* colors will be used where colors are not defined.
|
|
*/
|
|
public setTheme(theme: ITheme): void {
|
|
this.colors.foreground = this._validateColor(theme.foreground, DEFAULT_FOREGROUND);
|
|
this.colors.background = this._validateColor(theme.background, DEFAULT_BACKGROUND);
|
|
this.colors.cursor = this._validateColor(theme.cursor, DEFAULT_CURSOR);
|
|
this.colors.cursorAccent = this._validateColor(theme.cursorAccent, DEFAULT_CURSOR_ACCENT);
|
|
this.colors.selection = this._validateColor(theme.selection, DEFAULT_SELECTION);
|
|
this.colors.ansi[0] = this._validateColor(theme.black, DEFAULT_ANSI_COLORS[0]);
|
|
this.colors.ansi[1] = this._validateColor(theme.red, DEFAULT_ANSI_COLORS[1]);
|
|
this.colors.ansi[2] = this._validateColor(theme.green, DEFAULT_ANSI_COLORS[2]);
|
|
this.colors.ansi[3] = this._validateColor(theme.yellow, DEFAULT_ANSI_COLORS[3]);
|
|
this.colors.ansi[4] = this._validateColor(theme.blue, DEFAULT_ANSI_COLORS[4]);
|
|
this.colors.ansi[5] = this._validateColor(theme.magenta, DEFAULT_ANSI_COLORS[5]);
|
|
this.colors.ansi[6] = this._validateColor(theme.cyan, DEFAULT_ANSI_COLORS[6]);
|
|
this.colors.ansi[7] = this._validateColor(theme.white, DEFAULT_ANSI_COLORS[7]);
|
|
this.colors.ansi[8] = this._validateColor(theme.brightBlack, DEFAULT_ANSI_COLORS[8]);
|
|
this.colors.ansi[9] = this._validateColor(theme.brightRed, DEFAULT_ANSI_COLORS[9]);
|
|
this.colors.ansi[10] = this._validateColor(theme.brightGreen, DEFAULT_ANSI_COLORS[10]);
|
|
this.colors.ansi[11] = this._validateColor(theme.brightYellow, DEFAULT_ANSI_COLORS[11]);
|
|
this.colors.ansi[12] = this._validateColor(theme.brightBlue, DEFAULT_ANSI_COLORS[12]);
|
|
this.colors.ansi[13] = this._validateColor(theme.brightMagenta, DEFAULT_ANSI_COLORS[13]);
|
|
this.colors.ansi[14] = this._validateColor(theme.brightCyan, DEFAULT_ANSI_COLORS[14]);
|
|
this.colors.ansi[15] = this._validateColor(theme.brightWhite, DEFAULT_ANSI_COLORS[15]);
|
|
}
|
|
|
|
private _validateColor(color: string, fallback: string): string {
|
|
if (!color) {
|
|
return fallback;
|
|
}
|
|
|
|
const isColorValid = this._isColorValid(color);
|
|
|
|
if (!isColorValid) {
|
|
console.warn(`Color: ${color} is invalid using fallback ${fallback}`);
|
|
}
|
|
|
|
return isColorValid ? color : fallback;
|
|
}
|
|
|
|
private _isColorValid(color: string): boolean {
|
|
const litmus = 'red';
|
|
const d = this._document.createElement('div');
|
|
d.style.color = litmus;
|
|
d.style.color = color;
|
|
|
|
// Element's style.color will be reverted to litmus or set to '' if an invalid color is given
|
|
if (color !== litmus && (d.style.color === litmus || d.style.color === '')) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|