From 212ca9edf9c2be0499cdce39326abba57b088bcd Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Fri, 18 Feb 2011 22:08:45 +0000 Subject: [PATCH] 28772: Update regions in region highlight dynamically --- ChangeLog | 9 +- Doc/Zsh/zle.yo | 5 +- Functions/Zle/split-shell-arguments | 2 +- Src/Zle/compcore.c | 8 +- Src/Zle/compresult.c | 9 +- Src/Zle/zle.h | 56 ++++- Src/Zle/zle_refresh.c | 37 +-- Src/Zle/zle_tricky.c | 8 +- Src/Zle/zle_utils.c | 335 +++++++++++++++++++++++++++- 9 files changed, 413 insertions(+), 56 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8581d5134..4d23549cc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2011-02-18 Peter Stephenson + + * 28772: Doc/Zsh/zle.yo, Src/Zle/compcore.c, + Src/Zle/compresult.c, Src/Zle/zle.h, Src/Zle/zle_refresh.c, + Src/Zle/zle_tricky.c, Src/Zle/zle_utils.c: update regions + in $region_highlight dynamically. + 2011-02-17 Peter Stephenson * 28761: Completion/Unix/Command/_sccs: file completion missing @@ -14215,5 +14222,5 @@ ***************************************************** * This is used by the shell to define $ZSH_PATCHLEVEL -* $Revision: 1.5200 $ +* $Revision: 1.5201 $ ***************************************************** diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo index 591593d38..9c1c83c16 100644 --- a/Doc/Zsh/zle.yo +++ b/Doc/Zsh/zle.yo @@ -842,10 +842,7 @@ specifies that the first twenty characters of the text including 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. The line editor makes no attempt to -keep the highlighting effect synchronised with the line as it is edited; -hence region highlighting is best limited to static effects within -user widgets. +as soon as the line is accepted. ) vindex(WIDGET) item(tt(WIDGET) (scalar))( diff --git a/Functions/Zle/split-shell-arguments b/Functions/Zle/split-shell-arguments index ee737a067..32b04fcb5 100644 --- a/Functions/Zle/split-shell-arguments +++ b/Functions/Zle/split-shell-arguments @@ -15,7 +15,7 @@ local -a bufwords lbufwords local word integer pos=1 cpos=$((CURSOR+1)) opos iword ichar -bufwords=(${(z)BUFFER}) +bufwords=(${(Z+n+)BUFFER}) reply=() while [[ ${BUFFER[pos]} = [[:space:]] ]]; do diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c index c59815874..fa8b8c11f 100644 --- a/Src/Zle/compcore.c +++ b/Src/Zle/compcore.c @@ -1395,8 +1395,6 @@ set_comp_sep(void) LinkNode n; /* Save word position */ int owe = we, owb = wb; - /* Save cursor position and line length */ - int ocs, oll; /* * Values of word beginning and end and cursor after subtractions * due to separators. I think these are indexes into zlemetaline, @@ -1481,8 +1479,7 @@ set_comp_sep(void) /* Put the string in the lexer buffer and call the lexer to * * get the words we have to expand. */ - ocs = zlemetacs; - oll = zlemetall; + zle_save_positions(); ol = zlemetaline; addedx = 1; noerrs = 1; @@ -1639,9 +1636,8 @@ set_comp_sep(void) lexrestore(); wb = owb; we = owe; - zlemetacs = ocs; zlemetaline = ol; - zlemetall = oll; + zle_restore_positions(); if (cur < 0 || i < 1) return 1; owb = offs; diff --git a/Src/Zle/compresult.c b/Src/Zle/compresult.c index bdfcfd739..0389b52a2 100644 --- a/Src/Zle/compresult.c +++ b/Src/Zle/compresult.c @@ -698,8 +698,10 @@ hasbrpsfx(Cmatch m, char *pre, char *suf) { char *op = lastprebr, *os = lastpostbr; VARARR(char, oline, zlemetall); - int oll = zlemetall, ocs = zlemetacs, ole = lastend, opcs = brpcs, oscs = brscs, ret; + int oll = zlemetall, newll, ole = lastend; + int opcs = brpcs, oscs = brscs, ret; + zle_save_positions(); memcpy(oline, zlemetaline, zlemetall); lastprebr = lastpostbr = NULL; @@ -710,7 +712,10 @@ hasbrpsfx(Cmatch m, char *pre, char *suf) foredel(zlemetall, CUT_RAW); spaceinline(oll); memcpy(zlemetaline, oline, oll); - zlemetacs = ocs; + /* we do not want to restore zlemetall */ + newll = zlemetall; + zle_restore_positions(); + zlemetall = newll; lastend = ole; brpcs = opcs; brscs = oscs; diff --git a/Src/Zle/zle.h b/Src/Zle/zle.h index 32f3e59f6..bedf28f17 100644 --- a/Src/Zle/zle.h +++ b/Src/Zle/zle.h @@ -385,6 +385,47 @@ enum suffixflags { SUFFLAGS_SPACE = 0x0001 /* Add a space when removing suffix */ }; + +/* Flags for the region_highlight structure */ +enum { + /* Offsets include predisplay */ + ZRH_PREDISPLAY = 1 +}; + +/* + * Attributes used for highlighting regions. + * and mark. + */ +struct region_highlight { + /* Attributes turned on in the region */ + int atr; + /* Start of the region */ + int start; + /* Start of the region in metafied ZLE line */ + int start_meta; + /* + * End of the region: position of the first character not highlighted + * (the same system as for point and mark). + */ + int end; + /* End of the region in metafied ZLE line */ + int end_meta; + /* + * Any of the flags defined above. + */ + int flags; +}; + +/* + * Count of special uses of region highlighting, which account + * for the first few elements of region_highlights. + * 0: region between point and mark + * 1: isearch region + * 2: suffix + */ +#define N_SPECIAL_HIGHLIGHTS (3) + + #ifdef MULTIBYTE_SUPPORT /* * We use a wint_t here, since we need an invalid character as a @@ -420,15 +461,28 @@ typedef REFRESH_ELEMENT *REFRESH_STRING; #if defined(MULTIBYTE_SUPPORT) && defined(__STDC_ISO_10646__) +/* + * With ISO 10646 there is a private range defined within + * the encoding. We use this for storing single-byte + * characters in sections of strings that wouldn't convert to wide + * characters. This allows to preserve the string when transformed + * back to multibyte strings. + */ + +/* The start of the private range we use, for 256 characters */ #define ZSH_INVALID_WCHAR_BASE (0xe000U) +/* Detect a wide character within our range */ #define ZSH_INVALID_WCHAR_TEST(x) \ ((unsigned)(x) >= ZSH_INVALID_WCHAR_BASE && \ (unsigned)(x) <= (ZSH_INVALID_WCHAR_BASE + 255u)) +/* Turn a wide character in that range back to single byte */ #define ZSH_INVALID_WCHAR_TO_CHAR(x) \ ((char)((unsigned)(x) - ZSH_INVALID_WCHAR_BASE)) +/* Turn a wide character in that range to an integer */ #define ZSH_INVALID_WCHAR_TO_INT(x) \ ((int)((unsigned)(x) - ZSH_INVALID_WCHAR_BASE)) -#define ZSH_CHAR_TO_INVALID_WCHAR(x) \ +/* Turn a single byte character into a private wide character */ +#define ZSH_CHAR_TO_INVALID_WCHAR(x) \ ((wchar_t)(STOUC(x) + ZSH_INVALID_WCHAR_BASE)) #endif diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c index 3b60285c9..a78aef7db 100644 --- a/Src/Zle/zle_refresh.c +++ b/Src/Zle/zle_refresh.c @@ -210,50 +210,21 @@ int predisplaylen, postdisplaylen; static int default_atr_on, special_atr_on; -/* Flags for the region_highlight structure */ -enum { - /* Offsets include predisplay */ - ZRH_PREDISPLAY = 1 -}; - -/* - * Attributes used for highlighting regions. - * and mark. - */ -struct region_highlight { - /* Attributes turned on in the region */ - int atr; - /* Start of the region */ - int start; - /* - * End of the region: position of the first character not highlighted - * (the same system as for point and mark). - */ - int end; - /* - * Any of the flags defined above. - */ - int flags; -}; /* * 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. */ + +/**/ struct region_highlight *region_highlights; -/* - * Count of special uses of region highlighting, which account - * for the first few elements of region_highlights. - * 0: region between point and mark - * 1: isearch region - * 2: suffix - */ -#define N_SPECIAL_HIGHLIGHTS (3) + /* * Number of elements in region_highlights. * This includes the special elements above. */ +/**/ int n_region_highlights; /* diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c index 566537761..74ebf0981 100644 --- a/Src/Zle/zle_tricky.c +++ b/Src/Zle/zle_tricky.c @@ -2675,14 +2675,13 @@ int doexpandhist(void) { char *ol; - int oll, ocs, ne = noerrs, err, ona = noaliases; + int ne = noerrs, err, ona = noaliases; UNMETACHECK(); pushheap(); metafy_line(); - oll = zlemetall; - ocs = zlemetacs; + zle_save_positions(); ol = dupstring(zlemetaline); expanding = 1; excs = zlemetacs; @@ -2725,8 +2724,7 @@ doexpandhist(void) } strcpy(zlemetaline, ol); - zlemetall = oll; - zlemetacs = ocs; + zle_restore_positions(); unmetafy_line(); popheap(); diff --git a/Src/Zle/zle_utils.c b/Src/Zle/zle_utils.c index 5275bdbf6..3a2694bfd 100644 --- a/Src/Zle/zle_utils.c +++ b/Src/Zle/zle_utils.c @@ -179,6 +179,8 @@ zlecharasstring(ZLE_CHAR_T inchar, char *buf) * string length, without the NULL byte. * * If outcsp is non-NULL, assign the new character position. + * If outcsp is &zlemetacs, update the positions in the region_highlight + * array, too. This is a bit of a hack. * * If useheap is 1, memory is returned from the heap, else is allocated * for later freeing. @@ -190,6 +192,7 @@ zlelineasstring(ZLE_STRING_T instr, int inll, int incs, int *outllp, int *outcsp, int useheap) { int outcs, outll; + struct region_highlight *rhp; #ifdef MULTIBYTE_SUPPORT char *s; @@ -201,9 +204,22 @@ zlelineasstring(ZLE_STRING_T instr, int inll, int incs, int *outllp, outcs = 0; memset(&mbs, 0, sizeof(mbs)); - for (i=0; i < inll; i++, incs--) { + for (i=0; i < inll; i++) { if (incs == 0) outcs = mb_len; + incs--; + if (region_highlights && outcsp == &zlemetacs) { + for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; + rhp < region_highlights + n_region_highlights; + rhp++) { + if (rhp->start == 0) + rhp->start_meta = mb_len; + rhp->start--; + if (rhp->end == 0) + rhp->end_meta = mb_len; + rhp->end--; + } + } #ifdef __STDC_ISO_10646__ if (ZSH_INVALID_WCHAR_TEST(instr[i])) { s[mb_len++] = ZSH_INVALID_WCHAR_TO_CHAR(instr[i]); @@ -222,12 +238,30 @@ zlelineasstring(ZLE_STRING_T instr, int inll, int incs, int *outllp, } if (incs == 0) outcs = mb_len; + if (region_highlights && outcsp == &zlemetacs) { + for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; + rhp < region_highlights + n_region_highlights; + rhp++) { + if (rhp->start == 0) + rhp->start_meta = mb_len; + if (rhp->end == 0) + rhp->end_meta = mb_len; + } + } s[mb_len] = '\0'; outll = mb_len; #else outll = inll; outcs = incs; + if (region_highlights && outcsp == &zlemetacs) { + for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; + rhp < region_highlights + n_region_highlights; + rhp++) { + rhp->start_meta = rhp->start; + rhp->end_meta = rhp->end; + } + } #endif /* @@ -243,11 +277,33 @@ zlelineasstring(ZLE_STRING_T instr, int inll, int incs, int *outllp, #endif char *stopcs = strp + outcs; char *stopll = strp + outll; + char *startp = strp; + if (region_highlights && outcsp == &zlemetacs) { + for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; + rhp < region_highlights + n_region_highlights; + rhp++) { + /* Used as temporary storage */ + rhp->start = rhp->start_meta; + rhp->end = rhp->end_meta; + } + } while (strp < stopll) { if (imeta(*strp)) { if (strp < stopcs) outcs++; + if (region_highlights && outcsp == &zlemetacs) { + for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; + rhp < region_highlights + n_region_highlights; + rhp++) { + if (strp < startp + rhp->start) { + rhp->start_meta++; + } + if (strp < startp + rhp->end) { + rhp->end_meta++; + } + } + } outll++; } strp++; @@ -290,6 +346,9 @@ zlelineasstring(ZLE_STRING_T instr, int inll, int incs, int *outllp, * each metafied character) is converted into the corresponding * character position in *outcs. * + * If, further, outcs is &zlecs, we update the positions in the + * region_highlight array, too. (This is a bit of a hack.) + * * Note that instr is modified in place, hence should be copied * first if necessary; * @@ -304,6 +363,7 @@ stringaszleline(char *instr, int incs, int *outll, int *outsz, int *outcs) { ZLE_STRING_T outstr; int ll, sz; + struct region_highlight *rhp; #ifdef MULTIBYTE_SUPPORT mbstate_t mbs; #endif @@ -316,10 +376,32 @@ stringaszleline(char *instr, int incs, int *outll, int *outsz, int *outcs) * is all the processing required to calculate outcs. */ char *inptr = instr, *cspos = instr + incs; - while (*inptr && inptr < cspos) { + if (region_highlights && outcs == &zlecs) { + for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; + rhp < region_highlights + n_region_highlights; + rhp++) { + rhp->start = rhp->start_meta; + rhp->end = rhp->end_meta; + } + } + while (*inptr) { if (*inptr == Meta) { + if (inptr < cspos) { + incs--; + } + if (region_highlights && outcs == &zlecs) { + for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; + rhp < region_highlights + n_region_highlights; + rhp++) { + if (inptr - instr < rhp->start) { + rhp->start_meta--; + } + if (inptr - instr < rhp->end) { + rhp->end_meta--; + } + } + } inptr++; - incs--; } inptr++; } @@ -385,6 +467,20 @@ stringaszleline(char *instr, int incs, int *outll, int *outsz, int *outcs) int offs = inptr - instr; if (offs <= incs && incs < offs + (int)cnt) *outcs = outptr - outstr; + if (region_highlights && outcs == &zlecs) { + for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; + rhp < region_highlights + n_region_highlights; + rhp++) { + if (offs <= rhp->start_meta && + rhp->start_meta < offs + (int)cnt) { + rhp->start = outptr - outstr; + } + if (offs <= rhp->end_meta && + rhp->end_meta < offs + (int)cnt) { + rhp->end = outptr - outstr; + } + } + } } inptr += cnt; @@ -404,6 +500,14 @@ stringaszleline(char *instr, int incs, int *outll, int *outsz, int *outcs) *outll = ll; if (outcs) *outcs = incs; + if (region_highlights && outcs == &zlecs) { + for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; + rhp < region_highlights + n_region_highlights; + rhp++) { + rhp->start = rhp->start_meta; + rhp->end = rhp->end_meta; + } + } #endif return outstr; @@ -432,6 +536,158 @@ zlegetline(int *ll, int *cs) } +/* Forward reference */ +struct zle_region; + +/* A non-special entry in region_highlight */ +struct zle_region { + struct zle_region *next; + /* Entries of region_highlight, as needed */ + int atr; + int start; + int end; + int flags; +}; + +/* Forward reference */ +struct zle_position; + +/* A saved set of position information */ +struct zle_position { + /* Link pointer */ + struct zle_position *next; + /* Cursor position */ + int cs; + /* Mark */ + int mk; + /* Line length */ + int ll; + struct zle_region *regions; +}; + +/* LIFO stack of positions */ +struct zle_position *zle_positions; + +/* + * Save positions including cursor, end-of-line and + * (non-special) region highlighting. + * + * Must be matched by a subsequent zle_restore_positions(). + */ + +/**/ +void +zle_save_positions(void) +{ + struct region_highlight *rhp; + struct zle_position *newpos; + struct zle_region **newrhpp, *newrhp; + + newpos = (struct zle_position *)zalloc(sizeof(*newpos)); + + newpos->mk = mark; + if (zlemetaline) { + /* Use metafied information */ + newpos->cs = zlemetacs; + newpos->ll = zlemetall; + } else { + /* Use unmetafied information */ + newpos->cs = zlecs; + newpos->ll = zlell; + + } + + newrhpp = &newpos->regions; + *newrhpp = NULL; + if (region_highlights) { + for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; + rhp < region_highlights + n_region_highlights; + rhp++) { + /* + * This is a FIFO stack, so we preserve the order + * of entries when we restore region_highlights. + */ + newrhp = *newrhpp = (struct zle_region *)zalloc(sizeof(**newrhpp)); + newrhp->next = NULL; + newrhp->atr = rhp->atr; + newrhp->flags = rhp->flags; + if (zlemetaline) { + newrhp->start = rhp->start_meta; + newrhp->end = rhp->end_meta; + } else { + newrhp->start = rhp->start; + newrhp->end = rhp->end; + } + newrhpp = &newrhp->next; + } + } + + newpos->next = zle_positions; + zle_positions = newpos; +} + +/* + * Restore positions previously saved. + * Relies on zlemetaline being restored correctly beforehand, + * so that it can tell whether to use metafied positions or not. + */ + +/**/ +void +zle_restore_positions(void) +{ + struct zle_position *oldpos = zle_positions; + struct zle_region *oldrhp; + struct region_highlight *rhp; + int nreg; + + zle_positions = oldpos->next; + + mark = oldpos->mk; + if (zlemetaline) { + /* Use metafied information */ + zlemetacs = oldpos->cs; + zlemetall = oldpos->ll; + } else { + /* Use unmetafied information */ + zlecs = oldpos->cs; + zlell = oldpos->ll; + } + + /* Count number of regions and see if the array needs resizing */ + for (nreg = 0, oldrhp = oldpos->regions; + oldrhp; + nreg++, oldrhp = oldrhp->next) + ; + if (nreg + N_SPECIAL_HIGHLIGHTS != n_region_highlights) { + n_region_highlights = nreg + N_SPECIAL_HIGHLIGHTS; + region_highlights = (struct region_highlight *) + zrealloc(region_highlights, + sizeof(struct region_highlight) * n_region_highlights); + } + oldrhp = oldpos->regions; + rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; + while (oldrhp) { + struct zle_region *nextrhp = oldrhp->next; + + rhp->atr = oldrhp->atr; + rhp->flags = oldrhp->flags; + if (zlemetaline) { + rhp->start_meta = oldrhp->start; + rhp->end_meta = oldrhp->end; + } else { + rhp->start = oldrhp->start; + rhp->end = oldrhp->end; + } + + zfree(oldrhp, sizeof(*oldrhp)); + oldrhp = nextrhp; + rhp++; + } + + zfree(oldpos, sizeof(*oldpos)); +} + /* * Basic utility functions for adding to line or removing from line. * At this level the counts supplied are raw character counts, so @@ -450,6 +706,7 @@ mod_export void spaceinline(int ct) { int i; + struct region_highlight *rhp; if (zlemetaline) { sizeline(ct + zlemetall); @@ -460,6 +717,19 @@ spaceinline(int ct) if (mark > zlemetacs) mark += ct; + + if (region_highlights) { + for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; + rhp < region_highlights + n_region_highlights; + rhp++) { + if (rhp->start_meta >= zlemetacs) { + rhp->start_meta += ct; + } + if (rhp->end_meta >= zlemetacs) { + rhp->end_meta += ct; + } + } + } } else { sizeline(ct + zlell); for (i = zlell; --i >= zlecs;) @@ -469,26 +739,85 @@ spaceinline(int ct) if (mark > zlecs) mark += ct; + + if (region_highlights) { + for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; + rhp < region_highlights + n_region_highlights; + rhp++) { + if (rhp->start >= zlecs) { + rhp->start += ct; + } + if (rhp->end >= zlecs) { + rhp->end += ct; + } + } + } } region_active = 0; } +/* + * Within the ZLE line, cut the "cnt" characters from position "to". + */ + /**/ void shiftchars(int to, int cnt) { + struct region_highlight *rhp; + if (mark >= to + cnt) mark -= cnt; else if (mark > to) mark = to; if (zlemetaline) { + /* before to is updated... */ + if (region_highlights) { + for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; + rhp < region_highlights + n_region_highlights; + rhp++) { + if (rhp->start_meta > to) { + if (rhp->start_meta > to + cnt) + rhp->start_meta -= cnt; + else + rhp->start_meta = to; + } + if (rhp->end_meta > to) { + if (rhp->end_meta > to + cnt) + rhp->end_meta -= cnt; + else + rhp->end_meta = to; + } + } + } + while (to + cnt < zlemetall) { zlemetaline[to] = zlemetaline[to + cnt]; to++; } zlemetaline[zlemetall = to] = '\0'; } else { + /* before to is updated... */ + if (region_highlights) { + for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; + rhp < region_highlights + n_region_highlights; + rhp++) { + if (rhp->start > to) { + if (rhp->start > to + cnt) + rhp->start -= cnt; + else + rhp->start = to; + } + if (rhp->end > to) { + if (rhp->end > to + cnt) + rhp->end -= cnt; + else + rhp->end = to; + } + } + } + while (to + cnt < zlell) { zleline[to] = zleline[to + cnt]; to++;