321 lines · bash
1# perf bash and zsh completion2# SPDX-License-Identifier: GPL-2.03 4# Taken from git.git's completion script.5__my_reassemble_comp_words_by_ref()6{7 local exclude i j first8 # Which word separators to exclude?9 exclude="${1//[^$COMP_WORDBREAKS]}"10 cword_=$COMP_CWORD11 if [ -z "$exclude" ]; then12 words_=("${COMP_WORDS[@]}")13 return14 fi15 # List of word completion separators has shrunk;16 # re-assemble words to complete.17 for ((i=0, j=0; i < ${#COMP_WORDS[@]}; i++, j++)); do18 # Append each nonempty word consisting of just19 # word separator characters to the current word.20 first=t21 while22 [ $i -gt 0 ] &&23 [ -n "${COMP_WORDS[$i]}" ] &&24 # word consists of excluded word separators25 [ "${COMP_WORDS[$i]//[^$exclude]}" = "${COMP_WORDS[$i]}" ]26 do27 # Attach to the previous token,28 # unless the previous token is the command name.29 if [ $j -ge 2 ] && [ -n "$first" ]; then30 ((j--))31 fi32 first=33 words_[$j]=${words_[j]}${COMP_WORDS[i]}34 if [ $i = $COMP_CWORD ]; then35 cword_=$j36 fi37 if (($i < ${#COMP_WORDS[@]} - 1)); then38 ((i++))39 else40 # Done.41 return42 fi43 done44 words_[$j]=${words_[j]}${COMP_WORDS[i]}45 if [ $i = $COMP_CWORD ]; then46 cword_=$j47 fi48 done49}50 51# Define preload_get_comp_words_by_ref="false", if the function52# __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" ]; then56 type _get_comp_words_by_ref &>/dev/null ||57 preload_get_comp_words_by_ref="false"58fi59[ $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" ]; then64 exclude=$265 shift 266 fi67 __my_reassemble_comp_words_by_ref "$exclude"68 cur_=${words_[cword_]}69 while [ $# -gt 0 ]; do70 case "$1" in71 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 esac84 shift85 done86}87 88# Define preload__ltrim_colon_completions="false", if the function89# __perf__ltrim_colon_completions() is required instead.90preload__ltrim_colon_completions="true"91 92if [ $preload__ltrim_colon_completions = "true" ]; then93 type __ltrim_colon_completions &>/dev/null ||94 preload__ltrim_colon_completions="false"95fi96[ $preload__ltrim_colon_completions = "true" ] ||97__perf__ltrim_colon_completions()98{99 if [[ "$1" == *:* && "$COMP_WORDBREAKS" == *:* ]]; then100 # Remove colon-word prefix from COMPREPLY items101 local colon_word=${1%"${1##*:}"}102 local i=${#COMPREPLY[*]}103 while [[ $((--i)) -ge 0 ]]; do104 COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"}105 done106 fi107}108 109__perfcomp ()110{111 # Expansion of spaces to array is deliberate.112 # shellcheck disable=SC2207113 COMPREPLY=( $( compgen -W "$1" -- "$2" ) )114}115 116__perfcomp_colon ()117{118 __perfcomp "$1" "$2"119 if [ $preload__ltrim_colon_completions = "true" ]; then120 __ltrim_colon_completions $cur121 else122 __perf__ltrim_colon_completions $cur123 fi124}125 126__perf_prev_skip_opts ()127{128 local i cmd_ cmds_129 130 let i=cword-1131 cmds_=$($cmd $1 --list-cmds)132 prev_skip_opts=""133 while [ $i -ge 0 ]; do134 if [[ ${words[i]} == "$1" ]]; then135 return136 fi137 for cmd_ in $cmds_; do138 if [[ ${words[i]} == "$cmd_" ]]; then139 prev_skip_opts=${words[i]}140 return141 fi142 done143 ((i--))144 done145}146 147__perf_main ()148{149 local cmd150 151 cmd=${words[0]}152 COMPREPLY=()153 154 # Skip options backward and find the last perf command155 __perf_prev_skip_opts156 # List perf subcommands or long options157 if [ -z $prev_skip_opts ]; then158 if [[ $cur == --* ]]; then159 cmds=$($cmd --list-opts)160 else161 cmds=$($cmd --list-cmds)162 fi163 __perfcomp "$cmds" "$cur"164 # List possible events for -e option165 elif [[ $prev == @("-e"|"--event") &&166 $prev_skip_opts == @(record|stat|top) ]]; then167 168 local cur1=${COMP_WORDS[COMP_CWORD]}169 local raw_evts170 local arr s tmp result cpu_evts171 172 raw_evts=$($cmd list --raw-dump hw sw cache tracepoint pmu sdt)173 # aarch64 doesn't have /sys/bus/event_source/devices/cpu/events174 if [[ `uname -m` != aarch64 ]]; then175 cpu_evts=$(ls /sys/bus/event_source/devices/cpu/events)176 fi177 178 if [[ "$cur1" == */* && ${cur1#*/} =~ ^[A-Z] ]]; then179 OLD_IFS="$IFS"180 IFS=" "181 # Expansion of spaces to array is deliberate.182 # shellcheck disable=SC2206183 arr=($raw_evts)184 IFS="$OLD_IFS"185 186 for s in "${arr[@]}"187 do188 if [[ "$s" == *cpu/* ]]; then189 tmp=${s#*cpu/}190 result=$result" ""cpu/"${tmp^^}191 else192 result=$result" "$s193 fi194 done195 196 evts=${result}" "${cpu_evts}197 else198 evts=${raw_evts}" "${cpu_evts}199 fi200 201 if [[ "$cur1" == , ]]; then202 __perfcomp_colon "$evts" ""203 else204 __perfcomp_colon "$evts" "$cur1"205 fi206 elif [[ $prev == @("--pfm-events") &&207 $prev_skip_opts == @(record|stat|top) ]]; then208 local evts209 evts=$($cmd list --raw-dump pfm)210 __perfcomp "$evts" "$cur"211 elif [[ $prev == @("-M"|"--metrics") &&212 $prev_skip_opts == @(stat) ]]; then213 local metrics214 metrics=$($cmd list --raw-dump metric metricgroup)215 __perfcomp "$metrics" "$cur"216 else217 # List subcommands for perf commands218 if [[ $prev_skip_opts == @(kvm|kmem|mem|lock|sched|219 |data|help|script|test|timechart|trace) ]]; then220 subcmds=$($cmd $prev_skip_opts --list-cmds)221 __perfcomp_colon "$subcmds" "$cur"222 fi223 # List long option names224 if [[ $cur == --* ]]; then225 subcmd=$prev_skip_opts226 __perf_prev_skip_opts $subcmd227 subcmd=$subcmd" "$prev_skip_opts228 opts=$($cmd $subcmd --list-opts)229 __perfcomp "$opts" "$cur"230 fi231 fi232}233 234if [[ -n ${ZSH_VERSION-} ]]; then235 autoload -U +X compinit && compinit236 237 __perfcomp ()238 {239 emulate -L zsh240 241 local c IFS=$' \t\n'242 local -a array243 244 for c in ${=1}; do245 case $c in246 --*=*|*.) ;;247 *) c="$c " ;;248 esac249 array[${#array[@]}+1]="$c"250 done251 252 compset -P '*[=:]'253 compadd -Q -S '' -a -- array && _ret=0254 }255 256 __perfcomp_colon ()257 {258 emulate -L zsh259 260 local cur_="${2-$cur}"261 local c IFS=$' \t\n'262 local -a array263 264 if [[ "$cur_" == *:* ]]; then265 local colon_word=${cur_%"${cur_##*:}"}266 fi267 268 for c in ${=1}; do269 case $c in270 --*=*|*.) ;;271 *) c="$c " ;;272 esac273 array[$#array+1]=${c#"$colon_word"}274 done275 276 compset -P '*[=:]'277 compadd -Q -S '' -a -- array && _ret=0278 }279 280 _perf ()281 {282 local _ret=1 cur cword prev283 cur=${words[CURRENT]}284 prev=${words[CURRENT-1]}285 let cword=CURRENT-1286 emulate ksh -c __perf_main287 let _ret && _default && _ret=0288 # _ret is only assigned 0 or 1, disable inaccurate analysis.289 # shellcheck disable=SC2152290 return _ret291 }292 293 compdef _perf perf294 return295fi296 297type perf &>/dev/null &&298_perf()299{300 if [[ "$COMP_WORDBREAKS" != *,* ]]; then301 COMP_WORDBREAKS="${COMP_WORDBREAKS},"302 export COMP_WORDBREAKS303 fi304 305 if [[ "$COMP_WORDBREAKS" == *:* ]]; then306 COMP_WORDBREAKS="${COMP_WORDBREAKS/:/}"307 export COMP_WORDBREAKS308 fi309 310 local cur words cword prev311 if [ $preload_get_comp_words_by_ref = "true" ]; then312 _get_comp_words_by_ref -n =:, cur words cword prev313 else314 __perf_get_comp_words_by_ref -n =:, cur words cword prev315 fi316 __perf_main317} &&318 319complete -o bashdefault -o default -o nospace -F _perf perf 2>/dev/null \320 || complete -o default -o nospace -F _perf perf321