From 778a73b027509c9c9f70c8dbd184097efeacae43 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Mon, 27 Jan 2003 14:54:31 +0000 Subject: 18139: 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. --- ChangeLog | 8 ++++++ Doc/Zsh/zle.yo | 12 ++++++--- Src/Zle/zle.h | 2 +- Src/Zle/zle_main.c | 7 +++-- Src/Zle/zle_misc.c | 69 ++++++++++++++++++++++++++++++++++++++++--------- Src/Zle/zle_params.c | 73 +++++++++++++++++++++++++++------------------------- Src/Zle/zle_utils.c | 18 ++++++++----- 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 + + * 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 * 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; } -- cgit 1.4.1