From 955caae47843d12448bb273043537ccde22776f6 Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Sun, 3 May 2020 04:42:53 +0000 Subject: [PATCH 01/13] Support an 'owner' key in region_highlight. This is to allow plugins to easily remove only entries they had added. See https://github.com/zsh-users/zsh-syntax-highlighting/issues/418 and the cross-referenced issues. --- Doc/Zsh/zle.yo | 19 +++++++++++-------- Src/Zle/zle.h | 4 ++++ Src/Zle/zle_refresh.c | 29 +++++++++++++++++++++++------ Src/Zle/zle_utils.c | 2 ++ Src/prompt.c | 9 ++++++--- Test/X04zlehighlight.ztst | 11 +++++++++++ 6 files changed, 57 insertions(+), 17 deletions(-) diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo index c928b8ca2d..d92c4cae58 100644 --- a/Doc/Zsh/zle.yo +++ b/Doc/Zsh/zle.yo @@ -974,27 +974,30 @@ of the non-editable parts of the command line in tt(PREDISPLAY) and tt(POSTDISPLAY) are possible, but note that the tt(P) flag is needed for character indexing to include tt(PREDISPLAY). -Each string consists of the following parts: +Each string consists of the following whitespace-separated parts: startitemize() itemiz(Optionally, a `tt(P)' to signify that the start and end offset that follow include any string set by the tt(PREDISPLAY) special parameter; this is needed if the predisplay string itself is to be highlighted. -Whitespace may follow the `tt(P)'.) -itemiz(A start offset in the same units as tt(CURSOR), terminated by -whitespace.) -itemiz(An end offset in the same units as tt(CURSOR), terminated by -whitespace.) +Whitespace between the `tt(P)' and the start offset is optional.) +itemiz(A start offset in the same units as tt(CURSOR).) +itemiz(An end offset in the same units as tt(CURSOR).) itemiz(A highlight specification in the same format as used for contexts in the parameter tt(zle_highlight), see ifnzman(noderef(Character Highlighting))\ ifzman(the section `Character Highlighting' below); -for example, tt(standout) or tt(fg=red,bold)). +for example, tt(standout) or tt(fg=red,bold).) +itemiz(Optionally, a string of the form `tt(owner=)var(token)'. +The var(token) value is preserved verbatim but not parsed in any way. +Plugins may use this to identify elements they had added, for example, in order +to remove them with +`tt(region_highlight=+LPAR() ${region_highlight:#*owner=)var(token)tt(} +RPAR())'.) enditemize() For example, -example(region_highlight=("P0 20 bold")) +example(region_highlight=("P0 20 bold owner=myplugin")) specifies that the first twenty characters of the text including any predisplay string should be highlighted in bold. diff --git a/Src/Zle/zle.h b/Src/Zle/zle.h index 609493f8c4..1857965c49 100644 --- a/Src/Zle/zle.h +++ b/Src/Zle/zle.h @@ -447,6 +447,10 @@ struct region_highlight { * Any of the flags defined above. */ int flags; + /* + * User-settable "owner" key. Metafied. + */ + const char *owner; }; /* diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c index 7b8593dec0..787bf36ab2 100644 --- a/Src/Zle/zle_refresh.c +++ b/Src/Zle/zle_refresh.c @@ -212,9 +212,9 @@ static zattr default_atr_on, special_atr_on; /* * Array of region highlights, no special termination. - * The first element (0) always describes the region between - * point and mark. Any other elements are set by the user - * via the parameter region_highlight. + * The first N_SPECIAL_HIGHLIGHTS elements describe special uses of + * highlighting, documented under N_SPECIAL_HIGHLIGHTS. + * Any other elements are set by the user via the parameter region_highlight. */ /**/ @@ -414,16 +414,19 @@ get_region_highlight(UNUSED(Param pm)) arrsize--; rhp++, arrp++) { char digbuf1[DIGBUFSIZE], digbuf2[DIGBUFSIZE]; - int atrlen = 0, alloclen; + int atrlen, alloclen; + const char owner_equals[] = "owner="; 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 0 */ + 3; /* 2 spaces, 1 terminating NUL */ if (rhp->flags & ZRH_PREDISPLAY) alloclen += 2; /* "P " */ + if (rhp->owner) + alloclen += 1 /* space */ + strlen(owner_equals) + strlen(rhp->owner); *arrp = (char *)zhalloc(alloclen * sizeof(char)); /* * On input we allow a space after the flags. @@ -436,6 +439,12 @@ get_region_highlight(UNUSED(Param pm)) (rhp->flags & ZRH_PREDISPLAY) ? "P" : "", digbuf1, digbuf2); (void)output_highlight(rhp->atr, *arrp + strlen(*arrp)); + + if (rhp->owner) { + strcat(*arrp, " "); + strcat(*arrp, owner_equals); + strcat(*arrp, rhp->owner); + } } *arrp = NULL; return retarr; @@ -502,7 +511,15 @@ set_region_highlight(UNUSED(Param pm), char **aval) while (inblank(*strp)) strp++; - match_highlight(strp, &rhp->atr); + strp = (char*) match_highlight(strp, &rhp->atr); + + while (inblank(*strp)) + strp++; + + if (strpfx("owner=", strp)) + rhp->owner = ztrdup(strp + 6); + else + rhp->owner = NULL; } freearray(av); diff --git a/Src/Zle/zle_utils.c b/Src/Zle/zle_utils.c index 2b306fdcdb..328062558e 100644 --- a/Src/Zle/zle_utils.c +++ b/Src/Zle/zle_utils.c @@ -632,6 +632,7 @@ zle_save_positions(void) newrhp->next = NULL; newrhp->atr = rhp->atr; newrhp->flags = rhp->flags; + /* TODO: save rhp->owner here? */ if (zlemetaline) { newrhp->start = rhp->start_meta; newrhp->end = rhp->end_meta; @@ -694,6 +695,7 @@ zle_restore_positions(void) rhp->atr = oldrhp->atr; rhp->flags = oldrhp->flags; + rhp->owner = NULL; if (zlemetaline) { rhp->start_meta = oldrhp->start; rhp->end_meta = oldrhp->end; diff --git a/Src/prompt.c b/Src/prompt.c index b65bfb86b6..bc97347202 100644 --- a/Src/prompt.c +++ b/Src/prompt.c @@ -1724,10 +1724,11 @@ 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. + * Return a pointer to the first character not consumed. */ /**/ -mod_export void +mod_export const char * match_highlight(const char *teststr, zattr *on_var) { int found = 1; @@ -1745,7 +1746,7 @@ match_highlight(const char *teststr, zattr *on_var) atr = match_colour(&teststr, is_fg, 0); if (*teststr == ',') teststr++; - else if (*teststr) + else if (*teststr && *teststr != ' ') break; found = 1; /* skip out of range colours but keep scanning attributes */ @@ -1758,7 +1759,7 @@ match_highlight(const char *teststr, zattr *on_var) if (*val == ',') val++; - else if (*val) + else if (*val && *val != ' ') break; *on_var |= hl->mask_on; @@ -1769,6 +1770,8 @@ match_highlight(const char *teststr, zattr *on_var) } } } + + return teststr; } /* diff --git a/Test/X04zlehighlight.ztst b/Test/X04zlehighlight.ztst index 475a2e309b..9744a83bab 100644 --- a/Test/X04zlehighlight.ztst +++ b/Test/X04zlehighlight.ztst @@ -94,6 +94,17 @@ 0:basic region_highlight with 8 colors >0m27m24mCDE|32|trueCDE|39| + zpty_start + zpty_input 'rh_widget() { region_highlight+=( "0 4 fg=green owner=someplugin" ); typeset -p region_highlight }' + zpty_input 'zle -N rh_widget' + zpty_input 'bindkey "\C-a" rh_widget' + zpty_enable_zle + zpty_input $'\C-a' + zpty_line + zpty_stop +0:region_highlight owner information round trips +>typeset -a region_highlight=( '0 4 fg=green owner=someplugin' ) + zpty_start zpty_input 'rh_widget() { BUFFER="true"; region_highlight+=( "0 4 fg=#040810" ); }' zpty_input 'zle -N rh_widget' From 62444af2664ae35a85f8f442e00ae5b8135a50af Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Wed, 17 Jun 2020 08:55:59 +0000 Subject: [PATCH 02/13] squash! Support an 'owner' key in region_highlight. [s/owner=/memo=/g] Support a 'memo' key in region_highlight. This is to allow plugins to easily remove only entries they had added. See https://github.com/zsh-users/zsh-syntax-highlighting/issues/418 and the cross-referenced issues. This was initially worked on at https://github.com/zsh-users/zsh/pull/57, where it was initially called "owner=". --- Doc/Zsh/zle.yo | 6 +++--- Src/Zle/zle.h | 4 ++-- Src/Zle/zle_refresh.c | 18 +++++++++--------- Src/Zle/zle_utils.c | 4 ++-- Test/X04zlehighlight.ztst | 6 +++--- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo index d92c4cae58..cc2722be17 100644 --- a/Doc/Zsh/zle.yo +++ b/Doc/Zsh/zle.yo @@ -988,16 +988,16 @@ used for contexts in the parameter tt(zle_highlight), see ifnzman(noderef(Character Highlighting))\ ifzman(the section `Character Highlighting' below); for example, tt(standout) or tt(fg=red,bold).) -itemiz(Optionally, a string of the form `tt(owner=)var(token)'. +itemiz(Optionally, a string of the form `tt(memo=)var(token)'. The var(token) value is preserved verbatim but not parsed in any way. Plugins may use this to identify elements they had added, for example, in order to remove them with -`tt(region_highlight=+LPAR() ${region_highlight:#*owner=)var(token)tt(} +RPAR())'.) +`tt(region_highlight=+LPAR() ${region_highlight:#*memo=)var(token)tt(} +RPAR())'.) enditemize() For example, -example(region_highlight=("P0 20 bold owner=myplugin")) +example(region_highlight=("P0 20 bold memo=myplugin")) specifies that the first twenty characters of the text including any predisplay string should be highlighted in bold. diff --git a/Src/Zle/zle.h b/Src/Zle/zle.h index 1857965c49..391586c4a0 100644 --- a/Src/Zle/zle.h +++ b/Src/Zle/zle.h @@ -448,9 +448,9 @@ struct region_highlight { */ int flags; /* - * User-settable "owner" key. Metafied. + * User-settable "memo" key. Metafied. */ - const char *owner; + const char *memo; }; /* diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c index 787bf36ab2..96c2d62df1 100644 --- a/Src/Zle/zle_refresh.c +++ b/Src/Zle/zle_refresh.c @@ -415,7 +415,7 @@ get_region_highlight(UNUSED(Param pm)) rhp++, arrp++) { char digbuf1[DIGBUFSIZE], digbuf2[DIGBUFSIZE]; int atrlen, alloclen; - const char owner_equals[] = "owner="; + const char memo_equals[] = "memo="; sprintf(digbuf1, "%d", rhp->start); sprintf(digbuf2, "%d", rhp->end); @@ -425,8 +425,8 @@ get_region_highlight(UNUSED(Param pm)) 3; /* 2 spaces, 1 terminating NUL */ if (rhp->flags & ZRH_PREDISPLAY) alloclen += 2; /* "P " */ - if (rhp->owner) - alloclen += 1 /* space */ + strlen(owner_equals) + strlen(rhp->owner); + if (rhp->memo) + alloclen += 1 /* space */ + strlen(memo_equals) + strlen(rhp->memo); *arrp = (char *)zhalloc(alloclen * sizeof(char)); /* * On input we allow a space after the flags. @@ -440,10 +440,10 @@ get_region_highlight(UNUSED(Param pm)) digbuf1, digbuf2); (void)output_highlight(rhp->atr, *arrp + strlen(*arrp)); - if (rhp->owner) { + if (rhp->memo) { strcat(*arrp, " "); - strcat(*arrp, owner_equals); - strcat(*arrp, rhp->owner); + strcat(*arrp, memo_equals); + strcat(*arrp, rhp->memo); } } *arrp = NULL; @@ -516,10 +516,10 @@ set_region_highlight(UNUSED(Param pm), char **aval) while (inblank(*strp)) strp++; - if (strpfx("owner=", strp)) - rhp->owner = ztrdup(strp + 6); + if (strpfx("memo=", strp)) + rhp->memo = ztrdup(strp + 5); else - rhp->owner = NULL; + rhp->memo = NULL; } freearray(av); diff --git a/Src/Zle/zle_utils.c b/Src/Zle/zle_utils.c index 328062558e..044674eddd 100644 --- a/Src/Zle/zle_utils.c +++ b/Src/Zle/zle_utils.c @@ -632,7 +632,7 @@ zle_save_positions(void) newrhp->next = NULL; newrhp->atr = rhp->atr; newrhp->flags = rhp->flags; - /* TODO: save rhp->owner here? */ + /* TODO: save rhp->memo here? */ if (zlemetaline) { newrhp->start = rhp->start_meta; newrhp->end = rhp->end_meta; @@ -695,7 +695,7 @@ zle_restore_positions(void) rhp->atr = oldrhp->atr; rhp->flags = oldrhp->flags; - rhp->owner = NULL; + rhp->memo = NULL; if (zlemetaline) { rhp->start_meta = oldrhp->start; rhp->end_meta = oldrhp->end; diff --git a/Test/X04zlehighlight.ztst b/Test/X04zlehighlight.ztst index 9744a83bab..58d43cac25 100644 --- a/Test/X04zlehighlight.ztst +++ b/Test/X04zlehighlight.ztst @@ -95,15 +95,15 @@ >0m27m24mCDE|32|trueCDE|39| zpty_start - zpty_input 'rh_widget() { region_highlight+=( "0 4 fg=green owner=someplugin" ); typeset -p region_highlight }' + zpty_input 'rh_widget() { region_highlight+=( "0 4 fg=green memo=someplugin" ); typeset -p region_highlight }' zpty_input 'zle -N rh_widget' zpty_input 'bindkey "\C-a" rh_widget' zpty_enable_zle zpty_input $'\C-a' zpty_line zpty_stop -0:region_highlight owner information round trips ->typeset -a region_highlight=( '0 4 fg=green owner=someplugin' ) +0:region_highlight memo information round trips +>typeset -a region_highlight=( '0 4 fg=green memo=someplugin' ) zpty_start zpty_input 'rh_widget() { BUFFER="true"; region_highlight+=( "0 4 fg=#040810" ); }' From 0bc43f24727615f36f73223bf8326990408d30ca Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Wed, 17 Jun 2020 09:20:29 +0000 Subject: [PATCH 03/13] fixup! Support an 'owner' key in region_highlight. [Remove a magic number] --- Src/Zle/zle_refresh.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c index 96c2d62df1..1412d8a615 100644 --- a/Src/Zle/zle_refresh.c +++ b/Src/Zle/zle_refresh.c @@ -485,6 +485,7 @@ set_region_highlight(UNUSED(Param pm), char **aval) *aval; rhp++, aval++) { char *strp, *oldstrp; + const char memo_equals[] = "memo="; oldstrp = *aval; if (*oldstrp == 'P') { @@ -516,8 +517,8 @@ set_region_highlight(UNUSED(Param pm), char **aval) while (inblank(*strp)) strp++; - if (strpfx("memo=", strp)) - rhp->memo = ztrdup(strp + 5); + if (strpfx(memo_equals, strp)) + rhp->memo = ztrdup(strp + strlen(memo_equals)); else rhp->memo = NULL; } From 140f1e4f39db99b2920700f4d9c8b345abcd7b8d Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Wed, 17 Jun 2020 09:35:17 +0000 Subject: [PATCH 04/13] CHECKPOINT: Forward compatibility for the memo's value Incomplete; see test. Fixed in the next commit. --- Doc/Zsh/zle.yo | 13 ++++++++----- Src/Zle/zle_refresh.c | 23 ++++++++++++++++++++--- Test/X04zlehighlight.ztst | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 8 deletions(-) diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo index cc2722be17..dab964585b 100644 --- a/Doc/Zsh/zle.yo +++ b/Doc/Zsh/zle.yo @@ -989,15 +989,18 @@ ifnzman(noderef(Character Highlighting))\ ifzman(the section `Character Highlighting' below); for example, tt(standout) or tt(fg=red,bold).) itemiz(Optionally, a string of the form `tt(memo=)var(token)'. -The var(token) value is preserved verbatim but not parsed in any way. -Plugins may use this to identify elements they had added, for example, in order -to remove them with -`tt(region_highlight=+LPAR() ${region_highlight:#*memo=)var(token)tt(} +RPAR())'.) +The var(token) consists of everything between the `tt(=)' and the next +whitespace, comma, NUL, or the end of the string. +The var(token) is preserved verbatim but not parsed in any way. +Plugins may use this to identify array elements they have added: for example, +a plugin might set var(token) to its (the plugin's) name and then use +`tt(region_highlight=+LPAR() ${region_highlight:#*memo=)var(token)tt(} +RPAR())' +in order to remove array elements it have added.) enditemize() For example, -example(region_highlight=("P0 20 bold memo=myplugin")) +example(region_highlight=("P0 20 bold memo=foobar")) specifies that the first twenty characters of the text including any predisplay string should be highlighted in bold. diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c index 1412d8a615..8f0c10b667 100644 --- a/Src/Zle/zle_refresh.c +++ b/Src/Zle/zle_refresh.c @@ -517,9 +517,26 @@ set_region_highlight(UNUSED(Param pm), char **aval) while (inblank(*strp)) strp++; - if (strpfx(memo_equals, strp)) - rhp->memo = ztrdup(strp + strlen(memo_equals)); - else + if (strpfx(memo_equals, strp)) { + const char *memo_start = strp + strlen(memo_equals); + const char *memo_end = memo_start; + + /* + * Forward compatibility: end parsing at a comma or whitespace to + * allow the following extensions: + * + * - A fifth field: "0 20 bold memo=foo bar". + * + * - Additional attributes in the fourth field: "0 20 bold memo=foo,bar". + * + * For similar reasons, we don't flag an error if the fourth field + * doesn't start with "memo=" as we expect. + */ + while (*memo_end && *memo_end != ',' && !inblank(*memo_end)) + ++memo_end; + + rhp->memo = ztrduppfx(memo_start, memo_end - memo_start); + } else rhp->memo = NULL; } diff --git a/Test/X04zlehighlight.ztst b/Test/X04zlehighlight.ztst index 58d43cac25..20d8e55588 100644 --- a/Test/X04zlehighlight.ztst +++ b/Test/X04zlehighlight.ztst @@ -105,6 +105,44 @@ 0:region_highlight memo information round trips >typeset -a region_highlight=( '0 4 fg=green memo=someplugin' ) + zpty_start + zpty_input 'rh_widget() { region_highlight+=( "0 4 fg=green memo=someplugin,futureattribute=futurevalue" ); typeset -p region_highlight }' + zpty_input 'zle -N rh_widget' + zpty_input 'bindkey "\C-a" rh_widget' + zpty_enable_zle + zpty_input $'\C-a' + zpty_line + zpty_stop +0:region_highlight memo information forward compatibility, #1 +>typeset -a region_highlight=( '0 4 fg=green memo=someplugin' ) + + zpty_start + zpty_input 'rh_widget() { region_highlight+=( "0 4 fg=green memo=someplugin futurefifthfield" ); typeset -p region_highlight }' + zpty_input 'zle -N rh_widget' + zpty_input 'bindkey "\C-a" rh_widget' + zpty_enable_zle + zpty_input $'\C-a' + zpty_line + zpty_stop +0:region_highlight memo information forward compatibility, #2 +>typeset -a region_highlight=( '0 4 fg=green memo=someplugin' ) + + zpty_start + zpty_input 'rh_widget() { region_highlight+=( "0 4 fg=green memo=some'$'\0''plugin" ); typeset -p region_highlight }' + zpty_input 'zle -N rh_widget' + zpty_input 'bindkey "\C-a" rh_widget' + zpty_enable_zle + zpty_input $'\C-a' + zpty_line + zpty_stop +0:region_highlight memo information forward compatibility, #3: NULs +>typeset -a region_highlight=( '0 4 fg=green memo=some' ) +F:Fails because the memo_end iteration works on plain characters, but $'\0' is +F:encoded as META SPACE ("\x83\x20") and SPACE happens to test true for the +F:loop termination condition. +F: +F:set_region_highlight() should be taught to handle strp's being metafied. + zpty_start zpty_input 'rh_widget() { BUFFER="true"; region_highlight+=( "0 4 fg=#040810" ); }' zpty_input 'zle -N rh_widget' From a2b6a3f69ebb1b75dc7a85a5feb9e9307ee25b69 Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Wed, 17 Jun 2020 09:56:21 +0000 Subject: [PATCH 05/13] Support metafied and multibyte characters in the memo. Fixes NUL support (see tests). --- Src/Zle/zle_refresh.c | 20 ++++++++++++++++---- Test/X04zlehighlight.ztst | 5 ----- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c index 8f0c10b667..af52f8794f 100644 --- a/Src/Zle/zle_refresh.c +++ b/Src/Zle/zle_refresh.c @@ -519,7 +519,7 @@ set_region_highlight(UNUSED(Param pm), char **aval) if (strpfx(memo_equals, strp)) { const char *memo_start = strp + strlen(memo_equals); - const char *memo_end = memo_start; + const char *i, *memo_end; /* * Forward compatibility: end parsing at a comma or whitespace to @@ -527,14 +527,26 @@ set_region_highlight(UNUSED(Param pm), char **aval) * * - A fifth field: "0 20 bold memo=foo bar". * - * - Additional attributes in the fourth field: "0 20 bold memo=foo,bar". + * - Additional attributes in the fourth field: "0 20 bold memo=foo,bar" + * and "0 20 bold memo=foo\0bar". * * For similar reasons, we don't flag an error if the fourth field * doesn't start with "memo=" as we expect. */ - while (*memo_end && *memo_end != ',' && !inblank(*memo_end)) - ++memo_end; + i = memo_start; + /* ### TODO: Consider optimizing the common case that memo_start to + * end-of-string is entirely ASCII */ + while (1) { + int nbytes; + convchar_t c = unmeta_one(i, &nbytes); + + if (c == '\0' || c == ',' || inblank(c)) { + memo_end = i; + break; + } else + i += nbytes; + } rhp->memo = ztrduppfx(memo_start, memo_end - memo_start); } else rhp->memo = NULL; diff --git a/Test/X04zlehighlight.ztst b/Test/X04zlehighlight.ztst index 20d8e55588..7ab050bee0 100644 --- a/Test/X04zlehighlight.ztst +++ b/Test/X04zlehighlight.ztst @@ -137,11 +137,6 @@ zpty_stop 0:region_highlight memo information forward compatibility, #3: NULs >typeset -a region_highlight=( '0 4 fg=green memo=some' ) -F:Fails because the memo_end iteration works on plain characters, but $'\0' is -F:encoded as META SPACE ("\x83\x20") and SPACE happens to test true for the -F:loop termination condition. -F: -F:set_region_highlight() should be taught to handle strp's being metafied. zpty_start zpty_input 'rh_widget() { BUFFER="true"; region_highlight+=( "0 4 fg=#040810" ); }' From 6e08bb940b1d0c8e8868c88554be7b43c4020606 Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Wed, 17 Jun 2020 10:22:18 +0000 Subject: [PATCH 06/13] Document compatibility issues, sans a hacky workaround (see comments). --- Doc/Zsh/zle.yo | 8 ++++++++ README | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo index dab964585b..41a5559687 100644 --- a/Doc/Zsh/zle.yo +++ b/Doc/Zsh/zle.yo @@ -1008,6 +1008,14 @@ any predisplay string should be highlighted in bold. Note that the effect of tt(region_highlight) is not saved and disappears as soon as the line is accepted. +Note that zsh 5.8 and older does not support the `tt(memo=)var(token)' field +and may misparse the third (highlight specification) field when a memo +is given. +COMMENT(The syntax `tt(0 20 bold, memo=foobar)' (with an auxiliary comma) +happens to work on both zsh 5.8 and zsh 5.9-to-be, but I'm deliberately leaving +that undocumented as it's more of an accident of implementation than something +I'm comfortable making a first-class-citizen API promise.) + The final highlighting on the command line depends on both tt(region_highlight) and tt(zle_highlight); see ifzman(the section CHARACTER HIGHLIGHTING below)\ diff --git a/README b/README index 8ae615153e..293e1db1ed 100644 --- a/README +++ b/README @@ -83,6 +83,13 @@ affects you, make the implied colons in the first pattern explicit, as in: zstyle ':foo:*:baz:*' style value2 This will use value1 in both 5.8 and 5.9. +Elements of the region_highlight array have gained a fourth space-separated +field. Code written against 5.9 that sets the new field may break under 5.8: +for example, the element "0 20 bold memo=foo", which is valid under 5.9, would +not work under 5.8, because 5.8 does not recognize the space as terminating the +highlighting specification. On the other hand, code that does not set the new, +fourth field will continue to work under both 5.8 and 5.9. + Incompatibilities between 5.7.1 and 5.8 --------------------------------------- From 8233536cf6c8573ee453d1125a6578bbd2f49488 Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Wed, 17 Jun 2020 19:14:16 +0000 Subject: [PATCH 07/13] tweak docs --- Doc/Zsh/zle.yo | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo index 41a5559687..d7ec1b1023 100644 --- a/Doc/Zsh/zle.yo +++ b/Doc/Zsh/zle.yo @@ -992,10 +992,16 @@ itemiz(Optionally, a string of the form `tt(memo=)var(token)'. The var(token) consists of everything between the `tt(=)' and the next whitespace, comma, NUL, or the end of the string. The var(token) is preserved verbatim but not parsed in any way. + Plugins may use this to identify array elements they have added: for example, a plugin might set var(token) to its (the plugin's) name and then use `tt(region_highlight=+LPAR() ${region_highlight:#*memo=)var(token)tt(} +RPAR())' -in order to remove array elements it have added.) +in order to remove array elements it have added. + +(This example uses the `tt(${)var(name)tt(:#)var(pattern)tt(})' array-grepping +syntax described in +ifzman(the section `Parameter Expansion' in zmanref(zshexpn))\ +ifnzman(noderef(Parameter Expansion)).)) enditemize() For example, From 125ccbd0e7ad5fc555a02bbfdfb5cb7180a6cb77 Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Wed, 17 Jun 2020 19:21:54 +0000 Subject: [PATCH 08/13] tweak docs #2 --- README | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README b/README index 293e1db1ed..a3d301a1bb 100644 --- a/README +++ b/README @@ -89,6 +89,8 @@ for example, the element "0 20 bold memo=foo", which is valid under 5.9, would not work under 5.8, because 5.8 does not recognize the space as terminating the highlighting specification. On the other hand, code that does not set the new, fourth field will continue to work under both 5.8 and 5.9. +(As it happens, adding a comma after "bold" will make both 5.8 and 5.9 do the +right thing, but this should be viewed as an unsupported hack.) Incompatibilities between 5.7.1 and 5.8 --------------------------------------- From 12586a37437ef7caa0a083f69d419a79bd7e3665 Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Wed, 17 Jun 2020 19:22:14 +0000 Subject: [PATCH 09/13] docs tweak #3 --- Doc/Zsh/zle.yo | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo index d7ec1b1023..909abeb49d 100644 --- a/Doc/Zsh/zle.yo +++ b/Doc/Zsh/zle.yo @@ -1014,13 +1014,13 @@ any predisplay string should be highlighted in bold. Note that the effect of tt(region_highlight) is not saved and disappears as soon as the line is accepted. -Note that zsh 5.8 and older does not support the `tt(memo=)var(token)' field +Note that zsh 5.8 and older do not support the `tt(memo=)var(token)' field and may misparse the third (highlight specification) field when a memo is given. COMMENT(The syntax `tt(0 20 bold, memo=foobar)' (with an auxiliary comma) -happens to work on both zsh 5.8 and zsh 5.9-to-be, but I'm deliberately leaving -that undocumented as it's more of an accident of implementation than something -I'm comfortable making a first-class-citizen API promise.) +happens to work on both zsh <=5.8 and zsh 5.9-to-be, but that seems to be more of +an accident of implementation than something we should make a first-class-citizen +API promise. It's mentioned in the "Incompatibilities" section of README.) The final highlighting on the command line depends on both tt(region_highlight) and tt(zle_highlight); see From 866209dd8f8f343a4d664c29adf014046057b77c Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Thu, 18 Jun 2020 09:01:12 +0000 Subject: [PATCH 10/13] Save/restore memo in zle_save_positions()/zle_restore_positions(). This causes memos to be preserved across invocations of _cmdstring, at least (probably because _cmdstring calls `compset -q` and set_comp_sep() calls zle_save_positions()). --- Src/Zle/zle_utils.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Src/Zle/zle_utils.c b/Src/Zle/zle_utils.c index 044674eddd..ae87f47d45 100644 --- a/Src/Zle/zle_utils.c +++ b/Src/Zle/zle_utils.c @@ -568,6 +568,7 @@ struct zle_region { int start; int end; int flags; + const char *memo; }; /* Forward reference */ @@ -632,7 +633,7 @@ zle_save_positions(void) newrhp->next = NULL; newrhp->atr = rhp->atr; newrhp->flags = rhp->flags; - /* TODO: save rhp->memo here? */ + newrhp->memo = ztrdup(rhp->memo); if (zlemetaline) { newrhp->start = rhp->start_meta; newrhp->end = rhp->end_meta; @@ -695,7 +696,7 @@ zle_restore_positions(void) rhp->atr = oldrhp->atr; rhp->flags = oldrhp->flags; - rhp->memo = NULL; + rhp->memo = oldrhp->memo; /* transferring ownership */ if (zlemetaline) { rhp->start_meta = oldrhp->start; rhp->end_meta = oldrhp->end; From f743943a647d53627cee545e6ca8e88892b66842 Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Thu, 18 Jun 2020 09:32:38 +0000 Subject: [PATCH 11/13] Let zsfree() take a pointer to const, per best practice. --- Src/mem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Src/mem.c b/Src/mem.c index 5951e57ed0..a20e3f7296 100644 --- a/Src/mem.c +++ b/Src/mem.c @@ -1655,7 +1655,7 @@ free(FREE_ARG_T p) /**/ mod_export void -zsfree(char *p) +zsfree(const char *p) { if (p) zfree(p, strlen(p) + 1); From adf432ec8089b364d03b7c3ac15df4cda3d05161 Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Thu, 18 Jun 2020 09:33:40 +0000 Subject: [PATCH 12/13] Deallocate memos. Fixes a memory leak The allocation in zle_set_highlight() did not require an update. --- Src/Zle/zle_refresh.c | 3 +++ Src/Zle/zle_utils.c | 20 +++++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c index af52f8794f..d9d9503e24 100644 --- a/Src/Zle/zle_refresh.c +++ b/Src/Zle/zle_refresh.c @@ -469,6 +469,8 @@ set_region_highlight(UNUSED(Param pm), char **aval) /* no null termination, but include special highlighting at start */ int newsize = len + N_SPECIAL_HIGHLIGHTS; int diffsize = newsize - n_region_highlights; + + free_region_highlights_memos(); region_highlights = (struct region_highlight *) zrealloc(region_highlights, sizeof(struct region_highlight) * newsize); @@ -2844,6 +2846,7 @@ zle_refresh_finish(void) if (region_highlights) { + free_region_highlights_memos(); zfree(region_highlights, sizeof(struct region_highlight) * n_region_highlights); region_highlights = NULL; diff --git a/Src/Zle/zle_utils.c b/Src/Zle/zle_utils.c index ae87f47d45..ea18aafdef 100644 --- a/Src/Zle/zle_utils.c +++ b/Src/Zle/zle_utils.c @@ -557,6 +557,22 @@ zlegetline(int *ll, int *cs) } +/* + * free() the 'memo' elements of region_highlights. + */ + +/**/ +void +free_region_highlights_memos(void) +{ + struct region_highlight *rhp; + for (rhp = region_highlights; + rhp < region_highlights + n_region_highlights; + rhp++) { + zsfree(rhp->memo); + } +} + /* Forward reference */ struct zle_region; @@ -684,6 +700,7 @@ zle_restore_positions(void) nreg++, oldrhp = oldrhp->next) ; if (nreg + N_SPECIAL_HIGHLIGHTS != n_region_highlights) { + free_region_highlights_memos(); n_region_highlights = nreg + N_SPECIAL_HIGHLIGHTS; region_highlights = (struct region_highlight *) zrealloc(region_highlights, @@ -696,7 +713,7 @@ zle_restore_positions(void) rhp->atr = oldrhp->atr; rhp->flags = oldrhp->flags; - rhp->memo = oldrhp->memo; /* transferring ownership */ + rhp->memo = oldrhp->memo; /* transferring ownership of the permanently-allocated memory */ if (zlemetaline) { rhp->start_meta = oldrhp->start; rhp->end_meta = oldrhp->end; @@ -710,6 +727,7 @@ zle_restore_positions(void) rhp++; } } else if (region_highlights) { + free_region_highlights_memos(); zfree(region_highlights, sizeof(struct region_highlight) * n_region_highlights); region_highlights = NULL; From 23d1edce5d607addda4e38dc124485a0a599ce96 Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Thu, 18 Jun 2020 10:28:14 +0000 Subject: [PATCH 13/13] docs tweak #4 --- README | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README b/README index a3d301a1bb..9b1b1605f9 100644 --- a/README +++ b/README @@ -86,9 +86,9 @@ This will use value1 in both 5.8 and 5.9. Elements of the region_highlight array have gained a fourth space-separated field. Code written against 5.9 that sets the new field may break under 5.8: for example, the element "0 20 bold memo=foo", which is valid under 5.9, would -not work under 5.8, because 5.8 does not recognize the space as terminating the -highlighting specification. On the other hand, code that does not set the new, -fourth field will continue to work under both 5.8 and 5.9. +not work under 5.8. (Under the hood, 5.8 does not recognize the space as +terminating the highlighting specification.) On the other hand, code that does +not set the new, fourth field will continue to work under both 5.8 and 5.9. (As it happens, adding a comma after "bold" will make both 5.8 and 5.9 do the right thing, but this should be viewed as an unsupported hack.)