1# perf bash and zsh completion 2# SPDX-License-Identifier: GPL-2.0 3 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 51# Define preload_get_comp_words_by_ref="false", if the function 52# __perf_get_comp_words_by_ref() is required instead. 53preload_get_comp_words_by_ref="true" 54 55if [ $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" 58fi 59[ $preload_get_comp_words_by_ref = "true" ] || 60__perf_get_comp_words_by_ref() 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 88# Define preload__ltrim_colon_completions="false", if the function 89# __perf__ltrim_colon_completions() is required instead. 90preload__ltrim_colon_completions="true" 91 92if [ $preload__ltrim_colon_completions = "true" ]; then 93 type __ltrim_colon_completions &>/dev/null || 94 preload__ltrim_colon_completions="false" 95fi 96[ $preload__ltrim_colon_completions = "true" ] || 97__perf__ltrim_colon_completions() 98{ 99 if [[ "$1" == *:* && "$COMP_WORDBREAKS" == *:* ]]; then 100 # Remove colon-word prefix from COMPREPLY items 101 local colon_word=${1%"${1##*:}"} 102 local i=${#COMPREPLY[*]} 103 while [[ $((--i)) -ge 0 ]]; do 104 COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"} 105 done 106 fi 107} 108 109__perfcomp () 110{ 111 COMPREPLY=( $( compgen -W "$1" -- "$2" ) ) 112} 113 114__perfcomp_colon () 115{ 116 __perfcomp "$1" "$2" 117 if [ $preload__ltrim_colon_completions = "true" ]; then 118 __ltrim_colon_completions $cur 119 else 120 __perf__ltrim_colon_completions $cur 121 fi 122} 123 124__perf_prev_skip_opts () 125{ 126 local i cmd_ cmds_ 127 128 let i=cword-1 129 cmds_=$($cmd $1 --list-cmds) 130 prev_skip_opts=() 131 while [ $i -ge 0 ]; do 132 if [[ ${words[i]} == $1 ]]; then 133 return 134 fi 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} 144 145__perf_main () 146{ 147 local cmd 148 149 cmd=${words[0]} 150 COMPREPLY=() 151 152 # Skip options backward and find the last perf command 153 __perf_prev_skip_opts 154 # List perf subcommands or long options 155 if [ -z $prev_skip_opts ]; then 156 if [[ $cur == --* ]]; then 157 cmds=$($cmd --list-opts) 158 else 159 cmds=$($cmd --list-cmds) 160 fi 161 __perfcomp "$cmds" "$cur" 162 # List possible events for -e option 163 elif [[ $prev == @("-e"|"--event") && 164 $prev_skip_opts == @(record|stat|top) ]]; then 165 166 local cur1=${COMP_WORDS[COMP_CWORD]} 167 local raw_evts=$($cmd list --raw-dump hw sw cache tracepoint pmu sdt) 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 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 191 evts=${result}" "${cpu_evts} 192 else 193 evts=${raw_evts}" "${cpu_evts} 194 fi 195 196 if [[ "$cur1" == , ]]; then 197 __perfcomp_colon "$evts" "" 198 else 199 __perfcomp_colon "$evts" "$cur1" 200 fi 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" 205 elif [[ $prev == @("-M"|"--metrics") && 206 $prev_skip_opts == @(stat) ]]; then 207 local metrics=$($cmd list --raw-dump metric metricgroup) 208 __perfcomp "$metrics" "$cur" 209 else 210 # List subcommands for perf commands 211 if [[ $prev_skip_opts == @(kvm|kmem|mem|lock|sched| 212 |data|help|script|test|timechart|trace) ]]; then 213 subcmds=$($cmd $prev_skip_opts --list-cmds) 214 __perfcomp_colon "$subcmds" "$cur" 215 fi 216 # List long option names 217 if [[ $cur == --* ]]; then 218 subcmd=$prev_skip_opts 219 __perf_prev_skip_opts $subcmd 220 subcmd=$subcmd" "$prev_skip_opts 221 opts=$($cmd $subcmd --list-opts) 222 __perfcomp "$opts" "$cur" 223 fi 224 fi 225} 226 227if [[ -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 286fi 287 288type perf &>/dev/null && 289_perf() 290{ 291 if [[ "$COMP_WORDBREAKS" != *,* ]]; then 292 COMP_WORDBREAKS="${COMP_WORDBREAKS}," 293 export COMP_WORDBREAKS 294 fi 295 296 if [[ "$COMP_WORDBREAKS" == *:* ]]; then 297 COMP_WORDBREAKS="${COMP_WORDBREAKS/:/}" 298 export COMP_WORDBREAKS 299 fi 300 301 local cur words cword prev 302 if [ $preload_get_comp_words_by_ref = "true" ]; then 303 _get_comp_words_by_ref -n =:, cur words cword prev 304 else 305 __perf_get_comp_words_by_ref -n =:, cur words cword prev 306 fi 307 __perf_main 308} && 309 310complete -o bashdefault -o default -o nospace -F _perf perf 2>/dev/null \ 311 || complete -o default -o nospace -F _perf perf 312