Skip to content
This repository was archived by the owner on Aug 27, 2025. It is now read-only.

Commit e9eee76

Browse files
committed
Add bash programmable completion for vcgencmd
The completion file should be renamed "vcgencmd" and installed in /usr/share/bash-completion/completions/.
1 parent 97bc818 commit e9eee76

File tree

2 files changed

+323
-0
lines changed

2 files changed

+323
-0
lines changed
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
#!/usr/bin/env bats
2+
# Integration tests for vcgencmd command completion.
3+
# Runs on Raspberry Pi, requires bats-core package.
4+
5+
load /usr/share/bash-completion/bash_completion || true
6+
load /usr/share/bash-completion/completions/vcgencmd
7+
8+
9+
complete_command() {
10+
local cmd="$*"
11+
12+
COMP_LINE="${cmd}"
13+
mapfile -t COMP_WORDS < <( compgen -W "${cmd}" )
14+
15+
# index of current word in $COMP_WORDS array
16+
COMP_CWORD=$(( ${#COMP_WORDS[@]} - 1 ))
17+
if [[ ${cmd: -1} == " " ]]; then
18+
COMP_CWORD=$(( COMP_CWORD + 1 ))
19+
fi
20+
21+
# current pointer position in line
22+
COMP_POINT="${#cmd}"
23+
24+
# name of completion function
25+
complete_func=$(complete -p "${COMP_WORDS[0]}" | sed 's/.*-F \([^ ]*\) .*/\1/')
26+
[[ -n $complete_func ]]
27+
28+
# Run completion function. Sets the COMPREPLY array.
29+
$complete_func "${COMP_WORDS[0]}" || true
30+
31+
if [[ $DEBUG_VCGENCMD_TEST ]]; then
32+
echo >&3
33+
echo "COMP_LINE='${COMP_LINE}'" >&3
34+
echo "COMP_WORDS='${COMP_WORDS[*]}'" >&3
35+
echo "length COMP_WORDS = ${#COMP_WORDS[@]}" >&3
36+
echo "COMP_CWORD=${COMP_CWORD}" >&3
37+
echo "COMP_POINT=${COMP_POINT}" >&3
38+
echo "COMPREPLY=${COMPREPLY[*]}" >&3
39+
echo "length COMPREPLY=${#COMPREPLY[@]}" >&3
40+
fi
41+
}
42+
43+
is_pi4() {
44+
grep -qE '^Model.* Raspberry Pi 4' /proc/cpuinfo
45+
}
46+
47+
@test "vcgencmd - -> -t -h --help" {
48+
complete_command "vcgencmd -"
49+
[[ "${COMPREPLY[*]}" == "-t -h --help" ]]
50+
}
51+
52+
@test "--h -> --help" {
53+
complete_command "vcgencmd --h"
54+
[[ "${COMPREPLY[*]}" == "--help" ]]
55+
}
56+
57+
@test "--help -> (nothing)" {
58+
complete_command "vcgencmd --help "
59+
[[ "${#COMPREPLY[@]}" -eq 0 ]]
60+
}
61+
62+
@test "vcgencmd -xxx -> (nothing)" {
63+
complete_command "vcgencmd -xxx "
64+
[[ "${#COMPREPLY[@]}" -eq 0 ]]
65+
}
66+
67+
@test "vcgencmd foobar -> (nothing)" {
68+
complete_command "vcgencmd foobar "
69+
[[ "${#COMPREPLY[@]}" -eq 0 ]]
70+
}
71+
72+
@test "vcgencmd -> commands version get_config measure_temp ..." {
73+
complete_command "vcgencmd "
74+
[[ "${#COMPREPLY[@]}" -gt 60 ]]
75+
echo "${COMPREPLY[*]}" | grep -Ewo "(commands|version|get_config|measure_temp)"
76+
}
77+
78+
@test "vcgencmd -t -> commands version get_config measure_temp ..." {
79+
complete_command "vcgencmd -t "
80+
[[ "${#COMPREPLY[@]}" -gt 60 ]]
81+
echo "${COMPREPLY[*]}" | grep -Ewo "(commands|version|get_config|measure_temp)"
82+
}
83+
84+
@test "codec_enabled -> FLAC MJPG ..." {
85+
complete_command "vcgencmd codec_enabled "
86+
echo "${COMPREPLY[*]}" | grep -Ewo "(FLAC|MJPG|H263|PCM|VORB)"
87+
}
88+
89+
@test "measure_clock -> arm core uart ..." {
90+
complete_command "vcgencmd measure_clock "
91+
echo "${COMPREPLY[*]}" | grep -Ewo "(arm|core|uart|hdmi)"
92+
}
93+
94+
@test "measure_volts -> core sdram_[cip]" {
95+
complete_command "vcgencmd measure_clock "
96+
echo "${COMPREPLY[*]}" | grep -Ewo "(core|sdram_[cip])"
97+
}
98+
99+
@test "get_mem -> arm gpu" {
100+
complete_command "vcgencmd get_mem "
101+
echo "${COMPREPLY[*]}" | grep -Ewo "(arm|gpu)"
102+
}
103+
104+
@test "get_config -> int str arm_freq ..." {
105+
complete_command "vcgencmd get_config "
106+
[[ "${#COMPREPLY[@]}" -gt 30 ]]
107+
echo "${COMPREPLY[*]}" | grep -Ewo "(int|str|device_tree|arm_freq|total_mem|hdmi_cvt:0|enable_tvout)"
108+
}
109+
110+
@test "get_config hdmi_cvt: -> 0 1" {
111+
complete_command "vcgencmd get_config hdmi_cvt:"
112+
[[ "${COMPREPLY[*]}" == "0 1" ]]
113+
}
114+
115+
# Pi 4B has two hdmi pixel freq limits 0 and 1, Pi 2 and 3 just have one
116+
@test "get_config hdmi_pixel_freq_li -> hdmi_pixel_freq_limit:0" {
117+
if is_pi4; then
118+
skip "test only valid with 1 hdmi (earlier pi models)"
119+
fi
120+
complete_command "vcgencmd get_config hdmi_pixel_freq_li"
121+
[[ "${COMPREPLY[*]}" == "hdmi_pixel_freq_limit:0" ]]
122+
}
123+
124+
@test "get_config hdmi_pixel_freq_li -> hdmi_pixel_freq_limit:" {
125+
if ! is_pi4; then
126+
skip "test requires Pi 4 with 2 hdmi outputs"
127+
fi
128+
complete_command "vcgencmd get_config hdmi_pixel_freq_li"
129+
[[ "${COMPREPLY[*]}" == "hdmi_pixel_freq_limit:0 hdmi_pixel_freq_limit:1" ]]
130+
}
131+
132+
@test "get_config hdmi_pixel_freq_limit: -> 0 1" {
133+
if ! is_pi4; then
134+
skip "test requires Pi 4 with 2 hdmi outputs"
135+
fi
136+
complete_command "vcgencmd get_config hdmi_pixel_freq_limit:"
137+
[[ "${COMPREPLY[*]}" == "0 1" ]]
138+
}
139+
140+
@test "vcos -> version log" {
141+
complete_command "vcgencmd vcos "
142+
echo "${COMPREPLY[*]}" | grep -Ewo "(version|log)"
143+
}
144+
145+
@test "display_power -> 0 1 -1" {
146+
complete_command "vcgencmd display_power "
147+
[[ "${COMPREPLY[*]}" == "0 1 -1" ]]
148+
}
149+
150+
@test "-t display_power -> 0 1 -1" {
151+
complete_command "vcgencmd -t display_power "
152+
[[ "${COMPREPLY[*]}" == "0 1 -1" ]]
153+
}
154+
155+
@test "display_power [0, 1] -> 0 1 2 3 7" {
156+
local display_nums="0 1 2 3 7"
157+
complete_command "vcgencmd display_power 0 "
158+
[[ "${COMPREPLY[*]}" == "$display_nums" ]]
159+
complete_command "vcgencmd display_power 1 "
160+
[[ "${COMPREPLY[*]}" == "$display_nums" ]]
161+
}
162+
163+
@test "display_power -1 -> 0 1 2 3 7" {
164+
local display_nums="0 1 2 3 7"
165+
complete_command "vcgencmd display_power -1 "
166+
[[ "${COMPREPLY[*]}" == "$display_nums" ]]
167+
}
168+
169+
@test "BADARG display_power -1 -> (nothing)" {
170+
complete_command "vcgencmd BADARG display_power -1 "
171+
echo "${COMPREPLY[*]}"
172+
[[ "${COMPREPLY[*]}" == "" ]]
173+
}
174+
175+
@test "display_power BADARG -1 -> (nothing)" {
176+
complete_command "vcgencmd display_power BADARG -1 "
177+
echo "${COMPREPLY[*]}"
178+
[[ "${COMPREPLY[*]}" == "" ]]
179+
}
180+
181+
@test "-t display_power -1 -> 0 1 2 3 7" {
182+
complete_command "vcgencmd -t display_power -1 "
183+
[[ "${COMPREPLY[*]}" == "0 1 2 3 7" ]]
184+
}
185+
186+
@test "vcos log -> status" {
187+
complete_command "vcgencmd vcos log "
188+
[[ "${COMPREPLY[*]}" == "status" ]]
189+
}
190+
191+
@test "-t vcos log -> status" {
192+
complete_command "vcgencmd -t vcos log "
193+
[[ "${COMPREPLY[*]}" == "status" ]]
194+
}
195+
196+
@test "vcos 0 -> (nothing)" {
197+
complete_command "vcgencmd vcos 0 "
198+
[[ "${#COMPREPLY[@]}" -eq 0 ]]
199+
}
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# vcgencmd(1) completion -*- shell-script -*-
2+
3+
_vcgencmd_commands()
4+
{
5+
local commands fallback re
6+
commands="$(/usr/bin/vcgencmd commands 2> /dev/null)"
7+
fallback="codec_enabled commands display_power get_camera get_config
8+
get_lcd_info get_mem get_throttled measure_temp measure_volts
9+
mem_oom version"
10+
re='commands="(.*)"'
11+
12+
if [[ $commands =~ $re ]]; then
13+
commands="${BASH_REMATCH[1]}"
14+
commands="${commands//,}"
15+
else
16+
commands="${fallback}"
17+
fi
18+
19+
compgen -W "$commands" -- "$cur"
20+
}
21+
22+
# This function counts the number of args, excluding options,
23+
# providing exceptions for option-like arguments.
24+
# @param $1 chars Characters out of $COMP_WORDBREAKS which should
25+
# NOT be considered word breaks. See __reassemble_comp_words_by_ref.
26+
# @param $2 non_opt_args arguments that look like options, but aren't
27+
_vcgencmd_count_args()
28+
{
29+
local i cword words non_opt_args
30+
__reassemble_comp_words_by_ref "$1" words cword
31+
32+
args=1
33+
non_opt_args="$2"
34+
35+
for i in "${words[@]:1:cword-1}"; do
36+
if [[ "$i" != -* ]]; then
37+
args=$((args+1))
38+
else
39+
for a in $non_opt_args; do
40+
[[ "$i" == "$a" ]] && args=$((args+1))
41+
done
42+
fi
43+
done
44+
}
45+
46+
_vcgencmd() {
47+
local cur prev cword words opts='' args
48+
_init_completion -n ':' || return
49+
_vcgencmd_count_args ':' '-1'
50+
51+
if [[ $cword -eq 1 && $cur == -* ]] ; then
52+
mapfile -t COMPREPLY < <( compgen -W '-t -h --help' -- "$cur" )
53+
return 0
54+
fi
55+
56+
if [[ $args -eq 1 ]]; then
57+
case "$prev" in
58+
-h|--help)
59+
;;
60+
-t|vcgencmd)
61+
mapfile -t COMPREPLY < <( _vcgencmd_commands )
62+
;;
63+
-*)
64+
;;
65+
esac
66+
return 0
67+
fi
68+
69+
if [[ $args -eq 2 ]]; then
70+
case "$prev" in
71+
codec_enabled)
72+
opts='AGIF FLAC H263 H264 MJPA MJPB MJPG MPG2 MPG4 MVC0 PCM
73+
THRA VORB VP6 VP8 WMV9 WVC1'
74+
;;
75+
measure_clock)
76+
opts='arm core h264 isp v3d uart pwm emmc pixel vec hdmi dpi'
77+
;;
78+
measure_volts)
79+
opts='core sdram_c sdram_i sdram_p'
80+
;;
81+
get_mem)
82+
opts='arm gpu'
83+
;;
84+
get_config)
85+
opts='int str'
86+
opts+=" $("$1" get_config str | command sed -e 's/=.*$//')"
87+
opts+=" $("$1" get_config int | command sed -e 's/=.*$//')"
88+
;;
89+
display_power)
90+
opts='0 1 -1'
91+
;;
92+
vcos)
93+
opts='log version'
94+
;;
95+
esac
96+
fi
97+
98+
if [[ $args -eq 3 ]]; then
99+
case "${words[cword - 2]}" in
100+
display_power)
101+
case "$prev" in
102+
0|1|-1)
103+
opts='0 1 2 3 7'
104+
;;
105+
esac
106+
;;
107+
vcos)
108+
case "$prev" in
109+
log)
110+
opts='status'
111+
;;
112+
esac
113+
;;
114+
esac
115+
fi
116+
117+
[[ -n $opts ]] && mapfile -t COMPREPLY < <( compgen -W "$opts" -- "$cur" )
118+
[[ $prev == "get_config" ]] && __ltrim_colon_completions "$cur"
119+
120+
return 0
121+
} &&
122+
complete -F _vcgencmd vcgencmd
123+
124+
# ex: filetype=sh

0 commit comments

Comments
 (0)