531 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			531 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /**
 | |
|  * colors.js - color-related functions for blessed.
 | |
|  * Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
 | |
|  * https://github.com/chjj/blessed
 | |
|  */
 | |
| 
 | |
| exports.match = function(r1, g1, b1) {
 | |
|   if (typeof r1 === 'string') {
 | |
|     var hex = r1;
 | |
|     if (hex[0] !== '#') {
 | |
|       return -1;
 | |
|     }
 | |
|     hex = exports.hexToRGB(hex);
 | |
|     r1 = hex[0], g1 = hex[1], b1 = hex[2];
 | |
|   } else if (Array.isArray(r1)) {
 | |
|     b1 = r1[2], g1 = r1[1], r1 = r1[0];
 | |
|   }
 | |
| 
 | |
|   var hash = (r1 << 16) | (g1 << 8) | b1;
 | |
| 
 | |
|   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];
 | |
| 
 | |
|     diff = colorDistance(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) {
 | |
|   if (hex.length === 4) {
 | |
|     hex = hex[0]
 | |
|       + hex[1] + hex[1]
 | |
|       + hex[2] + hex[2]
 | |
|       + hex[3] + hex[3];
 | |
|   }
 | |
| 
 | |
|   var col = parseInt(hex.substring(1), 16)
 | |
|     , r = (col >> 16) & 0xff
 | |
|     , g = (col >> 8) & 0xff
 | |
|     , b = col & 0xff;
 | |
| 
 | |
|   return [r, g, b];
 | |
| };
 | |
| 
 | |
| // 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[1]. Maybe someone better at math can
 | |
| // propose a superior solution.
 | |
| // [1] http://stackoverflow.com/questions/1633828
 | |
| 
 | |
| function colorDistance(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);
 | |
| }
 | |
| 
 | |
| // This might work well enough for a terminal's colors: treat RGB as XYZ in a
 | |
| // 3-dimensional space and go midway between the two points.
 | |
| exports.mixColors = function(c1, c2, alpha) {
 | |
|   // if (c1 === 0x1ff) return c1;
 | |
|   // if (c2 === 0x1ff) return c1;
 | |
|   if (c1 === 0x1ff) c1 = 0;
 | |
|   if (c2 === 0x1ff) c2 = 0;
 | |
|   if (alpha == null) alpha = 0.5;
 | |
| 
 | |
|   c1 = exports.vcolors[c1];
 | |
|   var r1 = c1[0];
 | |
|   var g1 = c1[1];
 | |
|   var b1 = c1[2];
 | |
| 
 | |
|   c2 = exports.vcolors[c2];
 | |
|   var r2 = c2[0];
 | |
|   var g2 = c2[1];
 | |
|   var b2 = c2[2];
 | |
| 
 | |
|   r1 += (r2 - r1) * alpha | 0;
 | |
|   g1 += (g2 - g1) * alpha | 0;
 | |
|   b1 += (b2 - b1) * alpha | 0;
 | |
| 
 | |
|   return exports.match([r1, g1, b1]);
 | |
| };
 | |
| 
 | |
| exports.blend = function blend(attr, attr2, alpha) {
 | |
|   var name, i, c, nc;
 | |
| 
 | |
|   var bg = attr & 0x1ff;
 | |
|   if (attr2 != null) {
 | |
|     var bg2 = attr2 & 0x1ff;
 | |
|     if (bg === 0x1ff) bg = 0;
 | |
|     if (bg2 === 0x1ff) bg2 = 0;
 | |
|     bg = exports.mixColors(bg, bg2, alpha);
 | |
|   } else {
 | |
|     if (blend._cache[bg] != null) {
 | |
|       bg = blend._cache[bg];
 | |
|     // } else if (bg < 8) {
 | |
|     //   bg += 8;
 | |
|     } else if (bg >= 8 && bg <= 15) {
 | |
|       bg -= 8;
 | |
|     } else {
 | |
|       name = exports.ncolors[bg];
 | |
|       if (name) {
 | |
|         for (i = 0; i < exports.ncolors.length; i++) {
 | |
|           if (name === exports.ncolors[i] && i !== bg) {
 | |
|             c = exports.vcolors[bg];
 | |
|             nc = exports.vcolors[i];
 | |
|             if (nc[0] + nc[1] + nc[2] < c[0] + c[1] + c[2]) {
 | |
|               blend._cache[bg] = i;
 | |
|               bg = i;
 | |
|               break;
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   attr &= ~0x1ff;
 | |
|   attr |= bg;
 | |
| 
 | |
|   var fg = (attr >> 9) & 0x1ff;
 | |
|   if (attr2 != null) {
 | |
|     var fg2 = (attr2 >> 9) & 0x1ff;
 | |
|     // 0, 7, 188, 231, 251
 | |
|     if (fg === 0x1ff) {
 | |
|       // XXX workaround
 | |
|       fg = 248;
 | |
|     } else {
 | |
|       if (fg === 0x1ff) fg = 7;
 | |
|       if (fg2 === 0x1ff) fg2 = 7;
 | |
|       fg = exports.mixColors(fg, fg2, alpha);
 | |
|     }
 | |
|   } else {
 | |
|     if (blend._cache[fg] != null) {
 | |
|       fg = blend._cache[fg];
 | |
|     // } else if (fg < 8) {
 | |
|     //   fg += 8;
 | |
|     } else if (fg >= 8 && fg <= 15) {
 | |
|       fg -= 8;
 | |
|     } else {
 | |
|       name = exports.ncolors[fg];
 | |
|       if (name) {
 | |
|         for (i = 0; i < exports.ncolors.length; i++) {
 | |
|           if (name === exports.ncolors[i] && i !== fg) {
 | |
|             c = exports.vcolors[fg];
 | |
|             nc = exports.vcolors[i];
 | |
|             if (nc[0] + nc[1] + nc[2] < c[0] + c[1] + c[2]) {
 | |
|               blend._cache[fg] = i;
 | |
|               fg = i;
 | |
|               break;
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   attr &= ~(0x1ff << 9);
 | |
|   attr |= fg << 9;
 | |
| 
 | |
|   return attr;
 | |
| };
 | |
| 
 | |
| exports.blend._cache = {};
 | |
| 
 | |
| exports._cache = {};
 | |
| 
 | |
| exports.reduce = function(color, total) {
 | |
|   if (color >= 16 && total <= 16) {
 | |
|     color = exports.ccolors[color];
 | |
|   } else if (color >= 8 && total <= 8) {
 | |
|     color -= 8;
 | |
|   } else if (color >= 2 && total <= 2) {
 | |
|     color %= 2;
 | |
|   }
 | |
|   return color;
 | |
| };
 | |
| 
 | |
| // 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.
 | |
| 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.
 | |
| // Ported from the xterm color generation script.
 | |
| 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.match);
 | |
| 
 | |
|   exports.colors = cols;
 | |
|   exports.vcolors = _cols;
 | |
|   exports.ccolors = out;
 | |
| 
 | |
|   return out;
 | |
| })();
 | |
| 
 | |
| var colorNames = exports.colorNames = {
 | |
|   // special
 | |
|   default: -1,
 | |
|   normal: -1,
 | |
|   bg: -1,
 | |
|   fg: -1,
 | |
|   // normal
 | |
|   black: 0,
 | |
|   red: 1,
 | |
|   green: 2,
 | |
|   yellow: 3,
 | |
|   blue: 4,
 | |
|   magenta: 5,
 | |
|   cyan: 6,
 | |
|   white: 7,
 | |
|   // light
 | |
|   lightblack: 8,
 | |
|   lightred: 9,
 | |
|   lightgreen: 10,
 | |
|   lightyellow: 11,
 | |
|   lightblue: 12,
 | |
|   lightmagenta: 13,
 | |
|   lightcyan: 14,
 | |
|   lightwhite: 15,
 | |
|   // bright
 | |
|   brightblack: 8,
 | |
|   brightred: 9,
 | |
|   brightgreen: 10,
 | |
|   brightyellow: 11,
 | |
|   brightblue: 12,
 | |
|   brightmagenta: 13,
 | |
|   brightcyan: 14,
 | |
|   brightwhite: 15,
 | |
|   // alternate spellings
 | |
|   grey: 8,
 | |
|   gray: 8,
 | |
|   lightgrey: 7,
 | |
|   lightgray: 7,
 | |
|   brightgrey: 7,
 | |
|   brightgray: 7
 | |
| };
 | |
| 
 | |
| exports.convert = function(color) {
 | |
|   if (typeof color === 'number') {
 | |
|     ;
 | |
|   } else if (typeof color === 'string') {
 | |
|     color = color.replace(/[\- ]/g, '');
 | |
|     if (colorNames[color] != null) {
 | |
|       color = colorNames[color];
 | |
|     } else {
 | |
|       color = exports.match(color);
 | |
|     }
 | |
|   } else if (Array.isArray(color)) {
 | |
|     color = exports.match(color);
 | |
|   } else {
 | |
|     color = -1;
 | |
|   }
 | |
|   return color !== -1 ? color : 0x1ff;
 | |
| };
 | |
| 
 | |
| // Map higher colors to the first 8 colors.
 | |
| // This allows translation of high colors to low colors on 8-color terminals.
 | |
| // Why the hell did I do this by hand?
 | |
| 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]
 | |
|   ]
 | |
| };
 | |
| 
 | |
| exports.ncolors = [];
 | |
| 
 | |
| Object.keys(exports.ccolors).forEach(function(name) {
 | |
|   exports.ccolors[name].forEach(function(offset) {
 | |
|     if (typeof offset === 'number') {
 | |
|       exports.ncolors[offset] = name;
 | |
|       exports.ccolors[offset] = exports.colorNames[name];
 | |
|       return;
 | |
|     }
 | |
|     for (var i = offset[0], l = offset[1]; i <= l; i++) {
 | |
|       exports.ncolors[i] = name;
 | |
|       exports.ccolors[i] = exports.colorNames[name];
 | |
|     }
 | |
|   });
 | |
|   delete exports.ccolors[name];
 | |
| });
 |