summaryrefslogtreecommitdiff
path: root/Src/prompt.c
diff options
context:
space:
mode:
authorJoe Rayhawk <jrayhawk@fairlystable.org>2025-04-30 02:07:56 -0700
committerJoe Rayhawk <jrayhawk@fairlystable.org>2025-04-30 02:07:56 -0700
commit26e09889646be3ea65b4a3dfeda26213e4bb6a27 (patch)
tree4f3c73a9416bf47ad7e125383d23cf42879e38d7 /Src/prompt.c
parent841bce705a58b04220b1f257abcc00ae71cbdbdc (diff)
parent001cba48ce3b964cf01fb3e2af54b20eacbc9bf5 (diff)
downloadzsh-26e09889646be3ea65b4a3dfeda26213e4bb6a27.tar.gz
zsh-26e09889646be3ea65b4a3dfeda26213e4bb6a27.zip
Merge branch 'upstream' into debian
Diffstat (limited to 'Src/prompt.c')
-rw-r--r--Src/prompt.c429
1 files changed, 317 insertions, 112 deletions
diff --git a/Src/prompt.c b/Src/prompt.c
index 092de63a4..7467cdfb9 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;
@@ -401,7 +469,7 @@ putpromptchar(int doprint, int endchar, zattr *txtchangep)
test = 1;
break;
case 'S':
- if (time(NULL) - shtimer.tv_sec >= arg)
+ if (zmonotime(NULL) - shtimer.tv_sec >= arg)
test = 1;
break;
case 'v':
@@ -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;
}
@@ -488,8 +555,7 @@ putpromptchar(int doprint, int endchar, zattr *txtchangep)
if (jobtab[j].stat && jobtab[j].procs &&
!(jobtab[j].stat & STAT_NOPRINT)) numjobs++;
addbufspc(DIGBUFSIZE);
- sprintf(bv->bp, "%d", numjobs);
- bv->bp += strlen(bv->bp);
+ bv->bp += sprintf(bv->bp, "%d", numjobs);
break;
case 'M':
queue_signals();
@@ -519,71 +585,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 +658,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 '{': /*}*/
@@ -719,20 +781,18 @@ putpromptchar(int doprint, int endchar, zattr *txtchangep)
case 'L':
addbufspc(DIGBUFSIZE);
#if defined(ZLONG_IS_LONG_LONG) && defined(PRINTF_HAS_LLD)
- sprintf(bv->bp, "%lld", shlvl);
+ bv->bp += sprintf(bv->bp, "%lld", shlvl);
#else
- sprintf(bv->bp, "%ld", (long)shlvl);
+ bv->bp += sprintf(bv->bp, "%ld", (long)shlvl);
#endif
- bv->bp += strlen(bv->bp);
break;
case '?':
addbufspc(DIGBUFSIZE);
#if defined(ZLONG_IS_LONG_LONG) && defined(PRINTF_HAS_LLD)
- sprintf(bv->bp, "%lld", lastval);
+ bv->bp += sprintf(bv->bp, "%lld", lastval);
#else
- sprintf(bv->bp, "%ld", (long)lastval);
+ bv->bp += sprintf(bv->bp, "%ld", (long)lastval);
#endif
- bv->bp += strlen(bv->bp);
break;
case '%':
case ')':
@@ -823,8 +883,7 @@ putpromptchar(int doprint, int endchar, zattr *txtchangep)
fsptr = fsptr->prev;
}
addbufspc(DIGBUFSIZE);
- sprintf(bv->bp, "%d", depth);
- bv->bp += strlen(bv->bp);
+ bv->bp += sprintf(bv->bp, "%d", depth);
break;
}
case 'I':
@@ -841,11 +900,10 @@ putpromptchar(int doprint, int endchar, zattr *txtchangep)
lineno--;
addbufspc(DIGBUFSIZE);
#if defined(ZLONG_IS_LONG_LONG) && defined(PRINTF_HAS_LLD)
- sprintf(bv->bp, "%lld", flineno);
+ bv->bp += sprintf(bv->bp, "%lld", flineno);
#else
- sprintf(bv->bp, "%ld", (long)flineno);
+ bv->bp += sprintf(bv->bp, "%ld", (long)flineno);
#endif
- bv->bp += strlen(bv->bp);
break;
}
/* else we're in a file and lineno is already correct */
@@ -853,11 +911,10 @@ putpromptchar(int doprint, int endchar, zattr *txtchangep)
case 'i':
addbufspc(DIGBUFSIZE);
#if defined(ZLONG_IS_LONG_LONG) && defined(PRINTF_HAS_LLD)
- sprintf(bv->bp, "%lld", lineno);
+ bv->bp += sprintf(bv->bp, "%lld", lineno);
#else
- sprintf(bv->bp, "%ld", (long)lineno);
+ bv->bp += sprintf(bv->bp, "%ld", (long)lineno);
#endif
- bv->bp += strlen(bv->bp);
break;
case 'x':
if (funcstack && funcstack->tp != FS_SOURCE &&
@@ -1013,9 +1070,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 +1101,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 +1261,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 +1308,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 +1588,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 +1626,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 +1800,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 +1840,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 +1861,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 +1888,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 +1910,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 +1945,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)) {
@@ -1776,7 +1984,7 @@ match_highlight(const char *teststr, zattr *on_var)
static int
output_colour(int colour, int fg_bg, int truecol, char *buf)
{
- int atrlen = 3, len;
+ int atrlen = 3;
char *ptr = buf;
if (buf) {
strcpy(ptr, fg_bg == COL_SEQ_FG ? "fg=" : "bg=");
@@ -1794,14 +2002,11 @@ output_colour(int colour, int fg_bg, int truecol, char *buf)
*/
} else if (colour > 7) {
char digbuf[DIGBUFSIZE];
- sprintf(digbuf, "%d", colour);
- len = strlen(digbuf);
- atrlen += len;
+ atrlen += sprintf(digbuf, "%d", colour);
if (buf)
strcpy(ptr, digbuf);
} else {
- len = strlen(ansi_colours[colour]);
- atrlen += len;
+ atrlen += strlen(ansi_colours[colour]);
if (buf)
strcpy(ptr, ansi_colours[colour]);
}
@@ -2024,13 +2229,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