about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog10
-rw-r--r--Completion/Zsh/Command/_typeset6
-rw-r--r--Doc/Zsh/expn.yo13
-rw-r--r--Src/params.c2
-rw-r--r--Src/subst.c43
-rw-r--r--Test/D04parameter.ztst23
6 files changed, 93 insertions, 4 deletions
diff --git a/ChangeLog b/ChangeLog
index ea0a02f06..64d199b15 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2012-04-22  Peter Stephenson  <p.w.stephenson@ntlworld.com>
+
+	* 30431 (typo in _typeset fixed):
+	Completion/Zsh/Command/_typeset, Doc/Zsh/expn.yo, ASrc/params.c,
+	Src/subst.c, Test/D04parameter.ztst:  add ${...:|...} and
+	${...:*...} operators for removal or inclusion of results
+	by array element.
+
 2012-04-21  Barton E. Schaefer  <schaefer@zsh.org>
 
 	* 30433: Src/hist.c: double backslash is not line continuation.
@@ -16223,5 +16231,5 @@
 
 *****************************************************
 * This is used by the shell to define $ZSH_PATCHLEVEL
-* $Revision: 1.5636 $
+* $Revision: 1.5637 $
 *****************************************************
diff --git a/Completion/Zsh/Command/_typeset b/Completion/Zsh/Command/_typeset
index 9c9165563..d44783d64 100644
--- a/Completion/Zsh/Command/_typeset
+++ b/Completion/Zsh/Command/_typeset
@@ -75,9 +75,11 @@ if [[ "$state" = vars_eq ]]; then
     if (( $+opt_args[-w] ));then
       _wanted files expl 'zwc file' _files -g '*.zwc(-.)'
     elif [[ $service = autoload || -n $opt_args[(i)-[uU]] ]]; then
-      args=(${^fpath}/*(:t))
+      args=(${^fpath}/*(-.:t))
       # Filter out functions already loaded or marked for autoload.
-      args=(${args:#(${(kj.|.)~functions})})
+      local -a funckeys
+      funckeys=(${(k)functions})
+      args=(${args:|funckeys})
       _wanted functions expl 'shell function' compadd -a args
     else
       _functions
diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo
index 25c44f331..dbbdc5073 100644
--- a/Doc/Zsh/expn.yo
+++ b/Doc/Zsh/expn.yo
@@ -604,6 +604,19 @@ If var(name) is an array
 the matching array elements are removed (use the `tt((M))' flag to
 remove the non-matched elements).
 )
+item(tt(${)var(name)tt(:|)var(arrayname)tt(}))(
+If var(arrayname) is the name (N.B., not contents) of an array
+variable, then any elements contained in var(arrayname) are removed
+from the substitution of var(name).  If the substitution is scalar,
+either because var(name) is a scalar variable or the expression is
+quoted, the elements of var(arrayname) are instead tested against the
+entire expression.
+)
+item(tt(${)var(name)tt(:*)var(arrayname)tt(}))(
+Similar to the preceding subsitution, but in the opposite sense,
+so that entries present in both the original substitution and as
+elements of var(arrayname) are retained and others removed.
+)
 xitem(tt(${)var(name)tt(:)var(offset)tt(}))
 item(tt(${)var(name)tt(:)var(offset)tt(:)var(length)tt(}))(
 This syntax gives effects similar to parameter subscripting
diff --git a/Src/params.c b/Src/params.c
index b18fb90a6..24062e03a 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -3493,7 +3493,7 @@ arrayuniq_freenode(HashNode hn)
 }
 
 /**/
-static HashTable
+HashTable
 newuniqtable(zlong size)
 {
     HashTable ht = newhashtable((int)size, "arrayuniq", NULL);
diff --git a/Src/subst.c b/Src/subst.c
index dac536f14..82645ccfa 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -2876,6 +2876,49 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags)
 	    }
 	    break;
 	}
+    } else if (inbrace && (*s == '|' || *s == Bar ||
+			   *s == '*' || *s == Star)) {
+	int intersect = (*s == '*' || *s == Star);
+	char **compare = getaparam(++s), **ap, **apsrc;
+	if (compare) {
+	    HashTable ht = newuniqtable(arrlen(compare)+1);
+	    int present;
+	    for (ap = compare; *ap; ap++)
+		(void)addhashnode2(ht, *ap, (HashNode)
+				   zhalloc(sizeof(struct hashnode)));
+	    if (!vunset && isarr) {
+		if (!copied) {
+		    aval = arrdup(aval);
+		    copied = 1;
+		}
+		for (ap = apsrc = aval; *apsrc; apsrc++) {
+		    untokenize(*apsrc);
+		    present = (gethashnode2(ht, *apsrc) != NULL);
+		    if (intersect ? present : !present) {
+			if (ap != apsrc) {
+			    *ap = *apsrc;
+			}
+			ap++;
+		    }
+		}
+		*ap = NULL;
+	    } else {
+		if (vunset) {
+		    if (unset(UNSET)) {
+			*idend = '\0';
+			zerr("%s: parameter not set", idbeg);
+			deletehashtable(ht);
+			return NULL;
+		    }
+		    val = dupstring("");
+		} else {
+		    present = (gethashnode2(ht, val) != NULL);
+		    if (intersect ? !present : present)
+			val = dupstring("");
+		}
+	    }
+	    deletehashtable(ht);
+	}
     } else {			/* no ${...=...} or anything, but possible modifiers. */
 	/*
 	 * Handler ${+...}.  TODO: strange, why do we handle this only
diff --git a/Test/D04parameter.ztst b/Test/D04parameter.ztst
index 30e4ba0ab..d5a6a403e 100644
--- a/Test/D04parameter.ztst
+++ b/Test/D04parameter.ztst
@@ -169,6 +169,29 @@
 >a-string-with-slashes
 >a-string-with-slashes
 
+  args=('one' '#foo' '(bar' "'three'" two)
+  mod=('#foo' '(bar' "'three'" sir_not_appearing_in_this_film)
+  print ${args:|mod}
+  print ${args:*mod}
+  print "${(@)args:|mod}"
+  print "${(@)args:*mod}"
+  args=(two words)
+  mod=('one word' 'two words')
+  print "${args:|mod}"
+  print "${args:*mod}"
+  scalar='two words'
+  print ${scalar:|mod}
+  print ${scalar:*mod}
+0:"|" array exclusion and "*" array intersection
+>one two
+>#foo (bar 'three'
+>one two
+>#foo (bar 'three'
+>
+>two words
+>
+>two words
+
   str1='twocubed'
   array=(the number of protons in an oxygen nucleus)
   print $#str1 ${#str1} "$#str1 ${#str1}" $#array ${#array} "$#array ${#array}"