summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--Src/Modules/nearcolor.c178
-rw-r--r--Src/Modules/nearcolor.mdd5
-rw-r--r--Src/init.c1
-rw-r--r--Src/prompt.c19
-rw-r--r--Src/zsh.h7
6 files changed, 215 insertions, 1 deletions
diff --git a/ChangeLog b/ChangeLog
index 1dfcb58f9..d224f7840 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2018-11-05 Oliver Kiddle <okiddle@yahoo.co.uk>
+
+ * 43747: Src/Modules/nearcolor.c, Src/Modules/nearcolor.mdd,
+ Src/init.c, Src/prompt.c, Src/zsh.h: new module to map
+ colours from hex triplets to the nearest matching colour
+
2018-11-03 Peter Stephenson <p.w.stephenson@ntlworld.com>
* 43752: Completion/Base/Completer/_expand: Fix quoting if
diff --git a/Src/Modules/nearcolor.c b/Src/Modules/nearcolor.c
new file mode 100644
index 000000000..2a763d470
--- /dev/null
+++ b/Src/Modules/nearcolor.c
@@ -0,0 +1,178 @@
+#include "nearcolor.mdh"
+#include "nearcolor.pro"
+
+#include <math.h>
+
+struct cielab {
+ float L, a, b;
+};
+typedef struct cielab *Cielab;
+
+static float
+deltae(Cielab lab1, Cielab lab2)
+{
+ /* taking square root unnecessary as we're just comparing values */
+ return powf(lab1->L - lab2->L, 2) +
+ powf(lab1->a - lab2->a, 2) +
+ powf(lab1->b - lab2->b, 2);
+}
+
+static void
+RGBtoLAB(int red, int green, int blue, Cielab lab)
+{
+ float R = (float)red / 255.0;
+ float G = (float)green / 255.0;
+ float B = (float)blue / 255.0;
+ R = 100.0 * (R > 0.04045 ? powf((R + 0.055) / 1.055, 2.4) : R / 12.92);
+ G = 100.0 * (G > 0.04045 ? powf((G + 0.055) / 1.055, 2.4) : G / 12.92);
+ B = 100.0 * (B > 0.04045 ? powf((B + 0.055) / 1.055, 2.4) : B / 12.92);
+
+ /* Observer. = 2 degrees, Illuminant = D65 */
+ float X = (R * 0.4124 + G * 0.3576 + B * 0.1805) / 95.047;
+ float Y = (R * 0.2126 + G * 0.7152 + B * 0.0722) / 100.0;
+ float Z = (R * 0.0193 + G * 0.1192 + B * 0.9505) / 108.883;
+
+ X = (X > 0.008856) ? powf(X, 1.0/3.0) : (7.787 * X) + (16.0 / 116.0);
+ Y = (Y > 0.008856) ? powf(Y, 1.0/3.0) : (7.787 * Y) + (16.0 / 116.0);
+ Z = (Z > 0.008856) ? powf(Z, 1.0/3.0) : (7.787 * Z) + (16.0 / 116.0);
+
+ lab->L = (116.0 * Y) - 16.0;
+ lab->a = 500.0 * (X - Y);
+ lab->b = 200.0 * (Y - Z);
+}
+
+static int
+mapRGBto88(int red, int green, int blue)
+{
+ int component[] = { 0, 0x8b, 0xcd, 0xff, 0x2e, 0x5c, 0x8b, 0xa2, 0xb9, 0xd0, 0xe7 };
+ struct cielab orig, next;
+ float nextl, bestl = -1;
+ int r, g, b;
+ int comp_r = 0, comp_g = 0, comp_b = 0;
+
+ /* Get original value */
+ RGBtoLAB(red, green, blue, &orig);
+
+ /* try every one of the 72 colours */
+ for (r = 0; r < 11; r++) {
+ for (g = 0; g <= 3; g++) {
+ for (b = 0; b <= 3; b++) {
+ if (r > 3) g = b = r; /* advance inner loops to the block of greys */
+ RGBtoLAB(component[r], component[g], component[b], &next);
+ nextl = deltae(&orig, &next);
+ if (nextl < bestl || bestl < 0) {
+ bestl = nextl;
+ comp_r = r;
+ comp_g = g;
+ comp_b = b;
+ }
+ }
+ }
+ }
+
+ return (comp_r > 3) ? 77 + comp_r :
+ 16 + (comp_r * 16) + (comp_g * 4) + comp_b;
+}
+
+/*
+ * Convert RGB to nearest colour in the 256 colour range
+ */
+static int
+mapRGBto256(int red, int green, int blue)
+{
+ int component[] = {
+ 0, 0x5f, 0x87, 0xaf, 0xd7, 0xff,
+ 0x8, 0x12, 0x1c, 0x26, 0x30, 0x3a, 0x44, 0x4e,
+ 0x58, 0x62, 0x6c, 0x76, 0x80, 0x8a, 0x94, 0x9e,
+ 0xa8, 0xb2, 0xbc, 0xc6, 0xd0, 0xda, 0xe4, 0xee
+ };
+ struct cielab orig, next;
+ float nextl, bestl = -1;
+ int r, g, b;
+ int comp_r = 0, comp_g = 0, comp_b = 0;
+
+ /* Get original value */
+ RGBtoLAB(red, green, blue, &orig);
+
+ for (r = 0; r < sizeof(component)/sizeof(*component); r++) {
+ for (g = 0; g <= 5; g++) {
+ for (b = 0; b <= 5; b++) {
+ if (r > 5) g = b = r; /* advance inner loops to the block of greys */
+ RGBtoLAB(component[r], component[g], component[b], &next);
+ nextl = deltae(&orig, &next);
+ if (nextl < bestl || bestl < 0) {
+ bestl = nextl;
+ comp_r = r;
+ comp_g = g;
+ comp_b = b;
+ }
+ }
+ }
+ }
+
+ return (comp_r > 5) ? 226 + comp_r :
+ 16 + (comp_r * 36) + (comp_g * 6) + comp_b;
+}
+
+static int
+getnearestcolor(UNUSED(Hookdef dummy), Color_rgb col)
+{
+ if (tccolours == 256)
+ return mapRGBto256(col->red, col->green, col->blue);
+ if (tccolours == 88)
+ return mapRGBto88(col->red, col->green, col->blue);
+ return 0;
+}
+
+static struct features module_features = {
+ NULL, 0,
+ NULL, 0,
+ NULL, 0,
+ NULL, 0,
+ 0
+};
+
+/**/
+int
+setup_(UNUSED(Module m))
+{
+ return 0;
+}
+
+/**/
+int
+features_(Module m, char ***features)
+{
+ *features = featuresarray(m, &module_features);
+ return 0;
+}
+
+/**/
+int
+enables_(Module m, int **enables)
+{
+ return handlefeatures(m, &module_features, enables);
+}
+
+/**/
+int
+boot_(Module m)
+{
+ addhookfunc("get_color_attr", (Hookfn) getnearestcolor);
+ return 0;
+}
+
+/**/
+int
+cleanup_(Module m)
+{
+ deletehookfunc("get_color_attr", (Hookfn) getnearestcolor);
+ return setfeatureenables(m, &module_features, NULL);
+}
+
+/**/
+int
+finish_(UNUSED(Module m))
+{
+ return 0;
+}
diff --git a/Src/Modules/nearcolor.mdd b/Src/Modules/nearcolor.mdd
new file mode 100644
index 000000000..2fcdaf04e
--- /dev/null
+++ b/Src/Modules/nearcolor.mdd
@@ -0,0 +1,5 @@
+name=zsh/nearcolor
+link=dynamic
+load=no
+
+objects="nearcolor.o"
diff --git a/Src/init.c b/Src/init.c
index cec914329..e7e62e2f7 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -94,6 +94,7 @@ mod_export struct hookdef zshhooks[] = {
HOOKDEF("exit", NULL, HOOKF_ALL),
HOOKDEF("before_trap", NULL, HOOKF_ALL),
HOOKDEF("after_trap", NULL, HOOKF_ALL),
+ HOOKDEF("get_color_attr", NULL, HOOKF_ALL),
};
/* keep executing lists until EOF found */
diff --git a/Src/prompt.c b/Src/prompt.c
index 959ed8e3d..39edbdb2b 100644
--- a/Src/prompt.c
+++ b/Src/prompt.c
@@ -1621,7 +1621,24 @@ match_colour(const char **teststrp, int is_fg, int colour)
int shft, on, named = 0, tc;
if (teststrp) {
- if ((named = ialpha(**teststrp))) {
+ if (**teststrp == '#' && isxdigit((*teststrp)[1])) {
+ struct color_rgb color;
+ char *end;
+ zlong col = zstrtol(*teststrp+1, &end, 16);
+ if (end - *teststrp == 4) {
+ color.red = col >> 8 | ((col >> 8) << 4);
+ color.green = (col & 0xf0) >> 4;
+ color.green |= color.green << 4;
+ color.blue = col & 0xf;
+ color.blue |= color.blue << 4;
+ } else if (end - *teststrp == 7) {
+ color.red = col >> 16;
+ color.green = (col & 0xff00) >> 8;
+ color.blue = col & 0xff;
+ }
+ *teststrp = end;
+ colour = runhookdef(GETCOLORATTR, &color);
+ } else if ((named = ialpha(**teststrp))) {
colour = match_named_colour(teststrp);
if (colour == 8) {
/* default */
diff --git a/Src/zsh.h b/Src/zsh.h
index 894158818..68731e226 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -2707,6 +2707,12 @@ struct ttyinfo {
#define COL_SEQ_BG (1)
#define COL_SEQ_COUNT (2)
+struct color_rgb {
+ unsigned int red, green, blue;
+};
+
+typedef struct color_rgb *Color_rgb;
+
/*
* Flags to testcap() and set_colour_attribute (which currently only
* handles TSC_PROMPT).
@@ -3203,6 +3209,7 @@ enum {
#define EXITHOOK (zshhooks + 0)
#define BEFORETRAPHOOK (zshhooks + 1)
#define AFTERTRAPHOOK (zshhooks + 2)
+#define GETCOLORATTR (zshhooks + 3)
#ifdef MULTIBYTE_SUPPORT
/* Final argument to mb_niceformat() */