about summary refs log tree commit diff
path: root/Src
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2008-04-26 22:52:50 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2008-04-26 22:52:50 +0000
commit91a10708b25b78d36549de0177e2330670fe163d (patch)
tree860dc6613bcdbb00961d6b6d4081ec2346973b01 /Src
parent8a323cae8caaf8ffb9da3622469d21edbb027948 (diff)
downloadzsh-91a10708b25b78d36549de0177e2330670fe163d.tar.gz
zsh-91a10708b25b78d36549de0177e2330670fe163d.tar.xz
zsh-91a10708b25b78d36549de0177e2330670fe163d.zip
24822: highlighting of isearch matches
unposted: not in NEWS that COMBINING_CHARS is not on by default
Diffstat (limited to 'Src')
-rw-r--r--Src/Zle/zle_hist.c77
-rw-r--r--Src/Zle/zle_refresh.c55
2 files changed, 100 insertions, 32 deletions
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)) {