about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog4
-rw-r--r--Completion/X/Command/_xinput3
-rw-r--r--Completion/Zsh/Command/_compadd2
-rw-r--r--Doc/Zsh/compwid.yo2
-rw-r--r--Src/Zle/comp.h2
-rw-r--r--Src/Zle/compcore.c59
-rw-r--r--Src/Zle/complete.c21
7 files changed, 68 insertions, 25 deletions
diff --git a/ChangeLog b/ChangeLog
index 0f1886220..7721ccc8d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
 2021-10-30  Oliver Kiddle  <opk@zsh.org>
 
+	* 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  <phy1729@gmail.com>
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;
 }