Skip to content

Commit bc6f87d

Browse files
committed
feat(bash_completion): add _comp_array_filter
1 parent 05b4159 commit bc6f87d

File tree

1 file changed

+118
-0
lines changed

1 file changed

+118
-0
lines changed

bash_completion

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)