>From 46c0f5f7ca39f19c8c7835d2d60e01fa248363c0 Mon Sep 17 00:00:00 2001
From: Brand Huntsman
Date: Fri, 19 Jan 2018 03:56:54 -0700
Subject: [PATCH 3/4] RGB colors
Signed-off-by: Brand Huntsman
---
src/color.c | 167 +++++++++++++++++++++++++++++++++++++++++++++++++++
src/proto.h | 1 +
src/rcfile.c | 39 ++++++++++++
syntax/nanorc.nanorc | 4 +-
4 files changed, 209 insertions(+), 2 deletions(-)
diff --git a/src/color.c b/src/color.c
index 67f9359c..f7d5bad3 100644
--- a/src/color.c
+++ b/src/color.c
@@ -28,6 +28,7 @@
#include
#include
#include
+#include
#ifdef ENABLE_COLOR
@@ -431,6 +432,76 @@ void precalc_multicolorinfo(void)
}
}
+static int color_cube_size_squared;
+ /* Number of colors per cube face. */
+static int color_cube_size;
+ /* Number of colors per cube row. */
+static unsigned char gray_lut[256];
+ /* Grayscale lookup table. */
+static unsigned char color_lut[256];
+ /* Color lookup table.
+ * Channel intensity = 0 to (color_cube_size-1). */
+static unsigned char *low_color_cube;
+ /* Color cube to map extended colors to 8/16-color terminals. */
+static unsigned char _low_color_cube[125] = {
+ /* black0, red1, green2, yellow3, blue4, magenta5, cyan6, white7
+ * black8, red9, green10, yellow11, blue12, magenta13, cyan14, white15 */
+
+ /*000*/ 0, /*001*/ 0, /*002*/ 4, /*003*/ 4, /*004*/12,
+ /*010*/ 0, /*011*/ 8, /*012*/ 4, /*013*/ 4, /*014*/12,
+ /*020*/ 2, /*021*/ 2, /*022*/ 6, /*023*/ 6, /*024*/12,
+ /*030*/ 2, /*031*/ 2, /*032*/ 6, /*033*/ 6, /*034*/14,
+ /*040*/10, /*041*/10, /*042*/10, /*043*/14, /*044*/14,
+
+ /*100*/ 0, /*101*/ 8, /*102*/ 4, /*103*/ 4, /*104*/12,
+ /*110*/ 8, /*111*/ 8, /*112*/ 4, /*113*/ 4, /*114*/12,
+ /*120*/ 2, /*121*/ 2, /*122*/ 6, /*123*/ 6, /*124*/12,
+ /*130*/ 2, /*131*/ 2, /*132*/ 6, /*133*/ 6, /*134*/14,
+ /*140*/10, /*141*/10, /*142*/10, /*143*/14, /*144*/14,
+
+ /*200*/ 1, /*201*/ 1, /*202*/ 5, /*203*/ 5, /*204*/12,
+ /*210*/ 1, /*211*/ 1, /*212*/ 5, /*213*/ 5, /*214*/12,
+ /*220*/ 3, /*221*/ 3, /*222*/ 7, /*223*/ 7, /*224*/12,
+ /*230*/ 3, /*231*/ 3, /*232*/ 7, /*233*/ 7, /*234*/14,
+ /*240*/10, /*241*/10, /*242*/10, /*243*/14, /*244*/14,
+
+ /*300*/ 1, /*301*/ 1, /*302*/ 5, /*303*/ 5, /*304*/13,
+ /*310*/ 1, /*311*/ 1, /*312*/ 5, /*313*/ 5, /*314*/13,
+ /*320*/ 3, /*321*/ 3, /*322*/ 7, /*323*/ 7, /*324*/13,
+ /*330*/ 3, /*331*/ 3, /*332*/ 7, /*333*/ 7, /*334*/15,
+ /*340*/11, /*341*/11, /*342*/11, /*343*/15, /*344*/15,
+
+ /*400*/ 9, /*401*/ 9, /*402*/ 9, /*403*/13, /*404*/13,
+ /*410*/ 9, /*411*/ 9, /*412*/ 9, /*413*/13, /*414*/13,
+ /*420*/ 9, /*421*/ 9, /*422*/ 9, /*423*/13, /*424*/13,
+ /*430*/11, /*431*/11, /*432*/11, /*433*/15, /*434*/15,
+ /*440*/11, /*441*/11, /*442*/11, /*443*/15, /*444*/15,
+};
+
+/* Initialize the gray or color lookup table. */
+static void init_lut(int size, unsigned char lut[256],
+ unsigned char shades[], unsigned char g_codes[])
+{
+ if(g_codes == NULL)
+ color_cube_size = size;
+
+ /* Get index of each mid-point. */
+ int prev_index = 0;
+ for (int i = 0; i < (size-1); i++) {
+ float s = round(1000 * shades[i+0] / 255) / 1000;
+ float e = round(1000 * shades[i+1] / 255) / 1000;
+ int index = 255 * ((e - s)/2 + s);
+ /* Fill lookup table with g_codes or channel intensity. */
+ for (int ii = prev_index; ii <= index; ii++)
+ lut[ii] = (g_codes != NULL ? g_codes[i] : i);
+ prev_index = index+1;
+ }
+ /* Fill lookup table with g_codes or channel intensity.
+ * From last mid-point to 255. */
+ for (int ii = prev_index; ii <= 255; ii++)
+ lut[ii] = (g_codes != NULL ? g_codes[size-1] : size-1);
+}
+
#if defined(NCURSES_VERSION_MAJOR) && (NCURSES_VERSION_MAJOR >= 6)
#define HAS_EXTENDED_COLORS 1
#else
@@ -462,6 +533,102 @@ void extended_color_init(void)
nr_term_colors = 8;
} else if (nr_term_colors != 8)
nr_term_colors = 0;
+
+ /* Initialize lookup tables. */
+ switch (nr_term_colors) {
+ case 256:
+ {
+ unsigned char g_codes[30] = {
+ 16, 232, 233, 234, 235, 236, 237, 238, 239, 240,
+ 59, 241, 242, 243, 244, 102, 245, 246, 247, 248,
+ 145, 249, 250, 251, 252, 188, 253, 254, 255, 231
+ };
+ unsigned char g_shades[30] = {
+ 0, 8, 18, 28, 38, 48, 58, 68, 78, 88,
+ 95, 98, 108, 118, 128, 135, 138, 148, 158, 168,
+ 175, 178, 188, 198, 208, 215, 218, 228, 238, 255
+ };
+ init_lut(30, gray_lut, g_shades, g_codes);
+
+ unsigned char c_shades[6] = {0, 94, 135, 176, 214, 255};
+ init_lut(6, color_lut, c_shades, NULL);
+ low_color_cube = NULL;
+
+ break;
+ }
+ case 88:
+ {
+ /* Code 37 is identical to code 83, only use 83. */
+ unsigned char g_codes[11] = {
+ 16, 80, 81, 82, 83, 84, 85, 58, 86, 87, 79
+ };
+ unsigned char g_shades[11] = {
+ 0, 46, 92, 115, 139, 162, 185, 205, 208, 231, 255
+ };
+ init_lut(11, gray_lut, g_shades, g_codes);
+
+ unsigned char c_shades[4] = {0, 139, 205, 255};
+ init_lut(4, color_lut, c_shades, NULL);
+ low_color_cube = NULL;
+
+ break;
+ }
+ case 16:
+ {
+ unsigned char g_codes[4] = {0, 8, 7, 15};
+ unsigned char g_shades[4] = {0, 68, 176, 255};
+ /* black - 13% / 35% / 36% / 16% - white */
+ init_lut(4, gray_lut, g_shades, g_codes);
+
+ unsigned char c_shades[5] = {0, 51, 127, 204, 255};
+ /* dark - 10% / 25% / 30% / 25% / 10% - bright */
+ init_lut(5, color_lut, c_shades, NULL);
+ low_color_cube = _low_color_cube;
+
+ break;
+ }
+ case 8:
+ {
+ unsigned char g_codes[2] = {0, 7};
+ unsigned char g_shades[2] = {0, 68};
+ /* black - 13% / 87% - white (black background biased) */
+ init_lut(2, gray_lut, g_shades, g_codes);
+
+ unsigned char c_shades[5] = {0, 51, 127, 204, 255};
+ /* dark - 10% / 25% / 30% / 25% / 10% - bright */
+ init_lut(5, color_lut, c_shades, NULL);
+ low_color_cube = _low_color_cube;
+
+ /* Convert low color cube from 16 to 8 colors. */
+ for (int i = 0; i < 125; i++)
+ if (low_color_cube[i] > 7)
+ low_color_cube[i] -= 8;
+
+ break;
+ }}
+ color_cube_size_squared = color_cube_size * color_cube_size;
+}
+
+/* Convert RGB channel indices to a base or extended color code. */
+short map_extended_color(int ri, int gi, int bi)
+{
+ if (ri == gi && gi == bi) {
+ /* Use gray lookup table if all channels are identical.
+ * Map to 8/16/88/256-color. */
+ return gray_lut[gi];
+ }
+
+ int r = color_lut[ri];
+ int g = color_lut[gi];
+ int b = color_lut[bi];
+ if (low_color_cube != NULL) {
+ /* Map to 8/16-color. */
+ return low_color_cube[(r * color_cube_size_squared)
+ + (g * color_cube_size) + b];
+ } else {
+ /* Map to 88/256-color. */
+ return 16 + (r * color_cube_size_squared) + (g * color_cube_size) + b;
+ }
}
#endif /* ENABLE_COLOR */
diff --git a/src/proto.h b/src/proto.h
index 87334388..4a8429e8 100644
--- a/src/proto.h
+++ b/src/proto.h
@@ -250,6 +250,7 @@ void check_the_multis(filestruct *line);
void alloc_multidata_if_needed(filestruct *fileptr);
void precalc_multicolorinfo(void);
void extended_color_init(void);
+short map_extended_color(int ri, int gi, int bi);
#endif
/* Most functions in cut.c. */
diff --git a/src/rcfile.c b/src/rcfile.c
index 4d4070bd..645bbec2 100644
--- a/src/rcfile.c
+++ b/src/rcfile.c
@@ -569,12 +569,51 @@ void parse_includes(char *ptr)
lineno = lineno_save;
}
+static int hex2int(char c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+
+ /* To lowercase. */
+ c |= 32;
+ if (c >= 'a' && c <= 'f')
+ return 10 + c - 'a';
+
+ return -1;
+}
+
/* Return the short value corresponding to the color named in colorname,
* and set bold to TRUE if that color has bright prefix. */
short color_to_short(const char *colorname, bool *bold)
{
*bold = FALSE;
+ /* RGB colors are #RRGGBB or #RGB hex formatted values. */
+ if (*colorname == '#') {
+ int ri, gi, bi;
+
+ switch(strlen(colorname)){
+ case 4:
+ ri = (hex2int(colorname[1])<<4) | hex2int(colorname[1]);
+ gi = (hex2int(colorname[2])<<4) | hex2int(colorname[2]);
+ bi = (hex2int(colorname[3])<<4) | hex2int(colorname[3]);
+ break;
+ case 7:
+ ri = (hex2int(colorname[1])<<4) | hex2int(colorname[2]);
+ gi = (hex2int(colorname[3])<<4) | hex2int(colorname[4]);
+ bi = (hex2int(colorname[5])<<4) | hex2int(colorname[6]);
+ break;
+ default:
+ /* Invalid. */
+ ri = gi = bi = -1;
+ }
+
+ if (ri != -1 && gi != -1 && bi != -1)
+ return map_extended_color(ri, gi, bi);
+ rcfile_error(N_("Color \"%s\" not understood"), colorname);
+ return -1;
+ }
+
/* Index colors are numeric values from 0 to nr_term_colors-1.
* These are are not portable between terminals with different
* color counts. */
diff --git a/syntax/nanorc.nanorc b/syntax/nanorc.nanorc
index 705d5820..73bf9f45 100644
--- a/syntax/nanorc.nanorc
+++ b/syntax/nanorc.nanorc
@@ -8,7 +8,7 @@ icolor brightred "^[[:space:]]*((un)?(bind|set)|include|syntax|header|magic|comm
# Keywords
icolor brightgreen "^[[:space:]]*(set|unset)[[:space:]]+(allow_insecure_backup|atblanks|autoindent|backup|backwards|boldtext|casesensitive|constantshow|cutfromcursor|fill[[:space:]]+-?[[:digit:]]+|historylog|linenumbers|locking|morespace|mouse|multibuffer|noconvert|nohelp|nopauses|nonewlines|nowrap|positionlog|preserve|quickblank|quiet|rebinddelete|rebindkeypad|regexp|showcursor|smarthome|smooth|softwrap|suspend|tabsize[[:space:]]+[1-9][0-9]*|tabstospaces|tempfile|trimblanks|unix|view|wordbounds)\>"
-icolor yellow "^[[:space:]]*set[[:space:]]+((function|key|number|selected|status|title)color)[[:space:]]+((bold|italic|reverse|underline)(,(bold|italic|reverse|underline))*|((bold|italic|reverse|underline),)*((bright)?(white|black|red|blue|green|yellow|magenta|cyan)|[0-9]+)?(,(white|black|red|blue|green|yellow|magenta|cyan|[0-9]+))?)\>"
+icolor yellow "^[[:space:]]*set[[:space:]]+((function|key|number|selected|status|title)color)[[:space:]]+((bold|italic|reverse|underline)(,(bold|italic|reverse|underline))*|((bold|italic|reverse|underline),)*((bright)?(white|black|red|blue|green|yellow|magenta|cyan)|([0-9]+|#[0-9A-Fa-f]{6}|#[0-9A-Fa-f]{3}))?(,(white|black|red|blue|green|yellow|magenta|cyan|[0-9]+|#[0-9A-Fa-f]{6}|#[0-9A-Fa-f]{3}))?)\>"
icolor brightgreen "^[[:space:]]*set[[:space:]]+(backupdir|brackets|functioncolor|keycolor|matchbrackets|numbercolor|operatingdir|punct|quotestr|selectedcolor|speller|statuscolor|titlecolor|whitespace|wordchars)[[:space:]]+"
icolor brightgreen "^[[:space:]]*bind[[:space:]]+((\^([[:alpha:]]|[]0-9\^_]|Space)|M-([[:alpha:]]|[]!"#$%&'()*+,./0-9:;<=>address@hidden|}~-]|Space))|F([1-9]|1[0-6])|Ins|Del)[[:space:]]+[[:alpha:]]+[[:space:]]+(all|main|search|replace(with)?|gotoline|writeout|insert|ext(ernal)?cmd|help|spell|linter|browser|whereisfile|gotodir)([[:space:]]+#|[[:space:]]*$)"
icolor brightgreen "^[[:space:]]*unbind[[:space:]]+((\^([[:alpha:]]|[]0-9\^_]|Space)|M-([[:alpha:]]|[]!"#$%&'()*+,./0-9:;<=>address@hidden|}~-]|Space))|F([1-9]|1[0-6])|Ins|Del)[[:space:]]+(all|main|search|replace(with)?|gotoline|writeout|insert|ext(ernal)?cmd|help|spell|linter|browser|whereisfile|gotodir)([[:space:]]+#|[[:space:]]*$)"
@@ -20,7 +20,7 @@ icolor green "^[[:space:]]*((un)?(bind|set)|include|syntax|header|magic|comment|
color brightmagenta "".+"([[:space:]]|$)"
# Colors
-icolor yellow "^[[:space:]]*i?color[[:space:]]+((bold|italic|reverse|underline)(,(bold|italic|reverse|underline))*|((bold|italic|reverse|underline),)*((bright)?(white|black|red|blue|green|yellow|magenta|cyan)|[0-9]+)?(,(white|black|red|blue|green|yellow|magenta|cyan|[0-9]+))?)\>"
+icolor yellow "^[[:space:]]*i?color[[:space:]]+((bold|italic|reverse|underline)(,(bold|italic|reverse|underline))*|((bold|italic|reverse|underline),)*((bright)?(white|black|red|blue|green|yellow|magenta|cyan)|([0-9]+|#[0-9A-Fa-f]{6}|#[0-9A-Fa-f]{3}))?(,(white|black|red|blue|green|yellow|magenta|cyan|[0-9]+|#[0-9A-Fa-f]{6}|#[0-9A-Fa-f]{3}))?)\>"
icolor magenta "^[[:space:]]*i?color\>" "\<(start|end)="
# Comments
--
2.13.6