diff options
Diffstat (limited to 'Src/Zle')
-rw-r--r-- | Src/Zle/comp.h | 9 | ||||
-rw-r--r-- | Src/Zle/compcore.c | 146 | ||||
-rw-r--r-- | Src/Zle/complete.c | 23 | ||||
-rw-r--r-- | Src/Zle/complist.c | 38 | ||||
-rw-r--r-- | Src/Zle/compmatch.c | 15 | ||||
-rw-r--r-- | Src/Zle/compresult.c | 15 | ||||
-rw-r--r-- | Src/Zle/computil.c | 114 | ||||
-rw-r--r-- | Src/Zle/zle.h | 4 | ||||
-rw-r--r-- | Src/Zle/zle_hist.c | 9 | ||||
-rw-r--r-- | Src/Zle/zle_keymap.c | 2 | ||||
-rw-r--r-- | Src/Zle/zle_main.c | 8 | ||||
-rw-r--r-- | Src/Zle/zle_misc.c | 9 | ||||
-rw-r--r-- | Src/Zle/zle_move.c | 2 | ||||
-rw-r--r-- | Src/Zle/zle_refresh.c | 64 | ||||
-rw-r--r-- | Src/Zle/zle_thingy.c | 19 | ||||
-rw-r--r-- | Src/Zle/zle_utils.c | 23 |
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; } |