diff options
Diffstat (limited to 'Src/Zle')
-rw-r--r-- | Src/Zle/comp.h | 29 | ||||
-rw-r--r-- | Src/Zle/compcore.c | 64 | ||||
-rw-r--r-- | Src/Zle/compctl.c | 31 | ||||
-rw-r--r-- | Src/Zle/complete.c | 68 | ||||
-rw-r--r-- | Src/Zle/complist.c | 110 | ||||
-rw-r--r-- | Src/Zle/compmatch.c | 158 | ||||
-rw-r--r-- | Src/Zle/compresult.c | 5 | ||||
-rw-r--r-- | Src/Zle/computil.c | 77 | ||||
-rw-r--r-- | Src/Zle/iwidgets.list | 2 | ||||
-rw-r--r-- | Src/Zle/textobjects.c | 18 | ||||
-rw-r--r-- | Src/Zle/zle.h | 14 | ||||
-rw-r--r-- | Src/Zle/zle_keymap.c | 47 | ||||
-rw-r--r-- | Src/Zle/zle_main.c | 152 | ||||
-rw-r--r-- | Src/Zle/zle_misc.c | 14 | ||||
-rw-r--r-- | Src/Zle/zle_params.c | 177 | ||||
-rw-r--r-- | Src/Zle/zle_refresh.c | 10 | ||||
-rw-r--r-- | Src/Zle/zle_thingy.c | 17 | ||||
-rw-r--r-- | Src/Zle/zle_tricky.c | 80 | ||||
-rw-r--r-- | Src/Zle/zle_utils.c | 20 | ||||
-rw-r--r-- | Src/Zle/zle_vi.c | 195 | ||||
-rw-r--r-- | Src/Zle/zle_word.c | 92 |
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 = ®isters_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 = ®ister_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; } |