summaryrefslogtreecommitdiff
path: root/Src/Zle
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Zle')
-rw-r--r--Src/Zle/comp.h9
-rw-r--r--Src/Zle/compcore.c146
-rw-r--r--Src/Zle/complete.c23
-rw-r--r--Src/Zle/complist.c38
-rw-r--r--Src/Zle/compmatch.c15
-rw-r--r--Src/Zle/compresult.c15
-rw-r--r--Src/Zle/computil.c114
-rw-r--r--Src/Zle/zle.h4
-rw-r--r--Src/Zle/zle_hist.c9
-rw-r--r--Src/Zle/zle_keymap.c2
-rw-r--r--Src/Zle/zle_main.c8
-rw-r--r--Src/Zle/zle_misc.c9
-rw-r--r--Src/Zle/zle_move.c2
-rw-r--r--Src/Zle/zle_refresh.c64
-rw-r--r--Src/Zle/zle_thingy.c19
-rw-r--r--Src/Zle/zle_utils.c23
16 files changed, 370 insertions, 130 deletions
diff --git a/Src/Zle/comp.h b/Src/Zle/comp.h
index 2e3249b52..2ca779fe5 100644
--- a/Src/Zle/comp.h
+++ b/Src/Zle/comp.h
@@ -85,8 +85,8 @@ struct cmgroup {
#define CGF_NOSORT 1 /* don't sort this group */
#define CGF_LINES 2 /* these are to be printed on different lines */
#define CGF_HASDL 4 /* has display strings printed on separate lines */
-#define CGF_UNIQALL 8 /* remove all duplicates */
-#define CGF_UNIQCON 16 /* remove consecutive duplicates */
+#define CGF_UNIQALL 8 /* remove consecutive duplicates (if neither are set, */
+#define CGF_UNIQCON 16 /* don't deduplicate */ /* remove all dupes) */
#define CGF_PACKED 32 /* LIST_PACKED for this group */
#define CGF_ROWS 64 /* LIST_ROWS_FIRST for this group */
#define CGF_FILES 128 /* contains file names */
@@ -140,6 +140,7 @@ struct cmatch {
#define CMF_ALL (1<<13) /* a match representing all other matches */
#define CMF_DUMMY (1<<14) /* unselectable dummy match */
#define CMF_MORDER (1<<15) /* order by matches, not display strings */
+#define CMF_DELETE (1<<16) /* used for deduplication of unsorted matches, don't set */
/* Stuff for completion matcher control. */
@@ -299,7 +300,7 @@ struct menuinfo {
#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_UNIQALL 16 /* compadd -1: deduplicate consecutive only */
#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 */
@@ -329,7 +330,7 @@ struct cadata {
char *exp; /* explanation (-X) */
char *apar; /* array to store matches in (-A) */
char *opar; /* array to store originals in (-O) */
- char *dpar; /* array to delete non-matches in (-D) */
+ char **dpar; /* arrays to delete non-matches in (-D) */
char *disp; /* array with display lists (-d) */
char *mesg; /* message to show unconditionally (-x) */
int dummies; /* add that many dummy matches */
diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c
index 7e3badc57..fe3ea10fc 100644
--- a/Src/Zle/compcore.c
+++ b/Src/Zle/compcore.c
@@ -648,7 +648,7 @@ callcompfunc(char *s, char *fn)
if (compredirs)
freearray(compredirs);
if (rdstrs)
- compredirs = zlinklist2array(rdstrs);
+ compredirs = zlinklist2array(rdstrs, 1);
else
compredirs = (char **) zshcalloc(sizeof(char *));
@@ -821,6 +821,7 @@ callcompfunc(char *s, char *fn)
sfcontext = SFC_CWIDGET;
NEWHEAPS(compheap) {
LinkList largs = NULL;
+ int oxt = isset(XTRACE);
if (*cfargs) {
char **p = cfargs;
@@ -830,7 +831,9 @@ callcompfunc(char *s, char *fn)
while (*p)
addlinknode(largs, dupstring(*p++));
}
+ opts[XTRACE] = 0;
cfret = doshfunc(shfunc, largs, 1);
+ opts[XTRACE] = oxt;
} OLDHEAPS;
sfcontext = osc;
endparamscope();
@@ -1122,6 +1125,18 @@ check_param(char *s, int set, int test)
*
* TODO: passing s as a parameter while we get some mysterious
* offset "offs" into it via a global sucks badly.
+ *
+ * From ../lex.c we know:
+ * wb is the beginning position of the current word in the line
+ * we is the position of the end of the current word in the line
+ * From zle_tricky.c we know:
+ * offs is position within the word where we are completing
+ *
+ * So wb + offs is the current cursor position if COMPLETE_IN_WORD
+ * is set, otherwise it is the end of the word (same as we).
+ *
+ * Note below we are thus stepping backward from our completion
+ * position to find a '$' in the current word (if any).
*/
for (p = s + offs; ; p--) {
if (*p == String || *p == Qstring) {
@@ -1168,13 +1183,13 @@ check_param(char *s, int set, int test)
char *tb = b;
/* If this is a ${...}, see if we are before the '}'. */
- if (!skipparens(Inbrace, Outbrace, &tb))
+ if (!skipparens(Inbrace, Outbrace, &tb) && tb - s <= offs)
return NULL;
/* Ignore the possible (...) flags. */
b++, br++;
if ((qstring ? skipparens('(', ')', &b) :
- skipparens(Inpar, Outpar, &b)) > 0) {
+ skipparens(Inpar, Outpar, &b)) > 0 || b - s > offs) {
/*
* We are still within the parameter flags. There's no
* point trying to do anything clever here with
@@ -1922,7 +1937,7 @@ set_comp_sep(void)
mod_export void
set_list_array(char *name, LinkList l)
{
- setaparam(name, zlinklist2array(l));
+ setaparam(name, zlinklist2array(l, 1));
}
/* Get the words from a variable or a (list of words). */
@@ -2058,10 +2073,10 @@ 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 **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, bcp = 0, bcs = 0, bpadd = 0, bsadd = 0;
+ int dind, 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;
@@ -2069,7 +2084,7 @@ addmatches(Cadata dat, char **argv)
struct cmlist mst;
Cmlist oms = mstack;
Patprog cp = NULL, *pign = NULL;
- LinkList aparl = NULL, oparl = NULL, dparl = NULL;
+ LinkList aparl = NULL, oparl = NULL, *dparl = NULL;
Brinfo bp, bpl = brbeg, obpl, bsl = brend, obsl;
Heap oldheap;
@@ -2097,7 +2112,7 @@ addmatches(Cadata dat, char **argv)
curexpl->always = !!dat->mesg;
curexpl->count = curexpl->fcount = 0;
curexpl->str = dupstring(dat->mesg ? dat->mesg : dat->exp);
- if (dat->mesg)
+ if (dat->mesg && !dat->dpar && !dat->opar && !dat->apar)
addexpl(1);
} else
curexpl = NULL;
@@ -2163,11 +2178,24 @@ addmatches(Cadata dat, char **argv)
if (dat->opar)
oparl = newlinklist();
if (dat->dpar) {
- if (*(dat->dpar) == '(')
- dparr = NULL;
- else if ((dparr = get_user_var(dat->dpar)) && !*dparr)
- dparr = NULL;
- dparl = newlinklist();
+ int darr = 0, dparlen = arrlen(dat->dpar);
+ char **tail = dat->dpar + dparlen;
+
+ dparr = (char ***)hcalloc((1 + dparlen) * sizeof(char **));
+ dparl = (LinkList *)hcalloc((1 + dparlen) * sizeof(LinkList));
+ queue_signals();
+ while (darr < dparlen) {
+ if ((dparr[darr] = getaparam(dat->dpar[darr])) && *dparr[darr]) {
+ dparr[darr] = arrdup(dparr[darr]);
+ dparl[darr++] = newlinklist();
+ } else {
+ /* swap in the last -D argument if we didn't get a non-empty array */
+ dat->dpar[darr] = *--tail;
+ *tail = NULL;
+ --dparlen;
+ }
+ }
+ unqueue_signals();
}
/* Store the matcher in our stack of matchers. */
if (dat->match) {
@@ -2484,8 +2512,10 @@ addmatches(Cadata dat, char **argv)
}
if (!addit) {
compignored++;
- if (dparr && !*++dparr)
- dparr = NULL;
+ for (dind = 0; dparl && dparl[dind]; dind++) {
+ if (dparr[dind] && !*++dparr[dind])
+ dparr[dind] = NULL;
+ }
goto next_array;
}
}
@@ -2502,8 +2532,10 @@ addmatches(Cadata dat, char **argv)
!(dat->flags & CMF_FILE) ? 1 : 2) : 0),
&bpl, bcp, &bsl, bcs,
&isexact))) {
- if (dparr && !*++dparr)
- dparr = NULL;
+ for (dind = 0; dparl && dparl[dind]; dind++) {
+ if (dparr[dind] && !*++dparr[dind])
+ dparr[dind] = NULL;
+ }
goto next_array;
}
if (doadd) {
@@ -2530,10 +2562,14 @@ addmatches(Cadata dat, char **argv)
addlinknode(aparl, ms);
if (dat->opar)
addlinknode(oparl, s);
- if (dat->dpar && dparr) {
- addlinknode(dparl, *dparr);
- if (!*++dparr)
- dparr = NULL;
+ if (dat->dpar) {
+ for (dind = 0; dparl[dind]; dind++) {
+ if (dparr[dind]) {
+ addlinknode(dparl[dind], *dparr[dind]);
+ if (!*++dparr[dind])
+ dparr[dind] = NULL;
+ }
+ }
}
free_cline(lc);
}
@@ -2561,8 +2597,10 @@ addmatches(Cadata dat, char **argv)
set_list_array(dat->apar, aparl);
if (dat->opar)
set_list_array(dat->opar, oparl);
- if (dat->dpar)
- set_list_array(dat->dpar, dparl);
+ if (dat->dpar) {
+ for (dind = 0; dparl[dind]; dind++)
+ set_list_array(dat->dpar[dind], dparl[dind]);
+ }
if (dat->exp)
addexpl(0);
if (!hasallmatch && (dat->aflags & CAF_ALL)) {
@@ -3209,17 +3247,20 @@ makearray(LinkList l, int type, int flags, int *np, int *nlp, int *llp)
}
*cp = NULL;
}
- } else {
+ } else if (n > 0) {
if (!(flags & CGF_NOSORT)) {
/* Now sort the array (it contains matches). */
matchorder = flags;
qsort((void *) rp, n, sizeof(Cmatch),
(int (*) _((const void *, const void *)))matchcmp);
+ /* since the matches are sorted and the default is to remove
+ * all duplicates, -1 (remove only consecutive dupes) is a no-op,
+ * so this condition only checks for -2 */
if (!(flags & CGF_UNIQCON)) {
int dup;
- /* And delete the ones that occur more than once. */
+ /* we did not pass -2 so go ahead and remove those dupes */
for (ap = cp = rp; *ap; ap++) {
*cp++ = *ap;
for (bp = ap; bp[1] && matcheq(*ap, bp[1]); bp++, n--);
@@ -3241,30 +3282,47 @@ makearray(LinkList l, int type, int flags, int *np, int *nlp, int *llp)
if ((*ap)->flags & (CMF_NOLIST | CMF_MULT))
nl++;
}
+ /* used -O nosort or -V, don't sort */
} else {
+ /* didn't use -1 or -2, so remove all duplicates (efficient) */
if (!(flags & CGF_UNIQALL) && !(flags & CGF_UNIQCON)) {
- int dup;
-
- for (ap = rp; *ap; ap++) {
- for (bp = cp = ap + 1; *bp; bp++) {
- if (!matcheq(*ap, *bp))
- *cp++ = *bp;
- else
+ int dup, del = 0;
+
+ /* To avoid O(n^2) here, sort a copy of the list, then remove marked elements */
+ matchorder = flags;
+ Cmatch *sp, *asp;
+ sp = (Cmatch *) zhalloc((n + 1) * sizeof(Cmatch));
+ memcpy(sp, rp, (n + 1) * sizeof(Cmatch));
+ qsort((void *) sp, n, sizeof(Cmatch),
+ (int (*) _((const void *, const void *)))matchcmp);
+ for (asp = sp + 1; *asp; asp++) {
+ Cmatch *ap = asp - 1, *bp = asp;
+ if (matcheq(*ap, *bp)) {
+ bp[0]->flags = CMF_DELETE;
+ del = 1;
+ } else if (!ap[0]->disp) {
+ /* Mark those, that would show the same string in the list. */
+ for (dup = 0; bp[0] && !(bp[0])->disp &&
+ !strcmp((*ap)->str, (bp[0])->str); bp = ++sp) {
+ (bp[0])->flags |= CMF_MULT;
+ dup = 1;
+ }
+ if (dup)
+ (*ap)->flags |= CMF_FMULT;
+ }
+ }
+ if (del) {
+ int n_orig = n;
+ for (bp = rp, ap = rp; bp < rp + n_orig; ap++, bp++) {
+ while (bp[0]->flags & CMF_DELETE) {
+ bp++;
n--;
+ }
+ *ap = *bp;
}
- *cp = NULL;
- if (!(*ap)->disp) {
- for (dup = 0, bp = ap + 1; *bp; bp++)
- if (!(*bp)->disp &&
- !((*bp)->flags & CMF_MULT) &&
- !strcmp((*ap)->str, (*bp)->str)) {
- (*bp)->flags |= CMF_MULT;
- dup = 1;
- }
- if (dup)
- (*ap)->flags |= CMF_FMULT;
- }
+ *ap = NULL;
}
+ /* passed -1 but not -2, so remove consecutive duplicates (efficient) */
} else if (!(flags & CGF_UNIQCON)) {
int dup;
diff --git a/Src/Zle/complete.c b/Src/Zle/complete.c
index 7beb6d847..67a60963e 100644
--- a/Src/Zle/complete.c
+++ b/Src/Zle/complete.c
@@ -607,6 +607,7 @@ bin_compadd(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
char *oarg = NULL; /* argument of -o option */
int added; /* return value */
Cmatcher match = NULL;
+ size_t dparlen = 0, dparsize = 0; /* no. of -D options and array size */
if (incompfunc != 1) {
zwarnnam(name, "can only be called from completion function");
@@ -614,7 +615,8 @@ bin_compadd(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
}
dat.ipre = dat.isuf = dat.ppre = dat.psuf = dat.prpre = dat.mesg =
dat.pre = dat.suf = dat.group = dat.rems = dat.remf = dat.disp =
- dat.ign = dat.exp = dat.apar = dat.opar = dat.dpar = NULL;
+ dat.ign = dat.exp = dat.apar = dat.opar = NULL;
+ dat.dpar = NULL;
dat.match = NULL;
dat.flags = 0;
dat.aflags = CAF_MATCH;
@@ -741,7 +743,12 @@ bin_compadd(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
e = "parameter name expected after -%c";
break;
case 'D':
- sp = &(dat.dpar);
+ if (dparsize <= dparlen + 1) {
+ dparsize = (dparsize + 1) * 2;
+ dat.dpar = (char **)zrealloc(dat.dpar, sizeof(char *) * dparsize);
+ }
+ sp = dat.dpar + dparlen++;
+ *sp = dat.dpar[dparlen] = NULL;
e = "parameter name expected after -%c";
break;
case 'd':
@@ -768,11 +775,13 @@ bin_compadd(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
} else {
zwarnnam(name, "number expected after -%c", *p);
zsfree(mstr);
+ zfree(dat.dpar, dparsize);
return 1;
}
if (dat.dummies < 0) {
zwarnnam(name, "invalid number: %d", dat.dummies);
zsfree(mstr);
+ zfree(dat.dpar, dparsize);
return 1;
}
break;
@@ -782,6 +791,7 @@ bin_compadd(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
default:
zwarnnam(name, "bad option: -%c", *p);
zsfree(mstr);
+ zfree(dat.dpar, dparsize);
return 1;
}
if (sp) {
@@ -802,6 +812,7 @@ bin_compadd(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
/* Missing argument: argv[N] == "-X", argv[N+1] == NULL. */
zwarnnam(name, e, *p);
zsfree(mstr);
+ zfree(dat.dpar, dparsize);
return 1;
}
if (m) {
@@ -820,17 +831,21 @@ bin_compadd(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
if (mstr && (match = parse_cmatcher(name, mstr)) == pcm_err) {
zsfree(mstr);
+ zfree(dat.dpar, dparsize);
return 1;
}
zsfree(mstr);
if (!*argv && !dat.group && !dat.mesg &&
- !(dat.aflags & (CAF_NOSORT|CAF_UNIQALL|CAF_UNIQCON|CAF_ALL)))
+ !(dat.aflags & (CAF_NOSORT|CAF_UNIQALL|CAF_UNIQCON|CAF_ALL))) {
+ zfree(dat.dpar, dparsize);
return 1;
+ }
dat.match = match = cpcmatcher(match);
added = addmatches(&dat, argv);
freecmatcher(match);
+ zfree(dat.dpar, dparsize);
return added;
}
@@ -1343,7 +1358,7 @@ get_compstate(Param pm)
/**/
static void
-set_compstate(UNUSED(Param pm), HashTable ht)
+set_compstate(Param pm, HashTable ht)
{
struct compparam *cp;
Param *pp;
diff --git a/Src/Zle/complist.c b/Src/Zle/complist.c
index 429c8159f..0dc64db6a 100644
--- a/Src/Zle/complist.c
+++ b/Src/Zle/complist.c
@@ -603,6 +603,16 @@ zcoff(void)
zcputs(NULL, COL_NO);
}
+/* Clear to end of line, if possible and necessary. */
+static void
+cleareol()
+{
+ if (mlbeg >= 0 && tccan(TCCLEAREOL)) {
+ if (*last_cap)
+ zcoff(); /* If we used colors, prevent them from bleeding. */
+ tcout(TCCLEAREOL);
+ }
+}
static void
initiscol(void)
@@ -670,8 +680,7 @@ clprintfmt(char *p, int ml)
doiscol(i++);
cc++;
if (*p == '\n') {
- if (mlbeg >= 0 && tccan(TCCLEAREOL))
- tcout(TCCLEAREOL);
+ cleareol();
cc = 0;
}
if (ml == mlend - 1 && (cc % zterm_columns) == zterm_columns - 1)
@@ -693,8 +702,7 @@ clprintfmt(char *p, int ml)
!--mrestlines && (ask = asklistscroll(ml)))
return ask;
}
- if (mlbeg >= 0 && tccan(TCCLEAREOL))
- tcout(TCCLEAREOL);
+ cleareol();
return 0;
}
@@ -1047,8 +1055,7 @@ compprintnl(int ml)
{
int ask;
- if (mlbeg >= 0 && tccan(TCCLEAREOL))
- tcout(TCCLEAREOL);
+ cleareol();
putc('\n', shout);
if (mscroll && !--mrestlines && (ask = asklistscroll(ml)))
@@ -1263,8 +1270,8 @@ compprintfmt(char *fmt, int n, int dopr, int doesc, int ml, int *stop)
if ((cc >= zterm_columns - 2 || cchar == ZWC('\n')) && stat)
dopr = 2;
if (cchar == ZWC('\n')) {
- if (dopr == 1 && mlbeg >= 0 && tccan(TCCLEAREOL))
- tcout(TCCLEAREOL);
+ if (dopr == 1)
+ cleareol();
l += 1 + ((cc - 1) / zterm_columns);
cc = 0;
}
@@ -1306,8 +1313,7 @@ compprintfmt(char *fmt, int n, int dopr, int doesc, int ml, int *stop)
if (dopr) {
if (!(cc % zterm_columns))
fputs(" \010", shout);
- if (mlbeg >= 0 && tccan(TCCLEAREOL))
- tcout(TCCLEAREOL);
+ cleareol();
}
if (stat && n)
mfirstl = -1;
@@ -1338,8 +1344,8 @@ compzputs(char const *s, int ml)
c = *s;
s++;
putc(c, shout);
- if (c == '\n' && mlbeg >= 0 && tccan(TCCLEAREOL))
- tcout(TCCLEAREOL);
+ if (c == '\n')
+ cleareol();
if (mscroll && (++col == zterm_columns || c == '\n')) {
ml++;
if (!--mrestlines && (ask = asklistscroll(ml)))
@@ -1692,8 +1698,7 @@ compprintlist(int showall)
lastlistlen = listdat.nlines;
} else if ((nl = listdat.nlines + nlnct - 1) < zterm_lines) {
- if (mlbeg >= 0 && tccan(TCCLEAREOL))
- tcout(TCCLEAREOL);
+ cleareol();
tcmultout(TCUP, TCMULTUP, nl);
showinglist = -1;
@@ -3277,9 +3282,8 @@ domenuselect(Hookdef dummy, Chdata dat)
!strcmp(cmd->nam, "reverse-menu-complete")) {
mode = 0;
comprecursive = 1;
- unmetafy_line();
- reversemenucomplete(zlenoargs);
- metafy_line();
+ zmult = -zmult;
+ do_menucmp(0);
mselect = (*(minfo.cur))->gnum;
setwish = 1;
mline = -1;
diff --git a/Src/Zle/compmatch.c b/Src/Zle/compmatch.c
index cc4c3eca9..bb8359f1d 100644
--- a/Src/Zle/compmatch.c
+++ b/Src/Zle/compmatch.c
@@ -693,8 +693,9 @@ match_str(char *l, char *w, Brinfo *bpp, int bc, int *rwlp,
alen = mp->ralen; aol = mp->lalen;
}
/* Give up if we don't have enough characters for the
- * line-string and the anchor. */
- if (ll < llen + alen || lw < alen)
+ * line-string and the anchor, or for both anchors in
+ * the case of the trial completion word. */
+ if (ll < llen + alen || lw < alen + aol)
continue;
if (mp->flags & CMF_LEFT) {
@@ -1318,7 +1319,7 @@ pattern_match_equivalence(Cpattern lp, convchar_t wind, int wmtp,
convchar_t lchr;
int lmtp;
- if (!PATMATCHINDEX(lp->u.str, wind-1, &lchr, &lmtp)) {
+ if (!PATMATCHINDEX(lp->u.str, wind, &lchr, &lmtp)) {
/*
* No equivalent. No possible match; give up.
*/
@@ -1437,7 +1438,7 @@ pattern_match_restrict(Cpattern p, Cpattern wp, convchar_t *wsc, int wsclen,
/*
* If either is "?", they match each other; no further tests.
- * Apply this even if the character wasn't convertable;
+ * Apply this even if the character wasn't convertible;
* there's no point trying to be clever in that case.
*/
if (p->tp != CPAT_ANY || wp->tp != CPAT_ANY)
@@ -1495,7 +1496,7 @@ pattern_match_restrict(Cpattern p, Cpattern wp, convchar_t *wsc, int wsclen,
* characters. We're matching two patterns against
* one another to generate a character to insert.
* This is a bit too psychedelic, so I'm going to
- * bale out now. See you on the ground.
+ * bail out now. See you on the ground.
*/
return 0;
}
@@ -1563,7 +1564,7 @@ pattern_match(Cpattern p, char *s, Cpattern wp, char *ws)
c = unmeta_one(s, &len);
/*
* If either is "?", they match each other; no further tests.
- * Apply this even if the character wasn't convertable;
+ * Apply this even if the character wasn't convertible;
* there's no point trying to be clever in that case.
*/
if (p->tp != CPAT_ANY || wp->tp != CPAT_ANY)
@@ -1933,7 +1934,7 @@ bld_line(Cmatcher mp, ZLE_STRING_T line, char *mword, char *word,
* This is the nightmare case: we have line and
* and word matchers and some pattern which restricts
* the value on the line without us knowing exactly
- * what it is. Despatch to the special function
+ * what it is. Dispatch to the special function
* for that.
*/
if (mp && !mp->flags && mp->wlen <= wlen &&
diff --git a/Src/Zle/compresult.c b/Src/Zle/compresult.c
index 30fc60b78..57789c0f3 100644
--- a/Src/Zle/compresult.c
+++ b/Src/Zle/compresult.c
@@ -612,9 +612,10 @@ instmatch(Cmatch m, int *scs)
int pcs = zlemetacs;
l = 0;
- for (bp = brbeg, brpos = m->brpl,
- bradd = (m->pre ? strlen(m->pre) : 0);
- bp; bp = bp->next, brpos++) {
+ bradd = (m->pre ? strlen(m->pre) : 0);
+ for (bp = brbeg, brpos = m->brpl;
+ bp && brpos;
+ bp = bp->next, brpos++) {
zlemetacs = a + *brpos + bradd;
pcs = zlemetacs;
l = strlen(bp->str);
@@ -1583,7 +1584,7 @@ calclist(int showall)
nlines += 1 + printfmt(m->disp, 0, 0, 0);
g->flags |= CGF_HASDL;
} else {
- l = ZMB_nicewidth(m->disp);
+ l = ZMB_nicewidth(m->disp) + !!m->modec;
ndisp++;
if (l > glong)
glong = l;
@@ -2247,15 +2248,13 @@ iprintm(Cmgroup g, Cmatch *mp, UNUSED(int mc), UNUSED(int ml), int lastc, int wi
#ifdef MULTIBYTE_SUPPORT
len = mb_niceformat(m->disp, shout, NULL, 0);
#else
- nicezputs(m->disp, shout);
- len = niceztrlen(m->disp);
+ len = sb_niceformat(m->disp, shout, NULL, 0);
#endif
} else {
#ifdef MULTIBYTE_SUPPORT
len = mb_niceformat(m->str, shout, NULL, 0);
#else
- nicezputs(m->str, shout);
- len = niceztrlen(m->str);
+ len = sb_niceformat(m->str, shout, NULL, 0);
#endif
if ((g->flags & CGF_FILES) && m->modec) {
diff --git a/Src/Zle/computil.c b/Src/Zle/computil.c
index 90db8b4b8..59abb4cc4 100644
--- a/Src/Zle/computil.c
+++ b/Src/Zle/computil.c
@@ -1035,7 +1035,7 @@ freecadef(Cadef d)
freecaargs(d->rest);
zsfree(d->nonarg);
if (d->single)
- zfree(d->single, 256 * sizeof(Caopt));
+ zfree(d->single, 188 * sizeof(Caopt));
zfree(d, sizeof(*d));
d = s;
}
@@ -1079,6 +1079,21 @@ bslashcolon(char *s)
return r;
}
+/* Get an index into the single array used in struct cadef
+ * opt is the option letter and pre is either - or +
+ * we only keep an array for the 94 ASCII characters from ! to ~ so
+ * with - and + prefixes, the array is double that at 188 elements
+ * returns -1 if opt is out-of-range
+ */
+static int
+single_index(char pre, char opt)
+{
+ if (opt <= 0x20 || opt > 0x7e)
+ return -1;
+
+ return opt + (pre == '-' ? -0x21 : 94 - 0x21);
+}
+
/* Parse an argument definition. */
static Caarg
@@ -1151,8 +1166,8 @@ alloc_cadef(char **args, int single, char *match, char *nonarg, int flags)
ret->lastt = time(0);
ret->set = NULL;
if (single) {
- ret->single = (Caopt *) zalloc(256 * sizeof(Caopt));
- memset(ret->single, 0, 256 * sizeof(Caopt));
+ ret->single = (Caopt *) zalloc(188 * sizeof(Caopt));
+ memset(ret->single, 0, 188 * sizeof(Caopt));
} else
ret->single = NULL;
ret->match = ztrdup(match);
@@ -1558,9 +1573,10 @@ parse_cadef(char *nam, char **args)
* pointer for the definition in the array for fast lookup.
* But don't treat '--' as a single option called '-' */
-
- if (single && name[1] && !name[2] && name[1] != '-')
- ret->single[STOUC(name[1])] = opt;
+ if (single && name[1] && !name[2] && name[1] != '-') {
+ int sidx = single_index(*name, name[1]);
+ if (sidx >= 0) ret->single[sidx] = opt;
+ }
if (again == 1) {
/* Do it all again for `*-...'. */
@@ -1738,11 +1754,12 @@ ca_get_sopt(Cadef d, char *line, char **end, LinkList *lp)
Caopt p, pp = NULL;
char pre = *line++;
LinkList l = NULL;
+ int sidx;
*lp = NULL;
for (p = NULL; *line; line++) {
- if ((p = d->single[STOUC(*line)]) && p->active &&
- p->args && p->name[0] == pre) {
+ if ((sidx = single_index(pre, *line)) != -1 &&
+ (p = d->single[sidx]) && p->active && p->args) {
if (p->type == CAO_NEXT) {
if (!l)
*lp = l = newlinklist();
@@ -1813,7 +1830,7 @@ ca_get_arg(Cadef d, int n)
/* Mark options as inactive.
* d: option definitions for a set
* pass either:
- * xor: a list if exclusions
+ * xor: a list of exclusions
* opts: if set, all options excluded leaving only nornal/rest arguments */
static void
@@ -2031,9 +2048,9 @@ ca_parse_line(Cadef d, Cadef all, int multi, int first)
state.def = state.ddef = NULL;
state.curopt = state.dopt = NULL;
state.argbeg = state.optbeg = state.nargbeg = state.restbeg = state.actopts =
- state.nth = state.inopt = state.inarg = state.opt = state.arg = 1;
+ state.nth = state.inarg = state.opt = state.arg = 1;
state.argend = argend = arrlen(compwords) - 1;
- state.singles = state.oopt = 0;
+ state.inopt = state.singles = state.oopt = 0;
state.curpos = compcurrent;
state.args = znewlinklist();
state.oargs = (LinkList *) zalloc(d->nopts * sizeof(LinkList));
@@ -2080,9 +2097,14 @@ ca_parse_line(Cadef d, Cadef all, int multi, int first)
remnulargs(line);
untokenize(line);
- ca_inactive(d, argxor, cur - 1, 0);
- if ((d->flags & CDF_SEP) && cur != compcurrent && !strcmp(line, "--")) {
+ if (argxor) {
+ ca_inactive(d, argxor, cur - 1, 0);
+ argxor = NULL;
+ }
+ if ((d->flags & CDF_SEP) && cur != compcurrent && state.actopts &&
+ !strcmp(line, "--")) {
ca_inactive(d, NULL, cur, 1);
+ state.actopts = 0;
continue;
}
@@ -2136,7 +2158,8 @@ ca_parse_line(Cadef d, Cadef all, int multi, int first)
/* See if it's an option. */
- if (state.opt == 2 && (state.curopt = ca_get_opt(d, line, 0, &pe)) &&
+ if (state.opt == 2 && (*line == '-' || *line == '+') &&
+ (state.curopt = ca_get_opt(d, line, 0, &pe)) &&
(state.curopt->type == CAO_OEQUAL ?
(compwords[cur] || pe[-1] == '=') :
(state.curopt->type == CAO_EQUAL ?
@@ -2184,12 +2207,14 @@ ca_parse_line(Cadef d, Cadef all, int multi, int first)
state.curopt = NULL;
}
} else if (state.opt == 2 && d->single &&
+ (*line == '-' || *line == '+') &&
((state.curopt = ca_get_sopt(d, line, &pe, &sopts)) ||
(cur != compcurrent && sopts && nonempty(sopts)))) {
/* Or maybe it's a single-letter option? */
char *p;
Caopt tmpopt;
+ int sidx;
if (cur != compcurrent && sopts && nonempty(sopts))
state.curopt = (Caopt) uremnode(sopts, firstnode(sopts));
@@ -2207,7 +2232,8 @@ ca_parse_line(Cadef d, Cadef all, int multi, int first)
state.singles = (!pe || !*pe);
for (p = line + 1; p < pe; p++) {
- if ((tmpopt = d->single[STOUC(*p)])) {
+ if ((sidx = single_index(*line, *p)) != -1 &&
+ (tmpopt = d->single[sidx])) {
if (!state.oargs[tmpopt->num])
state.oargs[tmpopt->num] = znewlinklist();
@@ -2235,11 +2261,17 @@ ca_parse_line(Cadef d, Cadef all, int multi, int first)
} else if (multi && (*line == '-' || *line == '+') && cur != compcurrent
&& (ca_foreign_opt(d, all, line)))
return 1;
- else if (state.arg &&
- (!napat || cur <= compcurrent || !pattry(napat, line))) {
+ else if (state.arg && cur <= compcurrent) {
/* Otherwise it's a normal argument. */
- if (napat && cur <= compcurrent)
+
+ /* test pattern passed to -A. if it matches treat this as an unknown
+ * option and continue to the next word */
+ if (napat && cur < compcurrent && state.actopts) {
+ if (pattry(napat, line))
+ continue;
ca_inactive(d, NULL, cur + 1, 1);
+ state.actopts = 0;
+ }
arglast = 1;
/* if this is the first normal arg after an option, may have been
@@ -2293,7 +2325,7 @@ ca_parse_line(Cadef d, Cadef all, int multi, int first)
if (adef)
state.oopt = adef->num - state.nth;
- if (state.def)
+ if (state.def && cur != compcurrent)
argxor = state.def->xor;
if (state.def && state.def->type != CAA_NORMAL &&
@@ -2375,6 +2407,23 @@ ca_parse_line(Cadef d, Cadef all, int multi, int first)
return 0;
}
+/* Build a NUL-separated from a list.
+ *
+ * This is only used to populate values of $opt_args.
+ */
+
+static char *
+ca_nullist(LinkList l)
+{
+ if (l) {
+ char **array = zlinklist2array(l, 0 /* don't dup elements */);
+ char *ret = zjoin(array, '\0', 0 /* permanent allocation */);
+ free(array); /* the elements are owned by the list */
+ return ret;
+ } else
+ return ztrdup("");
+}
+
/* Build a colon-list from a list.
*
* This is only used to populate values of $opt_args.
@@ -2563,7 +2612,7 @@ bin_comparguments(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
case 's': min = 1; max = 1; break;
case 'M': min = 1; max = 1; break;
case 'a': min = 0; max = 0; break;
- case 'W': min = 2; max = 2; break;
+ case 'W': min = 3; max = 3; break;
case 'n': min = 1; max = 1; break;
default:
zwarnnam(nam, "invalid option: %s", args[0]);
@@ -2795,11 +2844,20 @@ bin_comparguments(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
return 0;
return 1;
case 'W':
- /* This gets two parameter names as arguments. The first is set to
- * the current word sans any option prefixes handled by comparguments.
+ /* This gets two parameter names and one integer as arguments.
+ *
+ * The first parameter is set to the current word sans any option
+ * prefixes handled by comparguments.
+ *
* The second parameter is set to an array containing the options on
* the line and their arguments. I.e. the stuff _arguments returns
- * to its caller in the `line' and `opt_args' parameters. */
+ * to its caller in the `line' and `opt_args' parameters.
+ *
+ * The integer is one if the second parameter (which is just $opt_args,
+ * you know) should encode multiple values by joining them with NULs
+ * and zero if it should encode multiple values by joining them with
+ * colons after backslash-escaping colons and backslashes.
+ */
{
Castate s;
char **ret, **p;
@@ -2807,6 +2865,7 @@ bin_comparguments(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
LinkList *a;
Caopt o;
int num;
+ int opt_args_use_NUL_separators = (args[3][0] != '0');
for (num = 0, s = lstate; s; s = s->snext)
num += countlinknodes(s->args);
@@ -2832,7 +2891,10 @@ bin_comparguments(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
if (*a) {
*p++ = (o->gsname ? tricat(o->gsname, o->name, "") :
ztrdup(o->name));
- *p++ = ca_colonlist(*a);
+ if (opt_args_use_NUL_separators)
+ *p++ = ca_nullist(*a);
+ else
+ *p++ = ca_colonlist(*a);
}
*p = NULL;
@@ -3591,7 +3653,7 @@ bin_compvalues(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
if (cv_laststate.vals) {
char **ret;
- ret = zlinklist2array(cv_laststate.vals);
+ ret = zlinklist2array(cv_laststate.vals, 1);
sethparam(args[1], ret);
return 0;
@@ -4016,7 +4078,7 @@ bin_comptry(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
set = (Ctset) zalloc(sizeof(*set));
- set->tags = zlinklist2array(list);
+ set->tags = zlinklist2array(list, 1);
set->next = NULL;
set->ptr = NULL;
set->tag = NULL;
diff --git a/Src/Zle/zle.h b/Src/Zle/zle.h
index 609493f8c..391586c4a 100644
--- a/Src/Zle/zle.h
+++ b/Src/Zle/zle.h
@@ -447,6 +447,10 @@ struct region_highlight {
* Any of the flags defined above.
*/
int flags;
+ /*
+ * User-settable "memo" key. Metafied.
+ */
+ const char *memo;
};
/*
diff --git a/Src/Zle/zle_hist.c b/Src/Zle/zle_hist.c
index 581ca4979..cfaa70dae 100644
--- a/Src/Zle/zle_hist.c
+++ b/Src/Zle/zle_hist.c
@@ -683,8 +683,13 @@ insertlastword(char **args)
}
nwords = countlinknodes(l);
} else {
- /* Some stored line. */
- if (!(he = quietgethist(evhist)) || !he->nwords) {
+ /* Some stored line. By default, search for a non-empty line. */
+ while ((he = quietgethist(evhist)) && histstep == -1 && !*args) {
+ if (he->nwords)
+ break;
+ evhist = addhistnum(evhist, histstep, HIST_FOREIGN);
+ }
+ if (!he || !he->nwords) {
unmetafy_line();
return 1;
}
diff --git a/Src/Zle/zle_keymap.c b/Src/Zle/zle_keymap.c
index 49b2a26ad..d90838f03 100644
--- a/Src/Zle/zle_keymap.c
+++ b/Src/Zle/zle_keymap.c
@@ -424,7 +424,7 @@ scankeys(HashNode hn, UNUSED(int flags))
/**************************/
/**/
-Keymap
+mod_export Keymap
openkeymap(char *name)
{
KeymapName n = (KeymapName) keymapnamtab->getnode(keymapnamtab, name);
diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c
index be68f4722..9edf30e01 100644
--- a/Src/Zle/zle_main.c
+++ b/Src/Zle/zle_main.c
@@ -906,6 +906,8 @@ getbyte(long do_keytmout, int *timeout, int full)
continue;
stopmsg = 1;
zexit(1, ZEXIT_NORMAL);
+ /* If called from an exit hook, zexit() returns, so: */
+ break;
}
icnt = 0;
if (errno == EINTR) {
@@ -929,6 +931,8 @@ getbyte(long do_keytmout, int *timeout, int full)
zerr("error on TTY read: %e", errno);
stopmsg = 1;
zexit(1, ZEXIT_NORMAL);
+ /* If called from an exit hook, zexit() returns, so: */
+ break;
}
}
if (cc == '\r') /* undo the exchange of \n and \r determined by */
@@ -1056,7 +1060,7 @@ getrestchar(int inchar, char *outstr, int *outcount)
#endif
/**/
-void
+mod_export void
redrawhook(void)
{
Thingy initthingy;
@@ -1065,6 +1069,7 @@ redrawhook(void)
int saverrflag = errflag, savretflag = retflag;
int lastcmd_prev = lastcmd;
int old_incompfunc = incompfunc;
+ int old_viinrepeat = viinrepeat;
char *args[2];
Thingy lbindk_save = lbindk, bindk_save = bindk;
@@ -1079,6 +1084,7 @@ redrawhook(void)
incompfunc = 0;
execzlefunc(initthingy, args, 1, 0);
incompfunc = old_incompfunc;
+ viinrepeat = old_viinrepeat;
/* Restore errflag and retflag as zlecallhook() does */
errflag = saverrflag | (errflag & ERRFLAG_INT);
diff --git a/Src/Zle/zle_misc.c b/Src/Zle/zle_misc.c
index 612ac2138..eba28d1ec 100644
--- a/Src/Zle/zle_misc.c
+++ b/Src/Zle/zle_misc.c
@@ -1508,9 +1508,6 @@ static struct suffixset *suffixlist;
/**/
static char *suffixfunc;
-/* Length associated with the suffix function */
-static int suffixfunclen;
-
/* Whether to remove suffix on uninsertable characters */
/**/
int suffixnoinsrem;
@@ -1611,7 +1608,7 @@ makesuffixstr(char *f, char *s, int n)
if (f) {
zsfree(suffixfunc);
suffixfunc = ztrdup(f);
- suffixfunclen = n;
+ suffixlen = n;
} else if (s) {
int inv, i, z = 0;
ZLE_STRING_T ws, lasts, wptr;
@@ -1685,7 +1682,7 @@ iremovesuffix(ZLE_INT_T c, int keep)
unmetafy_line();
}
- sprintf(buf, "%d", suffixfunclen);
+ sprintf(buf, "%d", suffixlen);
addlinknode(args, suffixfunc);
addlinknode(args, buf);
@@ -1800,5 +1797,5 @@ fixsuffix(void)
suffixlist = next;
}
- suffixfunclen = suffixnoinsrem = suffixlen = 0;
+ suffixnoinsrem = suffixlen = 0;
}
diff --git a/Src/Zle/zle_move.c b/Src/Zle/zle_move.c
index 155fda80d..3bafff3f1 100644
--- a/Src/Zle/zle_move.c
+++ b/Src/Zle/zle_move.c
@@ -166,7 +166,7 @@ decpos(int *pos)
*/
/**/
-char *
+mod_export char *
backwardmetafiedchar(char *start, char *endptr, convchar_t *retchr)
{
#ifdef MULTIBYTE_SUPPORT
diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c
index 7b8593dec..30b5d4447 100644
--- a/Src/Zle/zle_refresh.c
+++ b/Src/Zle/zle_refresh.c
@@ -212,9 +212,9 @@ static zattr default_atr_on, special_atr_on;
/*
* Array of region highlights, no special termination.
- * The first element (0) always describes the region between
- * point and mark. Any other elements are set by the user
- * via the parameter region_highlight.
+ * The first N_SPECIAL_HIGHLIGHTS elements describe special uses of
+ * highlighting, documented under N_SPECIAL_HIGHLIGHTS.
+ * Any other elements are set by the user via the parameter region_highlight.
*/
/**/
@@ -255,7 +255,9 @@ int cost;
#endif
static const REFRESH_ELEMENT zr_cr = { ZWC('\r'), 0 };
+#ifdef MULTIBYTE_SUPPORT
static const REFRESH_ELEMENT zr_dt = { ZWC('.'), 0 };
+#endif
static const REFRESH_ELEMENT zr_nl = { ZWC('\n'), 0 };
static const REFRESH_ELEMENT zr_sp = { ZWC(' '), 0 };
static const REFRESH_ELEMENT zr_zr = { ZWC('\0'), 0 };
@@ -414,16 +416,19 @@ get_region_highlight(UNUSED(Param pm))
arrsize--;
rhp++, arrp++) {
char digbuf1[DIGBUFSIZE], digbuf2[DIGBUFSIZE];
- int atrlen = 0, alloclen;
+ int atrlen, alloclen;
+ const char memo_equals[] = "memo=";
sprintf(digbuf1, "%d", rhp->start);
sprintf(digbuf2, "%d", rhp->end);
atrlen = output_highlight(rhp->atr, NULL);
alloclen = atrlen + strlen(digbuf1) + strlen(digbuf2) +
- 3; /* 2 spaces, 1 0 */
+ 3; /* 2 spaces, 1 terminating NUL */
if (rhp->flags & ZRH_PREDISPLAY)
alloclen += 2; /* "P " */
+ if (rhp->memo)
+ alloclen += 1 /* space */ + strlen(memo_equals) + strlen(rhp->memo);
*arrp = (char *)zhalloc(alloclen * sizeof(char));
/*
* On input we allow a space after the flags.
@@ -436,6 +441,12 @@ get_region_highlight(UNUSED(Param pm))
(rhp->flags & ZRH_PREDISPLAY) ? "P" : "",
digbuf1, digbuf2);
(void)output_highlight(rhp->atr, *arrp + strlen(*arrp));
+
+ if (rhp->memo) {
+ strcat(*arrp, " ");
+ strcat(*arrp, memo_equals);
+ strcat(*arrp, rhp->memo);
+ }
}
*arrp = NULL;
return retarr;
@@ -460,6 +471,8 @@ set_region_highlight(UNUSED(Param pm), char **aval)
/* no null termination, but include special highlighting at start */
int newsize = len + N_SPECIAL_HIGHLIGHTS;
int diffsize = newsize - n_region_highlights;
+
+ free_region_highlights_memos();
region_highlights = (struct region_highlight *)
zrealloc(region_highlights,
sizeof(struct region_highlight) * newsize);
@@ -476,6 +489,7 @@ set_region_highlight(UNUSED(Param pm), char **aval)
*aval;
rhp++, aval++) {
char *strp, *oldstrp;
+ const char memo_equals[] = "memo=";
oldstrp = *aval;
if (*oldstrp == 'P') {
@@ -502,7 +516,44 @@ set_region_highlight(UNUSED(Param pm), char **aval)
while (inblank(*strp))
strp++;
- match_highlight(strp, &rhp->atr);
+ strp = (char*) match_highlight(strp, &rhp->atr);
+
+ while (inblank(*strp))
+ strp++;
+
+ if (strpfx(memo_equals, strp)) {
+ const char *memo_start = strp + strlen(memo_equals);
+ const char *i, *memo_end;
+
+ /*
+ * Forward compatibility: end parsing at a comma or whitespace to
+ * allow the following extensions:
+ *
+ * - A fifth field: "0 20 bold memo=foo bar".
+ *
+ * - Additional attributes in the fourth field: "0 20 bold memo=foo,bar"
+ * and "0 20 bold memo=foo\0bar".
+ *
+ * For similar reasons, we don't flag an error if the fourth field
+ * doesn't start with "memo=" as we expect.
+ */
+ i = memo_start;
+
+ /* ### TODO: Consider optimizing the common case that memo_start to
+ * end-of-string is entirely ASCII */
+ while (1) {
+ int nbytes;
+ convchar_t c = unmeta_one(i, &nbytes);
+
+ if (c == '\0' || c == ',' || inblank(c)) {
+ memo_end = i;
+ break;
+ } else
+ i += nbytes;
+ }
+ rhp->memo = ztrduppfx(memo_start, memo_end - memo_start);
+ } else
+ rhp->memo = NULL;
}
freearray(av);
@@ -2797,6 +2848,7 @@ zle_refresh_finish(void)
if (region_highlights)
{
+ free_region_highlights_memos();
zfree(region_highlights,
sizeof(struct region_highlight) * n_region_highlights);
region_highlights = NULL;
diff --git a/Src/Zle/zle_thingy.c b/Src/Zle/zle_thingy.c
index ce61db27b..cd3f2c356 100644
--- a/Src/Zle/zle_thingy.c
+++ b/Src/Zle/zle_thingy.c
@@ -678,6 +678,7 @@ bin_zle_flags(char *name, char **args, UNUSED(Options ops), UNUSED(char func))
else if (!strcmp(*flag, "keepsuffix"))
w->flags |= ZLE_KEEPSUFFIX;
*/
+ /* If you add magic strings here, be consistent with bin_zle_call() */
else if (!strcmp(*flag, "vichange")) {
if (invicmdmode()) {
startvichange(-1);
@@ -703,7 +704,7 @@ bin_zle_call(char *name, char **args, UNUSED(Options ops), UNUSED(char func))
{
Thingy t;
struct modifier modsave = zmod;
- int ret, saveflag = 0, setbindk = 0, setlbindk, remetafy;
+ int ret, saveflag = 0, setbindk = 0, setlbindk = 0, remetafy;
char *wname = *args++, *keymap_restore = NULL, *keymap_tmp;
if (!wname)
@@ -727,12 +728,26 @@ bin_zle_call(char *name, char **args, UNUSED(Options ops), UNUSED(char func))
while (*args && **args == '-') {
char skip_this_arg[2] = "x";
char *num;
+ char *flag;
if (!args[0][1] || args[0][1] == '-') {
args++;
break;
}
while (*++(*args)) {
switch (**args) {
+ case 'f':
+ flag = args[0][1] ? args[0]+1 : args[1];
+ if (flag == NULL || strcmp(flag, "nolast")) {
+ zwarnnam(name, "%s", "'nolast' expected after -f");
+ if (remetafy)
+ metafy_line();
+ return 1;
+ }
+ if (!args[0][1])
+ *++args = skip_this_arg;
+ /* If you add magic strings here, be consistent with bin_zle_flags() */
+ setlbindk = 1;
+ break;
case 'n':
num = args[0][1] ? args[0]+1 : args[1];
if (!num) {
@@ -787,7 +802,7 @@ bin_zle_call(char *name, char **args, UNUSED(Options ops), UNUSED(char func))
* a vi range to detect a repeated key */
setbindk = setbindk ||
(t->widget && (t->widget->flags & (WIDGET_INT | ZLE_VIOPER)) == WIDGET_INT);
- setlbindk = t->widget && (t->widget->flags & ZLE_NOLAST) == ZLE_NOLAST;
+ setlbindk |= t->widget && (t->widget->flags & ZLE_NOLAST) == ZLE_NOLAST;
ret = execzlefunc(t, args, setbindk, setlbindk);
unrefthingy(t);
if (saveflag)
diff --git a/Src/Zle/zle_utils.c b/Src/Zle/zle_utils.c
index 2b306fdcd..526216fa7 100644
--- a/Src/Zle/zle_utils.c
+++ b/Src/Zle/zle_utils.c
@@ -557,6 +557,22 @@ zlegetline(int *ll, int *cs)
}
+/*
+ * free() the 'memo' elements of region_highlights.
+ */
+
+/**/
+void
+free_region_highlights_memos(void)
+{
+ struct region_highlight *rhp;
+ for (rhp = region_highlights;
+ rhp < region_highlights + n_region_highlights;
+ rhp++) {
+ zfree((char*) rhp->memo, 0);
+ }
+}
+
/* Forward reference */
struct zle_region;
@@ -568,6 +584,7 @@ struct zle_region {
int start;
int end;
int flags;
+ const char *memo;
};
/* Forward reference */
@@ -632,6 +649,7 @@ zle_save_positions(void)
newrhp->next = NULL;
newrhp->atr = rhp->atr;
newrhp->flags = rhp->flags;
+ newrhp->memo = ztrdup(rhp->memo);
if (zlemetaline) {
newrhp->start = rhp->start_meta;
newrhp->end = rhp->end_meta;
@@ -682,6 +700,7 @@ zle_restore_positions(void)
nreg++, oldrhp = oldrhp->next)
;
if (nreg + N_SPECIAL_HIGHLIGHTS != n_region_highlights) {
+ free_region_highlights_memos();
n_region_highlights = nreg + N_SPECIAL_HIGHLIGHTS;
region_highlights = (struct region_highlight *)
zrealloc(region_highlights,
@@ -694,6 +713,7 @@ zle_restore_positions(void)
rhp->atr = oldrhp->atr;
rhp->flags = oldrhp->flags;
+ rhp->memo = oldrhp->memo; /* transferring ownership of the permanently-allocated memory */
if (zlemetaline) {
rhp->start_meta = oldrhp->start;
rhp->end_meta = oldrhp->end;
@@ -707,6 +727,7 @@ zle_restore_positions(void)
rhp++;
}
} else if (region_highlights) {
+ free_region_highlights_memos();
zfree(region_highlights, sizeof(struct region_highlight) *
n_region_highlights);
region_highlights = NULL;
@@ -1509,7 +1530,7 @@ mkundoent(void)
struct change *ch;
UNMETACHECK();
- if(lastll == zlell && !ZS_memcmp(lastline, zleline, zlell)) {
+ if(lastll == zlell && lastlinesz >= zlell && !ZS_memcmp(lastline, zleline, zlell)) {
lastcs = zlecs;
return;
}