about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog8
-rw-r--r--Doc/Zsh/zle.yo12
-rw-r--r--Src/Zle/zle.h2
-rw-r--r--Src/Zle/zle_main.c7
-rw-r--r--Src/Zle/zle_misc.c69
-rw-r--r--Src/Zle/zle_params.c73
-rw-r--r--Src/Zle/zle_utils.c18
7 files changed, 129 insertions, 60 deletions
diff --git a/ChangeLog b/ChangeLog
index fbf03cb32..b40c631fa 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2003-01-27  Peter Stephenson  <pws@csr.com>
+
+	* 18139: Doc/Zsh/zle.yo, Src/Zle/zle.h, Src/Zle/zle_main.c,
+	Src/Zle/zle_misc.c, Src/Zle/zle_params.c, Src/Zle/zle_utils.c:
+	Improve $killring interface; can now change length.  Empty
+	strings in $killring are ignored when yank-popping.  Yank-popping
+	is more consistent about looping and using the original cutbuffer.
+
 2003-01-27  Oliver Kiddle  <opk@zsh.org>
 
 	* Doug Kearns: 18141: Completion/Unix/Command/_elinks:
diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo
index 771ff4d18..75d3faadf 100644
--- a/Doc/Zsh/zle.yo
+++ b/Doc/Zsh/zle.yo
@@ -622,10 +622,14 @@ vindex(killring)
 item(tt(killring) (array))(
 The array of previously killed items, with the most recently killed first.
 This gives the items that would be retrieved by a tt(yank-pop) in the
-same order, up to eight (which is the maximum stored internally).
-Unlike a normal array, only a maximum of eight elements may be written;
-any extra are ignored.  If fewer than eight elements are given, the
-remaining elements of the kill ring will be treated as undefined.
+same order.
+
+The default size for the kill ring is eight, however the length may be
+changed by normal array operations.  Any empty string in the kill ring is
+ignored by the tt(yank-pop) command, hence the size of the array
+effectively sets the maximum length of the kill ring, while the number of
+non-zero strings gives the current length, both as seen by the user at the
+command line.
 )
 
 vindex(LASTSEARCH)
diff --git a/Src/Zle/zle.h b/Src/Zle/zle.h
index a611fd58b..e636073c8 100644
--- a/Src/Zle/zle.h
+++ b/Src/Zle/zle.h
@@ -142,7 +142,7 @@ typedef struct cutbuffer *Cutbuffer;
 
 #define CUTBUFFER_LINE 1   /* for vi: buffer contains whole lines of data */
 
-#define KRINGCT 8   /* number of buffers in the kill ring */
+#define KRINGCTDEF 8   /* default number of buffers in the kill ring */
 
 /* Types of completion. */
 
diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c
index 1c45d120c..0e63bf5b1 100644
--- a/Src/Zle/zle_main.c
+++ b/Src/Zle/zle_main.c
@@ -1406,8 +1406,11 @@ finish_(Module m)
     if (rdstrs)
         freelinklist(rdstrs, freestr);
     zfree(cutbuf.buf, cutbuf.len);
-    for(i = KRINGCT; i--; )
-	zfree(kring[i].buf, kring[i].len);
+    if (kring) {
+	for(i = kringsize; i--; )
+	    zfree(kring[i].buf, kring[i].len);
+	zfree(kring, kringsize * sizeof(struct cutbuffer));
+    }
     for(i = 35; i--; )
 	zfree(vibuf[i].buf, vibuf[i].len);
 
diff --git a/Src/Zle/zle_misc.c b/Src/Zle/zle_misc.c
index 592a590b5..d63b52caa 100644
--- a/Src/Zle/zle_misc.c
+++ b/Src/Zle/zle_misc.c
@@ -331,28 +331,35 @@ copyregionaskill(char **args)
     return 0;
 }
 
+/*
+ * kct: index into kill ring, or -1 for original cutbuffer of yank.
+ * yankb, yanke: mark the start and end of last yank in editing buffer.
+ */
 static int kct, yankb, yanke;
+/* The original cutbuffer, either cutbuf or one of the vi buffers. */
+static Cutbuffer kctbuf;
 
 /**/
 int
 yank(char **args)
 {
-    Cutbuffer buf = &cutbuf;
     int n = zmult;
 
     if (n < 0)
 	return 1;
     if (zmod.flags & MOD_VIBUF)
-	buf = &vibuf[zmod.vibuf];
-    if (!buf->buf)
+	kctbuf = &vibuf[zmod.vibuf];
+    else
+	kctbuf = &cutbuf;
+    if (!kctbuf->buf)
 	return 1;
     mark = cs;
     yankb = cs;
     while (n--) {
-	kct = kringnum;
-	spaceinline(buf->len);
-	memcpy((char *)line + cs, buf->buf, buf->len);
-	cs += buf->len;
+	kct = -1;
+	spaceinline(kctbuf->len);
+	memcpy((char *)line + cs, kctbuf->buf, kctbuf->len);
+	cs += kctbuf->len;
 	yanke = cs;
     }
     return 0;
@@ -362,18 +369,56 @@ yank(char **args)
 int
 yankpop(char **args)
 {
-    int cc;
+    int cc, kctstart = kct;
+    Cutbuffer buf;
 
-    if (!(lastcmd & ZLE_YANK) || !kring[kct].buf)
+    if (!(lastcmd & ZLE_YANK))
 	return 1;
+    do {
+	/*
+	 * This is supposed to make the yankpop loop
+	 *   original buffer -> kill ring in order -> original buffer -> ...
+	 * where the original buffer is -1 and the remainder are
+	 * indices into the kill ring, remember that we need to start
+	 * that at kringnum rather than zero.
+	 */
+	if (kct == -1)
+	    kct = kringnum;
+	else {
+	    int kctnew = (kct + kringsize - 1) % kringsize;
+	    if (kctnew == kringnum)
+		kct = -1;
+	    else
+		kct = kctnew;
+	}
+	if (kct == -1)
+	    buf = kctbuf;	/* Use original cutbuffer */
+	else
+	    buf = kring+kct;	/* Use somewhere in the kill ring */
+	/* Careful to prevent infinite looping */
+	if (kct == kctstart)
+	    return 1;
+	/*
+	 * Skip unset buffers instead of stopping as we used to do.
+	 * Also skip zero-length buffers.
+	 * There are two reasons for this:
+	 * 1. We now map the array $killring directly into the
+	 *    killring, instead of via some extra size-checking logic.
+	 *    When $killring has been set, a buffer will always have
+	 *    at least a zero-length string in it.
+	 * 2. The old logic was inconsistent; when the kill ring
+	 *    was full, we could loop round and round it, otherwise
+	 *    we just stopped when we hit the first empty buffer.
+	 */
+    } while (!buf->buf || !*buf->buf);
+
     cs = yankb;
     foredel(yanke - yankb);
-    cc = kring[kct].len;
+    cc = buf->len;
     spaceinline(cc);
-    memcpy((char *)line + cs, kring[kct].buf, cc);
+    memcpy((char *)line + cs, buf->buf, cc);
     cs += cc;
     yanke = cs;
-    kct = (kct + KRINGCT - 1) % KRINGCT;
     return 0;
 }
 
diff --git a/Src/Zle/zle_params.c b/Src/Zle/zle_params.c
index c8b518cbf..e5277d64d 100644
--- a/Src/Zle/zle_params.c
+++ b/Src/Zle/zle_params.c
@@ -391,43 +391,41 @@ unset_cutbuffer(Param pm, int exp)
 static void
 set_killring(Param pm, char **x)
 {
-    int kpos, kcnt;
+    int kcnt;
+    Cutbuffer kptr;
     char **p;
 
-    kcnt = 0;
-    kpos = kringnum;
-
+    if (kring) {
+	for (kptr = kring, kcnt = 0; kcnt < kringsize; kcnt++, kptr++)
+	    if (kptr->buf)
+		free(kptr->buf);
+	zfree(kring, kringsize * sizeof(struct cutbuffer));
+	kring = NULL;
+	kringsize = kringnum = 0;
+    }
     if (x) {
 	/*
-	 * Insert the elements into the kill ring, up to a maximum
-	 * of KRINGCT.  We always handle the ring in the order
-	 * a series of yank-pops would show, i.e. starting with
-	 * the most recently cut and going backwards.
+	 * Insert the elements into the kill ring.
+	 * Regardless of the old order, we number it with the current
+	 * entry first.
 	 */
-	for (p = x; kcnt < KRINGCT && *p; kcnt++, p++) {
-	    Cutbuffer kptr = kring + kpos;
-	    if (kptr->buf)
-		free(kptr->buf);
-	    kptr->buf = (char *)zalloc(strlen(*p));
+	kringsize = arrlen(x);
+	kring = (Cutbuffer)zcalloc(kringsize * sizeof(struct cutbuffer));
+	for (p = x, kptr = kring; *p; p++, kptr++) {
+	    int len = strlen(*p);
+	    kptr->buf = (char *)zalloc(len);
 	    strcpy(kptr->buf, *p);
 	    unmetafy(kptr->buf, &kptr->len);
-	    kptr->flags = 0;
-	    kpos = (kpos + KRINGCT - 1) % KRINGCT;
+	    if (len != kptr->len) {
+		/* Might as well have the lengths consistent. */
+		char *p2 = zalloc(kptr->len);
+		memcpy(p2, kptr->buf, kptr->len);
+		zfree(kptr->buf, len);
+		kptr->buf = p2;
+	    }
 	}
 	freearray(x);
     }
-    /*
-     * Any values unsupplied are to be unset.
-     */
-    for (; kcnt < KRINGCT; kcnt++) {
-	Cutbuffer kptr = kring + kpos;
-	if (kptr->buf) {
-	    free(kptr->buf);
-	    kptr->buf = NULL;
-	    kptr->flags = kptr->len = 0;
-	}
-	kpos = (kpos + KRINGCT - 1) % KRINGCT;
-    }
 }
 
 /**/
@@ -436,23 +434,28 @@ get_killring(Param pm)
 {
     /*
      * Return the kill ring with the most recently killed first.
-     * Stop as soon as we find something which isn't set, i.e.
-     * don't fill in bogus entries.
+     * Since the kill ring is no longer a fixed length, we return
+     * all entries even if empty.
      */
     int kpos, kcnt;
     char **ret, **p;
 
-    for (kpos = kringnum, kcnt = 0; kcnt < KRINGCT; kcnt++) {
+    /* Supposed to work even if kring is NULL */
+    for (kpos = kringnum, kcnt = 0; kcnt < kringsize; kcnt++) {
 	if (!kring[kpos].buf)
 	    break;
-	kpos = (kpos + KRINGCT - 1) % KRINGCT;
+	kpos = (kpos + kringsize - 1) % kringsize;
     }
 
-    p = ret = (char **)zhalloc((kcnt+1) * sizeof(char *));
+    p = ret = (char **)zhalloc((kringsize+1) * sizeof(char *));
 
-    for (kpos = kringnum; kcnt; kcnt--) {
-	*p++ = metafy((char *)kring[kpos].buf, kring[kpos].len, META_HEAPDUP);
-	kpos = (kpos + KRINGCT - 1) % KRINGCT;
+    for (kpos = kringnum, kcnt = 0; kcnt < kringsize; kcnt++) {
+	Cutbuffer kptr = kring + kpos;
+	if (kptr->buf)
+	    *p++ = metafy((char *)kptr->buf, kptr->len, META_HEAPDUP);
+	else
+	    *p++ = dupstring("");
+	kpos = (kpos + kringsize - 1) % kringsize;
     }
     *p = NULL;
 
diff --git a/Src/Zle/zle_utils.c b/Src/Zle/zle_utils.c
index 107ff37ec..28f5647bd 100644
--- a/Src/Zle/zle_utils.c
+++ b/Src/Zle/zle_utils.c
@@ -38,9 +38,9 @@ struct cutbuffer cutbuf;
 /* Emacs-style kill buffer ring */
 
 /**/
-struct cutbuffer kring[KRINGCT];
+struct cutbuffer *kring;
 /**/
-int kringnum;
+int kringsize, kringnum;
 
 /* Vi named cut buffers.  0-25 are the named buffers "a to "z, and *
  * 26-34 are the numbered buffer stack "1 to "9.                   */
@@ -167,10 +167,16 @@ cut(int i, int ct, int dir)
 	cutbuf.buf = ztrdup("");
 	cutbuf.len = cutbuf.flags = 0;
     } else if (!(lastcmd & ZLE_KILL)) {
-	kringnum = (kringnum + 1) % KRINGCT;
-	if (kring[kringnum].buf)
-	    free(kring[kringnum].buf);
-	kring[kringnum] = cutbuf;
+	Cutbuffer kptr;
+	if (!kring) {
+	    kringsize = KRINGCTDEF;
+	    kring = (Cutbuffer)zcalloc(kringsize * sizeof(struct cutbuffer));
+	} else
+	    kringnum = (kringnum + 1) % kringsize;
+	kptr = kring + kringnum;
+	if (kptr->buf)
+	    zfree(kptr->buf, kptr->len);
+	*kptr = cutbuf;
 	cutbuf.buf = ztrdup("");
 	cutbuf.len = cutbuf.flags = 0;
     }