diff options
Diffstat (limited to 'Src/prompt.c')
-rw-r--r-- | Src/prompt.c | 137 |
1 files changed, 90 insertions, 47 deletions
diff --git a/Src/prompt.c b/Src/prompt.c index 959ed8e3d..568bfc2a9 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,24 +1616,12 @@ 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 (teststrp) { - if ((named = ialpha(**teststrp))) { - colour = match_named_colour(teststrp); - if (colour == 8) { - /* default */ - return is_fg ? TXTNOFGCOLOUR : TXTNOBGCOLOUR; - } - } - 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; @@ -1642,8 +1631,47 @@ match_colour(const char **teststrp, int is_fg, int colour) on = TXTBGCOLOUR; tc = TCBGCOLOUR; } + if (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; + } else + return TXT_ERROR; + *teststrp = end; + colour = runhookdef(GETCOLORATTR, &color) - 1; + if (colour == -1) { /* 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 (colour <= -2) { + return TXT_ERROR; + } + } else if ((named = ialpha(**teststrp))) { + colour = match_named_colour(teststrp); + if (colour == 8) { + /* default */ + return is_fg ? TXTNOFGCOLOUR : TXTNOBGCOLOUR; + } + } + else { + colour = (int)zstrtol(*teststrp, (char **)teststrp, 10); + 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. */ @@ -1654,7 +1682,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 @@ -1664,7 +1692,7 @@ match_colour(const char **teststrp, int is_fg, int colour) TXT_ATTR_BG_TERMCAP; } } - return on | (colour << shft); + return on | (zattr)colour << shft; } /* @@ -1674,7 +1702,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; @@ -1684,7 +1712,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); @@ -1694,7 +1723,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++) { @@ -1718,11 +1747,12 @@ match_highlight(const char *teststr, int *on_var) /* * Count or output a string for colour information: used - * by output_highlight(). + * by output_highlight(). count when buf is NULL. + * returned count excludes the terminating null byte. */ static int -output_colour(int colour, int fg_bg, int use_tc, char *buf) +output_colour(int colour, int fg_bg, int use_tc, int truecol, char *buf) { int atrlen = 3, len; char *ptr = buf; @@ -1730,8 +1760,12 @@ output_colour(int colour, int fg_bg, int use_tc, char *buf) strcpy(ptr, fg_bg == COL_SEQ_FG ? "fg=" : "bg="); ptr += 3; } + if (truecol) { + /* length of hex triplet always 7, don't need sprintf to count */ + atrlen += buf ? sprintf(ptr, "#%02x%02x%02x", colour >> 16, + (colour >> 8) & 0xff, colour & 0xff) : 7; /* colour should only be > 7 if using termcap but let's be safe */ - if (use_tc || colour > 7) { + } else if (use_tc || colour > 7) { char digbuf[DIGBUFSIZE]; sprintf(digbuf, "%d", colour); len = strlen(digbuf); @@ -1759,7 +1793,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; @@ -1769,6 +1803,7 @@ output_highlight(int atr, char *buf) len = output_colour(txtchangeget(atr, TXT_ATTR_FG_COL), COL_SEQ_FG, (atr & TXT_ATTR_FG_TERMCAP), + (atr & TXT_ATTR_FG_24BIT), ptr); atrlen += len; if (buf) @@ -1785,6 +1820,7 @@ output_highlight(int atr, char *buf) len = output_colour(txtchangeget(atr, TXT_ATTR_BG_COL), COL_SEQ_BG, (atr & TXT_ATTR_BG_TERMCAP), + (atr & TXT_ATTR_BG_24BIT), ptr); atrlen += len; if (buf) @@ -1922,7 +1958,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. */ @@ -1953,21 +1990,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); } @@ -1975,12 +2014,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. @@ -2024,6 +2064,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); |