summaryrefslogtreecommitdiff
path: root/Src/Zle/zle_misc.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Zle/zle_misc.c')
-rw-r--r--Src/Zle/zle_misc.c816
1 files changed, 816 insertions, 0 deletions
diff --git a/Src/Zle/zle_misc.c b/Src/Zle/zle_misc.c
new file mode 100644
index 000000000..42953852f
--- /dev/null
+++ b/Src/Zle/zle_misc.c
@@ -0,0 +1,816 @@
+/*
+ * zle_misc.c - miscellaneous editor routines
+ *
+ * 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_misc.pro"
+
+/* insert a metafied string, with repetition and suffix removal */
+
+/**/
+void
+doinsert(char *str)
+{
+ char *s;
+ int len = ztrlen(str);
+ int c1 = *str == Meta ? STOUC(str[1])^32 : STOUC(*str);/* first character */
+ int neg = zmult < 0; /* insert *after* the cursor? */
+ int m = neg ? -zmult : zmult; /* number of copies to insert */
+
+ iremovesuffix(c1);
+ invalidatelist();
+
+ if(insmode)
+ spaceinline(m * len);
+ else if(cs + m * len > ll)
+ spaceinline(cs + m * len - ll);
+ while(m--)
+ for(s = str; *s; s++)
+ line[cs++] = *s == Meta ? *++s ^ 32 : *s;
+ if(neg)
+ cs += zmult * len;
+}
+
+/**/
+void
+selfinsert(void)
+{
+ char s[3], *p = s;
+
+ if(imeta(c)) {
+ *p++ = Meta;
+ c ^= 32;
+ }
+ *p++ = c;
+ *p = 0;
+ doinsert(s);
+}
+
+/**/
+void
+selfinsertunmeta(void)
+{
+ c &= 0x7f;
+ if (c == '\r')
+ c = '\n';
+ selfinsert();
+}
+
+/**/
+void
+deletechar(void)
+{
+ if (zmult < 0) {
+ zmult = -zmult;
+ backwarddeletechar();
+ zmult = -zmult;
+ return;
+ }
+ if (cs + zmult <= ll) {
+ cs += zmult;
+ backdel(zmult);
+ } else
+ feep();
+}
+
+/**/
+void
+backwarddeletechar(void)
+{
+ if (zmult < 0) {
+ zmult = -zmult;
+ deletechar();
+ zmult = -zmult;
+ return;
+ }
+ backdel(zmult > cs ? cs : zmult);
+}
+
+/**/
+void
+killwholeline(void)
+{
+ int i, fg, n = zmult;
+
+ if (n < 0)
+ return;
+ while (n--) {
+ if ((fg = (cs && cs == ll)))
+ cs--;
+ while (cs && line[cs - 1] != '\n')
+ cs--;
+ for (i = cs; i != ll && line[i] != '\n'; i++);
+ forekill(i - cs + (i != ll), fg);
+ }
+}
+
+/**/
+void
+killbuffer(void)
+{
+ cs = 0;
+ forekill(ll, 0);
+}
+
+/**/
+void
+backwardkillline(void)
+{
+ int i = 0, n = zmult;
+
+ if (n < 0) {
+ zmult = -n;
+ killline();
+ zmult = n;
+ return;
+ }
+ while (n--) {
+ if (cs && line[cs - 1] == '\n')
+ cs--, i++;
+ else
+ while (cs && line[cs - 1] != '\n')
+ cs--, i++;
+ }
+ forekill(i, 1);
+}
+
+/**/
+void
+gosmacstransposechars(void)
+{
+ int cc;
+
+ if (cs < 2 || line[cs - 1] == '\n' || line[cs - 2] == '\n') {
+ if (cs == ll || line[cs] == '\n' ||
+ ((cs + 1 == ll || line[cs + 1] == '\n') &&
+ (!cs || line[cs - 1] == '\n'))) {
+ feep();
+ return;
+ }
+ cs += (cs == 0 || line[cs - 1] == '\n') ? 2 : 1;
+ }
+ cc = line[cs - 2];
+ line[cs - 2] = line[cs - 1];
+ line[cs - 1] = cc;
+}
+
+/**/
+void
+transposechars(void)
+{
+ int cc, ct;
+ int n = zmult;
+ int neg = n < 0;
+
+ if (neg)
+ n = -n;
+ while (n--) {
+ if (!(ct = cs) || line[cs - 1] == '\n') {
+ if (ll == cs || line[cs] == '\n') {
+ feep();
+ return;
+ }
+ if (!neg)
+ cs++;
+ ct++;
+ }
+ if (neg) {
+ if (cs && line[cs - 1] != '\n') {
+ cs--;
+ if (ct > 1 && line[ct - 2] != '\n')
+ ct--;
+ }
+ } else {
+ if (cs != ll && line[cs] != '\n')
+ cs++;
+ }
+ if (ct == ll || line[ct] == '\n')
+ ct--;
+ if (ct < 1 || line[ct - 1] == '\n') {
+ feep();
+ return;
+ }
+ cc = line[ct - 1];
+ line[ct - 1] = line[ct];
+ line[ct] = cc;
+ }
+}
+
+/**/
+void
+poundinsert(void)
+{
+ cs = 0;
+ vifirstnonblank();
+ if (line[cs] != '#') {
+ spaceinline(1);
+ line[cs] = '#';
+ cs = findeol();
+ while(cs != ll) {
+ cs++;
+ vifirstnonblank();
+ spaceinline(1);
+ line[cs] = '#';
+ cs = findeol();
+ }
+ } else {
+ foredel(1);
+ cs = findeol();
+ while(cs != ll) {
+ cs++;
+ vifirstnonblank();
+ if(line[cs] == '#')
+ foredel(1);
+ cs = findeol();
+ }
+ }
+ done = 1;
+}
+
+/**/
+void
+acceptline(void)
+{
+ done = 1;
+}
+
+/**/
+void
+acceptandhold(void)
+{
+ pushnode(bufstack, metafy((char *)line, ll, META_DUP));
+ stackcs = cs;
+ done = 1;
+}
+
+/**/
+void
+killline(void)
+{
+ int i = 0, n = zmult;
+
+ if (n < 0) {
+ zmult = -n;
+ backwardkillline();
+ zmult = n;
+ return;
+ }
+ while (n--) {
+ if (line[cs] == '\n')
+ cs++, i++;
+ else
+ while (cs != ll && line[cs] != '\n')
+ cs++, i++;
+ }
+ backkill(i, 0);
+}
+
+/**/
+void
+killregion(void)
+{
+ if (mark > ll)
+ mark = ll;
+ if (mark > cs)
+ forekill(mark - cs, 0);
+ else
+ backkill(cs - mark, 1);
+}
+
+/**/
+void
+copyregionaskill(void)
+{
+ if (mark > ll)
+ mark = ll;
+ if (mark > cs)
+ cut(cs, mark - cs, 0);
+ else
+ cut(mark, cs - mark, 1);
+}
+
+static int kct, yankb, yanke;
+
+/**/
+void
+yank(void)
+{
+ Cutbuffer buf = &cutbuf;
+ int n = zmult;
+
+ if (n < 0)
+ return;
+ if (zmod.flags & MOD_VIBUF)
+ buf = &vibuf[zmod.vibuf];
+ if (!buf->buf) {
+ feep();
+ return;
+ }
+ mark = cs;
+ yankb = cs;
+ while (n--) {
+ kct = kringnum;
+ spaceinline(buf->len);
+ memcpy((char *)line + cs, buf->buf, buf->len);
+ cs += buf->len;
+ yanke = cs;
+ }
+}
+
+/**/
+void
+yankpop(void)
+{
+ int cc;
+
+ if (!(lastcmd & ZLE_YANK) || !kring[kct].buf) {
+ feep();
+ return;
+ }
+ cs = yankb;
+ foredel(yanke - yankb);
+ cc = kring[kct].len;
+ spaceinline(cc);
+ memcpy((char *)line + cs, kring[kct].buf, cc);
+ cs += cc;
+ yanke = cs;
+ kct = (kct + KRINGCT - 1) % KRINGCT;
+}
+
+/**/
+void
+overwritemode(void)
+{
+ insmode ^= 1;
+}
+/**/
+void
+whatcursorposition(void)
+{
+ char msg[100];
+ char *s = msg;
+ int bol = findbol();
+ int c = STOUC(line[cs]);
+
+ if (cs == ll)
+ strucpy(&s, "EOF");
+ else {
+ strucpy(&s, "Char: ");
+ switch (c) {
+ case ' ':
+ strucpy(&s, "SPC");
+ break;
+ case '\t':
+ strucpy(&s, "TAB");
+ break;
+ case '\n':
+ strucpy(&s, "LFD");
+ break;
+ default:
+ if (imeta(c)) {
+ *s++ = Meta;
+ *s++ = c ^ 32;
+ } else
+ *s++ = c;
+ }
+ sprintf(s, " (0%o, %d, 0x%x)", c, c, c);
+ s += strlen(s);
+ }
+ sprintf(s, " point %d of %d(%d%%) column %d", cs+1, ll+1,
+ ll ? 100 * cs / ll : 0, cs - bol);
+ showmsg(msg);
+}
+
+/**/
+void
+undefinedkey(void)
+{
+ feep();
+}
+
+/**/
+void
+quotedinsert(void)
+{
+#ifndef HAS_TIO
+ struct sgttyb sob;
+
+ sob = shttyinfo.sgttyb;
+ sob.sg_flags = (sob.sg_flags | RAW) & ~ECHO;
+ ioctl(SHTTY, TIOCSETN, &sob);
+#endif
+ c = getkey(0);
+#ifndef HAS_TIO
+ setterm();
+#endif
+ if (c < 0)
+ feep();
+ else
+ selfinsert();
+}
+
+/**/
+void
+digitargument(void)
+{
+ int sign = (zmult < 0) ? -1 : 1;
+
+ if (!(zmod.flags & MOD_TMULT))
+ zmod.tmult = 0;
+ if (zmod.flags & MOD_NEG) {
+ /* If we just had a negative argument, this is the digit, *
+ * rather than the -1 assumed by negargument() */
+ zmod.tmult = sign * (c & 0xf);
+ zmod.flags &= ~MOD_NEG;
+ } else
+ zmod.tmult = zmod.tmult * 10 + sign * (c & 0xf);
+ zmod.flags |= MOD_TMULT;
+ prefixflag = 1;
+}
+
+/**/
+void
+negargument(void)
+{
+ if(zmod.flags & MOD_TMULT) {
+ feep();
+ return;
+ }
+ zmod.tmult = -1;
+ zmod.flags |= MOD_TMULT|MOD_NEG;
+ prefixflag = 1;
+}
+
+/**/
+void
+universalargument(void)
+{
+ int digcnt = 0, pref = 0, minus = 1, gotk;
+ while ((gotk = getkey(0)) != EOF) {
+ if (gotk == '-' && !digcnt) {
+ minus = -1;
+ digcnt++;
+ } else if (gotk >= '0' && gotk <= '9') {
+ pref = pref * 10 + (gotk & 0xf);
+ digcnt++;
+ } else {
+ ungetkey(gotk);
+ break;
+ }
+ }
+ if (digcnt)
+ zmod.tmult = minus * (pref ? pref : 1);
+ else
+ zmod.tmult *= 4;
+ zmod.flags |= MOD_TMULT;
+ prefixflag = 1;
+}
+
+/**/
+void
+copyprevword(void)
+{
+ int len, t0;
+
+ for (t0 = cs - 1; t0 >= 0; t0--)
+ if (iword(line[t0]))
+ break;
+ for (; t0 >= 0; t0--)
+ if (!iword(line[t0]))
+ break;
+ if (t0)
+ t0++;
+ len = cs - t0;
+ spaceinline(len);
+ memcpy((char *)&line[cs], (char *)&line[t0], len);
+ cs += len;
+}
+
+/**/
+void
+sendbreak(void)
+{
+ errflag = 1;
+}
+
+/**/
+void
+quoteregion(void)
+{
+ char *str;
+ size_t len;
+
+ if (mark > ll)
+ mark = ll;
+ if (mark < cs) {
+ int tmp = mark;
+ mark = cs;
+ cs = tmp;
+ }
+ str = (char *)hcalloc(len = mark - cs);
+ memcpy(str, (char *)&line[cs], len);
+ foredel(len);
+ str = makequote(str, &len);
+ spaceinline(len);
+ memcpy((char *)&line[cs], str, len);
+ mark = cs;
+ cs += len;
+}
+
+/**/
+void
+quoteline(void)
+{
+ char *str;
+ size_t len = ll;
+
+ str = makequote((char *)line, &len);
+ sizeline(len);
+ memcpy(line, str, len);
+ cs = ll = len;
+}
+
+/**/
+static char *
+makequote(char *str, size_t *len)
+{
+ int qtct = 0;
+ char *l, *ol;
+ char *end = str + *len;
+
+ for (l = str; l < end; l++)
+ if (*l == '\'')
+ qtct++;
+ *len += 2 + qtct*3;
+ l = ol = (char *)halloc(*len);
+ *l++ = '\'';
+ for (; str < end; str++)
+ if (*str == '\'') {
+ *l++ = '\'';
+ *l++ = '\\';
+ *l++ = '\'';
+ *l++ = '\'';
+ } else
+ *l++ = *str;
+ *l++ = '\'';
+ return ol;
+}
+
+static char *cmdbuf;
+static LinkList cmdll;
+static int cmdambig;
+
+/**/
+static void
+scancompcmd(HashNode hn, int flags)
+{
+ int l;
+ Thingy t = (Thingy) hn;
+
+ if(strpfx(cmdbuf, t->nam)) {
+ addlinknode(cmdll, t->nam);
+ l = pfxlen(peekfirst(cmdll), t->nam);
+ if (l < cmdambig)
+ cmdambig = l;
+ }
+
+}
+
+#define NAMLEN 60
+
+/**/
+Thingy
+executenamedcommand(char *prmt)
+{
+ Thingy cmd;
+ int len, l = strlen(prmt);
+ char *ptr;
+ char *okeymap = curkeymapname;
+
+ cmdbuf = halloc(l + NAMLEN + 2);
+ strcpy(cmdbuf, prmt);
+ statusline = cmdbuf;
+ selectkeymap("main", 1);
+ ptr = cmdbuf += l;
+ len = 0;
+ for (;;) {
+ *ptr = '_';
+ statusll = l + len + 1;
+ refresh();
+ if (!(cmd = getkeycmd()) || cmd == Th(z_sendbreak)) {
+ statusline = NULL;
+ selectkeymap(okeymap, 1);
+ return NULL;
+ }
+ if(cmd == Th(z_clearscreen)) {
+ clearscreen();
+ } else if(cmd == Th(z_redisplay)) {
+ redisplay();
+ } else if(cmd == Th(z_viquotedinsert)) {
+ *ptr = '^';
+ refresh();
+ c = getkey(0);
+ if(c == EOF || !c || len == NAMLEN)
+ feep();
+ else
+ *ptr++ = c, len++;
+ } else if(cmd == Th(z_quotedinsert)) {
+ if((c = getkey(0)) == EOF || !c || len == NAMLEN)
+ feep();
+ else
+ *ptr++ = c, len++;
+ } else if(cmd == Th(z_backwarddeletechar) ||
+ cmd == Th(z_vibackwarddeletechar)) {
+ if (len)
+ len--, ptr--;
+ } else if(cmd == Th(z_killregion) || cmd == Th(z_backwardkillword) ||
+ cmd == Th(z_vibackwardkillword)) {
+ while (len && (len--, *--ptr != '-'));
+ } else if(cmd == Th(z_killwholeline) || cmd == Th(z_vikillline) ||
+ cmd == Th(z_backwardkillline)) {
+ len = 0;
+ ptr = cmdbuf;
+ } else {
+ if(cmd == Th(z_acceptline) || cmd == Th(z_vicmdmode)) {
+ Thingy r;
+ unambiguous:
+ *ptr = 0;
+ r = rthingy(cmdbuf);
+ if (!(r->flags & DISABLED)) {
+ unrefthingy(r);
+ statusline = NULL;
+ selectkeymap(okeymap, 1);
+ return r;
+ }
+ unrefthingy(r);
+ }
+ if(cmd == Th(z_selfinsertunmeta)) {
+ c &= 0x7f;
+ if(c == '\r')
+ c = '\n';
+ cmd = Th(z_selfinsert);
+ }
+ if (cmd == Th(z_listchoices) || cmd == Th(z_deletecharorlist) ||
+ cmd == Th(z_expandorcomplete) || cmd == Th(z_completeword) ||
+ cmd == Th(z_expandorcompleteprefix) || cmd == Th(z_vicmdmode) ||
+ cmd == Th(z_acceptline) || c == ' ' || c == '\t') {
+ cmdambig = 100;
+
+ HEAPALLOC {
+ cmdll = newlinklist();
+ *ptr = 0;
+
+ scanhashtable(thingytab, 1, 0, DISABLED, scancompcmd, 0);
+ } LASTALLOC;
+ if (empty(cmdll))
+ feep();
+ else if (cmd == Th(z_listchoices) ||
+ cmd == Th(z_deletecharorlist)) {
+ int zmultsav = zmult;
+ *ptr = '_';
+ statusll = l + len + 1;
+ zmult = 1;
+ listlist(cmdll);
+ zmult = zmultsav;
+ } else if (!nextnode(firstnode(cmdll))) {
+ strcpy(ptr = cmdbuf, peekfirst(cmdll));
+ ptr += (len = strlen(ptr));
+ if(cmd == Th(z_acceptline) || cmd == Th(z_vicmdmode))
+ goto unambiguous;
+ } else {
+ strcpy(cmdbuf, peekfirst(cmdll));
+ ptr = cmdbuf + cmdambig;
+ *ptr = '_';
+ if (isset(AUTOLIST) &&
+ !(isset(LISTAMBIGUOUS) && cmdambig > len)) {
+ int zmultsav = zmult;
+ if (isset(LISTBEEP))
+ feep();
+ statusll = l + cmdambig + 1;
+ zmult = 1;
+ listlist(cmdll);
+ zmult = zmultsav;
+ }
+ len = cmdambig;
+ }
+ } else {
+ if (len == NAMLEN || icntrl(c) || cmd != Th(z_selfinsert))
+ feep();
+ else
+ *ptr++ = c, len++;
+ }
+ }
+ handlefeep();
+ }
+}
+
+/*****************/
+/* Suffix system */
+/*****************/
+
+/*
+ * The completion system sometimes tentatively adds a suffix to a word,
+ * which can be removed depending on what is inserted next. These
+ * functions provide the capability to handle a removable suffix.
+ *
+ * Any removable suffix consists of characters immediately before the
+ * cursor. Whether it is removed depends on the next editing action.
+ * There can be more than one suffix simultaneously present, with
+ * different actions deleting different numbers of characters.
+ *
+ * If the next editing action changes the buffer other than by inserting
+ * characters, normally the suffix should be removed so as to leave a
+ * meaningful complete word. The behaviour should be the same if the
+ * next character inserted is a word separator. If the next character
+ * reasonably belongs where it is typed, or if the next editing action
+ * is a deletion, the suffix should not be removed. Other reasons for
+ * suffix removal may have other behaviour.
+ *
+ * In order to maintain a consistent state, after a suffix has been added
+ * the table *must* be zeroed, one way or another, before the buffer is
+ * changed. If the suffix is not being removed, call fixsuffix() to
+ * indicate that it is being permanently fixed.
+ */
+
+/* Length of suffix to remove when inserting each possible character value. *
+ * suffixlen[256] is the length to remove for non-insertion editing actions. */
+
+/**/
+int suffixlen[257];
+
+/* Set up suffix: the last n characters are a suffix that should be *
+ * removed in the usual word end conditions. */
+
+/**/
+void
+makesuffix(int n)
+{
+ suffixlen[256] = suffixlen[' '] = suffixlen['\t'] = suffixlen['\n'] = n;
+}
+
+/* Set up suffix for parameter names: the last n characters are a suffix *
+ * that should be removed if the next character is one of the ones that *
+ * needs to go immediately after the parameter name. br indicates that *
+ * the name is in braces (${PATH} instead of $PATH), so the extra *
+ * characters that can only be used in braces are included. */
+
+/**/
+void
+makeparamsuffix(int br, int n)
+{
+ if(br || unset(KSHARRAYS))
+ suffixlen[':'] = suffixlen['['] = n;
+ if(br) {
+ suffixlen['#'] = suffixlen['%'] = suffixlen['?'] = n;
+ suffixlen['-'] = suffixlen['+'] = suffixlen['='] = n;
+ /*{*/ suffixlen['}'] = n;
+ }
+}
+
+/* Remove suffix, if there is one, when inserting character c. */
+
+/**/
+void
+iremovesuffix(int c)
+{
+ int sl = suffixlen[c];
+ if(sl) {
+ backdel(sl);
+ invalidatelist();
+ }
+ fixsuffix();
+}
+
+/* Fix the suffix in place, if there is one, making it non-removable. */
+
+/**/
+void
+fixsuffix(void)
+{
+ memset(suffixlen, 0, sizeof(suffixlen));
+}