summary refs log tree commit diff
diff options
context:
space:
mode:
authorOliver Kiddle <okiddle@yahoo.co.uk>2018-11-05 22:24:10 +0100
committerOliver Kiddle <okiddle@yahoo.co.uk>2018-11-05 22:24:12 +0100
commit50597692e021ee071b971e13a14dde5b22d31639 (patch)
treef74091a18120948924023914b0f5198331bdb243
parent37d0005a9e651f366076c930019464d162506a57 (diff)
downloadzsh-50597692e021ee071b971e13a14dde5b22d31639.tar.gz
zsh-50597692e021ee071b971e13a14dde5b22d31639.tar.xz
zsh-50597692e021ee071b971e13a14dde5b22d31639.zip
43759: add support for true colour terminals
-rw-r--r--ChangeLog5
-rw-r--r--Src/Modules/nearcolor.c8
-rw-r--r--Src/Zle/complist.c9
-rw-r--r--Src/Zle/zle.h4
-rw-r--r--Src/Zle/zle_refresh.c31
-rw-r--r--Src/Zle/zle_tricky.c9
-rw-r--r--Src/prompt.c104
-rw-r--r--Src/zsh.h33
-rw-r--r--Src/zsh_system.h4
9 files changed, 127 insertions, 80 deletions
diff --git a/ChangeLog b/ChangeLog
index d224f7840..cb18c9e71 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2018-11-05  Oliver Kiddle  <okiddle@yahoo.co.uk>
 
+	* 43759: Src/Modules/nearcolor.c, Src/Zle/complist.c,
+	Src/Zle/zle.h, Src/Zle/zle_refresh.c, Src/Zle/zle_tricky.c,
+	Src/prompt.c, Src/zsh.h, Src/zsh_system.h: add support for
+	true colour terminals
+
 	* 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
diff --git a/Src/Modules/nearcolor.c b/Src/Modules/nearcolor.c
index 2a763d470..128658e20 100644
--- a/Src/Modules/nearcolor.c
+++ b/Src/Modules/nearcolor.c
@@ -118,10 +118,12 @@ static int
 getnearestcolor(UNUSED(Hookdef dummy), Color_rgb col)
 {
     if (tccolours == 256)
-	return mapRGBto256(col->red, col->green, col->blue);
+	return mapRGBto256(col->red, col->green, col->blue) + 1;
     if (tccolours == 88)
-	return mapRGBto88(col->red, col->green, col->blue);
-    return 0;
+	return mapRGBto88(col->red, col->green, col->blue) + 1;
+    /* returning 1 indicates black rather than failure (0) so this
+     * module still serves to prevent fallback on true color */
+    return 1;
 }
 
 static struct features module_features = {
diff --git a/Src/Zle/complist.c b/Src/Zle/complist.c
index e768aee5d..429c8159f 100644
--- a/Src/Zle/complist.c
+++ b/Src/Zle/complist.c
@@ -1096,6 +1096,7 @@ compprintfmt(char *fmt, int n, int dopr, int doesc, int ml, int *stop)
 	    p += len;
 	    if (*p) {
 		int arg = 0, is_fg;
+		zattr atr;
 
 		if (idigit(*p))
 		    arg = zstrtol(p, &p, 10);
@@ -1159,13 +1160,13 @@ compprintfmt(char *fmt, int n, int dopr, int doesc, int ml, int *stop)
 		    /* colours must be ASCII */
 		    if (*p == '{') {
 			p++;
-			arg = match_colour((const char **)&p, is_fg, 0);
+			atr = match_colour((const char **)&p, is_fg, 0);
 			if (*p == '}')
 			    p++;
 		    } else
-			arg = match_colour(NULL, is_fg, arg);
-		    if (arg >= 0 && dopr)
-			set_colour_attribute(arg, is_fg ? COL_SEQ_FG :
+			atr = match_colour(NULL, is_fg, arg);
+		    if (atr != TXT_ERROR && dopr)
+			set_colour_attribute(atr, is_fg ? COL_SEQ_FG :
 					     COL_SEQ_BG, 0);
 		    break;
 		case ZWC('f'):
diff --git a/Src/Zle/zle.h b/Src/Zle/zle.h
index 8261da92b..f06c56483 100644
--- a/Src/Zle/zle.h
+++ b/Src/Zle/zle.h
@@ -430,7 +430,7 @@ enum {
  */
 struct region_highlight {
     /* Attributes turned on in the region */
-    int atr;
+    zattr atr;
     /* Start of the region */
     int start;
     /* Start of the region in metafied ZLE line */
@@ -488,7 +488,7 @@ typedef struct {
      * need the effect; 'off' attributes are only present for the
      * last character in the sequence.
      */
-    int atr;
+    zattr atr;
 } REFRESH_ELEMENT;
 
 /* A string of screen cells */
diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c
index d0dd1ef06..1f293845f 100644
--- a/Src/Zle/zle_refresh.c
+++ b/Src/Zle/zle_refresh.c
@@ -149,7 +149,7 @@ char *lpromptbuf, *rpromptbuf;
 /* Text attributes after displaying prompts */
 
 /**/
-unsigned pmpt_attr, rpmpt_attr;
+zattr pmpt_attr, rpmpt_attr;
 
 /* number of lines displayed */
 
@@ -208,7 +208,7 @@ int predisplaylen, postdisplaylen;
  * displayed on screen.
  */
 
-static int default_atr_on, special_atr_on;
+static zattr default_atr_on, special_atr_on;
 
 /*
  * Array of region highlights, no special termination.
@@ -521,7 +521,7 @@ unset_region_highlight(Param pm, int exp)
 
 
 /* The last attributes that were on. */
-static int lastatr;
+static zattr lastatr;
 
 /*
  * Clear the last attributes that we set:  used when we're going
@@ -560,7 +560,7 @@ tcoutclear(int cap)
 
 /**/
 void
-zwcputc(const REFRESH_ELEMENT *c, int *curatrp)
+zwcputc(const REFRESH_ELEMENT *c, zattr *curatrp)
 {
     /*
      * Safety: turn attributes off if last heard of turned on.
@@ -638,7 +638,7 @@ static int
 zwcwrite(const REFRESH_STRING s, size_t i)
 {
     size_t j;
-    int curatr = 0;
+    zattr curatr = 0;
 
     for (j = 0; j < i; j++)
 	zwcputc(s + j, &curatr);
@@ -891,7 +891,7 @@ snextline(Rparams rpms)
 
 /**/
 static void
-settextattributes(int atr)
+settextattributes(zattr atr)
 {
     if (txtchangeisset(atr, TXTNOBOLDFACE))
 	tsetcap(TCALLATTRSOFF, 0);
@@ -992,7 +992,7 @@ zrefresh(void)
     int tmppos;			/* t - tmpline				     */
     int tmpalloced;		/* flag to free tmpline when finished	     */
     int remetafy;		/* flag that zle line is metafied	     */
-    int txtchange;		/* attributes set after prompts              */
+    zattr txtchange;		/* attributes set after prompts              */
     int rprompt_off = 1;	/* Offset of rprompt from right of screen    */
     struct rparams rpms;
 #ifdef MULTIBYTE_SUPPORT
@@ -1212,8 +1212,9 @@ zrefresh(void)
     rpms.s = nbuf[rpms.ln = 0] + lpromptw;
     rpms.sen = *nbuf + winw;
     for (t = tmpline, tmppos = 0; tmppos < tmpll; t++, tmppos++) {
-	int base_atr_on = default_atr_on, base_atr_off = 0, ireg;
-	int all_atr_on, all_atr_off;
+	unsigned ireg;
+	zattr base_atr_on = default_atr_on, base_atr_off = 0;
+	zattr all_atr_on, all_atr_off;
 	struct region_highlight *rhp;
 	/*
 	 * Calculate attribute based on region.
@@ -1446,7 +1447,8 @@ zrefresh(void)
 	more_end = 1;
 
     if (statusline) {
-	int outll, outsz, all_atr_on, all_atr_off;
+	int outll, outsz;
+	zattr all_atr_on, all_atr_off;
 	char *statusdup = ztrdup(statusline);
 	ZLE_STRING_T outputline =
 	    stringaszleline(statusdup, 0, &outll, &outsz, NULL); 
@@ -1672,7 +1674,7 @@ zrefresh(void)
 
     /* output the right-prompt if appropriate */
 	if (put_rpmpt && !iln && !oput_rpmpt) {
-	    int attrchange;
+	    zattr attrchange;
 
 	    moveto(0, winw - rprompt_off - rpromptw);
 	    zputs(rpromptbuf, shout);
@@ -1926,7 +1928,7 @@ refreshline(int ln)
 /* 3: main display loop - write out the buffer using whatever tricks we can */
 
     for (;;) {
-	int now_off;
+	zattr now_off;
 
 #ifdef MULTIBYTE_SUPPORT
 	if ((!nl->chr || nl->chr != WEOF) && (!ol->chr || ol->chr != WEOF)) {
@@ -2506,8 +2508,9 @@ singlerefresh(ZLE_STRING_T tmpline, int tmpll, int tmpcs)
     *vp = zr_zr;
 
     for (t0 = 0; t0 < tmpll; t0++) {
-	int base_atr_on = 0, base_atr_off = 0, ireg;
-	int all_atr_on, all_atr_off;
+	unsigned ireg;
+	zattr base_atr_on = 0, base_atr_off = 0;
+	zattr all_atr_on, all_atr_off;
 	struct region_highlight *rhp;
 	/*
 	 * Calculate attribute based on region.
diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c
index 22c381237..2b25d6b2e 100644
--- a/Src/Zle/zle_tricky.c
+++ b/Src/Zle/zle_tricky.c
@@ -2431,6 +2431,7 @@ printfmt(char *fmt, int n, int dopr, int doesc)
 	/* Handle the `%' stuff (%% == %, %n == <number of matches>). */
 	if (doesc && *p == '%') {
 	    int arg = 0, is_fg;
+	    zattr atr;
 	    if (idigit(*++p))
 		arg = zstrtol(p, &p, 10);
 	    if (*p) {
@@ -2482,13 +2483,13 @@ printfmt(char *fmt, int n, int dopr, int doesc)
 		    is_fg = (*p == 'F');
 		    if (p[1] == '{') {
 			p += 2;
-			arg = match_colour((const char **)&p, is_fg, 0);
+			atr = match_colour((const char **)&p, is_fg, 0);
 			if (*p != '}')
 			    p--;
 		    } else
-			arg = match_colour(NULL, is_fg, arg);
-		    if (arg >= 0)
-			set_colour_attribute(arg, is_fg ? COL_SEQ_FG :
+			atr = match_colour(NULL, is_fg, arg);
+		    if (atr != TXT_ERROR)
+			set_colour_attribute(atr, is_fg ? COL_SEQ_FG :
 					     COL_SEQ_BG, 0);
 		    break;
 		case 'f':
diff --git a/Src/prompt.c b/Src/prompt.c
index 39edbdb2b..284c02475 100644
--- a/Src/prompt.c
+++ b/Src/prompt.c
@@ -33,7 +33,7 @@
 /* text attribute mask */
 
 /**/
-mod_export unsigned txtattrmask;
+mod_export zattr txtattrmask;
 
 /* the command stack for use with %_ in prompts */
 
@@ -168,7 +168,7 @@ promptpath(char *p, int npath, int tilde)
 
 /**/
 mod_export char *
-promptexpand(char *s, int ns, char *rs, char *Rs, unsigned int *txtchangep)
+promptexpand(char *s, int ns, char *rs, char *Rs, zattr *txtchangep)
 {
     struct buf_vars new_vars;
 
@@ -236,8 +236,8 @@ promptexpand(char *s, int ns, char *rs, char *Rs, unsigned int *txtchangep)
 }
 
 /* Parse the argument for %F and %K */
-static int
-parsecolorchar(int arg, int is_fg)
+static zattr
+parsecolorchar(zattr arg, int is_fg)
 {
     if (bv->fm[1] == '{') {
 	char *ep;
@@ -268,10 +268,11 @@ parsecolorchar(int arg, int is_fg)
 
 /**/
 static int
-putpromptchar(int doprint, int endchar, unsigned int *txtchangep)
+putpromptchar(int doprint, int endchar, zattr *txtchangep)
 {
     char *ss, *hostnam;
     int t0, arg, test, sep, j, numjobs, len;
+    zattr atr;
     struct tm *tm;
     struct timespec ts;
     time_t timet;
@@ -538,13 +539,13 @@ putpromptchar(int doprint, int endchar, unsigned int *txtchangep)
 		tsetcap(TCUNDERLINEEND, TSC_PROMPT|TSC_DIRTY);
 		break;
 	    case 'F':
-		arg = parsecolorchar(arg, 1);
-		if (arg >= 0 && !(arg & TXTNOFGCOLOUR)) {
-		    txtchangeset(txtchangep, arg & TXT_ATTR_FG_ON_MASK,
+		atr = parsecolorchar(arg, 1);
+		if (!(atr & (TXT_ERROR | TXTNOFGCOLOUR))) {
+		    txtchangeset(txtchangep, atr & TXT_ATTR_FG_ON_MASK,
 				 TXTNOFGCOLOUR | TXT_ATTR_FG_COL_MASK);
 		    txtunset(TXT_ATTR_FG_COL_MASK);
-		    txtset(arg & TXT_ATTR_FG_ON_MASK);
-		    set_colour_attribute(arg, COL_SEQ_FG, TSC_PROMPT);
+		    txtset(atr & TXT_ATTR_FG_ON_MASK);
+		    set_colour_attribute(atr, COL_SEQ_FG, TSC_PROMPT);
 		    break;
 		}
 		/* else FALLTHROUGH */
@@ -554,13 +555,13 @@ putpromptchar(int doprint, int endchar, unsigned int *txtchangep)
 		set_colour_attribute(TXTNOFGCOLOUR, COL_SEQ_FG, TSC_PROMPT);
 		break;
 	    case 'K':
-		arg = parsecolorchar(arg, 0);
-		if (arg >= 0 && !(arg & TXTNOBGCOLOUR)) {
-		    txtchangeset(txtchangep, arg & TXT_ATTR_BG_ON_MASK,
+		atr = parsecolorchar(arg, 0);
+		if (!(atr & (TXT_ERROR | TXTNOBGCOLOUR))) {
+		    txtchangeset(txtchangep, atr & TXT_ATTR_BG_ON_MASK,
 				 TXTNOBGCOLOUR | TXT_ATTR_BG_COL_MASK);
 		    txtunset(TXT_ATTR_BG_COL_MASK);
-		    txtset(arg & TXT_ATTR_BG_ON_MASK);
-		    set_colour_attribute(arg, COL_SEQ_BG, TSC_PROMPT);
+		    txtset(atr & TXT_ATTR_BG_ON_MASK);
+		    set_colour_attribute(atr, COL_SEQ_BG, TSC_PROMPT);
 		    break;
 		}
 		/* else FALLTHROUGH */
@@ -1185,7 +1186,7 @@ countprompt(char *str, int *wp, int *hp, int overf)
 /**/
 static int
 prompttrunc(int arg, int truncchar, int doprint, int endchar,
-	    unsigned int *txtchangep)
+	    zattr *txtchangep)
 {
     if (arg > 0) {
 	char ch = *bv->fm, *ptr, *truncstr;
@@ -1567,8 +1568,8 @@ static const char *ansi_colours[] = {
 /* Defines the available types of highlighting */
 struct highlight {
     const char *name;
-    int mask_on;
-    int mask_off;
+    zattr mask_on;
+    zattr mask_off;
 };
 
 static const struct highlight highlights[] = {
@@ -1615,11 +1616,21 @@ match_named_colour(const char **teststrp)
  */
 
 /**/
-mod_export int
+mod_export zattr
 match_colour(const char **teststrp, int is_fg, int colour)
 {
-    int shft, on, named = 0, tc;
+    int shft, named = 0, tc;
+    zattr on;
 
+    if (is_fg) {
+	shft = TXT_ATTR_FG_COL_SHIFT;
+	on = TXTFGCOLOUR;
+	tc = TCFGCOLOUR;
+    } else {
+	shft = TXT_ATTR_BG_COL_SHIFT;
+	on = TXTBGCOLOUR;
+	tc = TCBGCOLOUR;
+    }
     if (teststrp) {
 	if (**teststrp == '#' && isxdigit((*teststrp)[1])) {
 	    struct color_rgb color;
@@ -1637,7 +1648,12 @@ match_colour(const char **teststrp, int is_fg, int colour)
 		color.blue = col & 0xff;
 	    }
 	    *teststrp = end;
-	    colour = runhookdef(GETCOLORATTR, &color);
+	    colour = runhookdef(GETCOLORATTR, &color) - 1;
+	    if (colour < 0) { /* no hook function added, try true color (24-bit) */
+		colour = (((color.red << 8) + color.green) << 8) + color.blue;
+		return on | (is_fg ? TXT_ATTR_FG_24BIT : TXT_ATTR_BG_24BIT) |
+			(zattr)colour << shft;
+	    }
 	} else if ((named = ialpha(**teststrp))) {
 	    colour = match_named_colour(teststrp);
 	    if (colour == 8) {
@@ -1645,22 +1661,14 @@ match_colour(const char **teststrp, int is_fg, int colour)
 		return is_fg ? TXTNOFGCOLOUR : TXTNOBGCOLOUR;
 	    }
 	}
-	else
+	else {
 	    colour = (int)zstrtol(*teststrp, (char **)teststrp, 10);
-    }
-    if (colour < 0 || colour >= 256)
-	return -1;
-    if (is_fg) {
-	shft = TXT_ATTR_FG_COL_SHIFT;
-	on = TXTFGCOLOUR;
-	tc = TCFGCOLOUR;
-    } else {
-	shft = TXT_ATTR_BG_COL_SHIFT;
-	on = TXTBGCOLOUR;
-	tc = TCBGCOLOUR;
+	    if (colour < 0 || colour >= 256)
+		return TXT_ERROR;
+	}
     }
     /*
-     * Try termcap for numbered characters if posible.
+     * Try termcap for numbered characters if possible.
      * Don't for named characters, since our best bet
      * of getting the names right is with ANSI sequences.
      */
@@ -1671,7 +1679,7 @@ match_colour(const char **teststrp, int is_fg, int colour)
 	     * Can we assume ANSI colours work?
 	     */
 	    if (colour > 7)
-		return -1; /* No. */
+		return TXT_ERROR; /* No. */
 	} else {
 	    /*
 	     * We can handle termcap colours and the number
@@ -1681,7 +1689,7 @@ match_colour(const char **teststrp, int is_fg, int colour)
 		TXT_ATTR_BG_TERMCAP;
 	}
     }
-    return on | (colour << shft);
+    return on | (zattr)colour << shft;
 }
 
 /*
@@ -1691,7 +1699,7 @@ match_colour(const char **teststrp, int is_fg, int colour)
 
 /**/
 mod_export void
-match_highlight(const char *teststr, int *on_var)
+match_highlight(const char *teststr, zattr *on_var)
 {
     int found = 1;
 
@@ -1701,7 +1709,8 @@ match_highlight(const char *teststr, int *on_var)
 
 	found = 0;
 	if (strpfx("fg=", teststr) || strpfx("bg=", teststr)) {
-	    int is_fg = (teststr[0] == 'f'), atr;
+	    int is_fg = (teststr[0] == 'f');
+	    zattr atr;
 
 	    teststr += 3;
 	    atr = match_colour(&teststr, is_fg, 0);
@@ -1711,7 +1720,7 @@ match_highlight(const char *teststr, int *on_var)
 		break;
 	    found = 1;
 	    /* skip out of range colours but keep scanning attributes */
-	    if (atr >= 0)
+	    if (atr != TXT_ERROR)
 		*on_var |= atr;
 	} else {
 	    for (hl = highlights; hl->name; hl++) {
@@ -1776,7 +1785,7 @@ output_colour(int colour, int fg_bg, int use_tc, char *buf)
 
 /**/
 mod_export int
-output_highlight(int atr, char *buf)
+output_highlight(zattr atr, char *buf)
 {
     const struct highlight *hp;
     int atrlen = 0, len;
@@ -1939,7 +1948,8 @@ allocate_colour_buffer(void)
 	strlen(fg_bg_sequences[COL_SEQ_BG].end);
 
     len = lenfg > lenbg ? lenfg : lenbg;
-    colseq_buf = (char *)zalloc(len+1);
+    /* add 1 for the null and 14 for truecolor */
+    colseq_buf = (char *)zalloc(len+15);
 }
 
 /* Free the colour buffer previously allocated. */
@@ -1970,21 +1980,23 @@ free_colour_buffer(void)
 
 /**/
 mod_export void
-set_colour_attribute(int atr, int fg_bg, int flags)
+set_colour_attribute(zattr atr, int fg_bg, int flags)
 {
     char *ptr;
     int do_free, is_prompt = (flags & TSC_PROMPT) ? 1 : 0;
-    int colour, tc, def, use_termcap;
+    int colour, tc, def, use_termcap, use_truecolor;
 
     if (fg_bg == COL_SEQ_FG) {
 	colour = txtchangeget(atr, TXT_ATTR_FG_COL);
 	tc = TCFGCOLOUR;
 	def = txtchangeisset(atr, TXTNOFGCOLOUR);
+	use_truecolor = txtchangeisset(atr, TXT_ATTR_FG_24BIT);
 	use_termcap = txtchangeisset(atr, TXT_ATTR_FG_TERMCAP);
     } else {
 	colour = txtchangeget(atr, TXT_ATTR_BG_COL);
 	tc = TCBGCOLOUR;
 	def = txtchangeisset(atr, TXTNOBGCOLOUR);
+	use_truecolor = txtchangeisset(atr, TXT_ATTR_BG_24BIT);
 	use_termcap = txtchangeisset(atr, TXT_ATTR_BG_TERMCAP);
     }
 
@@ -1992,12 +2004,13 @@ set_colour_attribute(int atr, int fg_bg, int flags)
      * If we're not restoring the default, and either have a
      * colour value that is too large for ANSI, or have been told
      * to use the termcap sequence, try to use the termcap sequence.
+     * True color is not covered by termcap.
      *
      * We have already sanitised the values we allow from the
      * highlighting variables, so much of this shouldn't be
      * necessary at this point, but we might as well be safe.
      */
-    if (!def && (colour > 7 || use_termcap)) {
+    if (!def && !use_truecolor && (colour > 7 || use_termcap)) {
 	/*
 	 * We can if it's available, and either we couldn't get
 	 * the maximum number of colours, or the colour is in range.
@@ -2041,6 +2054,9 @@ set_colour_attribute(int atr, int fg_bg, int flags)
 	strcpy(ptr, fg_bg_sequences[fg_bg].def);
 	while (*ptr)
 	    ptr++;
+    } else if (use_truecolor) {
+	ptr += sprintf(ptr, "8;2;%d;%d;%d", colour >> 16,
+		(colour >> 8) & 0xff, colour & 0xff);
     } else
 	*ptr++ = colour + '0';
     strcpy(ptr, fg_bg_sequences[fg_bg].end);
diff --git a/Src/zsh.h b/Src/zsh.h
index 68731e226..10897372b 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -2633,6 +2633,12 @@ struct ttyinfo {
  * Text attributes for displaying in ZLE
  */
 
+#ifdef HAVE_STDINT_H
+  typedef uint64_t zattr;
+#else
+  typedef zulong zattr;
+#endif
+
 #define TXTBOLDFACE   0x0001
 #define TXTSTANDOUT   0x0002
 #define TXTUNDERLINE  0x0004
@@ -2664,32 +2670,41 @@ struct ttyinfo {
  */
 #define TXT_MULTIWORD_MASK  0x0400
 
+/* used when, e.g an invalid colour is specified */
+#define TXT_ERROR 0x0800
+
 /* Mask for colour to use in foreground */
-#define TXT_ATTR_FG_COL_MASK     0x000FF000
+#define TXT_ATTR_FG_COL_MASK     0x000000FFFFFF0000
 /* Bits to shift the foreground colour */
-#define TXT_ATTR_FG_COL_SHIFT    (12)
+#define TXT_ATTR_FG_COL_SHIFT    (16)
 /* Mask for colour to use in background */
-#define TXT_ATTR_BG_COL_MASK     0x0FF00000
+#define TXT_ATTR_BG_COL_MASK     0xFFFFFF0000000000
 /* Bits to shift the background colour */
-#define TXT_ATTR_BG_COL_SHIFT    (20)
+#define TXT_ATTR_BG_COL_SHIFT    (40)
 
 /* Flag to use termcap AF sequence to set colour, if available */
-#define TXT_ATTR_FG_TERMCAP      0x10000000
+#define TXT_ATTR_FG_TERMCAP      0x1000
 /* Flag to use termcap AB sequence to set colour, if available */
-#define TXT_ATTR_BG_TERMCAP      0x20000000
+#define TXT_ATTR_BG_TERMCAP      0x2000
+
+/* Flag to indicate that foreground is a 24-bit colour */
+#define TXT_ATTR_FG_24BIT        0x4000
+/* Flag to indicate that background is a 24-bit colour */
+#define TXT_ATTR_BG_24BIT        0x8000
 
 /* Things to turn on, including values for the colour elements */
 #define TXT_ATTR_ON_VALUES_MASK	\
     (TXT_ATTR_ON_MASK|TXT_ATTR_FG_COL_MASK|TXT_ATTR_BG_COL_MASK|\
-     TXT_ATTR_FG_TERMCAP|TXT_ATTR_BG_TERMCAP)
+     TXT_ATTR_FG_TERMCAP|TXT_ATTR_BG_TERMCAP|\
+     TXT_ATTR_FG_24BIT|TXT_ATTR_BG_24BIT)
 
 /* Mask out everything to do with setting a foreground colour */
 #define TXT_ATTR_FG_ON_MASK \
-    (TXTFGCOLOUR|TXT_ATTR_FG_COL_MASK|TXT_ATTR_FG_TERMCAP)
+    (TXTFGCOLOUR|TXT_ATTR_FG_COL_MASK|TXT_ATTR_FG_TERMCAP|TXT_ATTR_FG_24BIT)
 
 /* Mask out everything to do with setting a background colour */
 #define TXT_ATTR_BG_ON_MASK \
-    (TXTBGCOLOUR|TXT_ATTR_BG_COL_MASK|TXT_ATTR_BG_TERMCAP)
+    (TXTBGCOLOUR|TXT_ATTR_BG_COL_MASK|TXT_ATTR_BG_TERMCAP|TXT_ATTR_BG_24BIT)
 
 /* Mask out everything to do with activating colours */
 #define TXT_ATTR_COLOUR_ON_MASK			\
diff --git a/Src/zsh_system.h b/Src/zsh_system.h
index 8289ee97c..e7d529b6e 100644
--- a/Src/zsh_system.h
+++ b/Src/zsh_system.h
@@ -137,6 +137,10 @@ char *alloca _((size_t));
 #include <stddef.h>
 #endif
 
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+
 #include <stdio.h>
 #include <ctype.h>
 #include <sys/stat.h>