@@ -245,6 +245,124 @@ _upvars()
245245 done
246246}
247247
248+ # Filter the array elements with the specified condition.
249+ # @param $1 Array name (that is not "value" or other internal variable names)
250+ # @param $2 When none of the options -EFG are specified, this is used as the
251+ # command that tests the array element. If this is an existing function
252+ # name, the function is called with the value of the array element.
253+ # Otherwise, this shall be the shell command that tests the array-element
254+ # value stored in the shell variable "value".
255+ #
256+ # Options:
257+ # -E $2 is interpreted as a POSIX extended regular expression.
258+ # This is always the partial matching unless ^, $ is included
259+ # in $2.
260+ # -F $2 is interpreted as a fixed string.
261+ # -G $2 is interpreted as a glob pattern.
262+ #
263+ # -p Combined with -F or -G, it performs the prefix matching.
264+ # -s Combined with -F or -G, it performs the suffix matching.
265+ # -m Combined with -F or -G, it performs the middle matching.
266+ # -r Revert the condition, i.e., remove elements that satisfy
267+ # the original condition.
268+ #
269+ # -C Array compaction is not performed.
270+ #
271+ # @return 2 with a wrong usage, 1 when any elements are removed, 0 when the set
272+ # of array elements are unchanged. [ Note: the compaction will be performed
273+ # (without the option -C) even when the set of array elements are
274+ # unchanged. ]
275+ _comp_array_filter ()
276+ {
277+ local __comp_flags=' ' __comp_pattype=' ' __comp_anchoring=' '
278+ local OPTIND=1 OPTARG=' ' OPTERR=0 __comp_opt=' '
279+ while getopts ' EFGpsmrC' __comp_opt " $@ " ; do
280+ case $__comp_opt in
281+ [EFG]) __comp_pattype=$__comp_opt ;;
282+ [psm]) __comp_anchoring=$__comp_opt ;;
283+ [rC]) __comp_flags=$__comp_opt$__comp_flags ;;
284+ * )
285+ echo " bash_completion: $FUNCNAME : usage error" >&2
286+ return 2
287+ ;;
288+ esac
289+ done
290+
291+ shift $(( OPTIND - 1 ))
292+ if (( $# != 2 )) ; then
293+ printf ' bash_completion: %s: %s\n' " $FUNCNAME " " unexpected number of arguments." >&2
294+ printf ' usage: %s %s\n' " $FUNCNAME " " [-EFGpsmrC] ARRAY_NAME CONDITION" >&2
295+ return 2
296+ elif [[ $1 != [a-zA-Z_]* ([a-zA-Z_0-9]) ]]; then
297+ printf ' bash_completion: %s: %s\n' " $FUNCNAME " " invalid array name '$1 '." >&2
298+ return 2
299+ elif [[ $1 == @ (__comp_* | OPTIND| OPTARG| OPTERR) ]]; then
300+ printf ' bash_completion: %s: %s\n' " $FUNCNAME " " array name '$1 ' is reserved for internal uses." >&2
301+ return 2
302+ elif [[ ! $__comp_pattype && $1 == value ]]; then
303+ printf ' bash_completion: %s: %s\n' " $FUNCNAME " " array name '$1 ' cannot be used for the predicate." >&2
304+ return 2
305+ fi
306+ # When the array is empty:
307+ eval " ((\$ {#$1 [@]}))" || return 0
308+
309+ local __comp_predicate=' ' __comp_pattern=$2
310+ case $__comp_pattype in
311+ E)
312+ __comp_predicate=' [[ $__comp_value == $__comp_pattern ]]'
313+ ;;
314+ F)
315+ case $__comp_anchoring in
316+ p) __comp_predicate=' [[ $__comp_value == "$__comp_pattern"* ]]' ;;
317+ s) __comp_predicate=' [[ $__comp_value == *"$__comp_pattern" ]]' ;;
318+ m) __comp_predicate=' [[ $__comp_value == *"$__comp_pattern"* ]]' ;;
319+ * ) __comp_predicate=' [[ $__comp_value == "$__comp_pattern" ]]' ;;
320+ esac
321+ ;;
322+ G)
323+ case $__comp_anchoring in
324+ p) __comp_predicate=' [[ $__comp_value == $__comp_pattern* ]]' ;;
325+ s) __comp_predicate=' [[ $__comp_value == *$__comp_pattern ]]' ;;
326+ m) __comp_predicate=' [[ $__comp_value == *$__comp_pattern* ]]' ;;
327+ * ) __comp_predicate=' [[ $__comp_value == $__comp_pattern ]]' ;;
328+ esac
329+ ;;
330+ * )
331+ if declare -F " $2 " & > /dev/null; then
332+ _comp_predicate=" $2 \"\$ __comp_value\" "
333+ else
334+ _comp_predicate=" local value=\$ __comp_value; $2 "
335+ fi
336+ ;;
337+ esac
338+
339+ local __comp_unset=' ' __comp_expected_status=0
340+ [[ $__comp_flags == * r* ]] && __comp_expected_status=1
341+
342+ local __comp_indices __comp_index __comp_value
343+ eval " __comp_indices=(\"\$ {!$1 [@]}\" )"
344+ for __comp_index in " ${__comp_indices[@]} " ; do
345+ eval " __comp_value=\$ {$1 [\$ __comp_index]}; $__comp_predicate "
346+ case $? in
347+ " $__comp_expected_status " ) continue ;;
348+ [01])
349+ unset -v " $1 [\$ __comp_index]"
350+ __comp_unset=1
351+ ;;
352+ * )
353+ printf ' bash_completion: %s: %s\n' " $FUNCNAME " " the filter condition broken." >&2
354+ return 2
355+ ;;
356+ esac
357+ done
358+
359+ # Compaction of the sparse array
360+ [[ $__comp_flags == * C* ]] ||
361+ eval -- " ((\$ {#$1 [@]})) && $1 =(\"\$ {$1 [@]}\" )"
362+
363+ [[ ! $__comp_unset ]]
364+ }
365+
248366# Reassemble command line words, excluding specified characters from the
249367# list of word completion separators (COMP_WORDBREAKS).
250368# @param $1 chars Characters out of $COMP_WORDBREAKS which should
0 commit comments