2013-06-16 15:13:39 +00:00
|
|
|
/**
|
|
|
|
* Colors
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Try to match a hex code to a terminal color as best as possible.
|
2013-07-14 11:57:15 +00:00
|
|
|
// This entire function assumes the terminal user is using the
|
|
|
|
// default xterm colors.
|
2013-07-16 05:18:31 +00:00
|
|
|
exports.matchColor = function(hex) {
|
|
|
|
if (hex[0] !== '#') {
|
|
|
|
return hex;
|
2013-07-14 11:57:15 +00:00
|
|
|
}
|
|
|
|
|
2013-07-16 05:18:31 +00:00
|
|
|
if (hex.length === 4) {
|
|
|
|
hex = hex[0]
|
|
|
|
+ hex[1] + hex[1]
|
|
|
|
+ hex[2] + hex[2]
|
|
|
|
+ hex[3] + hex[3];
|
2013-07-14 11:57:15 +00:00
|
|
|
}
|
2013-06-16 15:13:39 +00:00
|
|
|
|
2013-07-16 05:18:31 +00:00
|
|
|
if (exports._cache[hex] != null) {
|
|
|
|
return exports._cache[hex];
|
2013-06-16 15:13:39 +00:00
|
|
|
}
|
|
|
|
|
2013-07-16 05:18:31 +00:00
|
|
|
var col = parseInt(hex.substring(1), 16)
|
|
|
|
, r1 = (col >> 16) & 0xff
|
|
|
|
, g1 = (col >> 8) & 0xff
|
|
|
|
, b1 = col & 0xff
|
2013-06-16 15:13:39 +00:00
|
|
|
, ldiff = Infinity
|
|
|
|
, li = -1
|
|
|
|
, i = 0
|
|
|
|
, c
|
2013-07-16 05:18:31 +00:00
|
|
|
, r2
|
|
|
|
, g2
|
|
|
|
, b2
|
2013-06-16 15:13:39 +00:00
|
|
|
, diff;
|
|
|
|
|
|
|
|
for (; i < exports.vcolors.length; i++) {
|
|
|
|
c = exports.vcolors[i];
|
2013-07-16 05:18:31 +00:00
|
|
|
r2 = c[0];
|
|
|
|
g2 = c[1];
|
|
|
|
b2 = c[2];
|
2013-06-16 15:13:39 +00:00
|
|
|
|
2013-07-16 05:18:31 +00:00
|
|
|
if (r1 === r2 && g1 === g2 && b1 === b2) {
|
|
|
|
diff = 0;
|
|
|
|
} else {
|
|
|
|
// diff = colorDistance3d(r1, g1, b1, r2, g2, b2);
|
|
|
|
diff = colorDistance3dWeight(r1, g1, b1, r2, g2, b2);
|
|
|
|
// diff = colorDistance3dWeightSqrt(r1, g1, b1, r2, g2, b2);
|
|
|
|
}
|
2013-06-16 15:13:39 +00:00
|
|
|
|
|
|
|
if (diff === 0) {
|
|
|
|
li = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (diff < ldiff) {
|
|
|
|
ldiff = diff;
|
|
|
|
li = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-16 05:18:31 +00:00
|
|
|
return exports._cache[hex] = li;
|
2013-06-16 15:13:39 +00:00
|
|
|
};
|
|
|
|
|
2013-07-22 04:53:10 +00:00
|
|
|
exports.matchColor_ = function(r1, g1, b1) {
|
2013-07-22 05:51:39 +00:00
|
|
|
if (typeof r1 === 'string') {
|
2013-07-22 04:53:10 +00:00
|
|
|
var hex = r1;
|
|
|
|
if (hex[0] !== '#') {
|
|
|
|
return hex;
|
|
|
|
}
|
|
|
|
if (hex.length === 4) {
|
|
|
|
hex = hex[0]
|
|
|
|
+ hex[1] + hex[1]
|
|
|
|
+ hex[2] + hex[2]
|
|
|
|
+ hex[3] + hex[3];
|
|
|
|
}
|
2013-07-22 05:51:39 +00:00
|
|
|
hex = exports.hexToRGB(hex);
|
2013-07-22 04:53:10 +00:00
|
|
|
r1 = hex[0], g1 = hex[1], b1 = hex[2];
|
|
|
|
}
|
|
|
|
|
2013-07-22 05:51:39 +00:00
|
|
|
var hash = (r1 << 16) | (g1 << 8) | b1;
|
2013-07-22 04:53:10 +00:00
|
|
|
|
|
|
|
if (exports._cache[hash] != null) {
|
|
|
|
return exports._cache[hash];
|
|
|
|
}
|
|
|
|
|
|
|
|
var ldiff = Infinity
|
|
|
|
, li = -1
|
|
|
|
, i = 0
|
|
|
|
, c
|
|
|
|
, r2
|
|
|
|
, g2
|
|
|
|
, b2
|
|
|
|
, diff;
|
|
|
|
|
|
|
|
for (; i < exports.vcolors.length; i++) {
|
|
|
|
c = exports.vcolors[i];
|
|
|
|
r2 = c[0];
|
|
|
|
g2 = c[1];
|
|
|
|
b2 = c[2];
|
|
|
|
|
|
|
|
if (r1 === r2 && g1 === g2 && b1 === b2) {
|
|
|
|
diff = 0;
|
|
|
|
} else {
|
|
|
|
// diff = colorDistance3d(r1, g1, b1, r2, g2, b2);
|
|
|
|
diff = colorDistance3dWeight(r1, g1, b1, r2, g2, b2);
|
|
|
|
// diff = colorDistance3dWeightSqrt(r1, g1, b1, r2, g2, b2);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (diff === 0) {
|
|
|
|
li = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (diff < ldiff) {
|
|
|
|
ldiff = diff;
|
|
|
|
li = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return exports._cache[hash] = li;
|
|
|
|
};
|
|
|
|
|
|
|
|
exports.RGBToHex = function(r, g, b) {
|
|
|
|
if (Array.isArray(r)) b = r[2], g = r[1], r = r[0];
|
|
|
|
|
|
|
|
function hex(n) {
|
|
|
|
n = n.toString(16);
|
|
|
|
if (n.length < 2) n = '0' + n;
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
return '#' + hex(r) + hex(g) + hex(b);
|
|
|
|
};
|
|
|
|
|
|
|
|
exports.hexToRGB = function(hex) {
|
|
|
|
var col = parseInt(hex.substring(1), 16)
|
|
|
|
, r = (col >> 16) & 0xff
|
|
|
|
, g = (col >> 8) & 0xff
|
|
|
|
, b = col & 0xff;
|
|
|
|
|
|
|
|
return [r, g, b];
|
|
|
|
};
|
|
|
|
|
2013-07-16 05:18:31 +00:00
|
|
|
// As it happens, comparing how similar two colors are is really hard. Here is
|
|
|
|
// one of the simplest solutions, which doesn't require conversion to another
|
|
|
|
// color space, posted on stackoverflow. Maybe someone better at math can
|
|
|
|
// propose a superior solution.
|
|
|
|
|
|
|
|
// http://stackoverflow.com/questions/9018016
|
|
|
|
function colorDistance3d(r1, g1, b1, r2, g2, b2) {
|
|
|
|
var d;
|
|
|
|
|
|
|
|
d = Math.sqrt(
|
|
|
|
Math.pow(r2 - r1, 2)
|
|
|
|
+ Math.pow(g2 - g1, 2)
|
|
|
|
+ Math.pow(b2 - b1, 2));
|
|
|
|
|
|
|
|
d /= Math.sqrt(
|
|
|
|
Math.pow(255, 2)
|
|
|
|
+ Math.pow(255, 2)
|
|
|
|
+ Math.pow(255, 2));
|
|
|
|
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
|
|
|
// http://stackoverflow.com/questions/1633828
|
|
|
|
function colorDistance3dWeight(r1, g1, b1, r2, g2, b2) {
|
|
|
|
return Math.pow(30 * (r1 - r2), 2)
|
|
|
|
+ Math.pow(59 * (g1 - g2), 2)
|
|
|
|
+ Math.pow(11 * (b1 - b2), 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
function colorDistance3dWeightSqrt(r1, g1, b1, r2, g2, b2) {
|
|
|
|
var d;
|
|
|
|
|
|
|
|
d = Math.sqrt(
|
|
|
|
Math.pow(30 * (r2 - r1), 2)
|
|
|
|
+ Math.pow(59 * (g2 - g1), 2)
|
|
|
|
+ Math.pow(11 * (b2 - b1), 2));
|
|
|
|
|
|
|
|
d /= Math.sqrt(
|
|
|
|
Math.pow(255, 2)
|
|
|
|
+ Math.pow(255, 2)
|
|
|
|
+ Math.pow(255, 2));
|
|
|
|
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
2013-06-24 11:16:02 +00:00
|
|
|
exports._cache = {};
|
|
|
|
|
2013-07-03 23:46:06 +00:00
|
|
|
// XTerm Colors
|
|
|
|
// These were actually tough to track down. The xterm source only uses color
|
|
|
|
// keywords. The X11 source needed to be examined to find the actual values.
|
|
|
|
// They then had to be mapped to rgb values and then converted to hex values.
|
2013-06-16 15:13:39 +00:00
|
|
|
exports.xterm = [
|
|
|
|
'#000000', // black
|
|
|
|
'#cd0000', // red3
|
|
|
|
'#00cd00', // green3
|
|
|
|
'#cdcd00', // yellow3
|
|
|
|
'#0000ee', // blue2
|
|
|
|
'#cd00cd', // magenta3
|
|
|
|
'#00cdcd', // cyan3
|
|
|
|
'#e5e5e5', // gray90
|
|
|
|
'#7f7f7f', // gray50
|
|
|
|
'#ff0000', // red
|
|
|
|
'#00ff00', // green
|
|
|
|
'#ffff00', // yellow
|
|
|
|
'#5c5cff', // rgb:5c/5c/ff
|
|
|
|
'#ff00ff', // magenta
|
|
|
|
'#00ffff', // cyan
|
|
|
|
'#ffffff' // white
|
|
|
|
];
|
|
|
|
|
|
|
|
// Seed all 256 colors. Assume xterm defaults.
|
2013-07-03 23:46:06 +00:00
|
|
|
// Ported from the xterm color generation script.
|
2013-06-16 15:13:39 +00:00
|
|
|
exports.colors = (function() {
|
|
|
|
var cols = exports.colors = []
|
|
|
|
, _cols = exports.vcolors = []
|
|
|
|
, r
|
|
|
|
, g
|
|
|
|
, b
|
|
|
|
, i
|
|
|
|
, l;
|
|
|
|
|
|
|
|
function hex(n) {
|
|
|
|
n = n.toString(16);
|
|
|
|
if (n.length < 2) n = '0' + n;
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
function push(i, r, g, b) {
|
|
|
|
cols[i] = '#' + hex(r) + hex(g) + hex(b);
|
|
|
|
_cols[i] = [r, g, b];
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0 - 15
|
|
|
|
exports.xterm.forEach(function(c, i) {
|
|
|
|
c = parseInt(c.substring(1), 16);
|
|
|
|
push(i, (c >> 16) & 0xff, (c >> 8) & 0xff, c & 0xff);
|
|
|
|
});
|
|
|
|
|
|
|
|
// 16 - 231
|
|
|
|
for (r = 0; r < 6; r++) {
|
|
|
|
for (g = 0; g < 6; g++) {
|
|
|
|
for (b = 0; b < 6; b++) {
|
|
|
|
i = 16 + (r * 36) + (g * 6) + b;
|
|
|
|
push(i,
|
|
|
|
r ? (r * 40 + 55) : 0,
|
|
|
|
g ? (g * 40 + 55) : 0,
|
|
|
|
b ? (b * 40 + 55) : 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 232 - 255 are grey.
|
|
|
|
for (g = 0; g < 24; g++) {
|
|
|
|
l = (g * 10) + 8;
|
|
|
|
i = 232 + g;
|
|
|
|
push(i, l, l, l);
|
|
|
|
}
|
|
|
|
|
|
|
|
return cols;
|
|
|
|
})();
|
|
|
|
|
|
|
|
// Map higher colors to the first 8 colors.
|
|
|
|
// This allows translation of high colors to low colors on 8-color terminals.
|
|
|
|
exports.ccolors = (function() {
|
|
|
|
var _cols = exports.vcolors.slice()
|
|
|
|
, cols = exports.colors.slice()
|
|
|
|
, out;
|
|
|
|
|
|
|
|
exports.vcolors = exports.vcolors.slice(0, 8);
|
|
|
|
exports.colors = exports.colors.slice(0, 8);
|
|
|
|
|
|
|
|
out = cols.map(exports.matchColor);
|
|
|
|
|
|
|
|
exports.colors = cols;
|
|
|
|
exports.vcolors = _cols;
|
|
|
|
exports.ccolors = out;
|
|
|
|
|
|
|
|
return out;
|
|
|
|
})();
|
|
|
|
|
|
|
|
var colorNames = exports.colorNames = {
|
|
|
|
default: -1,
|
2013-07-14 11:57:15 +00:00
|
|
|
normal: -1,
|
2013-06-16 15:13:39 +00:00
|
|
|
bg: -1,
|
|
|
|
fg: -1,
|
|
|
|
black: 0,
|
|
|
|
red: 1,
|
|
|
|
green: 2,
|
|
|
|
yellow: 3,
|
|
|
|
blue: 4,
|
|
|
|
magenta: 5,
|
|
|
|
cyan: 6,
|
|
|
|
white: 7,
|
|
|
|
lightblack: 8,
|
|
|
|
lightred: 9,
|
|
|
|
lightgreen: 10,
|
|
|
|
lightyellow: 11,
|
|
|
|
lightblue: 12,
|
|
|
|
lightmagenta: 13,
|
|
|
|
lightcyan: 14,
|
|
|
|
lightwhite: 15
|
|
|
|
};
|
|
|
|
|
|
|
|
//Object.keys(colorNames).forEach(function(name) {
|
|
|
|
// colorNames[colorNames[name]] = name;
|
|
|
|
//});
|
|
|
|
|
|
|
|
exports.convert = function(color) {
|
2013-07-14 11:43:17 +00:00
|
|
|
if (typeof color === 'string') {
|
|
|
|
color = color.replace(/[\- ]/g, '');
|
|
|
|
}
|
|
|
|
|
2013-06-16 15:13:39 +00:00
|
|
|
var val = colorNames[color];
|
2013-07-14 11:43:17 +00:00
|
|
|
|
2013-06-16 15:13:39 +00:00
|
|
|
if (val == null) val = color;
|
2013-07-14 11:43:17 +00:00
|
|
|
|
2013-06-16 15:13:39 +00:00
|
|
|
if (val == null) val = -1;
|
2013-07-14 11:43:17 +00:00
|
|
|
|
2013-06-16 15:13:39 +00:00
|
|
|
if (typeof val === 'string') {
|
2013-07-14 11:43:17 +00:00
|
|
|
val = val[0] === '#'
|
|
|
|
? exports.matchColor(val)
|
|
|
|
: -1;
|
2013-06-16 15:13:39 +00:00
|
|
|
}
|
2013-07-14 11:43:17 +00:00
|
|
|
|
2013-06-16 15:13:39 +00:00
|
|
|
if (val === -1) return 0x1ff;
|
2013-07-14 11:43:17 +00:00
|
|
|
|
2013-06-16 15:13:39 +00:00
|
|
|
return val;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Map higher colors to the first 8 colors.
|
|
|
|
// This allows translation of high colors to low colors on 8-color terminals.
|
2013-07-03 23:46:06 +00:00
|
|
|
// Why the hell did I do this by hand?
|
2013-06-16 15:13:39 +00:00
|
|
|
exports.ccolors = {
|
|
|
|
blue: [
|
|
|
|
4,
|
|
|
|
12,
|
|
|
|
[17, 21],
|
|
|
|
[24, 27],
|
|
|
|
[31, 33],
|
|
|
|
[38, 39],
|
|
|
|
45,
|
|
|
|
[54, 57],
|
|
|
|
[60, 63],
|
|
|
|
[67, 69],
|
|
|
|
[74, 75],
|
|
|
|
81,
|
|
|
|
[91, 93],
|
|
|
|
[97, 99],
|
|
|
|
[103, 105],
|
|
|
|
[110, 111],
|
|
|
|
117,
|
|
|
|
[128, 129],
|
|
|
|
[134, 135],
|
|
|
|
[140, 141],
|
|
|
|
[146, 147],
|
|
|
|
153,
|
|
|
|
165,
|
|
|
|
171,
|
|
|
|
177,
|
|
|
|
183,
|
|
|
|
189
|
|
|
|
],
|
|
|
|
|
|
|
|
green: [
|
|
|
|
2,
|
|
|
|
10,
|
|
|
|
22,
|
|
|
|
[28, 29],
|
|
|
|
[34, 36],
|
|
|
|
[40, 43],
|
|
|
|
[46, 50],
|
|
|
|
[64, 65],
|
|
|
|
[70, 72],
|
|
|
|
[76, 79],
|
|
|
|
[82, 86],
|
|
|
|
[106, 108],
|
|
|
|
[112, 115],
|
|
|
|
[118, 122],
|
|
|
|
[148, 151],
|
|
|
|
[154, 158],
|
|
|
|
[190, 194]
|
|
|
|
],
|
|
|
|
|
|
|
|
cyan: [
|
|
|
|
6,
|
|
|
|
14,
|
|
|
|
23,
|
|
|
|
30,
|
|
|
|
37,
|
|
|
|
44,
|
|
|
|
51,
|
|
|
|
66,
|
|
|
|
73,
|
|
|
|
80,
|
|
|
|
87,
|
|
|
|
109,
|
|
|
|
116,
|
|
|
|
123,
|
|
|
|
152,
|
|
|
|
159,
|
|
|
|
195
|
|
|
|
],
|
|
|
|
|
|
|
|
red: [
|
|
|
|
1,
|
|
|
|
9,
|
|
|
|
52,
|
|
|
|
[88, 89],
|
|
|
|
[94, 95],
|
|
|
|
[124, 126],
|
|
|
|
[130, 132],
|
|
|
|
[136, 138],
|
|
|
|
[160, 163],
|
|
|
|
[166, 169],
|
|
|
|
[172, 175],
|
|
|
|
[178, 181],
|
|
|
|
[196, 200],
|
|
|
|
[202, 206],
|
|
|
|
[208, 212],
|
|
|
|
[214, 218],
|
|
|
|
[220, 224]
|
|
|
|
],
|
|
|
|
|
|
|
|
magenta: [
|
|
|
|
5,
|
|
|
|
13,
|
|
|
|
53,
|
|
|
|
90,
|
|
|
|
96,
|
|
|
|
127,
|
|
|
|
133,
|
|
|
|
139,
|
|
|
|
164,
|
|
|
|
170,
|
|
|
|
176,
|
|
|
|
182,
|
|
|
|
201,
|
|
|
|
207,
|
|
|
|
213,
|
|
|
|
219,
|
|
|
|
225
|
|
|
|
],
|
|
|
|
|
|
|
|
yellow: [
|
|
|
|
3,
|
|
|
|
11,
|
|
|
|
58,
|
|
|
|
[100, 101],
|
|
|
|
[142, 144],
|
|
|
|
[184, 187],
|
|
|
|
[226, 230]
|
|
|
|
],
|
|
|
|
|
|
|
|
black: [
|
|
|
|
0,
|
|
|
|
8,
|
|
|
|
16,
|
|
|
|
59,
|
|
|
|
102,
|
|
|
|
[232, 243]
|
|
|
|
],
|
|
|
|
|
|
|
|
white: [
|
|
|
|
7,
|
|
|
|
15,
|
|
|
|
145,
|
|
|
|
188,
|
|
|
|
231,
|
|
|
|
[244, 255]
|
|
|
|
]
|
|
|
|
};
|
|
|
|
|
|
|
|
Object.keys(exports.ccolors).forEach(function(name) {
|
|
|
|
exports.ccolors[name].forEach(function(offset) {
|
|
|
|
if (typeof offset === 'number') {
|
2013-06-16 15:16:34 +00:00
|
|
|
exports.ccolors[offset] = exports.colorNames[name];
|
2013-06-16 15:13:39 +00:00
|
|
|
return;
|
|
|
|
}
|
2013-06-24 11:16:02 +00:00
|
|
|
for (var i = offset[0], l = offset[1]; i <= l; i++) {
|
|
|
|
exports.ccolors[i] = exports.colorNames[name];
|
|
|
|
}
|
2013-06-16 15:13:39 +00:00
|
|
|
});
|
|
|
|
delete exports.ccolors[name];
|
|
|
|
});
|