Commit | Line | Data |
---|---|---|
f38ab8af | 1 | # perf bash and zsh completion |
b2441318 | 2 | # SPDX-License-Identifier: GPL-2.0 |
98a4179c | 3 | |
c3fb6717 RR |
4 | # Taken from git.git's completion script. |
5 | __my_reassemble_comp_words_by_ref() | |
6 | { | |
7 | local exclude i j first | |
8 | # Which word separators to exclude? | |
9 | exclude="${1//[^$COMP_WORDBREAKS]}" | |
10 | cword_=$COMP_CWORD | |
11 | if [ -z "$exclude" ]; then | |
12 | words_=("${COMP_WORDS[@]}") | |
13 | return | |
14 | fi | |
15 | # List of word completion separators has shrunk; | |
16 | # re-assemble words to complete. | |
17 | for ((i=0, j=0; i < ${#COMP_WORDS[@]}; i++, j++)); do | |
18 | # Append each nonempty word consisting of just | |
19 | # word separator characters to the current word. | |
20 | first=t | |
21 | while | |
22 | [ $i -gt 0 ] && | |
23 | [ -n "${COMP_WORDS[$i]}" ] && | |
24 | # word consists of excluded word separators | |
25 | [ "${COMP_WORDS[$i]//[^$exclude]}" = "${COMP_WORDS[$i]}" ] | |
26 | do | |
27 | # Attach to the previous token, | |
28 | # unless the previous token is the command name. | |
29 | if [ $j -ge 2 ] && [ -n "$first" ]; then | |
30 | ((j--)) | |
31 | fi | |
32 | first= | |
33 | words_[$j]=${words_[j]}${COMP_WORDS[i]} | |
34 | if [ $i = $COMP_CWORD ]; then | |
35 | cword_=$j | |
36 | fi | |
37 | if (($i < ${#COMP_WORDS[@]} - 1)); then | |
38 | ((i++)) | |
39 | else | |
40 | # Done. | |
41 | return | |
42 | fi | |
43 | done | |
44 | words_[$j]=${words_[j]}${COMP_WORDS[i]} | |
45 | if [ $i = $COMP_CWORD ]; then | |
46 | cword_=$j | |
47 | fi | |
48 | done | |
49 | } | |
50 | ||
1312c8a8 YS |
51 | # Define preload_get_comp_words_by_ref="false", if the function |
52 | # __perf_get_comp_words_by_ref() is required instead. | |
53 | preload_get_comp_words_by_ref="true" | |
54 | ||
55 | if [ $preload_get_comp_words_by_ref = "true" ]; then | |
56 | type _get_comp_words_by_ref &>/dev/null || | |
57 | preload_get_comp_words_by_ref="false" | |
58 | fi | |
59 | [ $preload_get_comp_words_by_ref = "true" ] || | |
60 | __perf_get_comp_words_by_ref() | |
c3fb6717 RR |
61 | { |
62 | local exclude cur_ words_ cword_ | |
63 | if [ "$1" = "-n" ]; then | |
64 | exclude=$2 | |
65 | shift 2 | |
66 | fi | |
67 | __my_reassemble_comp_words_by_ref "$exclude" | |
68 | cur_=${words_[cword_]} | |
69 | while [ $# -gt 0 ]; do | |
70 | case "$1" in | |
71 | cur) | |
72 | cur=$cur_ | |
73 | ;; | |
74 | prev) | |
75 | prev=${words_[$cword_-1]} | |
76 | ;; | |
77 | words) | |
78 | words=("${words_[@]}") | |
79 | ;; | |
80 | cword) | |
81 | cword=$cword_ | |
82 | ;; | |
83 | esac | |
84 | shift | |
85 | done | |
86 | } | |
87 | ||
1312c8a8 YS |
88 | # Define preload__ltrim_colon_completions="false", if the function |
89 | # __perf__ltrim_colon_completions() is required instead. | |
90 | preload__ltrim_colon_completions="true" | |
91 | ||
92 | if [ $preload__ltrim_colon_completions = "true" ]; then | |
93 | type __ltrim_colon_completions &>/dev/null || | |
94 | preload__ltrim_colon_completions="false" | |
95 | fi | |
96 | [ $preload__ltrim_colon_completions = "true" ] || | |
97 | __perf__ltrim_colon_completions() | |
ae0c1f99 NK |
98 | { |
99 | if [[ "$1" == *:* && "$COMP_WORDBREAKS" == *:* ]]; then | |
100 | # Remove colon-word prefix from COMPREPLY items | |
30079d1d | 101 | local colon_word=${1%"${1##*:}"} |
ae0c1f99 NK |
102 | local i=${#COMPREPLY[*]} |
103 | while [[ $((--i)) -ge 0 ]]; do | |
104 | COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"} | |
105 | done | |
106 | fi | |
107 | } | |
108 | ||
12f9dd50 RR |
109 | __perfcomp () |
110 | { | |
111 | COMPREPLY=( $( compgen -W "$1" -- "$2" ) ) | |
112 | } | |
113 | ||
37e72c31 RR |
114 | __perfcomp_colon () |
115 | { | |
116 | __perfcomp "$1" "$2" | |
1312c8a8 YS |
117 | if [ $preload__ltrim_colon_completions = "true" ]; then |
118 | __ltrim_colon_completions $cur | |
119 | else | |
120 | __perf__ltrim_colon_completions $cur | |
121 | fi | |
37e72c31 RR |
122 | } |
123 | ||
67afff48 YS |
124 | __perf_prev_skip_opts () |
125 | { | |
126 | local i cmd_ cmds_ | |
127 | ||
128 | let i=cword-1 | |
eee200a6 | 129 | cmds_=$($cmd $1 --list-cmds) |
67afff48 YS |
130 | prev_skip_opts=() |
131 | while [ $i -ge 0 ]; do | |
eee200a6 YS |
132 | if [[ ${words[i]} == $1 ]]; then |
133 | return | |
134 | fi | |
67afff48 YS |
135 | for cmd_ in $cmds_; do |
136 | if [[ ${words[i]} == $cmd_ ]]; then | |
137 | prev_skip_opts=${words[i]} | |
138 | return | |
139 | fi | |
140 | done | |
141 | ((i--)) | |
142 | done | |
143 | } | |
6fdd9cb7 | 144 | |
2cf025e6 | 145 | __perf_main () |
98a4179c | 146 | { |
2cf025e6 | 147 | local cmd |
98a4179c | 148 | |
6e0dc374 | 149 | cmd=${words[0]} |
2cf025e6 | 150 | COMPREPLY=() |
98a4179c | 151 | |
67afff48 YS |
152 | # Skip options backward and find the last perf command |
153 | __perf_prev_skip_opts | |
35c2fde1 | 154 | # List perf subcommands or long options |
e003ce54 | 155 | if [ -z $prev_skip_opts ]; then |
35c2fde1 | 156 | if [[ $cur == --* ]]; then |
7335399a | 157 | cmds=$($cmd --list-opts) |
35c2fde1 NK |
158 | else |
159 | cmds=$($cmd --list-cmds) | |
35c2fde1 | 160 | fi |
7335399a | 161 | __perfcomp "$cmds" "$cur" |
6fdd9cb7 YS |
162 | # List possible events for -e option |
163 | elif [[ $prev == @("-e"|"--event") && | |
164 | $prev_skip_opts == @(record|stat|top) ]]; then | |
74cd5815 JY |
165 | |
166 | local cur1=${COMP_WORDS[COMP_CWORD]} | |
10864594 | 167 | local raw_evts=$($cmd list --raw-dump hw sw cache tracepoint pmu sdt) |
ffd1240e YY |
168 | local arr s tmp result cpu_evts |
169 | ||
170 | # aarch64 doesn't have /sys/bus/event_source/devices/cpu/events | |
171 | if [[ `uname -m` != aarch64 ]]; then | |
172 | cpu_evts=$(ls /sys/bus/event_source/devices/cpu/events) | |
173 | fi | |
74cd5815 JY |
174 | |
175 | if [[ "$cur1" == */* && ${cur1#*/} =~ ^[A-Z] ]]; then | |
176 | OLD_IFS="$IFS" | |
177 | IFS=" " | |
178 | arr=($raw_evts) | |
179 | IFS="$OLD_IFS" | |
180 | ||
181 | for s in ${arr[@]} | |
182 | do | |
183 | if [[ "$s" == *cpu/* ]]; then | |
184 | tmp=${s#*cpu/} | |
185 | result=$result" ""cpu/"${tmp^^} | |
186 | else | |
187 | result=$result" "$s | |
188 | fi | |
189 | done | |
190 | ||
ffd1240e | 191 | evts=${result}" "${cpu_evts} |
74cd5815 | 192 | else |
ffd1240e | 193 | evts=${raw_evts}" "${cpu_evts} |
74cd5815 JY |
194 | fi |
195 | ||
34c16db0 JY |
196 | if [[ "$cur1" == , ]]; then |
197 | __perfcomp_colon "$evts" "" | |
198 | else | |
199 | __perfcomp_colon "$evts" "$cur1" | |
200 | fi | |
493902fc IR |
201 | elif [[ $prev == @("--pfm-events") && |
202 | $prev_skip_opts == @(record|stat|top) ]]; then | |
203 | local evts=$($cmd list --raw-dump pfm) | |
204 | __perfcomp "$evts" "$cur" | |
fa880958 IR |
205 | elif [[ $prev == @("-M"|"--metrics") && |
206 | $prev_skip_opts == @(stat) ]]; then | |
207 | local metrics=$($cmd list --raw-dump metric metricgroup) | |
208 | __perfcomp "$metrics" "$cur" | |
02fde323 YS |
209 | else |
210 | # List subcommands for perf commands | |
6fdd9cb7 YS |
211 | if [[ $prev_skip_opts == @(kvm|kmem|mem|lock|sched| |
212 | |data|help|script|test|timechart|trace) ]]; then | |
67afff48 | 213 | subcmds=$($cmd $prev_skip_opts --list-cmds) |
02fde323 YS |
214 | __perfcomp_colon "$subcmds" "$cur" |
215 | fi | |
216 | # List long option names | |
217 | if [[ $cur == --* ]]; then | |
eee200a6 YS |
218 | subcmd=$prev_skip_opts |
219 | __perf_prev_skip_opts $subcmd | |
220 | subcmd=$subcmd" "$prev_skip_opts | |
02fde323 YS |
221 | opts=$($cmd $subcmd --list-opts) |
222 | __perfcomp "$opts" "$cur" | |
223 | fi | |
98a4179c | 224 | fi |
2cf025e6 RR |
225 | } |
226 | ||
f38ab8af RR |
227 | if [[ -n ${ZSH_VERSION-} ]]; then |
228 | autoload -U +X compinit && compinit | |
229 | ||
230 | __perfcomp () | |
231 | { | |
232 | emulate -L zsh | |
233 | ||
234 | local c IFS=$' \t\n' | |
235 | local -a array | |
236 | ||
237 | for c in ${=1}; do | |
238 | case $c in | |
239 | --*=*|*.) ;; | |
240 | *) c="$c " ;; | |
241 | esac | |
242 | array[${#array[@]}+1]="$c" | |
243 | done | |
244 | ||
245 | compset -P '*[=:]' | |
246 | compadd -Q -S '' -a -- array && _ret=0 | |
247 | } | |
248 | ||
249 | __perfcomp_colon () | |
250 | { | |
251 | emulate -L zsh | |
252 | ||
253 | local cur_="${2-$cur}" | |
254 | local c IFS=$' \t\n' | |
255 | local -a array | |
256 | ||
257 | if [[ "$cur_" == *:* ]]; then | |
258 | local colon_word=${cur_%"${cur_##*:}"} | |
259 | fi | |
260 | ||
261 | for c in ${=1}; do | |
262 | case $c in | |
263 | --*=*|*.) ;; | |
264 | *) c="$c " ;; | |
265 | esac | |
266 | array[$#array+1]=${c#"$colon_word"} | |
267 | done | |
268 | ||
269 | compset -P '*[=:]' | |
270 | compadd -Q -S '' -a -- array && _ret=0 | |
271 | } | |
272 | ||
273 | _perf () | |
274 | { | |
275 | local _ret=1 cur cword prev | |
276 | cur=${words[CURRENT]} | |
277 | prev=${words[CURRENT-1]} | |
278 | let cword=CURRENT-1 | |
279 | emulate ksh -c __perf_main | |
280 | let _ret && _default && _ret=0 | |
281 | return _ret | |
282 | } | |
283 | ||
284 | compdef _perf perf | |
285 | return | |
286 | fi | |
287 | ||
2cf025e6 RR |
288 | type perf &>/dev/null && |
289 | _perf() | |
290 | { | |
74cd5815 JY |
291 | if [[ "$COMP_WORDBREAKS" != *,* ]]; then |
292 | COMP_WORDBREAKS="${COMP_WORDBREAKS}," | |
293 | export COMP_WORDBREAKS | |
294 | fi | |
295 | ||
5d4fd9c8 JY |
296 | if [[ "$COMP_WORDBREAKS" == *:* ]]; then |
297 | COMP_WORDBREAKS="${COMP_WORDBREAKS/:/}" | |
298 | export COMP_WORDBREAKS | |
299 | fi | |
300 | ||
2cf025e6 | 301 | local cur words cword prev |
1312c8a8 | 302 | if [ $preload_get_comp_words_by_ref = "true" ]; then |
74cd5815 | 303 | _get_comp_words_by_ref -n =:, cur words cword prev |
1312c8a8 | 304 | else |
74cd5815 | 305 | __perf_get_comp_words_by_ref -n =:, cur words cword prev |
1312c8a8 | 306 | fi |
2cf025e6 | 307 | __perf_main |
98a4179c | 308 | } && |
7b6c48e1 RR |
309 | |
310 | complete -o bashdefault -o default -o nospace -F _perf perf 2>/dev/null \ | |
311 | || complete -o default -o nospace -F _perf perf |