summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--Doc/Zsh/zle.yo9
-rw-r--r--NEWS3
-rw-r--r--Src/Zle/zle_hist.c77
-rw-r--r--Src/Zle/zle_refresh.c55
5 files changed, 115 insertions, 35 deletions
diff --git a/ChangeLog b/ChangeLog
index eebd29b6a..09aabd7f8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
 2008-04-26  Peter Stephenson  <p.w.stephenson@ntlworld.com>
 
+	* unposted: NEWS: note that COMBINING_CHARS is not on by
+	default.
+
+	* 24882: Doc/Zsh/zle.yo, Src/Zle/zle_hist.c, Src/Zle/zle_refresh.c:
+	highlighting of incremental search match.
+
 	* unposted because everyone's seen enough of my mistakes:
 	Src/pattern.c, Src/Zle/zle_hist.c: with pattern matching the
 	end position of the match wasn't calculated; we used the
diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo
index 04d195bb8..888c87ea1 100644
--- a/Doc/Zsh/zle.yo
+++ b/Doc/Zsh/zle.yo
@@ -2064,6 +2064,10 @@ The contexts available for highlighting are the following:
 startitem()
 cindex(region, highlighting)
 cindex(highlighting, region)
+item(tt(isearch))(
+When one of the incremental history search widgets is active, the
+area of the command line matched by the search string or pattern.
+)
 item(tt(region))(
 The region between the cursor (point) and the mark as set with
 tt(set-mark-command).  The region is only highlighted if it is active,
@@ -2102,7 +2106,7 @@ mode.  The actual effect is specific to the terminal; on many terminals it
 is inverse video.  On some such terminals, where the cursor does not blink
 it appears with standout mode negated, making it less than clear where
 the cursor actually is.  On such terminals one of the other effects
-may be preferable for highlighting the region.
+may be preferable for highlighting the region and matched search string.
 )
 item(tt(underline))(
 The characters in the given context are shown underlined.  Some
@@ -2133,7 +2137,8 @@ enditem()
 If tt(zle_highlight) is not set or no value applies to a particular
 context, the defaults applied are equivalent to
 
-example(zle_highlight=LPAR()region:standout special:standout+RPAR())
+example(zle_highlight=LPAR()region:standout special:standout
+isearch:underline+RPAR())
 
 i.e. both the region and special characters are shown in standout mode.
 
diff --git a/NEWS b/NEWS
index e118ec3af..df8b52884 100644
--- a/NEWS
+++ b/NEWS
@@ -10,7 +10,8 @@ Major changes between versions 4.3.6 and 4.3.7
 The option COMBINING_CHARS has been added.  When it is set, the
 line editor assumes the terminal is capable of displaying zero-width
 combining characters (typically accents) correctly as modifications
-to the base character, and will act accordingly.
+to the base character, and will act accordingly.  Note it is not set
+by default owing to vagaries of terminals.
 
 The option HIST_FCNTL_LOCK has been added to provide locking of history
 files using the system call fcntl().  On recent NFS implementations this
diff --git a/Src/Zle/zle_hist.c b/Src/Zle/zle_hist.c
index 9f0288d0b..203492b55 100644
--- a/Src/Zle/zle_hist.c
+++ b/Src/Zle/zle_hist.c
@@ -907,6 +907,7 @@ static struct isrch_spot {
     int pat_hl;			/* histline where pattern search started */
     unsigned short pos;		/* The search position in our metafied str */
     unsigned short pat_pos;     /* pos where pattern search started */
+    unsigned short end_pos;	/* The position of the end of the matched str */
     unsigned short cs;		/* The visible search position to the user */
     unsigned short len;		/* The search string's length */
     unsigned short flags;	/* This spot's flags */
@@ -928,7 +929,7 @@ free_isrch_spots(void)
 /**/
 static void
 set_isrch_spot(int num, int hl, int pos, int pat_hl, int pat_pos,
-	       int cs, int len, int dir, int nomatch)
+	       int end_pos, int cs, int len, int dir, int nomatch)
 {
     if (num >= max_spot) {
 	if (!isrch_spots) {
@@ -944,6 +945,7 @@ set_isrch_spot(int num, int hl, int pos, int pat_hl, int pat_pos,
     isrch_spots[num].pos = (unsigned short)pos;
     isrch_spots[num].pat_hl = pat_hl;
     isrch_spots[num].pat_pos = (unsigned short)pat_pos;
+    isrch_spots[num].end_pos = (unsigned short)end_pos;
     isrch_spots[num].cs = (unsigned short)cs;
     isrch_spots[num].len = (unsigned short)len;
     isrch_spots[num].flags = (dir > 0? ISS_FORWARD : 0)
@@ -953,12 +955,13 @@ set_isrch_spot(int num, int hl, int pos, int pat_hl, int pat_pos,
 /**/
 static void
 get_isrch_spot(int num, int *hlp, int *posp, int *pat_hlp, int *pat_posp,
-	       int *csp, int *lenp, int *dirp, int *nomatch)
+	       int *end_posp, int *csp, int *lenp, int *dirp, int *nomatch)
 {
     *hlp = isrch_spots[num].hl;
     *posp = (int)isrch_spots[num].pos;
     *pat_hlp = isrch_spots[num].pat_hl;
     *pat_posp = (int)isrch_spots[num].pat_pos;
+    *end_posp = (int)isrch_spots[num].end_pos;
     *csp = (int)isrch_spots[num].cs;
     *lenp = (int)isrch_spots[num].len;
     *dirp = (isrch_spots[num].flags & ISS_FORWARD)? 1 : -1;
@@ -1011,6 +1014,9 @@ isearch_newpos(LinkList matchlist, int curpos, int dir,
 #define FIRST_SEARCH_CHAR	(NORM_PROMPT_POS + 14)
 
 /**/
+int isearch_active, isearch_startpos, isearch_endpos;
+
+/**/
 static void
 doisearch(char **args, int dir, int pattern)
 {
@@ -1088,6 +1094,12 @@ doisearch(char **args, int dir, int pattern)
      */
     int dup_ok = 0;
     /*
+     * End position of the match.
+     * When forward matching, this is the position for the cursor.
+     * When backward matching, the cursor position is pos.
+     */
+    int end_pos = 0;
+    /*
      * savekeys records the unget buffer, so that if we have arguments
      * they don't pollute the input.
      * feep indicates we should feep.  This is a well-known word
@@ -1138,7 +1150,7 @@ doisearch(char **args, int dir, int pattern)
     pat_pos = pos = zlemetacs;
     for (;;) {
 	/* Remember the current values in case search fails (doesn't push). */
-	set_isrch_spot(top_spot, hl, pos, pat_hl, pat_pos,
+	set_isrch_spot(top_spot, hl, pos, pat_hl, pat_pos, end_pos,
 		       zlemetacs, sbptr, dir, nomatch);
 	if (sbptr == 1 && sbuf[0] == '^') {
 	    zlemetacs = 0;
@@ -1147,11 +1159,6 @@ doisearch(char **args, int dir, int pattern)
 	} else if (sbptr > 0) {
 	    /* The matched text, used as flag that we matched */
 	    char *t = NULL;
-	    /*
-	     * When forward matching, position for the cursor.
-	     * When backward matching, the position is pos.
-	     */
-	    int forwardmatchpos = 0;
 	    last_line = zt;
 
 	    sbuf[sbptr] = '\0';
@@ -1233,7 +1240,7 @@ doisearch(char **args, int dir, int pattern)
 			     */
 			    if (!skip_pos &&
 				pattryrefs(patprog, zt, -1, -1, 0, NULL, NULL,
-					   &forwardmatchpos))
+					   &end_pos))
 				t = zt;
 			} else {
 			    if (!matchlist && !skip_pos) {
@@ -1268,7 +1275,7 @@ doisearch(char **args, int dir, int pattern)
 					newpos = pos + 1;
 				}
 				newpos = isearch_newpos(matchlist, newpos,
-							dir, &forwardmatchpos);
+							dir, &end_pos);
 				/* need a new list next time if off the end */
 				if (newpos < 0) {
 				    freematchlist(matchlist);
@@ -1316,7 +1323,7 @@ doisearch(char **args, int dir, int pattern)
 			} else
 			    t = zlinefind(zt, pos, sbuf, dir, sens);
 			if (t)
-			    forwardmatchpos = pos + sbptr - (sbuf[0] == '^');
+			    end_pos = pos + sbptr - (sbuf[0] == '^');
 		    }
 		}
 		if (t) {
@@ -1333,7 +1340,8 @@ doisearch(char **args, int dir, int pattern)
 		     && (isrch_spots[top_spot-1].flags >> ISS_NOMATCH_SHIFT))
 			top_spot--;
 		    get_isrch_spot(top_spot, &hl, &pos, &pat_hl, &pat_pos,
-				   &zlemetacs, &sbptr, &dir, &nomatch);
+				   &end_pos, &zlemetacs, &sbptr, &dir,
+				   &nomatch);
 		    if (!nomatch) {
 			feep = 1;
 			nomatch = 1;
@@ -1366,7 +1374,7 @@ doisearch(char **args, int dir, int pattern)
 	    if (t || (nosearch && !nomatch)) {
 		zle_setline(he);
 		if (dir == 1)
-		    zlemetacs = forwardmatchpos;
+		    zlemetacs = end_pos;
 		else
 		    zlemetacs = pos;
 		statusline = ibuf + NORM_PROMPT_POS;
@@ -1384,11 +1392,39 @@ doisearch(char **args, int dir, int pattern)
 	}
 	sbuf[sbptr] = '_';
 	sbuf[sbptr+1] = '\0';
+	if (!nomatch && sbptr && (sbptr > 1 || sbuf[0] != '^')) {
+#ifdef MULTIBYTE_SUPPORT
+	    int charpos = 0, charcount = 0, ret;
+	    wint_t wc;
+	    mbstate_t mbs;
+
+	    /*
+	     * Count unmetafied character positions for the
+	     * start and end of the match for the benefit of
+	     * highlighting.
+	     */
+	    memset(&mbs, 0, sizeof(mbs));
+	    while (charpos < end_pos) {
+		ret = mb_metacharlenconv_r(zlemetaline + charpos, &wc, &mbs);
+		if (charpos <= pos && pos < charpos + ret)
+		    isearch_startpos = charcount;
+		charcount++;
+		charpos += ret;
+	    }
+	    isearch_endpos = charcount;
+#else
+	    isearch_startpos = ztrsub(zlemetaline + pos, zlemetaline);
+	    isearch_endpos = ztrsub(zlemetaline + end_pos,
+				    zlemetaline);
+#endif
+	    isearch_active = 1;
+	} else
+	    isearch_active = 0;
     ref:
 	zrefresh();
 	if (!(cmd = getkeycmd()) || cmd == Th(z_sendbreak)) {
 	    int i;
-	    get_isrch_spot(0, &hl, &pos, &pat_hl, &pat_pos,
+	    get_isrch_spot(0, &hl, &pos, &pat_hl, &pat_pos, &end_pos,
 			   &i, &sbptr, &dir, &nomatch);
 	    he = quietgethist(hl);
 	    zle_setline(he);
@@ -1410,7 +1446,7 @@ doisearch(char **args, int dir, int pattern)
 	    	cmd == Th(z_backwarddeletechar)) {
 	    if (top_spot) {
 		get_isrch_spot(--top_spot, &hl, &pos, &pat_hl, &pat_pos,
-			       &zlemetacs, &sbptr, &dir, &nomatch);
+			       &end_pos, &zlemetacs, &sbptr, &dir, &nomatch);
 		patprog = NULL;
 		nosearch = 1;
 	    } else
@@ -1452,7 +1488,7 @@ doisearch(char **args, int dir, int pattern)
 		  cmd == Th(z_historyincrementalpatternsearchbackward)) {
 	    pat_hl = hl;
 	    pat_pos = pos;
-	    set_isrch_spot(top_spot++, hl, pos, pat_hl, pat_pos,
+	    set_isrch_spot(top_spot++, hl, pos, pat_hl, pat_pos, end_pos,
 			   zlemetacs, sbptr, dir, nomatch);
 	    if (dir != -1)
 		dir = -1;
@@ -1463,7 +1499,7 @@ doisearch(char **args, int dir, int pattern)
 		  cmd == Th(z_historyincrementalpatternsearchforward)) {
 	    pat_hl = hl;
 	    pat_pos = pos;
-	    set_isrch_spot(top_spot++, hl, pos, pat_hl, pat_pos,
+	    set_isrch_spot(top_spot++, hl, pos, pat_hl, pat_pos, end_pos,
 			   zlemetacs, sbptr, dir, nomatch);
 	    if (dir != 1)
 		dir = 1;
@@ -1473,7 +1509,7 @@ doisearch(char **args, int dir, int pattern)
 	} else if(cmd == Th(z_virevrepeatsearch)) {
 	    pat_hl = hl;
 	    pat_pos = pos;
-	    set_isrch_spot(top_spot++, hl, pos, pat_hl, pat_pos,
+	    set_isrch_spot(top_spot++, hl, pos, pat_hl, pat_pos, end_pos,
 			   zlemetacs, sbptr, dir, nomatch);
 	    dir = -odir;
 	    skip_pos = 1;
@@ -1481,7 +1517,7 @@ doisearch(char **args, int dir, int pattern)
 	} else if(cmd == Th(z_virepeatsearch)) {
 	    pat_hl = hl;
 	    pat_pos = pos;
-	    set_isrch_spot(top_spot++, hl, pos, pat_hl, pat_pos,
+	    set_isrch_spot(top_spot++, hl, pos, pat_hl, pat_pos, end_pos,
 			   zlemetacs, sbptr, dir, nomatch);
 	    dir = odir;
 	    skip_pos = 1;
@@ -1534,7 +1570,7 @@ doisearch(char **args, int dir, int pattern)
 		feep = 1;
 		continue;
 	    }
-	    set_isrch_spot(top_spot++, hl, pos, pat_hl, pat_pos,
+	    set_isrch_spot(top_spot++, hl, pos, pat_hl, pat_pos, end_pos,
 			   zlemetacs, sbptr, dir, nomatch);
 	    if (sbptr >= sibuf - FIRST_SEARCH_CHAR - 2 
 #ifdef MULTIBYTE_SUPPORT
@@ -1569,6 +1605,7 @@ doisearch(char **args, int dir, int pattern)
     zsfree(okeymap);
     if (matchlist)
 	freematchlist(matchlist);
+    isearch_active = 0;
     /*
      * Don't allow unused characters provided as a string to the
      * widget to overflow and be used as separated commands.
diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c
index 66cae9f97..cc0dbe4c0 100644
--- a/Src/Zle/zle_refresh.c
+++ b/Src/Zle/zle_refresh.c
@@ -242,8 +242,15 @@ struct 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
+ */
+#define N_SPECIAL_HIGHLIGHTS	(2)
+/*
  * Number of elements in region_highlights.
- * This includes the region between point and mark, element 0.
+ * This includes the special elements above.
  */
 int n_region_highlights;
 
@@ -380,12 +387,14 @@ void zle_set_highlight(void)
     char **atrs = getaparam("zle_highlight");
     int special_atr_on_set = 0;
     int region_atr_on_set = 0;
+    int isearch_atr_on_set = 0;
+    struct region_highlight *rhp;
 
     special_atr_on = 0;
     if (!region_highlights) {
 	region_highlights = (struct region_highlight *)
-	    zshcalloc(sizeof(struct region_highlight));
-	n_region_highlights = 1;
+	    zshcalloc(N_SPECIAL_HIGHLIGHTS*sizeof(struct region_highlight));
+	n_region_highlights = N_SPECIAL_HIGHLIGHTS;
     } else {
 	region_highlights->atr = 0;
     }
@@ -394,14 +403,23 @@ void zle_set_highlight(void)
 	for (; *atrs; atrs++) {
 	    if (!strcmp(*atrs, "none")) {
 		/* reset attributes for consistency... usually unnecessary */
-		special_atr_on = region_highlights->atr = 0;
-		special_atr_on_set = region_atr_on_set = 1;
+		special_atr_on = 0;
+		special_atr_on_set = region_atr_on_set =
+		    isearch_atr_on_set = 1;
+		for (rhp = region_highlights;
+		     rhp < region_highlights + N_SPECIAL_HIGHLIGHTS;
+		     rhp++) {
+		    rhp->atr = 0;
+		}
 	    } else if (strpfx("special:", *atrs)) {
 		match_highlight(*atrs + 8, &special_atr_on);
 		special_atr_on_set = 1;
 	    } else if (strpfx("region:", *atrs)) {
 		match_highlight(*atrs + 7, &region_highlights->atr);
 		region_atr_on_set = 1;
+	    } else if (strpfx("isearch:", *atrs)) {
+		match_highlight(*atrs + 8, &(region_highlights[1].atr));
+		isearch_atr_on_set = 1;
 	    }
 	}
     }
@@ -411,6 +429,8 @@ void zle_set_highlight(void)
 	special_atr_on = TXTSTANDOUT;
     if (!region_atr_on_set)
 	region_highlights->atr = TXTSTANDOUT;
+    if (!isearch_atr_on_set)
+	region_highlights[1].atr = TXTUNDERLINE;
     special_atr_off = special_atr_on << TXT_ATTR_OFF_ON_SHIFT;
 }
 
@@ -432,15 +452,17 @@ get_region_highlight(UNUSED(Param pm))
 
     /* region_highlights may not have been set yet */
     if (!arrsize)
-	arrsize = 1;
+	arrsize = N_SPECIAL_HIGHLIGHTS;
     arrp = retarr = (char **)zhalloc(arrsize*sizeof(char *));
     /* ignore NULL termination */
     arrsize--;
     if (arrsize) {
 	struct region_highlight *rhp;
 
-	/* ignore point/mark at start */
-	for (rhp = region_highlights+1; arrsize--; rhp++, arrp++) {
+	/* ignore special highlighting */
+	for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS;
+	     arrsize--;
+	     rhp++, arrp++) {
 	    char digbuf1[DIGBUFSIZE], digbuf2[DIGBUFSIZE];
 	    int atrlen = 0, alloclen, done1;
 	    const struct highlight *hp;
@@ -503,9 +525,9 @@ set_region_highlight(UNUSED(Param pm), char **aval)
     struct region_highlight *rhp;
 
     len = aval ? arrlen(aval) : 0;
-    if (n_region_highlights != len + 1) {
-	/* no null termination, but include point/mark region at start */
-	n_region_highlights = len + 1;
+    if (n_region_highlights != len + N_SPECIAL_HIGHLIGHTS) {
+	/* no null termination, but include special highlighting at start */
+	n_region_highlights = len + N_SPECIAL_HIGHLIGHTS;
 	region_highlights = (struct region_highlight *)
 	    zrealloc(region_highlights,
 		     sizeof(struct region_highlight) * n_region_highlights);
@@ -514,7 +536,9 @@ set_region_highlight(UNUSED(Param pm), char **aval)
     if (!aval)
 	return;
 
-    for (rhp = region_highlights + 1; *aval; rhp++, aval++) {
+    for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS;
+	 *aval;
+	 rhp++, aval++) {
 	char *strp, *oldstrp;
 
 	oldstrp = *aval;
@@ -1050,6 +1074,13 @@ zrefresh(void)
     } else {
 	region_highlights->start = region_highlights->end = -1;
     }
+    /* check for isearch string to highlight */
+    if (isearch_active) {
+	region_highlights[1].start = isearch_startpos;
+	region_highlights[1].end = isearch_endpos;
+    } else {
+	region_highlights[1].start = region_highlights[1].end = -1;
+    }
 
     if (clearlist && listshown > 0) {
 	if (tccan(TCCLEAREOD)) {