From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on inbox.vuxu.org X-Spam-Level: X-Spam-Status: No, score=-3.4 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED,UNPARSEABLE_RELAY autolearn=ham autolearn_force=no version=3.4.4 Received: (qmail 11491 invoked from network); 26 Oct 2021 23:15:58 -0000 Received: from zero.zsh.org (2a02:898:31:0:48:4558:7a:7368) by inbox.vuxu.org with ESMTPUTF8; 26 Oct 2021 23:15:58 -0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=zsh.org; s=rsa-20210803; h=List-Archive:List-Owner:List-Post:List-Unsubscribe: List-Subscribe:List-Help:List-Id:Sender:Message-ID:Date:Content-ID: Content-Type:MIME-Version:Subject:To:From:Reply-To:Cc: Content-Transfer-Encoding:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References; bh=+IkIegQ0zzo4nmss8CIHR/m33pdjNmPv9+hFE3cliYU=; b=Q8fYV5fwizDWzJRjorxq52XWvy /nGXxu4QA4Vl2j3fCizcm7Y/Ip0WS39lwHe/Ccuw575h+dtJKTH4mEmXxtqg19PDjKYUIB5XhUvXR YHCKzjVpEU/t1Sezgc2bg0WLVNbE0k0eo3rfbIQJRHEQ/elICLlhal4gn+mCOaoqV5ajfqummv3nN z463xbJTxMtR+hzDKDw0IbHWyW2LV7Fp4kQ/6wYTOa+fCRxpgR5l3jqJViuDjiNeWN1dk4s9Fqyiw I+XVocuOdWFo6h0Ui6iXSAXD+qrRmwLzafrpiMoAIKC2ukSONFXbdBDbkMV+o9EGoY9BzjlPRpKUW mApcpNLw==; Received: from authenticated user by zero.zsh.org with local id 1mfVfg-000EP7-CX; Tue, 26 Oct 2021 23:15:56 +0000 Received: from authenticated user by zero.zsh.org with esmtpsa (TLS1.3:TLS_AES_256_GCM_SHA384:256) id 1mfVfM-000E9Z-Ep; Tue, 26 Oct 2021 23:15:36 +0000 Received: from [192.168.178.21] (helo=hydra) by mail.kiddle.eu with esmtp(Exim 4.94.2) (envelope-from ) id 1mfVfL-000Hyi-AJ for zsh-workers@zsh.org; Wed, 27 Oct 2021 01:15:35 +0200 From: Oliver Kiddle To: Zsh workers Subject: PATCH: allow multiple -D options to compadd MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-ID: <69110.1635290135.1@hydra> Date: Wed, 27 Oct 2021 01:15:35 +0200 Message-ID: <69111-1635290135.316655@q0KS.YZZr.UFy0> X-Seq: 49528 Archived-At: X-Loop: zsh-workers@zsh.org Errors-To: zsh-workers-owner@zsh.org Precedence: list Precedence: bulk Sender: zsh-workers-request@zsh.org X-no-archive: yes List-Id: List-Help: List-Subscribe: List-Unsubscribe: List-Post: List-Owner: List-Archive: The -D option to compadd removes array elements at positions corresponding to whatever completion words don't match in the specified array. If you've got both an array of display strings and an array of matches, it can be useful to remove relevant elements from both of these arrays. Currently you either have to use compadd -D twice, use an array of numbers or approach the problem some other way. I couldn't think of any reason why compadd couldn't simply allow multiple -D options and remove elements in all the passed arrays. This patch enables that. The first change for xinput completion demonstrates a use. Before this, get_user_var() was used to retrieve the arrays after first checking that it doesn't start with '('. This function is common to several compadd options and allows a choice of '( one two three )' style words, a scalar converted to a one element array or an associative array. None of that seemed useful with -D. Failures would only be reported when it later tried to assign the new array value. Removing elements based on position is meaningless for an associative array given the lack of ordering. And then it tries to pair up whatever remained as new keys/values. I briefly tried to make it print an error for an argument that isn't an array but I can't see how to safely pass that back out from the middle of that function despite critical stuff like heap swaps. It now simply drops any element that isn't a non-empty array. The old code wasn't ideal either anyway. I'd be interested if someone with better understanding of the zsh error functions has ideas. Oliver 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; }