diff options
Diffstat (limited to 'Src/Zle/zle_utils.c')
-rw-r--r-- | Src/Zle/zle_utils.c | 650 |
1 files changed, 650 insertions, 0 deletions
diff --git a/Src/Zle/zle_utils.c b/Src/Zle/zle_utils.c new file mode 100644 index 000000000..8fe3e7f0b --- /dev/null +++ b/Src/Zle/zle_utils.c @@ -0,0 +1,650 @@ +/* + * zle_utils.c - miscellaneous line editor utilities + * + * This file is part of zsh, the Z shell. + * + * Copyright (c) 1992-1997 Paul Falstad + * All rights reserved. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and to distribute modified versions of this software for any + * purpose, provided that the above copyright notice and the following + * two paragraphs appear in all copies of this software. + * + * In no event shall Paul Falstad or the Zsh Development Group be liable + * to any party for direct, indirect, special, incidental, or consequential + * damages arising out of the use of this software and its documentation, + * even if Paul Falstad and the Zsh Development Group have been advised of + * the possibility of such damage. + * + * Paul Falstad and the Zsh Development Group specifically disclaim any + * warranties, including, but not limited to, the implied warranties of + * merchantability and fitness for a particular purpose. The software + * provided hereunder is on an "as is" basis, and Paul Falstad and the + * Zsh Development Group have no obligation to provide maintenance, + * support, updates, enhancements, or modifications. + * + */ + +#include "zle.mdh" +#include "zle_utils.pro" + +/* Primary cut buffer */ + +/**/ +struct cutbuffer cutbuf; + +/* Emacs-style kill buffer ring */ + +/**/ +struct cutbuffer kring[KRINGCT]; +/**/ +int 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. */ + +/**/ +struct cutbuffer vibuf[35]; + +/* the line before last mod (for undo purposes) */ + +/**/ +char *lastline; +/**/ +int lastlinesz, lastll; + +/* size of line buffer */ + +/**/ +int linesz; + +/* make sure that the line buffer has at least sz chars */ + +/**/ +void +sizeline(int sz) +{ + while (sz > linesz) + line = (unsigned char *)realloc(line, (linesz *= 4) + 2); +} + +/* insert space for ct chars at cursor position */ + +/**/ +void +spaceinline(int ct) +{ + int i; + + sizeline(ct + ll); + for (i = ll; --i >= cs;) + line[i + ct] = line[i]; + ll += ct; + line[ll] = '\0'; + + if (mark > cs) + mark += ct; +} + +/**/ +static void +shiftchars(int to, int cnt) +{ + if (mark >= to + cnt) + mark -= cnt; + else if (mark > to) + mark = to; + + while (to + cnt < ll) { + line[to] = line[to + cnt]; + to++; + } + line[ll = to] = '\0'; +} + +/**/ +void +backkill(int ct, int dir) +{ + int i = (cs -= ct); + + cut(i, ct, dir); + shiftchars(i, ct); +} + +/**/ +void +forekill(int ct, int dir) +{ + int i = cs; + + cut(i, ct, dir); + shiftchars(i, ct); +} + +/**/ +void +cut(int i, int ct, int dir) +{ + if (zmod.flags & MOD_VIBUF) { + struct cutbuffer *b = &vibuf[zmod.vibuf]; + + if (!(zmod.flags & MOD_VIAPP) || !b->buf) { + zfree(b->buf, b->len); + b->buf = (char *)zalloc(ct); + memcpy(b->buf, (char *) line + i, ct); + b->len = ct; + b->flags = vilinerange ? CUTBUFFER_LINE : 0; + } else { + int len = b->len; + + if(vilinerange) + b->flags |= CUTBUFFER_LINE; + b->buf = realloc(b->buf, ct + len + !!(b->flags & CUTBUFFER_LINE)); + if (b->flags & CUTBUFFER_LINE) + b->buf[len++] = '\n'; + memcpy(b->buf + len, (char *) line + i, ct); + b->len = len + ct; + } + return; + } else { + /* Save in "1, shifting "1-"8 along to "2-"9 */ + int n; + zfree(vibuf[34].buf, vibuf[34].len); + for(n=34; n>26; n--) + vibuf[n] = vibuf[n-1]; + vibuf[26].buf = (char *)zalloc(ct); + memcpy(vibuf[26].buf, (char *) line + i, ct); + vibuf[26].len = ct; + vibuf[26].flags = vilinerange ? CUTBUFFER_LINE : 0; + } + if (!cutbuf.buf) { + 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; + cutbuf.buf = ztrdup(""); + cutbuf.len = cutbuf.flags = 0; + } + if (dir) { + char *s = (char *)zalloc(cutbuf.len + ct); + + memcpy(s, (char *) line + i, ct); + memcpy(s + ct, cutbuf.buf, cutbuf.len); + free(cutbuf.buf); + cutbuf.buf = s; + cutbuf.len += ct; + } else { + cutbuf.buf = realloc(cutbuf.buf, cutbuf.len + ct); + memcpy(cutbuf.buf + cutbuf.len, (char *) line + i, ct); + cutbuf.len += ct; + } + if(vilinerange) + cutbuf.flags |= CUTBUFFER_LINE; + else + cutbuf.flags &= ~CUTBUFFER_LINE; +} + +/**/ +void +backdel(int ct) +{ + shiftchars(cs -= ct, ct); +} + +/**/ +void +foredel(int ct) +{ + shiftchars(cs, ct); +} + +/**/ +void +setline(char const *s) +{ + sizeline(strlen(s)); + strcpy((char *) line, s); + unmetafy((char *) line, &ll); + if ((cs = ll) && invicmdmode()) + cs--; +} + +/**/ +int +findbol(void) +{ + int x = cs; + + while (x > 0 && line[x - 1] != '\n') + x--; + return x; +} + +/**/ +int +findeol(void) +{ + int x = cs; + + while (x != ll && line[x] != '\n') + x++; + return x; +} + +/**/ +void +findline(int *a, int *b) +{ + *a = findbol(); + *b = findeol(); +} + +/* Search for needle in haystack. Haystack is a metafied string while * + * needle is unmetafied and len-long. Start the search at position * + * pos. Search forward if dir > 0 otherwise search backward. */ + +/**/ +char * +hstrnstr(char *haystack, int pos, char *needle, int len, int dir, int sens) +{ + char *s = haystack + pos; + + if (dir > 0) { + while (*s) { + if (metadiffer(s, needle, len) < sens) + return s; + s += 1 + (*s == Meta); + } + } else { + for (;;) { + if (metadiffer(s, needle, len) < sens) + return s; + if (s == haystack) + break; + s -= 1 + (s != haystack+1 && s[-2] == Meta); + } + } + return NULL; +} + +/* Query the user, and return a single character response. The * + * question is assumed to have been printed already, and the * + * cursor is left immediately after the response echoed. * + * (Might cause a problem if this takes it onto the next line.) * + * <Tab> is interpreted as 'y'; any other control character is * + * interpreted as 'n'. If there are any characters in the * + * buffer, this is taken as a negative response, and no * + * characters are read. Case is folded. */ + +/**/ +int +getzlequery(void) +{ + int c; +#ifdef FIONREAD + int val; + + /* check for typeahead, which is treated as a negative response */ + ioctl(SHTTY, FIONREAD, (char *)&val); + if (val) { + putc('n', shout); + return 'n'; + } +#endif + + /* get a character from the tty and interpret it */ + c = getkey(0); + if (c == '\t') + c = 'y'; + else if (icntrl(c) || c == EOF) + c = 'n'; + else + c = tulower(c); + + /* echo response and return */ + putc(c, shout); + return c; +} + +/* Format a string, keybinding style. */ + +/**/ +char * +bindztrdup(char *str) +{ + int c, len = 1; + char *buf, *ptr, *ret; + + for(ptr = str; *ptr; ptr++) { + c = *ptr == Meta ? STOUC(*++ptr) ^ 32 : STOUC(*ptr); + if(c & 0x80) { + len += 3; + c &= 0x7f; + } + if(c < 32 || c == 0x7f) { + len++; + c ^= 64; + } + len += c == '\\' || c == '^'; + len++; + } + ptr = buf = zalloc(len); + for(; *str; str++) { + c = *str == Meta ? STOUC(*++str) ^ 32 : STOUC(*str); + if(c & 0x80) { + *ptr++ = '\\'; + *ptr++ = 'M'; + *ptr++ = '-'; + c &= 0x7f; + } + if(c < 32 || c == 0x7f) { + *ptr++ = '^'; + c ^= 64; + } + if(c == '\\' || c == '^') + *ptr++ = '\\'; + *ptr++ = c; + } + *ptr = 0; + ret = dquotedztrdup(buf); + zsfree(buf); + return ret; +} + +/* Display a metafied string, keybinding-style. */ + +/**/ +int +printbind(char *str, FILE *stream) +{ + char *b = bindztrdup(str); + int ret = zputs(b, stream); + + zsfree(b); + return ret; +} + +/* Display a message where the completion list normally goes. * + * The message must be metafied. */ + +/**/ +void +showmsg(char const *msg) +{ + char const *p; + int up = 0, cc = 0, c; + + trashzle(); + clearflag = isset(USEZLE) && !termflags && isset(ALWAYSLASTPROMPT); + + for(p = msg; (c = *p); p++) { + if(c == Meta) + c = *++p ^ 32; + if(c == '\n') { + putc('\n', shout); + up += 1 + cc / columns; + cc = 0; + } else { + char const *n = nicechar(c); + fputs(n, shout); + cc += strlen(n); + } + } + up += cc / columns; + + if (clearflag) { + putc('\r', shout); + tcmultout(TCUP, TCMULTUP, up + nlnct); + } else + putc('\n', shout); + showinglist = 0; +} + +/* handle the error flag */ + +/**/ +void +feep(void) +{ + feepflag = 1; +} + +/**/ +void +handlefeep(void) +{ + if(feepflag) + beep(); + feepflag = 0; +} + +/***************/ +/* undo system */ +/***************/ + +/* head of the undo list, and the current position */ + +static struct change *changes, *curchange; + +/* list of pending changes, not yet in the undo system */ + +static struct change *nextchanges, *endnextchanges; + +/**/ +void +initundo(void) +{ + nextchanges = NULL; + changes = curchange = zalloc(sizeof(*curchange)); + curchange->prev = curchange->next = NULL; + curchange->del = curchange->ins = NULL; + lastline = zalloc(lastlinesz = linesz); + memcpy(lastline, line, lastll = ll); +} + +/**/ +void +freeundo(void) +{ + freechanges(changes); + freechanges(nextchanges); + zfree(lastline, lastlinesz); +} + +/**/ +static void +freechanges(struct change *p) +{ + struct change *n; + + for(; p; p = n) { + n = p->next; + zsfree(p->del); + zsfree(p->ins); + zfree(p, sizeof(*p)); + } +} + +/* register pending changes in the undo system */ + +/**/ +void +handleundo(void) +{ + mkundoent(); + if(!nextchanges) + return; + setlastline(); + if(curchange->next) { + freechanges(curchange->next); + curchange->next = NULL; + zsfree(curchange->del); + zsfree(curchange->ins); + curchange->del = curchange->ins = NULL; + } + nextchanges->prev = curchange->prev; + if(curchange->prev) + curchange->prev->next = nextchanges; + else + changes = nextchanges; + curchange->prev = endnextchanges; + endnextchanges->next = curchange; + nextchanges = endnextchanges = NULL; +} + +/* add an entry to the undo system, if anything has changed */ + +/**/ +void +mkundoent(void) +{ + int pre, suf; + int sh = ll < lastll ? ll : lastll; + struct change *ch; + + if(lastll == ll && !memcmp(lastline, line, ll)) + return; + for(pre = 0; pre < sh && line[pre] == lastline[pre]; ) + pre++; + for(suf = 0; suf < sh - pre && + line[ll - 1 - suf] == lastline[lastll - 1 - suf]; ) + suf++; + ch = zalloc(sizeof(*ch)); + ch->next = NULL; + ch->hist = histline; + ch->off = pre; + if(suf + pre == lastll) + ch->del = NULL; + else + ch->del = metafy(lastline + pre, lastll - pre - suf, META_DUP); + if(suf + pre == ll) + ch->ins = NULL; + else + ch->ins = metafy((char *)line + pre, ll - pre - suf, META_DUP); + if(nextchanges) { + ch->flags = CH_PREV; + ch->prev = endnextchanges; + endnextchanges->flags |= CH_NEXT; + endnextchanges->next = ch; + } else { + nextchanges = ch; + ch->flags = 0; + ch->prev = NULL; + } + endnextchanges = ch; +} + +/* set lastline to match line */ + +/**/ +void +setlastline(void) +{ + if(lastlinesz != linesz) + lastline = realloc(lastline, lastlinesz = linesz); + memcpy(lastline, line, lastll = ll); +} + +/* move backwards through the change list */ + +/**/ +void +undo(void) +{ + handleundo(); + do { + if(!curchange->prev) { + feep(); + return; + } + unapplychange(curchange = curchange->prev); + } while(curchange->flags & CH_PREV); + setlastline(); +} + +/**/ +static void +unapplychange(struct change *ch) +{ + if(ch->hist != histline) { + remember_edits(); + setline(zle_get_event(histline = ch->hist)); + } + cs = ch->off; + if(ch->ins) + foredel(ztrlen(ch->ins)); + if(ch->del) { + char *c = ch->del; + + spaceinline(ztrlen(c)); + for(; *c; c++) + if(*c == Meta) + line[cs++] = STOUC(*++c) ^ 32; + else + line[cs++] = STOUC(*c); + } +} + +/* move forwards through the change list */ + +/**/ +void +redo(void) +{ + handleundo(); + do { + if(!curchange->next) { + feep(); + return; + } + applychange(curchange); + curchange = curchange->next; + } while(curchange->prev->flags & CH_NEXT); + setlastline(); +} + +/**/ +static void +applychange(struct change *ch) +{ + if(ch->hist != histline) { + remember_edits(); + setline(zle_get_event(histline = ch->hist)); + } + cs = ch->off; + if(ch->del) + foredel(ztrlen(ch->del)); + if(ch->ins) { + char *c = ch->ins; + + spaceinline(ztrlen(c)); + for(; *c; c++) + if(*c == Meta) + line[cs++] = STOUC(*++c) ^ 32; + else + line[cs++] = STOUC(*c); + } +} + +/* vi undo: toggle between the end of the undo list and the preceding point */ + +/**/ +void +viundochange(void) +{ + handleundo(); + if(curchange->next) { + do { + applychange(curchange); + curchange = curchange->next; + } while(curchange->next); + setlastline(); + } else + undo(); +} |