From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on inbox.vuxu.org X-Spam-Level: X-Spam-Status: No, score=-3.5 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,DKIM_VALID_EF,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.4 Received: from zero.zsh.org (zero.zsh.org [IPv6:2a02:898:31:0:48:4558:7a:7368]) by inbox.vuxu.org (Postfix) with ESMTP id 4F6252650B for ; Thu, 25 Jan 2024 00:28:17 +0100 (CET) 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=0NlVuAeRlSkrNstJGcOv7Vh8cl8ENpLNjbtQ/iQV7qk=; b=HZvDcSqvtU9nCss6I9MvBhxtWN jo5gNwS3NrbkXaxa+qOUZSlfQbXjxNQ0cZ4MiiTV1ZjrzNV/0sI1XqmN7J3FPkMQ1Db0vJb4sb4S3 r0oEXjUeTNyBOxq5qygvZWSTsMPrPwh+HwHOWvyQ0bXUW92nAAzLYoL+ixRy26/N47FR+tPnQrTl2 a/r4KB8SP+yANH1W1Via405wrrV4qb6kPzLXrZ/19DUv3tGWTxvAnMDcCOmwMiGPAMlNdPiSRL4mc aVGi3hK3fzCaVt3ZTgtjnu2EJZT6wqG52lcJCix7MyOF+9viVIoqeOY7vl4YiHcaoGvKWnFgYJFCX AoY3n3wA==; Received: by zero.zsh.org with local id 1rSmfJ-000CEF-Qz; Wed, 24 Jan 2024 23:28:17 +0000 Received: by zero.zsh.org with esmtpsa (TLS1.3:TLS_AES_256_GCM_SHA384:256) id 1rSmYb-000Abm-Ak; Wed, 24 Jan 2024 23:21:21 +0000 Received: from [192.168.178.21] (helo=hydra) by mail.kiddle.eu with esmtp(Exim 4.97.1) (envelope-from ) id 1rSmYa-000000005U5-16d5 for zsh-workers@zsh.org; Thu, 25 Jan 2024 00:21:20 +0100 From: Oliver Kiddle To: Zsh workers Subject: PATCH: "layer" solution to overlapping regions in region_highlight MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-ID: <21083.1706138480.1@hydra> Date: Thu, 25 Jan 2024 00:21:20 +0100 Message-ID: <21084-1706138480.260334@sW7l.AVt3.fMhc> X-Seq: 52500 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: With more than one plugin that makes use of highlighting, it is difficult to ensure correct ordering so that if regions overlap, the right highlighting takes precedence. I think the zsh-syntax-highlighting even needs to reimplement highlighting for the region. The following patch is one approach to solving this. It adds a layer= token similar to memo= so that priorities can be specified. I'm not especially knowledgeable of how the same basic problem is solved elsewhere. Should we find a solution that supports mixing so that foreground colours can be preserved within a area where the formatting only covers the background colour? Is there existing convention on whether a lower or higher number for the layer would take precedence (this gives precedence to the higher value and applies 10 as the default and 20 for the region). Oliver diff --git a/Src/Zle/zle.h b/Src/Zle/zle.h index 1a3e4c241..010ead3d2 100644 --- a/Src/Zle/zle.h +++ b/Src/Zle/zle.h @@ -435,6 +435,8 @@ enum { struct region_highlight { /* Attributes turned on in the region */ zattr atr; + /* Priority for this region relative to others that overlap */ + int layer; /* Start of the region */ int start; /* Start of the region in metafied ZLE line */ diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c index a587f696a..f076bdd61 100644 --- a/Src/Zle/zle_refresh.c +++ b/Src/Zle/zle_refresh.c @@ -210,6 +210,12 @@ int predisplaylen, postdisplaylen; static zattr default_attr, special_attr, ellipsis_attr; +/* + * Layer applied to highlighting for special characters + */ + +static int special_layer; + /* * Array of region highlights, no special termination. * The first N_SPECIAL_HIGHLIGHTS elements describe special uses of @@ -337,6 +343,13 @@ zle_set_highlight(void) } } + /* Default layers */ + region_highlights[0].layer = 20; /* region */ + region_highlights[1].layer = 20; /* isearch */ + region_highlights[2].layer = 10; /* suffix */ + region_highlights[3].layer = 15; /* paste */ + special_layer = 30; + if (atrs) { for (; *atrs; atrs++) { if (!strcmp(*atrs, "none")) { @@ -346,30 +359,34 @@ 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); + match_highlight(*atrs + 8, &default_attr, NULL); } else if (strpfx("special:", *atrs)) { - match_highlight(*atrs + 8, &special_attr); + match_highlight(*atrs + 8, &special_attr, &special_layer); special_attr_set = 1; } else if (strpfx("region:", *atrs)) { - match_highlight(*atrs + 7, ®ion_highlights[0].atr); + match_highlight(*atrs + 7, &(region_highlights[0].atr), + &(region_highlights[0].layer)); region_attr_set = 1; } else if (strpfx("isearch:", *atrs)) { - match_highlight(*atrs + 8, &(region_highlights[1].atr)); + match_highlight(*atrs + 8, &(region_highlights[1].atr), + &(region_highlights[1].layer)); isearch_attr_set = 1; } else if (strpfx("suffix:", *atrs)) { - match_highlight(*atrs + 7, &(region_highlights[2].atr)); + match_highlight(*atrs + 7, &(region_highlights[2].atr), + &(region_highlights[2].layer)); suffix_attr_set = 1; } else if (strpfx("paste:", *atrs)) { - match_highlight(*atrs + 6, &(region_highlights[3].atr)); + match_highlight(*atrs + 6, &(region_highlights[3].atr), + &(region_highlights[3].layer)); paste_attr_set = 1; } else if (strpfx("ellipsis:", *atrs)) { - match_highlight(*atrs + 9, &ellipsis_attr); + match_highlight(*atrs + 9, &ellipsis_attr, NULL); ellipsis_attr_set = 1; } } } - /* Defaults */ + /* Default attributes */ if (!special_attr_set) special_attr = TXTSTANDOUT; if (!region_attr_set) @@ -407,14 +424,13 @@ zle_free_highlight(void) char ** get_region_highlight(UNUSED(Param pm)) { - int arrsize = n_region_highlights; + int arrsize = n_region_highlights - N_SPECIAL_HIGHLIGHTS; char **retarr, **arrp; struct region_highlight *rhp; /* region_highlights may not have been set yet */ - if (!arrsize) + if (!n_region_highlights) return hmkarray(NULL); - arrsize -= N_SPECIAL_HIGHLIGHTS; DPUTS(arrsize < 0, "arrsize is negative from n_region_highlights"); arrp = retarr = (char **)zhalloc((arrsize+1)*sizeof(char *)); @@ -422,20 +438,18 @@ get_region_highlight(UNUSED(Param pm)) for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; arrsize--; rhp++, arrp++) { - char digbuf1[DIGBUFSIZE], digbuf2[DIGBUFSIZE]; - int atrlen, alloclen; - const char memo_equals[] = "memo="; - - sprintf(digbuf1, "%d", rhp->start); - sprintf(digbuf2, "%d", rhp->end); - - atrlen = output_highlight(rhp->atr, NULL); - alloclen = atrlen + strlen(digbuf1) + strlen(digbuf2) + - 3; /* 2 spaces, 1 terminating NUL */ + char digbuf[2 * DIGBUFSIZE], layerbuf[7 + DIGBUFSIZE]; + int offset; + const char memo_equals[] = " memo="; + int alloclen = sprintf(digbuf, "%d %d", rhp->start, rhp->end) + + output_highlight(rhp->atr, NULL) + + 2; /* space and terminating NUL */ if (rhp->flags & ZRH_PREDISPLAY) - alloclen += 2; /* "P " */ + alloclen++; /* "P" */ + if (rhp->layer != 10) + alloclen += sprintf(layerbuf, ",layer=%d", rhp->layer); if (rhp->memo) - alloclen += 1 /* space */ + strlen(memo_equals) + strlen(rhp->memo); + alloclen += sizeof(memo_equals) - 1 + strlen(rhp->memo); *arrp = (char *)zhalloc(alloclen * sizeof(char)); /* * On input we allow a space after the flags. @@ -444,13 +458,14 @@ get_region_highlight(UNUSED(Param pm)) * into three words, and then check the first to * see if there are flags. However, it's arguable. */ - sprintf(*arrp, "%s%s %s ", + offset = sprintf(*arrp, "%s%s ", (rhp->flags & ZRH_PREDISPLAY) ? "P" : "", - digbuf1, digbuf2); - (void)output_highlight(rhp->atr, *arrp + strlen(*arrp)); + digbuf); + (void)output_highlight(rhp->atr, *arrp + offset); + if (rhp->layer != 10) + strcat(*arrp, layerbuf); if (rhp->memo) { - strcat(*arrp, " "); strcat(*arrp, memo_equals); strcat(*arrp, rhp->memo); } @@ -459,12 +474,10 @@ get_region_highlight(UNUSED(Param pm)) return retarr; } - /* * The parameter system requires the pm argument, but this * may be NULL if called directly. */ - /**/ void set_region_highlight(UNUSED(Param pm), char **aval) @@ -523,7 +536,8 @@ set_region_highlight(UNUSED(Param pm), char **aval) while (inblank(*strp)) strp++; - strp = (char*) match_highlight(strp, &rhp->atr); + rhp->layer = 10; /* default */ + strp = (char*) match_highlight(strp, &rhp->atr, &rhp->layer); while (inblank(*strp)) strp++; @@ -1180,27 +1194,40 @@ zrefresh(void) rpms.s = nbuf[rpms.ln = 0] + lpromptw; rpms.sen = *nbuf + winw; for (t = tmpline, tmppos = 0; tmppos < tmpll; t++, tmppos++) { - unsigned ireg; zattr base_attr = mixattrs(default_attr, prompt_attr); zattr all_attr; struct region_highlight *rhp; + int layer, nextlayer = 0; /* * Calculate attribute based on region. */ - for (ireg = 0, rhp = region_highlights; - ireg < n_region_highlights; - ireg++, rhp++) { - int offset; - if (rhp->flags & ZRH_PREDISPLAY) - offset = 0; /* include predisplay in start end */ - else - offset = predisplaylen; /* increment over it */ - if (rhp->start + offset <= tmppos && - tmppos < rhp->end + offset) { - base_attr = mixattrs(rhp->atr, base_attr); + do { + unsigned ireg; + layer = nextlayer; + nextlayer = special_layer; + for (ireg = 0, rhp = region_highlights; + ireg < n_region_highlights; + ireg++, rhp++) { + if (rhp->layer == layer) { + int offset; + if (rhp->flags & ZRH_PREDISPLAY) + offset = 0; /* include predisplay in start end */ + else + offset = predisplaylen; /* increment over it */ + if (rhp->start + offset <= tmppos && + tmppos < rhp->end + offset) { + base_attr = mixattrs(rhp->atr, base_attr); + if (layer > special_layer) + all_attr = mixattrs(rhp->atr, all_attr); + } + } else if (rhp->layer > layer && rhp->layer < nextlayer) { + nextlayer = rhp->layer; + } } - } - all_attr = mixattrs(special_attr, base_attr); + if (special_layer == layer) { + all_attr = mixattrs(special_attr, base_attr); + } + } while (nextlayer > layer); if (t == scs) /* if cursor is here, remember it */ rpms.nvcs = rpms.s - nbuf[rpms.nvln = rpms.ln]; diff --git a/Src/prompt.c b/Src/prompt.c index e4c213a13..ec79067cd 100644 --- a/Src/prompt.c +++ b/Src/prompt.c @@ -260,7 +260,7 @@ parsehighlight(char *arg, char endchar, zattr *atr) if ((node = (Param) ht->getnode(ht, arg))) { attrs = node->gsu.s->getfn(node); entered = 1; - if (match_highlight(attrs, atr) == attrs) + if (match_highlight(attrs, atr, 0) == attrs) *atr = TXT_ERROR; } else *atr = TXT_ERROR; @@ -1884,12 +1884,13 @@ 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; @@ -1918,6 +1919,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)) {