diff options
author | Axel Beckert <abe@deuxchevaux.org> | 2022-04-11 00:17:48 +0200 |
---|---|---|
committer | Axel Beckert <abe@deuxchevaux.org> | 2022-04-11 00:17:48 +0200 |
commit | b09f4483416c54c1782824633dfabaf2ec0265b6 (patch) | |
tree | 304bc82642862525ae680c7fbaa249663b10ad57 /Src/Zle/compcore.c | |
parent | 12eb3e5356f2fc3351eed58ef1cef1b8fb83b504 (diff) | |
parent | 6e55c920503071e917619b8cb1a188cd35d772db (diff) | |
download | zsh-b09f4483416c54c1782824633dfabaf2ec0265b6.tar.gz zsh-b09f4483416c54c1782824633dfabaf2ec0265b6.zip |
New upstream version 5.8.1.2-test
Diffstat (limited to 'Src/Zle/compcore.c')
-rw-r--r-- | Src/Zle/compcore.c | 146 |
1 files changed, 102 insertions, 44 deletions
diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c index 7e3badc57..fe3ea10fc 100644 --- a/Src/Zle/compcore.c +++ b/Src/Zle/compcore.c @@ -648,7 +648,7 @@ callcompfunc(char *s, char *fn) if (compredirs) freearray(compredirs); if (rdstrs) - compredirs = zlinklist2array(rdstrs); + compredirs = zlinklist2array(rdstrs, 1); else compredirs = (char **) zshcalloc(sizeof(char *)); @@ -821,6 +821,7 @@ callcompfunc(char *s, char *fn) sfcontext = SFC_CWIDGET; NEWHEAPS(compheap) { LinkList largs = NULL; + int oxt = isset(XTRACE); if (*cfargs) { char **p = cfargs; @@ -830,7 +831,9 @@ callcompfunc(char *s, char *fn) while (*p) addlinknode(largs, dupstring(*p++)); } + opts[XTRACE] = 0; cfret = doshfunc(shfunc, largs, 1); + opts[XTRACE] = oxt; } OLDHEAPS; sfcontext = osc; endparamscope(); @@ -1122,6 +1125,18 @@ check_param(char *s, int set, int test) * * TODO: passing s as a parameter while we get some mysterious * offset "offs" into it via a global sucks badly. + * + * From ../lex.c we know: + * wb is the beginning position of the current word in the line + * we is the position of the end of the current word in the line + * From zle_tricky.c we know: + * offs is position within the word where we are completing + * + * So wb + offs is the current cursor position if COMPLETE_IN_WORD + * is set, otherwise it is the end of the word (same as we). + * + * Note below we are thus stepping backward from our completion + * position to find a '$' in the current word (if any). */ for (p = s + offs; ; p--) { if (*p == String || *p == Qstring) { @@ -1168,13 +1183,13 @@ check_param(char *s, int set, int test) char *tb = b; /* If this is a ${...}, see if we are before the '}'. */ - if (!skipparens(Inbrace, Outbrace, &tb)) + if (!skipparens(Inbrace, Outbrace, &tb) && tb - s <= offs) return NULL; /* Ignore the possible (...) flags. */ b++, br++; if ((qstring ? skipparens('(', ')', &b) : - skipparens(Inpar, Outpar, &b)) > 0) { + skipparens(Inpar, Outpar, &b)) > 0 || b - s > offs) { /* * We are still within the parameter flags. There's no * point trying to do anything clever here with @@ -1922,7 +1937,7 @@ set_comp_sep(void) mod_export void set_list_array(char *name, LinkList l) { - setaparam(name, zlinklist2array(l)); + setaparam(name, zlinklist2array(l, 1)); } /* Get the words from a variable or a (list of words). */ @@ -2058,10 +2073,10 @@ addmatches(Cadata dat, char **argv) /* ms: "match string" - string to use as completion. * Overloaded at one place as a temporary. */ char *s, *ms, *lipre = NULL, *lisuf = NULL, *lpre = NULL, *lsuf = NULL; - char **aign = NULL, **dparr = NULL, *oaq = autoq, *oppre = dat->ppre; + char **aign = NULL, ***dparr = NULL, *oaq = autoq, *oppre = dat->ppre; char *oqp = qipre, *oqs = qisuf, qc, **disp = NULL, *ibuf = NULL; char **arrays = NULL; - int lpl, lsl, bcp = 0, bcs = 0, bpadd = 0, bsadd = 0; + int dind, lpl, lsl, bcp = 0, bcs = 0, bpadd = 0, bsadd = 0; int ppl = 0, psl = 0, ilen = 0; int llpl = 0, llsl = 0, nm = mnum, gflags = 0, ohp = haspattern; int isexact, doadd, ois = instring, oib = inbackt; @@ -2069,7 +2084,7 @@ addmatches(Cadata dat, char **argv) struct cmlist mst; Cmlist oms = mstack; Patprog cp = NULL, *pign = NULL; - LinkList aparl = NULL, oparl = NULL, dparl = NULL; + LinkList aparl = NULL, oparl = NULL, *dparl = NULL; Brinfo bp, bpl = brbeg, obpl, bsl = brend, obsl; Heap oldheap; @@ -2097,7 +2112,7 @@ addmatches(Cadata dat, char **argv) curexpl->always = !!dat->mesg; curexpl->count = curexpl->fcount = 0; curexpl->str = dupstring(dat->mesg ? dat->mesg : dat->exp); - if (dat->mesg) + if (dat->mesg && !dat->dpar && !dat->opar && !dat->apar) addexpl(1); } else curexpl = NULL; @@ -2163,11 +2178,24 @@ addmatches(Cadata dat, char **argv) if (dat->opar) oparl = newlinklist(); if (dat->dpar) { - if (*(dat->dpar) == '(') - dparr = NULL; - else if ((dparr = get_user_var(dat->dpar)) && !*dparr) - dparr = NULL; - dparl = newlinklist(); + int darr = 0, dparlen = arrlen(dat->dpar); + char **tail = dat->dpar + dparlen; + + dparr = (char ***)hcalloc((1 + dparlen) * sizeof(char **)); + dparl = (LinkList *)hcalloc((1 + dparlen) * sizeof(LinkList)); + queue_signals(); + while (darr < dparlen) { + if ((dparr[darr] = getaparam(dat->dpar[darr])) && *dparr[darr]) { + dparr[darr] = arrdup(dparr[darr]); + dparl[darr++] = newlinklist(); + } else { + /* swap in the last -D argument if we didn't get a non-empty array */ + dat->dpar[darr] = *--tail; + *tail = NULL; + --dparlen; + } + } + unqueue_signals(); } /* Store the matcher in our stack of matchers. */ if (dat->match) { @@ -2484,8 +2512,10 @@ addmatches(Cadata dat, char **argv) } if (!addit) { compignored++; - if (dparr && !*++dparr) - dparr = NULL; + for (dind = 0; dparl && dparl[dind]; dind++) { + if (dparr[dind] && !*++dparr[dind]) + dparr[dind] = NULL; + } goto next_array; } } @@ -2502,8 +2532,10 @@ addmatches(Cadata dat, char **argv) !(dat->flags & CMF_FILE) ? 1 : 2) : 0), &bpl, bcp, &bsl, bcs, &isexact))) { - if (dparr && !*++dparr) - dparr = NULL; + for (dind = 0; dparl && dparl[dind]; dind++) { + if (dparr[dind] && !*++dparr[dind]) + dparr[dind] = NULL; + } goto next_array; } if (doadd) { @@ -2530,10 +2562,14 @@ addmatches(Cadata dat, char **argv) addlinknode(aparl, ms); if (dat->opar) addlinknode(oparl, s); - if (dat->dpar && dparr) { - addlinknode(dparl, *dparr); - if (!*++dparr) - dparr = NULL; + if (dat->dpar) { + for (dind = 0; dparl[dind]; dind++) { + if (dparr[dind]) { + addlinknode(dparl[dind], *dparr[dind]); + if (!*++dparr[dind]) + dparr[dind] = NULL; + } + } } free_cline(lc); } @@ -2561,8 +2597,10 @@ addmatches(Cadata dat, char **argv) set_list_array(dat->apar, aparl); if (dat->opar) set_list_array(dat->opar, oparl); - if (dat->dpar) - set_list_array(dat->dpar, dparl); + if (dat->dpar) { + for (dind = 0; dparl[dind]; dind++) + set_list_array(dat->dpar[dind], dparl[dind]); + } if (dat->exp) addexpl(0); if (!hasallmatch && (dat->aflags & CAF_ALL)) { @@ -3209,17 +3247,20 @@ makearray(LinkList l, int type, int flags, int *np, int *nlp, int *llp) } *cp = NULL; } - } else { + } else if (n > 0) { if (!(flags & CGF_NOSORT)) { /* Now sort the array (it contains matches). */ matchorder = flags; qsort((void *) rp, n, sizeof(Cmatch), (int (*) _((const void *, const void *)))matchcmp); + /* since the matches are sorted and the default is to remove + * all duplicates, -1 (remove only consecutive dupes) is a no-op, + * so this condition only checks for -2 */ if (!(flags & CGF_UNIQCON)) { int dup; - /* And delete the ones that occur more than once. */ + /* we did not pass -2 so go ahead and remove those dupes */ for (ap = cp = rp; *ap; ap++) { *cp++ = *ap; for (bp = ap; bp[1] && matcheq(*ap, bp[1]); bp++, n--); @@ -3241,30 +3282,47 @@ makearray(LinkList l, int type, int flags, int *np, int *nlp, int *llp) if ((*ap)->flags & (CMF_NOLIST | CMF_MULT)) nl++; } + /* used -O nosort or -V, don't sort */ } else { + /* didn't use -1 or -2, so remove all duplicates (efficient) */ if (!(flags & CGF_UNIQALL) && !(flags & CGF_UNIQCON)) { - int dup; - - for (ap = rp; *ap; ap++) { - for (bp = cp = ap + 1; *bp; bp++) { - if (!matcheq(*ap, *bp)) - *cp++ = *bp; - else + int dup, del = 0; + + /* To avoid O(n^2) here, sort a copy of the list, then remove marked elements */ + matchorder = flags; + Cmatch *sp, *asp; + sp = (Cmatch *) zhalloc((n + 1) * sizeof(Cmatch)); + memcpy(sp, rp, (n + 1) * sizeof(Cmatch)); + qsort((void *) sp, n, sizeof(Cmatch), + (int (*) _((const void *, const void *)))matchcmp); + for (asp = sp + 1; *asp; asp++) { + Cmatch *ap = asp - 1, *bp = asp; + if (matcheq(*ap, *bp)) { + bp[0]->flags = CMF_DELETE; + del = 1; + } else if (!ap[0]->disp) { + /* Mark those, that would show the same string in the list. */ + for (dup = 0; bp[0] && !(bp[0])->disp && + !strcmp((*ap)->str, (bp[0])->str); bp = ++sp) { + (bp[0])->flags |= CMF_MULT; + dup = 1; + } + if (dup) + (*ap)->flags |= CMF_FMULT; + } + } + if (del) { + int n_orig = n; + for (bp = rp, ap = rp; bp < rp + n_orig; ap++, bp++) { + while (bp[0]->flags & CMF_DELETE) { + bp++; n--; + } + *ap = *bp; } - *cp = NULL; - if (!(*ap)->disp) { - for (dup = 0, bp = ap + 1; *bp; bp++) - if (!(*bp)->disp && - !((*bp)->flags & CMF_MULT) && - !strcmp((*ap)->str, (*bp)->str)) { - (*bp)->flags |= CMF_MULT; - dup = 1; - } - if (dup) - (*ap)->flags |= CMF_FMULT; - } + *ap = NULL; } + /* passed -1 but not -2, so remove consecutive duplicates (efficient) */ } else if (!(flags & CGF_UNIQCON)) { int dup; |