Skip to content

Commit ba54e99

Browse files
akinomyogacalestyo
andcommitted
feat(completions/ARRAY): add _comp_xfunc_ARRAY_filter
Co-authored-by: Christoph Anton Mitterer <[email protected]>
1 parent 3b3e1c9 commit ba54e99

File tree

1 file changed

+151
-0
lines changed

1 file changed

+151
-0
lines changed

completions/ARRAY

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
# Utility xfunc functions for array manipulations -*- shell-script -*-
2+
3+
# Filter the array elements with the specified condition.
4+
# @param $1 Array name (that is not "value" or other internal variable names)
5+
# @param $2 When any of the options `-EFG' is specified, the second argument is
6+
# used as a pattern string whose meaning is determined by the option `-EFG'.
7+
# Otherwise, the second argument specifies the command that tests the array
8+
# element. The command is supposed to exit with:
9+
#
10+
# status 0 .... when the element should be preserved
11+
# status 1 .... when the element should be removed
12+
# status 2 .... when the usage of the predicate is wrong
13+
# status 27 ... when the loop should be canceled. All the remaining
14+
# elements will be preserved regardless of the presence of
15+
# option `-r'.
16+
#
17+
# The other exit statuses are reserved and cancel the array filtering with an
18+
# error message, and the function returns with the exit status 2. If this is
19+
# an existing command name, the command is called with the value of the array
20+
# element being specified as the first command argument. Otherwise, this
21+
# shall be a shell command that tests the array-element value stored in the
22+
# environment variable "value".
23+
#
24+
# Options:
25+
#
26+
# The following options specify the type of the pattern. When mutiple
27+
# options are supplied, the last-specified one overwrite the previous
28+
# option.
29+
#
30+
# -E $2 is interpreted as a POSIX extended regular expression.
31+
# The default anchoring is `-m` (see below).
32+
# -F $2 is interpreted as a fixed string. The default anchoring
33+
# is `-m` (see below).
34+
# -G $2 is interpreted as a glob pattern. The default anchoring
35+
# is `-x` (see below).
36+
#
37+
# Combined with any of -EFG, the following options specify the anchoring
38+
# type of the pattern matching. When multiple options are supplied, the
39+
# last-specified one overwrites the previous option.
40+
#
41+
# -p performs the prefix matching.
42+
# -s performs the suffix matching.
43+
# -m performs the middle matching.
44+
# -x performs the exact matching.
45+
#
46+
# -r Revert the condition, i.e., remove elements that satisfy
47+
# the original condition.
48+
# -C Array compaction is not performed.
49+
#
50+
# @return 2 with a wrong usage, 1 when any elements are removed, 0 when the set
51+
# of array elements are unchanged. [ Note: the compaction will be performed
52+
# (without the option -C) even when the set of array elements are
53+
# unchanged. ]
54+
_comp_xfunc_ARRAY_filter()
55+
{
56+
local _comp_local_flags='' _comp_local_pattype='' _comp_local_anchoring=''
57+
local OPTIND=1 OPTARG='' OPTERR=0 _comp_local_opt=''
58+
while getopts 'EFGpsmxrC' _comp_local_opt "$@"; do
59+
case $_comp_local_opt in
60+
[EFG]) _comp_local_pattype=$_comp_local_opt ;;
61+
[psmx]) _comp_local_anchoring=$_comp_local_opt ;;
62+
[rC]) _comp_local_flags=$_comp_local_opt$_comp_local_flags ;;
63+
*)
64+
printf 'bash_completion: %s: %s\n' "$FUNCNAME" 'usage error' >&2
65+
printf 'usage: %s %s\n' "$FUNCNAME" "[-EFGpsmxrC] ARRAY_NAME CONDITION" >&2
66+
return 2
67+
;;
68+
esac
69+
done
70+
71+
shift "$((OPTIND - 1))"
72+
if (($# != 2)); then
73+
printf 'bash_completion: %s: %s\n' "$FUNCNAME" "unexpected number of arguments: $#" >&2
74+
printf 'usage: %s %s\n' "$FUNCNAME" "[-EFGpsmxrC] ARRAY_NAME CONDITION" >&2
75+
return 2
76+
elif [[ $1 != [a-zA-Z_]*([a-zA-Z_0-9]) ]]; then
77+
printf 'bash_completion: %s: %s\n' "$FUNCNAME" "invalid array name '$1'." >&2
78+
return 2
79+
elif [[ $1 == @(_comp_local_*|OPTIND|OPTARG|OPTERR) ]]; then
80+
printf 'bash_completion: %s: %s\n' "$FUNCNAME" "array name '$1' is reserved for internal uses" >&2
81+
return 2
82+
elif [[ ! $_comp_local_pattype && $1 == value ]]; then
83+
printf 'bash_completion: %s: %s\n' "$FUNCNAME" "array name '$1' cannot be used for the predicate" >&2
84+
return 2
85+
fi
86+
# When the array is empty:
87+
eval "((\${#$1[@]}))" || return 0
88+
89+
local _comp_local_predicate='' _comp_local_pattern=$2
90+
case $_comp_local_pattype in
91+
E)
92+
case $_comp_local_anchoring in
93+
p) _comp_local_predicate='[[ $_comp_local_value =~ ^($_comp_local_pattern) ]]' ;;
94+
s) _comp_local_predicate='[[ $_comp_local_value =~ ($_comp_local_pattern)$ ]]' ;;
95+
x) _comp_local_predicate='[[ $_comp_local_value =~ ^($_comp_local_pattern)$ ]]' ;;
96+
*) _comp_local_predicate='[[ $_comp_local_value =~ $_comp_local_pattern ]]' ;;
97+
esac
98+
;;
99+
F)
100+
case $_comp_local_anchoring in
101+
p) _comp_local_predicate='[[ $_comp_local_value == "$_comp_local_pattern"* ]]' ;;
102+
s) _comp_local_predicate='[[ $_comp_local_value == *"$_comp_local_pattern" ]]' ;;
103+
x) _comp_local_predicate='[[ $_comp_local_value == "$_comp_local_pattern" ]]' ;;
104+
*) _comp_local_predicate='[[ $_comp_local_value == *"$_comp_local_pattern"* ]]' ;;
105+
esac
106+
;;
107+
G)
108+
case $_comp_local_anchoring in
109+
p) _comp_local_predicate='[[ $_comp_local_value == $_comp_local_pattern* ]]' ;;
110+
s) _comp_local_predicate='[[ $_comp_local_value == *$_comp_local_pattern ]]' ;;
111+
m) _comp_local_predicate='[[ $_comp_local_value == *$_comp_local_pattern* ]]' ;;
112+
*) _comp_local_predicate='[[ $_comp_local_value == $_comp_local_pattern ]]' ;;
113+
esac
114+
;;
115+
*)
116+
if type -t "$2" &>/dev/null; then
117+
_comp_local_predicate="$2 \"\$_comp_local_value\""
118+
else
119+
_comp_local_predicate="local -x value=\$_comp_local_value; $2"
120+
fi
121+
;;
122+
esac
123+
124+
local _comp_local_unset='' _comp_local_expected_status=0
125+
[[ $_comp_local_flags == *r* ]] && _comp_local_expected_status=1
126+
127+
local _comp_local_indices _comp_local_index _comp_local_value
128+
eval "_comp_local_indices=(\"\${!$1[@]}\")"
129+
for _comp_local_index in "${_comp_local_indices[@]}"; do
130+
eval "_comp_local_value=\${$1[\$_comp_local_index]}; $_comp_local_predicate"
131+
case $? in
132+
"$_comp_local_expected_status") continue ;;
133+
[01])
134+
unset -v "$1[\$_comp_local_index]"
135+
_comp_local_unset=1
136+
;;
137+
27) break ;;
138+
*)
139+
printf 'bash_completion: %s: %s\n' "$FUNCNAME" \
140+
"filter condition broken '${_comp_local_pattype:+-$_comp_local_pattype }$2'" >&2
141+
return 2
142+
;;
143+
esac
144+
done
145+
146+
# Compaction of the sparse array
147+
[[ $_comp_local_flags == *C* ]] ||
148+
eval "((\${#$1[@]})) && $1=(\"\${$1[@]}\")"
149+
150+
[[ ! $_comp_local_unset ]]
151+
}

0 commit comments

Comments
 (0)