From 4d2bcf2fe7637b641ccde31a8ca7c4875f0699c1 Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Mon, 27 Apr 2020 19:30:39 +0000 Subject: 45729: internal: Add a second parameter to zlinklist2array(), analogously to hlinklist2array(). Will be used in the next commit. --- Src/Zle/compcore.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Src/Zle/compcore.c') diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c index 7e3badc57..958fef8e7 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 *)); @@ -1922,7 +1922,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). */ -- cgit v1.2.3 From 2cf6032a301d994c578e5e1942c4815e85651647 Mon Sep 17 00:00:00 2001 From: Bart Schaefer Date: Thu, 11 Feb 2021 19:13:47 -0800 Subject: 47997: Disable XTRACE around user-defined completion widgets. --- ChangeLog | 6 ++++++ NEWS | 5 +++++ README | 3 +++ Src/Zle/compcore.c | 3 +++ 4 files changed, 17 insertions(+) (limited to 'Src/Zle/compcore.c') diff --git a/ChangeLog b/ChangeLog index 4e85336ea..4946b84c3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2021-02-11 Bart Schaefer + + * unposted: NEWS, README: mention the effects of 47997. + + * 47997: Src/Zle/compcore.c: disable xtrace around completions + 2021-02-07 Oliver Kiddle * 47944: Completion/BSD/Command/_bsd_pkg, diff --git a/NEWS b/NEWS index a5becf67b..cf270ff51 100644 --- a/NEWS +++ b/NEWS @@ -30,6 +30,11 @@ The compinit function learnt a -w option to explain why compdump runs. The zsh/datetime module's strftime builtin learnt an -n option to omit the trailing newline when printing a formatted time. +The XTRACE option is now disabled while running user-defined completion +widgets. This corresponds to long-standing behavior of other user ZLE +widgets. Use the _complete_debug widget to capture XTRACE output, or +use "functions -T" to enable tracing of specific completion functions. + Changes from 5.7.1-test-3 to 5.8 -------------------------------- diff --git a/README b/README index 9b1b1605f..3ebf75f1b 100644 --- a/README +++ b/README @@ -92,6 +92,9 @@ not set the new, fourth field will continue to work under both 5.8 and 5.9. (As it happens, adding a comma after "bold" will make both 5.8 and 5.9 do the right thing, but this should be viewed as an unsupported hack.) +The XTRACE option is now disabled while running user-defined completion +widgets. See NEWS. + Incompatibilities between 5.7.1 and 5.8 --------------------------------------- diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c index 958fef8e7..5162d97dc 100644 --- a/Src/Zle/compcore.c +++ b/Src/Zle/compcore.c @@ -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(); -- cgit v1.2.3 From d0e071c5f0bf6a879756f72e1f0d0ae6952a4b49 Mon Sep 17 00:00:00 2001 From: Bart Schaefer Date: Sat, 15 May 2021 13:40:37 -0700 Subject: 48790: COMPLETE_IN_WORD inside brace-param --- ChangeLog | 2 ++ Src/Zle/compcore.c | 28 ++++++++++++++++++++++++---- 2 files changed, 26 insertions(+), 4 deletions(-) (limited to 'Src/Zle/compcore.c') diff --git a/ChangeLog b/ChangeLog index 973455232..e7a602e68 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ 2021-05-15 Bart Schaefer + * 48790: Src/Zle/compcore.c: COMPLETE_IN_WORD inside brace-param + * 48710: Completion/Zsh/Command/_zed, Doc/Zsh/contrib.yo, Functions/Misc/zed: add "zed -h" aka "histed", update doc and completion; improve compatibility with SH_WORD_SPLIT diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c index 5162d97dc..131e86825 100644 --- a/Src/Zle/compcore.c +++ b/Src/Zle/compcore.c @@ -1125,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) { @@ -1171,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) { + tb = ++b, br++; + if ((qstring ? skipparens('(', ')', &tb) : + skipparens(Inpar, Outpar, &tb)) > 0 || tb - s >= offs) { /* * We are still within the parameter flags. There's no * point trying to do anything clever here with @@ -1188,6 +1200,14 @@ check_param(char *s, int set, int test) ispar = 2; return NULL; } + if ((qstring ? '(' : Inpar) == *b) { + /* + * We are inside the braces but on the opening paren. + * There is nothing useful to complete here? + */ + return NULL; + } else + b = tb; /* Skip over the flags */ for (tb = p - 1; tb > s && *tb != Outbrace && *tb != Inbrace; tb--); if (tb > s && *tb == Inbrace && (tb[-1] == String || *tb == Qstring)) -- cgit v1.2.3 From 0a8d5cdbc860444c77de5880f2ff181a8ae33a83 Mon Sep 17 00:00:00 2001 From: Oliver Kiddle Date: Tue, 28 Sep 2021 23:40:38 +0200 Subject: 49450: don't display explanation with compadd -x if any of -D, -A or -O are also used --- ChangeLog | 5 +++++ Src/Zle/compcore.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'Src/Zle/compcore.c') diff --git a/ChangeLog b/ChangeLog index b1f295bd7..a84a66882 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2021-09-28 Oliver Kiddle + + * 49450: Src/Zle/compcore.c: don't display explanation with + compadd -x if any of -D, -A or -O are also used + 2021-09-26 Daniel Shahaf * unposted: Doc/Zsh/contrib.yo, Doc/Zsh/mod_curses.yo, diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c index 131e86825..63136854e 100644 --- a/Src/Zle/compcore.c +++ b/Src/Zle/compcore.c @@ -2120,7 +2120,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; -- cgit v1.2.3 From 632fee7cdfcd234a5c7c53f17777ca18e62d82e3 Mon Sep 17 00:00:00 2001 From: Oliver Kiddle Date: Sat, 30 Oct 2021 23:27:29 +0200 Subject: 49528: allow multiple -D options to compadd --- ChangeLog | 4 +++ Completion/X/Command/_xinput | 3 +-- Completion/Zsh/Command/_compadd | 2 +- Doc/Zsh/compwid.yo | 2 ++ Src/Zle/comp.h | 2 +- Src/Zle/compcore.c | 59 ++++++++++++++++++++++++++++------------- Src/Zle/complete.c | 21 ++++++++++++--- 7 files changed, 68 insertions(+), 25 deletions(-) (limited to 'Src/Zle/compcore.c') diff --git a/ChangeLog b/ChangeLog index 0f1886220..7721ccc8d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2021-10-30 Oliver Kiddle + * 49528: Src/Zle/comp.h, Src/Zle/compcore.c, Src/Zle/complete.c, + Completion/X/Command/_xinput, Completion/Zsh/Command/_compadd, + Doc/Zsh/compwid.yo: allow multiple -D options to compadd + * unposted (c.f. Bart: 49531): Test/Y02compmatch.ztst: fix test 2021-10-27 Matthew Martin diff --git a/Completion/X/Command/_xinput b/Completion/X/Command/_xinput index 00a976d5d..2bbadd65a 100644 --- a/Completion/X/Command/_xinput +++ b/Completion/X/Command/_xinput @@ -106,8 +106,7 @@ case $state in if [[ $PREFIX$SUFFIX = [^-]*[^0-9]* ]]; then # match based on the names but insert IDs - compadd "$expl[@]" -M 'b:=* m:{[:lower:]}={[:upper:]}' -D ids -a names - compadd "$expl[@]" -M 'b:=* m:{[:lower:]}={[:upper:]}' -D disp -a names + compadd "$expl[@]" -M 'b:=* m:{[:lower:]}={[:upper:]}' -D ids -D disp -a names compadd "$expl[@]" -U -ld disp -a ids && ret=0 zstyle -s ":completion:${curcontext}:input-devices" insert-ids out || out=menu diff --git a/Completion/Zsh/Command/_compadd b/Completion/Zsh/Command/_compadd index 9c92cda76..4456cf71e 100644 --- a/Completion/Zsh/Command/_compadd +++ b/Completion/Zsh/Command/_compadd @@ -31,7 +31,7 @@ args=( '-n[hide matches in completion listing]' '-O+[populate array with matches instead of adding them]:array:_parameters -g "*array*"' '-A+[populate array with expanded matches instead of adding them]:array:_parameters -g "*array*"' - '-D+[delete elements from array corresponding to non-matching candidates]:array:_parameters -g "*array*"' + '*-D+[delete elements from array corresponding to non-matching candidates]:array:_parameters -g "*array*"' ) case $service in diff --git a/Doc/Zsh/compwid.yo b/Doc/Zsh/compwid.yo index 9f67f13b7..d32a0702f 100644 --- a/Doc/Zsh/compwid.yo +++ b/Doc/Zsh/compwid.yo @@ -725,6 +725,8 @@ As with tt(-O), the var(completions) are not added to the set of matches. Instead, whenever the var(n)th var(completion) does not match, the var(n)th element of the var(array) is removed. Elements for which the corresponding var(completion) matches are retained. +This option can be used more than once to remove elements from multiple +arrays. ) item(tt(-C))( This option adds a special match which expands to all other matches diff --git a/Src/Zle/comp.h b/Src/Zle/comp.h index 2e3249b52..0c5fbd4f0 100644 --- a/Src/Zle/comp.h +++ b/Src/Zle/comp.h @@ -329,7 +329,7 @@ struct cadata { char *exp; /* explanation (-X) */ char *apar; /* array to store matches in (-A) */ char *opar; /* array to store originals in (-O) */ - char *dpar; /* array to delete non-matches in (-D) */ + char **dpar; /* arrays to delete non-matches in (-D) */ char *disp; /* array with display lists (-d) */ char *mesg; /* message to show unconditionally (-x) */ int dummies; /* add that many dummy matches */ diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c index 63136854e..2f3d53834 100644 --- a/Src/Zle/compcore.c +++ b/Src/Zle/compcore.c @@ -2081,10 +2081,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; @@ -2092,7 +2092,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; @@ -2186,11 +2186,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) { @@ -2507,8 +2520,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; } } @@ -2525,8 +2540,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) { @@ -2553,10 +2570,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); } @@ -2584,8 +2605,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)) { diff --git a/Src/Zle/complete.c b/Src/Zle/complete.c index 71d114de9..67a60963e 100644 --- a/Src/Zle/complete.c +++ b/Src/Zle/complete.c @@ -607,6 +607,7 @@ bin_compadd(char *name, char **argv, UNUSED(Options ops), UNUSED(int func)) char *oarg = NULL; /* argument of -o option */ int added; /* return value */ Cmatcher match = NULL; + size_t dparlen = 0, dparsize = 0; /* no. of -D options and array size */ if (incompfunc != 1) { zwarnnam(name, "can only be called from completion function"); @@ -614,7 +615,8 @@ bin_compadd(char *name, char **argv, UNUSED(Options ops), UNUSED(int func)) } dat.ipre = dat.isuf = dat.ppre = dat.psuf = dat.prpre = dat.mesg = dat.pre = dat.suf = dat.group = dat.rems = dat.remf = dat.disp = - dat.ign = dat.exp = dat.apar = dat.opar = dat.dpar = NULL; + dat.ign = dat.exp = dat.apar = dat.opar = NULL; + dat.dpar = NULL; dat.match = NULL; dat.flags = 0; dat.aflags = CAF_MATCH; @@ -741,7 +743,12 @@ bin_compadd(char *name, char **argv, UNUSED(Options ops), UNUSED(int func)) e = "parameter name expected after -%c"; break; case 'D': - sp = &(dat.dpar); + if (dparsize <= dparlen + 1) { + dparsize = (dparsize + 1) * 2; + dat.dpar = (char **)zrealloc(dat.dpar, sizeof(char *) * dparsize); + } + sp = dat.dpar + dparlen++; + *sp = dat.dpar[dparlen] = NULL; e = "parameter name expected after -%c"; break; case 'd': @@ -768,11 +775,13 @@ bin_compadd(char *name, char **argv, UNUSED(Options ops), UNUSED(int func)) } else { zwarnnam(name, "number expected after -%c", *p); zsfree(mstr); + zfree(dat.dpar, dparsize); return 1; } if (dat.dummies < 0) { zwarnnam(name, "invalid number: %d", dat.dummies); zsfree(mstr); + zfree(dat.dpar, dparsize); return 1; } break; @@ -782,6 +791,7 @@ bin_compadd(char *name, char **argv, UNUSED(Options ops), UNUSED(int func)) default: zwarnnam(name, "bad option: -%c", *p); zsfree(mstr); + zfree(dat.dpar, dparsize); return 1; } if (sp) { @@ -802,6 +812,7 @@ bin_compadd(char *name, char **argv, UNUSED(Options ops), UNUSED(int func)) /* Missing argument: argv[N] == "-X", argv[N+1] == NULL. */ zwarnnam(name, e, *p); zsfree(mstr); + zfree(dat.dpar, dparsize); return 1; } if (m) { @@ -820,17 +831,21 @@ bin_compadd(char *name, char **argv, UNUSED(Options ops), UNUSED(int func)) if (mstr && (match = parse_cmatcher(name, mstr)) == pcm_err) { zsfree(mstr); + zfree(dat.dpar, dparsize); return 1; } zsfree(mstr); if (!*argv && !dat.group && !dat.mesg && - !(dat.aflags & (CAF_NOSORT|CAF_UNIQALL|CAF_UNIQCON|CAF_ALL))) + !(dat.aflags & (CAF_NOSORT|CAF_UNIQALL|CAF_UNIQCON|CAF_ALL))) { + zfree(dat.dpar, dparsize); return 1; + } dat.match = match = cpcmatcher(match); added = addmatches(&dat, argv); freecmatcher(match); + zfree(dat.dpar, dparsize); return added; } -- cgit v1.2.3 From b067ab08d65c7ec9a48f5527076bf0f9b17e622c Mon Sep 17 00:00:00 2001 From: Jun-ichi Takimoto Date: Mon, 1 Nov 2021 23:33:57 +0900 Subject: 49535: fix completion for ${ and ${(a) --- ChangeLog | 5 +++++ Src/Zle/compcore.c | 14 +++----------- 2 files changed, 8 insertions(+), 11 deletions(-) (limited to 'Src/Zle/compcore.c') diff --git a/ChangeLog b/ChangeLog index 4bc42ce9a..3278e7b20 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2021-11-01 Jun-ichi Takimoto + + * 49535: Src/Zle/compcore.c: fix completion of parameter names + for ${ and ${(a) + 2021-10-31 Bart Schaefer * users/27302: Completion/Unix/Type/_remote_files: respect setting diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c index 2f3d53834..c6deff756 100644 --- a/Src/Zle/compcore.c +++ b/Src/Zle/compcore.c @@ -1187,9 +1187,9 @@ check_param(char *s, int set, int test) return NULL; /* Ignore the possible (...) flags. */ - tb = ++b, br++; - if ((qstring ? skipparens('(', ')', &tb) : - skipparens(Inpar, Outpar, &tb)) > 0 || tb - s >= offs) { + b++, br++; + if ((qstring ? skipparens('(', ')', &b) : + 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 @@ -1200,14 +1200,6 @@ check_param(char *s, int set, int test) ispar = 2; return NULL; } - if ((qstring ? '(' : Inpar) == *b) { - /* - * We are inside the braces but on the opening paren. - * There is nothing useful to complete here? - */ - return NULL; - } else - b = tb; /* Skip over the flags */ for (tb = p - 1; tb > s && *tb != Outbrace && *tb != Inbrace; tb--); if (tb > s && *tb == Inbrace && (tb[-1] == String || *tb == Qstring)) -- cgit v1.2.3 From 48be30e530a6786f1d47a3dd79f4b6eef2967639 Mon Sep 17 00:00:00 2001 From: Mikael Magnusson Date: Fri, 25 Mar 2022 23:57:30 +0100 Subject: 49893: Fix comments for UNIQCON/ALL --- ChangeLog | 5 +++++ Src/Zle/comp.h | 6 +++--- Src/Zle/compcore.c | 8 +++++++- 3 files changed, 15 insertions(+), 4 deletions(-) (limited to 'Src/Zle/compcore.c') diff --git a/ChangeLog b/ChangeLog index 27bbdc4a0..96f0dc719 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,11 @@ * 49908: Test/ztst.zsh: reset LC_CTYPE to C during tests. +2022-03-30 Mikael Magnusson + + * 49893: Src/Zle/comp.h, Src/Zle/compcore.c: Fix comments for + UNIQCON/ALL + 2022-03-29 Bart Schaefer * 49918: NEWS, README: Update for 49917 and 49911. diff --git a/Src/Zle/comp.h b/Src/Zle/comp.h index 0c5fbd4f0..a8480c2ba 100644 --- a/Src/Zle/comp.h +++ b/Src/Zle/comp.h @@ -85,8 +85,8 @@ struct cmgroup { #define CGF_NOSORT 1 /* don't sort this group */ #define CGF_LINES 2 /* these are to be printed on different lines */ #define CGF_HASDL 4 /* has display strings printed on separate lines */ -#define CGF_UNIQALL 8 /* remove all duplicates */ -#define CGF_UNIQCON 16 /* remove consecutive duplicates */ +#define CGF_UNIQALL 8 /* remove consecutive duplicates (if neither are set, */ +#define CGF_UNIQCON 16 /* don't deduplicate */ /* remove all dupes) */ #define CGF_PACKED 32 /* LIST_PACKED for this group */ #define CGF_ROWS 64 /* LIST_ROWS_FIRST for this group */ #define CGF_FILES 128 /* contains file names */ @@ -299,7 +299,7 @@ struct menuinfo { #define CAF_NOSORT 2 /* compadd -V: don't sort */ #define CAF_MATCH 4 /* compadd without -U: do matching */ #define CAF_UNIQCON 8 /* compadd -2: don't deduplicate */ -#define CAF_UNIQALL 16 /* compadd -1: deduplicate */ +#define CAF_UNIQALL 16 /* compadd -1: deduplicate consecutive only */ #define CAF_ARRAYS 32 /* compadd -a or -k: array/assoc parameter names */ #define CAF_KEYS 64 /* compadd -k: assoc parameter names */ #define CAF_ALL 128 /* compadd -C: _all_matches */ diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c index c6deff756..a9ace5587 100644 --- a/Src/Zle/compcore.c +++ b/Src/Zle/compcore.c @@ -3254,10 +3254,13 @@ makearray(LinkList l, int type, int flags, int *np, int *nlp, int *llp) 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--); @@ -3279,7 +3282,9 @@ 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 (inefficient) */ if (!(flags & CGF_UNIQALL) && !(flags & CGF_UNIQCON)) { int dup; @@ -3303,6 +3308,7 @@ makearray(LinkList l, int type, int flags, int *np, int *nlp, int *llp) (*ap)->flags |= CMF_FMULT; } } + /* passed -1 but not -2, so remove consecutive duplicates (efficient) */ } else if (!(flags & CGF_UNIQCON)) { int dup; -- cgit v1.2.3 From 6a9b3bb290abc1f9427f6574d9b12ec00108f907 Mon Sep 17 00:00:00 2001 From: Mikael Magnusson Date: Sat, 26 Mar 2022 02:34:31 +0100 Subject: 49915: Efficient dedup for unsorted completions --- ChangeLog | 3 +++ Src/Zle/comp.h | 1 + Src/Zle/compcore.c | 54 ++++++++++++++++++++++++++++++++++-------------------- 3 files changed, 38 insertions(+), 20 deletions(-) (limited to 'Src/Zle/compcore.c') diff --git a/ChangeLog b/ChangeLog index 96f0dc719..4b02f3bc8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -10,6 +10,9 @@ * 49893: Src/Zle/comp.h, Src/Zle/compcore.c: Fix comments for UNIQCON/ALL + * 49915: Src/Zle/comp.h, Src/Zle/compcore.c: Efficient dedup + for unsorted completions + 2022-03-29 Bart Schaefer * 49918: NEWS, README: Update for 49917 and 49911. diff --git a/Src/Zle/comp.h b/Src/Zle/comp.h index a8480c2ba..2ca779fe5 100644 --- a/Src/Zle/comp.h +++ b/Src/Zle/comp.h @@ -140,6 +140,7 @@ struct cmatch { #define CMF_ALL (1<<13) /* a match representing all other matches */ #define CMF_DUMMY (1<<14) /* unselectable dummy match */ #define CMF_MORDER (1<<15) /* order by matches, not display strings */ +#define CMF_DELETE (1<<16) /* used for deduplication of unsorted matches, don't set */ /* Stuff for completion matcher control. */ diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c index a9ace5587..0b5b22a30 100644 --- a/Src/Zle/compcore.c +++ b/Src/Zle/compcore.c @@ -3284,30 +3284,44 @@ makearray(LinkList l, int type, int flags, int *np, int *nlp, int *llp) } /* used -O nosort or -V, don't sort */ } else { - /* didn't use -1 or -2, so remove all duplicates (inefficient) */ + /* 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, i, 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; -- cgit v1.2.3 From 774c634d2e494046865e59af2f9e3b2d0a74597a Mon Sep 17 00:00:00 2001 From: Mikael Magnusson Date: Wed, 30 Mar 2022 20:34:24 +0200 Subject: 49926: remove unused variable from 49915 --- Src/Zle/compcore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Src/Zle/compcore.c') diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c index 0b5b22a30..18b8cb531 100644 --- a/Src/Zle/compcore.c +++ b/Src/Zle/compcore.c @@ -3286,7 +3286,7 @@ makearray(LinkList l, int type, int flags, int *np, int *nlp, int *llp) } else { /* didn't use -1 or -2, so remove all duplicates (efficient) */ if (!(flags & CGF_UNIQALL) && !(flags & CGF_UNIQCON)) { - int dup, i, del = 0; + int dup, del = 0; /* To avoid O(n^2) here, sort a copy of the list, then remove marked elements */ matchorder = flags; -- cgit v1.2.3 From 9eda39735430549f2beebc94282fee90b4fb552c Mon Sep 17 00:00:00 2001 From: Mikael Magnusson Date: Sun, 3 Apr 2022 01:08:51 +0200 Subject: 49957: Brown paper bag for 49915 The code would crash when n == 0. There's not really any point doing any of this when n is 0 so just skip everything. It also tried to NULL terminate a list a little to eagerly. --- ChangeLog | 2 ++ Src/Zle/compcore.c | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'Src/Zle/compcore.c') diff --git a/ChangeLog b/ChangeLog index f7766aefa..3b0edff7a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,8 @@ * 49959: Completion/Zsh/Context/_brace_parameter: _brace_parameter: add (-) + * 49957: Src/Zle/compcore.c: Brown paper bag for 49915 + 2022-04-02 dana * unposted (see 48073): Completion/Zsh/Command/_fc: Complete diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c index 18b8cb531..fe3ea10fc 100644 --- a/Src/Zle/compcore.c +++ b/Src/Zle/compcore.c @@ -3247,7 +3247,7 @@ 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; @@ -3320,8 +3320,8 @@ makearray(LinkList l, int type, int flags, int *np, int *nlp, int *llp) } *ap = *bp; } + *ap = NULL; } - *ap = NULL; /* passed -1 but not -2, so remove consecutive duplicates (efficient) */ } else if (!(flags & CGF_UNIQCON)) { int dup; -- cgit v1.2.3