about summary refs log tree commit diff
path: root/Src/prompt.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/prompt.c')
-rw-r--r--Src/prompt.c392
1 files changed, 303 insertions, 89 deletions
diff --git a/Src/prompt.c b/Src/prompt.c
index 092de63a4..e10b05215 100644
--- a/Src/prompt.c
+++ b/Src/prompt.c
@@ -30,10 +30,20 @@
 #include "zsh.mdh"
 #include "prompt.pro"
 
-/* text attribute mask */
+/* current text attributes */
 
 /**/
-mod_export zattr txtattrmask;
+mod_export zattr txtcurrentattrs;
+
+/* pending changes for attributes */
+
+/**/
+mod_export zattr txtpendingattrs;
+
+/* mask of attributes with an unknown state */
+
+/**/
+mod_export zattr txtunknownattrs;
 
 /* the command stack for use with %_ in prompts */
 
@@ -160,15 +170,11 @@ promptpath(char *p, int npath, int tilde)
  * between spacing and non-spacing parts of the prompt, and
  * Nularg, which (in a non-spacing sequence) indicates a
  * `glitch' space.
- *
- * txtchangep gives an integer controlling the attributes of
- * the prompt.  This is for use in zle to maintain the attributes
- * consistently.  Other parts of the shell should not need to use it.
  */
 
 /**/
 mod_export char *
-promptexpand(char *s, int ns, char *rs, char *Rs, zattr *txtchangep)
+promptexpand(char *s, int ns, char *rs, char *Rs)
 {
     struct buf_vars new_vars;
 
@@ -212,7 +218,7 @@ promptexpand(char *s, int ns, char *rs, char *Rs, zattr *txtchangep)
     new_vars.bp1 = NULL;
     new_vars.truncwidth = 0;
 
-    putpromptchar(1, '\0', txtchangep);
+    putpromptchar(1, '\0');
     addbufspc(2);
     if (new_vars.dontcount)
 	*new_vars.bp++ = Outpar;
@@ -235,6 +241,68 @@ promptexpand(char *s, int ns, char *rs, char *Rs, zattr *txtchangep)
     return new_vars.buf;
 }
 
+/* Get the escape sequence for a given attribute. */
+/**/
+mod_export char *
+zattrescape(zattr atr, int *len)
+{
+    struct buf_vars new_vars;
+    zattr savecurrent = txtcurrentattrs;
+    zattr saveunknown = txtunknownattrs;
+
+    memset(&new_vars, 0, sizeof(new_vars));
+    new_vars.last = bv;
+    bv = &new_vars;
+    new_vars.bufspc = 256;
+    new_vars.bp = new_vars.bufline = new_vars.buf = zshcalloc(new_vars.bufspc);
+    new_vars.dontcount = 1;
+
+    txtunknownattrs = 0;
+    treplaceattrs(atr);
+    applytextattributes(TSC_PROMPT);
+
+    bv = new_vars.last;
+
+    txtpendingattrs = txtcurrentattrs = savecurrent;
+    txtunknownattrs = saveunknown;
+
+    return unmetafy(new_vars.buf, len);
+}
+
+/* Parse the argument for %H */
+/**/
+mod_export char *
+parsehighlight(char *arg, char endchar, zattr *atr)
+{
+    static int entered = 0;
+    char *var = ".zle.hlgroups";
+    struct value vbuf;
+    Value v;
+    char *ep, *attrs;
+    if ((ep = strchr(arg, endchar)))
+	*ep = '\0';
+    if (!entered && (v = getvalue(&vbuf, &var, 0)) &&
+	    PM_TYPE(v->pm->node.flags) == PM_HASHED)
+    {
+	Param node;
+	HashTable ht = v->pm->gsu.h->getfn(v->pm);
+	if (ht && (node = (Param) ht->getnode(ht, arg))) {
+	    attrs = node->gsu.s->getfn(node);
+	    entered = 1;
+	    if (match_highlight(attrs, atr, 0) == attrs)
+		*atr = TXT_ERROR;
+	} else
+	    *atr = TXT_ERROR;
+    } else
+	*atr = TXT_ERROR;
+    if (ep)
+	*ep++ = endchar;
+    else
+	ep = strchr(arg, '\0');
+    entered = 0;
+    return ep;
+}
+
 /* Parse the argument for %F and %K */
 static zattr
 parsecolorchar(zattr arg, int is_fg)
@@ -253,7 +321,7 @@ parsecolorchar(zattr arg, int is_fg)
 	    *ep = '\0';
 	    /* expand the contents of the argument so you can use
 	     * %v for example */
-	    coll = col = promptexpand(bv->fm, 0, NULL, NULL, NULL);
+	    coll = col = promptexpand(bv->fm, 0, NULL, NULL);
 	    *ep = oc;
 	    arg = match_colour((const char **)&coll, is_fg, 0);
 	    free(col);
@@ -278,7 +346,7 @@ parsecolorchar(zattr arg, int is_fg)
 
 /**/
 static int
-putpromptchar(int doprint, int endchar, zattr *txtchangep)
+putpromptchar(int doprint, int endchar)
 {
     char *ss, *hostnam;
     int t0, arg, test, sep, j, numjobs, len;
@@ -430,10 +498,9 @@ putpromptchar(int doprint, int endchar, zattr *txtchangep)
 		/* Don't do the current truncation until we get back */
 		otruncwidth = bv->truncwidth;
 		bv->truncwidth = 0;
-		if (!putpromptchar(test == 1 && doprint, sep,
-				   txtchangep) || !*++bv->fm ||
-		    !putpromptchar(test == 0 && doprint, ')',
-				   txtchangep)) {
+		if (!putpromptchar(test == 1 && doprint, sep) ||
+				   !*++bv->fm ||
+		    !putpromptchar(test == 0 && doprint, ')')) {
 		    bv->truncwidth = otruncwidth;
 		    return 0;
 		}
@@ -519,71 +586,67 @@ putpromptchar(int doprint, int endchar, zattr *txtchangep)
 		unqueue_signals();
 		break;
 	    case 'S':
-		txtchangeset(txtchangep, TXTSTANDOUT, TXTNOSTANDOUT);
-		txtset(TXTSTANDOUT);
-		tsetcap(TCSTANDOUTBEG, TSC_PROMPT);
+		tsetattrs(TXTSTANDOUT);
+	        applytextattributes(TSC_PROMPT);
 		break;
 	    case 's':
-		txtchangeset(txtchangep, TXTNOSTANDOUT, TXTSTANDOUT);
-		txtunset(TXTSTANDOUT);
-		tsetcap(TCSTANDOUTEND, TSC_PROMPT|TSC_DIRTY);
+		tunsetattrs(TXTSTANDOUT);
+	        applytextattributes(TSC_PROMPT);
 		break;
 	    case 'B':
-		txtchangeset(txtchangep, TXTBOLDFACE, TXTNOBOLDFACE);
-		txtset(TXTBOLDFACE);
-		tsetcap(TCBOLDFACEBEG, TSC_PROMPT|TSC_DIRTY);
+		tsetattrs(TXTBOLDFACE);
+	        applytextattributes(TSC_PROMPT);
 		break;
 	    case 'b':
-		txtchangeset(txtchangep, TXTNOBOLDFACE, TXTBOLDFACE);
-		txtunset(TXTBOLDFACE);
-		tsetcap(TCALLATTRSOFF, TSC_PROMPT|TSC_DIRTY);
+		tunsetattrs(TXTBOLDFACE);
+	        applytextattributes(TSC_PROMPT);
 		break;
 	    case 'U':
-		txtchangeset(txtchangep, TXTUNDERLINE, TXTNOUNDERLINE);
-		txtset(TXTUNDERLINE);
-		tsetcap(TCUNDERLINEBEG, TSC_PROMPT);
+		tsetattrs(TXTUNDERLINE);
+	        applytextattributes(TSC_PROMPT);
 		break;
 	    case 'u':
-		txtchangeset(txtchangep, TXTNOUNDERLINE, TXTUNDERLINE);
-		txtunset(TXTUNDERLINE);
-		tsetcap(TCUNDERLINEEND, TSC_PROMPT|TSC_DIRTY);
+		tunsetattrs(TXTUNDERLINE);
+	        applytextattributes(TSC_PROMPT);
 		break;
 	    case 'F':
 		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(atr & TXT_ATTR_FG_ON_MASK);
-		    set_colour_attribute(atr, COL_SEQ_FG, TSC_PROMPT);
+		if (atr && atr != TXT_ERROR) {
+		    tsetattrs(atr);
+		    applytextattributes(TSC_PROMPT);
 		    break;
 		}
 		/* else FALLTHROUGH */
 	    case 'f':
-		txtchangeset(txtchangep, TXTNOFGCOLOUR, TXT_ATTR_FG_ON_MASK);
-		txtunset(TXT_ATTR_FG_ON_MASK);
-		set_colour_attribute(TXTNOFGCOLOUR, COL_SEQ_FG, TSC_PROMPT);
+		tunsetattrs(TXTFGCOLOUR);
+		applytextattributes(TSC_PROMPT);
 		break;
 	    case 'K':
 		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(atr & TXT_ATTR_BG_ON_MASK);
-		    set_colour_attribute(atr, COL_SEQ_BG, TSC_PROMPT);
+		if (atr && atr != TXT_ERROR) {
+		    tsetattrs(atr);
+		    applytextattributes(TSC_PROMPT);
 		    break;
 		}
 		/* else FALLTHROUGH */
 	    case 'k':
-		txtchangeset(txtchangep, TXTNOBGCOLOUR, TXT_ATTR_BG_ON_MASK);
-		txtunset(TXT_ATTR_BG_ON_MASK);
-		set_colour_attribute(TXTNOBGCOLOUR, COL_SEQ_BG, TSC_PROMPT);
+		tunsetattrs(TXTBGCOLOUR);
+	        applytextattributes(TSC_PROMPT);
+		break;
+	    case 'H':
+		if (bv->fm[1] == '{') {
+		    bv->fm = parsehighlight(bv->fm + 2, '}', &atr);
+		    --bv->fm;
+		    if (atr != TXT_ERROR) {
+			treplaceattrs(atr);
+			applytextattributes(TSC_PROMPT);
+		    }
+		}
 		break;
 	    case '[':
 		if (idigit(*++bv->fm))
 		    arg = zstrtol(bv->fm, &bv->fm, 10);
-		if (!prompttrunc(arg, ']', doprint, endchar, txtchangep))
+		if (!prompttrunc(arg, ']', doprint, endchar))
 		    return *bv->fm;
 		break;
 	    case '<':
@@ -596,7 +659,7 @@ putpromptchar(int doprint, int endchar, zattr *txtchangep)
 		    if (arg <= 0)
 			arg = 1;
 		}
-		if (!prompttrunc(arg, *bv->fm, doprint, endchar, txtchangep))
+		if (!prompttrunc(arg, *bv->fm, doprint, endchar))
 		    return *bv->fm;
 		break;
 	    case '{': /*}*/
@@ -1013,9 +1076,8 @@ stradd(char *d)
 mod_export void
 tsetcap(int cap, int flags)
 {
-    if (tccan(cap) && !isset(SINGLELINEZLE) &&
-        !(termflags & (TERM_NOUP|TERM_BAD|TERM_UNKNOWN))) {
-	switch (flags & TSC_OUTPUT_MASK) {
+    if (tccan(cap) && !(termflags & (TERM_NOUP|TERM_BAD|TERM_UNKNOWN))) {
+	switch (flags) {
 	case TSC_RAW:
 	    tputs(tcstr[cap], 1, putraw);
 	    break;
@@ -1045,20 +1107,6 @@ tsetcap(int cap, int flags)
 	    }
 	    break;
 	}
-
-	if (flags & TSC_DIRTY) {
-	    flags &= ~TSC_DIRTY;
-	    if (txtisset(TXTBOLDFACE) && cap != TCBOLDFACEBEG)
-		tsetcap(TCBOLDFACEBEG, flags);
-	    if (txtisset(TXTSTANDOUT))
-		tsetcap(TCSTANDOUTBEG, flags);
-	    if (txtisset(TXTUNDERLINE))
-		tsetcap(TCUNDERLINEBEG, flags);
-	    if (txtisset(TXTFGCOLOUR))
-		set_colour_attribute(txtattrmask, COL_SEQ_FG, flags);
-	    if (txtisset(TXTBGCOLOUR))
-		set_colour_attribute(txtattrmask, COL_SEQ_BG, flags);
-	}
     }
 }
 
@@ -1219,8 +1267,7 @@ countprompt(char *str, int *wp, int *hp, int overf)
 
 /**/
 static int
-prompttrunc(int arg, int truncchar, int doprint, int endchar,
-	    zattr *txtchangep)
+prompttrunc(int arg, int truncchar, int doprint, int endchar)
 {
     if (arg > 0) {
 	char ch = *bv->fm, *ptr, *truncstr;
@@ -1267,7 +1314,7 @@ prompttrunc(int arg, int truncchar, int doprint, int endchar,
 	w = bv->bp - bv->buf;
 	bv->fm++;
 	bv->trunccount = bv->dontcount;
-	putpromptchar(doprint, endchar, txtchangep);
+	putpromptchar(doprint, endchar);
 	bv->trunccount = 0;
 	ptr = bv->buf + w;	/* putpromptchar() may have realloc()'d */
 	*bv->bp = '\0';
@@ -1547,7 +1594,7 @@ prompttrunc(int arg, int truncchar, int doprint, int endchar,
 	     * With bv->truncwidth set to zero, we always reach endchar *
 	     * (or the terminating NULL) this time round.         *
 	     */
-	    if (!putpromptchar(doprint, endchar, txtchangep))
+	    if (!putpromptchar(doprint, endchar))
 		return 0;
 	}
 	/* Now we have to trick it into matching endchar again */
@@ -1585,6 +1632,158 @@ cmdpop(void)
 	cmdsp--;
 }
 
+/* functions for handling attributes */
+
+/**/
+mod_export void
+applytextattributes(int flags)
+{
+    zattr change = txtcurrentattrs ^ txtpendingattrs;
+    zattr keepon = ~change & txtpendingattrs & TXT_ATTR_ALL;
+    zattr turnoff = change & ~txtpendingattrs & TXT_ATTR_ALL;
+    int keepcount, turncount = 0;
+
+    /* bail out early if we wouldn't do anything */
+    if (!change)
+	return;
+
+    if (txtunknownattrs) {
+	txtunknownattrs &= ~change; /* changes cease to be unknown */
+	/* can't turn unknown attrs back on so avoid wiping them */
+	keepcount = 1;
+    } else {
+	/* If we want to turn off more attributes than we want to keep on
+	 * then it takes fewer termcap sequences to just turn off all the
+	 * attributes. */
+	for (keepcount = 0; keepon; keepcount++) /* count bits */
+	    keepon &= keepon - 1;
+	for (; turnoff; turncount++)
+	    turnoff &= turnoff - 1;
+    }
+
+    /* enabling bold can be relied upon to disable faint
+     * (the converse not so as that commonly does nothing at all) */
+    if (txtcurrentattrs & TXTFAINT && txtpendingattrs & TXTBOLDFACE) {
+	--turncount;
+	change &= ~TXTFAINT;
+    }
+
+    if (keepcount < turncount ||
+	    (change & ~txtpendingattrs & TXT_ATTR_FONT_WEIGHT)) {
+	tsetcap(TCALLATTRSOFF, flags);
+	/* this cleared all attributes, may need to restore some */
+	change = txtpendingattrs & TXT_ATTR_ALL & ~txtunknownattrs;
+	txtunknownattrs = 0;
+    } else {
+	if (change & ~txtpendingattrs & TXTSTANDOUT) {
+	    tsetcap(TCSTANDOUTEND, flags);
+	    /* in some cases, that clears all attributes */
+	    change = (txtpendingattrs & TXT_ATTR_ALL & ~txtunknownattrs) |
+		    (TXTUNDERLINE & change);
+	}
+	if (change & ~txtpendingattrs & TXTUNDERLINE) {
+	    tsetcap(TCUNDERLINEEND, flags);
+	    /* in some cases, that clears all attributes */
+	    change = txtpendingattrs & TXT_ATTR_ALL & ~txtunknownattrs;
+	}
+	if (change & ~txtpendingattrs & TXTITALIC)
+	    tsetcap(TCITALICSEND, flags);
+    }
+    if (change & txtpendingattrs & TXTBOLDFACE)
+	tsetcap(TCBOLDFACEBEG, flags);
+    if (change & txtpendingattrs & TXTFAINT)
+	tsetcap(TCFAINTBEG, flags);
+    if (change & txtpendingattrs & TXTSTANDOUT)
+	tsetcap(TCSTANDOUTBEG, flags);
+    if (change & txtpendingattrs & TXTUNDERLINE)
+	tsetcap(TCUNDERLINEBEG, flags);
+    if (change & txtpendingattrs & TXTITALIC)
+	tsetcap(TCITALICSBEG, flags);
+
+    if (change & TXT_ATTR_FG_MASK)
+	set_colour_attribute(txtpendingattrs, COL_SEQ_FG, flags);
+    if (change & TXT_ATTR_BG_MASK)
+	set_colour_attribute(txtpendingattrs, COL_SEQ_BG, flags);
+
+    txtcurrentattrs = txtpendingattrs;
+}
+
+/**/
+mod_export void
+cleartextattributes(int flags)
+{
+    treplaceattrs(0);
+    applytextattributes(flags);
+}
+
+/**/
+mod_export void
+treplaceattrs(zattr newattrs)
+{
+    if (newattrs == TXT_ERROR)
+	return;
+
+    if (txtunknownattrs) {
+	/* Set current attributes to the opposite of the new ones
+	 * for any that are unknown so that applytextattributes()
+	 * detects them as changed. */
+	txtcurrentattrs &= ~txtunknownattrs;
+	txtcurrentattrs |= txtunknownattrs & ~newattrs;
+    }
+
+    txtpendingattrs = newattrs;
+}
+
+/**/
+mod_export void
+tsetattrs(zattr newattrs)
+{
+    /* assume any unknown attributes that we're now setting were unset */
+    txtcurrentattrs &= ~(newattrs & txtunknownattrs);
+
+    txtpendingattrs |= newattrs & TXT_ATTR_ALL;
+    if (newattrs & TXTFGCOLOUR) {
+	txtpendingattrs &= ~TXT_ATTR_FG_MASK;
+	txtpendingattrs |= newattrs & TXT_ATTR_FG_MASK;
+    }
+    if (newattrs & TXTBGCOLOUR) {
+	txtpendingattrs &= ~TXT_ATTR_BG_MASK;
+	txtpendingattrs |= newattrs & TXT_ATTR_BG_MASK;
+    }
+}
+
+/**/
+mod_export void
+tunsetattrs(zattr newattrs)
+{
+    /* assume any unknown attributes that we're now unsetting were set */
+    txtcurrentattrs |= newattrs & txtunknownattrs;
+
+    txtpendingattrs &= ~(newattrs & TXT_ATTR_ALL);
+    if (newattrs & TXTFGCOLOUR)
+	txtpendingattrs &= ~TXT_ATTR_FG_MASK;
+    if (newattrs & TXTBGCOLOUR)
+	txtpendingattrs &= ~TXT_ATTR_BG_MASK;
+}
+
+/* Merge two attribute sets. In an case where attributes might conflict
+ * choose those from the first parameter.  Foreground and background
+ * colours are taken together - less likely to end up with unreadable
+ * combinations. */
+
+/**/
+mod_export zattr
+mixattrs(zattr primary, zattr secondary)
+{
+    zattr result = secondary;
+    /* take colours from primary */
+    if (primary & (TXTFGCOLOUR|TXTBGCOLOUR))
+        result &= ~TXT_ATTR_COLOUR_MASK;
+    /* take font weight from primary */
+    if (primary & TXT_ATTR_FONT_WEIGHT)
+        result &= ~TXT_ATTR_FONT_WEIGHT;
+    return result | primary;
+}
 
 /*****************************************************************************
  * Utilities dealing with colour and other forms of highlighting.
@@ -1607,10 +1806,12 @@ struct highlight {
 };
 
 static const struct highlight highlights[] = {
-    { "none", 0, TXT_ATTR_ON_MASK },
-    { "bold", TXTBOLDFACE, 0 },
+    { "none", 0, TXT_ATTR_ALL },
+    { "bold", TXTBOLDFACE, TXTFAINT },
+    { "faint", TXTFAINT, TXTBOLDFACE },
     { "standout", TXTSTANDOUT, 0 },
     { "underline", TXTUNDERLINE, 0 },
+    { "italic", TXTITALIC, 0 },
     { NULL, 0, 0 }
 };
 
@@ -1645,8 +1846,8 @@ match_named_colour(const char **teststrp)
  * Match just the colour part of a highlight specification.
  * If teststrp is NULL, use the already parsed numeric colour.
  * Return the attributes to set in the attribute variable.
- * Return -1 for out of range.  Does not check the character
- * following the colour specification.
+ * Return TXT_ERROR for out of range.  Does not check the
+ * character following the colour specification.
  */
 
 /**/
@@ -1666,7 +1867,7 @@ match_colour(const char **teststrp, int is_fg, int colour)
 	tc = TCBGCOLOUR;
     }
     if (teststrp) {
-	if (**teststrp == '#' && isxdigit(STOUC((*teststrp)[1]))) {
+	if (**teststrp == '#' && isxdigit((unsigned char) (*teststrp)[1])) {
 	    struct color_rgb color;
 	    char *end;
 	    zlong col = zstrtol(*teststrp+1, &end, 16);
@@ -1693,10 +1894,8 @@ match_colour(const char **teststrp, int is_fg, int colour)
 	    }
 	} else if ((named = ialpha(**teststrp))) {
 	    colour = match_named_colour(teststrp);
-	    if (colour == 8) {
-		/* default */
-		return is_fg ? TXTNOFGCOLOUR : TXTNOBGCOLOUR;
-	    }
+	    if (colour == 8) /* default */
+		return 0;
 	    if (colour < 0)
 		return TXT_ERROR;
 	}
@@ -1717,23 +1916,30 @@ match_colour(const char **teststrp, int is_fg, int colour)
 /*
  * Match a set of highlights in the given teststr.
  * Set *on_var to reflect the values found.
+ * Set *layer to the layer
  * Return a pointer to the first character not consumed.
  */
 
 /**/
 mod_export const char *
-match_highlight(const char *teststr, zattr *on_var)
+match_highlight(const char *teststr, zattr *on_var, int *layer)
 {
     int found = 1;
 
     *on_var = 0;
     while (found && *teststr) {
 	const struct highlight *hl;
+	zattr atr = 0;
 
 	found = 0;
-	if (strpfx("fg=", teststr) || strpfx("bg=", teststr)) {
+	if (strpfx("hl=", teststr)) {
+	    teststr += 3;
+	    teststr = parsehighlight((char *)teststr, ',', &atr);
+	    if (atr != TXT_ERROR)
+		*on_var = atr;
+	    found = 1;
+	} else if (strpfx("fg=", teststr) || strpfx("bg=", teststr)) {
 	    int is_fg = (teststr[0] == 'f');
-	    zattr atr;
 
 	    teststr += 3;
 	    atr = match_colour(&teststr, is_fg, 0);
@@ -1745,6 +1951,14 @@ match_highlight(const char *teststr, zattr *on_var)
 	    /* skip out of range colours but keep scanning attributes */
 	    if (atr != TXT_ERROR)
 		*on_var |= atr;
+	} else if (layer && strpfx("layer=", teststr)) {
+	    teststr += 6;
+	    *layer = (int) zstrtol(teststr, (char **) &teststr, 10);
+	    if (*teststr == ',')
+		teststr++;
+	    else if (*teststr && *teststr != ' ')
+		break;
+	    found = 1;
 	} else {
 	    for (hl = highlights; hl->name; hl++) {
 		if (strpfx(hl->name, teststr)) {
@@ -2024,13 +2238,13 @@ set_colour_attribute(zattr atr, int fg_bg, int flags)
     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);
+	def = !(atr & TXTFGCOLOUR);
+	use_truecolor = atr & TXT_ATTR_FG_24BIT;
     } else {
 	colour = txtchangeget(atr, TXT_ATTR_BG_COL);
 	tc = TCBGCOLOUR;
-	def = txtchangeisset(atr, TXTNOBGCOLOUR);
-	use_truecolor = txtchangeisset(atr, TXT_ATTR_BG_24BIT);
+	def = !(atr & TXTBGCOLOUR);
+	use_truecolor = atr & TXT_ATTR_BG_24BIT;
     }
 
     /* Test if current zle_highlight settings are customized, or