xref: /openbmc/linux/tools/perf/perf-completion.sh (revision 9a87ffc99ec8eb8d35eed7c4f816d75f5cc9662e)
1a8b4c701SRamkumar Ramachandra# perf bash and zsh completion
2b2441318SGreg Kroah-Hartman# SPDX-License-Identifier: GPL-2.0
3a8b4c701SRamkumar Ramachandra
4a8b4c701SRamkumar Ramachandra# Taken from git.git's completion script.
5a8b4c701SRamkumar Ramachandra__my_reassemble_comp_words_by_ref()
6a8b4c701SRamkumar Ramachandra{
7a8b4c701SRamkumar Ramachandra	local exclude i j first
8a8b4c701SRamkumar Ramachandra	# Which word separators to exclude?
9a8b4c701SRamkumar Ramachandra	exclude="${1//[^$COMP_WORDBREAKS]}"
10a8b4c701SRamkumar Ramachandra	cword_=$COMP_CWORD
11a8b4c701SRamkumar Ramachandra	if [ -z "$exclude" ]; then
12a8b4c701SRamkumar Ramachandra		words_=("${COMP_WORDS[@]}")
13a8b4c701SRamkumar Ramachandra		return
14a8b4c701SRamkumar Ramachandra	fi
15a8b4c701SRamkumar Ramachandra	# List of word completion separators has shrunk;
16a8b4c701SRamkumar Ramachandra	# re-assemble words to complete.
17a8b4c701SRamkumar Ramachandra	for ((i=0, j=0; i < ${#COMP_WORDS[@]}; i++, j++)); do
18a8b4c701SRamkumar Ramachandra		# Append each nonempty word consisting of just
19a8b4c701SRamkumar Ramachandra		# word separator characters to the current word.
20a8b4c701SRamkumar Ramachandra		first=t
21a8b4c701SRamkumar Ramachandra		while
22a8b4c701SRamkumar Ramachandra			[ $i -gt 0 ] &&
23a8b4c701SRamkumar Ramachandra			[ -n "${COMP_WORDS[$i]}" ] &&
24a8b4c701SRamkumar Ramachandra			# word consists of excluded word separators
25a8b4c701SRamkumar Ramachandra			[ "${COMP_WORDS[$i]//[^$exclude]}" = "${COMP_WORDS[$i]}" ]
26a8b4c701SRamkumar Ramachandra		do
27a8b4c701SRamkumar Ramachandra			# Attach to the previous token,
28a8b4c701SRamkumar Ramachandra			# unless the previous token is the command name.
29a8b4c701SRamkumar Ramachandra			if [ $j -ge 2 ] && [ -n "$first" ]; then
30a8b4c701SRamkumar Ramachandra				((j--))
31a8b4c701SRamkumar Ramachandra			fi
32a8b4c701SRamkumar Ramachandra			first=
33a8b4c701SRamkumar Ramachandra			words_[$j]=${words_[j]}${COMP_WORDS[i]}
34a8b4c701SRamkumar Ramachandra			if [ $i = $COMP_CWORD ]; then
35a8b4c701SRamkumar Ramachandra				cword_=$j
36a8b4c701SRamkumar Ramachandra			fi
37a8b4c701SRamkumar Ramachandra			if (($i < ${#COMP_WORDS[@]} - 1)); then
38a8b4c701SRamkumar Ramachandra				((i++))
39a8b4c701SRamkumar Ramachandra			else
40a8b4c701SRamkumar Ramachandra				# Done.
41a8b4c701SRamkumar Ramachandra				return
42a8b4c701SRamkumar Ramachandra			fi
43a8b4c701SRamkumar Ramachandra		done
44a8b4c701SRamkumar Ramachandra		words_[$j]=${words_[j]}${COMP_WORDS[i]}
45a8b4c701SRamkumar Ramachandra		if [ $i = $COMP_CWORD ]; then
46a8b4c701SRamkumar Ramachandra			cword_=$j
47a8b4c701SRamkumar Ramachandra		fi
48a8b4c701SRamkumar Ramachandra	done
49a8b4c701SRamkumar Ramachandra}
50a8b4c701SRamkumar Ramachandra
511312c8a8SYunlong Song# Define preload_get_comp_words_by_ref="false", if the function
521312c8a8SYunlong Song# __perf_get_comp_words_by_ref() is required instead.
531312c8a8SYunlong Songpreload_get_comp_words_by_ref="true"
541312c8a8SYunlong Song
551312c8a8SYunlong Songif [ $preload_get_comp_words_by_ref = "true" ]; then
56a8b4c701SRamkumar Ramachandra	type _get_comp_words_by_ref &>/dev/null ||
571312c8a8SYunlong Song	preload_get_comp_words_by_ref="false"
581312c8a8SYunlong Songfi
591312c8a8SYunlong Song[ $preload_get_comp_words_by_ref = "true" ] ||
601312c8a8SYunlong Song__perf_get_comp_words_by_ref()
61a8b4c701SRamkumar Ramachandra{
62a8b4c701SRamkumar Ramachandra	local exclude cur_ words_ cword_
63a8b4c701SRamkumar Ramachandra	if [ "$1" = "-n" ]; then
64a8b4c701SRamkumar Ramachandra		exclude=$2
65a8b4c701SRamkumar Ramachandra		shift 2
66a8b4c701SRamkumar Ramachandra	fi
67a8b4c701SRamkumar Ramachandra	__my_reassemble_comp_words_by_ref "$exclude"
68a8b4c701SRamkumar Ramachandra	cur_=${words_[cword_]}
69a8b4c701SRamkumar Ramachandra	while [ $# -gt 0 ]; do
70a8b4c701SRamkumar Ramachandra		case "$1" in
71a8b4c701SRamkumar Ramachandra		cur)
72a8b4c701SRamkumar Ramachandra			cur=$cur_
73a8b4c701SRamkumar Ramachandra			;;
74a8b4c701SRamkumar Ramachandra		prev)
75a8b4c701SRamkumar Ramachandra			prev=${words_[$cword_-1]}
76a8b4c701SRamkumar Ramachandra			;;
77a8b4c701SRamkumar Ramachandra		words)
78a8b4c701SRamkumar Ramachandra			words=("${words_[@]}")
79a8b4c701SRamkumar Ramachandra			;;
80a8b4c701SRamkumar Ramachandra		cword)
81a8b4c701SRamkumar Ramachandra			cword=$cword_
82a8b4c701SRamkumar Ramachandra			;;
83a8b4c701SRamkumar Ramachandra		esac
84a8b4c701SRamkumar Ramachandra		shift
85a8b4c701SRamkumar Ramachandra	done
86a8b4c701SRamkumar Ramachandra}
87a8b4c701SRamkumar Ramachandra
881312c8a8SYunlong Song# Define preload__ltrim_colon_completions="false", if the function
891312c8a8SYunlong Song# __perf__ltrim_colon_completions() is required instead.
901312c8a8SYunlong Songpreload__ltrim_colon_completions="true"
911312c8a8SYunlong Song
921312c8a8SYunlong Songif [ $preload__ltrim_colon_completions = "true" ]; then
93a8b4c701SRamkumar Ramachandra	type __ltrim_colon_completions &>/dev/null ||
941312c8a8SYunlong Song	preload__ltrim_colon_completions="false"
951312c8a8SYunlong Songfi
961312c8a8SYunlong Song[ $preload__ltrim_colon_completions = "true" ] ||
971312c8a8SYunlong Song__perf__ltrim_colon_completions()
98a8b4c701SRamkumar Ramachandra{
99a8b4c701SRamkumar Ramachandra	if [[ "$1" == *:* && "$COMP_WORDBREAKS" == *:* ]]; then
100a8b4c701SRamkumar Ramachandra		# Remove colon-word prefix from COMPREPLY items
101a8b4c701SRamkumar Ramachandra		local colon_word=${1%"${1##*:}"}
102a8b4c701SRamkumar Ramachandra		local i=${#COMPREPLY[*]}
103a8b4c701SRamkumar Ramachandra		while [[ $((--i)) -ge 0 ]]; do
104a8b4c701SRamkumar Ramachandra			COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"}
105a8b4c701SRamkumar Ramachandra		done
106a8b4c701SRamkumar Ramachandra	fi
107a8b4c701SRamkumar Ramachandra}
108a8b4c701SRamkumar Ramachandra
109a8b4c701SRamkumar Ramachandra__perfcomp ()
110a8b4c701SRamkumar Ramachandra{
111a8b4c701SRamkumar Ramachandra	COMPREPLY=( $( compgen -W "$1" -- "$2" ) )
112a8b4c701SRamkumar Ramachandra}
113a8b4c701SRamkumar Ramachandra
114a8b4c701SRamkumar Ramachandra__perfcomp_colon ()
115a8b4c701SRamkumar Ramachandra{
116a8b4c701SRamkumar Ramachandra	__perfcomp "$1" "$2"
1171312c8a8SYunlong Song	if [ $preload__ltrim_colon_completions = "true" ]; then
118a8b4c701SRamkumar Ramachandra		__ltrim_colon_completions $cur
1191312c8a8SYunlong Song	else
1201312c8a8SYunlong Song		__perf__ltrim_colon_completions $cur
1211312c8a8SYunlong Song	fi
122a8b4c701SRamkumar Ramachandra}
123a8b4c701SRamkumar Ramachandra
12467afff48SYunlong Song__perf_prev_skip_opts ()
12567afff48SYunlong Song{
12667afff48SYunlong Song	local i cmd_ cmds_
12767afff48SYunlong Song
12867afff48SYunlong Song	let i=cword-1
129eee200a6SYunlong Song	cmds_=$($cmd $1 --list-cmds)
13067afff48SYunlong Song	prev_skip_opts=()
13167afff48SYunlong Song	while [ $i -ge 0 ]; do
132eee200a6SYunlong Song		if [[ ${words[i]} == $1 ]]; then
133eee200a6SYunlong Song			return
134eee200a6SYunlong Song		fi
13567afff48SYunlong Song		for cmd_ in $cmds_; do
13667afff48SYunlong Song			if [[ ${words[i]} == $cmd_ ]]; then
13767afff48SYunlong Song				prev_skip_opts=${words[i]}
13867afff48SYunlong Song				return
13967afff48SYunlong Song			fi
14067afff48SYunlong Song		done
14167afff48SYunlong Song		((i--))
14267afff48SYunlong Song	done
14367afff48SYunlong Song}
1446fdd9cb7SYunlong Song
145a8b4c701SRamkumar Ramachandra__perf_main ()
146a8b4c701SRamkumar Ramachandra{
147a8b4c701SRamkumar Ramachandra	local cmd
148a8b4c701SRamkumar Ramachandra
149a8b4c701SRamkumar Ramachandra	cmd=${words[0]}
150a8b4c701SRamkumar Ramachandra	COMPREPLY=()
151a8b4c701SRamkumar Ramachandra
15267afff48SYunlong Song	# Skip options backward and find the last perf command
15367afff48SYunlong Song	__perf_prev_skip_opts
154a8b4c701SRamkumar Ramachandra	# List perf subcommands or long options
155e003ce54SYunlong Song	if [ -z $prev_skip_opts ]; then
156a8b4c701SRamkumar Ramachandra		if [[ $cur == --* ]]; then
1577335399aSYunlong Song			cmds=$($cmd --list-opts)
158a8b4c701SRamkumar Ramachandra		else
159a8b4c701SRamkumar Ramachandra			cmds=$($cmd --list-cmds)
160a8b4c701SRamkumar Ramachandra		fi
1617335399aSYunlong Song		__perfcomp "$cmds" "$cur"
1626fdd9cb7SYunlong Song	# List possible events for -e option
1636fdd9cb7SYunlong Song	elif [[ $prev == @("-e"|"--event") &&
1646fdd9cb7SYunlong Song		$prev_skip_opts == @(record|stat|top) ]]; then
16574cd5815SJin Yao
16674cd5815SJin Yao		local cur1=${COMP_WORDS[COMP_CWORD]}
16774cd5815SJin Yao		local raw_evts=$($cmd list --raw-dump)
168*ffd1240eSYicong Yang		local arr s tmp result cpu_evts
169*ffd1240eSYicong Yang
170*ffd1240eSYicong Yang		# aarch64 doesn't have /sys/bus/event_source/devices/cpu/events
171*ffd1240eSYicong Yang		if [[ `uname -m` != aarch64 ]]; then
172*ffd1240eSYicong Yang			cpu_evts=$(ls /sys/bus/event_source/devices/cpu/events)
173*ffd1240eSYicong Yang		fi
17474cd5815SJin Yao
17574cd5815SJin Yao		if [[ "$cur1" == */* && ${cur1#*/} =~ ^[A-Z] ]]; then
17674cd5815SJin Yao			OLD_IFS="$IFS"
17774cd5815SJin Yao			IFS=" "
17874cd5815SJin Yao			arr=($raw_evts)
17974cd5815SJin Yao			IFS="$OLD_IFS"
18074cd5815SJin Yao
18174cd5815SJin Yao			for s in ${arr[@]}
18274cd5815SJin Yao			do
18374cd5815SJin Yao				if [[ "$s" == *cpu/* ]]; then
18474cd5815SJin Yao					tmp=${s#*cpu/}
18574cd5815SJin Yao					result=$result" ""cpu/"${tmp^^}
18674cd5815SJin Yao				else
18774cd5815SJin Yao					result=$result" "$s
18874cd5815SJin Yao				fi
18974cd5815SJin Yao			done
19074cd5815SJin Yao
191*ffd1240eSYicong Yang			evts=${result}" "${cpu_evts}
19274cd5815SJin Yao		else
193*ffd1240eSYicong Yang			evts=${raw_evts}" "${cpu_evts}
19474cd5815SJin Yao		fi
19574cd5815SJin Yao
19634c16db0SJin Yao		if [[ "$cur1" == , ]]; then
19734c16db0SJin Yao			__perfcomp_colon "$evts" ""
19834c16db0SJin Yao		else
19974cd5815SJin Yao			__perfcomp_colon "$evts" "$cur1"
20034c16db0SJin Yao		fi
20102fde323SYunlong Song	else
2023bca2354SRamkumar Ramachandra		# List subcommands for perf commands
2036fdd9cb7SYunlong Song		if [[ $prev_skip_opts == @(kvm|kmem|mem|lock|sched|
2046fdd9cb7SYunlong Song			|data|help|script|test|timechart|trace) ]]; then
20567afff48SYunlong Song			subcmds=$($cmd $prev_skip_opts --list-cmds)
2068f2f5adaSRamkumar Ramachandra			__perfcomp_colon "$subcmds" "$cur"
20702fde323SYunlong Song		fi
208a8b4c701SRamkumar Ramachandra		# List long option names
20902fde323SYunlong Song		if [[ $cur == --* ]];  then
210eee200a6SYunlong Song			subcmd=$prev_skip_opts
211eee200a6SYunlong Song			__perf_prev_skip_opts $subcmd
212eee200a6SYunlong Song			subcmd=$subcmd" "$prev_skip_opts
213a8b4c701SRamkumar Ramachandra			opts=$($cmd $subcmd --list-opts)
214a8b4c701SRamkumar Ramachandra			__perfcomp "$opts" "$cur"
215a8b4c701SRamkumar Ramachandra		fi
21602fde323SYunlong Song	fi
217a8b4c701SRamkumar Ramachandra}
218a8b4c701SRamkumar Ramachandra
219a8b4c701SRamkumar Ramachandraif [[ -n ${ZSH_VERSION-} ]]; then
220a8b4c701SRamkumar Ramachandra	autoload -U +X compinit && compinit
221a8b4c701SRamkumar Ramachandra
222a8b4c701SRamkumar Ramachandra	__perfcomp ()
223a8b4c701SRamkumar Ramachandra	{
224a8b4c701SRamkumar Ramachandra		emulate -L zsh
225a8b4c701SRamkumar Ramachandra
226a8b4c701SRamkumar Ramachandra		local c IFS=$' \t\n'
227a8b4c701SRamkumar Ramachandra		local -a array
228a8b4c701SRamkumar Ramachandra
229a8b4c701SRamkumar Ramachandra		for c in ${=1}; do
230a8b4c701SRamkumar Ramachandra			case $c in
231a8b4c701SRamkumar Ramachandra			--*=*|*.) ;;
232a8b4c701SRamkumar Ramachandra			*) c="$c " ;;
233a8b4c701SRamkumar Ramachandra			esac
234a8b4c701SRamkumar Ramachandra			array[${#array[@]}+1]="$c"
235a8b4c701SRamkumar Ramachandra		done
236a8b4c701SRamkumar Ramachandra
237a8b4c701SRamkumar Ramachandra		compset -P '*[=:]'
238a8b4c701SRamkumar Ramachandra		compadd -Q -S '' -a -- array && _ret=0
239a8b4c701SRamkumar Ramachandra	}
240a8b4c701SRamkumar Ramachandra
241a8b4c701SRamkumar Ramachandra	__perfcomp_colon ()
242a8b4c701SRamkumar Ramachandra	{
243a8b4c701SRamkumar Ramachandra		emulate -L zsh
244a8b4c701SRamkumar Ramachandra
245a8b4c701SRamkumar Ramachandra		local cur_="${2-$cur}"
246a8b4c701SRamkumar Ramachandra		local c IFS=$' \t\n'
247a8b4c701SRamkumar Ramachandra		local -a array
248a8b4c701SRamkumar Ramachandra
249a8b4c701SRamkumar Ramachandra		if [[ "$cur_" == *:* ]]; then
250a8b4c701SRamkumar Ramachandra			local colon_word=${cur_%"${cur_##*:}"}
251a8b4c701SRamkumar Ramachandra		fi
252a8b4c701SRamkumar Ramachandra
253a8b4c701SRamkumar Ramachandra		for c in ${=1}; do
254a8b4c701SRamkumar Ramachandra			case $c in
255a8b4c701SRamkumar Ramachandra			--*=*|*.) ;;
256a8b4c701SRamkumar Ramachandra			*) c="$c " ;;
257a8b4c701SRamkumar Ramachandra			esac
258a8b4c701SRamkumar Ramachandra			array[$#array+1]=${c#"$colon_word"}
259a8b4c701SRamkumar Ramachandra		done
260a8b4c701SRamkumar Ramachandra
261a8b4c701SRamkumar Ramachandra		compset -P '*[=:]'
262a8b4c701SRamkumar Ramachandra		compadd -Q -S '' -a -- array && _ret=0
263a8b4c701SRamkumar Ramachandra	}
264a8b4c701SRamkumar Ramachandra
265a8b4c701SRamkumar Ramachandra	_perf ()
266a8b4c701SRamkumar Ramachandra	{
267a8b4c701SRamkumar Ramachandra		local _ret=1 cur cword prev
268a8b4c701SRamkumar Ramachandra		cur=${words[CURRENT]}
269a8b4c701SRamkumar Ramachandra		prev=${words[CURRENT-1]}
270a8b4c701SRamkumar Ramachandra		let cword=CURRENT-1
271a8b4c701SRamkumar Ramachandra		emulate ksh -c __perf_main
272a8b4c701SRamkumar Ramachandra		let _ret && _default && _ret=0
273a8b4c701SRamkumar Ramachandra		return _ret
274a8b4c701SRamkumar Ramachandra	}
275a8b4c701SRamkumar Ramachandra
276a8b4c701SRamkumar Ramachandra	compdef _perf perf
277a8b4c701SRamkumar Ramachandra	return
278a8b4c701SRamkumar Ramachandrafi
279a8b4c701SRamkumar Ramachandra
280a8b4c701SRamkumar Ramachandratype perf &>/dev/null &&
281a8b4c701SRamkumar Ramachandra_perf()
282a8b4c701SRamkumar Ramachandra{
28374cd5815SJin Yao	if [[ "$COMP_WORDBREAKS" != *,* ]]; then
28474cd5815SJin Yao		COMP_WORDBREAKS="${COMP_WORDBREAKS},"
28574cd5815SJin Yao		export COMP_WORDBREAKS
28674cd5815SJin Yao	fi
28774cd5815SJin Yao
2885d4fd9c8SJin Yao	if [[ "$COMP_WORDBREAKS" == *:* ]]; then
2895d4fd9c8SJin Yao		COMP_WORDBREAKS="${COMP_WORDBREAKS/:/}"
2905d4fd9c8SJin Yao		export COMP_WORDBREAKS
2915d4fd9c8SJin Yao	fi
2925d4fd9c8SJin Yao
293a8b4c701SRamkumar Ramachandra	local cur words cword prev
2941312c8a8SYunlong Song	if [ $preload_get_comp_words_by_ref = "true" ]; then
29574cd5815SJin Yao		_get_comp_words_by_ref -n =:, cur words cword prev
2961312c8a8SYunlong Song	else
29774cd5815SJin Yao		__perf_get_comp_words_by_ref -n =:, cur words cword prev
2981312c8a8SYunlong Song	fi
299a8b4c701SRamkumar Ramachandra	__perf_main
300a8b4c701SRamkumar Ramachandra} &&
301a8b4c701SRamkumar Ramachandra
302a8b4c701SRamkumar Ramachandracomplete -o bashdefault -o default -o nospace -F _perf perf 2>/dev/null \
303a8b4c701SRamkumar Ramachandra	|| complete -o default -o nospace -F _perf perf
304