diff options
Diffstat (limited to 'Src')
-rw-r--r-- | Src/Zle/comp.h | 12 | ||||
-rw-r--r-- | Src/Zle/comp1.c | 18 | ||||
-rw-r--r-- | Src/Zle/comp1.export | 5 | ||||
-rw-r--r-- | Src/Zle/compctl.c | 30 | ||||
-rw-r--r-- | Src/Zle/zle_main.c | 3 | ||||
-rw-r--r-- | Src/Zle/zle_params.c | 12 | ||||
-rw-r--r-- | Src/Zle/zle_refresh.c | 29 | ||||
-rw-r--r-- | Src/Zle/zle_tricky.c | 441 | ||||
-rw-r--r-- | Src/glob.c | 51 | ||||
-rw-r--r-- | Src/subst.c | 24 | ||||
-rw-r--r-- | Src/utils.c | 5 |
11 files changed, 494 insertions, 136 deletions
diff --git a/Src/Zle/comp.h b/Src/Zle/comp.h index 42a647199..c9d6aa859 100644 --- a/Src/Zle/comp.h +++ b/Src/Zle/comp.h @@ -190,6 +190,7 @@ struct cmgroup { LinkList lmatches; /* list of matches */ LinkList lfmatches; /* list of matches without fignore */ LinkList lallccs; /* list of used compctls */ + int num; /* number of this group */ }; @@ -213,6 +214,8 @@ struct cmatch { int brsl; /* ...and the suffix */ char *rems; /* when to remove the suffix */ char *remf; /* shell function to call for suffix-removal */ + int rnum; /* group relative number */ + int gnum; /* global number */ }; #define CMF_FILE 1 /* this is a file */ @@ -298,7 +301,12 @@ struct cpattern { #define CP_PATINSERT (1 << 23) #define CP_UNAMBIG (1 << 24) #define CP_UNAMBIGC (1 << 25) +#define CP_LISTMAX (1 << 26) +#define CP_LASTPROMPT (1 << 27) +#define CP_TOEND (1 << 28) +#define CP_OLDLIST (1 << 29) +#define CP_OLDINS (1 << 30) -#define CP_NUM 26 +#define CP_NUM 31 -#define CP_ALLMASK ((1 << CP_NUM) - 1) +#define CP_ALLMASK ((int) ((((unsigned int) 1) << CP_NUM) - 1)) diff --git a/Src/Zle/comp1.c b/Src/Zle/comp1.c index 904f66305..fe21b1dfc 100644 --- a/Src/Zle/comp1.c +++ b/Src/Zle/comp1.c @@ -52,7 +52,7 @@ void (*comp_setunsetptr) _((int, int)); /* pointers to functions required by compctl and defined by zle */ /**/ -int (*addmatchesptr) _((char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, int, int, Cmatcher, char *, char **)); +int (*addmatchesptr) _((char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, int, int, Cmatcher, char *, char *, char *, char **)); /**/ char *(*comp_strptr) _((int *, int *, int)); @@ -103,7 +103,8 @@ int incompfunc; long compcurrent, compnmatches, compmatcher, - compmatchertot; + compmatchertot, + complistmax; /**/ char **compwords, @@ -124,7 +125,11 @@ char **compwords, *compexact, *compexactstr, *comppatmatch, - *comppatinsert; + *comppatinsert, + *complastprompt, + *comptoend, + *compoldlist, + *compoldins; /**/ Param *comppms; @@ -439,7 +444,8 @@ setup_comp1(Module m) compcontext = compparameter = compredirect = compquote = compquoting = comprestore = complist = compinsert = compexact = compexactstr = comppatmatch = comppatinsert = - compforcelist = NULL; + compforcelist = complastprompt = comptoend = + compoldlist = compoldins = NULL; makecompparamsptr = NULL; comp_setunsetptr = NULL; return 0; @@ -487,6 +493,10 @@ finish_comp1(Module m) zsfree(compexactstr); zsfree(comppatmatch); zsfree(comppatinsert); + zsfree(complastprompt); + zsfree(comptoend); + zsfree(compoldlist); + zsfree(compoldins); return 0; } diff --git a/Src/Zle/comp1.export b/Src/Zle/comp1.export index 1be9b6492..4f9fb143d 100644 --- a/Src/Zle/comp1.export +++ b/Src/Zle/comp1.export @@ -19,11 +19,15 @@ compforcelist compinsert compiprefix compisuffix +complastprompt complist +complistmax compmatcher compmatcherstr compmatchertot compnmatches +compoldlist +compoldins compparameter comppatinsert comppatmatch @@ -36,6 +40,7 @@ comprestore comp_setunsetptr comp_strptr compsuffix +comptoend compwords freecmatcher freecmlist diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c index 2ebe2d4a4..28c7cb7b7 100644 --- a/Src/Zle/compctl.c +++ b/Src/Zle/compctl.c @@ -1694,7 +1694,7 @@ bin_compadd(char *name, char **argv, char *ops, int func) char *p, **sp, *e; char *ipre = NULL, *isuf = NULL, *ppre = NULL, *psuf = NULL, *prpre = NULL; char *pre = NULL, *suf = NULL, *group = NULL, *m = NULL, *rs = NULL; - char *ign = NULL, *rf = NULL, *expl = NULL; + char *ign = NULL, *rf = NULL, *expl = NULL, *apar = NULL, *opar = NULL; int f = 0, a = CAF_MATCH, dm; Cmatcher match = NULL; @@ -1791,6 +1791,14 @@ bin_compadd(char *name, char **argv, char *ops, int func) sp = &rf; e = "function name expected after -%c"; break; + case 'A': + sp = &apar; + e = "parameter name expected after -%c"; + break; + case 'O': + sp = ⦷ + e = "parameter name expected after -%c"; + break; case '-': argv++; goto ca_args; @@ -1799,15 +1807,13 @@ bin_compadd(char *name, char **argv, char *ops, int func) return 1; } if (sp) { - if (*sp) { - zerrnam(name, "doubled option: -%c", NULL, *p); - return 1; - } if (p[1]) { - *sp = p + 1; + if (!*sp) + *sp = p + 1; p = "" - 1; } else if (argv[1]) { - *sp = *++argv; + if (!*sp) + *sp = *++argv; p = "" - 1; } else { zerrnam(name, e, NULL, *p); @@ -1826,7 +1832,7 @@ bin_compadd(char *name, char **argv, char *ops, int func) match = cpcmatcher(match); a = addmatchesptr(ipre, isuf, ppre, psuf, prpre, pre, suf, group, - rs, rf, ign, f, a, match, expl, argv); + rs, rf, ign, f, a, match, expl, apar, opar, argv); freecmatcher(match); return a; @@ -2152,7 +2158,13 @@ static struct compparam { { "pattern_match", PM_SCALAR, VAL(comppatmatch), NULL, NULL }, { "pattern_insert", PM_SCALAR, VAL(comppatinsert), NULL, NULL }, { "unambiguous", PM_SCALAR | PM_READONLY, NULL, NULL, VAL(get_unambig) }, - { "unambiguous_cursor", PM_INTEGER | PM_READONLY, NULL, NULL, VAL(get_unambig_curs) }, + { "unambiguous_cursor", PM_INTEGER | PM_READONLY, NULL, NULL, + VAL(get_unambig_curs) }, + { "list_max", PM_INTEGER, VAL(complistmax), NULL, NULL }, + { "last_prompt", PM_SCALAR, VAL(complastprompt), NULL, NULL }, + { "to_end", PM_SCALAR, VAL(comptoend), NULL, NULL }, + { "old_list", PM_SCALAR, VAL(compoldlist), NULL, NULL }, + { "old_insert", PM_SCALAR, VAL(compoldins), NULL, NULL }, { NULL, 0, NULL, NULL, NULL } }; diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index 479994249..7a5d0d7db 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -883,7 +883,7 @@ trashzle(void) moveto(nlnct, 0); if (clearflag && tccan(TCCLEAREOD)) { tcout(TCCLEAREOD); - clearflag = 0; + clearflag = listshown = 0; } if (postedit) fprintf(shout, "%s", postedit); @@ -927,6 +927,7 @@ setup_zle(Module m) /* miscellaneous initialisations */ stackhist = stackcs = -1; kungetbuf = (char *) zalloc(kungetsz = 32); + hasperm = 0; /* initialise the keymap system */ init_keymaps(); diff --git a/Src/Zle/zle_params.c b/Src/Zle/zle_params.c index adde116f2..d9fefe659 100644 --- a/Src/Zle/zle_params.c +++ b/Src/Zle/zle_params.c @@ -61,6 +61,8 @@ static struct zleparam { zleunsetfn, NULL }, { "RBUFFER", PM_SCALAR, FN(set_rbuffer), FN(get_rbuffer), zleunsetfn, NULL }, + { "PREBUFFER", PM_SCALAR | PM_READONLY, NULL, FN(get_prebuffer), + zleunsetfn, NULL }, { "WIDGET", PM_SCALAR | PM_READONLY, NULL, FN(get_widget), zleunsetfn, NULL }, { "LASTWIDGET", PM_SCALAR | PM_READONLY, NULL, FN(get_lwidget), @@ -212,6 +214,16 @@ get_rbuffer(Param pm) /**/ static char * +get_prebuffer(Param pm) +{ + if (chline) + return dupstrpfx(chline, hptr - chline); + else + return dupstring(""); +} + +/**/ +static char * get_widget(Param pm) { return bindk->nam; diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c index b9f39b70b..1f1063b8d 100644 --- a/Src/Zle/zle_refresh.c +++ b/Src/Zle/zle_refresh.c @@ -53,6 +53,11 @@ int nlnct; /**/ int showinglist; +/* Non-zero if a completion list was displayed. */ + +/**/ +int listshown; + /* Non-zero if ALWAYS_LAST_PROMPT has been used, meaning that the * * screen below the buffer display should not be cleared by * * zrefresh(), but should be by trashzle(). */ @@ -253,13 +258,23 @@ zrefresh(void) if (inlist) return; - if (clearlist) { - invalidatelist(); - moveto(0, 0); - clearflag = 0; - resetneeded = 1; - clearlist = 0; + if (clearlist && listshown) { + if (tccan(TCCLEAREOD)) { + int ovln = vln, ovcs = vcs; + + moveto(nlnct, 0); + tcout(TCCLEAREOD); + moveto(ovln, ovcs); + } else { + invalidatelist(); + moveto(0, 0); + clearflag = 0; + resetneeded = 1; + } + listshown = 0; } + clearlist = 0; + #ifdef HAVE_SELECT cost = 0; /* reset */ #endif @@ -287,6 +302,7 @@ zrefresh(void) moveto(0, 0); t0 = olnct; /* this is to clear extra lines even when */ winchanged = 0; /* the terminal cannot TCCLEAREOD */ + listshown = 0; } #endif resetvideo(); @@ -303,6 +319,7 @@ zrefresh(void) tcout(TCCLEAREOD); else cleareol = 1; /* request: clear to end of line */ + listshown = 0; } if (t0 > -1) olnct = t0; diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c index 4ae7495c3..1f13d55b4 100644 --- a/Src/Zle/zle_tricky.c +++ b/Src/Zle/zle_tricky.c @@ -72,12 +72,27 @@ static int wb, we; static int offs; -/* These control the type of completion that will be done. They are * - * affected by the choice of ZLE command and by relevant shell options. * - * usemenu is set to 2 if we have to start automenu. */ +/* These control the type of completion that will be done. They are * + * affected by the choice of ZLE command and by relevant shell options. * + * usemenu is set to 2 if we have to start automenu and 3 if we have to * + * insert a match as if for menucompletion but without really stating it. */ static int usemenu, useglob, useexact, useline, uselist; +/* Non-zero if we should keep an old list. */ + +static int oldlist, oldins; + +/* The match and group number to insert when starting menucompletion. */ + +static int insmnum, insgnum, insgroup; + +/* This is used to decide when the cursor should be moved to the end of * + * the inserted word: 0 - never, 1 - only when a single match is inserted, * + * 2 - when a full match is inserted (single or menu), 3 - always. */ + +static int movetoend; + /* != 0 if we are in the middle of a menu completion */ static int menucmp; @@ -99,12 +114,12 @@ static int menupos, menulen, menuend, menuwe, menuinsc; /* This is for completion inside a brace expansion. brbeg and brend hold * * strings that were temporarily removed from the string to complete. * - * brpl and brsl, brbsl hold the offset of these strings. * + * brpl and brsl, hold the offset of these strings. * * brpcs and brscs hold the positions of the re-inserted string in the * * line. */ static char *brbeg = NULL, *brend = NULL; -static int brpl, brsl, brbsl, brpcs, brscs; +static int brpl, brsl, brpcs, brscs, qbrpl, qbrsl, hasunqu; /* The list of matches. fmatches contains the matches we first ignore * * because of fignore. */ @@ -114,7 +129,16 @@ static LinkList matches, fmatches; /* This holds the list of matches-groups. lmatches is a pointer to the * * last element in this list. */ -static Cmgroup amatches, lmatches; +static Cmgroup pmatches, amatches, lmatches; + +/* Non-zero if we have permanently allocated matches. */ + +/**/ +int hasperm; + +/* Number of permanently allocated matches and groups. */ + +static int permmnum, permgnum; /* The total number of matches and the number of matches to be listed. */ @@ -155,6 +179,7 @@ static char *ppre, *psuf, *lppre, *lpsuf, *prpre; static char *fpre, *fsuf; static char *ipre, *ripre; static char *isuf; +static char *qfpre, *qfsuf, *qrpre, *qrsuf, *qlpre, *qlsuf; static int lpl, lsl, rpl, rsl, fpl, fsl, lppl, lpsl; static int noreal; @@ -485,14 +510,9 @@ reversemenucomplete(void) * with the next completions. This gives you a way to * * accept several selections from the list of matches. */ -/**/ -void -acceptandmenucomplete(void) +static void +acceptlast(void) { - if (!menucmp) { - feep(); - return; - } if (brbeg && *brbeg) { int l; @@ -514,6 +534,17 @@ acceptandmenucomplete(void) menupos = cs; menuwe = 1; } +} + +/**/ +void +acceptandmenucomplete(void) +{ + if (!menucmp) { + feep(); + return; + } + acceptlast(); menucomplete(); } @@ -650,7 +681,13 @@ check_param(char *s, int set) int n = 0, br = 1; if (*b == Inbrace) { - /* If this is a ${...}, ignore the possible (...) flags. */ + char *tb = b; + + /* If this is a ${...}, see if we are before the '}'. */ + if (!skipparens(Inbrace, Outbrace, &tb)) + return NULL; + + /* Ignore the possible (...) flags. */ b++, br++; n = skipparens(Inpar, Outpar, &b); } @@ -1494,11 +1531,13 @@ get_comp_string(void) if (tt && tt < s + myoffs) { /* Braces are go: delete opening brace */ - char *com = NULL; + char *com = NULL, *tmp; int pl, sl; brbeg = dupstring(tt); brpl = tt - s; + tmp = dupstrpfx(s, tt - s); + qbrpl = strlen(quotename(tmp, NULL)); pl = 1; sl = 0; chuck(tt); @@ -1531,8 +1570,8 @@ get_comp_string(void) if (*p == Outbrace) chuck(p); brsl = strlen(s) - (p - s); - brbsl = p - s; brend[sl] = '\0'; + qbrsl = strlen(quotename(p, NULL)); } /* we are still waiting for an outbrace and maybe commas */ if (brbeg) @@ -2040,7 +2079,7 @@ static int match_str(char *l, char *w, int *bp, int *rwlp, int sfx, int test) { int ll = strlen(l), lw = strlen(w), oll = ll, olw = lw; - int il = 0, iw = 0, t, ind, add, bc; + int il = 0, iw = 0, t, ind, add, bc = (bp ? *bp : 0); VARARR(unsigned char, ea, ll + 1); char *ow; Cmlist ms; @@ -2054,9 +2093,9 @@ match_str(char *l, char *w, int *bp, int *rwlp, int sfx, int test) if (sfx) { l += ll; w += lw; - ind = -1; add = -1; bc = brsl; + ind = -1; add = -1; } else { - ind = 0; add = 1; bc = brpl; + ind = 0; add = 1; } /* ow will always point to the beginning (or end) of that sub-string * in w that wasn't put in the match-variables yet. */ @@ -2406,17 +2445,19 @@ comp_match(char *pfx, char *sfx, char *w, Comp cp, wl = strlen(w); *clp = bld_parts(w, wl, wl, NULL); *exact = 0; + *bpl = (qu ? qbrpl : brpl); + *bsl = (qu ? qbrsl : brsl); } else { Cline pli, plil; int mpl, rpl, wl; - if (qu) - w = quotename(w, NULL); + w = (qu ? quotename(w, NULL) : dupstring(w)); wl = strlen(w); /* Always try to match the prefix. */ + *bpl = (qu ? qbrpl : brpl); if ((mpl = match_str(pfx, w, bpl, &rpl, 0, 0)) < 0) return NULL; @@ -2441,6 +2482,7 @@ comp_match(char *pfx, char *sfx, char *w, Comp cp, plil = matchlastpart; /* The try to match the suffix. */ + *bsl = (qu ? qbrsl : brsl); if ((msl = match_str(sfx, w + mpl, bsl, &rsl, 1, 0)) < 0) { free_cline(pli); @@ -2479,6 +2521,7 @@ comp_match(char *pfx, char *sfx, char *w, Comp cp, pli = matchparts; } r = dupstring(matchbuf); + *clp = pli; /* Test if the string built is equal to the one from the line. */ @@ -2489,6 +2532,9 @@ comp_match(char *pfx, char *sfx, char *w, Comp cp, } else *exact = !strcmp(pfx, w); } + if (!qu) + hasunqu = 1; + return r; } @@ -3398,6 +3444,22 @@ add_match_data(int alt, char *str, Cline line, return cm; } +/* This stores the strings from the list in an array. */ + +static void +set_param(char *name, LinkList l) +{ + char **a, **p; + LinkNode n; + + a = (char **) zalloc((countlinknodes(l) + 1) * sizeof(char *)); + for (p = a, n = firstnode(l); n; incnode(n)) + *p++ = ztrdup((char *) getdata(n)); + *p = NULL; + + setaparam(name, a); +} + /* This is used by compadd to add a couple of matches. The arguments are * the strings given via options. The last argument is the array with * the matches. */ @@ -3407,22 +3469,29 @@ int addmatches(char *ipre, char *isuf, char *ppre, char *psuf, char *prpre, char *pre, char *suf, char *group, char *rems, char *remf, char *ign, - int flags, int aflags, Cmatcher match, char *exp, char **argv) + int flags, int aflags, Cmatcher match, char *exp, + char *apar, char *opar, char **argv) { char *s, *ms, *lipre = NULL, *lisuf = NULL, *lpre = NULL, *lsuf = NULL; char **aign = NULL; int lpl, lsl, pl, sl, bpl, bsl, llpl = 0, llsl = 0, nm = mnum; - int oisalt = 0, isalt, isexact; + int oisalt = 0, isalt, isexact, doadd; Cline lc = NULL; Cmatch cm; struct cmlist mst; Cmlist oms = mstack; Comp cp = NULL; + LinkList aparl = NULL, oparl = NULL; /* Switch back to the heap that was used when the completion widget * was invoked. */ SWITCHHEAPS(compheap) { HEAPALLOC { + doadd = (!apar && !opar); + if (apar) + aparl = newlinklist(); + if (opar) + oparl = newlinklist(); if (exp) { expl = (Cexpl) zhalloc(sizeof(struct cexpl)); expl->count = expl->fcount = 0; @@ -3548,9 +3617,17 @@ addmatches(char *ipre, char *isuf, rems = NULL; } else if (rems) rems = dupstring(rems); + + /* Probably quote the prefix and suffix for testing. */ + if (!cp && (aflags & CAF_MATCH) && !(aflags & CAF_QUOTE)) { + lpre = quotename(lpre, NULL); + lsuf = quotename(lsuf, NULL); + llpl = strlen(lpre); + llsl = strlen(lsuf); + } } /* Walk through the matches given. */ - for (; (s = dupstring(*argv)); argv++) { + for (; (s = *argv); argv++) { sl = strlen(s); bpl = brpl; bsl = brsl; @@ -3565,25 +3642,40 @@ addmatches(char *ipre, char *isuf, if ((filell = strlen(*pt)) < sl && !strcmp(*pt, s + sl - filell)) isalt = 1; + + if (isalt && !doadd) + continue; } if (!(aflags & CAF_MATCH)) { - ms = s; - lc = bld_parts(s, sl, -1, NULL); + ms = dupstring(s); + lc = bld_parts(ms, sl, -1, NULL); isexact = 0; } else if (!(ms = comp_match(lpre, lsuf, s, cp, &lc, - (aflags & CAF_QUOTE), + !(aflags & CAF_QUOTE), &bpl, &bsl, &isexact))) continue; - cm = add_match_data(isalt, ms, lc, ipre, ipre, isuf, pre, prpre, - ppre, psuf, suf, bpl, bsl, - flags, isexact); - cm->rems = rems; - cm->remf = remf; + if (doadd) { + cm = add_match_data(isalt, ms, lc, ipre, ipre, isuf, pre, + prpre, ppre, psuf, suf, bpl, bsl, + flags, isexact); + cm->rems = rems; + cm->remf = remf; + } else { + if (apar) + addlinknode(aparl, ms); + if (opar) + addlinknode(oparl, s); + free_cline(lc); + } } compnmatches = mnum; if (exp) addexpl(); + if (apar) + set_param(apar, aparl); + if (opar) + set_param(opar, oparl); } LASTALLOC; } SWITCHBACKHEAPS; @@ -3629,9 +3721,6 @@ addmatch(char *s, char *t) hn = (HashNode) t; pm = (Param) t; - if (incompfunc) - s = dupstring(s); - if (addwhat == -1 || addwhat == -5 || addwhat == -6 || addwhat == CC_FILES || addwhat == -7 || addwhat == -8) { if ((addwhat == CC_FILES || @@ -3645,10 +3734,13 @@ addmatch(char *s, char *t) !strcmp(*pt, s + sl - filell)) isalt = 1; } - if (!(ms = comp_match(fpre, fsuf, s, filecomp, &lc, - (addwhat == CC_FILES || addwhat == -6 || - addwhat == -5 || addwhat == -8), - &bpl, &bsl, &isexact))) + ms = ((addwhat == CC_FILES || addwhat == -6 || + addwhat == -5 || addwhat == -8) ? + comp_match(qfpre, qfsuf, s, filecomp, &lc, 1, + &bpl, &bsl, &isexact) : + comp_match(fpre, fsuf, s, filecomp, &lc, 0, + &bpl, &bsl, &isexact)); + if (!ms) return; if (addwhat == -7 && !findcmd(s, 0)) @@ -3678,10 +3770,19 @@ addmatch(char *s, char *t) (((addwhat & CC_DISCMDS) && (hn->flags & DISABLED)) || ((addwhat & CC_EXCMDS) && !(hn->flags & DISABLED)))) || ((addwhat & CC_BINDINGS) && !(hn->flags & DISABLED))))) { - if (!(ms = comp_match(rpre, rsuf, s, patcomp, &lc, + char *p1, *s1, *p2, *s2; + + if (addwhat == CC_QUOTEFLAG) { + p1 = qrpre; s1 = qrsuf; + p2 = rpre; s2 = rsuf; + } else { + p1 = qlpre; s1 = qlsuf; + p2 = lpre; s2 = lsuf; + } + if (!(ms = comp_match(p1, s1, s, patcomp, &lc, (addwhat == CC_QUOTEFLAG), &bpl, &bsl, &isexact)) && - !(ms = comp_match(lpre, lsuf, s, NULL, &lc, + !(ms = comp_match(p2, s2, s, NULL, &lc, (addwhat == CC_QUOTEFLAG), &bpl, &bsl, &isexact))) return; @@ -4002,6 +4103,7 @@ docompletion(char *s, int lst, int incmd) ainfo = fainfo = NULL; matchers = newlinklist(); + hasunqu = 0; useline = (lst != COMP_LIST_COMPLETE); useexact = (isset(RECEXACT) && usemenu != 1); uselist = (useline ? @@ -4014,6 +4116,12 @@ docompletion(char *s, int lst, int incmd) zsfree(compforcelist); compforcelist = ztrdup(""); haspattern = 0; + complistmax = getiparam("LISTMAX"); + zsfree(complastprompt); + complastprompt = ztrdup(((isset(ALWAYSLASTPROMPT) && zmult == 1) || + (unset(ALWAYSLASTPROMPT) && zmult != 1)) ? + "yes" : ""); + movetoend = ((cs == we || isset(ALWAYSTOEND)) ? 2 : 1); /* Make sure we have the completion list and compctl. */ if (makecomplist(s, incmd, lst)) { @@ -4031,7 +4139,7 @@ docompletion(char *s, int lst, int incmd) /* We have matches. */ if (nmatches > 1) /* There is more than one match. */ - do_ambiguous(); + do_ambiguous(); else if (nmatches == 1) { /* Only one match. */ @@ -4039,6 +4147,7 @@ docompletion(char *s, int lst, int incmd) while (!m->mcount) m = m->next; + menucur = NULL; do_single(m->matches[0]); invalidatelist(); } @@ -4069,9 +4178,8 @@ docompletion(char *s, int lst, int incmd) g = g->next; } if (!tr) { - clearflag = ((isset(USEZLE) && !termflags && - (isset(ALWAYSLASTPROMPT) && zmult == 1)) || - (unset(ALWAYSLASTPROMPT) && zmult != 1)); + clearflag = (isset(USEZLE) && !termflags && + complastprompt && *complastprompt); if (clearflag && up + nlnct < lines) tcmultout(TCUP, TCMULTUP, up + nlnct); @@ -4099,7 +4207,8 @@ callcompfunc(char *s, char *fn) { List list; int lv = lastval; - + char buf[20]; + if ((list = getshfunc(fn)) != &dummy_list) { char **p, *tmp; int set, aadd = 0, usea = 1, icf = incompfunc, osc = sfcontext; @@ -4108,7 +4217,10 @@ callcompfunc(char *s, char *fn) comppms = (Param *) zalloc(CP_NUM * sizeof(Param)); set = -1 & ~(CP_PARAMETER | CP_REDIRECT | CP_QUOTE | CP_QUOTING | - CP_EXACTSTR | CP_FORCELIST | (useglob ? 0 : CP_PATMATCH)); + CP_EXACTSTR | CP_FORCELIST | CP_OLDLIST | CP_OLDINS | + (useglob ? 0 : CP_PATMATCH)); + if (!*complastprompt) + set &= ~CP_LASTPROMPT; zsfree(compcontext); zsfree(compparameter); zsfree(compredirect); @@ -4205,20 +4317,17 @@ callcompfunc(char *s, char *fn) zsfree(compprefix); zsfree(compsuffix); if (unset(COMPLETEINWORD)) { - if (linwhat == IN_MATH) - tmp = s; - else - tmp = quotename(s, NULL); + /* Maybe we'll have to do quoting here some time. */ + tmp = dupstring(s); untokenize(tmp); compprefix = ztrdup(tmp); compsuffix = ztrdup(""); } else { - char *ss = s + offs, sav; + char *ss, sav; - if (linwhat == IN_MATH) - tmp = s; - else - tmp = quotename(s, &ss); + tmp = dupstring(s); + ss = tmp + offs; + sav = *ss; *ss = '\0'; untokenize(tmp); @@ -4260,6 +4369,30 @@ callcompfunc(char *s, char *fn) compexact = ztrdup(""); set &= ~CP_EXACT; } + zsfree(comptoend); + if (movetoend == 1) + comptoend = ztrdup("single"); + else + comptoend = ztrdup("match"); + zsfree(compoldlist); + zsfree(compoldins); + if (hasperm && permmnum) { + if (listshown) + compoldlist = "shown"; + else + compoldlist = "yes"; + set |= CP_OLDLIST; + if (menucur) { + sprintf(buf, "%d", (*menucur)->gnum); + compoldins = buf; + set |= CP_OLDINS; + } else + compoldins = ""; + } else + compoldlist = compoldins = ""; + compoldlist = ztrdup(compoldlist); + compoldins = ztrdup(compoldins); + incompfunc = 1; startparamscope(); makecompparamsptr(); @@ -4294,10 +4427,32 @@ callcompfunc(char *s, char *fn) else if (!strcmp(compinsert, "auto") || !strcmp(compinsert, "automenu")) useline = 1, usemenu = 2; - else + else if (idigit(*compinsert)) { + char *m; + + useline = 1; usemenu = 3; + insmnum = atoi(compinsert); + if ((m = strchr(compinsert, ':'))) { + insgroup = 1; + insgnum = atoi(m + 1); + } + } else useline = usemenu = 0; useexact = (compexact && !strcmp(compexact, "accept")); + if (!comptoend || !*comptoend) + movetoend = 0; + else if (!strcmp(comptoend, "single")) + movetoend = 1; + else if (!strcmp(comptoend, "always")) + movetoend = 3; + else + movetoend = 2; + + oldlist = (hasperm && compoldlist && !strcmp(compoldlist, "keep")); + oldins = (hasperm && menucur && + compoldins && !strcmp(compoldins, "keep")); + zfree(comppms, CP_NUM * sizeof(Param)); comppms = ocpms; } @@ -4327,6 +4482,7 @@ makecomplist(char *s, int incmd, int lst) struct cmlist ms; Cmlist m; char *p, *os = s; + int onm = nmatches; /* Inside $... ? */ if (compfunc && (p = check_param(s, 0))) @@ -4382,10 +4538,12 @@ makecomplist(char *s, int incmd, int lst) if (!validlist) lastambig = 0; - amatches = 0; + amatches = NULL; mnum = 0; unambig_mnum = -1; isuf = NULL; + insmnum = insgnum = 1; + insgroup = oldlist = oldins = 0; begcmgroup("default", 0); ccused = newlinklist(); @@ -4399,7 +4557,7 @@ makecomplist(char *s, int incmd, int lst) endcmgroup(NULL); - if (amatches) + if (amatches && !oldlist) amatches->ccs = (Compctl *) makearray(ccused, 0, &(amatches->ccount), NULL); else { @@ -4408,7 +4566,13 @@ makecomplist(char *s, int incmd, int lst) for (n = firstnode(ccused); n; incnode(n)) freecompctl((Compctl) getdata(n)); } + if (oldlist) { + nmatches = onm; + validlist = 1; + amatches = pmatches; + return 0; + } PERMALLOC { permmatches(); } LASTALLOC; @@ -4996,9 +5160,9 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) delit = ispattern = 0; usemenu = um; patcomp = filecomp = NULL; - menucur = NULL; - rpre = rsuf = lpre = lsuf = ppre = psuf = lppre = lpsuf = prpre = - fpre = fsuf = ipre = ripre = prpre = NULL; + rpre = rsuf = lpre = lsuf = ppre = psuf = lppre = lpsuf = + fpre = fsuf = ipre = ripre = prpre = + qfpre = qfsuf = qrpre = qrsuf = qlpre = qlsuf = NULL; curcc = cc; @@ -5106,8 +5270,10 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) lpre = zhalloc(lpl + 1); memcpy(lpre, s, lpl); lpre[lpl] = '\0'; + qlpre = quotename(lpre, NULL); lsuf = dupstring(s + offs); lsl = strlen(lsuf); + qlsuf = quotename(lsuf, NULL); /* First check for ~.../... */ if (ic == Tilde) { @@ -5126,9 +5292,11 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) rpre = (*p || *lpre == Tilde || *lpre == Equals) ? (noreal = 0, getreal(tt)) : dupstring(tt); + qrpre = quotename(rpre, NULL); for (p = lsuf; *p && *p != String && *p != Tick; p++); rsuf = *p ? (noreal = 0, getreal(lsuf)) : dupstring(lsuf); + qrsuf = quotename(rsuf, NULL); /* Check if word is a pattern. */ @@ -5204,7 +5372,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) lppre = dupstring((char *) (line + wb)); line[cs] = save; if (brbeg && *brbeg) - strcpy(lppre + brpl, lppre + brpl + strlen(brbeg)); + strcpy(lppre + qbrpl, lppre + qbrpl + strlen(brbeg)); if ((p = strrchr(lppre, '/'))) { p[1] = '\0'; lppl = strlen(lppre); @@ -5226,7 +5394,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) lpsuf = dupstring((char *) (line + cs)); line[we] = save; if (brend && *brend) { - char *p = lpsuf + brsl - (cs - wb); + char *p = lpsuf + qbrsl - (cs - wb); strcpy(p, p + strlen(brend)); } @@ -5241,8 +5409,10 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) /* And get the file prefix. */ fpre = dupstring(((s1 == s || s1 == rpre || ic) && (*s != '/' || cs == wb)) ? s1 : s1 + 1); + qfpre = quotename(fpre, NULL); /* And the suffix. */ fsuf = dupstrpfx(rsuf, s2 - rsuf); + qfsuf = quotename(fsuf, NULL); if (comppatmatch && *comppatmatch && (ispattern & 2)) { int t2; @@ -5506,6 +5676,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) * that things starting with these characters will be added. */ rpre = dyncat((ic == Tilde) ? "~" : "=", rpre); rpl++; + qrpre = dyncat((ic == Tilde) ? "~" : "=", qrpre); } if (!ic && (cc->mask & CC_COMMPATH) && !*ppre && !*psuf) { /* If we have to complete commands, add alias names, * @@ -6137,7 +6308,10 @@ permmatches(void) Cmatch *p, *q; Cexpl *ep, *eq, e, o; Compctl *cp, *cq; - int nn, nl, fi = 0; + int nn, nl, fi = 0, gn = 1, mn = 1, rn; + + if (hasperm) + freematches(); amatches = lmatches = NULL; nmatches = smatches = 0; @@ -6179,13 +6353,17 @@ permmatches(void) n->next = amatches; amatches = n; n->prev = 0; + n->num = gn++; n->flags = g->flags; n->mcount = g->mcount; n->matches = p = (Cmatch *) ncalloc((n->mcount + 1) * sizeof(Cmatch)); - for (q = g->matches; *q; q++, p++) + for (rn = 1, q = g->matches; *q; q++, p++, rn) { *p = dupmatch(*q); + (*p)->rnum = rn++; + (*p)->gnum = mn++; + } *p = NULL; n->lcount = g->lcount; @@ -6216,6 +6394,10 @@ permmatches(void) n->ccs = NULL; g = g->next; } + pmatches = amatches; + hasperm = 1; + permmnum = mn - 1; + permgnum = gn - 1; } /* This frees one match. */ @@ -6247,7 +6429,7 @@ freematch(Cmatch m) static void freematches(void) { - Cmgroup g = amatches, n; + Cmgroup g = pmatches, n; Cmatch *m; Cexpl *e; Compctl *c; @@ -6281,24 +6463,27 @@ freematches(void) g = n; } + hasperm = 0; } /* Insert the given string into the command line. If move is non-zero, * * the cursor position is changed and len is the length of the string * - * to insert (if it is -1, the length is calculated here). */ + * to insert (if it is -1, the length is calculated here). * + * The last argument says if we should quote the string. */ /**/ -static void +static int inststrlen(char *str, int move, int len) { if (!len || !str) - return; + return 0; if (len == -1) len = strlen(str); spaceinline(len); strncpy((char *)(line + cs), str, len); if (move) cs += len; + return len; } /* This builds the unambiguous string. If ins is non-zero, it is @@ -6319,10 +6504,11 @@ cline_str(Cline l, int ins, int *csp) * to re-insert. */ if (ins) { if ((hasp = (brbeg && *brbeg))) { - plen = strlen(brbeg); pl = brpl; + plen = strlen(brbeg); pl = (hasunqu ? brpl : qbrpl); } if ((hass = (brend && *brend))) { - slen = strlen(brend); sl = we - wb - brsl - plen - slen + 1; + slen = strlen(brend); + sl = we - wb - (hasunqu ? brsl : qbrsl) - plen - slen + 1; } if (!pl) { inststrlen(brbeg, 1, -1); @@ -6606,6 +6792,7 @@ do_ambiguous(void) * how REC_EXACT takes effect. We effectively turn the ambiguous * * completion into an unambiguous one. */ if (ainfo && ainfo->exact == 1 && useexact && !(fromcomp & FC_LINE)) { + menucur = NULL; do_single(ainfo->exactm); invalidatelist(); return; @@ -6628,6 +6815,8 @@ do_ambiguous(void) int atend = (cs == we), oll = ll, la; VARARR(char, oline, ll); + menucur = NULL; + /* Copy the line buffer to be able to easily test if it changed. */ memcpy(oline, line, ll); @@ -6653,6 +6842,10 @@ do_ambiguous(void) fromcomp = ((isset(AUTOMENU) ? FC_LINE : 0) | ((atend && cs != lastend) ? FC_INWORD : 0)); + /* Probably move the cursor to then end. */ + if (movetoend == 3) + cs = lastend; + /* If the LIST_AMBIGUOUS option (meaning roughly `show a list only * * if the completion is completely ambiguous') is set, and some * * prefix was inserted, return now, bypassing the list-displaying * @@ -6674,7 +6867,8 @@ do_ambiguous(void) * if it is needed. */ if (isset(LISTBEEP)) feep(); - if (uselist && usemenu != 2 && !showinglist && + if (uselist && usemenu != 2 && + (!showinglist || (usemenu == 3 && !oldlist)) && (smatches >= 2 || (compforcelist && *compforcelist))) showinglist = -2; } @@ -6721,7 +6915,7 @@ do_single(Cmatch m) /* We are currently not in a menu-completion, * * so set the position variables. */ menupos = wb; - menuwe = (cs == we) || isset(ALWAYSTOEND); + menuwe = (movetoend >= 2 || (movetoend == 1 && !menucmp)); menuend = we; } /* If we are already in a menu-completion or if we have done a * @@ -6770,14 +6964,20 @@ do_single(Cmatch m) * If it is, we append a slash. */ struct stat buf; char *p; + int t = 0; - /* Build the path name. */ - p = (char *) zhalloc(strlen(prpre) + strlen(str) + + if (m->ipre && m->ipre[0] == '~' && !m->ipre[1]) + t = 1; + else { + /* Build the path name. */ + p = (char *) zhalloc(strlen(prpre) + strlen(str) + strlen(psuf) + 3); - sprintf(p, "%s%s%s", (prpre && *prpre) ? prpre : "./", str, psuf); + sprintf(p, "%s%s%s", (prpre && *prpre) ? prpre : "./", str, psuf); - /* And do the stat. */ - if (!(sr = ztat(p, &buf, 0)) && S_ISDIR(buf.st_mode)) { + /* And do the stat. */ + t = (!(sr = ztat(p, &buf, 0)) && S_ISDIR(buf.st_mode)); + } + if (t) { /* It is a directory, so add the slash. */ havesuff = 1; inststrlen("/", 1, 1); @@ -6822,23 +7022,71 @@ do_single(Cmatch m) if (menuwe && m->ripre && isset(AUTOPARAMKEYS)) makeparamsuffix(((m->flags & CMF_PARBR) ? 1 : 0), menuinsc); - if (menucmp && !menuwe) + if ((menucmp && !menuwe) || !movetoend) cs = menuend; } +/* This maps the value in v into the range [0,m-1], decrementing v + * if it is non-negative and making negative values cound backwards. */ + +static int +comp_mod(int v, int m) +{ + if (v >= 0) + v--; + if (v >= 0) + return v % m; + else { + while (v < 0) + v += m; + return v; + } +} + /* This handles the beginning of menu-completion. */ /**/ static void do_ambig_menu(void) { - menucmp = 1; - menucur = NULL; - menugrp = amatches; - while (!menugrp->mcount) - menugrp = menugrp->next; - do_single(menugrp->matches[0]); - menucur = menugrp->matches; + Cmatch *mc; + + if (usemenu != 3) { + menucmp = 1; + menucur = NULL; + } else { + if (oldlist) { + if (oldins) + acceptlast(); + } else + menucur = NULL; + } + if (insgroup) { + insgnum = comp_mod(insgnum, permgnum); + for (menugrp = amatches; + menugrp && menugrp->num != insgnum + 1; + menugrp = menugrp->next); + if (!menugrp || !menugrp->mcount) { + menucur = NULL; + return; + } + insmnum = comp_mod(insmnum, menugrp->mcount); + } else { + int c = 0; + + insmnum = comp_mod(insmnum, permmnum); + for (menugrp = amatches; + menugrp && (c += menugrp->mcount) <= insmnum; + menugrp = menugrp->next) + insmnum -= menugrp->mcount; + if (!menugrp) { + menucur = NULL; + return; + } + } + mc = menugrp->matches + insmnum; + do_single(*mc); + menucur = mc; } /* Return the length of the common prefix of s and t. */ @@ -6924,6 +7172,15 @@ printfmt(char *fmt, int n, int dopr) u = 0; m = 1; tcout(TCUNDERLINEEND); break; + case '{': + for (p++; *p && (*p != '%' || p[1] != '}'); p++, cc++) + if (dopr) + putc(*p, shout); + if (*p) + p++; + else + p--; + break; } if (m) { if (b) @@ -6971,7 +7228,6 @@ listmatches(void) Cexpl *e; int nlines = 0, ncols, nlist = 0, longest = 1, pnl = 0; int of = isset(LISTTYPES), opl = 0; - int listmax = getiparam("LISTMAX"); #ifdef DEBUG /* Sanity check */ @@ -6983,11 +7239,10 @@ listmatches(void) /* Set the cursor below the prompt. */ trashzle(); - showinglist = 0; + showinglist = listshown = 0; clearflag = (isset(USEZLE) && !termflags && - (isset(ALWAYSLASTPROMPT) && zmult == 1)) || - (unset(ALWAYSLASTPROMPT) && zmult != 1); + complastprompt && *complastprompt); for (g = amatches; g; g = g->next) { char **pp = g->ylist; @@ -7066,7 +7321,8 @@ listmatches(void) } /* Maybe we have to ask if the user wants to see the list. */ - if ((listmax && nlist > listmax) || (!listmax && nlines >= lines)) { + if ((complistmax && nlist > complistmax) || + (!complistmax && nlines >= lines)) { int qup; zsetterm(); qup = printfmt("zsh: do you wish to see all %n possibilities? ", nlist, 1); @@ -7204,6 +7460,7 @@ listmatches(void) if ((nlines += nlnct - 1) < lines) { tcmultout(TCUP, TCMULTUP, nlines); showinglist = -1; + listshown = 1; } else clearflag = 0, putc('\n', shout); } else diff --git a/Src/glob.c b/Src/glob.c index f8fd2aa4a..0d6d4d778 100644 --- a/Src/glob.c +++ b/Src/glob.c @@ -397,6 +397,7 @@ scanner(Complist q) int pbcwdsav = pathbufcwd; int errssofar = errsfound; struct dirsav ds; + char *str; ds.ino = ds.dev = 0; ds.dirname = NULL; @@ -412,17 +413,18 @@ scanner(Complist q) scanner(q->next); } c = q->comp; + str = c->str; /* Now the actual matching for the current path section. */ - if (!(c->next || c->left) && !haswilds(c->str) + if (!(c->next || c->left) && !haswilds(str) && (!((c->stat & (C_LCMATCHUC|C_IGNCASE)) || c->errsmax) - || !strcmp(".", c->str) || !strcmp("..", c->str))) { + || !*str || !strcmp(".", str) || !strcmp("..", str))) { /* * We always need to match . and .. explicitly, even if we're * checking other strings for case-insensitive matches. * * It's a straight string to the end of the path section. */ - int l = strlen(c->str); + int l = strlen(str); if (l + !l + pathpos - pathbufcwd >= PATH_MAX) { int err; @@ -442,14 +444,14 @@ scanner(Complist q) /* Not the last path section. Just add it to the path. */ int oppos = pathpos; - if (!errflag && !(q->closure && !strcmp(c->str, "."))) { - addpath(c->str); + if (!errflag && !(q->closure && !strcmp(str, "."))) { + addpath(str); if (!closure || statfullpath("", NULL, 1)) scanner((q->closure) ? q : q->next); pathbuf[pathpos = oppos] = '\0'; } } else - insert(c->str, 0); + insert(str, 0); } else { /* Do pattern matching on current path section. */ char *fn = pathbuf[pathbufcwd] ? unmeta(pathbuf + pathbufcwd) : "."; @@ -2282,16 +2284,45 @@ int getmatch(char **sp, char *pat, int fl, int n, char *replstr) { Comp c; - char *s = *sp, *t, *start, sav; - int i, l = strlen(*sp), matched; MUSTUSEHEAP("getmatch"); /* presumably covered by prefork() test */ - repllist = NULL; + c = parsereg(pat); + if (!c) { + zerr("bad pattern: %s", pat, 0); + return 1; + } + return igetmatch(sp, c, fl, n, replstr); +} + +/**/ +void +getmatcharr(char ***ap, char *pat, int fl, int n, char *replstr) +{ + char **arr = *ap, **pp; + Comp c; + + MUSTUSEHEAP("getmatch"); /* presumably covered by prefork() test */ + c = parsereg(pat); if (!c) { zerr("bad pattern: %s", pat, 0); - return 1; + return; } + *ap = pp = ncalloc(sizeof(char *) * (arrlen(arr) + 1)); + while ((*pp = *arr++)) + if (igetmatch(pp, c, fl, n, replstr)) + pp++; +} + +/**/ +static int +igetmatch(char **sp, Comp c, int fl, int n, char *replstr) +{ + char *s = *sp, *t, *start, sav; + int i, l = strlen(*sp), matched; + + repllist = NULL; + if (fl & SUB_ALL) { i = domatch(s, c, 0); *sp = get_match_ret(*sp, 0, i ? l : 0, fl, i ? replstr : 0); diff --git a/Src/subst.c b/Src/subst.c index c62fcce6b..e8e22f943 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -1361,16 +1361,24 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) NULL, s[-1]); return NULL; } - singsub(&s); + { + char t = s[-1]; + + singsub(&s); + if (t == '/' && (flags & SUB_SUBSTR)) { + if (*s == '#' || *s == '%') { + flags &= ~SUB_SUBSTR; + if (*s == '%') + flags |= SUB_END; + s++; + } else if (*s == '\\') { + s++; + } + } + } if (!vunset && isarr) { - char **ap = aval; - char **pp = aval = (char **)ncalloc(sizeof(char *) * (arrlen(aval) + 1)); - - while ((*pp = *ap++)) { - if (getmatch(pp, s, flags, flnum, replstr)) - pp++; - } + getmatcharr(&aval, s, flags, flnum, replstr); copied = 1; } else { if (vunset) diff --git a/Src/utils.c b/Src/utils.c index 12b7fc7eb..86679e90f 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -3177,10 +3177,7 @@ bslashquote(const char *s, char **e, int instring) *v++ = *u; } *v = '\0'; - if (strcmp(buf, s)) - tt = dupstring(buf); - else - tt = s; + tt = dupstring(buf); v += tt - buf; if (e && (sf & 1)) *e += tt - buf; |