From 2a888b3d5ae1f485649b811ea433f286238fd308 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Wed, 10 Aug 2005 10:56:40 +0000 Subject: c.f. 21590: metafy_line()/unmetafy_line() now support wide characters --- ChangeLog | 12 ++ Src/Zle/compcore.c | 86 +++++++---- Src/Zle/compctl.c | 76 +++++---- Src/Zle/complist.c | 134 +++++++++------- Src/Zle/compresult.c | 275 ++++++++++++++++++--------------- Src/Zle/zle.h | 13 ++ Src/Zle/zle_hist.c | 22 +-- Src/Zle/zle_main.c | 5 + Src/Zle/zle_misc.c | 23 ++- Src/Zle/zle_params.c | 50 ++++-- Src/Zle/zle_refresh.c | 71 +++++++-- Src/Zle/zle_thingy.c | 4 +- Src/Zle/zle_tricky.c | 419 +++++++++++++++++++++++++++++--------------------- Src/Zle/zle_utils.c | 229 ++++++++++++++++++++------- Src/hist.c | 56 ++++--- Src/lex.c | 19 +-- Src/utils.c | 2 +- 17 files changed, 943 insertions(+), 553 deletions(-) diff --git a/ChangeLog b/ChangeLog index d3b5d90ac..8fe4b035e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2005-08-10 Peter Stephenson + + * c.f. 21590: Src/hist.c, Src/lex.c, Src/utils.c, + Src/Zle/compcore.c, Src/Zle/compctl.c, Src/Zle/complist.c, + Src/Zle/compresult.c, Src/Zle/zle.h, Src/Zle/zle_hist.c, + Src/Zle/zle_main.c, Src/Zle/zle_misc.c, Src/Zle/zle_params.c, + Src/Zle/zle_refresh.c, Src/Zle/zle_thingy.c, Src/Zle/zle_tricky.c, + Src/Zle/zle_utils.c: upgrade metafy_line()/unmetafy_line() to + take account of wide characters. Add extra conversion where + necessary. Also attempt fix for singlerefresh() prompt with + ZLE_UNICODE_SUPPORT (untested). + 2005-08-10 Wayne Davison * 21579: Thorsten Dahlheimer: Src/builtin.c: Made printf %s diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c index 0c1f13078..df43cc1ac 100644 --- a/Src/Zle/compcore.c +++ b/Src/Zle/compcore.c @@ -281,7 +281,10 @@ mod_export int lastend; #define inststr(X) inststrlen((X),1,-1) -/* Main completion entry point, called from zle. */ +/* + * Main completion entry point, called from zle. + * At this point the line is already metafied. + */ /**/ int @@ -292,6 +295,8 @@ do_completion(UNUSED(Hookdef dummy), Compldat dat) char *opm; LinkNode n; + METACHECK(); + pushheap(); ainfo = fainfo = NULL; @@ -329,7 +334,7 @@ do_completion(UNUSED(Hookdef dummy), Compldat dat) (isset(LISTPACKED) ? "packed rows" : "rows") : (isset(LISTPACKED) ? "packed" : "")); startauto = isset(AUTOMENU); - movetoend = ((zlecs == we || isset(ALWAYSTOEND)) ? 2 : 1); + movetoend = ((zlemetacs == we || isset(ALWAYSTOEND)) ? 2 : 1); showinglist = 0; hasmatched = hasunmatched = 0; minmlen = 1000000; @@ -341,10 +346,10 @@ do_completion(UNUSED(Hookdef dummy), Compldat dat) /* Make sure we have the completion list and compctl. */ if (makecomplist(s, incmd, lst)) { /* Error condition: feeeeeeeeeeeeep(). */ - zlecs = 0; - foredel(zlell); + zlemetacs = 0; + foredel(zlemetall); inststr(origline); - zlecs = origcs; + zlemetacs = origcs; clearlist = 1; ret = 1; minfo.cur = NULL; @@ -366,10 +371,10 @@ do_completion(UNUSED(Hookdef dummy), Compldat dat) ret = selfinsert(zlenoargs); else if (!useline && uselist) { /* All this and the guy only wants to see the list, sigh. */ - zlecs = 0; - foredel(zlell); + zlemetacs = 0; + foredel(zlemetall); inststr(origline); - zlecs = origcs; + zlemetacs = origcs; showinglist = -2; } else if (useline == 2 && nmatches > 1) { do_allmatches(1); @@ -414,10 +419,10 @@ do_completion(UNUSED(Hookdef dummy), Compldat dat) invalidatelist(); if (forcelist) clearlist = 1; - zlecs = 0; - foredel(zlell); + zlemetacs = 0; + foredel(zlemetall); inststr(origline); - zlecs = origcs; + zlemetacs = origcs; } /* Print the explanation strings if needed. */ if (!showinglist && validlist && usemenu != 2 && uselist && @@ -430,9 +435,9 @@ do_completion(UNUSED(Hookdef dummy), Compldat dat) for (n = firstnode(matchers); n; incnode(n)) freecmatcher((Cmatcher) getdata(n)); - zlell = strlen((char *)zleline); - if (zlecs > zlell) - zlecs = zlell; + zlemetall = strlen((char *)zlemetaline); + if (zlemetacs > zlemetall) + zlemetacs = zlemetall; popheap(); return ret; @@ -469,6 +474,11 @@ before_complete(UNUSED(Hookdef dummy), int *lst) /* We may have to reset the cursor to its position after the * * string inserted by the last completion. */ + /* + * Currently this hook runs before metafication. + * This is the only hook of the three defined here of + * which that is true. + */ if ((fromcomp & FC_INWORD) && (zlecs = lastend) > zlell) zlecs = zlell; @@ -499,10 +509,10 @@ after_complete(UNUSED(Hookdef dummy), int *dat) minfo.cur = NULL; if (ret >= 2) { fixsuffix(); - zlecs = 0; - foredel(zlell); + zlemetacs = 0; + foredel(zlemetall); inststr(origline); - zlecs = origcs; + zlemetacs = origcs; if (ret == 2) { clearlist = 1; invalidatelist(); @@ -525,6 +535,8 @@ callcompfunc(char *s, char *fn) int lv = lastval; char buf[20]; + METACHECK(); + if ((prog = getshfunc(fn)) != &dummy_eprog) { char **p, *tmp; int aadd = 0, usea = 1, icf = incompfunc, osc = sfcontext; @@ -683,10 +695,10 @@ callcompfunc(char *s, char *fn) int l; compiprefix = (char *) zalloc((l = wb - parwb) + 1); - memcpy(compiprefix, zleline + parwb, l); + memcpy(compiprefix, zlemetaline + parwb, l); compiprefix[l] = '\0'; compisuffix = (char *) zalloc((l = parwe - we) + 1); - memcpy(compisuffix, zleline + we, l); + memcpy(compisuffix, zlemetaline + we, l); compisuffix[l] = '\0'; wb = parwb; @@ -1152,7 +1164,7 @@ check_param(char *s, int set, int test) } /* And adjust wb, we, and offs again. */ offs -= b - s; - wb = zlecs - offs; + wb = zlemetacs - offs; we = wb + e - b; ispar = (br >= 2 ? 2 : 1); b[we-wb] = '\0'; @@ -1265,6 +1277,11 @@ comp_str(int *ipl, int *pl, int untok) return str; } +/* + * This is the code behind compset -q, which splits the + * the current word as if it were a command line. + */ + /**/ int set_comp_sep(void) @@ -1273,11 +1290,13 @@ set_comp_sep(void) char *s = comp_str(&lip, &lp, 1); LinkList foo = newlinklist(); LinkNode n; - int owe = we, owb = wb, ocs = zlecs, swb, swe, scs, soffs, ne = noerrs; - int tl, got = 0, i = 0, j, cur = -1, oll = zlell, sl, css = 0; + int owe = we, owb = wb, ocs, swb, swe, scs, soffs, ne = noerrs; + int tl, got = 0, i = 0, j, cur = -1, oll, sl, css = 0; int remq = 0, dq = 0, odq, sq = 0, osq, issq = 0, sqq = 0, lsq = 0, qa = 0; int ois = instring, oib = inbackt, noffs = lp, ona = noaliases; - char *tmp, *p, *ns, *ol = (char *) zleline, sav, *qp, *qs, *ts, qc = '\0'; + char *tmp, *p, *ns, *ol, sav, *qp, *qs, *ts, qc = '\0'; + + METACHECK(); s += lip; wb += lip; @@ -1289,13 +1308,16 @@ set_comp_sep(void) /* Put the string in the lexer buffer and call the lexer to * * get the words we have to expand. */ zleparse = 1; + ocs = zlemetacs; + oll = zlemetall; + ol = (char *)zlemetaline; addedx = 1; noerrs = 1; lexsave(); tmp = (char *) zhalloc(tl = 3 + strlen(s)); tmp[0] = ' '; memcpy(tmp + 1, s, noffs); - tmp[(scs = zlecs = 1 + noffs)] = 'x'; + tmp[(scs = zlemetacs = 1 + noffs)] = 'x'; strcpy(tmp + 2 + noffs, s + noffs); switch (*compqstack) { @@ -1318,8 +1340,8 @@ set_comp_sep(void) if (*p == '\\' && p[1] == '\\') { dq++; chuck(p); - if (j > zlecs) { - zlecs++; + if (j > zlemetacs) { + zlemetacs++; css++; } if (!*p) @@ -1329,8 +1351,8 @@ set_comp_sep(void) odq = dq; osq = sq; inpush(dupstrspace(tmp), 0, NULL); - zleline = (unsigned char *) tmp; - zlell = tl - 1; + zlemetaline = (unsigned char *) tmp; + zlemetall = tl - 1; strinbeg(0); noaliases = 1; do { @@ -1383,7 +1405,7 @@ set_comp_sep(void) swb = wb - 1 - dq - sq; swe = we - 1 - dq - sq; sqq = lsq; - soffs = zlecs - swb - css; + soffs = zlemetacs - swb - css; chuck(p + soffs); ns = dupstring(p); } @@ -1397,9 +1419,9 @@ set_comp_sep(void) lexrestore(); wb = owb; we = owe; - zlecs = ocs; - zleline = (unsigned char *) ol; - zlell = oll; + zlemetacs = ocs; + zlemetaline = (unsigned char *) ol; + zlemetall = oll; if (cur < 0 || i < 1) return 1; owb = offs; diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c index 4b33a2921..2789068e7 100644 --- a/Src/Zle/compctl.c +++ b/Src/Zle/compctl.c @@ -198,16 +198,21 @@ compctlread(char *name, char **args, Options ops, char *reply) return 1; } + METACHECK(); + if (OPT_ISSET(ops,'l')) { - /* -ln gives the index of the word the cursor is currently on, which is - available in zlecs (but remember that Zsh counts from one, not zero!) */ + /* + * -ln gives the index of the word the cursor is currently on, which + * is available in zlemetacs (but remember that Zsh counts from one, + * not zero!) + */ if (OPT_ISSET(ops,'n')) { char nbuf[14]; if (OPT_ISSET(ops,'e') || OPT_ISSET(ops,'E')) - printf("%d\n", zlecs + 1); + printf("%d\n", zlemetacs + 1); if (!OPT_ISSET(ops,'e')) { - sprintf(nbuf, "%d", zlecs + 1); + sprintf(nbuf, "%d", zlemetacs + 1); setsparam(reply, ztrdup(nbuf)); } return 0; @@ -215,11 +220,11 @@ compctlread(char *name, char **args, Options ops, char *reply) /* without -n, the current line is assigned to the given parameter as a scalar */ if (OPT_ISSET(ops,'e') || OPT_ISSET(ops,'E')) { - zputs((char *) zleline, stdout); + zputs((char *) zlemetaline, stdout); putchar('\n'); } if (!OPT_ISSET(ops,'e')) - setsparam(reply, ztrdup((char *) zleline)); + setsparam(reply, ztrdup((char *) zlemetaline)); } else { int i; @@ -2560,7 +2565,9 @@ makecomplistor(Compctl cc, char *s, int incmd, int compadd, int sub) static void makecomplistlist(Compctl cc, char *s, int incmd, int compadd) { - int oloffs = offs, owe = we, owb = wb, ocs = zlecs; + int oloffs = offs, owe = we, owb = wb, ocs = zlemetacs; + + METACHECK(); if (cc->ext) /* Handle extended completion. */ @@ -2574,7 +2581,7 @@ makecomplistlist(Compctl cc, char *s, int incmd, int compadd) offs = oloffs; wb = owb; we = owe; - zlecs = ocs; + zlemetacs = ocs; } /* This add matches for extended completion patterns */ @@ -2751,15 +2758,17 @@ sep_comp_string(char *ss, char *s, int noffs) { LinkList foo = newlinklist(); LinkNode n; - int owe = we, owb = wb, ocs = zlecs, swb, swe, scs, soffs, ne = noerrs; - int sl = strlen(ss), tl, got = 0, i = 0, cur = -1, oll = zlell, remq; + int owe = we, owb = wb, ocs = zlemetacs, swb, swe, scs, soffs, ne = noerrs; + int sl = strlen(ss), tl, got = 0, i = 0, cur = -1, oll = zlemetall, remq; int ois = instring, oib = inbackt, ona = noaliases; - char *tmp, *p, *ns, *ol = (char *) zleline, sav, *oaq = autoq, *qp, *qs; - char *ts, qc = '\0'; + char *tmp, *p, *ns, *ol = (char *) zlemetaline, sav, *oaq = autoq; + char *qp, *qs, *ts, qc = '\0'; swb = swe = soffs = 0; ns = NULL; + METACHECK(); + /* Put the string in the lexer buffer and call the lexer to * * get the words we have to expand. */ zleparse = 1; @@ -2770,13 +2779,13 @@ sep_comp_string(char *ss, char *s, int noffs) strcpy(tmp, ss); tmp[sl] = ' '; memcpy(tmp + sl + 1, s, noffs); - tmp[(scs = zlecs = sl + 1 + noffs)] = 'x'; + tmp[(scs = zlemetacs = sl + 1 + noffs)] = 'x'; strcpy(tmp + sl + 2 + noffs, s + noffs); if ((remq = (*compqstack == '\\'))) tmp = rembslash(tmp); inpush(dupstrspace(tmp), 0, NULL); - zleline = (unsigned char *) tmp; - zlell = tl - 1; + zlemetaline = (unsigned char *) tmp; + zlemetall = tl - 1; strinbeg(0); noaliases = 1; do { @@ -2807,7 +2816,7 @@ sep_comp_string(char *ss, char *s, int noffs) cur = i; swb = wb - 1; swe = we - 1; - soffs = zlecs - swb; + soffs = zlemetacs - swb; chuck(p + soffs); ns = dupstring(p); } @@ -2821,9 +2830,9 @@ sep_comp_string(char *ss, char *s, int noffs) lexrestore(); wb = owb; we = owe; - zlecs = ocs; - zleline = (unsigned char *) ol; - zlell = oll; + zlemetacs = ocs; + zlemetaline = (unsigned char *) ol; + zlemetall = oll; if (cur < 0 || i < 1) return 1; owb = offs; @@ -2979,8 +2988,8 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) addlinknode(allccs, cc); } /* Go to the end of the word if complete_in_word is not set. */ - if (unset(COMPLETEINWORD) && zlecs != we) - zlecs = we, offs = strlen(s); + if (unset(COMPLETEINWORD) && zlemetacs != we) + zlemetacs = we, offs = strlen(s); s = dupstring(s); delit = ispattern = 0; @@ -3200,15 +3209,15 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) ppre = dupstrpfx(rpre, s1 - rpre + 1); psuf = dupstring(s2); - if (zlecs != wb) { - char save = zleline[zlecs]; + if (zlemetacs != wb) { + char save = zlemetaline[zlemetacs]; - zleline[zlecs] = 0; - lppre = dupstring((char *) zleline + wb + + zlemetaline[zlemetacs] = 0; + lppre = dupstring((char *) zlemetaline + wb + (qipre && *qipre ? (strlen(qipre) - (*qipre == '\'' || *qipre == '\"')) : 0)); - zleline[zlecs] = save; + zlemetaline[zlemetacs] = save; if (brbeg) { Brinfo bp; @@ -3230,25 +3239,26 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) lppre = NULL; lppl = 0; } - if (zlecs != we) { + if (zlemetacs != we) { int end = we; - char save = zleline[end]; + char save = zlemetaline[end]; if (qisuf && *qisuf) { int ql = strlen(qisuf); end -= ql - (qisuf[ql-1] == '\'' || qisuf[ql-1] == '"'); } - zleline[end] = 0; - lpsuf = dupstring((char *) (zleline + zlecs)); - zleline[end] = save; + zlemetaline[end] = 0; + lpsuf = dupstring((char *) (zlemetaline + zlemetacs)); + zlemetaline[end] = save; if (brend) { Brinfo bp; char *p; int bl; for (bp = brend; bp; bp = bp->next) { - p = lpsuf + (we - zlecs) - bp->qpos - (bl = strlen(bp->str)); + p = lpsuf + (we - zlemetacs) - bp->qpos - + (bl = strlen(bp->str)); strcpy(p, p + bl); } } @@ -3262,7 +3272,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) /* And get the file prefix. */ fpre = dupstring(((s1 == s || s1 == rpre || ic) && - (*s != '/' || zlecs == wb)) ? s1 : s1 + 1); + (*s != '/' || zlemetacs == wb)) ? s1 : s1 + 1); qfpre = quotename(fpre, NULL); /* And the suffix. */ fsuf = dupstrpfx(rsuf, s2 - rsuf); diff --git a/Src/Zle/complist.c b/Src/Zle/complist.c index 3a3d77971..045e86837 100644 --- a/Src/Zle/complist.c +++ b/Src/Zle/complist.c @@ -1771,28 +1771,30 @@ setmstatus(char *status, char *sline, int sll, int scs, char *p, *s, *ret = NULL; int pl, sl, max; + METACHECK(); + if (csp) { - *csp = zlecs; - *llp = zlell; + *csp = zlemetacs; + *llp = zlemetall; *lenp = lastend - wb; - ret = dupstring((char *) zleline); + ret = dupstring((char *) zlemetaline); - p = (char *) zhalloc(zlecs - wb + 1); - strncpy(p, (char *) zleline + wb, zlecs - wb); - p[zlecs - wb] = '\0'; - if (lastend < zlecs) + p = (char *) zhalloc(zlemetacs - wb + 1); + strncpy(p, (char *) zlemetaline + wb, zlemetacs - wb); + p[zlemetacs - wb] = '\0'; + if (lastend < zlemetacs) s = ""; else { - s = (char *) zhalloc(lastend - zlecs + 1); - strncpy(s, (char *) zleline + zlecs, lastend - zlecs); - s[lastend - zlecs] = '\0'; + s = (char *) zhalloc(lastend - zlemetacs + 1); + strncpy(s, (char *) zlemetaline + zlemetacs, lastend - zlemetacs); + s[lastend - zlemetacs] = '\0'; } - zlecs = 0; - foredel(zlell); + zlemetacs = 0; + foredel(zlemetall); spaceinline(sll); - memcpy(zleline, sline, sll); - zlecs = scs; + memcpy(zlemetaline, sline, sll); + zlemetacs = scs; } else { p = complastprefix; s = complastsuffix; @@ -1970,7 +1972,7 @@ domenuselect(Hookdef dummy, Chdata dat) Menustack u = NULL; int i = 0, acc = 0, wishcol = 0, setwish = 0, oe = onlyexpl, wasnext = 0; int space, lbeg = 0, step = 1, wrap, pl = nlnct, broken = 0, first = 1; - int nolist = 0, mode = 0, modecs, modell, modelen; + int nolist = 0, mode = 0, modecs, modell, modelen, wasmeta; char *s; char status[MAX_STATUS], *modeline = NULL; @@ -1990,6 +1992,23 @@ domenuselect(Hookdef dummy, Chdata dat) unqueue_signals(); return 0; } + /* + * Lots of the logic here doesn't really make sense if the + * line isn't metafied, but the evidence was that only used + * to be metafied locally in a couple of places. + * It's horrifically difficult to work out where the line + * is metafied, so I've resorted to the following. + * Unfortunately we need to unmetatfy in zrefresh() when + * we want to display something. Maybe this function can + * be done better. + */ + if (zlemetaline != NULL) + wasmeta = 1; + else { + wasmeta = 0; + metafy_line(); + } + if ((s = getsparam("MENUSCROLL"))) { if (!(step = mathevali(s))) step = (lines - nlnct) >> 1; @@ -2010,11 +2029,11 @@ domenuselect(Hookdef dummy, Chdata dat) * was before completion started. */ mode = MM_INTER; - zlecs = 0; - foredel(zlell); + zlemetacs = 0; + foredel(zlemetall); spaceinline(l); - strncpy((char *) zleline, origline, l); - zlecs = origcs; + strncpy((char *) zlemetaline, origline, l); + zlemetacs = origcs; setmstatus(status, NULL, 0 , 0, NULL, NULL, NULL); } else if (strpfx("search", s)) { mode = (strstr(s, "back") ? MM_BSEARCH : MM_FSEARCH); @@ -2108,15 +2127,15 @@ domenuselect(Hookdef dummy, Chdata dat) * completion we don't want that, we always want to * be able to type the next character. */ - modeline = dupstring(zleline); - modecs = zlecs; - modell = zlell; + modeline = dupstring((char *)zlemetaline); + modecs = zlemetacs; + modell = zlemetall; modelen = minfo.len; } first = 0; if (mode == MM_INTER) { - statusline = stringaszleline((unsigned char *)status, - &statusll, NULL); + statusline = stringaszleline((unsigned char *)status, 0, + &statusll, NULL, NULL); } else if (mode) { int l = sprintf(status, "%s%sisearch%s: ", ((msearchstate & MS_FAILED) ? "failed " : ""), @@ -2125,8 +2144,8 @@ domenuselect(Hookdef dummy, Chdata dat) strncat(status, msearchstr, MAX_STATUS - l - 1); - statusline = stringaszleline((unsigned char *)status, - &statusll, NULL); + statusline = stringaszleline((unsigned char *)status, 0, + &statusll, NULL, NULL); } else { statusline = NULL; statusll = 0; @@ -2207,11 +2226,11 @@ domenuselect(Hookdef dummy, Chdata dat) * start. */ mode = MM_INTER; - zlecs = 0; - foredel(zlell); + zlemetacs = 0; + foredel(zlemetall); spaceinline(l); - strncpy((char *) zleline, origline, l); - zlecs = origcs; + strncpy((char *) zlemetaline, origline, l); + zlemetacs = origcs; setmstatus(status, NULL, 0, 0, NULL, NULL, NULL); continue; @@ -2226,8 +2245,8 @@ domenuselect(Hookdef dummy, Chdata dat) s->prev = u; u = s; - s->line = dupstring((char *) zleline); - s->cs = zlecs; + s->line = dupstring((char *) zlemetaline); + s->cs = zlemetacs; s->mline = mline; s->mlbeg = mlbeg; memcpy(&(s->info), &minfo, sizeof(struct menuinfo)); @@ -2266,21 +2285,21 @@ domenuselect(Hookdef dummy, Chdata dat) * the command line as it is with just the * characters typed by the user. */ - zlecs = 0; - foredel(zlell); + zlemetacs = 0; + foredel(zlemetall); spaceinline(l); - strncpy((char *) zleline, origline, l); - zlecs = origcs; + strncpy((char *) zlemetaline, origline, l); + zlemetacs = origcs; if (cmd == Th(z_selfinsert)) selfinsert(zlenoargs); else selfinsertunmeta(zlenoargs); - saveline = (char *) zhalloc(zlell); - memcpy(saveline, zleline, zlell); - savell = zlell; - savecs = zlecs; + saveline = (char *) zhalloc(zlemetall); + memcpy(saveline, zlemetaline, zlemetall); + savell = zlemetall; + savecs = zlemetacs; iforcemenu = -1; } else mode = 0; @@ -2294,8 +2313,8 @@ domenuselect(Hookdef dummy, Chdata dat) if (nmatches < 1 || !minfo.cur || !*(minfo.cur)) { nolist = 1; if (mode == MM_INTER) { - statusline = stringaszleline((unsigned char *)status, - &statusll, NULL); + statusline = stringaszleline((unsigned char *)status, 0, + &statusll, NULL, NULL); } else { /* paranoia */ statusline = NULL; @@ -2339,8 +2358,8 @@ domenuselect(Hookdef dummy, Chdata dat) mode = 0; s->prev = u; u = s; - s->line = dupstring((char *) zleline); - s->cs = zlecs; + s->line = dupstring((char *) zlemetaline); + s->cs = zlemetacs; s->mline = mline; s->mlbeg = mlbeg; memcpy(&(s->info), &minfo, sizeof(struct menuinfo)); @@ -2394,11 +2413,11 @@ domenuselect(Hookdef dummy, Chdata dat) break; handleundo(); - zlecs = 0; - foredel(zlell); + zlemetacs = 0; + foredel(zlemetall); spaceinline(l = strlen(u->line)); - strncpy((char *) zleline, u->line, l); - zlecs = u->cs; + strncpy((char *) zlemetaline, u->line, l); + zlemetacs = u->cs; menuacc = u->acc; memcpy(&minfo, &(u->info), sizeof(struct menuinfo)); p = &(minfo.cur); @@ -2435,8 +2454,8 @@ domenuselect(Hookdef dummy, Chdata dat) if (nolist) { if (mode == MM_INTER) { - statusline = stringaszleline((unsigned char *)status, - &statusll, NULL); + statusline = stringaszleline((unsigned char *)status, 0, + &statusll, NULL, NULL); } else { /* paranoia */ statusline = NULL; @@ -2783,11 +2802,11 @@ domenuselect(Hookdef dummy, Chdata dat) origline = modeline; origcs = modecs; origll = modell; - zlecs = 0; - foredel(zlell); + zlemetacs = 0; + foredel(zlemetall); spaceinline(origll); - strncpy((char *) zleline, origline, origll); - zlecs = origcs; + strncpy((char *) zlemetaline, origline, origll); + zlemetacs = origcs; minfo.len = modelen; } else { mode = 0; @@ -2880,9 +2899,7 @@ domenuselect(Hookdef dummy, Chdata dat) acc = 1; break; } - metafy_line(); do_single(**p); - unmetafy_line(); mselect = (**p)->gnum; } if (u) @@ -2898,9 +2915,7 @@ domenuselect(Hookdef dummy, Chdata dat) clearlist = listshown = 1; if (acc && validlist && minfo.cur) { menucmp = lastambig = hasoldlist = 0; - metafy_line(); do_single(*(minfo.cur)); - unmetafy_line(); } if (wasnext || broken) { menucmp = 2; @@ -2923,6 +2938,9 @@ domenuselect(Hookdef dummy, Chdata dat) mlbeg = -1; fdat = NULL; + if (!wasmeta) + unmetafy_line(); + return (broken == 2 ? 3 : ((dat && !broken) ? (acc ? 1 : 2) : (!noselect ^ acc))); } diff --git a/Src/Zle/compresult.c b/Src/Zle/compresult.c index b07e71aff..09794813f 100644 --- a/Src/Zle/compresult.c +++ b/Src/Zle/compresult.c @@ -169,11 +169,13 @@ static char * cline_str(Cline l, int ins, int *csp, LinkList posl) { Cline s; - int ocs = zlecs, ncs, pcs, scs, opos = -1, npos; + int ocs = zlemetacs, ncs, pcs, scs, opos = -1, npos; int pm, pmax, pmm, pma, sm, smax, smm, sma, d, dm, mid; int i, j, li = 0, cbr, padd = (ins ? wb - ocs : -ocs); Brinfo brp, brs; + METACHECK(); + l = cut_cline(l); pmm = pma = smm = sma = dm = pcs = scs = 0; @@ -205,7 +207,7 @@ cline_str(Cline l, int ins, int *csp, LinkList posl) } while (brs && !brs->curpos) { if (cbr < 0) - cbr = zlecs; + cbr = zlemetacs; inststrlen(brs->str, 1, -1); brs = brs->prev; } @@ -214,21 +216,21 @@ cline_str(Cline l, int ins, int *csp, LinkList posl) while (l) { /* Insert the original string if no prefix. */ if (l->olen && !(l->flags & CLF_SUF) && !l->prefix) { - pcs = zlecs + l->olen; + pcs = zlemetacs + l->olen; inststrlen(l->orig, 1, l->olen); } else { /* Otherwise insert the prefix. */ for (s = l->prefix; s; s = s->next) { - pcs = zlecs + s->llen; + pcs = zlemetacs + s->llen; if (s->flags & CLF_LINE) inststrlen(s->line, 1, s->llen); else inststrlen(s->word, 1, s->wlen); - scs = zlecs; + scs = zlemetacs; if ((s->flags & CLF_DIFF) && (!dm || (s->flags & CLF_MATCHED))) { - d = zlecs; dm = s->flags & CLF_MATCHED; - if (posl && (npos = zlecs + padd) != opos) { + d = zlemetacs; dm = s->flags & CLF_MATCHED; + if (posl && (npos = zlemetacs + padd) != opos) { opos = npos; addlinknode(posl, (void *) ((long) npos)); } @@ -240,11 +242,11 @@ cline_str(Cline l, int ins, int *csp, LinkList posl) int ocs, bl; while (brp && li >= brp->curpos) { - ocs = zlecs; + ocs = zlemetacs; bl = strlen(brp->str); - zlecs = pcs - (li - brp->curpos); + zlemetacs = pcs - (li - brp->curpos); inststrlen(brp->str, 1, bl); - zlecs = ocs + bl; + zlemetacs = ocs + bl; pcs += bl; scs += bl; brp = brp->next; @@ -253,14 +255,14 @@ cline_str(Cline l, int ins, int *csp, LinkList posl) /* Remember the position if this is the first prefix with * missing characters. */ if ((l->flags & CLF_MISS) && !(l->flags & CLF_SUF)) { - if (posl && (npos = zlecs + padd) != opos) { + if (posl && (npos = zlemetacs + padd) != opos) { opos = npos; addlinknode(posl, (void *) ((long) npos)); } if (((pmax <= (l->max - l->min) || (pma && l->max != l->min)) && (!pmm || (l->flags & CLF_MATCHED))) || ((l->flags & CLF_MATCHED) && !pmm)) { - pm = zlecs; pmax = l->max - l->min; pmm = l->flags & CLF_MATCHED; + pm = zlemetacs; pmax = l->max - l->min; pmm = l->flags & CLF_MATCHED; pma = ((l->prefix || l->suffix) && l->min == cline_sublen(l)); } } @@ -268,35 +270,35 @@ cline_str(Cline l, int ins, int *csp, LinkList posl) int ocs, bl; while (brs && li >= brs->curpos) { - ocs = zlecs; + ocs = zlemetacs; bl = strlen(brs->str); - zlecs = scs - (li - brs->curpos); + zlemetacs = scs - (li - brs->curpos); if (cbr < 0) - cbr = zlecs; + cbr = zlemetacs; inststrlen(brs->str, 1, bl); - zlecs = ocs + bl; + zlemetacs = ocs + bl; pcs += bl; brs = brs->prev; } } - pcs = zlecs; + pcs = zlemetacs; /* Insert the anchor. */ if (l->flags & CLF_LINE) inststrlen(l->line, 1, l->llen); else inststrlen(l->word, 1, l->wlen); - scs = zlecs; + scs = zlemetacs; if (ins) { int ocs, bl; li += l->llen; while (brp && li >= brp->curpos) { - ocs = zlecs; + ocs = zlemetacs; bl = strlen(brp->str); - zlecs = pcs + l->llen - (li - brp->curpos); + zlemetacs = pcs + l->llen - (li - brp->curpos); inststrlen(brp->str, 1, bl); - zlecs = ocs + bl; + zlemetacs = ocs + bl; pcs += bl; scs += bl; brp = brp->next; @@ -305,16 +307,16 @@ cline_str(Cline l, int ins, int *csp, LinkList posl) /* Remember the cursor position for suffixes and mids. */ if (l->flags & CLF_MISS) { if (l->flags & CLF_MID) - mid = zlecs; + mid = zlemetacs; else if (l->flags & CLF_SUF) { - if (posl && (npos = zlecs + padd) != opos) { + if (posl && (npos = zlemetacs + padd) != opos) { opos = npos; addlinknode(posl, (void *) ((long) npos)); } if (((smax <= (l->min - l->max) || (sma && l->max != l->min)) && (!smm || (l->flags & CLF_MATCHED))) || ((l->flags & CLF_MATCHED) && !smm)) { - sm = zlecs; smax = l->min - l->max; smm = l->flags & CLF_MATCHED; + sm = zlemetacs; smax = l->min - l->max; smm = l->flags & CLF_MATCHED; sma = ((l->prefix || l->suffix) && l->min == cline_sublen(l)); } } @@ -323,20 +325,20 @@ cline_str(Cline l, int ins, int *csp, LinkList posl) int ocs, bl; while (brs && li >= brs->curpos) { - ocs = zlecs; + ocs = zlemetacs; bl = strlen(brs->str); - zlecs = scs - (li - brs->curpos); + zlemetacs = scs - (li - brs->curpos); if (cbr < 0) - cbr = zlecs; + cbr = zlemetacs; inststrlen(brs->str, 1, bl); - zlecs = ocs + bl; + zlemetacs = ocs + bl; pcs += bl; brs = brs->prev; } } /* And now insert the suffix or the original string. */ if (l->olen && (l->flags & CLF_SUF) && !l->suffix) { - pcs = zlecs; + pcs = zlemetacs; inststrlen(l->orig, 1, l->olen); if (ins) { int ocs, bl; @@ -344,22 +346,22 @@ cline_str(Cline l, int ins, int *csp, LinkList posl) li += l->olen; while (brp && li >= brp->curpos) { - ocs = zlecs; + ocs = zlemetacs; bl = strlen(brp->str); - zlecs = pcs + l->olen - (li - brp->curpos); + zlemetacs = pcs + l->olen - (li - brp->curpos); inststrlen(brp->str, 1, bl); - zlecs = ocs + bl; + zlemetacs = ocs + bl; pcs += bl; brp = brp->next; } while (brs && li >= brs->curpos) { - ocs = zlecs; + ocs = zlemetacs; bl = strlen(brs->str); - zlecs = pcs + l->olen - (li - brs->curpos); + zlemetacs = pcs + l->olen - (li - brs->curpos); if (cbr < 0) - cbr = zlecs; + cbr = zlemetacs; inststrlen(brs->str, 1, bl); - zlecs = ocs + bl; + zlemetacs = ocs + bl; pcs += bl; brs = brs->prev; } @@ -370,13 +372,13 @@ cline_str(Cline l, int ins, int *csp, LinkList posl) for (j = -1, i = 0, s = l->suffix; s; s = s->next) { if (j < 0 && (s->flags & CLF_DIFF)) j = i, js = s; - pcs = zlecs; + pcs = zlemetacs; if (s->flags & CLF_LINE) { inststrlen(s->line, 0, s->llen); - i += s->llen; scs = zlecs + s->llen; + i += s->llen; scs = zlemetacs + s->llen; } else { inststrlen(s->word, 0, s->wlen); - i += s->wlen; scs = zlecs + s->wlen; + i += s->wlen; scs = zlemetacs + s->wlen; } if (ins) { int ocs, bl; @@ -384,32 +386,32 @@ cline_str(Cline l, int ins, int *csp, LinkList posl) li += s->llen; while (brp && li >= brp->curpos) { - ocs = zlecs; + ocs = zlemetacs; bl = strlen(brp->str); - zlecs = pcs + (li - brp->curpos); + zlemetacs = pcs + (li - brp->curpos); inststrlen(brp->str, 1, bl); - zlecs = ocs + bl; + zlemetacs = ocs + bl; pcs += bl; scs += bl; brp = brp->next; } while (brs && li >= brs->curpos) { - ocs = zlecs; + ocs = zlemetacs; bl = strlen(brs->str); - zlecs = scs - (li - brs->curpos); + zlemetacs = scs - (li - brs->curpos); if (cbr < 0) - cbr = zlecs; + cbr = zlemetacs; inststrlen(brs->str, 1, bl); - zlecs = ocs + bl; + zlemetacs = ocs + bl; pcs += bl; brs = brs->prev; } } } - zlecs += i; + zlemetacs += i; if (j >= 0 && (!dm || (js->flags & CLF_MATCHED))) { - d = zlecs - j; dm = js->flags & CLF_MATCHED; - if (posl && (npos = zlecs - j + padd) != opos) { + d = zlemetacs - j; dm = js->flags & CLF_MATCHED; + if (posl && (npos = zlemetacs - j + padd) != opos) { opos = npos; addlinknode(posl, (void *) ((long) npos)); } @@ -417,7 +419,7 @@ cline_str(Cline l, int ins, int *csp, LinkList posl) } l = l->next; } - if (posl && (npos = zlecs + padd) != opos) + if (posl && (npos = zlemetacs + padd) != opos) #if 0 /* This could be used to put an extra colon before the end-of-word * position if there is nothing missing. */ @@ -426,23 +428,23 @@ cline_str(Cline l, int ins, int *csp, LinkList posl) addlinknode(posl, (void *) ((long) npos)); if (ins) { - int ocs = zlecs; + int ocs = zlemetacs; for (; brp; brp = brp->next) inststrlen(brp->str, 1, -1); for (; brs; brs = brs->prev) { if (cbr < 0) - cbr = zlecs; + cbr = zlemetacs; inststrlen(brs->str, 1, -1); } if (mid >= ocs) - mid += zlecs - ocs; + mid += zlemetacs - ocs; if (pm >= ocs) - pm += zlecs - ocs; + pm += zlemetacs - ocs; if (sm >= ocs) - sm += zlecs - ocs; + sm += zlemetacs - ocs; if (d >= ocs) - d += zlecs - ocs; + d += zlemetacs - ocs; if (posl) { LinkNode node; @@ -451,7 +453,7 @@ cline_str(Cline l, int ins, int *csp, LinkList posl) for (node = firstnode(posl); node; incnode(node)) { p = (long) getdata(node); if (p >= ocs) - setdata(node, (void *) (p + zlecs - ocs)); + setdata(node, (void *) (p + zlemetacs - ocs)); } } } @@ -461,16 +463,16 @@ cline_str(Cline l, int ins, int *csp, LinkList posl) * suffix, and finally a place where the matches differ. */ ncs = (mid >= 0 ? mid : (cbr >= 0 ? cbr : - (pm >= 0 ? pm : (sm >= 0 ? sm : (d >= 0 ? d : zlecs))))); + (pm >= 0 ? pm : (sm >= 0 ? sm : (d >= 0 ? d : zlemetacs))))); if (ins != 1) { /* We always inserted the string in the line. If that was not * requested, we copy it and remove from the line. */ - char *r = zalloc((i = zlecs - ocs) + 1); + char *r = zalloc((i = zlemetacs - ocs) + 1); - memcpy(r, (char *) (zleline + ocs), i); + memcpy(r, (char *) (zlemetaline + ocs), i); r[i] = '\0'; - zlecs = ocs; + zlemetacs = ocs; foredel(i); if (csp) @@ -478,8 +480,8 @@ cline_str(Cline l, int ins, int *csp, LinkList posl) return r; } - lastend = zlecs; - zlecs = ncs; + lastend = zlemetacs; + zlemetacs = ncs; return NULL; } @@ -579,9 +581,11 @@ unambig_data(int *cp, char **pp, char **ip) static int instmatch(Cmatch m, int *scs) { - int l, r = 0, ocs, a = zlecs, brb = 0, bradd, *brpos; + int l, r = 0, ocs, a = zlemetacs, brb = 0, bradd, *brpos; Brinfo bp; + METACHECK(); + zsfree(lastprebr); zsfree(lastpostbr); lastprebr = lastpostbr = NULL; @@ -606,28 +610,28 @@ instmatch(Cmatch m, int *scs) /* The string itself. */ inststrlen(m->str, 1, (l = strlen(m->str))); r += l; - ocs = zlecs; + ocs = zlemetacs; /* Re-insert the brace beginnings, if any. */ if (brbeg) { - int pcs = zlecs; + int pcs = zlemetacs; l = 0; for (bp = brbeg, brpos = m->brpl, bradd = (m->pre ? strlen(m->pre) : 0); bp; bp = bp->next, brpos++) { - zlecs = a + *brpos + bradd; - pcs = zlecs; + zlemetacs = a + *brpos + bradd; + pcs = zlemetacs; l = strlen(bp->str); bradd += l; - brpcs = zlecs; + brpcs = zlemetacs; inststrlen(bp->str, 1, l); r += l; ocs += l; } lastprebr = (char *) zalloc(pcs - a + 1); - memcpy(lastprebr, (char *) zleline + a, pcs - a); + memcpy(lastprebr, (char *) zlemetaline + a, pcs - a); lastprebr[pcs - a] = '\0'; - zlecs = ocs; + zlemetacs = ocs; } /* Path suffix. */ if (m->psuf) { @@ -636,24 +640,24 @@ instmatch(Cmatch m, int *scs) } /* Re-insert the brace end. */ if (brend) { - a = zlecs; + a = zlemetacs; for (bp = brend, brpos = m->brsl, bradd = 0; bp; bp = bp->next, brpos++) { - zlecs = a - *brpos; - ocs = brscs = zlecs; + zlemetacs = a - *brpos; + ocs = brscs = zlemetacs; l = strlen(bp->str); bradd += l; inststrlen(bp->str, 1, l); - brb = zlecs; + brb = zlemetacs; r += l; } - zlecs = a + bradd; + zlemetacs = a + bradd; if (scs) *scs = ocs; } else { brscs = -1; if (scs) - *scs = zlecs; + *scs = zlemetacs; } /* -S suffix */ if (m->suf) { @@ -666,12 +670,12 @@ instmatch(Cmatch m, int *scs) r += l; } if (brend) { - lastpostbr = (char *) zalloc(zlecs - brb + 1); - memcpy(lastpostbr, (char *) zleline + brb, zlecs - brb); - lastpostbr[zlecs - brb] = '\0'; + lastpostbr = (char *) zalloc(zlemetacs - brb + 1); + memcpy(lastpostbr, (char *) zlemetaline + brb, zlemetacs - brb); + lastpostbr[zlemetacs - brb] = '\0'; } - lastend = zlecs; - zlecs = ocs; + lastend = zlemetacs; + zlemetacs = ocs; return r; } @@ -687,20 +691,20 @@ hasbrpsfx(Cmatch m, char *pre, char *suf) return 1; else { char *op = lastprebr, *os = lastpostbr; - VARARR(char, oline, zlell); - int oll = zlell, ocs = zlecs, ole = lastend, opcs = brpcs, oscs = brscs, ret; + VARARR(char, oline, zlemetall); + int oll = zlemetall, ocs = zlemetacs, ole = lastend, opcs = brpcs, oscs = brscs, ret; - memcpy(oline, zleline, zlell); + memcpy(oline, zlemetaline, zlemetall); lastprebr = lastpostbr = NULL; instmatch(m, NULL); - zlecs = 0; - foredel(zlell); + zlemetacs = 0; + foredel(zlemetall); spaceinline(oll); - memcpy(zleline, oline, oll); - zlecs = ocs; + memcpy(zlemetaline, oline, oll); + zlemetacs = ocs; lastend = ole; brpcs = opcs; brscs = oscs; @@ -754,7 +758,7 @@ do_ambiguous(void) * completion options. */ do_ambig_menu(); } else if (ainfo) { - int atend = (zlecs == we), la, eq, tcs; + int atend = (zlemetacs == we), la, eq, tcs; VARARR(char, old, we - wb); minfo.cur = NULL; @@ -763,9 +767,9 @@ do_ambiguous(void) fixsuffix(); /* First remove the old string from the line. */ - tcs = zlecs; - zlecs = wb; - memcpy(old, (char *) zleline + wb, we - wb); + tcs = zlemetacs; + zlemetacs = wb; + memcpy(old, (char *) zlemetaline + wb, we - wb); foredel(we - wb); /* Now get the unambiguous string and insert it into the line. */ @@ -776,23 +780,23 @@ do_ambiguous(void) * old string. Unless there were matches added with -U, that is. */ if (lastend < we && !lenchanged && !hasunmatched) { - zlecs = wb; + zlemetacs = wb; foredel(lastend - wb); inststrlen(old, 0, we - wb); lastend = we; - zlecs = tcs; + zlemetacs = tcs; } if (eparq) { - tcs = zlecs; - zlecs = lastend; + tcs = zlemetacs; + zlemetacs = lastend; for (eq = eparq; eq; eq--) inststrlen("\"", 0, 1); - zlecs = tcs; + zlemetacs = tcs; } /* la is non-zero if listambiguous may be used. Copying and * comparing the line looks like BFI but it is the easiest * solution. Really. */ - la = (zlell != origll || strncmp(origline, (char *) zleline, zlell)); + la = (zlemetall != origll || strncmp(origline, (char *) zlemetaline, zlemetall)); /* If REC_EXACT and AUTO_MENU are set and what we inserted is an * * exact match, we want menu completion the next time round * @@ -800,11 +804,11 @@ do_ambiguous(void) * taken as an exact match. Also we remember if we just moved the * * cursor into the word. */ fromcomp = ((isset(AUTOMENU) ? FC_LINE : 0) | - ((atend && zlecs != lastend) ? FC_INWORD : 0)); + ((atend && zlemetacs != lastend) ? FC_INWORD : 0)); /* Probably move the cursor to the end. */ if (movetoend == 3) - zlecs = lastend; + zlemetacs = lastend; /* If the LIST_AMBIGUOUS option (meaning roughly `show a list only * * if the completion is completely ambiguous') is set, and some * @@ -947,7 +951,7 @@ do_single(Cmatch m) * so set the position variables. */ minfo.pos = wb; minfo.we = (movetoend >= 2 || (movetoend == 1 && !menucmp) || - (!movetoend && zlecs == we)); + (!movetoend && zlemetacs == we)); minfo.end = we; } /* If we are already in a menu-completion or if we have done a * @@ -959,7 +963,7 @@ do_single(Cmatch m) l = we - wb; minfo.insc = 0; - zlecs = minfo.pos; + zlemetacs = minfo.pos; foredel(l); if (m->flags & CMF_ALL) { @@ -969,8 +973,8 @@ do_single(Cmatch m) /* And then we insert the new string. */ minfo.len = instmatch(m, &scs); - minfo.end = zlecs; - zlecs = minfo.pos + minfo.len; + minfo.end = zlemetacs; + zlemetacs = minfo.pos + minfo.len; if (m->suf) { havesuff = 1; @@ -987,13 +991,13 @@ do_single(Cmatch m) } else { /* There is no user-specified suffix, * * so generate one automagically. */ - zlecs = scs; + zlemetacs = scs; if (partest && (m->flags & CMF_PARBR)) { int pq; /*{{*/ /* Completing a parameter in braces. Add a removable `}' suffix. */ - zlecs += eparq; + zlemetacs += eparq; for (pq = parq; pq; pq--) inststrlen("\"", 1, 1); minfo.insc += parq; @@ -1005,7 +1009,7 @@ do_single(Cmatch m) havesuff = 1; } if (((m->flags & CMF_FILE) || (partest && isset(AUTOPARAMSLASH))) && - zlecs > 0 && zleline[zlecs - 1] != '/') { + zlemetacs > 0 && zlemetaline[zlemetacs - 1] != '/') { /* If we have a filename or we completed a parameter name * * and AUTO_PARAM_SLASH is set, lets see if it is a directory. * * If it is, we append a slash. */ @@ -1079,7 +1083,7 @@ do_single(Cmatch m) } } if (!minfo.insc) - zlecs = minfo.pos + minfo.len - m->qisl; + zlemetacs = minfo.pos + minfo.len - m->qisl; } /* If completing in a brace expansion... */ if (brbeg) { @@ -1092,7 +1096,7 @@ do_single(Cmatch m) } else if (!menucmp) { /*{{*/ /* Otherwise, add a `,' suffix, and let `}' remove it. */ - zlecs = scs; + zlemetacs = scs; havesuff = 1; inststrlen(",", 1, 1); minfo.insc++; @@ -1121,9 +1125,9 @@ do_single(Cmatch m) makeparamsuffix(((m->flags & CMF_PARBR) ? 1 : 0), minfo.insc - parq); if ((menucmp && !minfo.we) || !movetoend) { - zlecs = minfo.end; - if (zlecs + m->qisl == lastend) - zlecs += minfo.insc; + zlemetacs = minfo.end; + if (zlemetacs + m->qisl == lastend) + zlemetacs += minfo.insc; } { Cmatch *om = minfo.cur; @@ -1169,9 +1173,13 @@ do_menucmp(int lst) (((*minfo.cur)->flags & (CMF_NOLIST | CMF_MULT)) && (!(*minfo.cur)->str || !*(*minfo.cur)->str))); /* ... and insert it into the command line. */ - metafy_line(); - do_single(*(minfo.cur)); - unmetafy_line(); + /* Already metafied when called from domenuselect already */ + if (zlemetaline == NULL) { + metafy_line(); + do_single(*minfo.cur); + unmetafy_line(); + } else + do_single(*minfo.cur); } /**/ @@ -1207,6 +1215,15 @@ reverse_menu(UNUSED(Hookdef dummy), UNUSED(void *dummy2)) mod_export int accept_last(void) { + /* give up trying to work out what state it should be in */ + int wasmeta; + if (zlemetaline != NULL) { + wasmeta = 1; + } else { + wasmeta = 0; + metafy_line(); + } + if (!menuacc) { zsfree(minfo.prebr); minfo.prebr = ztrdup(lastprebr); @@ -1232,29 +1249,32 @@ accept_last(void) iremovesuffix(',', 1); - l = (brscs >= 0 ? brscs : zlecs) - brpcs; + l = (brscs >= 0 ? brscs : zlemetacs) - brpcs; zsfree(lastbrbeg->str); lastbrbeg->str = (char *) zalloc(l + 2); - memcpy(lastbrbeg->str, zleline + brpcs, l); + memcpy(lastbrbeg->str, zlemetaline + brpcs, l); lastbrbeg->str[l] = ','; lastbrbeg->str[l + 1] = '\0'; } else { int l; - zlecs = minfo.pos + minfo.len + minfo.insc; + zlemetacs = minfo.pos + minfo.len + minfo.insc; iremovesuffix(' ', 1); - l = zlecs; - zlecs = minfo.pos + minfo.len + minfo.insc - (*(minfo.cur))->qisl; - if (zlecs < l) - foredel(l - zlecs); - else if (zlecs > zlell) - zlecs = zlell; + l = zlemetacs; + zlemetacs = minfo.pos + minfo.len + minfo.insc - (*(minfo.cur))->qisl; + if (zlemetacs < l) + foredel(l - zlemetacs); + else if (zlemetacs > zlemetall) + zlemetacs = zlemetall; inststrlen(" ", 1, 1); minfo.insc = minfo.len = 0; - minfo.pos = zlecs; + minfo.pos = zlemetacs; minfo.we = 1; } + + if (!wasmeta) + unmetafy_line(); return 0; } @@ -2182,8 +2202,9 @@ invalidate_list(void) { invcount++; if (validlist) { - if (showinglist == -2) + if (showinglist == -2) { zrefresh(); + } freematches(lastmatches, 1); lastmatches = NULL; hasoldlist = 0; diff --git a/Src/Zle/zle.h b/Src/Zle/zle.h index f23d7aa2c..ff4d81b47 100644 --- a/Src/Zle/zle.h +++ b/Src/Zle/zle.h @@ -279,3 +279,16 @@ enum { ZSL_COPY = 1, /* Copy the argument, don't modify it */ ZSL_TOEND = 2, /* Go to the end of the new line */ }; + +#ifdef DEBUG +#define STRINGIFY_LITERAL(x) # x +#define STRINGIFY(x) STRINGIFY_LITERAL(x) +#define ERRMSG(x) (__FILE__ ":" STRINGIFY(__LINE__) ": " x) +#define METACHECK() \ + DPUTS(zlemetaline == NULL, ERRMSG("line not metafied")) +#define UNMETACHECK() \ + DPUTS(zlemetaline != NULL, ERRMSG("line metafied")) +#else +#define METACHECK() +#define UNMETACHECK() +#endif diff --git a/Src/Zle/zle_hist.c b/Src/Zle/zle_hist.c index bed66ac0e..c00eafe18 100644 --- a/Src/Zle/zle_hist.c +++ b/Src/Zle/zle_hist.c @@ -82,7 +82,8 @@ zletext(Histent ent, struct zle_text *zt) return; } - zt->text = stringaszleline(ent->text, &zt->len, NULL); + zt->text = stringaszleline((unsigned char *)ent->text, 0, + &zt->len, NULL, NULL); zt->alloced = 1; } @@ -351,7 +352,7 @@ historysearchbackward(char **args) return ret; } if (*args) { - str = stringaszleline((unsigned char *)*args, &hp, NULL); + str = stringaszleline((unsigned char *)*args, 0, &hp, NULL, NULL); } else { if (histline == curhist || histline != srch_hl || zlecs != srch_cs || mark != 0 || ZS_memcmp(srch_str, zleline, histpos) != 0) { @@ -410,7 +411,7 @@ historysearchforward(char **args) return ret; } if (*args) { - str = stringaszleline((unsigned char *)*args, &hp, NULL); + str = stringaszleline((unsigned char *)*args, 0, &hp, NULL, NULL); } else { if (histline == curhist || histline != srch_hl || zlecs != srch_cs || mark != 0 || ZS_memcmp(srch_str, zleline, histpos) != 0) { @@ -631,7 +632,7 @@ insertlastword(char **args) n = zmult; zmult = 1; - zs = stringaszleline((unsigned char *)s, &len, NULL); + zs = stringaszleline((unsigned char *)s, 0, &len, NULL, NULL); doinsert(zs, len); free(zs); zmult = n; @@ -736,8 +737,8 @@ pushlineoredit(char **args) if (zmult < 0) return 1; if (hline && *hline) { - ZLE_STRING_T zhline = stringaszleline((unsigned char *)hline, - &ics, NULL); + ZLE_STRING_T zhline = stringaszleline((unsigned char *)hline, 0, + &ics, NULL, NULL); sizeline(ics + zlell + 1); /* careful of overlapping copy */ @@ -780,7 +781,7 @@ zgetline(UNUSED(char **args)) return 1; } else { int cc; - ZLE_STRING_T lineadd = stringaszleline(s, &cc, NULL); + ZLE_STRING_T lineadd = stringaszleline(s, 0, &cc, NULL, NULL); spaceinline(cc); ZS_memcpy(zleline + zlecs, lineadd, cc); @@ -1257,8 +1258,8 @@ getvisrchstr(void) cmd == Th(z_vicmdmode)) { int newlen; sbuf[sptr] = ZWC('\0'); - visrchstr = zlelineasstring(sbuf + 1, sptr - 1, 0, &newlen, - NULL, 0); + visrchstr = (char *)zlelineasstring(sbuf + 1, sptr - 1, 0, &newlen, + NULL, 0); if (!newlen) { zsfree(visrchstr); visrchstr = ztrdup(vipenultsrchstr); @@ -1378,7 +1379,8 @@ virepeatsearch(UNUSED(char **args)) n = -n; visrchsense = -visrchsense; } - srcstr = stringaszleline(visrchstr, &srclen, NULL); + srcstr = stringaszleline((unsigned char *)visrchstr, 0, + &srclen, NULL, NULL); if (!(he = quietgethist(histline))) return 1; while ((he = movehistent(he, visrchsense, hist_skip_flags))) { diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index 1acff3bbb..2522f67fd 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -42,6 +42,11 @@ /**/ mod_export ZLE_STRING_T zleline; +/* Cursor position and line length in zle */ + +/**/ +mod_export int zlecs, zlell; + /* != 0 if in a shell function called from completion, such that read -[cl] * * will work (i.e., the line is metafied, and the above word arrays are OK). */ diff --git a/Src/Zle/zle_misc.c b/Src/Zle/zle_misc.c index 44bc611d5..9ade372b1 100644 --- a/Src/Zle/zle_misc.c +++ b/Src/Zle/zle_misc.c @@ -69,7 +69,7 @@ selfinsert(UNUSED(char **args)) tmp = lastchar_wide; doinsert(&tmp, 1); #else - char s = lastchar; + unsigned char s = lastchar; doinsert(&s, 1); #endif return 0; @@ -480,7 +480,8 @@ whatcursorposition(UNUSED(char **args)) * convert a single character, remembering it may * turn into a multibyte string or be metafied. */ - mbstr = zlelineasstring(zleline+zlecs, 1, 0, &len, NULL, 1); + mbstr = (char *)zlelineasstring(zleline+zlecs, 1, 0, + &len, NULL, 1); strcpy(s, mbstr); s += len; } @@ -654,7 +655,7 @@ copyprevshellword(UNUSED(char **args)) if (p) { int len; - ZLE_STRING_T lineadd = stringaszleline(p, &len, NULL); + ZLE_STRING_T lineadd = stringaszleline(p, 0, &len, NULL, NULL); spaceinline(len); ZS_memcpy(zleline + zlecs, lineadd, len); @@ -777,7 +778,7 @@ executenamedcommand(char *prmt) clearlist = 1; /* prmt may be constant */ prmt = ztrdup(prmt); - zprmt = stringaszleline((unsigned char *)prmt, &l, NULL); + zprmt = stringaszleline((unsigned char *)prmt, 0, &l, NULL, NULL); cmdbuf = zhalloc((l + NAMLEN + 2) * ZLE_CHAR_SIZE); ZS_memcpy(cmdbuf, zprmt, l); free(zprmt); @@ -860,7 +861,8 @@ executenamedcommand(char *prmt) Thingy r; unambiguous: *ptr = 0; - namedcmdstr = zlelineasstring(cmdbuf, len, 0, NULL, NULL, 0); + namedcmdstr = (char *)zlelineasstring(cmdbuf, len, 0, + NULL, NULL, 0); r = rthingy(namedcmdstr); free(namedcmdstr); namedcmdstr = NULL; @@ -890,7 +892,8 @@ executenamedcommand(char *prmt) namedcmdll = newlinklist(); - namedcmdstr = zlelineasstring(cmdbuf, len, 0, NULL, NULL, 0); + namedcmdstr = (char *)zlelineasstring(cmdbuf, len, 0, + NULL, NULL, 0); scanhashtable(thingytab, 1, 0, DISABLED, scancompcmd, 0); free(namedcmdstr); namedcmdstr = NULL; @@ -912,7 +915,9 @@ executenamedcommand(char *prmt) zmult = zmultsav; } else if (!nextnode(firstnode(namedcmdll))) { char *peekstr = ztrdup(peekfirst(namedcmdll)); - ZLE_STRING_T ztmp = stringaszleline(peekstr, &len, NULL); + ZLE_STRING_T ztmp = + stringaszleline((unsigned char *)peekstr, 0, &len, + NULL, NULL); zsfree(peekstr); ZS_memcpy(ptr = cmdbuf, ztmp, len); ptr += len; @@ -922,7 +927,9 @@ executenamedcommand(char *prmt) } else { int ltmp; char *peekstr = ztrdup(peekfirst(namedcmdll)); - ZLE_STRING_T ztmp = stringaszleline(peekstr, <mp, NULL); + ZLE_STRING_T ztmp = + stringaszleline((unsigned char *)peekstr, 0, <mp, + NULL, NULL); zsfree(peekstr); ZS_memcpy(cmdbuf, ztmp, ltmp); free(ztmp); diff --git a/Src/Zle/zle_params.c b/Src/Zle/zle_params.c index f089a5f47..7aef5959d 100644 --- a/Src/Zle/zle_params.c +++ b/Src/Zle/zle_params.c @@ -126,6 +126,8 @@ static struct zleparam { { NULL, 0, NULL, NULL } }; +/* ro means parameters are readonly, used from completion */ + /**/ mod_export void makezleparams(int ro) @@ -187,7 +189,10 @@ set_buffer(UNUSED(Param pm), char *x) static char * get_buffer(UNUSED(Param pm)) { - return (char *)zlelineasstring(zleline, zlell, 0, NULL, NULL, 1); + if (zlemetaline != 0) + return dupstring((char *)zlemetaline); + else + return (char *)zlelineasstring(zleline, zlell, 0, NULL, NULL, 1); } /**/ @@ -208,7 +213,17 @@ set_cursor(UNUSED(Param pm), zlong x) static zlong get_cursor(UNUSED(Param pm)) { - return zlecs; + if (zlemetaline != NULL) { + /* A lot of work for one number, but still... */ + ZLE_STRING_T tmpline; + int tmpcs, tmpll, tmpsz; + tmpline = stringaszleline(zlemetaline, zlemetacs, + &tmpll, &tmpsz, &tmpcs); + free(tmpline); + return tmpcs; + } + else + return zlecs; } /**/ @@ -238,9 +253,9 @@ set_lbuffer(UNUSED(Param pm), char *x) int len; if (x && *x != ZWC('\0')) - y = stringaszleline((unsigned char *)x, &len, NULL); + y = stringaszleline((unsigned char *)x, 0, &len, NULL, NULL); else - y = ZWC(""), len = 0; + y = ZWS(""), len = 0; sizeline(zlell - zlecs + len); ZS_memmove(zleline + len, zleline + zlecs, zlell - zlecs); ZS_memcpy(zleline, y, len); @@ -257,7 +272,10 @@ set_lbuffer(UNUSED(Param pm), char *x) static char * get_lbuffer(UNUSED(Param pm)) { - return (char *)zlelineasstring(zleline, zlecs, 0, NULL, NULL, 1); + if (zlemetaline != NULL) + return dupstrpfx((char *)zlemetaline, zlemetacs); + else + return (char *)zlelineasstring(zleline, zlecs, 0, NULL, NULL, 1); } /**/ @@ -268,9 +286,9 @@ set_rbuffer(UNUSED(Param pm), char *x) int len; if (x && *x != ZWC('\0')) - y = stringaszleline((unsigned char *)x, &len, NULL); + y = stringaszleline((unsigned char *)x, 0, &len, NULL, NULL); else - y = ZWC(""), len = 0; + y = ZWS(""), len = 0; sizeline(zlell = zlecs + len); ZS_memcpy(zleline + zlecs, y, len); zsfree(x); @@ -284,8 +302,11 @@ set_rbuffer(UNUSED(Param pm), char *x) static char * get_rbuffer(UNUSED(Param pm)) { - return (char *)zlelineasstring(zleline + zlecs, zlell - zlecs, - 0, NULL, NULL, 1); + if (zlemetaline != NULL) + return dupstrpfx((char *)zleline + zlemetacs, zlemetall - zlemetacs); + else + return (char *)zlelineasstring(zleline + zlecs, zlell - zlecs, + 0, NULL, NULL, 1); } /**/ @@ -435,7 +456,7 @@ set_cutbuffer(UNUSED(Param pm), char *x) cutbuf.flags = 0; if (x) { int n; - cutbuf.buf = stringaszleline((unsigned char *)x, &n, NULL); + cutbuf.buf = stringaszleline((unsigned char *)x, 0, &n, NULL, NULL); cutbuf.len = n; free(x); } else { @@ -490,7 +511,8 @@ set_killring(UNUSED(Param pm), char **x) int n, len = strlen(*p); kptr = kring + kpos; - kptr->buf = stringaszleline((unsigned char *)*p, &n, NULL); + kptr->buf = stringaszleline((unsigned char *)*p, 0, &n, + NULL, NULL); kptr->len = n; zfree(*p, len+1); @@ -556,7 +578,7 @@ set_prepost(ZLE_STRING_T *textvar, int *lenvar, char *x) *lenvar = 0; } if (x) { - *textvar = stringaszleline((unsigned char *)x, lenvar, NULL); + *textvar = stringaszleline((unsigned char *)x, 0, lenvar, NULL, NULL); free(x); } } @@ -610,8 +632,8 @@ static char * get_lsearch(UNUSED(Param pm)) { if (previous_search_len) - return zlelineasstring(previous_search, previous_search_len, 0, - NULL, NULL, 1); + return (char *)zlelineasstring(previous_search, previous_search_len, 0, + NULL, NULL, 1); else return ""; } diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c index b45047ac2..da9fe45b7 100644 --- a/Src/Zle/zle_refresh.c +++ b/Src/Zle/zle_refresh.c @@ -333,7 +333,8 @@ zrefresh(void) *qbuf; /* tmp */ int tmpcs, tmpll; /* ditto cursor position and line length */ int tmpalloced; /* flag to free tmpline when finished */ - + int remetafy; /* flag that zle line is metafied */ + if (trashedzle) reexpandprompt(); @@ -344,6 +345,17 @@ zrefresh(void) if (inlist) return; + /* + * zrefresh() is called from all over the place, so we can't + * be sure if the line is metafied for completion or not. + */ + if (zlemetaline != NULL) { + remetafy = 1; + unmetafy_line(); + } + else + remetafy = 0; + if (predisplaylen || postdisplaylen) { /* There is extra text to display at the start or end of the line */ tmpline = zalloc((zlell + predisplaylen + postdisplaylen)*sizeof(*tmpline)); @@ -743,6 +755,9 @@ singlelineout: } if (showinglist == -1) showinglist = nlnct; + + if (remetafy) + metafy_line(); } #define tcinscost(X) (tccan(TCMULTINS) ? tclen[TCMULTINS] : (X)*tclen[TCINS]) @@ -1189,6 +1204,12 @@ singlerefresh(ZLE_STRING_T tmpline, int tmpll, int tmpcs) int t0, /* tmp */ vsiz, /* size of new video buffer */ nvcs = 0; /* new video cursor column */ +#ifdef ZLE_UNICODE_SUPPORT + ZLE_STRING_T lpwbuf, lpwp; /* converted lprompt and pointer */ + char *lpptr, /* pointer into multibyte lprompt */ + lpend; /* end of multibyte lprompt */ + mbstate_t ps; /* shift state */ +#endif nlnct = 1; /* generate the new line buffer completely */ @@ -1208,14 +1229,44 @@ singlerefresh(ZLE_STRING_T tmpline, int tmpll, int tmpcs) } /* only use last part of prompt */ - /* TODO convert prompt to wide char */ #ifdef ZLE_UNICODE_SUPPORT - t0 = mbtowc(vbuf, strchr(lpromptbuf, 0) - lpromptw, lpromptw); - if (t0 >= 0) { - vbuf[t0] = ZWC('\0'); - vp = vbuf + t0; - } else - /* FIXME What to do? */ ; + /* + * Convert the entire lprompt so that we know how to count + * characters. + * + * TODO screen widths are still not correct, indeed lpromptw knows + * nothing about multibyte characters so may be too long. + */ + lpend = strchr(lpromptbuf, 0); + /* Worst case number of characters, not null-terminated */ + lpwp = lpwbuf = (ZLE_STRING_T)zalloc((lpend - lpromptbuf) + * sizeof(*lpwbuf)); + /* Reset shift state, maybe. */ + memset(&ps, '\0', sizeof(ps)); + for (lpptr = lpromptbuf; lpptr < lpend; ) { + t0 = mbrtowc(lpwp, lpptr, lpend - lpptr, &ps); + if (t0 > 0) { + /* successfully converted */ + lpptr += t0; + lpwp++; + } else { + /* dunno, try to recover */ + lpptr++; + *lpwp++ = ZWC('?'); + } + } + if (lpwp - lpwbuf < lpromptw) { + /* Not enough characters for lpromptw. */ + ZS_memcpy(vbuf, lpwbuf, lpwp - lpwbuf); + vp = vbuf + (lpwp - lpwbuf); + while (vp < vbuf + lpromptw) + *vp++ = ZWC(' '); + } else { + ZS_memcpy(vbuf, lpwp - lpromptw, lpromptw); + vp = vbuf + lpromptw; + } + *vp = ZWC('\0'); + zfree(lpwbuf, lpromptw * sizeof(*lpwbuf)); #else memcpy(vbuf, strchr(lpromptbuf, 0) - lpromptw, lpromptw); vbuf[lpromptw] = '\0'; @@ -1223,10 +1274,10 @@ singlerefresh(ZLE_STRING_T tmpline, int tmpll, int tmpcs) #endif for (t0 = 0; t0 < tmpll; t0++) { - if (tmpline[t0] == ZWC('\t')) + if (tmpline[t0] == ZWC('\t')) { for (*vp++ = ZWC(' '); (vp - vbuf) & 7; ) *vp++ = ZWC(' '); - else if (tmpline[t0] == ZWC('\n')) { + } else if (tmpline[t0] == ZWC('\n')) { *vp++ = ZWC('\\'); *vp++ = ZWC('n'); } else if (ZC_icntrl(tmpline[t0])) { diff --git a/Src/Zle/zle_thingy.c b/Src/Zle/zle_thingy.c index 5885fb10f..d756b94e6 100644 --- a/Src/Zle/zle_thingy.c +++ b/Src/Zle/zle_thingy.c @@ -416,8 +416,8 @@ bin_zle_refresh(UNUSED(char *name), char **args, Options ops, UNUSED(char func)) statusll = 0; if (*args) { if (**args) { - statusline = stringaszleline((unsigned char *)*args, &statusll, - NULL); + statusline = stringaszleline((unsigned char *)*args, 0, &statusll, + NULL, NULL); } if (*++args) { LinkList l = newlinklist(); diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c index f59823f0b..ba149cfe8 100644 --- a/Src/Zle/zle_tricky.c +++ b/Src/Zle/zle_tricky.c @@ -33,19 +33,40 @@ /* * The main part of ZLE maintains the line being edited as binary data, * but here, where we interface with the lexer and other bits of zsh, we - * need the line metafied. The technique used is quite simple: on entry - * to the expansion/completion system, we metafy the line in place, - * adjusting zlell and zlecs to match. All completion and expansion is - * done on the metafied line. Immediately before returning, the line is - * unmetafied again, changing zlell and zlecs back. (zlell and zlecs - * might have changed during completion, so they can't be merely saved - * and restored.) The various indexes into the line that are used in - * this file only are not translated: they remain indexes into the - * metafied line. + * need the line metafied and, if necessary, converted from wide + * characters into multibyte strings. On entry to the + * expansion/completion system, we metafy the line from zleline into + * zlemetaline, with zlell and zlecs adjusted into zlemetall zlemetacs + * to match. zlemetall and zlemetacs refer to raw character positions, + * in other words a metafied character contributes 2 to each. All + * completion and expansion is done on the metafied line. Immediately + * before returning, the line is unmetafied again, so that zleline, + * zlell and zlecs are once again valid. (zlell and zlecs might have + * changed during completion, so they can't be merely saved and + * restored.) The various indexes into the line that are used in this + * file only are not translated: they remain indexes into the metafied + * line. + * + * zlemetaline is always NULL when not in use and non-NULL when in use. + * This can be used to test if the line is metafied. It would be + * possible to use zlecs and zlell directly, updated as appropriate when + * metafying and unmetafying, instead of zlemetacs and zlemetall, + * however the current system seems clearer. */ #define inststr(X) inststrlen((X),1,-1) +/* + * The state of the line being edited between metafy_line() + * unmetafy_line(). + * + * zlemetacs and zlemetall are defined in lex.c. + */ +/**/ +mod_export unsigned char *zlemetaline; +/**/ +mod_export int metalinesz; + /* The line before completion was tried. */ /**/ @@ -153,7 +174,10 @@ mod_export int comprecursive; /**/ int hascompwidgets; -/* Find out if we have to insert a tab (instead of trying to complete). */ +/* + * Find out if we have to insert a tab (instead of trying to complete). + * The line is not metafied here. + */ /**/ static int @@ -250,6 +274,7 @@ deletecharorlist(char **args) useglob = isset(GLOBCOMPLETE); wouldinstab = 0; + /* Line not yet metafied */ if (zlecs != zlell) { fixsuffix(); invalidatelist(); @@ -583,32 +608,24 @@ docomplete(int lst) return 0; } - /* - * TODO: metafy_line() currently tries to metafy in place. - * For ZLE_UNICODE_SUPPORT we need to metafy into a separate - * string, replacing all use of zleline, zlecs and zlell here - * with those values, then restoring at the end. - * - * The alternative is probably too horrendous to contemplate. - */ metafy_line(); - ocs = zlecs; - origline = dupstring((char *) zleline); - origcs = zlecs; - origll = zlell; + ocs = zlemetacs; + origline = dupstring((char *) zlemetaline); + origcs = zlemetacs; + origll = zlemetall; if (!isfirstln && chline != NULL) { /* If we are completing in a multi-line buffer (which was not * * taken from the history), we have to prepend the stuff saved * * in chline to the contents of line. */ - ol = dupstring((char *)zleline); + ol = dupstring((char *)zlemetaline); /* Make sure that chline is zero-terminated. */ *hptr = '\0'; - zlecs = 0; + zlemetacs = 0; inststr(chline); - chl = zlecs; - zlecs += ocs; + chl = zlemetacs; + zlemetacs += ocs; } else ol = NULL; inwhat = IN_NOTHING; @@ -622,35 +639,35 @@ docomplete(int lst) * NOTE: get_comp_string() calls pushheap(), but not popheap(). */ noerrs = 1; s = get_comp_string(); - DPUTS(wb < 0 || zlecs < wb || zlecs > we, - "BUG: 0 <= wb <= zlecs <= we is not true!"); + DPUTS(wb < 0 || zlemetacs < wb || zlemetacs > we, + "BUG: 0 <= wb <= zlemetacs <= we is not true!"); noerrs = ne; /* For vi mode, reset the start-of-insertion pointer to the beginning * * of the word being completed, if it is currently later. Vi itself * * would never change the pointer in the middle of an insertion, but * * then vi doesn't have completion. More to the point, this is only * * an emulation. */ - if (viinsbegin > ztrsub((char *) zleline + wb, (char *) zleline)) - viinsbegin = ztrsub((char *) zleline + wb, (char *) zleline); + if (viinsbegin > ztrsub((char *) zlemetaline + wb, (char *) zlemetaline)) + viinsbegin = ztrsub((char *) zlemetaline + wb, (char *) zlemetaline); /* If we added chline to the line buffer, reset the original contents. */ if (ol) { - zlecs -= chl; + zlemetacs -= chl; wb -= chl; we -= chl; if (wb < 0) { - strcpy((char *) zleline, ol); - zlell = strlen((char *) zleline); - zlecs = ocs; + strcpy((char *) zlemetaline, ol); + zlemetall = strlen((char *) zlemetaline); + zlemetacs = ocs; popheap(); unmetafy_line(); zsfree(s); active = 0; return 1; } - ocs = zlecs; - zlecs = 0; + ocs = zlemetacs; + zlemetacs = 0; foredel(chl); - zlecs = ocs; + zlemetacs = ocs; } freeheap(); /* Save the lexer state, in case the completion code uses the lexer * @@ -694,7 +711,7 @@ docomplete(int lst) if (*q == String && q[1] != Inpar && q[1] != Inbrack) { if (*++q == Inbrace) { if (! skipparens(Inbrace, Outbrace, &q) && - q == s + zlecs - wb) + q == s + zlemetacs - wb) lst = COMP_EXPAND; } else { char *t, sav, sav2; @@ -725,7 +742,7 @@ docomplete(int lst) q++; sav = *q; *q = '\0'; - if (zlecs - wb == q - s && + if (zlemetacs - wb == q - s && (idigit(sav2) || checkparams(t))) lst = COMP_EXPAND; *q = sav; @@ -735,7 +752,7 @@ docomplete(int lst) lst = COMP_COMPLETE; } else break; - } while (q < s + zlecs - wb); + } while (q < s + zlemetacs - wb); if (lst == COMP_EXPAND_COMPLETE) { /* If it is still not clear if we should use expansion or * * completion and there is a `$' or a backtick in the word, * @@ -760,7 +777,7 @@ docomplete(int lst) for (q = w; *q; q++) if (INULL(*q)) *q = Nularg; - zlecs = wb; + zlemetacs = wb; foredel(we - wb); untokenize(x = ox = dupstring(w)); @@ -775,8 +792,8 @@ docomplete(int lst) /* Do expansion. */ char *ol = (olst == COMP_EXPAND || olst == COMP_EXPAND_COMPLETE) ? - dupstring((char *)zleline) : (char *)zleline; - int ocs = zlecs, ne = noerrs; + dupstring((char *)zlemetaline) : (char *)zlemetaline; + int ocs = zlemetacs, ne = noerrs; noerrs = 1; ret = doexpansion(origword, lst, olst, lincmd); @@ -786,8 +803,8 @@ docomplete(int lst) /* If expandorcomplete was invoked and the expansion didn't * * change the command line, do completion. */ if (olst == COMP_EXPAND_COMPLETE && - !strcmp(ol, (char *)zleline)) { - zlecs = ocs; + !strcmp(ol, (char *)zlemetaline)) { + zlemetacs = ocs; errflag = 0; if (!compfunc) { @@ -808,15 +825,15 @@ docomplete(int lst) } else { if (ret) clearlist = 1; - if (!strcmp(ol, (char *)zleline)) { + if (!strcmp(ol, (char *)zlemetaline)) { /* We may have removed some quotes. For completion, other * parts of the code re-install them, but for expansion * we have to do it here. */ - zlecs = 0; - foredel(zlell); + zlemetacs = 0; + foredel(zlemetall); spaceinline(origll); - memcpy(zleline, origline, origll); - zlecs = origcs; + memcpy(zlemetaline, origline, origll); + zlemetacs = origcs; } } } else @@ -828,11 +845,11 @@ docomplete(int lst) /* Reset the lexer state, pop the heap. */ lexrestore(); popheap(); - unmetafy_line(); dat[0] = lst; dat[1] = ret; runhookdef(AFTERCOMPLETEHOOK, (void *) dat); + unmetafy_line(); active = 0; return dat[1]; @@ -865,23 +882,26 @@ addx(char **ptmp) { int addspace = 0; - if (!zleline[zlecs] || zleline[zlecs] == '\n' || - (iblank(zleline[zlecs]) && (!zlecs || zleline[zlecs-1] != '\\')) || - zleline[zlecs] == ')' || zleline[zlecs] == '`' || - zleline[zlecs] == '}' || - zleline[zlecs] == ';' || zleline[zlecs] == '|' || - zleline[zlecs] == '&' || - zleline[zlecs] == '>' || zleline[zlecs] == '<' || - (instring && (zleline[zlecs] == '"' || zleline[zlecs] == '\'')) || - (addspace = (comppref && !iblank(zleline[zlecs])))) { - *ptmp = (char *)zleline; - zleline = (ZLE_STRING_T)zhalloc(strlen((char *)zleline) + 3 + - addspace); - memcpy(zleline, *ptmp, zlecs); - zleline[zlecs] = 'x'; + if (!zlemetaline[zlemetacs] || zlemetaline[zlemetacs] == '\n' || + (iblank(zlemetaline[zlemetacs]) && + (!zlemetacs || zlemetaline[zlemetacs-1] != '\\')) || + zlemetaline[zlemetacs] == ')' || zlemetaline[zlemetacs] == '`' || + zlemetaline[zlemetacs] == '}' || + zlemetaline[zlemetacs] == ';' || zlemetaline[zlemetacs] == '|' || + zlemetaline[zlemetacs] == '&' || + zlemetaline[zlemetacs] == '>' || zlemetaline[zlemetacs] == '<' || + (instring && (zlemetaline[zlemetacs] == '"' || + zlemetaline[zlemetacs] == '\'')) || + (addspace = (comppref && !iblank(zlemetaline[zlemetacs])))) { + *ptmp = (char *)zlemetaline; + zlemetaline = (unsigned char *)zhalloc(strlen((char *)zlemetaline) + + 3 + addspace); + memcpy(zlemetaline, *ptmp, zlemetacs); + zlemetaline[zlemetacs] = 'x'; if (addspace) - zleline[zlecs+1] = ' '; - strcpy((char *)zleline + zlecs + 1 + addspace, (*ptmp) + zlecs); + zlemetaline[zlemetacs+1] = ' '; + strcpy((char *)zlemetaline + zlemetacs + 1 + addspace, + (*ptmp) + zlemetacs); addedx = 1 + addspace; } else { addedx = 0; @@ -902,35 +922,47 @@ dupstrspace(const char *str) return t; } -/* These functions metafy and unmetafy the ZLE buffer, as described at the * - * top of this file. Note that zlell and zlecs are translated. They *must* be * - * called in matching pairs, around all the expansion/completion code. * - * Currently, there are four pairs: in history expansion, in the main * - * completion function, and one in each of the middle-of-menu-completion * - * functions (there's one for each direction). */ +/* + * These functions metafy and unmetafy the ZLE buffer, as described at + * the top of this file. They *must* be called in matching pairs, + * around all the expansion/completion code. + * + * The variables zleline, zlell and zlecs are metafied into + * zlemetaline, zlemetall and zlemetacs. Only the latter variables + * should be referred to from above zle (i.e. in the main shell), + * or when using the completion API (if that's not too strong a + * way of referring to it). + */ /**/ mod_export void metafy_line(void) { - int len = zlell; - char *s; + UNMETACHECK(); + + zlemetaline = zlelineasstring(zleline, zlell, zlecs, + &zlemetall, &zlemetacs, 0); + metalinesz = zlemetall; - for (s = (char *) zleline; s < (char *) zleline + zlell;) - if (imeta(*s++)) - len++; - sizeline(len); - (void) metafy((char *) zleline, zlell, META_NOALLOC); - zlell = len; - zlecs = metalen((char *) zleline, zlecs); + /* + * We will always allocate a new zleline based on zlemetaline. + */ + free(zleline); + zleline = NULL; } /**/ mod_export void unmetafy_line(void) { - zlecs = ztrsub((char *) zleline + zlecs, (char *) zleline); - (void) unmetafy((char *) zleline, &zlell); + METACHECK(); + + /* paranoia */ + zlemetaline[zlemetall] = '\0'; + zleline = stringaszleline(zlemetaline, zlemetacs, &zlell, &linesz, &zlecs); + + free(zlemetaline); + zlemetaline = NULL; } /* Free a brinfo list. */ @@ -1004,6 +1036,8 @@ get_comp_string(void) int ona = noaliases, qsub; char *s = NULL, *linptr, *tmp, *p, *tt = NULL, rdop[20]; + METACHECK(); + freebrinfo(brbeg); freebrinfo(brend); brbeg = lastbrbeg = brend = lastbrend = NULL; @@ -1025,7 +1059,8 @@ get_comp_string(void) * "...", `...`, or ((...)). Nowadays this is only used to find * * out if we are inside `...`. */ - for (i = j = k = 0, p = (char *)zleline; p < (char *)zleline + zlecs; p++) + for (i = j = k = 0, p = (char *)zlemetaline; + p < (char *)zlemetaline + zlemetacs; p++) if (*p == '`' && !(k & 1)) i++; else if (*p == '\"' && !(k & 1) && !(i & 1)) @@ -1037,7 +1072,7 @@ get_comp_string(void) inbackt = (i & 1); instring = 0; addx(&tmp); - linptr = (char *)zleline; + linptr = (char *)zlemetaline; pushheap(); start: @@ -1146,14 +1181,14 @@ get_comp_string(void) tt = tokstr ? dupstring(tokstr) : NULL; if (isset(RCQUOTES) && *tt == Snull) { - char *p, *e = tt + zlecs - wb; + char *p, *e = tt + zlemetacs - wb; for (p = tt; *p && p < e; p++) if (*p == '\'') qsub++; } /* If we added a `x', remove it. */ if (addedx && tt) - chuck(tt + zlecs - wb - qsub); + chuck(tt + zlemetacs - wb - qsub); tt0 = tok; /* Store the number of this word. */ clwpos = i; @@ -1201,8 +1236,8 @@ get_comp_string(void) /* If this is the word the cursor is in and we added a `x', * * remove it. */ if (clwpos == i++ && addedx) - chuck(&clwords[i - 1][((zlecs - wb - qsub) >= sl) ? - (sl - 1) : (zlecs - wb - qsub)]); + chuck(&clwords[i - 1][((zlemetacs - wb - qsub) >= sl) ? + (sl - 1) : (zlemetacs - wb - qsub)]); } while (tok != LEXERR && tok != ENDINPUT && (tok != SEPER || (zleparse && !tt0))); /* Calculate the number of words stored in the clwords array. */ @@ -1224,13 +1259,14 @@ get_comp_string(void) /* We are in command or process substitution if we are not in * a $((...)). */ if (parend >= 0 && !tmp) - zleline = (unsigned char *) dupstring(tmp = (char *)zleline); - linptr = (char *) zleline + zlell + addedx - parbegin + 1; - if ((linptr - (char *) zleline) < 3 || *linptr != '(' || + zlemetaline = (unsigned char *) + dupstring(tmp = (char *)zlemetaline); + linptr = (char *) zlemetaline + zlemetall + addedx - parbegin + 1; + if ((linptr - (char *) zlemetaline) < 3 || *linptr != '(' || linptr[-1] != '(' || linptr[-2] != '$') { if (parend >= 0) { - zlell -= parend; - zleline[zlell + addedx] = '\0'; + zlemetall -= parend; + zlemetaline[zlemetall + addedx] = '\0'; } lexrestore(); tt = NULL; @@ -1243,7 +1279,7 @@ get_comp_string(void) else if (!t0 || t0 == ENDINPUT) { /* There was no word (empty line). */ s = ztrdup(""); - we = wb = zlecs; + we = wb = zlemetacs; clwpos = clwnum; t0 = STRING; } else if (t0 == STRING) { @@ -1264,7 +1300,7 @@ get_comp_string(void) *s = sav; if (*s == '+') s++; - if (skipparens(Inbrack, Outbrack, &s) > 0 || s > tt + zlecs - wb) { + if (skipparens(Inbrack, Outbrack, &s) > 0 || s > tt + zlemetacs - wb) { s = NULL; inwhat = IN_MATH; if ((keypm = (Param) paramtab->getnode(paramtab, varname)) && @@ -1273,7 +1309,7 @@ get_comp_string(void) else insubscr = 1; } else if (*s == '=') { - if (zlecs > wb + (s - tt)) { + if (zlemetacs > wb + (s - tt)) { s++; wb += s - tt; s = ztrdup(s); @@ -1294,17 +1330,17 @@ get_comp_string(void) } lincmd = 1; } - if (we > zlell) - we = zlell; - tt = (char *)zleline; + if (we > zlemetall) + we = zlemetall; + tt = (char *)zlemetaline; if (tmp) { - zleline = (unsigned char *)tmp; - zlell = strlen((char *)zleline); + zlemetaline = (unsigned char *)tmp; + zlemetall = strlen((char *)zlemetaline); } if (t0 != STRING && inwhat != IN_MATH) { if (tmp) { tmp = NULL; - linptr = (char *)zleline; + linptr = (char *)zlemetaline; lexrestore(); addedx = 0; goto start; @@ -1325,7 +1361,7 @@ get_comp_string(void) int i = 0; char *nnb = (iident(*s) ? s : s + 1), *nb = NULL, *ne = NULL; - for (tt = s; ++tt < s + zlecs - wb;) + for (tt = s; ++tt < s + zlemetacs - wb;) if (*tt == Inbrack) { i++; nb = nnb; @@ -1354,23 +1390,23 @@ get_comp_string(void) int lev; char *p; - for (wb = zlecs - 1, lev = 0; wb > 0; wb--) - if (zleline[wb] == ']' || zleline[wb] == ')') + for (wb = zlemetacs - 1, lev = 0; wb > 0; wb--) + if (zlemetaline[wb] == ']' || zlemetaline[wb] == ')') lev++; - else if (zleline[wb] == '[') { + else if (zlemetaline[wb] == '[') { if (!lev--) break; - } else if (zleline[wb] == '(') { - if (!lev && zleline[wb - 1] == '(') + } else if (zlemetaline[wb] == '(') { + if (!lev && zlemetaline[wb - 1] == '(') break; if (lev) lev--; } - p = (char *) zleline + wb; + p = (char *) zlemetaline + wb; wb++; if (wb && (*p == '[' || *p == '(') && !skipparens(*p, (*p == '[' ? ']' : ')'), &p)) { - we = (p - (char *) zleline) - 1; + we = (p - (char *) zlemetaline) - 1; if (insubscr == 2) insubscr = 3; } @@ -1378,25 +1414,26 @@ get_comp_string(void) /* In mathematical expression, we complete parameter names * * (even if they don't have a `$' in front of them). So we * * have to find that name. */ - for (we = zlecs; iident(zleline[we]); we++); - for (wb = zlecs; --wb >= 0 && iident(zleline[wb]);); + for (we = zlemetacs; iident(zlemetaline[we]); we++); + for (wb = zlemetacs; --wb >= 0 && iident(zlemetaline[wb]);); wb++; } zsfree(s); s = zalloc(we - wb + 1); - strncpy(s, (char *) zleline + wb, we - wb); + strncpy(s, (char *) zlemetaline + wb, we - wb); s[we - wb] = '\0'; - if (wb > 2 && zleline[wb - 1] == '[' && iident(zleline[wb - 2])) { + if (wb > 2 && zlemetaline[wb - 1] == '[' && + iident(zlemetaline[wb - 2])) { int i = wb - 3; - unsigned char sav = zleline[wb - 1]; + unsigned char sav = zlemetaline[wb - 1]; - while (i >= 0 && iident(zleline[i])) + while (i >= 0 && iident(zlemetaline[i])) i--; - zleline[wb - 1] = '\0'; + zlemetaline[wb - 1] = '\0'; zsfree(varname); - varname = ztrdup((char *) zleline + i + 1); - zleline[wb - 1] = sav; + varname = ztrdup((char *) zlemetaline + i + 1); + zlemetaline[wb - 1] = sav; if ((keypm = (Param) paramtab->getnode(paramtab, varname)) && (keypm->flags & PM_HASHED)) { if (insubscr != 3) @@ -1407,7 +1444,7 @@ get_comp_string(void) parse_subst_string(s); } /* This variable will hold the current word in quoted form. */ - offs = zlecs - wb; + offs = zlemetacs - wb; if ((p = parambeg(s))) { for (p = s; *p; p++) if (*p == Dnull) @@ -1451,34 +1488,34 @@ get_comp_string(void) /* While building the quoted form, we also clean up the command line. */ for (p = s, i = wb, j = 0; *p; p++, i++) if (INULL(*p)) { - if (i < zlecs) + if (i < zlemetacs) offs--; if (*p == Snull && isset(RCQUOTES)) j = 1-j; if (p[1] || *p != Bnull) { if (*p == Bnull) { - if (zlecs == i + 1) - zlecs++, offs++; + if (zlemetacs == i + 1) + zlemetacs++, offs++; } else { - ocs = zlecs; - zlecs = i; + ocs = zlemetacs; + zlemetacs = i; foredel(1); - if ((zlecs = ocs) > i--) - zlecs--; + if ((zlemetacs = ocs) > i--) + zlemetacs--; we--; } } else { - ocs = zlecs; - zlecs = we; + ocs = zlemetacs; + zlemetacs = we; backdel(1); if (ocs == we) - zlecs = we - 1; + zlemetacs = we - 1; else - zlecs = ocs; + zlemetacs = ocs; we--; } chuck(p--); - } else if (j && *p == '\'' && i < zlecs) + } else if (j && *p == '\'' && i < zlemetacs) offs--; zsfree(origword); @@ -1746,9 +1783,24 @@ inststrlen(char *str, int move, int len) if (len == -1) len = strlen(str); spaceinline(len); - strncpy((char *)(zleline + zlecs), str, len); - if (move) - zlecs += len; + if (zlemetaline != NULL) + { + strncpy((char *)(zlemetaline + zlemetacs), str, len); + if (move) + zlemetacs += len; + } + else + { + unsigned char *instr; + ZLE_STRING_T zlestr; + int zlelen; + + instr = (unsigned char *)ztrduppfx((char *)str, len); + zlestr = stringaszleline(instr, 0, &zlelen, NULL, NULL); + ZS_strncpy(zleline + zlecs, zlestr, zlelen); + free(zlestr); + zsfree((char *)instr); + } return len; } @@ -1801,17 +1853,17 @@ doexpansion(char *s, int lst, int olst, int explincmd) if (lst == COMP_LIST_EXPAND) { /* Only the list of expansions was requested. Restore the * command line. */ - zlecs = 0; - foredel(zlell); + zlemetacs = 0; + foredel(zlemetall); spaceinline(origll); - memcpy(zleline, origline, origll); - zlecs = origcs; + memcpy(zlemetaline, origline, origll); + zlemetacs = origcs; ret = listlist(vl); showinglist = 0; goto end; } /* Remove the current word and put the expansions there. */ - zlecs = wb; + zlemetacs = wb; foredel(we - wb); while ((ss = (char *)ugetnode(vl))) { ret = 0; @@ -1820,11 +1872,11 @@ doexpansion(char *s, int lst, int olst, int explincmd) inststr(ss); #if 0 if (olst != COMP_EXPAND_COMPLETE || nonempty(vl) || - (zlecs && zleline[zlecs-1] != '/')) { + (zlemetacs && zlemetaline[zlemetacs-1] != '/')) { #endif if (nonempty(vl) || !first) { spaceinline(1); - zleline[zlecs++] = ' '; + zlemetaline[zlemetacs++] = ' '; } first = 0; } @@ -2250,14 +2302,16 @@ doexpandhist(void) unsigned char *ol; int oll, ocs, ne = noerrs, err, ona = noaliases; + UNMETACHECK(); + pushheap(); metafy_line(); - oll = zlell; - ocs = zlecs; - ol = (unsigned char *)dupstring((char *)zleline); + oll = zlemetall; + ocs = zlemetacs; + ol = (unsigned char *)dupstring((char *)zlemetaline); expanding = 1; - excs = zlecs; - zlell = zlecs = 0; + excs = zlemetacs; + zlemetall = zlemetacs = 0; lexsave(); /* We push ol as it will remain unchanged */ inpush((char *) ol, 0, NULL); @@ -2283,8 +2337,8 @@ doexpandhist(void) expanding = 0; if (!err) { - zlecs = excs; - if (strcmp((char *)zleline, (char *)ol)) { + zlemetacs = excs; + if (strcmp((char *)zlemetaline, (char *)ol)) { unmetafy_line(); /* For vi mode -- reset the beginning-of-insertion pointer * * to the beginning of the line. This seems a little silly, * @@ -2296,9 +2350,9 @@ doexpandhist(void) } } - strcpy((char *)zleline, (char *)ol); - zlell = oll; - zlecs = ocs; + strcpy((char *)zlemetaline, (char *)ol); + zlemetall = oll; + zlemetacs = ocs; unmetafy_line(); popheap(); @@ -2325,26 +2379,35 @@ fixmagicspace(void) int magicspace(char **args) { - char *bangq; + ZLE_STRING_T bangq; + ZLE_CHAR_T zlebangchar[1]; int ret; fixmagicspace(); - for (bangq = (char *)zleline; (bangq = strchr(bangq, bangchar)); - bangq += 2) - if (bangq[1] == '"' && (bangq == (char *)zleline || bangq[-1] != '\\')) - break; + #ifdef ZLE_UNICODE_SUPPORT /* - * TODO: expansion and completion with Unicode are currently - * fundamentally broken. Most of the code for this hasn't been - * commented out, but crashing the shell just because you entered - * a space seems to be worth guarding against. + * TODO: bangchar should really be a multibyte string representing + * a single character, since there's no fundamental reason why + * it shouldn't be a Unicode character. In practice this is + * very minor, however. */ - ret = selfinsert(args); + if (mbtowc(zlebangchar, (char *)&bangchar, 1) < 0) + return selfinsert(args); #else + zlebangchar[0] = bangchar; +#endif + for (bangq = zleline; bangq < zleline + zlell; bangq++) + { + if (*bangq != zlebangchar[0]) + continue; + if (bangq[1] == ZWC('"') && + (bangq == zleline || bangq[-1] == ZWC('\\'))) + break; + } + if (!(ret = selfinsert(args)) && - (!bangq || bangq + 2 > (char *)zleline + zlecs)) + (!bangq || bangq + 2 > zleline + zlecs)) doexpandhist(); -#endif return ret; } @@ -2369,8 +2432,7 @@ getcurcmd(void) zleparse = 2; lexsave(); metafy_line(); - inpush(dupstrspace((char *) zleline), 0, NULL); - unmetafy_line(); + inpush(dupstrspace((char *) zlemetaline), 0, NULL); strinbeg(1); pushheap(); do { @@ -2381,8 +2443,8 @@ getcurcmd(void) if (tok == STRING && curlincmd) { zsfree(s); s = ztrdup(tokstr); - cmdwb = zlell - wordbeg; - cmdwe = zlell + 1 - inbufct; + cmdwb = zlemetall - wordbeg; + cmdwe = zlemetall + 1 - inbufct; } } while (tok != ENDINPUT && tok != LEXERR && zleparse); @@ -2390,6 +2452,7 @@ getcurcmd(void) strinend(); inpop(); errflag = zleparse = 0; + unmetafy_line(); lexrestore(); return s; @@ -2426,8 +2489,13 @@ processcmd(UNUSED(char **args)) int expandcmdpath(UNUSED(char **args)) { - int oldcs = zlecs, na = noaliases; + /* + * zleline is not metafied for most of this function + * (that happens within getcurcmd()). + */ + int oldcs = zlecs, na = noaliases, strll; char *s, *str; + ZLE_STRING_T zlestr; noaliases = 1; s = getcurcmd(); @@ -2440,8 +2508,11 @@ expandcmdpath(UNUSED(char **args)) return 1; zlecs = cmdwb; foredel(cmdwe - cmdwb); - spaceinline(strlen(str)); - strncpy((char *)zleline + zlecs, str, strlen(str)); + zlestr = stringaszleline((unsigned char *)str, 0, + &strll, NULL, NULL); + spaceinline(strll); + ZS_strncpy(zleline + zlecs, zlestr, strll); + free(zlestr); zlecs = oldcs; if (zlecs >= cmdwe - 1) zlecs += cmdwe - cmdwb + strlen(str); @@ -2461,7 +2532,7 @@ expandorcompleteprefix(char **args) comppref = 1; ret = expandorcomplete(args); - if (zlecs && zleline[zlecs - 1] == ' ') + if (zlecs && zleline[zlecs - 1] == ZWC(' ')) makesuffixstr(NULL, "\\-", 0); comppref = 0; return ret; diff --git a/Src/Zle/zle_utils.c b/Src/Zle/zle_utils.c index aa691bcdc..f8c4d2013 100644 --- a/Src/Zle/zle_utils.c +++ b/Src/Zle/zle_utils.c @@ -66,21 +66,36 @@ int linesz; void sizeline(int sz) { - while (sz > linesz) + int cursz = (zlemetaline != NULL) ? metalinesz : linesz; + + while (sz > cursz) { - if (linesz < 256) - linesz = 256; + if (cursz < 256) + cursz = 256; else - linesz *= 4; + cursz *= 4; - zleline = - (ZLE_STRING_T)realloc(zleline, - (linesz + 2) * ZLE_CHAR_SIZE); + if (zlemetaline != NULL) { + /* One spare character for the NULL */ + zlemetaline = (unsigned char *)realloc(zlemetaline, cursz + 1); + } else { + /* One spare character for the NULL, one for the newline */ + zleline = + (ZLE_STRING_T)realloc(zleline, + (cursz + 2) * ZLE_CHAR_SIZE); + } } + + if (zlemetaline != NULL) + metalinesz = cursz; + else + linesz = cursz; } /* * Insert a character, called from main shell. + * Note this always operates on the metafied multibyte version of the + * line. */ /**/ @@ -88,20 +103,7 @@ mod_export void zleaddtoline(int chr) { spaceinline(1); -#ifdef ZLE_UNICODE_SUPPORT - /* - * TODO: the main shell has as yet very little notion of multibyte - * characters. Until this gets fixed we just have to assume - * this is a complete character. - * - * Possibly we could get away with attempting to build up a - * multibyte character here, storing partial characters between - * calls. - */ - zleline[zlecs++] = (ZLE_CHAR_T)chr; -#else - zleline[zlecs++] = chr; -#endif + zlemetaline[zlemetacs++] = chr; } /* @@ -125,9 +127,11 @@ zleaddtoline(int chr) /**/ mod_export unsigned char * -zlelineasstring(ZLE_STRING_T instr, int inll, int incs, int *outll, - int *outcs, int useheap) +zlelineasstring(ZLE_STRING_T instr, int inll, int incs, int *outllp, + int *outcsp, int useheap) { + int outcs, outll; + #ifdef ZLE_UNICODE_SUPPORT char *s; int i, j; @@ -135,9 +139,10 @@ zlelineasstring(ZLE_STRING_T instr, int inll, int incs, int *outll, s = zalloc(inll * MB_CUR_MAX + 1); + outcs = 0; for(i=0; i < inll; i++, incs--) { - if (outcs != NULL && incs == 0) - *outcs = mb_len; + if (incs == 0) + outcs = mb_len; j = wctomb(s + mb_len, instr[i]); if (j == -1) { /* invalid char; what to do? */ @@ -147,8 +152,41 @@ zlelineasstring(ZLE_STRING_T instr, int inll, int incs, int *outll, } s[mb_len] = '\0'; - if (outll != NULL) - *outll = mb_len; + outll = mb_len; +#else + outll = inll; + outcs = incs; +#endif + + /* + * *outcsp and *outllp are to be indexes into the final string, + * not character offsets, so we need to take account of any + * metafiable characters. + */ + if (outcsp != NULL || outllp != NULL) { +#ifdef ZLE_UNICODE_SUPPORT + unsigned char *strp = (unsigned char *)s; +#else + unsigned char *strp = instr; +#endif + unsigned char *stopcs = strp + outcs; + unsigned char *stopll = strp + outll; + + while (strp < stopll) { + if (imeta(*strp)) { + if (strp < stopcs) + outcs++; + outll++; + } + strp++; + } + if (outcsp != NULL) + *outcsp = outcs; + if (outllp != NULL) + *outllp = outll; + } + +#ifdef ZLE_UNICODE_SUPPORT if (useheap) { unsigned char *ret = @@ -163,11 +201,6 @@ zlelineasstring(ZLE_STRING_T instr, int inll, int incs, int *outll, return (unsigned char *) metafy((char *) s, mb_len, META_REALLOC); } #else - if (outll != NULL) - *outll = inll; - if (outcs != NULL) - *outcs = incs; - return (unsigned char *) metafy((char *) instr, inll, useheap ? META_HEAPDUP : META_DUP); #endif @@ -186,6 +219,11 @@ zlelineasstring(ZLE_STRING_T instr, int inll, int incs, int *outll, * may take a newline and a null at a later stage.) These are not * included in *outsz. * + * If outcs is non-NULL, the character position in the original + * string incs (a standard string offset, i.e. incremented 2 for + * each metafied character) is converted into the corresponding + * character position in *outcs. + * * Note that instr is modified in place, hence should be copied * first if necessary; * @@ -196,7 +234,8 @@ zlelineasstring(ZLE_STRING_T instr, int inll, int incs, int *outll, /**/ mod_export ZLE_STRING_T -stringaszleline(unsigned char *instr, int *outll, int *outsz) +stringaszleline(unsigned char *instr, int incs, + int *outll, int *outsz, int *outcs) { ZLE_STRING_T outstr; int ll, sz; @@ -204,7 +243,23 @@ stringaszleline(unsigned char *instr, int *outll, int *outsz) mbstate_t ps; #endif - unmetafy(instr, &ll); + if (outcs) { + /* + * Take account of Meta characters in the input string + * before we unmetafy it. This does not yet take account + * of multibyte characters. If there are none, this + * is all the processing required to calculate outcs. + */ + unsigned char *inptr = instr, *cspos = instr + incs; + while (*inptr && inptr < cspos) { + if (*inptr == STOUC(Meta)) { + inptr++; + incs--; + } + inptr++; + } + } + unmetafy((char *)instr, &ll); /* * ll is the maximum number of characters there can be in @@ -246,29 +301,53 @@ stringaszleline(unsigned char *instr, int *outll, int *outsz) if (*outptr == L'\0' && ret == 0) ret = 1; + if (outcs) { + int offs = inptr - (char *)instr; + if (offs <= incs && incs < offs + ret) + *outcs = outptr - outstr; + } + inptr += ret; outptr++; ll -= ret; } *outll = outptr - outstr; - } - else + } else { *outll = 0; + if (outcs) + *outcs = 0; + } #else memcpy((char *)outstr, (char *)instr, ll); *outll = ll; + if (outcs) + *outcs = incs; #endif return outstr; } - +/* + * This function is called when we are playing very nasty tricks + * indeed: see bufferwords in hist.c. Consequently we can make + * absolutely no assumption about the state whatsoever, except + * that it has one. + */ /**/ mod_export unsigned char * zlegetline(int *ll, int *cs) { - return zlelineasstring(zleline, zlell, zlecs, ll, cs, 0); + if (zlemetaline != NULL) { + *ll = zlemetall; + *cs = zlemetacs; + return (unsigned char *)ztrdup((char *)zlemetaline); + } else if (zleline) { + return zlelineasstring(zleline, zlell, zlecs, ll, cs, 0); + } else { + *ll = *cs = 0; + return (unsigned char *)ztrdup(""); + } } @@ -280,14 +359,25 @@ spaceinline(int ct) { int i; - sizeline(ct + zlell); - for (i = zlell; --i >= zlecs;) - zleline[i + ct] = zleline[i]; - zlell += ct; - zleline[zlell] = ZWC('\0'); + if (zlemetaline) { + sizeline(ct + zlemetall); + for (i = zlemetall; --i >= zlemetacs;) + zlemetaline[i + ct] = zlemetaline[i]; + zlemetall += ct; + zlemetaline[zlemetall] = '\0'; - if (mark > zlecs) - mark += ct; + if (mark > zlemetacs) + mark += ct; + } else { + sizeline(ct + zlell); + for (i = zlell; --i >= zlecs;) + zleline[i + ct] = zleline[i]; + zlell += ct; + zleline[zlell] = ZWC('\0'); + + if (mark > zlecs) + mark += ct; + } } /**/ @@ -299,11 +389,19 @@ shiftchars(int to, int cnt) else if (mark > to) mark = to; - while (to + cnt < zlell) { - zleline[to] = zleline[to + cnt]; - to++; + if (zlemetaline) { + while (to + cnt < zlemetall) { + zlemetaline[to] = zlemetaline[to + cnt]; + to++; + } + zlemetaline[zlemetall = to] = '\0'; + } else { + while (to + cnt < zlell) { + zleline[to] = zleline[to + cnt]; + to++; + } + zleline[zlell = to] = ZWC('\0'); } - zleline[zlell = to] = ZWC('\0'); } /**/ @@ -333,6 +431,7 @@ cut(int i, int ct, int dir) if (!ct) return; + UNMETACHECK(); if (zmod.flags & MOD_VIBUF) { struct cutbuffer *b = &vibuf[zmod.vibuf]; @@ -411,14 +510,20 @@ cut(int i, int ct, int dir) mod_export void backdel(int ct) { - shiftchars(zlecs -= ct, ct); + if (zlemetaline != NULL) + shiftchars(zlemetacs -= ct, ct); + else + shiftchars(zlecs -= ct, ct); } /**/ mod_export void foredel(int ct) { - shiftchars(zlecs, ct); + if (zlemetaline != NULL) + shiftchars(zlemetacs, ct); + else + shiftchars(zlecs, ct); } /**/ @@ -437,7 +542,7 @@ setline(char *s, int flags) */ free(zleline); - zleline = stringaszleline(scp, &zlell, &linesz); + zleline = stringaszleline((unsigned char *)scp, 0, &zlell, &linesz, NULL); if ((flags & ZSL_TOEND) && (zlecs = zlell) && invicmdmode()) zlecs--; @@ -760,6 +865,19 @@ freechanges(struct change *p) mod_export void handleundo(void) { + int remetafy; + + /* + * Yuk: we call this from within the completion system, + * so we need to convert back to the form which can be + * copied into undo entries. + */ + if (zlemetaline != NULL) { + unmetafy_line(); + remetafy = 1; + } else + remetafy = 0; + mkundoent(); if(!nextchanges) return; @@ -780,6 +898,9 @@ handleundo(void) curchange->prev = endnextchanges; endnextchanges->next = curchange; nextchanges = endnextchanges = NULL; + + if (remetafy) + metafy_line(); } /* add an entry to the undo system, if anything has changed */ @@ -792,7 +913,8 @@ mkundoent(void) int sh = zlell < lastll ? zlell : lastll; struct change *ch; - if(lastll == zlell && !memcmp(lastline, zleline, zlell * ZLE_CHAR_SIZE)) + UNMETACHECK(); + if(lastll == zlell && !ZS_memcmp(lastline, zleline, zlell)) return; for(pre = 0; pre < sh && zleline[pre] == lastline[pre]; ) pre++; @@ -840,6 +962,7 @@ mkundoent(void) void setlastline(void) { + UNMETACHECK(); if(lastlinesz != linesz) lastline = realloc(lastline, (lastlinesz = linesz) * ZLE_CHAR_SIZE); ZS_memcpy(lastline, zleline, (lastll = zlell)); diff --git a/Src/hist.c b/Src/hist.c index 6b3aa3b33..00773cd74 100644 --- a/Src/hist.c +++ b/Src/hist.c @@ -222,12 +222,12 @@ iaddtoline(int c) exlast--; zleaddtolineptr('\\'); } - if (excs > zlecs) { + if (excs > zlemetacs) { excs += 1 + inbufct - exlast; - if (excs < zlecs) + if (excs < zlemetacs) /* this case could be handled better but it is * * so rare that it does not worth it */ - excs = zlecs; + excs = zlemetacs; } exlast = inbufct; zleaddtolineptr(itok(c) ? ztokens[c - Pound] : c); @@ -662,8 +662,8 @@ ihungetc(int c) hungetc('\n'), hungetc('\\'); if (expanding) { - zlecs--; - zlell--; + zlemetacs--; + zlemetall--; exlast++; } DPUTS(hptr <= chline, "BUG: hungetc attempted at buffer start"); @@ -2241,15 +2241,27 @@ histfileIsLocked(void) return lockhistct > 0; } -/* Get the words in the current buffer. Using the lexer. */ +/* + * Get the words in the current buffer. Using the lexer. + * + * As far as I can make out, this is a gross hack based on a gross hack. + * When analysing lines from within zle, we tweak the metafied line + * positions (zlemetall and zlemetacs) directly in the lexer. That's + * bad enough, but this function appears to be designed to be called + * from outside zle, pretending to be in zle and calling out, so + * we set zlemetall and zlemetacs locally and copy the current zle line, + * which may not even be valid at this point. + * + * However, I'm so confused it could simply be baking Bakewell tarts. + */ /**/ mod_export LinkList bufferwords(LinkList list, char *buf, int *index) { - int num = 0, cur = -1, got = 0, ne = noerrs, ocs = zlecs, oll = zlell; + int num = 0, cur = -1, got = 0, ne = noerrs; int owb = wb, owe = we, oadx = addedx, ozp = zleparse, onc = nocomments; - int ona = noaliases; + int ona = noaliases, ocs = zlemetacs, oll = zlemetall; char *p; if (!list) @@ -2267,47 +2279,47 @@ bufferwords(LinkList list, char *buf, int *index) p[l] = ' '; p[l + 1] = '\0'; inpush(p, 0, NULL); - zlell = strlen(p) ; - zlecs = zlell + 1; + zlemetall = strlen(p) ; + zlemetacs = zlemetall + 1; nocomments = 1; } else { int ll, cs; char *linein; if (zlegetlineptr) { - linein = zlegetlineptr(&ll, &cs); + linein = (char *)zlegetlineptr(&ll, &cs); } else { linein = ztrdup(""); ll = cs = 0; } - zlell = ll + 1; /* length of line plus space added below */ - zlecs = cs; + zlemetall = ll + 1; /* length of line plus space added below */ + zlemetacs = cs; if (!isfirstln && chline) { p = (char *) zhalloc(hptr - chline + ll + 2); memcpy(p, chline, hptr - chline); memcpy(p + (hptr - chline), linein, ll); p[(hptr - chline) + ll] = ' '; - p[(hptr - chline) + zlell] = '\0'; + p[(hptr - chline) + zlemetall] = '\0'; inpush(p, 0, NULL); /* * advance line length and character position over * prepended string. */ - zlell += hptr - chline; - zlecs += hptr - chline; + zlemetall += hptr - chline; + zlemetacs += hptr - chline; } else { p = (char *) zhalloc(ll + 2); memcpy(p, linein, ll); p[ll] = ' '; - p[zlell] = '\0'; + p[zlemetall] = '\0'; inpush(p, 0, NULL); } - zsfree(linein); + zsfree(linein); } - if (zlecs) - zlecs--; + if (zlemetacs) + zlemetacs--; strinbeg(0); noaliases = 1; do { @@ -2363,8 +2375,8 @@ bufferwords(LinkList list, char *buf, int *index) nocomments = onc; noerrs = ne; lexrestore(); - zlecs = ocs; - zlell = oll; + zlemetacs = ocs; + zlemetall = oll; wb = owb; we = owe; addedx = oadx; diff --git a/Src/lex.c b/Src/lex.c index 482090ad1..bf2adb1dc 100644 --- a/Src/lex.c +++ b/Src/lex.c @@ -72,11 +72,12 @@ int inalmore; int nocorrect; /* - * Cursor position and line length in zle + * Cursor position and line length in zle when the line is + * metafied for access from the main shell. */ /**/ -mod_export int zlecs, zlell; +mod_export int zlemetacs, zlemetall; /* inwhat says what exactly we are in * * (its value is one of the IN_* things). */ @@ -521,10 +522,10 @@ add(int c) } } -#define SETPARBEGIN {if (zleparse && !(inbufflags & INP_ALIAS) && zlecs >= zlell+1-inbufct) parbegin = inbufct;} +#define SETPARBEGIN {if (zleparse && !(inbufflags & INP_ALIAS) && zlemetacs >= zlemetall+1-inbufct) parbegin = inbufct;} #define SETPAREND {\ if (zleparse && !(inbufflags & INP_ALIAS) && parbegin != -1 && parend == -1) {\ - if (zlecs >= zlell + 1 - inbufct)\ + if (zlemetacs >= zlemetall + 1 - inbufct)\ parbegin = -1;\ else\ parend = inbufct;} } @@ -1293,7 +1294,7 @@ dquote_parse(char endchar, int sub) int pct = 0, brct = 0, bct = 0, intick = 0, err = 0; int c; int math = endchar == ')' || endchar == ']'; - int zlemath = math && zlecs > zlell + addedx - inbufct; + int zlemath = math && zlemetacs > zlemetall + addedx - inbufct; while (((c = hgetc()) != endchar || bct || (math && ((pct > 0) || (brct > 0))) || @@ -1420,7 +1421,7 @@ dquote_parse(char endchar, int sub) err = intick || endchar || err; else if (err == 1) err = c; - if (zlemath && zlecs <= zlell + 1 - inbufct) + if (zlemath && zlemetacs <= zlemetall + 1 - inbufct) inwhat = IN_MATH; return err; } @@ -1549,9 +1550,9 @@ parse_subst_string(char *s) mod_export void gotword(void) { - we = zlell + 1 - inbufct + (addedx == 2 ? 1 : 0); - if (zlecs <= we) { - wb = zlell - wordbeg + addedx; + we = zlemetall + 1 - inbufct + (addedx == 2 ? 1 : 0); + if (zlemetacs <= we) { + wb = zlemetall - wordbeg + addedx; zleparse = 0; } } diff --git a/Src/utils.c b/Src/utils.c index cafcc7fbc..e7a85f5da 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -2812,7 +2812,7 @@ getbaudrate(struct ttyinfo *shttyinfo) * META_NOALLOC: buf points to a memory area which is long enough to hold * * the quoted form, just quote it and return buf. * * META_STATIC: store the quoted string in a static area. The original * - * string should be at most PATH_MAX long. * + * string should be at most PATH_MAX long. * * META_ALLOC: allocate memory for the new string with zalloc(). * * META_DUP: leave buf unchanged and allocate space for the return * * value even if buf does not contains special characters * -- cgit 1.4.1