summaryrefslogtreecommitdiff
path: root/Src/Zle
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Zle')
-rw-r--r--Src/Zle/comp.h29
-rw-r--r--Src/Zle/compcore.c64
-rw-r--r--Src/Zle/compctl.c31
-rw-r--r--Src/Zle/complete.c68
-rw-r--r--Src/Zle/complist.c110
-rw-r--r--Src/Zle/compmatch.c158
-rw-r--r--Src/Zle/compresult.c5
-rw-r--r--Src/Zle/computil.c77
-rw-r--r--Src/Zle/iwidgets.list2
-rw-r--r--Src/Zle/textobjects.c18
-rw-r--r--Src/Zle/zle.h14
-rw-r--r--Src/Zle/zle_keymap.c47
-rw-r--r--Src/Zle/zle_main.c152
-rw-r--r--Src/Zle/zle_misc.c14
-rw-r--r--Src/Zle/zle_params.c177
-rw-r--r--Src/Zle/zle_refresh.c10
-rw-r--r--Src/Zle/zle_thingy.c17
-rw-r--r--Src/Zle/zle_tricky.c80
-rw-r--r--Src/Zle/zle_utils.c20
-rw-r--r--Src/Zle/zle_vi.c195
-rw-r--r--Src/Zle/zle_word.c92
21 files changed, 1030 insertions, 350 deletions
diff --git a/Src/Zle/comp.h b/Src/Zle/comp.h
index 023c41814..3711fde29 100644
--- a/Src/Zle/comp.h
+++ b/Src/Zle/comp.h
@@ -125,7 +125,7 @@ struct cmatch {
#define CMF_REMOVE (1<< 1) /* remove the suffix */
#define CMF_ISPAR (1<< 2) /* is paramter expansion */
#define CMF_PARBR (1<< 3) /* paramter expansion with a brace */
-#define CMF_PARNEST (1<< 4) /* nested paramter expansion */
+#define CMF_PARNEST (1<< 4) /* nested parameter expansion */
#define CMF_NOLIST (1<< 5) /* should not be listed */
#define CMF_DISPLINE (1<< 6) /* display strings one per line */
#define CMF_HIDE (1<< 7) /* temporarily hide this one */
@@ -160,9 +160,15 @@ struct cmatcher {
int ralen; /* length of right anchor */
};
+/* Flags for cmatcher::flags */
+/* Upon match, insert the string from the line rather than the string
+ * from the trial completion ("word"). */
#define CMF_LINE 1
+/* Match with an anchor on the left. */
#define CMF_LEFT 2
+/* Match with an anchor on the right. */
#define CMF_RIGHT 4
+/* ... */
#define CMF_INTER 8
/*
@@ -229,7 +235,6 @@ struct cpattern {
* the anchor. */
typedef struct cline *Cline;
-typedef struct clsub Clsub;
struct cline {
Cline next;
@@ -285,14 +290,14 @@ struct menuinfo {
/* Flags for compadd and addmatches(). */
-#define CAF_QUOTE 1
-#define CAF_NOSORT 2
-#define CAF_MATCH 4
-#define CAF_UNIQCON 8
-#define CAF_UNIQALL 16
-#define CAF_ARRAYS 32
-#define CAF_KEYS 64
-#define CAF_ALL 128
+#define CAF_QUOTE 1 /* compadd -Q: positional arguments already quoted */
+#define CAF_NOSORT 2 /* compadd -V: don't sort */
+#define CAF_MATCH 4 /* compadd without -U: do matching */
+#define CAF_UNIQCON 8 /* compadd -2: don't deduplicate */
+#define CAF_UNIQALL 16 /* compadd -1: deduplicate */
+#define CAF_ARRAYS 32 /* compadd -a or -k: array/assoc parameter names */
+#define CAF_KEYS 64 /* compadd -k: assoc parameter names */
+#define CAF_ALL 128 /* compadd -C: _all_matches */
/* Data for compadd and addmatches() */
@@ -367,7 +372,7 @@ typedef void (*CLPrintFunc)(Cmgroup, Cmatch *, int, int, int, int);
#define CP_QISUFFIX (1 << CPN_QISUFFIX)
#define CPN_COMPSTATE 9
#define CP_COMPSTATE (1 << CPN_COMPSTATE)
-
+/* See comprpms */
#define CP_REALPARAMS 10
#define CP_ALLREALS ((unsigned int) 0x3ff)
@@ -424,7 +429,7 @@ typedef void (*CLPrintFunc)(Cmgroup, Cmatch *, int, int, int, int);
#define CP_QUOTES (1 << CPN_QUOTES)
#define CPN_IGNORED 25
#define CP_IGNORED (1 << CPN_IGNORED)
-
+/* See compkpms */
#define CP_KEYPARAMS 26
#define CP_ALLKEYS ((unsigned int) 0x3ffffff)
diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c
index ae3a64074..d1cf7a08a 100644
--- a/Src/Zle/compcore.c
+++ b/Src/Zle/compcore.c
@@ -30,10 +30,6 @@
#include "complete.mdh"
#include "compcore.pro"
-/* The last completion widget called. */
-
-static Widget lastcompwidget;
-
/* Flags saying what we have to do with the result. */
/**/
@@ -429,6 +425,7 @@ do_completion(UNUSED(Hookdef dummy), Compldat dat)
}
} else {
invalidatelist();
+ lastambig = isset(BASHAUTOLIST);
if (forcelist)
clearlist = 1;
zlemetacs = 0;
@@ -471,8 +468,7 @@ before_complete(UNUSED(Hookdef dummy), int *lst)
/* If we are doing a menu-completion... */
- if (minfo.cur && menucmp && *lst != COMP_LIST_EXPAND &&
- (menucmp != 1 || !compwidget || compwidget == lastcompwidget)) {
+ if (minfo.cur && menucmp && *lst != COMP_LIST_EXPAND) {
do_menucmp(*lst);
return 1;
}
@@ -481,7 +477,6 @@ before_complete(UNUSED(Hookdef dummy), int *lst)
onlyexpl = listdat.valid = 0;
return 1;
}
- lastcompwidget = compwidget;
/* We may have to reset the cursor to its position after the *
* string inserted by the last completion. */
@@ -841,6 +836,7 @@ callcompfunc(char *s, char *fn)
endparamscope();
lastcmd = 0;
incompfunc = icf;
+ startauto = 0;
if (!complist)
uselist = 0;
@@ -888,8 +884,13 @@ callcompfunc(char *s, char *fn)
useline = 1, usemenu = 1;
else if (strpfx("auto", compinsert))
useline = 1, usemenu = 2;
- else
+ else {
useline = usemenu = 0;
+ /* if compstate[insert] was emptied, no unambiguous prefix
+ * ever gets inserted so allow the next tab to already start
+ * menu completion */
+ startauto = lastambig = isset(AUTOMENU);
+ }
if (useline && (p = strchr(compinsert, ':'))) {
insmnum = atoi(++p);
@@ -902,7 +903,7 @@ callcompfunc(char *s, char *fn)
#endif
}
}
- startauto = ((compinsert &&
+ startauto = startauto || ((compinsert &&
!strcmp(compinsert, "automenu-unambiguous")) ||
(bashlistfirst && isset(AUTOMENU) &&
(!compinsert || !*compinsert)));
@@ -1049,6 +1050,13 @@ makecomplist(char *s, int incmd, int lst)
}
}
+/*
+ * Quote 's' according to compqstack, aka $compstate[all_quotes].
+ *
+ * If 'ign' is 1, skip the innermost quoting level. Otherwise 'ign'
+ * must be 0.
+ */
+
/**/
mod_export char *
multiquote(char *s, int ign)
@@ -1056,12 +1064,11 @@ multiquote(char *s, int ign)
if (s) {
char *os = s, *p = compqstack;
- if (p && *p && (ign < 1 || p[ign])) {
- if (ign > 0)
- p += ign;
+ if (p && *p && (ign == 0 || p[1])) {
+ if (ign)
+ p++;
while (*p) {
- if (ign >= 0 || p[1])
- s = quotestring(s, NULL, *p);
+ s = quotestring(s, *p);
p++;
}
}
@@ -1071,6 +1078,12 @@ multiquote(char *s, int ign)
return NULL;
}
+/*
+ * tildequote(s, ign): Equivalent to multiquote(s, ign), except that if
+ * compqstack[0] == QT_BACKSLASH and s[0] == '~', then that tilde is not
+ * quoted.
+ */
+
/**/
mod_export char *
tildequote(char *s, int ign)
@@ -1970,6 +1983,11 @@ get_user_var(char *nam)
}
}
+/*
+ * If KEYS, then NAME is an associative array; return its keys.
+ * Else, NAME is a plain array; return its elements.
+ */
+
static char **
get_data_arr(char *name, int keys)
{
@@ -2031,16 +2049,17 @@ addmatch(char *str, int flags, char ***dispp, int line)
int
addmatches(Cadata dat, char **argv)
{
+ /* ms: "match string" - string to use as completion.
+ * Overloaded at one place as a temporary. */
char *s, *ms, *lipre = NULL, *lisuf = NULL, *lpre = NULL, *lsuf = NULL;
char **aign = NULL, **dparr = NULL, *oaq = autoq, *oppre = dat->ppre;
char *oqp = qipre, *oqs = qisuf, qc, **disp = NULL, *ibuf = NULL;
char **arrays = NULL;
- int lpl, lsl, pl, sl, bcp = 0, bcs = 0, bpadd = 0, bsadd = 0;
+ int lpl, lsl, bcp = 0, bcs = 0, bpadd = 0, bsadd = 0;
int ppl = 0, psl = 0, ilen = 0;
int llpl = 0, llsl = 0, nm = mnum, gflags = 0, ohp = haspattern;
int isexact, doadd, ois = instring, oib = inbackt;
Cline lc = NULL, pline = NULL, sline = NULL;
- Cmatch cm;
struct cmlist mst;
Cmlist oms = mstack;
Patprog cp = NULL, *pign = NULL;
@@ -2199,9 +2218,14 @@ addmatches(Cadata dat, char **argv)
/* Test if there is an existing -P prefix. */
if (dat->pre && *dat->pre) {
- pl = pfxlen(dat->pre, lpre);
- llpl -= pl;
- lpre += pl;
+ int prefix_length = pfxlen(dat->pre, lpre);
+ if (dat->pre[prefix_length] == '\0' ||
+ lpre[prefix_length] == '\0') {
+ /* $compadd_args[-P] is a prefix of ${PREFIX}, or
+ * vice-versa. */
+ llpl -= prefix_length;
+ lpre += prefix_length;
+ }
}
}
/* Now duplicate the strings we have from the command line. */
@@ -2413,6 +2437,7 @@ addmatches(Cadata dat, char **argv)
if (dat->psuf)
psl = strlen(dat->psuf);
for (; (s = *argv); argv++) {
+ int sl;
bpl = obpl;
bsl = obsl;
if (disp) {
@@ -2473,6 +2498,7 @@ addmatches(Cadata dat, char **argv)
goto next_array;
}
if (doadd) {
+ Cmatch cm;
Brinfo bp;
for (bp = obpl; bp; bp = bp->next)
diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c
index 8381867d0..52c6f1233 100644
--- a/Src/Zle/compctl.c
+++ b/Src/Zle/compctl.c
@@ -1400,7 +1400,7 @@ printcompctl(char *s, Compctl cc, int printflags, int ispat)
untokenize(p);
quotedzputs(p, stdout);
} else
- quotedzputs(quotestring(s, NULL, QT_BACKSLASH), stdout);
+ quotedzputs(quotestring(s, QT_BACKSLASH), stdout);
}
/* loop through flags w/o args that are set, printing them if so */
@@ -1536,7 +1536,7 @@ printcompctl(char *s, Compctl cc, int printflags, int ispat)
char *p = dupstring(s);
untokenize(p);
- quotedzputs(quotestring(p, NULL, QT_BACKSLASH), stdout);
+ quotedzputs(quotestring(p, QT_BACKSLASH), stdout);
}
}
putchar('\n');
@@ -1740,8 +1740,8 @@ static int addwhat;
* This uses the instring variable exported from zle_tricky.c.
*/
-#define quotename(s, e) \
-quotestring(s, e, instring == QT_NONE ? QT_BACKSLASH : instring)
+#define quotename(s) \
+quotestring(s, instring == QT_NONE ? QT_BACKSLASH : instring)
/* Hook functions */
@@ -1965,7 +1965,7 @@ addmatch(char *s, char *t)
if (!ms)
return;
- if (addwhat == -7 && !findcmd(s, 0))
+ if (addwhat == -7 && !findcmd(s, 0, 0))
return;
isfile = CMF_FILE;
} else if (addwhat == CC_QUOTEFLAG || addwhat == -2 ||
@@ -2135,7 +2135,7 @@ gen_matches_files(int dirs, int execs, int all)
{
DIR *d;
struct stat buf;
- char *n, p[PATH_MAX], *q = NULL, *e, *pathpref;
+ char *n, p[PATH_MAX+1], *q = NULL, *e, *pathpref;
LinkList l = NULL;
int ns = 0, ng = opts[NULLGLOB], test, aw = addwhat, pathpreflen;
@@ -2469,7 +2469,7 @@ makecomplistcmd(char *os, int incmd, int flags)
/* If the command string starts with `=', try the path name of the *
* command. */
if (cmdstr && cmdstr[0] == Equals) {
- char *c = findcmd(cmdstr + 1, 1);
+ char *c = findcmd(cmdstr + 1, 1, 0);
if (c) {
zsfree(cmdstr);
@@ -2509,7 +2509,8 @@ makecomplistpc(char *os, int incmd)
int ret = 0;
s = ((shfunctab->getnode(shfunctab, cmdstr) ||
- builtintab->getnode(builtintab, cmdstr)) ? NULL : findcmd(cmdstr, 1));
+ builtintab->getnode(builtintab, cmdstr)) ? NULL :
+ findcmd(cmdstr, 1, 0));
for (pc = patcomps; pc; pc = pc->next) {
if ((pat = patcompile(pc->pat, PAT_STATIC, NULL)) &&
@@ -3153,10 +3154,10 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
lpre = zhalloc(lpl + 1);
memcpy(lpre, s, lpl);
lpre[lpl] = '\0';
- qlpre = quotename(lpre, NULL);
+ qlpre = quotename(lpre);
lsuf = dupstring(s + offs);
lsl = strlen(lsuf);
- qlsuf = quotename(lsuf, NULL);
+ qlsuf = quotename(lsuf);
/* First check for ~.../... */
if (ic == Tilde) {
@@ -3175,11 +3176,11 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
rpre = (*p || *lpre == Tilde || *lpre == Equals) ?
(noreal = 0, getreal(tt)) :
dupstring(tt);
- qrpre = quotename(rpre, NULL);
+ qrpre = quotename(rpre);
for (p = lsuf; *p && *p != String && *p != Tick; p++);
rsuf = *p ? (noreal = 0, getreal(lsuf)) : dupstring(lsuf);
- qrsuf = quotename(rsuf, NULL);
+ qrsuf = quotename(rsuf);
/* Check if word is a pattern. */
@@ -3315,10 +3316,10 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
/* And get the file prefix. */
fpre = dupstring(((s1 == s || s1 == rpre || ic) &&
(*s != '/' || zlemetacs == wb)) ? s1 : s1 + 1);
- qfpre = quotename(fpre, NULL);
+ qfpre = quotename(fpre);
/* And the suffix. */
fsuf = dupstrpfx(rsuf, s2 - rsuf);
- qfsuf = quotename(fsuf, NULL);
+ qfsuf = quotename(fsuf);
if (comppatmatch && *comppatmatch && (ispattern & 2)) {
int t2;
@@ -3992,7 +3993,7 @@ enables_(Module m, int **enables)
/**/
int
-boot_(Module m)
+boot_(UNUSED(Module m))
{
addhookfunc("compctl_make", (Hookfn) ccmakehookfn);
addhookfunc("compctl_cleanup", (Hookfn) cccleanuphookfn);
diff --git a/Src/Zle/complete.c b/Src/Zle/complete.c
index ee4e5b0a5..7980518b7 100644
--- a/Src/Zle/complete.c
+++ b/Src/Zle/complete.c
@@ -52,7 +52,7 @@ char **compwords,
*compqiprefix,
*compqisuffix,
*compquote,
- *compqstack,
+ *compqstack, /* compstate[all_quotes] */
*comppatmatch,
*complastprompt;
/**/
@@ -72,8 +72,26 @@ char *compiprefix,
*compoldins,
*compvared;
+/*
+ * An array of Param structures for compsys special parameters;
+ * see 'comprparams' below. An entry for $compstate is added
+ * by makecompparams().
+ *
+ * See CP_REALPARAMS.
+ */
+
/**/
-Param *comprpms, *compkpms;
+Param *comprpms;
+
+/*
+ * An array of Param structures for elemens of $compstate; see
+ * 'compkparams' below.
+ *
+ * See CP_KEYPARAMS.
+ */
+
+/**/
+Param *compkpms;
/**/
mod_export void
@@ -231,16 +249,17 @@ parse_cmatcher(char *name, char *s)
if (!*s) break;
switch (*s) {
- case 'b': fl2 = CMF_INTER;
+ case 'b': fl2 = CMF_INTER; /* FALLTHROUGH */
case 'l': fl = CMF_LEFT; break;
- case 'e': fl2 = CMF_INTER;
+ case 'e': fl2 = CMF_INTER; /* FALLTHROUGH */
case 'r': fl = CMF_RIGHT; break;
case 'm': fl = 0; break;
- case 'B': fl2 = CMF_INTER;
+ case 'B': fl2 = CMF_INTER; /* FALLTHROUGH */
case 'L': fl = CMF_LEFT | CMF_LINE; break;
- case 'E': fl2 = CMF_INTER;
+ case 'E': fl2 = CMF_INTER; /* FALLTHROUGH */
case 'R': fl = CMF_RIGHT | CMF_LINE; break;
case 'M': fl = CMF_LINE; break;
+ case 'x': break;
default:
if (name)
zwarnnam(name, "unknown match specification character `%c'",
@@ -252,6 +271,15 @@ parse_cmatcher(char *name, char *s)
zwarnnam(name, "missing `:'");
return pcm_err;
}
+ if (*s == 'x') {
+ if (s[2] && !inblank(s[2])) {
+ if (name)
+ zwarnnam(name,
+ "unexpected pattern following x: specification");
+ return pcm_err;
+ }
+ return ret;
+ }
s += 2;
if (!*s) {
if (name)
@@ -527,8 +555,8 @@ static int
bin_compadd(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
{
struct cadata dat;
- char *p, **sp, *e, *m = NULL, *mstr = NULL;
- int dm;
+ char *mstr = NULL; /* argument of -M options, accumulated */
+ int added; /* return value */
Cmatcher match = NULL;
if (incompfunc != 1) {
@@ -544,14 +572,16 @@ bin_compadd(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
dat.dummies = -1;
for (; *argv && **argv == '-'; argv++) {
+ char *p; /* loop variable, points into argv */
if (!(*argv)[1]) {
argv++;
break;
}
for (p = *argv + 1; *p; p++) {
- sp = NULL;
- e = NULL;
- dm = 0;
+ char *m = NULL; /* argument of -M option (this one only) */
+ char **sp = NULL; /* the argument to an option should be copied
+ to *sp. */
+ const char *e; /* error message */
switch (*p) {
case 'q':
dat.flags |= CMF_REMOVE;
@@ -633,7 +663,6 @@ bin_compadd(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
case 'M':
sp = &m;
e = "matching specification expected after -%c";
- dm = 1;
break;
case 'X':
sp = &(dat.exp);
@@ -704,27 +733,29 @@ bin_compadd(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
}
if (sp) {
if (p[1]) {
+ /* Pasted argument: -Xfoo. */
if (!*sp)
*sp = p + 1;
p = "" - 1;
} else if (argv[1]) {
+ /* Argument in a separate word: -X foo. */
argv++;
if (!*sp)
*sp = *argv;
p = "" - 1;
} else {
+ /* Missing argument: argv[N] == "-X", argv[N+1] == NULL. */
zwarnnam(name, e, *p);
zsfree(mstr);
return 1;
}
- if (dm) {
+ if (m) {
if (mstr) {
char *tmp = tricat(mstr, " ", m);
zsfree(mstr);
mstr = tmp;
} else
mstr = ztrdup(m);
- m = NULL;
}
}
}
@@ -743,10 +774,10 @@ bin_compadd(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
return 1;
dat.match = match = cpcmatcher(match);
- dm = addmatches(&dat, argv);
+ added = addmatches(&dat, argv);
freecmatcher(match);
- return dm;
+ return added;
}
#define CVT_RANGENUM 0
@@ -1207,8 +1238,9 @@ makecompparams(void)
addcompparams(comprparams, comprpms);
- if (!(cpm = createparam(COMPSTATENAME,
- PM_SPECIAL|PM_REMOVABLE|PM_LOCAL|PM_HASHED)))
+ if (!(cpm = createparam(
+ COMPSTATENAME,
+ PM_SPECIAL|PM_REMOVABLE|PM_SINGLE|PM_LOCAL|PM_HASHED)))
cpm = (Param) paramtab->getnode(paramtab, COMPSTATENAME);
DPUTS(!cpm, "param not set in makecompparams");
diff --git a/Src/Zle/complist.c b/Src/Zle/complist.c
index 0ccb88505..2edaf6eca 100644
--- a/Src/Zle/complist.c
+++ b/Src/Zle/complist.c
@@ -34,8 +34,9 @@
/* Information about the list shown. */
/*
- * noselect: 1 if complistmatches indicated we shouldn't do selection.
- * Tested in domenuselect.
+ * noselect: 1 if complistmatches indicated we shouldn't do selection;
+ * -1 if interactive mode needs to reset the selection list.
+ * Tested in domenuselect, and in complistmatches to skip redraw.
* mselect: Local copy of the index of the currently selected match.
* Initialised to the gnum entry of the current match for
* each completion.
@@ -113,7 +114,7 @@ static Cmgroup *mgtab, *mgtabp;
* Allow us to keep track of pointer arithmetic for mgtab; could
* just as well have been for mtab but wasn't.
*/
-int mgtabsize;
+static int mgtabsize;
#endif
/*
@@ -346,9 +347,10 @@ getcoldef(char *s)
char sav = p[1];
p[1] = '\0';
+ s = metafy(s, -1, META_USEHEAP);
tokenize(s);
gprog = patcompile(s, 0, NULL);
- p[1] =sav;
+ p[1] = sav;
s = p + 1;
}
@@ -414,6 +416,7 @@ getcoldef(char *s)
break;
*s++ = '\0';
}
+ p = metafy(p, -1, META_USEHEAP);
tokenize(p);
if ((prog = patcompile(p, 0, NULL))) {
Patcol pc, po;
@@ -661,7 +664,9 @@ clprintfmt(char *p, int ml)
initiscol();
- for (; *p; p++) {
+ while (*p) {
+ convchar_t chr;
+ int chrlen = MB_METACHARLENCONV(p, &chr);
doiscol(i++);
cc++;
if (*p == '\n') {
@@ -672,11 +677,16 @@ clprintfmt(char *p, int ml)
if (ml == mlend - 1 && (cc % zterm_columns) == zterm_columns - 1)
return 0;
- if (*p == Meta) {
+ while (chrlen) {
+ if (*p == Meta) {
+ p++;
+ chrlen--;
+ putc(*p ^ 32, shout);
+ } else
+ putc(*p, shout);
+ chrlen--;
p++;
- putc(*p ^ 32, shout);
- } else
- putc(*p, shout);
+ }
if ((beg = !(cc % zterm_columns)))
ml++;
if (mscroll && !(cc % zterm_columns) &&
@@ -989,6 +999,7 @@ asklistscroll(int ml)
fflush(shout);
zsetterm();
+ menuselect_bindings(); /* sanity in case deleted by user */
selectlocalmap(lskeymap);
if (!(cmd = getkeycmd()) || cmd == Th(z_sendbreak))
ret = 1;
@@ -1979,7 +1990,8 @@ complistmatches(UNUSED(Hookdef dummy), Chdata dat)
}
#endif
- noselect = 0;
+ if (noselect > 0)
+ noselect = 0;
if ((minfo.asked == 2 && mselect < 0) || nlnct >= zterm_lines) {
showinglist = 0;
@@ -2077,9 +2089,11 @@ complistmatches(UNUSED(Hookdef dummy), Chdata dat)
last_cap = (char *) zhalloc(max_caplen + 1);
*last_cap = '\0';
- if (!mnew && inselect && onlnct == nlnct && mlbeg >= 0 && mlbeg == molbeg)
- singledraw();
- else if (!compprintlist(mselect >= 0) || !clearflag)
+ if (!mnew && inselect &&
+ onlnct == nlnct && mlbeg >= 0 && mlbeg == molbeg) {
+ if (!noselect)
+ singledraw();
+ } else if (!compprintlist(mselect >= 0) || !clearflag)
noselect = 1;
onlnct = nlnct;
@@ -2092,7 +2106,7 @@ complistmatches(UNUSED(Hookdef dummy), Chdata dat)
popheap();
opts[EXTENDEDGLOB] = extendedglob;
- return noselect;
+ return (noselect < 0 ? 0 : noselect);
}
static int
@@ -2433,6 +2447,7 @@ domenuselect(Hookdef dummy, Chdata dat)
unqueue_signals();
mhasstat = (mstatus && *mstatus);
fdat = dat;
+ menuselect_bindings(); /* sanity in case deleted by user */
selectlocalmap(mskeymap);
noselect = 1;
while ((menuacc &&
@@ -2545,14 +2560,23 @@ domenuselect(Hookdef dummy, Chdata dat)
} else {
statusline = NULL;
}
+ if (noselect < 0) {
+ showinglist = clearlist = 0;
+ clearflag = 1;
+ }
zrefresh();
statusline = NULL;
inselect = 1;
+ selected = 1;
if (noselect) {
+ if (noselect < 0) {
+ /* no selection until after processing keystroke */
+ noselect = 0;
+ goto getk;
+ }
broken = 1;
break;
}
- selected = 1;
if (!i) {
i = mcols * mlines;
while (i--)
@@ -2750,6 +2774,7 @@ domenuselect(Hookdef dummy, Chdata dat)
if (nmessages) {
showinglist = -2;
zrefresh();
+ noselect = -1;
} else {
trashzle();
zsetterm();
@@ -3383,7 +3408,7 @@ domenuselect(Hookdef dummy, Chdata dat)
do_single(*(minfo.cur));
}
if (wasnext || broken) {
- menucmp = 2;
+ menucmp = 1;
showinglist = ((validlist && !nolist) ? -2 : 0);
minfo.asked = 0;
if (!noselect) {
@@ -3486,6 +3511,37 @@ enables_(Module m, int **enables)
}
/**/
+static void
+menuselect_bindings(void)
+{
+ if (!(mskeymap = openkeymap("menuselect"))) {
+ mskeymap = newkeymap(NULL, "menuselect");
+ linkkeymap(mskeymap, "menuselect", 1);
+ bindkey(mskeymap, "\t", refthingy(t_completeword), NULL);
+ bindkey(mskeymap, "\n", refthingy(t_acceptline), NULL);
+ bindkey(mskeymap, "\r", refthingy(t_acceptline), NULL);
+ bindkey(mskeymap, "\33[A", refthingy(t_uplineorhistory), NULL);
+ bindkey(mskeymap, "\33[B", refthingy(t_downlineorhistory), NULL);
+ bindkey(mskeymap, "\33[C", refthingy(t_forwardchar), NULL);
+ bindkey(mskeymap, "\33[D", refthingy(t_backwardchar), NULL);
+ bindkey(mskeymap, "\33OA", refthingy(t_uplineorhistory), NULL);
+ bindkey(mskeymap, "\33OB", refthingy(t_downlineorhistory), NULL);
+ bindkey(mskeymap, "\33OC", refthingy(t_forwardchar), NULL);
+ bindkey(mskeymap, "\33OD", refthingy(t_backwardchar), NULL);
+ }
+ if (!(lskeymap = openkeymap("listscroll"))) {
+ lskeymap = newkeymap(NULL, "listscroll");
+ linkkeymap(lskeymap, "listscroll", 1);
+ bindkey(lskeymap, "\t", refthingy(t_completeword), NULL);
+ bindkey(lskeymap, " ", refthingy(t_completeword), NULL);
+ bindkey(lskeymap, "\n", refthingy(t_acceptline), NULL);
+ bindkey(lskeymap, "\r", refthingy(t_acceptline), NULL);
+ bindkey(lskeymap, "\33[B", refthingy(t_downlineorhistory), NULL);
+ bindkey(lskeymap, "\33OB", refthingy(t_downlineorhistory), NULL);
+ }
+}
+
+/**/
int
boot_(Module m)
{
@@ -3503,27 +3559,7 @@ boot_(Module m)
}
addhookfunc("comp_list_matches", (Hookfn) complistmatches);
addhookfunc("menu_start", (Hookfn) domenuselect);
- mskeymap = newkeymap(NULL, "menuselect");
- linkkeymap(mskeymap, "menuselect", 1);
- bindkey(mskeymap, "\t", refthingy(t_completeword), NULL);
- bindkey(mskeymap, "\n", refthingy(t_acceptline), NULL);
- bindkey(mskeymap, "\r", refthingy(t_acceptline), NULL);
- bindkey(mskeymap, "\33[A", refthingy(t_uplineorhistory), NULL);
- bindkey(mskeymap, "\33[B", refthingy(t_downlineorhistory), NULL);
- bindkey(mskeymap, "\33[C", refthingy(t_forwardchar), NULL);
- bindkey(mskeymap, "\33[D", refthingy(t_backwardchar), NULL);
- bindkey(mskeymap, "\33OA", refthingy(t_uplineorhistory), NULL);
- bindkey(mskeymap, "\33OB", refthingy(t_downlineorhistory), NULL);
- bindkey(mskeymap, "\33OC", refthingy(t_forwardchar), NULL);
- bindkey(mskeymap, "\33OD", refthingy(t_backwardchar), NULL);
- lskeymap = newkeymap(NULL, "listscroll");
- linkkeymap(lskeymap, "listscroll", 1);
- bindkey(lskeymap, "\t", refthingy(t_completeword), NULL);
- bindkey(lskeymap, " ", refthingy(t_completeword), NULL);
- bindkey(lskeymap, "\n", refthingy(t_acceptline), NULL);
- bindkey(lskeymap, "\r", refthingy(t_acceptline), NULL);
- bindkey(lskeymap, "\33[B", refthingy(t_downlineorhistory), NULL);
- bindkey(lskeymap, "\33OB", refthingy(t_downlineorhistory), NULL);
+ menuselect_bindings();
return 0;
}
diff --git a/Src/Zle/compmatch.c b/Src/Zle/compmatch.c
index 0e41ac3a5..f82f00e1d 100644
--- a/Src/Zle/compmatch.c
+++ b/Src/Zle/compmatch.c
@@ -498,14 +498,27 @@ add_match_sub(Cmatcher m, char *l, int ll, char *w, int wl)
/**/
int
match_str(char *l, char *w, Brinfo *bpp, int bc, int *rwlp,
- int sfx, int test, int part)
+ const int sfx, int test, int part)
{
- int ll = strlen(l), lw = strlen(w), oll = ll, olw = lw, exact = 0, wexact = 0;
- int il = 0, iw = 0, t, ind, add, he = 0, bpc, obc = bc, bslash;
+ /* How many characters from the line string and from the word string are
+ * yet to be matched. */
+ int ll = strlen(l), lw = strlen(w);
+ /* Number of characters from the line string and word string matched. */
+ int il = 0, iw = 0;
+ /* How many characters were matched exactly in the line and in the word. */
+ int exact = 0, wexact = 0;
+ int he = 0;
+ int bslash;
char *ow;
- Cmlist ms;
+ Cmlist ms; /* loop variable */
Cmatcher mp, lm = NULL;
Brinfo bp = NULL;
+ const int obc = bc;
+ const int ind = (sfx ? -1 : 0);
+ const int add = (sfx ? -1 : 1);
+ const int original_ll = ll, original_lw = lw;
+
+ /* INVARIANT: il+ll == original_ll; iw+lw == original_lw */
if (!test) {
start_match();
@@ -516,9 +529,6 @@ match_str(char *l, char *w, Brinfo *bpp, int bc, int *rwlp,
if (sfx) {
l += ll; w += lw;
- ind = -1; add = -1;
- } else {
- ind = 0; add = 1;
}
/* ow will always point to the beginning (or end) of that sub-string
* in w that wasn't put in the match-variables yet. */
@@ -559,8 +569,7 @@ match_str(char *l, char *w, Brinfo *bpp, int bc, int *rwlp,
bslash = 0;
if (!sfx && lw && (!part || test) &&
(l[ind] == w[ind] ||
- (bslash = (lw > 1 && w[ind] == '\\' &&
- (ind ? (w[0] == l[0]) : (w[1] == l[0])))))) {
+ (bslash = (lw > 1 && w[ind] == '\\' && w[ind+1] == l[0])))) {
/* No matcher could be used, but the strings have the same
* character here, skip over it. */
l += add; w += (bslash ? (add + add) : add);
@@ -583,9 +592,8 @@ match_str(char *l, char *w, Brinfo *bpp, int bc, int *rwlp,
/* First try the matchers. Err... see above. */
for (mp = NULL, ms = mstack; !mp && ms; ms = ms->next) {
for (mp = ms->matcher; mp; mp = mp->next) {
- t = 1;
if ((lm && lm == mp) ||
- ((oll == ll || olw == lw) &&
+ ((original_ll == ll || original_lw == lw) &&
(test == 1 || (test && !mp->left && !mp->right)) &&
mp->wlen < 0))
/* If we were called recursively, don't use `*' patterns
@@ -593,9 +601,88 @@ match_str(char *l, char *w, Brinfo *bpp, int bc, int *rwlp,
continue;
if (mp->wlen < 0) {
- int both, loff, aoff, llen, alen, zoff, moff, ct, ict, aol;
- char *tp, savl = '\0', savw;
- Cpattern ap, aop;
+ /* `*'-pattern. */
+ /*
+ * Similar to the identically-named variable in the 'else'
+ * block.
+ */
+ int t;
+ /*
+ * 1 iff the anchor and the word are on the same side of
+ * the line pattern; that is: if either
+ * - the anchor is on the left and we are matching
+ * a prefix; or
+ * - the anchor is on the right and we are matching
+ * a suffix.
+ */
+ int both;
+ /*
+ * Offset from the line pattern pointer ('l') to the start
+ * of the line pattern.
+ */
+ int loff;
+ /*
+ * Offset from the line pattern pointer ('l') to the start
+ * of the anchor.
+ */
+ int aoff;
+ /*
+ * The length of the line pattern.
+ */
+ int llen;
+ /*
+ * The length of the anchor.
+ *
+ * SEE: ap; aol, aop
+ */
+ int alen;
+ /*
+ * ### Related to 'zoff', which was removed in 2016.
+ */
+ int moff;
+ /*
+ * ### These two are related.
+ *
+ * ### They may have a relation similar to that of lw/iw
+ * ### (q.v.), at least during the 'for' loop. They may be
+ * ### overloaded/repurposed after it.
+ */
+ int ct, ict;
+ /*
+ * The length of the OTHER anchor: the left anchor when
+ * we're anchored on the right, and of the right anchor
+ * when we're anchored on the left.
+ */
+ int aol;
+ /*
+ * LOST: Documentation comment. Last seen 10 years ago in
+ * the temporal lobe. Reward promised for its safe return.
+ * Contact zsh-workers@zsh.org.
+ */
+ char *tp;
+ /*
+ * Temporary variable. Used as temporary storage for a
+ *
+ * {
+ * () {
+ * local foo="$foo"
+ * foo[1]=bar
+ * ...
+ * }
+ * (use original $foo here)
+ * }
+ *
+ * operation. Similar to savw.
+ */
+ char savl;
+ /*
+ * The anchor on this end.
+ */
+ Cpattern ap;
+ /*
+ * The anchor on the other end.
+ */
+ Cpattern aop;
/* This is for `*' patterns, first initialise some
* local variables. */
@@ -611,14 +698,14 @@ match_str(char *l, char *w, Brinfo *bpp, int bc, int *rwlp,
continue;
if (mp->flags & CMF_LEFT) {
- ap = mp->left; zoff = 0; moff = alen; aop = mp->right;
+ ap = mp->left; moff = alen; aop = mp->right;
if (sfx) {
both = 0; loff = -llen; aoff = -(llen + alen);
} else {
both = 1; loff = alen; aoff = 0;
}
} else {
- ap = mp->right; zoff = alen; moff = 0; aop = mp->left;
+ ap = mp->right; moff = 0; aop = mp->left;
if (sfx) {
both = 1; loff = -(llen + alen); aoff = -alen;
} else {
@@ -644,8 +731,8 @@ match_str(char *l, char *w, Brinfo *bpp, int bc, int *rwlp,
/* Fine, now we call ourselves recursively to find the
* string matched by the `*'. */
- if (sfx && (savl = l[-(llen + zoff)]))
- l[-(llen + zoff)] = '\0';
+ if (sfx && (savl = l[-(llen + alen)]))
+ l[-(llen + alen)] = '\0';
for (t = 0, tp = w, ct = 0, ict = lw - alen + 1;
ict;
tp += add, ct++, ict--) {
@@ -667,22 +754,25 @@ match_str(char *l, char *w, Brinfo *bpp, int bc, int *rwlp,
!match_parts(l + aoff , tp - moff, alen, part))
break;
if (sfx) {
- if ((savw = tp[-zoff]))
- tp[-zoff] = '\0';
+ /* Call ourselves recursively with the
+ * anchor removed. */
+ char savw;
+ if ((savw = tp[-alen]))
+ tp[-alen] = '\0';
t = match_str(l - ll, w - lw,
- NULL, 0, NULL, 1, 2, part);
+ NULL, 0, NULL, sfx, 2, part);
if (savw)
- tp[-zoff] = savw;
+ tp[-alen] = savw;
} else
t = match_str(l + llen + moff, tp + moff,
- NULL, 0, NULL, 0, 1, part);
+ NULL, 0, NULL, sfx, 1, part);
if (t || (mp->wlen == -1 && !both))
break;
}
}
ict = ct;
if (sfx && savl)
- l[-(llen + zoff)] = savl;
+ l[-(llen + alen)] = savl;
/* Have we found a position in w where the rest of l
* matches? */
@@ -752,18 +842,22 @@ match_str(char *l, char *w, Brinfo *bpp, int bc, int *rwlp,
bc += llen;
exact = 0;
- if (!test)
+ if (!test) {
+ int bpc;
while (bp &&
bc >= (bpc = (useqbr ? bp->qpos : bp->pos))) {
bp->curpos = matchbufadded + bpc - bc + obc;
bp = bp->next;
}
+ }
ow = w;
if (!llen && !alen) {
lm = mp;
- if (he)
+ if (he) {
+ /* Signal the outer for loop to continue. */
mp = NULL;
+ }
else
he = 1;
} else {
@@ -772,6 +866,11 @@ match_str(char *l, char *w, Brinfo *bpp, int bc, int *rwlp,
break;
} else if (ll >= mp->llen && lw >= mp->wlen) {
/* Non-`*'-pattern. */
+ /*
+ * Similar to the identically-named variable in the 'if'
+ * block.
+ */
+ int t = 1;
char *tl, *tw;
int tll, tlw, til, tiw;
@@ -875,12 +974,14 @@ match_str(char *l, char *w, Brinfo *bpp, int bc, int *rwlp,
bc += mp->llen;
exact = 0;
- if (!test)
+ if (!test) {
+ int bpc;
while (bp &&
bc >= (bpc = (useqbr ? bp->qpos : bp->pos))) {
bp->curpos = matchbufadded + bpc - bc + obc;
bp = bp->next;
}
+ }
ow = w;
lm = NULL;
he = 0;
@@ -896,8 +997,7 @@ match_str(char *l, char *w, Brinfo *bpp, int bc, int *rwlp,
bslash = 0;
if ((!test || sfx) && lw &&
(l[ind] == w[ind] ||
- (bslash = (lw > 1 && w[ind] == '\\' &&
- (ind ? (w[0] == l[0]) : (w[1] == l[0])))))) {
+ (bslash = (lw > 1 && w[ind] == '\\' && w[ind+1] == l[0])))) {
/* No matcher could be used, but the strings have the same
* character here, skip over it. */
l += add; w += (bslash ? (add + add ) : add);
diff --git a/Src/Zle/compresult.c b/Src/Zle/compresult.c
index 7fec7c804..05799399d 100644
--- a/Src/Zle/compresult.c
+++ b/Src/Zle/compresult.c
@@ -1174,6 +1174,10 @@ do_single(Cmatch m)
zlemetacs = minfo.end;
if (zlemetacs + m->qisl == lastend)
zlemetacs += minfo.insc;
+
+ /* Advance CURSOR past compadd -s/-S suffixes. */
+ zlemetacs += strlen(psuf);
+ zlemetacs += m->suf ? strlen(m->suf) : 0;
}
{
Cmatch *om = minfo.cur;
@@ -1191,6 +1195,7 @@ do_single(Cmatch m)
if (menucmp)
minfo.cur = &m;
runhookdef(INSERTMATCHHOOK, (void *) &dat);
+ redrawhook();
minfo.cur = om;
}
}
diff --git a/Src/Zle/computil.c b/Src/Zle/computil.c
index 60fb096be..c78167329 100644
--- a/Src/Zle/computil.c
+++ b/Src/Zle/computil.c
@@ -199,11 +199,11 @@ cd_calc(void)
set->count++;
if ((l = strlen(str->str)) > cd_state.pre)
cd_state.pre = l;
- if ((l = MB_METASTRWIDTH(str->str)) > cd_state.premaxw)
+ if ((l = ZMB_nicewidth(str->str)) > cd_state.premaxw)
cd_state.premaxw = l;
if (str->desc) {
set->desc++;
- if ((l = strlen(str->desc)) > cd_state.suf)
+ if ((l = strlen(str->desc)) > cd_state.suf) /* ### strlen() assumes no \n */
cd_state.suf = l;
}
}
@@ -490,7 +490,7 @@ cd_init(char *nam, char *hide, char *mlen, char *sep,
setp = &(cd_state.sets);
cd_state.sep = ztrdup(sep);
cd_state.slen = strlen(sep);
- cd_state.swidth = MB_METASTRWIDTH(sep);
+ cd_state.swidth = ZMB_nicewidth(sep);
cd_state.sets = NULL;
cd_state.showd = disp;
cd_state.maxg = cd_state.groups = cd_state.descs = 0;
@@ -526,7 +526,8 @@ cd_init(char *nam, char *hide, char *mlen, char *sep,
str->other = NULL;
str->set = set;
- for (tmp = *ap; *tmp && *tmp != ':'; tmp++)
+ /* Advance tmp to the first unescaped colon. */
+ for (tmp = *ap; *tmp && *tmp != ':'; tmp++)
if (*tmp == '\\' && tmp[1])
tmp++;
@@ -537,7 +538,7 @@ cd_init(char *nam, char *hide, char *mlen, char *sep,
*tmp = '\0';
str->str = str->match = ztrdup(rembslash(*ap));
str->len = strlen(str->str);
- str->width = MB_METASTRWIDTH(str->str);
+ str->width = ZMB_nicewidth(str->str);
str->sortstr = NULL;
}
if (str)
@@ -692,7 +693,7 @@ cd_get(char **params)
* end of screen as safety margin
*/
d = str->desc;
- w = MB_METASTRWIDTH(d);
+ w = ZMB_nicewidth(d);
if (w <= remw)
strcpy(p, d);
else {
@@ -701,7 +702,7 @@ cd_get(char **params)
l = MB_METACHARLEN(d);
memcpy(pp, d, l);
pp[l] = '\0';
- w = MB_METASTRWIDTH(pp);
+ w = ZMB_nicewidth(pp);
if (w > remw) {
*pp = '\0';
break;
@@ -792,7 +793,7 @@ cd_get(char **params)
cd_state.swidth - CM_SPACE;
p = pp = dbuf + cd_state.slen;
d = str->desc;
- w = MB_METASTRWIDTH(d);
+ w = ZMB_nicewidth(d);
if (w <= remw) {
strcpy(p, d);
remw -= w;
@@ -802,7 +803,7 @@ cd_get(char **params)
l = MB_METACHARLEN(d);
memcpy(pp, d, l);
pp[l] = '\0';
- w = MB_METASTRWIDTH(pp);
+ w = ZMB_nicewidth(pp);
if (w > remw) {
*pp = '\0';
break;
@@ -1693,10 +1694,10 @@ ca_get_opt(Cadef d, char *line, int full, char **end)
for (p = d->opts; p; p = p->next)
if (p->active && ((!p->args || p->type == CAO_NEXT) ?
!strcmp(p->name, line) : strpfx(p->name, line))) {
- int l = strlen(p->name);
- if ((p->type == CAO_OEQUAL || p->type == CAO_EQUAL) &&
- line[l] && line[l] != '=')
- continue;
+ int l = strlen(p->name);
+ if ((p->type == CAO_OEQUAL || p->type == CAO_EQUAL) &&
+ line[l] && line[l] != '=')
+ continue;
if (end) {
/* Return a pointer to the end of the option. */
@@ -2158,7 +2159,8 @@ ca_parse_line(Cadef d, int multi, int first)
state.opt = 0;
else
state.curopt = NULL;
- } else if (multi && (*line == '-' || *line == '+') && cur != compcurrent
+ } else if (multi && (*line == '-' || *line == '+') && cur != compcurrent &&
+ ca_get_opt(d, line, 0, NULL)
#if 0
/**** Ouch. Using this will disable the mutual exclusion
of different sets. Not using it will make the -A
@@ -2167,9 +2169,11 @@ ca_parse_line(Cadef d, int multi, int first)
#endif
)
return 1;
- else if (state.arg && (!napat || !pattry(napat, line))) {
+ else if (state.arg &&
+ (!napat || cur <= compcurrent || !pattry(napat, line))) {
/* Otherwise it's a normal argument. */
- if (napat && ca_inactive(d, NULL, cur + 1, 1, NULL))
+ if (napat && cur <= compcurrent &&
+ ca_inactive(d, NULL, cur + 1, 1, NULL))
return 1;
arglast = 1;
@@ -2308,7 +2312,10 @@ ca_parse_line(Cadef d, int multi, int first)
return 0;
}
-/* Build a colon-list from a list. */
+/* Build a colon-list from a list.
+ *
+ * This is only used to populate values of $opt_args.
+ */
static char *
ca_colonlist(LinkList l)
@@ -2318,16 +2325,19 @@ ca_colonlist(LinkList l)
int len = 0;
char *p, *ret, *q;
+ /* Compute the length to be allocated. */
for (n = firstnode(l); n; incnode(n)) {
len++;
for (p = (char *) getdata(n); *p; p++)
- len += (*p == ':' ? 2 : 1);
+ len += (*p == ':' || *p == '\\') ? 2 : 1;
}
ret = q = (char *) zalloc(len);
+ /* Join L into RET, joining with colons and escaping colons and
+ * backslashes. */
for (n = firstnode(l); n;) {
for (p = (char *) getdata(n); *p; p++) {
- if (*p == ':')
+ if (*p == ':' || *p == '\\')
*q++ = '\\';
*q++ = *p;
}
@@ -3546,7 +3556,7 @@ comp_quote(char *str, int prefix)
if ((x = (prefix && *str == '=')))
*str = 'x';
- ret = quotestring(str, NULL, *compqstack);
+ ret = quotestring(str, *compqstack);
if (x)
*str = *ret = '=';
@@ -4480,6 +4490,10 @@ cfp_matcher_pats(char *matcher, char *add)
return add;
}
+/*
+ * ### This function call is skipped by _approximate, so "opt" probably means "optimize".
+ */
+
static void
cfp_opt_pats(char **pats, char *matcher)
{
@@ -4732,7 +4746,7 @@ cf_ignore(char **names, LinkList ign, char *style, char *path)
for (; (n = *names); names++) {
if (!ztat(n, &nst, 1) && S_ISDIR(nst.st_mode)) {
if (tpwd && nst.st_dev == est.st_dev && nst.st_ino == est.st_ino) {
- addlinknode(ign, quotestring(n, NULL, QT_BACKSLASH));
+ addlinknode(ign, quotestring(n, QT_BACKSLASH));
continue;
}
if (tpar && !strncmp((c = dupstring(n)), path, pl)) {
@@ -4748,7 +4762,7 @@ cf_ignore(char **names, LinkList ign, char *style, char *path)
if (found || ((e = strrchr(c, '/')) && e > c + pl &&
!ztat(c, &st, 1) && st.st_dev == nst.st_dev &&
st.st_ino == nst.st_ino))
- addlinknode(ign, quotestring(n, NULL, QT_BACKSLASH));
+ addlinknode(ign, quotestring(n, QT_BACKSLASH));
}
}
}
@@ -4811,6 +4825,20 @@ cf_remove_other(char **names, char *pre, int *amb)
return NULL;
}
+/*
+ * SYNOPSIS:
+ * 1. compfiles -p parnam1 parnam2 skipped matcher sdirs parnam3 varargs [..varargs]
+ * 2. compfiles -p- parnam1 parnam2 skipped matcher sdirs parnam3 varargs [..varargs]
+ * 3. compfiles -P parnam1 parnam2 skipped matcher sdirs parnam3
+ *
+ * 1. Set parnam1 to an array of patterns....
+ * ${(P)parnam1} is an in/out parameter.
+ * 2. Like #1 but without calling cfp_opt_pats(). (This is only used by _approximate.)
+ * 3. Like #1 but varargs is implicitly set to char *varargs[2] = { "*(-/)", NULL };.
+ *
+ * parnam2 has to do with the accept-exact style (see cfp_test_exact()).
+ */
+
static int
bin_compfiles(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
{
@@ -4839,11 +4867,12 @@ bin_compfiles(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
}
queue_signals();
if (!(tmp = getaparam(args[1]))) {
+ unqueue_signals();
zwarnnam(nam, "unknown parameter: %s", args[1]);
return 0;
}
for (l = newlinklist(); *tmp; tmp++)
- addlinknode(l, *tmp);
+ addlinknode(l, quotestring(*tmp, QT_BACKSLASH_PATTERN));
set_list_array(args[1], cf_pats((args[0][1] == 'P'), !!args[0][2],
l, getaparam(args[2]), args[3],
args[4], args[5],
@@ -4994,7 +5023,7 @@ enables_(Module m, int **enables)
/**/
int
-boot_(Module m)
+boot_(UNUSED(Module m))
{
return 0;
}
diff --git a/Src/Zle/iwidgets.list b/Src/Zle/iwidgets.list
index 2b2654c5d..58310cd74 100644
--- a/Src/Zle/iwidgets.list
+++ b/Src/Zle/iwidgets.list
@@ -143,6 +143,7 @@
"vi-delete", videlete, ZLE_KEEPSUFFIX | ZLE_LASTCOL | ZLE_VIOPER
"vi-delete-char", videletechar, ZLE_KEEPSUFFIX
"vi-digit-or-beginning-of-line", vidigitorbeginningofline, 0
+"vi-down-case", vidowncase, ZLE_LASTCOL | ZLE_VIOPER
"vi-down-line-or-history", vidownlineorhistory, ZLE_LINEMOVE
"vi-end-of-line", viendofline, ZLE_LASTCOL
"vi-fetch-history", vifetchhistory, ZLE_LINEMOVE
@@ -188,6 +189,7 @@
"vi-swap-case", viswapcase, ZLE_LASTCOL
"vi-undo-change", viundochange, ZLE_KEEPSUFFIX
"vi-unindent", viunindent, ZLE_LASTCOL | ZLE_VIOPER
+"vi-up-case", viupcase, ZLE_LASTCOL | ZLE_VIOPER
"vi-up-line-or-history", viuplineorhistory, ZLE_LINEMOVE
"vi-yank", viyank, ZLE_LASTCOL | ZLE_VIOPER
"vi-yank-eol", viyankeol, 0
diff --git a/Src/Zle/textobjects.c b/Src/Zle/textobjects.c
index 9b3277a97..3db0781ff 100644
--- a/Src/Zle/textobjects.c
+++ b/Src/Zle/textobjects.c
@@ -1,5 +1,5 @@
/*
- * textobjects.c - ZLE module implementing Vim style text objects
+ * textobjects.c - ZLE widgets implementing Vim style text objects
*
* This file is part of zsh, the Z shell.
*
@@ -54,11 +54,7 @@ selectword(UNUSED(char **args))
int sclass = viclass(zleline[zlecs]);
int doblanks = all && sclass;
- if (!invicmdmode()) {
- region_active = 1;
- mark = zlecs;
- }
- if (!region_active || zlecs == mark) {
+ if (!region_active || zlecs == mark || mark == -1) {
/* search back to first character of same class as the start position
* also stop at the beginning of the line */
mark = zlecs;
@@ -207,8 +203,12 @@ selectword(UNUSED(char **args))
/* Adjustment: vi operators don't include the cursor position, in insert
* or emacs mode the region also doesn't but for vi visual mode it is
* included. */
- if (zlecs && zlecs > mark && !virangeflag)
- DECCS();
+ if (!virangeflag) {
+ if (!invicmdmode())
+ region_active = 1;
+ else if (zlecs && zlecs > mark)
+ DECCS();
+ }
return 0;
}
@@ -315,7 +315,7 @@ selectargument(UNUSED(char **args))
}
/* Adjustment: vi operators don't include the cursor position */
- if (!virangeflag)
+ if (!virangeflag && invicmdmode())
DECCS();
return 0;
diff --git a/Src/Zle/zle.h b/Src/Zle/zle.h
index e9b14281d..8f92e5611 100644
--- a/Src/Zle/zle.h
+++ b/Src/Zle/zle.h
@@ -284,6 +284,20 @@ struct change {
#define CH_NEXT (1<<0) /* next structure is also part of this change */
#define CH_PREV (1<<1) /* previous structure is also part of this change */
+/* vi change handling for vi-repeat-change */
+
+/*
+ * Examination of the code suggests vichgbuf is consistently tied
+ * to raw byte input, so it is left as a character array rather
+ * than turned into wide characters. In particular, when we replay
+ * it we use ungetbytes().
+ */
+struct vichange {
+ struct modifier mod; /* value of zmod associated with vi change */
+ char *buf; /* bytes for keys that make up the vi command */
+ int bufsz, bufptr; /* allocated and in use sizes of buf */
+};
+
/* known thingies */
#define Th(X) (&thingies[X])
diff --git a/Src/Zle/zle_keymap.c b/Src/Zle/zle_keymap.c
index 382eb8d41..04eb70675 100644
--- a/Src/Zle/zle_keymap.c
+++ b/Src/Zle/zle_keymap.c
@@ -135,7 +135,10 @@ mod_export HashTable keymapnamtab;
/**/
char *keybuf;
-static int keybuflen, keybufsz = 20;
+/**/
+int keybuflen;
+
+static int keybufsz = 20;
/* last command executed with execute-named-command */
@@ -1322,15 +1325,15 @@ default_bindings(void)
amap->first[i] = refthingy(t_undefinedkey);
/* safe fallback keymap:
- * 0-255 self-insert, except: *
- * '\n' accept-line *
- * '\r' accept-line */
+ * 0-255 .self-insert, except: *
+ * '\n' .accept-line *
+ * '\r' .accept-line */
for (i = 0; i < 256; i++)
- smap->first[i] = refthingy(t_selfinsert);
- unrefthingy(t_selfinsert);
- unrefthingy(t_selfinsert);
- smap->first['\n'] = refthingy(t_acceptline);
- smap->first['\r'] = refthingy(t_acceptline);
+ smap->first[i] = refthingy(t_Dselfinsert);
+ unrefthingy(t_Dselfinsert);
+ unrefthingy(t_Dselfinsert);
+ smap->first['\n'] = refthingy(t_Dacceptline);
+ smap->first['\r'] = refthingy(t_Dacceptline);
/* vt100 arrow keys are bound by default, for historical reasons. *
* Both standard and keypad modes are supported. */
@@ -1366,6 +1369,8 @@ default_bindings(void)
bindkey(vismap, "\33", refthingy(t_deactivateregion), NULL);
bindkey(vismap, "o", refthingy(t_exchangepointandmark), NULL);
bindkey(vismap, "p", refthingy(t_putreplaceselection), NULL);
+ bindkey(vismap, "u", refthingy(t_vidowncase), NULL);
+ bindkey(vismap, "U", refthingy(t_viupcase), NULL);
bindkey(vismap, "x", refthingy(t_videlete), NULL);
bindkey(vismap, "~", refthingy(t_vioperswapcase), NULL);
@@ -1374,8 +1379,12 @@ default_bindings(void)
bindkey(amap, "ge", refthingy(t_vibackwardwordend), NULL);
bindkey(amap, "gE", refthingy(t_vibackwardblankwordend), NULL);
bindkey(amap, "gg", refthingy(t_beginningofbufferorhistory), NULL);
+ bindkey(amap, "gu", refthingy(t_vidowncase), NULL);
+ bindkey(amap, "gU", refthingy(t_viupcase), NULL);
bindkey(amap, "g~", refthingy(t_vioperswapcase), NULL);
bindkey(amap, "g~~", NULL, "g~g~");
+ bindkey(amap, "guu", NULL, "gugu");
+ bindkey(amap, "gUU", NULL, "gUgU");
/* emacs mode: arrow keys */
add_cursor_key(emap, TCUPCURSOR, t_uplineorhistory, 'A');
@@ -1615,11 +1624,18 @@ getkeymapcmd(Keymap km, Thingy *funcp, char **strp)
else
lastchar = lastc;
if(lastlen != keybuflen) {
+ /*
+ * We want to keep only the first lastlen bytes of the key
+ * buffer in the key buffer that were marked as used by the key
+ * binding above, and make the rest available for input again.
+ * That rest (but not what we are keeping) needs to be
+ * unmetafied.
+ */
unmetafy(keybuf + lastlen, &keybuflen);
ungetbytes(keybuf+lastlen, keybuflen);
if(vichgflag)
- vichgbufptr -= keybuflen;
- keybuf[lastlen] = 0;
+ curvichg.bufptr -= keybuflen;
+ keybuf[keybuflen = lastlen] = 0;
}
*funcp = func;
*strp = str;
@@ -1672,7 +1688,7 @@ getkeybuf(int w)
mod_export void
ungetkeycmd(void)
{
- ungetbytes(keybuf, keybuflen);
+ ungetbytes_unmeta(keybuf, keybuflen);
}
/* read a command from the current keymap, with widgets */
@@ -1690,17 +1706,12 @@ getkeycmd(void)
if(!*seq)
return NULL;
if(!func) {
- int len;
- char *pb;
-
if (++hops == 20) {
zerr("string inserting another one too many times");
hops = 0;
return NULL;
}
- pb = unmetafy(ztrdup(str), &len);
- ungetbytes(pb, len);
- zfree(pb, strlen(str) + 1);
+ ungetbytes_unmeta(str, strlen(str));
goto sentstring;
}
if (func == Th(z_executenamedcmd) && !statusline) {
diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c
index 6e2bfded8..15ea79643 100644
--- a/Src/Zle/zle_main.c
+++ b/Src/Zle/zle_main.c
@@ -357,6 +357,21 @@ ungetbytes(char *s, int len)
ungetbyte(*--s);
}
+/**/
+void
+ungetbytes_unmeta(char *s, int len)
+{
+ s += len;
+ while (len--) {
+ if (len && s[-2] == Meta) {
+ ungetbyte(*--s ^ 32);
+ len--;
+ s--;
+ } else
+ ungetbyte(*--s);
+ }
+}
+
#if defined(pyr) && defined(HAVE_SELECT)
static int
breakread(int fd, char *buf, int n)
@@ -456,7 +471,7 @@ calc_timeout(struct ztmout *tmoutp, long do_keytmout)
tfdat = (Timedfn)getdata(tfnode);
diff = tfdat->when - time(NULL);
- if (diff < 0) {
+ if (diff <= 0) {
/* Already due; call it and rescan. */
tfdat->func();
continue;
@@ -909,13 +924,13 @@ getbyte(long do_keytmout, int *timeout)
ret = STOUC(cc);
}
/*
- * vichgbuf is raw bytes, not wide characters, so is dealt
+ * curvichg.buf is raw bytes, not wide characters, so is dealt
* with here.
*/
if (vichgflag) {
- if (vichgbufptr == vichgbufsz)
- vichgbuf = realloc(vichgbuf, vichgbufsz *= 2);
- vichgbuf[vichgbufptr++] = ret;
+ if (curvichg.bufptr == curvichg.bufsz)
+ curvichg.buf = realloc(curvichg.buf, curvichg.bufsz *= 2);
+ curvichg.buf[curvichg.bufptr++] = ret;
}
errno = old_errno;
return lastchar = ret;
@@ -1026,28 +1041,43 @@ getrestchar(int inchar, char *outstr, int *outcount)
#endif
/**/
-void redrawhook(void)
+void
+redrawhook(void)
{
Thingy initthingy;
if ((initthingy = rthingy_nocreate("zle-line-pre-redraw"))) {
+ /* Duplicating most of zlecallhook() to save additional state */
+ int saverrflag = errflag, savretflag = retflag;
int lastcmd_prev = lastcmd;
int old_incompfunc = incompfunc;
char *args[2];
Thingy lbindk_save = lbindk, bindk_save = bindk;
+
refthingy(lbindk_save);
refthingy(bindk_save);
args[0] = initthingy->nam;
args[1] = NULL;
+
+ /* The generic redraw hook cannot be a completion function, so
+ * temporarily reset state for special variable handling etc.
+ */
incompfunc = 0;
- execzlefunc(initthingy, args, 0);
+ execzlefunc(initthingy, args, 1);
incompfunc = old_incompfunc;
+
+ /* Restore errflag and retflag as zlecallhook() does */
+ errflag = saverrflag | (errflag & ERRFLAG_INT);
+ retflag = savretflag;
+
unrefthingy(initthingy);
unrefthingy(lbindk);
unrefthingy(bindk);
lbindk = lbindk_save;
bindk = bindk_save;
+
/* we can't set ZLE_NOTCOMMAND since it's not a legit widget, so
- * restore lastcmd manually so that we don't mess up the global state */
+ * restore lastcmd manually so that we don't mess up the global state
+ */
lastcmd = lastcmd_prev;
}
}
@@ -1144,11 +1174,19 @@ zlecore(void)
}
- region_active = 0;
popheap();
}
-/* Read a line. It is returned metafied. */
+/* Read a line. It is returned metafied.
+ *
+ * Parameters:
+ * - lp: left prompt, e.g., $PS1
+ * - rp: right prompt, e.g., $RPS1
+ * - flags: ZLRF_* flags (I think), see zlereadflags
+ * - context: ZLCON_* flags (I think), see zlecontext
+ * - init: "zle-line-init"
+ * - finish: "zle-line-finish"
+ */
/**/
char *
@@ -1222,6 +1260,7 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish)
*zleline = ZWC('\0');
virangeflag = lastcmd = done = zlecs = zlell = mark = yankb = yanke = 0;
vichgflag = 0;
+ viinrepeat = 0;
viinsbegin = 0;
statusline = NULL;
selectkeymap("main", 1);
@@ -1277,6 +1316,7 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish)
lastcol = -1;
initmodifier(&zmod);
prefixflag = 0;
+ region_active = 0;
zrefresh();
@@ -1284,6 +1324,9 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish)
zlecallhook(init, NULL);
+ if (zleline && *zleline)
+ redrawhook();
+
if ((bracket = getaparam("zle_bracketed_paste")) && arrlen(bracket) == 2)
fputs(*bracket, shout);
@@ -1326,6 +1369,16 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish)
return s;
}
+/**/
+static int
+execimmortal(Thingy func, char **args)
+{
+ Thingy immortal = rthingy_nocreate(dyncat(".", func->nam));
+ if (immortal)
+ return execzlefunc(immortal, args, 0);
+ return 1;
+}
+
/*
* Execute a widget. The third argument indicates that the global
* variable bindk should be set temporarily so that WIDGET etc.
@@ -1337,6 +1390,8 @@ int
execzlefunc(Thingy func, char **args, int set_bindk)
{
int r = 0, ret = 0, remetafy = 0;
+ int nestedvichg = vichgflag;
+ int isrepeat = (viinrepeat == 3);
Widget w;
Thingy save_bindk = bindk;
@@ -1346,8 +1401,10 @@ execzlefunc(Thingy func, char **args, int set_bindk)
unmetafy_line();
remetafy = 1;
}
+ if (isrepeat)
+ viinrepeat = 2;
- if(func->flags & DISABLED) {
+ if (func->flags & DISABLED) {
/* this thingy is not the name of a widget */
char *nm = nicedup(func->nam, 0);
char *msg = tricat("No such widget `", nm, "'");
@@ -1355,7 +1412,7 @@ execzlefunc(Thingy func, char **args, int set_bindk)
zsfree(nm);
showmsg(msg);
zsfree(msg);
- ret = 1;
+ ret = execimmortal(func, args);
} else if((w = func->widget)->flags & (WIDGET_INT|WIDGET_NCOMP)) {
int wflags = w->flags;
@@ -1419,7 +1476,7 @@ execzlefunc(Thingy func, char **args, int set_bindk)
zsfree(nm);
showmsg(msg);
zsfree(msg);
- ret = 1;
+ ret = execimmortal(func, args);
} else {
int osc = sfcontext, osi = movefd(0);
int oxt = isset(XTRACE);
@@ -1441,6 +1498,12 @@ execzlefunc(Thingy func, char **args, int set_bindk)
opts[XTRACE] = oxt;
sfcontext = osc;
endparamscope();
+ if (errflag == ERRFLAG_ERROR) {
+ int saverr = errflag;
+ errflag &= ~ERRFLAG_ERROR;
+ if ((ret = execimmortal(func, args)) != 0)
+ errflag |= saverr;
+ }
lastcmd = w->flags & ~(WIDGET_INUSE|WIDGET_FREE);
if (inuse) {
w->flags &= WIDGET_INUSE|WIDGET_FREE;
@@ -1469,6 +1532,25 @@ execzlefunc(Thingy func, char **args, int set_bindk)
CCRIGHT();
if (remetafy)
metafy_line();
+
+ /* if this widget constituted the vi change, end it */
+ if (vichgflag == 2 && !nestedvichg) {
+ if (invicmdmode()) {
+ if (ret) {
+ free(curvichg.buf);
+ } else {
+ if (lastvichg.buf)
+ free(lastvichg.buf);
+ lastvichg = curvichg;
+ }
+ vichgflag = 0;
+ curvichg.buf = NULL;
+ } else
+ vichgflag = 1; /* vi change continues while in insert mode */
+ }
+ if (isrepeat)
+ viinrepeat = !invicmdmode();
+
return ret;
}
@@ -1604,6 +1686,7 @@ bin_vared(char *name, char **args, Options ops, UNUSED(int func))
return 1;
} else if (v) {
if (*s) {
+ unqueue_signals();
zwarnnam(name, "not an identifier: `%s'", args[0]);
return 1;
}
@@ -1840,11 +1923,17 @@ int
recursiveedit(UNUSED(char **args))
{
int locerror;
+ int q = queue_signal_level();
+
+ /* zlecore() expects to be entered with signal queue disabled */
+ dont_queue_signals();
redrawhook();
zrefresh();
zlecore();
+ restore_queue_signals(q);
+
locerror = errflag ? 1 : 0;
errflag = done = eofsent = 0;
@@ -1856,6 +1945,7 @@ void
reexpandprompt(void)
{
static int reexpanding;
+ static int looping;
if (!reexpanding++) {
/*
@@ -1866,15 +1956,33 @@ reexpandprompt(void)
int local_lastval = lastval;
lastval = pre_zle_status;
- free(lpromptbuf);
- lpromptbuf = promptexpand(raw_lp ? *raw_lp : NULL, 1, NULL, NULL,
- &pmpt_attr);
- rpmpt_attr = pmpt_attr;
- free(rpromptbuf);
- rpromptbuf = promptexpand(raw_rp ? *raw_rp : NULL, 1, NULL, NULL,
- &rpmpt_attr);
+ do {
+ /* A new SIGWINCH may arrive while in promptexpand(), causing
+ * looping to increment. This only happens when a command
+ * substitution is used in a PROMPT_SUBST prompt, but
+ * nevertheless keep trying until we see no more changes.
+ */
+ char *new_lprompt, *new_rprompt;
+ looping = reexpanding;
+
+ new_lprompt = promptexpand(raw_lp ? *raw_lp : NULL, 1, NULL, NULL,
+ &pmpt_attr);
+ free(lpromptbuf);
+ lpromptbuf = new_lprompt;
+
+ if (looping != reexpanding)
+ continue;
+
+ rpmpt_attr = pmpt_attr;
+ new_rprompt = promptexpand(raw_rp ? *raw_rp : NULL, 1, NULL, NULL,
+ &rpmpt_attr);
+ free(rpromptbuf);
+ rpromptbuf = new_rprompt;
+ } while (looping != reexpanding);
+
lastval = local_lastval;
- }
+ } else
+ looping = reexpanding;
reexpanding--;
}
@@ -2150,7 +2258,7 @@ finish_(UNUSED(Module m))
cleanup_keymaps();
deletehashtable(thingytab);
- zfree(vichgbuf, vichgbufsz);
+ zfree(lastvichg.buf, lastvichg.bufsz);
zfree(kungetbuf, kungetsz);
free_isrch_spots();
if (rdstrs)
diff --git a/Src/Zle/zle_misc.c b/Src/Zle/zle_misc.c
index 0483f758d..898b552de 100644
--- a/Src/Zle/zle_misc.c
+++ b/Src/Zle/zle_misc.c
@@ -597,7 +597,7 @@ static void pastebuf(Cutbuffer buf, int mult, int position)
zlecs += cc;
}
yanke = zlecs;
- if (zlecs)
+ if (zlecs && invicmdmode())
DECCS();
}
}
@@ -609,8 +609,10 @@ viputbefore(UNUSED(char **args))
int n = zmult;
startvichange(-1);
- if (n < 0 || zmod.flags & MOD_NULL)
+ if (n < 0)
return 1;
+ if (zmod.flags & MOD_NULL)
+ return 0;
if (zmod.flags & MOD_VIBUF)
kctbuf = &vibuf[zmod.vibuf];
else
@@ -630,8 +632,10 @@ viputafter(UNUSED(char **args))
int n = zmult;
startvichange(-1);
- if (n < 0 || zmod.flags & MOD_NULL)
+ if (n < 0)
return 1;
+ if (zmod.flags & MOD_NULL)
+ return 0;
if (zmod.flags & MOD_VIBUF)
kctbuf = &vibuf[zmod.vibuf];
else
@@ -780,7 +784,7 @@ bracketedpaste(char **args)
int n;
ZLE_STRING_T wpaste;
wpaste = stringaszleline((zmult == 1) ? pbuf :
- quotestring(pbuf, NULL, QT_SINGLE_OPTIONAL), 0, &n, NULL, NULL);
+ quotestring(pbuf, QT_SINGLE_OPTIONAL), 0, &n, NULL, NULL);
cuttext(wpaste, n, CUT_REPLACE);
if (!(zmod.flags & MOD_VIBUF)) {
kct = -1;
@@ -1497,7 +1501,7 @@ struct suffixset {
};
/* The list of suffix structures */
-struct suffixset *suffixlist;
+static struct suffixset *suffixlist;
/* Shell function to call to remove the suffix. */
diff --git a/Src/Zle/zle_params.c b/Src/Zle/zle_params.c
index b5bb288f1..1e4c5b832 100644
--- a/Src/Zle/zle_params.c
+++ b/Src/Zle/zle_params.c
@@ -103,9 +103,27 @@ static const struct gsu_integer yankend_gsu =
{ get_yankend, set_yankend, zleunsetfn };
static const struct gsu_integer yankactive_gsu =
{ get_yankactive, NULL, zleunsetfn };
+static const struct gsu_integer isearchmatchstart_gsu =
+{ get_isearchmatchstart, NULL, zleunsetfn };
+static const struct gsu_integer isearchmatchend_gsu =
+{ get_isearchmatchend, NULL, zleunsetfn };
+static const struct gsu_integer isearchmatchactive_gsu =
+{ get_isearchmatchactive, NULL, zleunsetfn };
+static const struct gsu_integer suffixstart_gsu =
+{ get_suffixstart, NULL, zleunsetfn };
+static const struct gsu_integer suffixend_gsu =
+{ get_suffixend, NULL, zleunsetfn };
+static const struct gsu_integer suffixactive_gsu =
+{ get_suffixactive, NULL, zleunsetfn };
static const struct gsu_array killring_gsu =
{ get_killring, set_killring, unset_killring };
+
+static const struct gsu_scalar register_gsu =
+{ strgetfn, set_register, unset_register };
+static const struct gsu_hash registers_gsu =
+{ hashgetfn, set_registers, zleunsetfn };
+
/* implementation is in zle_refresh.c */
static const struct gsu_array region_highlight_gsu =
{ get_region_highlight, set_region_highlight, unset_region_highlight };
@@ -152,6 +170,12 @@ static struct zleparam {
{ "YANK_START", PM_INTEGER, GSU(yankstart_gsu), NULL },
{ "YANK_END", PM_INTEGER, GSU(yankend_gsu), NULL },
{ "YANK_ACTIVE", PM_INTEGER | PM_READONLY, GSU(yankactive_gsu), NULL },
+ { "ISEARCHMATCH_START", PM_INTEGER, GSU(isearchmatchstart_gsu), NULL },
+ { "ISEARCHMATCH_END", PM_INTEGER, GSU(isearchmatchend_gsu), NULL },
+ { "ISEARCHMATCH_ACTIVE", PM_INTEGER | PM_READONLY, GSU(isearchmatchactive_gsu), NULL },
+ { "SUFFIX_START", PM_INTEGER, GSU(suffixstart_gsu), NULL },
+ { "SUFFIX_END", PM_INTEGER, GSU(suffixend_gsu), NULL },
+ { "SUFFIX_ACTIVE", PM_INTEGER | PM_READONLY, GSU(suffixactive_gsu), NULL },
{ "ZLE_STATE", PM_SCALAR | PM_READONLY, GSU(zle_state_gsu), NULL },
{ NULL, 0, NULL, NULL }
};
@@ -163,6 +187,7 @@ mod_export void
makezleparams(int ro)
{
struct zleparam *zp;
+ Param reg_param;
for(zp = zleparams; zp->name; zp++) {
Param pm = createparam(zp->name, (zp->type |PM_SPECIAL|PM_REMOVABLE|
@@ -188,6 +213,11 @@ makezleparams(int ro)
if ((zp->type & PM_UNSET) && (zmod.flags & (MOD_MULT|MOD_TMULT)))
pm->node.flags &= ~PM_UNSET;
}
+
+ reg_param = createspecialhash("registers", get_registers, &scan_registers,
+ PM_LOCAL|PM_REMOVABLE);
+ reg_param->gsu.h = &registers_gsu;
+ reg_param->level = locallevel + 1;
}
/* Special unset function for ZLE special parameters: act like the standard *
@@ -521,6 +551,48 @@ set_yankend(UNUSED(Param pm), zlong i)
}
/**/
+static zlong
+get_isearchmatchstart(UNUSED(Param pm))
+{
+ return isearch_startpos;
+}
+
+/**/
+static zlong
+get_isearchmatchend(UNUSED(Param pm))
+{
+ return isearch_endpos;
+}
+
+/**/
+static zlong
+get_isearchmatchactive(UNUSED(Param pm))
+{
+ return isearch_active;
+}
+
+/**/
+static zlong
+get_suffixstart(UNUSED(Param pm))
+{
+ return zlecs - suffixlen;
+}
+
+/**/
+static zlong
+get_suffixend(UNUSED(Param pm))
+{
+ return zlecs;
+}
+
+/**/
+static zlong
+get_suffixactive(UNUSED(Param pm))
+{
+ return suffixlen;
+}
+
+/**/
static char *
get_cutbuffer(UNUSED(Param pm))
{
@@ -652,6 +724,111 @@ unset_killring(Param pm, int exp)
}
}
+/**/
+static void
+set_register(Param pm, char *value)
+{
+ int n = 0;
+ int offset = -1;
+ Cutbuffer vbuf;
+
+ if (!pm->node.nam || pm->node.nam[1])
+ ;
+ else if (*pm->node.nam >= '0' && *pm->node.nam <= '9')
+ offset = '0' - 26;
+ else if (*pm->node.nam >= 'a' && *pm->node.nam <= 'z')
+ offset = 'a';
+
+ if (offset == -1) {
+ zerr("invalid zle register: %s", pm->node.nam);
+ return;
+ }
+
+ vbuf = &vibuf[*pm->node.nam - offset];
+ if (*value)
+ vbuf->buf = stringaszleline(value, 0, &n, NULL, NULL);
+ vbuf->len = n;
+}
+
+/**/
+static void
+unset_register(Param pm, UNUSED(int exp))
+{
+ set_register(pm, "");
+}
+
+/**/
+static void
+scan_registers(UNUSED(HashTable ht), ScanFunc func, int flags)
+{
+ int i;
+ char ch;
+ struct param pm;
+
+ memset((void *)&pm, 0, sizeof(struct param));
+ pm.node.flags = PM_SCALAR | PM_READONLY;
+ pm.gsu.s = &nullsetscalar_gsu;
+
+ for (i = 0, ch = 'a'; i < 36; i++) {
+ pm.node.nam = zhalloc(2);
+ *pm.node.nam = ch;
+ pm.node.nam[1] = '\0';
+ pm.u.str = zlelineasstring(vibuf[i].buf, vibuf[i].len, 0, NULL, NULL, 1);
+ func(&pm.node, flags);
+ if (ch++ == 'z')
+ ch = '0';
+ }
+}
+
+/**/
+static HashNode
+get_registers(UNUSED(HashTable ht), const char *name)
+{
+ Param pm = (Param) hcalloc(sizeof(struct param));
+ int vbuf = -1;
+ pm->node.nam = dupstring(name);
+ pm->node.flags = PM_SCALAR;
+ pm->gsu.s = &register_gsu;
+
+ if (name[1])
+ ;
+ else if (*name >= '0' && *name <= '9')
+ vbuf = *name - '0' + 26;
+ else if (*name >= 'a' && *name <= 'z')
+ vbuf = *name - 'a';
+
+ if (vbuf == -1) {
+ pm->u.str = dupstring("");
+ pm->node.flags |= (PM_UNSET|PM_SPECIAL);
+ } else
+ pm->u.str = zlelineasstring(vibuf[vbuf].buf, vibuf[vbuf].len, 0, NULL, NULL, 1);
+
+ return &pm->node;
+}
+
+/**/
+static void
+set_registers(UNUSED(Param pm), HashTable ht)
+{
+ int i;
+ HashNode hn;
+
+ if (!ht)
+ return;
+
+ for (i = 0; i < ht->hsize; i++)
+ for (hn = ht->nodes[i]; hn; hn = hn->next) {
+ struct value v;
+ v.isarr = v.flags = v.start = 0;
+ v.end = -1;
+ v.arr = NULL;
+ v.pm = (Param) hn;
+
+ set_register(v.pm, getstrvalue(&v));
+ }
+ deleteparamtable(ht);
+}
+
static void
set_prepost(ZLE_STRING_T *textvar, int *lenvar, char *x)
{
diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c
index 3d2471e27..8d173cda1 100644
--- a/Src/Zle/zle_refresh.c
+++ b/Src/Zle/zle_refresh.c
@@ -946,7 +946,7 @@ addmultiword(REFRESH_ELEMENT *base, ZLE_STRING_T tptr, int ichars)
/*
* Swap the old and new video buffers, plus any associated multiword
- * buffers. The new buffer becomes the old one; the new new buffer
+ * buffers. The new buffer becomes the old one; the new buffer
* will be filled with the command line next time.
*/
static void
@@ -1143,8 +1143,7 @@ zrefresh(void)
tsetcap(TCALLATTRSOFF, 0);
tsetcap(TCSTANDOUTEND, 0);
tsetcap(TCUNDERLINEEND, 0);
- /* cheat on attribute unset */
- txtunset(TXTBOLDFACE|TXTSTANDOUT|TXTUNDERLINE);
+ txtattrmask = 0;
if (trashedzle && !clearflag)
reexpandprompt();
@@ -2424,6 +2423,7 @@ clearscreen(UNUSED(char **args))
tcoutclear(TCCLEARSCREEN);
resetneeded = 1;
clearflag = 0;
+ reexpandprompt();
return 0;
}
@@ -2434,8 +2434,8 @@ redisplay(UNUSED(char **args))
moveto(0, 0);
zputc(&zr_cr); /* extra care */
tc_upcurs(lprompth - 1);
- resetneeded = 1;
- clearflag = 0;
+ resetneeded = !showinglist;
+ clearflag = showinglist;
return 0;
}
diff --git a/Src/Zle/zle_thingy.c b/Src/Zle/zle_thingy.c
index 21495b6f2..c7092854a 100644
--- a/Src/Zle/zle_thingy.c
+++ b/Src/Zle/zle_thingy.c
@@ -269,7 +269,7 @@ freewidget(Widget w)
zfree(w, sizeof(*w));
}
-/* Add am internal widget provided by a module. The name given is the *
+/* Add an internal widget provided by a module. The name given is the *
* canonical one, which must not begin with a dot. The widget is first *
* bound to the dotted canonical name; if that name is already taken by *
* an internal widget, failure is indicated. The same widget is then *
@@ -678,7 +678,16 @@ bin_zle_flags(char *name, char **args, UNUSED(Options ops), UNUSED(char func))
else if (!strcmp(*flag, "keepsuffix"))
w->flags |= ZLE_KEEPSUFFIX;
*/
- else {
+ else if (!strcmp(*flag, "vichange")) {
+ if (invicmdmode()) {
+ startvichange(-1);
+ if (zmod.flags & (MOD_MULT|MOD_TMULT)) {
+ Param pm = (Param) paramtab->getnode(paramtab, "NUMERIC");
+ if (pm && pm->node.flags & PM_SPECIAL)
+ pm->node.flags &= ~PM_UNSET;
+ }
+ }
+ } else {
zwarnnam(name, "invalid flag `%s' given to zle -f", *flag);
ret = 1;
}
@@ -756,6 +765,10 @@ bin_zle_call(char *name, char **args, UNUSED(Options ops), UNUSED(char func))
}
t = rthingy(wname);
+ /* for internal widgets we set bindk except for when getting
+ * a vi range to detect a repeated key */
+ setbindk = setbindk ||
+ (t->widget && (t->widget->flags & (WIDGET_INT | ZLE_VIOPER)) == WIDGET_INT);
ret = execzlefunc(t, args, setbindk);
unrefthingy(t);
if (saveflag)
diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c
index cc4b7d673..3d8679119 100644
--- a/Src/Zle/zle_tricky.c
+++ b/Src/Zle/zle_tricky.c
@@ -100,8 +100,7 @@ mod_export int usemenu, useglob;
/**/
mod_export int wouldinstab;
-/* != 0 if we are in the middle of a menu completion. May be == 2 to force *
- * menu completion even if using different widgets. */
+/* != 0 if we are in the middle of a menu completion. */
/**/
mod_export int menucmp;
@@ -425,8 +424,8 @@ mod_export int instring, inbackt;
* This uses the instring variable above.
*/
-#define quotename(s, e) \
-quotestring(s, e, instring == QT_NONE ? QT_BACKSLASH : instring)
+#define quotename(s) \
+quotestring(s, instring == QT_NONE ? QT_BACKSLASH : instring)
/* Check if the given string is the name of a parameter and if this *
* parameter is one worth expanding. */
@@ -710,7 +709,8 @@ docomplete(int lst)
for (t0 = cmdnamtab->hsize - 1; t0 >= 0; t0--)
for (hn = cmdnamtab->nodes[t0]; hn;
hn = hn->next) {
- if (strpfx(q, hn->nam) && findcmd(hn->nam, 0))
+ if (strpfx(q, hn->nam) &&
+ findcmd(hn->nam, 0, 0))
n++;
if (n == 2)
break;
@@ -1162,6 +1162,7 @@ get_comp_string(void)
inpush(dupstrspace(linptr), 0, NULL);
strinbeg(0);
wordpos = cp = rd = ins = oins = linarr = parct = ia = redirpos = 0;
+ we = wb = zlemetacs;
tt0 = NULLTOK;
/* This loop is possibly the wrong way to do this. It goes through *
@@ -1239,6 +1240,20 @@ get_comp_string(void)
/* Record if we haven't had the command word yet */
if (wordpos == redirpos)
redirpos++;
+ if (zlemetacs < (zlemetall - inbufct) &&
+ zlemetacs >= wordbeg && wb == we) {
+ /* Cursor is in the middle of a redirection, treat as a word */
+ we = zlemetall - (inbufct + addedx);
+ if (addedx && we > wb) {
+ /* Assume we are in {param}> form, wb points at "{" */
+ wb++;
+ /* Should complete parameter names here */
+ } else {
+ /* In "2>" form, zlemetacs points at "2" */
+ wb = zlemetacs;
+ /* Should insert a space under cursor here */
+ }
+ }
}
if (tok == DINPAR)
tokstr = NULL;
@@ -1290,8 +1305,12 @@ get_comp_string(void)
zsfree(cmdstr);
cmdstr = ztrdup(tokstr);
cmdtok = tok;
- /* If everything before is a redirection, don't reset the index */
- if (wordpos != redirpos)
+ /*
+ * If everything before is a redirection, or anything
+ * complicated enough that we've seen the word the
+ * cursor is on, don't reset the index.
+ */
+ if (wordpos != redirpos && clwpos == -1)
wordpos = redirpos = 0;
} else if (tok == SEPER) {
/*
@@ -1399,9 +1418,17 @@ get_comp_string(void)
/* If this is the word the cursor is in and we added a `x', *
* remove it. */
if (clwpos == wordpos++ && addedx) {
+ int chuck_at, word_diff;
zlemetacs_qsub = zlemetacs - qsub;
- chuck(&clwords[wordpos - 1][((zlemetacs_qsub - wb) >= sl) ?
- (sl - 1) : (zlemetacs_qsub - wb)]);
+ word_diff = zlemetacs_qsub - wb;
+ /* Ensure we chuck within the word... */
+ if (word_diff >= sl)
+ chuck_at = sl -1;
+ else if (word_diff < 0)
+ chuck_at = 0;
+ else
+ chuck_at = word_diff;
+ chuck(&clwords[wordpos - 1][chuck_at]);
}
} while (tok != LEXERR && tok != ENDINPUT &&
(tok != SEPER || (lexflags && tt0 == NULLTOK)));
@@ -1449,7 +1476,9 @@ get_comp_string(void)
t0 = STRING;
} else if (t0 == STRING || t0 == TYPESET) {
/* We found a simple string. */
- s = ztrdup(clwords[clwpos]);
+ s = clwords[clwpos];
+ DPUTS(!s, "Completion word has disappeared!");
+ s = ztrdup(s ? s : "");
} else if (t0 == ENVSTRING) {
char sav;
/* The cursor was inside a parameter assignment. */
@@ -1850,8 +1879,12 @@ get_comp_string(void)
ocs = zlemetacs;
zlemetacs = i;
foredel(skipchars, CUT_RAW);
- if ((zlemetacs = ocs) > --i)
+ if ((zlemetacs = ocs) > --i) {
zlemetacs -= skipchars;
+ /* do not skip past the beginning of the word */
+ if (wb > zlemetacs)
+ zlemetacs = wb;
+ }
we -= skipchars;
}
} else {
@@ -1862,6 +1895,9 @@ get_comp_string(void)
zlemetacs = we - skipchars;
else
zlemetacs = ocs;
+ /* do not skip past the beginning of the word */
+ if (wb > zlemetacs)
+ zlemetacs = wb;
we -= skipchars;
}
/* we need to get rid of all the quotation bits... */
@@ -1983,11 +2019,11 @@ get_comp_string(void)
new->next = NULL;
new->str = dupstrpfx(bbeg, len);
- new->str = ztrdup(quotename(new->str, NULL));
+ new->str = ztrdup(quotename(new->str));
untokenize(new->str);
new->pos = begi;
*dbeg = '\0';
- new->qpos = strlen(quotename(predup, NULL));
+ new->qpos = strlen(quotename(predup));
*dbeg = '{';
i -= len;
boffs -= len;
@@ -2046,11 +2082,11 @@ get_comp_string(void)
lastbrbeg = new;
new->str = dupstrpfx(bbeg, len);
- new->str = ztrdup(quotename(new->str, NULL));
+ new->str = ztrdup(quotename(new->str));
untokenize(new->str);
new->pos = begi;
*dbeg = '\0';
- new->qpos = strlen(quotename(predup, NULL));
+ new->qpos = strlen(quotename(predup));
*dbeg = '{';
i -= len;
boffs -= len;
@@ -2096,7 +2132,7 @@ get_comp_string(void)
brend = new;
new->str = dupstrpfx(bbeg, len);
- new->str = ztrdup(quotename(new->str, NULL));
+ new->str = ztrdup(quotename(new->str));
untokenize(new->str);
new->pos = dp - predup - len + 1;
new->qpos = len;
@@ -2125,11 +2161,11 @@ get_comp_string(void)
lastbrbeg = new;
new->str = dupstrpfx(bbeg, len);
- new->str = ztrdup(quotename(new->str, NULL));
+ new->str = ztrdup(quotename(new->str));
untokenize(new->str);
new->pos = begi;
*dbeg = '\0';
- new->qpos = strlen(quotename(predup, NULL));
+ new->qpos = strlen(quotename(predup));
*dbeg = '{';
boffs -= len;
memmove(dbeg, dbeg + len, 1+strlen(dbeg+len));
@@ -2144,7 +2180,7 @@ get_comp_string(void)
p = bp->pos;
l = bp->qpos;
bp->pos = strlen(predup + p + l);
- bp->qpos = strlen(quotename(predup + p + l, NULL));
+ bp->qpos = strlen(quotename(predup + p + l));
memmove(predup + p, predup + p + l, 1+bp->pos);
}
}
@@ -2267,7 +2303,7 @@ doexpansion(char *s, int lst, int olst, int explincmd)
foredel(we - wb, CUT_RAW);
while ((ss = (char *)ugetnode(vl))) {
ret = 0;
- ss = quotename(ss, NULL);
+ ss = quotename(ss);
untokenize(ss);
inststr(ss);
if (nonempty(vl) || !first) {
@@ -2976,7 +3012,7 @@ processcmd(UNUSED(char **args))
inststr(" ");
untokenize(s);
- inststr(quotename(s, NULL));
+ inststr(quotename(s));
zsfree(s);
done = 1;
@@ -3006,7 +3042,7 @@ expandcmdpath(UNUSED(char **args))
return 1;
}
- str = findcmd(s, 1);
+ str = findcmd(s, 1, 0);
zsfree(s);
if (!str)
return 1;
diff --git a/Src/Zle/zle_utils.c b/Src/Zle/zle_utils.c
index 6e9a98bde..c6df3d89c 100644
--- a/Src/Zle/zle_utils.c
+++ b/Src/Zle/zle_utils.c
@@ -587,7 +587,7 @@ struct zle_position {
};
/* LIFO stack of positions */
-struct zle_position *zle_positions;
+static struct zle_position *zle_positions;
/*
* Save positions including cursor, end-of-line and
@@ -1412,7 +1412,7 @@ zlong undo_changeno;
/* If positive, don't undo beyond this point */
-zlong undo_limitno;
+static zlong undo_limitno;
/**/
void
@@ -1589,9 +1589,14 @@ undo(char **args)
break;
if (prev->changeno <= undo_limitno && !*args)
return 1;
- if (!unapplychange(prev) && last_change >= 0)
- unapplychange(prev);
- curchange = prev;
+ if (!unapplychange(prev)) {
+ if (last_change >= 0) {
+ unapplychange(prev);
+ curchange = prev;
+ }
+ } else {
+ curchange = prev;
+ }
} while (last_change >= (zlong)0 || (curchange->flags & CH_PREV));
setlastline();
return 0;
@@ -1678,7 +1683,7 @@ viundochange(char **args)
/**/
int
-splitundo(char **args)
+splitundo(UNUSED(char **args))
{
if (vistartchange >= 0) {
mergeundo();
@@ -1699,6 +1704,7 @@ mergeundo(void)
current->flags |= CH_PREV;
current->prev->flags |= CH_NEXT;
}
+ vistartchange = -1;
}
/*
@@ -1720,6 +1726,8 @@ zlecallhook(char *name, char *arg)
if (!thingy)
return;
+ /* If anything here needs changing, see also redrawhook() */
+
saverrflag = errflag;
savretflag = retflag;
diff --git a/Src/Zle/zle_vi.c b/Src/Zle/zle_vi.c
index 86840bdd6..e0923db3e 100644
--- a/Src/Zle/zle_vi.c
+++ b/Src/Zle/zle_vi.c
@@ -45,61 +45,71 @@ int wordflag;
/**/
int vilinerange;
-/* last vi change buffer, for vi change repetition */
+/*
+ * lastvichg: last vi change buffer, for vi change repetition
+ * curvichg: current incomplete vi change
+ */
+
+/**/
+struct vichange lastvichg, curvichg;
+
+/*
+ * true whilst a vi change is active causing keys to be
+ * accumulated in curvichg.buf
+ * first set to 2 and when the initial widget finishes, reduced to 1 if
+ * in insert mode implying that the change continues until returning to
+ * normal mode
+ */
/**/
-int vichgbufsz, vichgbufptr, vichgflag;
+int vichgflag;
/*
- * Examination of the code suggests vichgbuf is consistently tied
- * to raw byte input, so it is left as a character array rather
- * than turned into wide characters. In particular, when we replay
- * it we use ungetbytes().
+ * analogous to vichgflag for a repeated change with the value following
+ * a similar pattern (is 3 until first repeated widget starts)
*/
+
/**/
-char *vichgbuf;
+int viinrepeat;
/* point where vi insert mode was last entered */
/**/
int viinsbegin;
-static struct modifier lastmod;
-static int inrepeat, vichgrepeat;
-
/**
* im: >= 0: is an insertmode
- * -1: skip setting insert mode
+ * -1: skip setting insert/overwrite mode
* -2: entering viins at start of editing from clean --- don't use
- * inrepeat or lastchar, synthesise an i to enter insert mode.
+ * inrepeat or keybuf, synthesise an entry to insert mode.
+ * Note that zmult is updated so this should be called before zmult is used.
*/
/**/
void
startvichange(int im)
{
- if (im != -1) {
- vichgflag = 1;
- if (im > -1)
- insmode = im;
- }
- if (inrepeat && im != -2) {
- zmod = lastmod;
- inrepeat = vichgflag = 0;
- vichgrepeat = 1;
- } else {
- lastmod = zmod;
- if (vichgbuf)
- free(vichgbuf);
- vichgbuf = (char *)zalloc(vichgbufsz = 16);
+ if (im > -1)
+ insmode = im;
+ if (viinrepeat && im != -2) {
+ zmod = lastvichg.mod;
+ vichgflag = 0;
+ } else if (!vichgflag) {
+ curvichg.mod = zmod;
+ if (curvichg.buf)
+ free(curvichg.buf);
+ curvichg.buf = (char *)zalloc(curvichg.bufsz = 16 + keybuflen);
if (im == -2) {
- vichgbuf[0] =
+ vichgflag = 1;
+ curvichg.buf[0] =
zlell ? (insmode ? (zlecs < zlell ? 'i' : 'a') : 'R') : 'o';
+ curvichg.buf[1] = '\0';
+ curvichg.bufptr = 1;
} else {
- vichgbuf[0] = lastchar;
+ vichgflag = 2;
+ strcpy(curvichg.buf, keybuf);
+ unmetafy(curvichg.buf, &curvichg.bufptr);
}
- vichgbufptr = 1;
- vichgrepeat = 0;
}
}
@@ -208,10 +218,13 @@ getvirange(int wf)
*/
if ((k2 == bindk) ? dovilinerange() : execzlefunc(k2, zlenoargs, 1))
ret = -1;
- if(vichgrepeat)
+ if (viinrepeat)
zmult = mult1;
- else
+ else {
zmult = mult1 * zmod.tmult;
+ if (vichgflag == 2)
+ curvichg.mod.mult = zmult;
+ }
} while(prefixflag && !ret);
wordflag = 0;
selectlocalmap(NULL);
@@ -255,7 +268,7 @@ getvirange(int wf)
}
/* visual selection mode needs to include additional position */
- if (visual == 1 && invicmdmode())
+ if (visual == 1 && pos < zlell && invicmdmode())
INCPOS(pos);
/* Was it a line-oriented move? If so, the command will have set *
@@ -383,7 +396,6 @@ videlete(UNUSED(char **args))
vifirstnonblank(zlenoargs);
}
}
- vichgflag = 0;
return ret;
}
@@ -391,9 +403,10 @@ videlete(UNUSED(char **args))
int
videletechar(char **args)
{
- int n = zmult;
+ int n;
startvichange(-1);
+ n = zmult;
/* handle negative argument */
if (n < 0) {
@@ -440,9 +453,10 @@ vichange(UNUSED(char **args))
int
visubstitute(UNUSED(char **args))
{
- int n = zmult;
+ int n;
startvichange(1);
+ n = zmult;
if (n < 0)
return 1;
/* it is an error to be on the end of line */
@@ -498,7 +512,6 @@ viyank(UNUSED(char **args))
cut(zlecs, c2 - zlecs, CUT_YANK);
ret = 0;
}
- vichgflag = 0;
/* cursor now at the start of the range yanked. For line mode
* restore the column position */
if (vilinerange && lastcol != -1) {
@@ -536,9 +549,10 @@ int
viyankwholeline(UNUSED(char **args))
{
int bol = findbol(), oldcs = zlecs;
- int n = zmult;
+ int n;
startvichange(-1);
+ n = zmult;
if (n < 1)
return 1;
while(n--) {
@@ -572,16 +586,17 @@ vireplace(UNUSED(char **args))
* a change, we always read the argument normally, even if the count *
* was bad. When recording a change for repeating, and a bad count is *
* given, we squash the repeat buffer to avoid repeating the partial *
- * command; we've lost the previous change, but that can't be avoided *
- * without a rewrite of the repeat code. */
+ * command. */
/**/
int
vireplacechars(UNUSED(char **args))
{
ZLE_INT_T ch;
- int n = zmult, fail = 0, newchars = 0;
+ int n, fail = 0, newchars = 0;
+ startvichange(1);
+ n = zmult;
if (n > 0) {
if (region_active) {
int a, b;
@@ -618,21 +633,15 @@ vireplacechars(UNUSED(char **args))
n = pos - zlecs;
}
}
- startvichange(1);
+
/* check argument range */
if (n < 1 || fail) {
- if(vichgrepeat)
+ if (viinrepeat)
vigetkey();
- if(vichgflag) {
- free(vichgbuf);
- vichgbuf = NULL;
- vichgflag = 0;
- }
return 1;
}
/* get key */
if((ch = vigetkey()) == ZLEEOF) {
- vichgflag = 0;
return 1;
}
/* do change */
@@ -659,7 +668,6 @@ vireplacechars(UNUSED(char **args))
zleline[zlecs++] = ch;
zlecs--;
}
- vichgflag = 0;
return 0;
}
@@ -670,7 +678,16 @@ vicmdmode(UNUSED(char **args))
if (invicmdmode() || selectkeymap("vicmd", 0))
return 1;
mergeundo();
- vichgflag = 0;
+ insmode = unset(OVERSTRIKE);
+ if (vichgflag == 1) {
+ vichgflag = 0;
+ if (lastvichg.buf)
+ free(lastvichg.buf);
+ lastvichg = curvichg;
+ curvichg.buf = NULL;
+ }
+ if (viinrepeat == 1)
+ viinrepeat = 0;
if (zlecs != findbol())
DECCS();
return 0;
@@ -725,7 +742,50 @@ vioperswapcase(UNUSED(char **args))
vifirstnonblank();
#endif
}
- vichgflag = 0;
+ return ret;
+}
+
+/**/
+int
+viupcase(UNUSED(char **args))
+{
+ int oldcs, c2, ret = 1;
+
+ /* get the range */
+ startvichange(1);
+ if ((c2 = getvirange(0)) != -1) {
+ oldcs = zlecs;
+ /* covert the case of all letters within range */
+ while (zlecs < c2) {
+ zleline[zlecs] = ZC_toupper(zleline[zlecs]);
+ INCCS();
+ }
+ /* go back to the first line of the range */
+ zlecs = oldcs;
+ ret = 0;
+ }
+ return ret;
+}
+
+/**/
+int
+vidowncase(UNUSED(char **args))
+{
+ int oldcs, c2, ret = 1;
+
+ /* get the range */
+ startvichange(1);
+ if ((c2 = getvirange(0)) != -1) {
+ oldcs = zlecs;
+ /* convert the case of all letters within range */
+ while (zlecs < c2) {
+ zleline[zlecs] = ZC_tolower(zleline[zlecs]);
+ INCCS();
+ }
+ /* go back to the first line of the range */
+ zlecs = oldcs;
+ ret = 0;
+ }
return ret;
}
@@ -734,21 +794,23 @@ int
virepeatchange(UNUSED(char **args))
{
/* make sure we have a change to repeat */
- if (!vichgbuf || vichgflag)
+ if (!lastvichg.buf || vichgflag || virangeflag)
return 1;
/* restore or update the saved count and buffer */
if (zmod.flags & MOD_MULT) {
- lastmod.mult = zmod.mult;
- lastmod.flags |= MOD_MULT;
+ lastvichg.mod.mult = zmod.mult;
+ lastvichg.mod.flags |= MOD_MULT;
}
if (zmod.flags & MOD_VIBUF) {
- lastmod.vibuf = zmod.vibuf;
- lastmod.flags = (lastmod.flags & ~MOD_VIAPP) |
+ lastvichg.mod.vibuf = zmod.vibuf;
+ lastvichg.mod.flags = (lastvichg.mod.flags & ~MOD_VIAPP) |
MOD_VIBUF | (zmod.flags & MOD_VIAPP);
- }
+ } else if (lastvichg.mod.flags & MOD_VIBUF &&
+ lastvichg.mod.vibuf >= 27 && lastvichg.mod.vibuf <= 34)
+ lastvichg.mod.vibuf++; /* for "1 to "8 advance to next buffer */
/* repeat the command */
- inrepeat = 1;
- ungetbytes(vichgbuf, vichgbufptr);
+ viinrepeat = 3;
+ ungetbytes(lastvichg.buf, lastvichg.bufptr);
return 0;
}
@@ -764,10 +826,8 @@ viindent(UNUSED(char **args))
region_active = 2;
/* get the range */
if ((c2 = getvirange(0)) == -1) {
- vichgflag = 0;
return 1;
}
- vichgflag = 0;
/* must be a line range */
if (!vilinerange) {
zlecs = oldcs;
@@ -802,10 +862,8 @@ viunindent(UNUSED(char **args))
region_active = 2;
/* get the range */
if ((c2 = getvirange(0)) == -1) {
- vichgflag = 0;
return 1;
}
- vichgflag = 0;
/* must be a line range */
if (!vilinerange) {
zlecs = oldcs;
@@ -828,12 +886,13 @@ viunindent(UNUSED(char **args))
int
vibackwarddeletechar(char **args)
{
- int n = zmult;
+ int n;
if (invicmdmode())
startvichange(-1);
/* handle negative argument */
+ n = zmult;
if (n < 0) {
int ret;
zmult = -n;
@@ -873,10 +932,11 @@ int
vijoin(UNUSED(char **args))
{
int x, pos;
- int n = zmult;
+ int n;
int visual = region_active;
startvichange(-1);
+ n = zmult;
if (n < 1)
return 1;
if (visual && zlecs > mark) {
@@ -915,9 +975,10 @@ vijoin(UNUSED(char **args))
int
viswapcase(UNUSED(char **args))
{
- int eol, n = zmult;
+ int eol, n;
startvichange(-1);
+ n = zmult;
if (n < 1)
return 1;
eol = findeol();
diff --git a/Src/Zle/zle_word.c b/Src/Zle/zle_word.c
index 2e6d75e86..e4a878eab 100644
--- a/Src/Zle/zle_word.c
+++ b/Src/Zle/zle_word.c
@@ -153,7 +153,7 @@ emacsforwardword(char **args)
/**/
int
-viforwardblankwordend(UNUSED(char **args))
+viforwardblankwordend(char **args)
{
int n = zmult;
@@ -678,46 +678,54 @@ killword(char **args)
int
transposewords(UNUSED(char **args))
{
- int p1, p2, p3, p4, len, x = zlecs, pos;
+ int p1, p2, p3, p4, pt, len, x = zlecs, pos;
ZLE_STRING_T temp, pp;
int n = zmult;
int neg = n < 0, ocs = zlecs;
if (neg)
n = -n;
- while (n--) {
- while (x != zlell && zleline[x] != ZWC('\n') && !ZC_iword(zleline[x]))
- INCPOS(x);
- if (x == zlell || zleline[x] == ZWC('\n')) {
- x = zlecs;
- while (x) {
- if (ZC_iword(zleline[x]))
- break;
- pos = x;
- DECPOS(pos);
- if (zleline[pos] == ZWC('\n'))
- break;
- x = pos;
- }
- if (!x)
- return 1;
+
+ while (x != zlell && zleline[x] != ZWC('\n') && !ZC_iword(zleline[x]))
+ INCPOS(x);
+
+ if (x == zlell || zleline[x] == ZWC('\n')) {
+ x = zlecs;
+ while (x) {
+ if (ZC_iword(zleline[x]))
+ break;
pos = x;
DECPOS(pos);
if (zleline[pos] == ZWC('\n'))
- return 1;
- }
- for (p4 = x; p4 != zlell && ZC_iword(zleline[p4]); INCPOS(p4))
- ;
- for (p3 = p4; p3; ) {
- pos = p3;
- DECPOS(pos);
- if (!ZC_iword(zleline[pos]))
break;
- p3 = pos;
+ x = pos;
}
- if (!p3)
+ if (!x)
return 1;
- for (p2 = p3; p2; ) {
+ pos = x;
+ DECPOS(pos);
+ if (zleline[pos] == ZWC('\n'))
+ return 1;
+ }
+
+ for (p4 = x; p4 != zlell && ZC_iword(zleline[p4]); INCPOS(p4))
+ ;
+
+ for (p3 = p4; p3; ) {
+ pos = p3;
+ DECPOS(pos);
+ if (!ZC_iword(zleline[pos]))
+ break;
+ p3 = pos;
+ }
+
+ if (!p3)
+ return 1;
+
+ p1 = p2 = pt = p3;
+
+ while (n--) {
+ for (p2 = pt; p2; ) {
pos = p2;
DECPOS(pos);
if (ZC_iword(zleline[pos]))
@@ -733,20 +741,24 @@ transposewords(UNUSED(char **args))
break;
p1 = pos;
}
- pp = temp = (ZLE_STRING_T)zhalloc((p4 - p1)*ZLE_CHAR_SIZE);
- len = p4 - p3;
- ZS_memcpy(pp, zleline + p3, len);
- pp += len;
- len = p3 - p2;
- ZS_memcpy(pp, zleline + p2, len);
- pp += len;
- ZS_memcpy(pp, zleline + p1, p2 - p1);
+ pt = p1;
+ }
- ZS_memcpy(zleline + p1, temp, p4 - p1);
+ pp = temp = (ZLE_STRING_T)zhalloc((p4 - p1)*ZLE_CHAR_SIZE);
+ len = p4 - p3;
+ ZS_memcpy(pp, zleline + p3, len);
+ pp += len;
+ len = p3 - p2;
+ ZS_memcpy(pp, zleline + p2, len);
+ pp += len;
+ ZS_memcpy(pp, zleline + p1, p2 - p1);
+
+ ZS_memcpy(zleline + p1, temp, p4 - p1);
- zlecs = p4;
- }
if (neg)
zlecs = ocs;
+ else
+ zlecs = p4;
+
return 0;
}