From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on inbox.vuxu.org X-Spam-Level: X-Spam-Status: No, score=-1.1 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE autolearn=ham autolearn_force=no version=3.4.2 Received: from primenet.com.au (ns1.primenet.com.au [203.24.36.2]) by inbox.vuxu.org (OpenSMTPD) with ESMTP id 4bbab1bb for ; Thu, 7 Feb 2019 20:33:24 +0000 (UTC) Received: (qmail 9205 invoked by alias); 7 Feb 2019 20:33:08 -0000 Mailing-List: contact zsh-workers-help@zsh.org; run by ezmlm Precedence: bulk X-No-Archive: yes List-Id: Zsh Workers List List-Post: List-Help: List-Unsubscribe: X-Seq: 44057 Received: (qmail 27564 invoked by uid 1010); 7 Feb 2019 20:33:08 -0000 X-Qmail-Scanner-Diagnostics: from mail-wm1-f66.google.com by f.primenet.com.au (envelope-from , uid 7791) with qmail-scanner-2.11 (clamdscan: 0.100.2/25112. spamassassin: 3.4.2. Clear:RC:0(209.85.128.66):SA:0(-2.0/5.0):. Processed in 2.599582 secs); 07 Feb 2019 20:33:08 -0000 X-Envelope-From: tamelingdaniel@gmail.com X-Qmail-Scanner-Mime-Attachments: | X-Qmail-Scanner-Zip-Files: | DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=date:from:to:subject:message-id:mail-followup-to:references :mime-version:content-disposition:in-reply-to; bh=nLggX7pR3nmEDCcWRZbkSN47dMaTii1OtOBw1BmynSs=; b=Ph21AQBoQW3IELJB2jclSx+TOZVv2/z/pGxdPNR7zBnMGG54RuuXMZyXJSeRTNaiT6 C5+Zn/Ntb7wkR24eCEgUDOGGGaiKwF4m9GME8ducN5YcQlXiofMB3xw57gHbeASHDvSU wxaNMVF1PCeJlnz08all5AsOZqytur2QV85kbu1PrzIvYv7sUuRFcnvCkJByFOPF/E0O grECQ4rmHRf9pFpFoflZJPE1/auHVXr/YLBEFewIUl9ET5Kdt2R3p0DPA6LDZ4QGCPcS FKTDPE6jaC/ux6TViikQbgZeVoul09JFRE4oruefj3nl11nc7o3DL00b7OYYk3SHVw27 1ZqA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:subject:message-id:mail-followup-to :references:mime-version:content-disposition:in-reply-to; bh=nLggX7pR3nmEDCcWRZbkSN47dMaTii1OtOBw1BmynSs=; b=VtlJNHfxc/6OW8NFekzyH2r6ZzuerjqcW3NtCHVNMdGSCEebuEldIO1oiq2u4kCsY4 eqIwofpGpVEBNDd001VzpOhMOBTd/GRi3QFMgP2Y/V5oTQfBrOtNo992eM+VyVszbG+U +sJQF5Ar1yybwljuSRMliv6TBVWoRPkEvJUF9oX1twTFMCSiZXRONPG8nBq3otyiklTW 8E0Ej+eU/+59Chnr4hY3IkcoR3RnJv9j65fWHZiuZpyW9pjDDhakPXbLP9/GiyZo9r+S /zwFxJbd4DlolkY70NhXFz8uIrHMZA1wNX5YSyJITZGX1yEl3TR5AaAtd3oTrJ4OLywV pR0g== X-Gm-Message-State: AHQUAuZXGXc1NiSgQAX/8QNDKoc7RvNe8Fli3R1pf4HxAuDOrxNHhhR+ DikTREZE34xGriE264G1Sd5ZprotLV0= X-Google-Smtp-Source: AHgI3IY91ZIiFXX7yDzORVTMaGaMvaL2GH0izBRcJUXrw4ES7LDfWnIbdfwo8JiWqm5lIXOZQb5hTA== X-Received: by 2002:a1c:eb1a:: with SMTP id j26mr7834568wmh.127.1549571578948; Thu, 07 Feb 2019 12:32:58 -0800 (PST) Date: Thu, 7 Feb 2019 21:32:57 +0100 From: Daniel Tameling To: zsh-workers@zsh.org Subject: Re: [PATCH] Support true colours via termcap interface Message-ID: <20190207203257.7sfyvpooegdjgice@Daniels-MacBook-Air.local> Mail-Followup-To: zsh-workers@zsh.org References: <20190203215711.sofrde7s4lb7nttb@Daniels-MacBook-Air.local> <20190204061946.dmygdd7n5c2zoi7d@Daniels-MacBook-Air.local> <20190204212123.mpzkt4bpajx2cxpw@Daniels-MacBook-Air.local> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline In-Reply-To: On Thu, Feb 07, 2019 at 08:36:50AM +0100, Sebastian Gniazdowski wrote: > > Could you restore the is_default_zle_highlight to its functioning state? > Took me some time, but yes, I managed it. In comparison to my last patch I made the following changes: a) I had missed that for colours > 7 the termcap interface was used. This is now unnecessary as the termcap attribute is returned whenever it makes sense to use this interface. That the colours > 7 check was still there broke true colours, so I removed that and now it's working fine. b) zle_highlight sequences are added to customize the true colour escape sequences: fg_24bit_start_code, fg_24bit_delim and the corresponding bg properties. For the end of the sequence, I used the normal end_codes as they appear to be usually the same. c) for the def case in set_colour_attribute, the true colour branch is removed. I don't see any way that could be triggered, and having a true colour version of "restore the default colour" doesn't really make sense in my opinion. d) move the is_default_zle_highlight logic to the place where the zle_highlight array is checked. This has the advantage that one doesn't need the string comparisons as the logic is implicit: if zle_highlight is not NULL bypass termcap, else use it. This has also the advantage that with "unset zle_highlight" you go back to using termcap; to accomplish the same thing, you currently have to set the codes you changed back to their default. There is one last problem, I don't know how to address best: once you use zle_highlight, you don't get the default sequences back if you remove an entry from the array or unset it. The X04 test passes as well. With TERM=xterm-direct only the two nearcolor module tests fail, which only make sense for 256 colour terminals. So everything looks good to me. I have tried to make the test more terminal agnostic, but that is something for the next email. Best regards, Daniel diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo index c2b9f5430..7bbbba5cd 100644 --- a/Doc/Zsh/zle.yo +++ b/Doc/Zsh/zle.yo @@ -2682,6 +2682,12 @@ colour. item(tt(fg_end_code) (tt(m)))( The end of the escape sequence for the foreground colour. ) +item(tt(fg_24bit_start_code) (tt(\e[38;2;)))( +The start of the escape sequence for the 24-bit foreground colour. +) +item(tt(fg_24bit_delim) (tt(;)))( +The delimiter between the colours for the escape sequence for the 24-bit foreground colour. +) item(tt(bg_start_code) (tt(\e[4)))( The start of the escape sequence for the background colour. See tt(fg_start_code) above. @@ -2693,6 +2699,12 @@ background colour. item(tt(bg_end_code) (tt(m)))( The end of the escape sequence for the background colour. ) +item(tt(bg_24bit_start_code) (tt(\e[48;2;)))( +The start of the escape sequence for the 24-bit background colour. +) +item(tt(bg_24bit_delim) (tt(;)))( +The delimiter between the colours for the escape sequence for the 24-bit background colour. +) enditem() The available types of highlighting are the following. Note that diff --git a/Src/prompt.c b/Src/prompt.c index f2b3f161e..11442b69e 100644 --- a/Src/prompt.c +++ b/Src/prompt.c @@ -1621,7 +1621,6 @@ match_colour(const char **teststrp, int is_fg, int colour) { int shft, named = 0, tc; zattr on; - if (is_fg) { shft = TXT_ATTR_FG_COL_SHIFT; on = TXTFGCOLOUR; @@ -1652,6 +1651,14 @@ match_colour(const char **teststrp, int is_fg, int colour) 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; + /* + * If we have a true colour termcap entry and colour > 7 + * use termcap; for colours 0-7 termcap usually emits the + * standard ANSI sequences; we don't want that. + */ + if (tccolours == 0x1000000 && colour > 7) { + on |= is_fg ? TXT_ATTR_FG_TERMCAP : TXT_ATTR_BG_TERMCAP; + } return on | (is_fg ? TXT_ATTR_FG_24BIT : TXT_ATTR_BG_24BIT) | (zattr)colour << shft; } else if (colour <= -2) { @@ -1668,7 +1675,7 @@ match_colour(const char **teststrp, int is_fg, int colour) } else { colour = (int)zstrtol(*teststrp, (char **)teststrp, 10); - if (colour < 0 || colour >= 256) + if (colour < 0 || colour >= tccolours) return TXT_ERROR; } } @@ -1692,6 +1699,16 @@ match_colour(const char **teststrp, int is_fg, int colour) */ on |= is_fg ? TXT_ATTR_FG_TERMCAP : TXT_ATTR_BG_TERMCAP; + /* + * If our terminal supports more than 256 colours it is + * most likely a true colour terminal (it's not always + * 256*256*256 colours: sometimes tccolours get truncated + * to the largest short, which is significantly smaller); + * if we don't use termcap, we want to emit true colour + * escape sequences for colour > 7. + */ + if (tccolours > 256 && colour > 7) + on |= is_fg ? TXT_ATTR_FG_24BIT : TXT_ATTR_BG_24BIT; } } return on | (zattr)colour << shft; @@ -1867,6 +1884,10 @@ output_highlight(zattr atr, char *buf) #define TC_COL_FG_END "m" /* Code to reset foreground colour */ #define TC_COL_FG_DEFAULT "9" +/* Start of true colour foreground escape sequence */ +#define TC_COL_FG_24BIT_START "\033[38;2;" +/* Delimiter for true colour foreground escape sequence */ +#define TC_COL_FG_24BIT_DELIM ";" /* Start of escape sequence for background colour */ #define TC_COL_BG_START "\033[4" @@ -1874,11 +1895,17 @@ output_highlight(zattr atr, char *buf) #define TC_COL_BG_END "m" /* Code to reset background colour */ #define TC_COL_BG_DEFAULT "9" +/* Start of true colour background escape sequence */ +#define TC_COL_BG_24BIT_START "\033[48;2;" +/* Delimiter for true colour background escape sequence */ +#define TC_COL_BG_24BIT_DELIM ";" struct colour_sequences { char *start; /* Escape sequence start */ char *end; /* Escape sequence terminator */ char *def; /* Code to reset default colour */ + char *start_24bit; /* True colour escape sequence start */ + char *delim_24bit; /* Delimiter for true colour sequence */ }; static struct colour_sequences fg_bg_sequences[2]; @@ -1902,10 +1929,14 @@ set_default_colour_sequences(void) fg_bg_sequences[COL_SEQ_FG].start = ztrdup(TC_COL_FG_START); fg_bg_sequences[COL_SEQ_FG].end = ztrdup(TC_COL_FG_END); fg_bg_sequences[COL_SEQ_FG].def = ztrdup(TC_COL_FG_DEFAULT); + fg_bg_sequences[COL_SEQ_FG].start_24bit = ztrdup(TC_COL_FG_24BIT_START); + fg_bg_sequences[COL_SEQ_FG].delim_24bit = ztrdup(TC_COL_FG_24BIT_DELIM); fg_bg_sequences[COL_SEQ_BG].start = ztrdup(TC_COL_BG_START); fg_bg_sequences[COL_SEQ_BG].end = ztrdup(TC_COL_BG_END); fg_bg_sequences[COL_SEQ_BG].def = ztrdup(TC_COL_BG_DEFAULT); + fg_bg_sequences[COL_SEQ_BG].start_24bit = ztrdup(TC_COL_BG_24BIT_START); + fg_bg_sequences[COL_SEQ_BG].delim_24bit = ztrdup(TC_COL_BG_24BIT_DELIM); } static void @@ -1919,6 +1950,12 @@ set_colour_code(char *str, char **var) *var = metafy(keyseq, len, META_DUP); } +/* + * if non-zero try to use termcap to emit colors + * otherwise use fg_bg_sequences + */ +static int is_default_zle_highlight = 1; + /* Allocate buffer for colour code composition */ /**/ @@ -1926,7 +1963,7 @@ mod_export void allocate_colour_buffer(void) { char **atrs; - int lenfg, lenbg, len; + int lenfg, lenbg, len, len24bit; if (colseq_buf_allocs++) return; @@ -1940,33 +1977,59 @@ allocate_colour_buffer(void) set_colour_code(*atrs + 16, &fg_bg_sequences[COL_SEQ_FG].def); } else if (strpfx("fg_end_code:", *atrs)) { set_colour_code(*atrs + 12, &fg_bg_sequences[COL_SEQ_FG].end); + } else if (strpfx("fg_24bit_start_code:", *atrs)) { + set_colour_code(*atrs + 20, &fg_bg_sequences[COL_SEQ_FG].start_24bit); + } else if (strpfx("fg_24bit_delim:", *atrs)) { + set_colour_code(*atrs + 15, &fg_bg_sequences[COL_SEQ_FG].delim_24bit); } else if (strpfx("bg_start_code:", *atrs)) { set_colour_code(*atrs + 14, &fg_bg_sequences[COL_SEQ_BG].start); } else if (strpfx("bg_default_code:", *atrs)) { set_colour_code(*atrs + 16, &fg_bg_sequences[COL_SEQ_BG].def); } else if (strpfx("bg_end_code:", *atrs)) { set_colour_code(*atrs + 12, &fg_bg_sequences[COL_SEQ_BG].end); + } else if (strpfx("bg_24bit_start_code:", *atrs)) { + set_colour_code(*atrs + 20, &fg_bg_sequences[COL_SEQ_BG].start_24bit); + } else if (strpfx("bg_24bit_delim:", *atrs)) { + set_colour_code(*atrs + 15, &fg_bg_sequences[COL_SEQ_BG].delim_24bit); } } - } + is_default_zle_highlight = 0; + } else + is_default_zle_highlight = 1; lenfg = strlen(fg_bg_sequences[COL_SEQ_FG].def); - /* always need 1 character for non-default code */ - if (lenfg < 1) - lenfg = 1; + /* make sure there is space for 3 digit colours */ + if (lenfg < 3) + lenfg = 3; lenfg += strlen(fg_bg_sequences[COL_SEQ_FG].start) + strlen(fg_bg_sequences[COL_SEQ_FG].end); lenbg = strlen(fg_bg_sequences[COL_SEQ_BG].def); - /* always need 1 character for non-default code */ - if (lenbg < 1) - lenbg = 1; + /* make sure there is space for 3 digit colours */ + if (lenbg < 3) + lenbg = 3; lenbg += strlen(fg_bg_sequences[COL_SEQ_BG].start) + strlen(fg_bg_sequences[COL_SEQ_BG].end); len = lenfg > lenbg ? lenfg : lenbg; - /* add 1 for the null and 14 for truecolor */ - colseq_buf = (char *)zalloc(len+15); + + lenfg = strlen(fg_bg_sequences[COL_SEQ_FG].start_24bit) + + 2 * strlen(fg_bg_sequences[COL_SEQ_FG].delim_24bit) + + strlen(fg_bg_sequences[COL_SEQ_FG].end); + /* add 9 for the colours */ + lenfg += 9; + + lenbg = strlen(fg_bg_sequences[COL_SEQ_BG].start_24bit) + + 2 * strlen(fg_bg_sequences[COL_SEQ_BG].delim_24bit) + + strlen(fg_bg_sequences[COL_SEQ_BG].end); + /* add 9 for the colours */ + lenbg += 9; + + len24bit = lenfg > lenbg ? lenfg : lenbg; + len = len > len24bit ? len : len24bit; + + /* add 1 for the null */ + colseq_buf = (char *)zalloc(len+1); } /* Free the colour buffer previously allocated. */ @@ -2002,7 +2065,6 @@ 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, use_truecolor; - int is_default_zle_highlight = 1; if (fg_bg == COL_SEQ_FG) { colour = txtchangeget(atr, TXT_ATTR_FG_COL); @@ -2018,17 +2080,6 @@ set_colour_attribute(zattr atr, int fg_bg, int flags) use_termcap = txtchangeisset(atr, TXT_ATTR_BG_TERMCAP); } - /* Test if current zle_highlight settings are customized, or - * the typical "standard" codes */ - if (0 != strcmp(fg_bg_sequences[fg_bg].start, fg_bg == COL_SEQ_FG ? TC_COL_FG_START : TC_COL_BG_START) || - /* the same in-fix for both FG and BG */ - 0 != strcmp(fg_bg_sequences[fg_bg].def, TC_COL_FG_DEFAULT) || - /* the same suffix for both FG and BG */ - 0 != strcmp(fg_bg_sequences[fg_bg].end, TC_COL_FG_END)) - { - is_default_zle_highlight = 0; - } - /* * If we're not restoring the default, and either have a * colour value that is too large for ANSI, or have been told @@ -2039,8 +2090,7 @@ set_colour_attribute(zattr atr, int fg_bg, int flags) * highlighting variables, so much of this shouldn't be * necessary at this point, but we might as well be safe. */ - if (!def && !use_truecolor && - (is_default_zle_highlight && (colour > 7 || use_termcap))) + if (!def && is_default_zle_highlight && use_termcap) { /* * We can if it's available, and either we couldn't get @@ -2083,31 +2133,27 @@ set_colour_attribute(zattr atr, int fg_bg, int flags) * or the typical true-color code: .start + 8;2;%d;%d;%d + .end * or the typical 256-color code: .start + 8;5;%d + .end */ - if (use_truecolor) - strcpy(colseq_buf, fg_bg == COL_SEQ_FG ? TC_COL_FG_START : TC_COL_BG_START); + if (use_truecolor){ + strcpy(colseq_buf, fg_bg_sequences[fg_bg].start_24bit); + } else strcpy(colseq_buf, fg_bg_sequences[fg_bg].start); ptr = colseq_buf + strlen(colseq_buf); if (def) { - if (use_truecolor) - strcpy(ptr, fg_bg == COL_SEQ_FG ? TC_COL_FG_DEFAULT : TC_COL_BG_DEFAULT); - else - strcpy(ptr, fg_bg_sequences[fg_bg].def); + 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); + ptr += sprintf(ptr, "%d%s%d%s%d", colour >> 16, + fg_bg_sequences[fg_bg].delim_24bit, (colour >> 8) & 0xff, + fg_bg_sequences[fg_bg].delim_24bit, colour & 0xff); } else if (colour > 7 && colour <= 255) { ptr += sprintf(ptr, "%d", colour); } else *ptr++ = colour + '0'; - if (use_truecolor) - strcpy(ptr, fg_bg == COL_SEQ_FG ? TC_COL_FG_END : TC_COL_BG_END); - else - strcpy(ptr, fg_bg_sequences[fg_bg].end); + strcpy(ptr, fg_bg_sequences[fg_bg].end); if (is_prompt) { if (!bv->dontcount) { addbufspc(1); diff --git a/Test/X04zlehighlight.ztst b/Test/X04zlehighlight.ztst index 000949698..c44202bd7 100644 --- a/Test/X04zlehighlight.ztst +++ b/Test/X04zlehighlight.ztst @@ -13,7 +13,7 @@ zpty -d zpty zsh "${(q)ZTST_testdir}/../Src/zsh -fiV +Z" zpty -w zsh "module_path=( ${(j< >)${(@q-)module_path}} \$module_path )" - zpty -w zsh 'zle_highlight=( fg_start_code:"CDE|3" fg_end_code:"|" bg_start_code:"BCDE|4" bg_end_code:"|" )' + zpty -w zsh 'zle_highlight=( fg_start_code:"CDE|3" fg_24bit_start_code:"FGH|3|" fg_end_code:"|" bg_start_code:"BCDE|4|" bg_24bit_start_code:"FGH|4" bg_end_code:"|" )' } zpty_input() { zpty ${${(M)2:#nonl}:+-n} -w zsh "$1" @@ -103,7 +103,7 @@ zpty_line 1 p # the line of interest, preserving escapes ("p") zpty_stop 0:basic region_highlight with true-color (hex-triplets) ->0m27m24m38;2;4;8;16mtrueCDE|39| +>0m27m24mFGH|3|4;8;16|trueCDE|39| zpty_start zpty_input 'zmodload zsh/nearcolor' @@ -139,7 +139,7 @@ zpty_line 1 p # the line of interest, preserving escapes ("p") zpty_stop 0:overlapping region_highlight with true-color ->0m27m24m38;2;0;204;0mt38;2;204;0;0mrCDE|39|38;2;0;204;0mueCDE|39| +>0m27m24mFGH|3|0;204;0|tFGH|3|204;0;0|rCDE|39|FGH|3|0;204;0|ueCDE|39| zpty_start zpty_input 'zmodload zsh/nearcolor'