about summary refs log tree commit diff
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));
+}