From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on inbox.vuxu.org X-Spam-Level: X-Spam-Status: No, score=-3.4 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham autolearn_force=no version=3.4.4 Received: (qmail 23207 invoked from network); 4 Jan 2023 01:06:17 -0000 Received: from zero.zsh.org (2a02:898:31:0:48:4558:7a:7368) by inbox.vuxu.org with ESMTPUTF8; 4 Jan 2023 01:06:17 -0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=zsh.org; s=rsa-20210803; h=List-Archive:List-Owner:List-Post:List-Unsubscribe: List-Subscribe:List-Help:List-Id:Sender:Message-ID:Date:Content-ID: Content-Type:MIME-Version:Subject:To:From:Reply-To:Cc: Content-Transfer-Encoding:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References; bh=xNFR4C7BFWsXyvxI53IriKEhJB/Pd3lzTaSWuqB5oGs=; b=kjlnx7xBtuoHE5I7wnxkuoig8p bJ0pAiC9Zk5Lhg3xHmHHACrtyyLtbh1Gm4unTqvs/kHvWR40GGcc7MZaoSwCzIvms3xPwMKHzc2lq wB9Gebwm5a3Zxvsk/OCbKv6QX81PhpE6fRMvdfhyB7NozyA7KMCUJiiWJT842hfLa3RO6eFpSkJnb SrMNnHQd3v4kbSFCiBBIrG/+Re4VbH6wV55Gyy5JyFctQa5N4L0oWQ1JQ8paK8TdF1qndsBTV070L +rVfezuqwuyKOueF3ZotvO2FCwi3LyKng5ObX5fb7HgRRH1w1e2CDYPWWPa4F+IEQuucLQCVdpa4U zS17BtFg==; Received: by zero.zsh.org with local id 1pCsES-000408-LT; Wed, 04 Jan 2023 01:06:16 +0000 Received: by zero.zsh.org with esmtpsa (TLS1.3:TLS_AES_256_GCM_SHA384:256) id 1pCs7U-0003X6-99; Wed, 04 Jan 2023 00:59:04 +0000 Received: from [192.168.178.21] (helo=hydra) by mail.kiddle.eu with esmtp(Exim 4.95) (envelope-from ) id 1pCs7T-0009QG-Ph for zsh-workers@zsh.org; Wed, 04 Jan 2023 01:59:03 +0100 From: Oliver Kiddle To: Zsh workers Subject: PATCH: support for italic and faint fonts from region_highlight MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-ID: <36222.1672793943.1@hydra> Date: Wed, 04 Jan 2023 01:59:03 +0100 Message-ID: <36223-1672793943.791824@SLuG.9t5a.jH-P> X-Seq: 51274 Archived-At: X-Loop: zsh-workers@zsh.org Errors-To: zsh-workers-owner@zsh.org Precedence: list Precedence: bulk Sender: zsh-workers-request@zsh.org X-no-archive: yes List-Id: List-Help: , List-Subscribe: , List-Unsubscribe: , List-Post: List-Owner: List-Archive: Having got rid of the OFF flags in zattr, there are bits available for additional attributes. This patch adds support for italic and faint in $region_highlight using two of the available 8 bits. Other attributes with widely documented sequences include blink, strikeout, double underline, invisible. None of these strike me as especially useful and adding them might limit future expansion. I've also come across fast blinking, overline, borders, rounded borders, curly, dotted, dashed and coloured underline. One approach could be to find a way to support user-defined attributes e.g: zle_highlight+=( 'user1_begin_code:\e[9m' 'user1_end_code:\e[29m' 'user2_begin_code:\e[58;5;88m\e[4;3m' 'user2_end_code:\e[4;0m' 'user2_excl:underline' special:user1 paste:user2 ) This patch doesn't address prompts at all. We've discussed ideas before such as %O...%o. or %A{italic}. The %A form would need to support ways to unset attributes too so "noitalic" and perhaps "normal" for font weight that is neither bold nor faint. But would it be better to instead use an associative array and lookup attributes via that, e.g: zle_theme=( [warning]='fg=yellow' ) print -P '%A{warning}Yellow text%a' I currently need to convert colours to a variety of forms in my .zshrc to suit a variety of commands and this could be made easier. A final matter where ideas and opinions would be useful is the precedence of values in region_highlight. In my own setup I've experienced frustrations with array order not being a convenient way to manage this and looking at external plugins, everyone just appends values so I doubt it works especially well when mixing plugins. Most attributes are merged so if one value requires bold and another underline, you get both. But for colours, entries later in region_highlight take precedence. I've followed that pattern for font weight. A special-case appears to have been made for special character highlighting. In one instance, I suspect a bug in the old code. A solution that comes to mind would be to allow a layer= entry in the attribute list. We could assign default layers to region, paste, special etc. This also might not need users to wait for plugin authors to update their plugin where plugins allow attributes to be customised. What would be a good naming/numbering scheme for layers, are there established existing conventions on that, e.g. in the graphics field? Would we also need another parameter to mask what is passed through from lower layers? Finally, some notes on the patch: italic does have a termcap entry but it is sometimes missing where it would be supported so this falls back on defaults. Does anyone have a view on whether we should use "italics" instead of "italic" as the naming? There is no termcap entry for faint so that is hard-coded. To avoid duplicating all of tsetcap() I've extended it to handle fake termcap entries for higher-numbered values of the cap parameter and an added X in the macro name, e.g. TCXFAINTBEG. Oliver diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo index 58700072a..60254e828 100644 --- a/Doc/Zsh/zle.yo +++ b/Doc/Zsh/zle.yo @@ -2780,9 +2780,13 @@ This works similarly to the foreground colour, except the background is not usually affected by the bold attribute. ) item(tt(bold))( -The characters in the given context are shown in a bold font. +The characters in the given context are shown with a bold font weight. Not all terminals distinguish bold fonts. ) +item(tt(faint))( +The characters in the given context are shown with a faint font weight. +Not all terminals distinguish faint fonts. +) item(tt(standout))( The characters in the given context are shown in the terminal's standout mode. The actual effect is specific to the terminal; on many terminals it @@ -2796,6 +2800,10 @@ The characters in the given context are shown underlined. Some terminals show the foreground in a different colour instead; in this case whitespace will not be highlighted. ) +item(tt(italic))( +The characters in the given context are shown in a italic font. +Not all terminals support italic fonts. +) enditem() The characters described above as `special' are as follows. The diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c index d56478147..e2131fb05 100644 --- a/Src/Zle/zle_refresh.c +++ b/Src/Zle/zle_refresh.c @@ -1193,23 +1193,23 @@ zrefresh(void) offset = predisplaylen; /* increment over it */ if (rhp->start + offset <= tmppos && tmppos < rhp->end + offset) { - if (rhp->atr & (TXTFGCOLOUR|TXTBGCOLOUR)) { - /* override colour with later entry */ - base_attr = rhp->atr; - } else { - /* no colour set yet */ - base_attr |= rhp->atr; - } + /* override colour with later entry */ + if (rhp->atr & (TXTFGCOLOUR|TXTBGCOLOUR)) + base_attr &= ~TXT_ATTR_COLOUR_MASK; + /* override font weight with later entry */ + if (rhp->atr & TXT_ATTR_FONT_WEIGHT) + base_attr &= ~TXT_ATTR_FONT_WEIGHT; + base_attr |= rhp->atr; } } - if (special_attr & (TXTFGCOLOUR|TXTBGCOLOUR)) { - /* keep colours from special attributes */ - all_attr = special_attr | - (base_attr & ~TXT_ATTR_COLOUR_MASK); - } else { - /* keep colours from standard attributes */ - all_attr = special_attr | base_attr; - } + all_attr = base_attr; + /* keep colours from special attributes */ + if (special_attr & (TXTFGCOLOUR|TXTBGCOLOUR)) + all_attr &= ~TXT_ATTR_COLOUR_MASK; + /* keep font weight from special attributes */ + if (special_attr & TXT_ATTR_FONT_WEIGHT) + all_attr &= ~TXT_ATTR_FONT_WEIGHT; + all_attr |= special_attr; if (t == scs) /* if cursor is here, remember it */ rpms.nvcs = rpms.s - nbuf[rpms.nvln = rpms.ln]; @@ -2441,14 +2441,14 @@ singlerefresh(ZLE_STRING_T tmpline, int tmpll, int tmpcs) } } } - if (special_attr & (TXTFGCOLOUR|TXTBGCOLOUR)) { - /* keep colours from special attributes */ - all_attr = special_attr | - (base_attr & ~TXT_ATTR_COLOUR_MASK); - } else { - /* keep colours from standard attributes */ - all_attr = special_attr | base_attr; - } + all_attr = base_attr; + /* keep colours from special attributes */ + if (special_attr & (TXTFGCOLOUR|TXTBGCOLOUR)) + all_attr &= ~TXT_ATTR_COLOUR_MASK; + /* keep font weight from special attributes */ + if (special_attr & TXT_ATTR_FONT_WEIGHT) + all_attr &= ~TXT_ATTR_FONT_WEIGHT; + all_attr |= special_attr; if (tmpline[t0] == ZWC('\t')) { for (*vp++ = zr_sp; (vp - vbuf) & 7; ) diff --git a/Src/init.c b/Src/init.c index 75ef2e094..9eef3f16d 100644 --- a/Src/init.c +++ b/Src/init.c @@ -747,7 +747,7 @@ init_shout(void) static char *tccapnams[TC_COUNT] = { "cl", "le", "LE", "nd", "RI", "up", "UP", "do", "DO", "dc", "DC", "ic", "IC", "cd", "ce", "al", "dl", "ta", - "md", "so", "us", "me", "se", "ue", "ch", + "md", "so", "us", "ZH", "me", "se", "ue", "ZR", "ch", "ku", "kd", "kl", "kr", "sc", "rc", "bc", "AF", "AB" }; @@ -872,6 +872,19 @@ init_term(void) /* The following is an attempt at a heuristic, * but it fails in some cases */ /* rprompt_indent = ((hasam && !hasbw) || hasye || !tccan(TCLEFT)); */ + + /* if there's no termcap entry for italics, use CSI 3 m */ + if (!tccan(TCITALICSBEG)) { + zsfree(tcstr[TCITALICSBEG]); + tcstr[TCITALICSBEG] = ztrdup("\033[3m"); + tclen[TCITALICSBEG] = 4; + } + if (!tccan(TCITALICSEND)) { + zsfree(tcstr[TCITALICSEND]); + tcstr[TCITALICSEND] = ztrdup("\033[23m"); + tclen[TCITALICSEND] = 5; + } + } return 1; } diff --git a/Src/prompt.c b/Src/prompt.c index 880194f87..dc575085f 100644 --- a/Src/prompt.c +++ b/Src/prompt.c @@ -45,6 +45,12 @@ mod_export zattr txtpendingattrs; /**/ mod_export zattr txtunknownattrs; +/* common escape sequences not found in termcap */ + +static char *tcxstr[TCX_COUNT - TC_COUNT] = { + "\e[2m", /* faint */ +}; + /* the command stack for use with %_ in prompts */ /**/ @@ -1004,22 +1010,23 @@ stradd(char *d) mod_export void tsetcap(int cap, int flags) { - if (tccan(cap) && !isset(SINGLELINEZLE) && + if ((cap >= TC_COUNT || tccan(cap)) && !isset(SINGLELINEZLE) && !(termflags & (TERM_NOUP|TERM_BAD|TERM_UNKNOWN))) { + const char *tcseq = (cap >= TC_COUNT) ? tcxstr[cap - TC_COUNT] : tcstr[cap]; switch (flags) { case TSC_RAW: - tputs(tcstr[cap], 1, putraw); + tputs(tcseq, 1, putraw); break; case 0: default: - tputs(tcstr[cap], 1, putshout); + tputs(tcseq, 1, putshout); break; case TSC_PROMPT: if (!bv->dontcount) { addbufspc(1); *bv->bp++ = Inpar; } - tputs(tcstr[cap], 1, putstr); + tputs(tcseq, 1, putstr); if (!bv->dontcount) { int glitch = 0; @@ -1590,7 +1597,14 @@ applytextattributes(int flags) turnoff &= turnoff - 1; } - if (keepcount < turncount || (change & ~txtpendingattrs & TXTBOLDFACE)) { + /* enabling bold can be relied upon to disable faint */ + 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; @@ -1607,13 +1621,19 @@ applytextattributes(int 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(TCXFAINTBEG, 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); @@ -1700,9 +1720,11 @@ struct highlight { static const struct highlight highlights[] = { { "none", 0, TXT_ATTR_ALL }, - { "bold", TXTBOLDFACE, 0 }, + { "bold", TXTBOLDFACE, TXTFAINT }, + { "faint", TXTFAINT, TXTBOLDFACE }, { "standout", TXTSTANDOUT, 0 }, { "underline", TXTUNDERLINE, 0 }, + { "italic", TXTITALIC, 0 }, { NULL, 0, 0 } }; diff --git a/Src/zsh.h b/Src/zsh.h index 35ae033e3..e8b9fd84b 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -2648,20 +2648,26 @@ struct ttyinfo { #define TCBOLDFACEBEG 18 #define TCSTANDOUTBEG 19 #define TCUNDERLINEBEG 20 -#define TCALLATTRSOFF 21 -#define TCSTANDOUTEND 22 -#define TCUNDERLINEEND 23 -#define TCHORIZPOS 24 -#define TCUPCURSOR 25 -#define TCDOWNCURSOR 26 -#define TCLEFTCURSOR 27 -#define TCRIGHTCURSOR 28 -#define TCSAVECURSOR 29 -#define TCRESTRCURSOR 30 -#define TCBACKSPACE 31 -#define TCFGCOLOUR 32 -#define TCBGCOLOUR 33 -#define TC_COUNT 34 +#define TCITALICSBEG 21 +#define TCALLATTRSOFF 22 +#define TCSTANDOUTEND 23 +#define TCUNDERLINEEND 24 +#define TCITALICSEND 26 +#define TCHORIZPOS 26 +#define TCUPCURSOR 27 +#define TCDOWNCURSOR 28 +#define TCLEFTCURSOR 29 +#define TCRIGHTCURSOR 30 +#define TCSAVECURSOR 31 +#define TCRESTRCURSOR 32 +#define TCBACKSPACE 33 +#define TCFGCOLOUR 34 +#define TCBGCOLOUR 35 +#define TC_COUNT 36 + +/* escape sequences for which there is no termcap sequence */ +#define TCXFAINTBEG 36 +#define TCX_COUNT 37 #define tccan(X) (tclen[X]) @@ -2676,12 +2682,14 @@ struct ttyinfo { #endif #define TXTBOLDFACE 0x0001 -#define TXTSTANDOUT 0x0002 -#define TXTUNDERLINE 0x0004 -#define TXTFGCOLOUR 0x0008 -#define TXTBGCOLOUR 0x0010 +#define TXTFAINT 0x0002 +#define TXTSTANDOUT 0x0004 +#define TXTUNDERLINE 0x0008 +#define TXTITALIC 0x0010 +#define TXTFGCOLOUR 0x0020 +#define TXTBGCOLOUR 0x0040 -#define TXT_ATTR_ALL 0x001F +#define TXT_ATTR_ALL 0x007F /* * Indicates to zle_refresh.c that the character entry is an @@ -2690,7 +2698,10 @@ struct ttyinfo { #define TXT_MULTIWORD_MASK 0x0400 /* used when, e.g an invalid colour is specified */ -#define TXT_ERROR 0xF00000F000000800 +#define TXT_ERROR 0xF00000F000000003 + +/* Mask for font weight */ +#define TXT_ATTR_FONT_WEIGHT (TXTBOLDFACE|TXTFAINT) /* Mask for colour to use in foreground */ #define TXT_ATTR_FG_COL_MASK 0x000000FFFFFF0000