zsh-workers
 help / color / mirror / code / Atom feed
From: Wayne Davison <wayne@tenor.clarinet.com>
To: Zefram <A.Main@dcs.warwick.ac.uk>
Cc: Z Shell workers mailing list <zsh-workers@math.gatech.edu>
Subject: Updated isearch patch based on ZLE 8-bit patch
Date: Fri, 10 May 1996 20:31:40 -0700	[thread overview]
Message-ID: <199605110331.UAA01392@tenor.clari.net> (raw)
In-Reply-To: A.Main's message of Fri, 10 May 1996 10:39:17 +0100. <23053.199605100939@stone.dcs.warwick.ac.uk>

I've updated the incremental search code based on Zefram's latest 8-bit
patch.  I am still using the beta 17 release with only my isearch and
Zefram's 8-bit ZLE patches applied, but since the 8-bit patch applied
with minimal difficulty I think that this diff should also apply easily
to the code with the other published patches.

This patch includes my small fix to ztrlen(), so if you already applied
that it will probably be easier to unapply it before running this through
patch.

I fixed lots of glitches in the new interaction between a meta-expanded
line and the non-meta-expanded lines.  I also added a "Failing" string
to the mini-buffer prompt when the search fails and fixed the way the
isearch code handles backing up through failure cases (it no longer rings
the bell if backing up to a previous failure, for instance).

Discussion of internals:

I added two meta-related functions to utils.c since I thought they might
be useful.  I only use each one once, however, so if you don't want the
new functions, integrate them into zle_hist.c.  They are:

1. metalen(str, len) -- this function takes a pointer to a metafied
string and a length from the PRE-metified version of the string and
returns the length including any meta characters.  I use this function
to convert "cs" into a "pos" in the metafied line.

2. ztrsub(s2, s1) -- this function performs pointer subtraction in a
metafied string, returning (s2 - s1) - the_number_of_meta_chars_in_
_the_substring.

When doisearch() converts the current search string into its metafied
form, I decided to just use the META_STATIC return and limit the search
string to PATH_MAX characters.  If you don't like this, META_USEHEAP
could be used instead -- I just didn't like the thought of a new alloc
for each typed character (even when backing up).

I needed to add extra variables to the isearch_spots array, so I decided
to save some memory by making some of the ints unsigned shorts.  If you
don't like this, change them back to ints.

I modified hstrnstr() to have a separate forward and backward loop,
making the code more efficient.

Finally, I eliminated one extra call to refresh() that didn't seem to be
needed.

I tested this with various searches, including some lines with null
characters on them, and it worked fine.

..wayne..
---8<------8<------8<------8<---cut here--->8------>8------>8------>8---
Index: utils.c
@@ -2872,6 +2872,24 @@
     return s;
 }
 
+/* Return the character length of a metafied substring, given the      *
+ * unmetafied substring length.                                        */
+
+/**/
+int
+metalen(char *s, int len)
+{
+    int mlen = len;
+
+    while (len--) {
+	if (*s++ == Meta) {
+	    mlen++;
+	    s++;
+	}
+    }
+    return mlen;
+}
+
 /* This function converts a zsh internal string to a form which can be *
  * passed to a system call as a filename.  The result is stored in a   *
  * single static area.  NULL returned if the result is longer than     *
@@ -2926,7 +2944,7 @@
 	return 1;
 }
 
-/* Unmetafy and check the length of a string. */
+/* Return the unmetafied length of a metafied string. */
 
 /**/
 int
@@ -2936,11 +2954,33 @@
 
     for (l = 0; *s; l++)
 	if (*s++ == Meta) {
-	    s++;
 #ifdef DEBUG
 	    if (! *s)
 		fprintf(stderr, "BUG: unexpected end of string in ztrlen()\n");
+	    else
 #endif
+	    s++;
+	}
+    return l;
+}
+
+/* Subtract two pointers in a metafied string. */
+
+/**/
+int
+ztrsub(char const *t, char const *s)
+{
+    int l = t - s;
+
+    while (s != t)
+	if (*s++ == Meta) {
+#ifdef DEBUG
+	    if (! *s || s == t)
+		fprintf(stderr, "BUG: substring ends in the middle of a metachar in ztrsub()\n");
+	    else
+#endif
+	    s++;
+	    l--;
 	}
     return l;
 }
Index: zle_hist.c
@@ -572,17 +572,20 @@
 extern int ungetok;
 
 struct isrch_spot {
-    int hl;		/* This spot's histline */
-    int pos;		/* The search position on the line */
-    int len;		/* How long the search string was */
-    int dir;		/* The direction we're searching */
+    int hl;			/* This spot's histline */
+    unsigned short pos;		/* The search position in our metafied 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 */
+#define ISS_FAILING	1
+#define ISS_FORWARD	2
 } *isrch_spots;
 
 static int max_spot = 0;
 
 /**/
 void
-set_isrch_spot(int num, int hl, int pos, int len, int dir)
+set_isrch_spot(int num, int hl, int pos, int cs, int len, int dir, int nomatch)
 {
     if (num >= max_spot) {
 	if (!isrch_spots) {
@@ -595,98 +598,121 @@
     }
 
     isrch_spots[num].hl = hl;
-    isrch_spots[num].pos = pos;
-    isrch_spots[num].len = len;
-    isrch_spots[num].dir = dir;
+    isrch_spots[num].pos = (unsigned short)pos;
+    isrch_spots[num].cs = (unsigned short)cs;
+    isrch_spots[num].len = (unsigned short)len;
+    isrch_spots[num].flags = (dir > 0? ISS_FORWARD : 0)
+			   + (nomatch? ISS_FAILING : 0);
 }
 
 /**/
 void
-get_isrch_spot(int num, int *hlp, int *posp, int *lenp, int *dirp)
+get_isrch_spot(int num, int *hlp, int *posp, int *csp, int *lenp, int *dirp, int *nomatch)
 {
     *hlp = isrch_spots[num].hl;
-    *posp = isrch_spots[num].pos;
-    *lenp = isrch_spots[num].len;
-    *dirp = isrch_spots[num].dir;
+    *posp = (int)isrch_spots[num].pos;
+    *csp = (int)isrch_spots[num].cs;
+    *lenp = (int)isrch_spots[num].len;
+    *dirp = (isrch_spots[num].flags & ISS_FORWARD)? 1 : -1;
+    *nomatch = (isrch_spots[num].flags & ISS_FAILING);
 }
 
+#define ISEARCH_PROMPT		"failing XXX-i-search: "
+#define NORM_PROMPT_POS		8
+#define FIRST_SEARCH_CHAR	(NORM_PROMPT_POS + 14)
+
 /**/
 void
 doisearch(int dir)
 {
-    char *s, *ibuf = halloc(80), *sbuf = ibuf + 14;
-    int sbptr = 0, cmd, top_spot = 0, pos = cs, sibuf = 80;
+    char *s, *ibuf = halloc(80), *sbuf = ibuf + FIRST_SEARCH_CHAR;
+    int sbptr = 0, cmd, top_spot = 0, pos, sibuf = 80;
     int nomatch = 0, skip_line = 0, skip_pos = 0;
     int odir = dir, *obindtab = bindtab;
 
-    strcpy(ibuf, (dir == -1) ? "bck-i-search: " : "fwd-i-search: ");
-    statusline = ibuf;
+    strcpy(ibuf, ISEARCH_PROMPT);
+    memcpy(ibuf + NORM_PROMPT_POS, (dir == 1) ? "fwd" : "bck", 3);
     if (histline == curhist) {
 	zsfree(curhistline);
-	curhistline = metafy(UTOSCP(line), ll, META_DUP);
+	s = curhistline = metafy(UTOSCP(line), ll, META_DUP);
     }
+    else
+	s = metafy(UTOSCP(line), ll, META_USEHEAP);
     bindtab = mainbindtab;
-    s = curhistline;
+    pos = metalen(s, cs);
     for (;;) {
 	/* Remember the current values in case search fails (doesn't push). */
-	set_isrch_spot(top_spot, histline, pos, sbptr, dir);
-	if (sbptr == 1 && sbuf[0] == '^')
+	set_isrch_spot(top_spot, histline, pos, cs, sbptr, dir, nomatch);
+	if (sbptr == 1 && sbuf[0] == '^') {
 	    cs = 0;
-	else if (sbptr > 0) {
-	    statusline = ibuf = metafy(ibuf, sbptr + 14, META_USEHEAP);
-	    sbuf = ibuf + 14;
+    	    nomatch = 0;
+	    statusline = ibuf + NORM_PROMPT_POS;
+	} else if (sbptr > 0) {
+	    char *mbuf = metafy(sbuf, sbptr, META_STATIC);
+	    char *last_line = s;
+
 	    for (;;) {
 		char *t;
 
 		if (skip_pos) {
-		    pos += dir;
-		    if (pos < 0 || sbuf[0] == '^' || pos >= strlen(s))
+		    if (dir < 0) {
+			if (pos == 0)
+			    skip_line = 1;
+			else
+			    pos -= 1 + (pos != 1 && s[pos-2] == Meta);
+		    } else if (sbuf[0] != '^') {
+			if (pos >= strlen(s+1))
+			    skip_line = 1;
+			else
+			    pos += 1 + (s[pos] == Meta);
+		    } else
 			skip_line = 1;
 		    skip_pos = 0;
 		}
 		if (!skip_line && ((sbuf[0] == '^') ?
-		    (t = (strncmp(s, sbuf + 1, strlen(sbuf + 1))) ? NULL : s) :
-		    (t = hstrnstr(s, pos,  sbuf, strlen(sbuf), dir)))) {
-		    char savet = *t;
+		    (t = (strncmp(s, mbuf + 1, strlen(mbuf + 1))) ? NULL : s) :
+		    (t = hstrnstr(s, pos, mbuf, strlen(mbuf), dir)))) {
 		    setline(s);
-		    *t = 0;
-		    pos = strlen(s);
-		    cs = ztrlen(s);
-		    *t = savet;
-		    if (dir == 1)
-			cs += sbptr - (sbuf[0] == '^');
+		    pos = t - s;
+		    cs = ztrsub(t, s) + (dir == 1? sbptr - (sbuf[0]=='^') : 0);
 	    	    nomatch = 0;
+		    statusline = ibuf + NORM_PROMPT_POS;
 		    break;
 		}
 		histline += dir;
 		if (!(s = qgetevent(histline))) {
+		    if (sbptr == (int)isrch_spots[top_spot-1].len
+		     && (isrch_spots[top_spot-1].flags & ISS_FAILING))
+			top_spot--;
+		    get_isrch_spot(top_spot, &histline, &pos, &cs, &sbptr,
+				   &dir, &nomatch);
 		    if (!nomatch) {
 			feep();
 			nomatch = 1;
 		    }
-		    if (sbptr == isrch_spots[top_spot-1].len)
-			top_spot--;
-		    get_isrch_spot(top_spot, &histline, &pos, &sbptr, &dir);
-		    s = curhistline;
+		    s = last_line;
 		    skip_line = 0;
+		    statusline = ibuf;
 		    break;
 		}
-		pos = dir == 1? 0 : ztrlen(s) - sbptr + (sbuf[0] == '^');
-		skip_line = (pos < 0 || strcmp(curhistline, s) == 0);
+		pos = dir == 1? 0 : strlen(s);
+		skip_line = !strcmp(last_line, s);
 	    }
-	    unmetafy(ibuf, NULL);
-	} else
+	} else {
 	    top_spot = 0;
+    	    nomatch = 0;
+	    statusline = ibuf + NORM_PROMPT_POS;
+	}
 	sbuf[sbptr] = '_';
-	statusline = ibuf;
-	statusll = sbptr + 15;
+	statusll = sbuf - statusline + sbptr + 1;
     ref:
 	refresh();
 	if ((cmd = getkeycmd()) < 0 || cmd == z_sendbreak) {
-	    get_isrch_spot(0, &histline, &pos, &sbptr, &dir);
+	    int i;
+	    get_isrch_spot(0, &histline, &pos, &i, &sbptr, &dir, &nomatch);
 	    s = qgetevent(histline);
 	    setline(s);
-	    cs = pos;
+	    cs = i;
 	    break;
 	}
 	switch (cmd) {
@@ -702,15 +728,21 @@
 	case z_vibackwarddeletechar:
 	case z_backwarddeletechar:
 	    if (top_spot)
-		get_isrch_spot(--top_spot, &histline, &pos, &sbptr, &dir);
+		get_isrch_spot(--top_spot, &histline, &pos, &cs, &sbptr,
+			       &dir, &nomatch);
 	    else
 		feep();
+	    if (nomatch) {
+		statusline = ibuf;
+		skip_pos = 1;
+	    }
 	    s = qgetevent(histline);
 	    if (!sbptr || (sbptr == 1 && sbuf[0] == '^')) {
+		int i = cs;
 		setline(s);
-		cs = pos;
+		cs = i;
 	    }
-	    memcpy(ibuf, (dir == 1) ? "fwd" : "bck", 3);
+	    memcpy(ibuf + NORM_PROMPT_POS, (dir == 1) ? "fwd" : "bck", 3);
 	    continue;
 	case z_acceptandhold:
 	    acceptandhold();
@@ -725,31 +757,30 @@
 	    acceptline();
 	    goto brk;
 	case z_historyincrementalsearchbackward:
-	    set_isrch_spot(top_spot++, histline, pos, sbptr, dir);
+	    set_isrch_spot(top_spot++, histline, pos, cs, sbptr, dir, nomatch);
 	    if (dir != -1)
 		dir = -1;
 	    else
 		skip_pos = 1;
 	    goto rpt;
 	case z_historyincrementalsearchforward:
-	    set_isrch_spot(top_spot++, histline, pos, sbptr, dir);
+	    set_isrch_spot(top_spot++, histline, pos, cs, sbptr, dir, nomatch);
 	    if (dir != 1)
 		dir = 1;
 	    else
 		skip_pos = 1;
 	    goto rpt;
 	case z_virevrepeatsearch:
-	    set_isrch_spot(top_spot++, histline, pos, sbptr, dir);
+	    set_isrch_spot(top_spot++, histline, pos, cs, sbptr, dir, nomatch);
 	    dir = -odir;
 	    skip_pos = 1;
 	    goto rpt;
 	case z_virepeatsearch:
-	    set_isrch_spot(top_spot++, histline, pos, sbptr, dir);
+	    set_isrch_spot(top_spot++, histline, pos, cs, sbptr, dir, nomatch);
 	    dir = odir;
 	    skip_pos = 1;
 	rpt:
-	    memcpy(ibuf, (dir == 1) ? "fwd" : "bck", 3);
-	    refresh();
+	    memcpy(ibuf + NORM_PROMPT_POS, (dir == 1) ? "fwd" : "bck", 3);
 	    continue;
 	case z_sendstring:
 	    sendstring();
@@ -778,10 +809,14 @@
 		goto brk;
 	    }
 	ins:
-	    set_isrch_spot(top_spot++, histline, pos, sbptr, dir);
-	    if(sbptr == sibuf - 16) {
-		statusline = ibuf = hrealloc(ibuf, sibuf, sibuf * 2);
-		sbuf = ibuf + 14;
+	    if (sbptr == PATH_MAX) {
+		feep();
+		break;
+	    }
+	    set_isrch_spot(top_spot++, histline, pos, cs, sbptr, dir, nomatch);
+	    if (sbptr == sibuf - FIRST_SEARCH_CHAR - 2) {
+		ibuf = hrealloc(ibuf, sibuf, sibuf * 2);
+		sbuf = ibuf + FIRST_SEARCH_CHAR;
 		sibuf *= 2;
 	    }
 	    sbuf[sbptr++] = c;
Index: zle_utils.c
@@ -265,17 +265,22 @@
 char *
 hstrnstr(char *str, int pos, char *t, int len, int dir)
 {
-    char *s;
+    char *s = str + pos;
 
-    for (s = str + pos; dir == -1 || *s; ) {
-	if (!strncmp(t, s, len))
-	    return s;
-	if(dir == -1) {
-	    if(s == str)
-		break;
-	    s -= 1 + (s>str+1 && s[-2] == Meta);
-	} else
+    if (dir > 0) {
+	while (*s) {
+	    if (!strncmp(t, s, len))
+		return s;
 	    s += 1 + (*s == Meta);
+	}
+    } else {
+	for (;;) {
+	    if (!strncmp(t, s, len))
+		return s;
+	    if (s == str)
+		break;
+	    s -= 1 + (s != str+1 && s[-2] == Meta);
+	}
     }
     return NULL;
 }
---8<------8<------8<------8<---cut here--->8------>8------>8------>8---



      parent reply	other threads:[~1996-05-11  3:53 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
1996-05-10  9:39 Zefram
1996-05-10 21:12 ` Wayne Davison
1996-05-11  3:31 ` Wayne Davison [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=199605110331.UAA01392@tenor.clari.net \
    --to=wayne@tenor.clarinet.com \
    --cc=A.Main@dcs.warwick.ac.uk \
    --cc=zsh-workers@math.gatech.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).