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++;