Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

PATCH: Re: region_highlight converts `fg=default` to `none`, which is not the same



On 12 Oct 2020, Marlon Richert wrote:
> I am using `zsh-syntax-highlighting` and I want my paths to be blue, but the
> slashes in there to be my terminal's default text color. I've tested it and
> `zsh-syntax-highlighting` correctly puts, for example,
>
> ```
> region_highlight=( '0 2 fg=10' '3 16 fg=4' '3 4 fg=default' '9 10 fg=default' )
>
> However, after this assignment occurs, when I `print -r "${(q+)region_highlight
> [@]}"`, I get as output
>
> '0 2 fg=10' '3 16 fg=4' '3 4 none' '9 10 none'

It's been five years but this should now fix this.

Fixing this would have been hard at that time. Now, since the later
refactoring of the highlighting code, we just need to hold a bit mask to
track which attributes were explicitly set as opposed to inherited.

This does also impact the colour merging strategy. In 5.9, later entries
in region_highlight inherit all the earlier attributes. You can change
the colour but not remove bold, underline etc. So the best approach for
backward compatibility is to inherit by default. This may mean a lot of
explicit disabling of inheritance is needed.

With this patch, if you want bold text and no inherited attributes, you
need: none,bold
They apply in sequence.

You can also do things like fg=default,bg=white,nobold,underline
"no" can be prefixed to bold, italic etc. That includes nounderline,
even though we may want underline=double underline=curly etc in future,
in which case underline=off might seem logical. nobold and nofaint have
the same effect of selecting normal font weight. So nobold will turn off
faint and vice-versa. Anyone have strong opinions on how we indicate
disabled attributes - other things like "-" prefixes would be no harder
to implement.

Because "none" asserts terminal defaults over inherited attributes,
an empty attribute should not appear as "none" in the value of
region_highlight. An empty string would work but I've gone with
"inherit" instead. Unrecognised words are ignored so you can reinput
that.

"+" and "=" were suggested back then as prefixes to select between
inheritance or otherwise but these would not be backward compatible with
5.9 and when you see something like +bold,italic it is not obvious which
of + and , have higher precedence.

If you have started to rely on the changed merging approach that came in
with layers, you may find your colours change. Thankfully layers have
not yet hit a release so no need to be compatible with that.

Oliver

diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo
index e20184121..9f7aeb0b9 100644
--- a/Doc/Zsh/zle.yo
+++ b/Doc/Zsh/zle.yo
@@ -990,14 +990,14 @@ The var(token) is preserved verbatim but not parsed in any way.
 Plugins may use this to identify array elements they have added: for example,
 a plugin might set var(token) to its (the plugin's) name and then use
 `tt(region_highlight=+LPAR() ${region_highlight:#*memo=)var(token)tt(} +RPAR())'
-in order to remove array elements it have added.
+in order to remove array elements it added.
 
 (This example uses the `tt(${)var(name)tt(:#)var(pattern)tt(})' array-grepping
 syntax described in
 sectref(Parameter Expansion)(zshexpn).))
 enditemize()
 
-For example, 
+For example,
 
 example(region_highlight=("P0 20 bold memo=foobar"))
 
@@ -1009,12 +1009,16 @@ as soon as the line is accepted.
 
 Note that zsh 5.8 and older do not support the `tt(memo=)var(token)' field
 and may misparse the third (highlight specification) field when a memo
-is given.
-COMMENT(The syntax `tt(0 20 bold, memo=foobar)' (with an auxiliary comma)
-happens to work on both zsh <=5.8 and zsh 5.9-to-be, but that seems to be more of
+is given. COMMENT(The syntax `tt(0 20 bold, memo=foobar)' (with an auxiliary comma)
+happens to work on both zsh <=5.8 and zsh 5.9, but that seems to be more of
 an accident of implementation than something we should make a first-class-citizen
 API promise.  It's mentioned in the "Incompatibilities" section of README.)
 
+Where a particular region is covered by multiple entries in
+tt(region_highlight), their effects are merged. In the case of conflicts, later
+entries take precedence over earlier ones. This precedence ordering can be
+overridden by specifying layers.
+
 The final highlighting on the command line depends on both tt(region_highlight)
 and tt(zle_highlight); see
 sectref(Character Highlighting)(below) for details.
@@ -2818,9 +2822,9 @@ not all types of highlighting are available on all terminals:
 
 startitem()
 item(tt(none))(
-No highlighting is applied to the given context.  It is not useful for
-this to appear with other types of highlighting; it is used to override
-a default.
+The terminal's default highlighting is applied to the given context.
+This can be useful as a way to clear all inherited highlighting, so
+may be used before naming other types of highlighting.
 )
 item(tt(fg=)var(colour))(
 The foreground colour should be set to var(colour), a decimal integer,
@@ -2888,12 +2892,20 @@ the associative array tt(.zle.hlgroups) to determine the actual highlighting.
 item(tt(layer=)var(layer))(
 The layer is used to determine precedence when multiple highlighting regions
 overlap. The var(layer) is a decimal integer, with higher numbers taking
-precedence over lower numbers. The default layer is 10 with 30 used as the
-default for tt(special), 20 for tt(region) and tt(isearch) and 15 for
-tt(paste).
-)
+precedence over lower numbers. This cannot be used with the tt(default) and
+tt(ellipsis) fields of tt(zle_highlight) because they treated as base layers.
+With the other fields 30 applies by default for tt(special), 20 for tt(region)
+and tt(isearch) and 15 for tt(paste). Highlighting defined in
+tt(region_highlight) defaults to layer 10 and would take precedence over
+highlighting for any fields of tt(zle_highlight) that are assigned to the same
+layer.)
 enditem()
 
+In addition, the simple highlighting types can be prefixed with tt("no") to
+explicitly disable them. This is useful where highlighting is merged with
+inherited highlighting from other definitions. Note that tt(nobold) selects a
+normal font weight so also has the effect of disabling tt(faint).
+
 The characters described above as `special' are as follows.  The
 formatting described here is used irrespective of whether the characters
 are highlighted:
diff --git a/Src/Modules/hlgroup.c b/Src/Modules/hlgroup.c
index 6c5a4bec4..1dc6ac2ef 100644
--- a/Src/Modules/hlgroup.c
+++ b/Src/Modules/hlgroup.c
@@ -43,7 +43,7 @@ convertattr(char *attrstr, int sgr)
     char *r, *s;
     int len;
 
-    match_highlight(attrstr, &atr, NULL);
+    match_highlight(attrstr, &atr, NULL, NULL);
     s = zattrescape(atr, sgr ? NULL : &len);
 
     if (sgr) {
diff --git a/Src/Modules/watch.c b/Src/Modules/watch.c
index acc499518..0d86142c1 100644
--- a/Src/Modules/watch.c
+++ b/Src/Modules/watch.c
@@ -375,7 +375,7 @@ watchlog2(int inout, WATCH_STRUCT_UTMP *u, char *fmt, int prnt, int fini)
 		    break;
 		case 'H':
 		    if (*fmt == '{') {
-			fmt = parsehighlight(fmt + 1, '}', &atr);
+			fmt = parsehighlight(fmt + 1, '}', &atr, NULL);
 			if (atr && atr != TXT_ERROR)
 			    treplaceattrs(atr);
 		    }
diff --git a/Src/Zle/complist.c b/Src/Zle/complist.c
index ea18434a3..4c87c15d7 100644
--- a/Src/Zle/complist.c
+++ b/Src/Zle/complist.c
@@ -1183,7 +1183,7 @@ compprintfmt(char *fmt, int n, int dopr, int doesc, int ml, int *stop)
 		    break;
 		case ZWC('H'):
 		    if (*p == '{') {
-			p = parsehighlight(p + 1, '}', &atr);
+			p = parsehighlight(p + 1, '}', &atr, NULL);
 			if (atr != TXT_ERROR && dopr)
 			    treplaceattrs(atr);
 		    }
diff --git a/Src/Zle/zle.h b/Src/Zle/zle.h
index 91eefc9e5..bf479d4cc 100644
--- a/Src/Zle/zle.h
+++ b/Src/Zle/zle.h
@@ -433,8 +433,10 @@ enum {
  * and mark.
  */
 struct region_highlight {
-    /* Attributes turned on in the region */
+    /* Attributes for the region */
     zattr atr;
+    /* Explicitly set attributes for the region */
+    zattr atrmask;
     /* Priority for this region relative to others that overlap */
     int layer;
     /* Start of the region */
diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c
index 3ea15ed60..793fb1e7a 100644
--- a/Src/Zle/zle_main.c
+++ b/Src/Zle/zle_main.c
@@ -1277,7 +1277,7 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish)
     raw_rp = rp;
     rpromptbuf = promptexpand(rp ? *rp : NULL, 1, markers[2], NULL, NULL);
     rpmpt_attr = txtcurrentattrs;
-    prompt_attr = mixattrs(pmpt_attr, rpmpt_attr);
+    prompt_attr = mixattrs(pmpt_attr, pmpt_attr, rpmpt_attr);
     free_prepostdisplay();
 
     zlereadflags = flags;
@@ -2032,7 +2032,7 @@ reexpandprompt(void)
 
 	    new_rprompt = promptexpand(raw_rp ? *raw_rp : NULL, 1, markers[2], NULL, NULL);
 	    rpmpt_attr = txtcurrentattrs;
-	    prompt_attr = mixattrs(pmpt_attr, rpmpt_attr);
+	    prompt_attr = mixattrs(pmpt_attr, pmpt_attr, rpmpt_attr);
 	    free(rpromptbuf);
 	    rpromptbuf = new_rprompt;
 	} while (looping != reexpanding);
diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c
index 943eda672..fd92ea6d7 100644
--- a/Src/Zle/zle_refresh.c
+++ b/Src/Zle/zle_refresh.c
@@ -208,7 +208,7 @@ int predisplaylen, postdisplaylen;
  * and for ellipsis continuation markers.
  */
 
-static zattr default_attr, special_attr, ellipsis_attr;
+static zattr default_attr, special_attr, special_mask, ellipsis_attr;
 
 /*
  * Layer applied to highlighting for special characters
@@ -359,28 +359,33 @@ zle_set_highlight(void)
 		paste_attr_set = region_attr_set =
 		    isearch_attr_set = suffix_attr_set = 1;
 	    } else if (strpfx("default:", *atrs)) {
-		match_highlight(*atrs + 8, &default_attr, NULL);
+		match_highlight(*atrs + 8, &default_attr, NULL, NULL);
 	    } else if (strpfx("special:", *atrs)) {
-		match_highlight(*atrs + 8, &special_attr, &special_layer);
+		match_highlight(*atrs + 8, &special_attr, &special_mask,
+			&special_layer);
 		special_attr_set = 1;
 	    } else if (strpfx("region:", *atrs)) {
 		match_highlight(*atrs + 7, &(region_highlights[0].atr),
+                        &(region_highlights[0].atrmask),
 			&(region_highlights[0].layer));
 		region_attr_set = 1;
 	    } else if (strpfx("isearch:", *atrs)) {
 		match_highlight(*atrs + 8, &(region_highlights[1].atr),
+                        &(region_highlights[0].atrmask),
 			&(region_highlights[1].layer));
 		isearch_attr_set = 1;
 	    } else if (strpfx("suffix:", *atrs)) {
 		match_highlight(*atrs + 7, &(region_highlights[2].atr),
+                        &(region_highlights[0].atrmask),
 			&(region_highlights[2].layer));
 		suffix_attr_set = 1;
 	    } else if (strpfx("paste:", *atrs)) {
 		match_highlight(*atrs + 6, &(region_highlights[3].atr),
+                        &(region_highlights[0].atrmask),
 			&(region_highlights[3].layer));
 		paste_attr_set = 1;
 	    } else if (strpfx("ellipsis:", *atrs)) {
-		match_highlight(*atrs + 9, &ellipsis_attr, NULL);
+		match_highlight(*atrs + 9, &ellipsis_attr, NULL, NULL);
 		ellipsis_attr_set = 1;
 	    }
 	}
@@ -442,7 +447,7 @@ get_region_highlight(UNUSED(Param pm))
 	int offset;
 	const char memo_equals[] = " memo=";
 	int alloclen = sprintf(digbuf, "%d %d", rhp->start, rhp->end) +
-	    output_highlight(rhp->atr, NULL) +
+	    output_highlight(rhp->atr, rhp->atrmask, NULL) +
 	    2; /* space and terminating NUL */
 	if (rhp->flags & ZRH_PREDISPLAY)
 	    alloclen++; /* "P" */
@@ -461,7 +466,7 @@ get_region_highlight(UNUSED(Param pm))
 	offset = sprintf(*arrp, "%s%s ",
 		(rhp->flags & ZRH_PREDISPLAY) ? "P" : "",
 		digbuf);
-	(void)output_highlight(rhp->atr, *arrp + offset);
+	(void)output_highlight(rhp->atr, rhp->atrmask, *arrp + offset);
 
 	if (rhp->layer != 10)
 	    strcat(*arrp, layerbuf);
@@ -537,7 +542,8 @@ set_region_highlight(UNUSED(Param pm), char **aval)
 	    strp++;
 
 	rhp->layer = 10; /* default */
-	strp = (char*) match_highlight(strp, &rhp->atr, &rhp->layer);
+	strp = (char*) match_highlight(strp, &rhp->atr, &rhp->atrmask,
+		&rhp->layer);
 
 	while (inblank(*strp))
 	    strp++;
@@ -1197,7 +1203,7 @@ zrefresh(void)
     rpms.s = nbuf[rpms.ln = 0] + lpromptw;
     rpms.sen = *nbuf + winw;
     for (t = tmpline, tmppos = 0; tmppos < tmpll; t++, tmppos++) {
-	zattr base_attr = mixattrs(default_attr, prompt_attr);
+	zattr base_attr = mixattrs(default_attr, default_attr, prompt_attr);
 	zattr all_attr = 0;
 	struct region_highlight *rhp;
 	int layer, nextlayer = 0;
@@ -1219,9 +1225,10 @@ zrefresh(void)
 			offset = predisplaylen; /* increment over it */
 		    if (rhp->start + offset <= tmppos &&
 			tmppos < rhp->end + offset) {
-			base_attr = mixattrs(rhp->atr, base_attr);
+			base_attr = mixattrs(rhp->atr, rhp->atrmask, base_attr);
 			if (layer > special_layer)
-			    all_attr = mixattrs(rhp->atr, all_attr);
+			    all_attr = mixattrs(rhp->atr, rhp->atrmask,
+				    all_attr);
 		    }
 		} else if (rhp->layer > layer &&
 			(rhp->layer < nextlayer || nextlayer <= layer)) {
@@ -1229,7 +1236,7 @@ zrefresh(void)
 		}
 	    }
 	    if (special_layer == layer) {
-		all_attr = mixattrs(special_attr, base_attr);
+		all_attr = mixattrs(special_attr, special_mask, base_attr);
 	    }
 	} while (nextlayer > layer);
 
@@ -2467,7 +2474,7 @@ singlerefresh(ZLE_STRING_T tmpline, int tmpll, int tmpcs)
 		}
 	    }
 	}
-	all_attr = mixattrs(special_attr, base_attr);
+	all_attr = mixattrs(special_attr, special_mask, base_attr);
 
 	if (t0 == tmpcs)
 	    nvcs = vp - vbuf;
diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c
index aa3c71bc2..f399ebd00 100644
--- a/Src/Zle/zle_tricky.c
+++ b/Src/Zle/zle_tricky.c
@@ -2503,7 +2503,7 @@ printfmt(char *fmt, int n, int dopr, int doesc)
 		    break;
 		case 'H':
 		    if (p[1] == '{') {
-			p = parsehighlight(p + 2, '}', &atr);
+			p = parsehighlight(p + 2, '}', &atr, NULL);
 			--p;
 			if (atr != TXT_ERROR)
 			    treplaceattrs(atr);
diff --git a/Src/prompt.c b/Src/prompt.c
index 801f1a727..4ec9f22de 100644
--- a/Src/prompt.c
+++ b/Src/prompt.c
@@ -277,7 +277,7 @@ zattrescape(zattr atr, int *len)
 /* Parse the argument for %H */
 /**/
 mod_export char *
-parsehighlight(char *arg, char endchar, zattr *atr)
+parsehighlight(char *arg, char endchar, zattr *atr, zattr *mask)
 {
     static int entered = 0;
     char *var = ".zle.hlgroups";
@@ -294,7 +294,7 @@ parsehighlight(char *arg, char endchar, zattr *atr)
 	if (ht && (node = (Param) ht->getnode(ht, arg))) {
 	    attrs = node->gsu.s->getfn(node);
 	    entered = 1;
-	    if (match_highlight(attrs, atr, 0) == attrs)
+	    if (match_highlight(attrs, atr, mask, NULL) == attrs)
 		*atr = TXT_ERROR;
 	} else
 	    *atr = TXT_ERROR;
@@ -639,7 +639,7 @@ putpromptchar(int doprint, int endchar)
 		break;
 	    case 'H':
 		if (bv->fm[1] == '{') {
-		    bv->fm = parsehighlight(bv->fm + 2, '}', &atr);
+		    bv->fm = parsehighlight(bv->fm + 2, '}', &atr, NULL);
 		    --bv->fm;
 		    if (atr != TXT_ERROR) {
 			treplaceattrs(atr);
@@ -1757,23 +1757,27 @@ tunsetattrs(zattr newattrs)
 	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. */
+/* Merge two attribute sets.
+ * secondary is the background base attributes
+ * primary is attributes to be overlaid, taking precedence.
+ * mask indicates those attributes in primary that were explicitly
+ * set allowing an explicitly disabled attribute in primary to take
+ * precedence. */
 
 /**/
 mod_export zattr
-mixattrs(zattr primary, zattr secondary)
+mixattrs(zattr primary, zattr mask, 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;
+    zattr select = mask & TXT_ATTR_ALL;
+
+    if (mask & TXTFGCOLOUR)
+	select |= TXT_ATTR_FG_MASK;
+    if (mask & TXTBGCOLOUR)
+	select |= TXT_ATTR_BG_MASK;
+    if (mask & TXT_ATTR_FONT_WEIGHT)
+	select |= TXT_ATTR_FONT_WEIGHT;
+
+    return (primary & select) | (secondary & ~select);
 }
 
 /*****************************************************************************
@@ -1923,15 +1927,17 @@ 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 *setmask to explicitly set attributes
  * 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, int *layer)
+match_highlight(const char *teststr, zattr *on_var, zattr *setmask, int *layer)
 {
     int found = 1;
+    zattr mask = 0;
 
     *on_var = 0;
     while (found && *teststr) {
@@ -1941,7 +1947,7 @@ match_highlight(const char *teststr, zattr *on_var, int *layer)
 	found = 0;
 	if (strpfx("hl=", teststr)) {
 	    teststr += 3;
-	    teststr = parsehighlight((char *)teststr, ',', &atr);
+	    teststr = parsehighlight((char *)teststr, ',', &atr, &mask);
 	    if (atr != TXT_ERROR)
 		*on_var = atr;
 	    found = 1;
@@ -1958,6 +1964,7 @@ match_highlight(const char *teststr, zattr *on_var, int *layer)
 	    /* skip out of range colours but keep scanning attributes */
 	    if (atr != TXT_ERROR)
 		*on_var |= atr;
+	    mask |= is_fg ? TXTFGCOLOUR : TXTBGCOLOUR;
 	} else if (layer && strpfx("layer=", teststr)) {
 	    teststr += 6;
 	    *layer = (int) zstrtol(teststr, (char **) &teststr, 10);
@@ -1967,7 +1974,8 @@ match_highlight(const char *teststr, zattr *on_var, int *layer)
 		break;
 	    found = 1;
 	} else {
-	    for (hl = highlights; hl->name; hl++) {
+	    int turn_off = 0;
+	    for (hl = highlights; !found && hl->name; hl++) {
 		if (strpfx(hl->name, teststr)) {
 		    const char *val = teststr + strlen(hl->name);
 
@@ -1976,14 +1984,25 @@ match_highlight(const char *teststr, zattr *on_var, int *layer)
 		    else if (*val && *val != ' ')
 			break;
 
-		    *on_var |= hl->mask_on;
-		    *on_var &= ~hl->mask_off;
+		    if (turn_off) {
+			*on_var &= ~hl->mask_on & ~hl->mask_off;
+		    } else {
+			*on_var |= hl->mask_on;
+			*on_var &= ~hl->mask_off;
+		    }
+		    mask |= hl->mask_on | hl->mask_off;
 		    teststr = val;
 		    found = 1;
 		}
+		/* delayed this to the end of the first iteration because "none"
+		 * starts with "no" */
+		if (hl == highlights && (turn_off = strpfx("no", teststr)))
+		    teststr += 2;
 	    }
 	}
     }
+    if (setmask)
+	*setmask = mask;
 
     return teststr;
 }
@@ -2038,22 +2057,28 @@ output_colour(int colour, int fg_bg, int truecol, char *buf)
 
 /**/
 mod_export int
-output_highlight(zattr atr, char *buf)
+output_highlight(zattr atr, zattr mask, char *buf)
 {
     const struct highlight *hp;
     int atrlen = 0, len;
     char *ptr = buf;
 
-    if (atr & TXTFGCOLOUR) {
-	len = output_colour(txtchangeget(atr, TXT_ATTR_FG_COL),
-			    COL_SEQ_FG,
-			    (atr & TXT_ATTR_FG_24BIT),
-			    ptr);
-	atrlen += len;
-	if (buf)
-	    ptr += len;
+    if (mask == TXT_ATTR_ALL) {
+	zattr threebits = ~atr & TXT_ATTR_ALL;
+	threebits &= threebits - 1; /* can't be both bold and faint */
+	threebits &= threebits - 1; /* strip next bit to allow one "no" entry */
+
+	if (threebits) { /* more remain - shorter to start with "none" */
+	    mask &= atr; /* mark unset bits from atr as done */
+	    atrlen = 4;
+	    if (buf) {
+		strcpy(ptr, "none");
+		ptr += 4;
+	    }
+	}
     }
-    if (atr & TXTBGCOLOUR) {
+
+    if (mask & TXTFGCOLOUR) {
 	if (atrlen) {
 	    atrlen++;
 	    if (buf) {
@@ -2061,16 +2086,46 @@ output_highlight(zattr atr, char *buf)
 		ptr++;
 	    }
 	}
-	len = output_colour(txtchangeget(atr, TXT_ATTR_BG_COL),
-			    COL_SEQ_BG,
-			    (atr & TXT_ATTR_BG_24BIT),
-			    ptr);
-	atrlen += len;
-	if (buf)
-	    ptr += len;
+	if (atr & TXTFGCOLOUR) {
+	    len = output_colour(txtchangeget(atr, TXT_ATTR_FG_COL), COL_SEQ_FG,
+		    (atr & TXT_ATTR_FG_24BIT), ptr);
+	    atrlen += len;
+	    if (buf)
+		ptr += len;
+	} else {
+	    atrlen += 10;
+	    if (buf) {
+		strcpy(ptr, "fg=default");
+		ptr += 10;
+	    }
+	}
     }
+    if (mask & TXTBGCOLOUR) {
+	if (atrlen) {
+	    atrlen++;
+	    if (buf) {
+		strcpy(ptr, ",");
+		ptr++;
+	    }
+	}
+	if (atr & TXTBGCOLOUR) {
+	    len = output_colour(txtchangeget(atr, TXT_ATTR_BG_COL), COL_SEQ_BG,
+		    (atr & TXT_ATTR_BG_24BIT), ptr);
+	    atrlen += len;
+	    if (buf)
+		ptr += len;
+	} else {
+	    atrlen += 10;
+	    if (buf) {
+		strcpy(ptr, "bg=default");
+		ptr += 10;
+	    }
+	}
+    }
+
     for (hp = highlights; hp->name; hp++) {
-	if (hp->mask_on & atr) {
+	if (hp->mask_on & mask && !(hp->mask_off & mask & atr)) {
+	    mask &= ~hp->mask_off;
 	    if (atrlen) {
 		atrlen++;
 		if (buf) {
@@ -2078,6 +2133,13 @@ output_highlight(zattr atr, char *buf)
 		    ptr++;
 		}
 	    }
+	    if (!(hp->mask_on & atr)) {
+		atrlen += 2;
+		if (buf) {
+		    strcpy(ptr, "no");
+		    ptr += 2;
+		}
+	    }
 	    len = strlen(hp->name);
 	    atrlen += len;
 	    if (buf) {
@@ -2088,9 +2150,11 @@ output_highlight(zattr atr, char *buf)
     }
 
     if (atrlen == 0) {
+	/* "none" means no attributes but if there was nothing, attributes
+	 * are left untouched so return something that signifies that. */
 	if (buf)
-	    strcpy(ptr, "none");
-	return 4;
+	    strcpy(ptr, "inherit");
+	return 7;
     }
     return atrlen;
 }




Messages sorted by: Reverse Date, Date, Thread, Author