mirror of
https://github.com/tmux/tmux.git
synced 2026-07-10 03:19:31 +00:00
315 lines
7.3 KiB
Bash
315 lines
7.3 KiB
Bash
#!/bin/sh
|
|
# Exercise format and style rendering in live contexts.
|
|
|
|
PATH=/bin:/usr/bin
|
|
TERM=screen
|
|
LANG=C.UTF-8
|
|
LC_ALL=C.UTF-8
|
|
export PATH TERM LANG LC_ALL
|
|
|
|
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
|
|
|
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
|
TMUX2="$TEST_TMUX -LtestB$$ -f/dev/null"
|
|
LIMIT=20000
|
|
|
|
cleanup()
|
|
{
|
|
$TMUX kill-server 2>/dev/null
|
|
$TMUX2 kill-server 2>/dev/null
|
|
}
|
|
|
|
fail()
|
|
{
|
|
echo "$1" >&2
|
|
cleanup
|
|
exit 1
|
|
}
|
|
|
|
run_cmd()
|
|
{
|
|
if command -v timeout >/dev/null 2>&1; then
|
|
timeout 10 "$@"
|
|
else
|
|
"$@"
|
|
fi
|
|
}
|
|
|
|
bounded()
|
|
{
|
|
name=$1
|
|
text=$2
|
|
|
|
n=$(printf '%s' "$text" | wc -c)
|
|
[ "$n" -le "$LIMIT" ] || fail "$name too large: $n bytes"
|
|
}
|
|
|
|
tmux_run()
|
|
{
|
|
name=$1
|
|
shift
|
|
|
|
out=$(
|
|
if command -v timeout >/dev/null 2>&1; then
|
|
timeout 10 $TMUX "$@" 2>&1
|
|
else
|
|
$TMUX "$@" 2>&1
|
|
fi
|
|
)
|
|
rc=$?
|
|
bounded "$name" "$out"
|
|
[ "$rc" -eq 0 ] || fail "$name failed: $out"
|
|
printf '%s' "$out"
|
|
}
|
|
|
|
capture()
|
|
{
|
|
out=$(
|
|
if command -v timeout >/dev/null 2>&1; then
|
|
timeout 10 $TMUX2 capture-pane -p -t out:0 2>/dev/null
|
|
else
|
|
$TMUX2 capture-pane -p -t out:0 2>/dev/null
|
|
fi
|
|
)
|
|
rc=$?
|
|
bounded "capture-pane" "$out"
|
|
[ "$rc" -eq 0 ] || fail "capture-pane failed"
|
|
printf '%s\n' "$out"
|
|
}
|
|
|
|
capture_esc()
|
|
{
|
|
out=$(
|
|
if command -v timeout >/dev/null 2>&1; then
|
|
timeout 10 $TMUX2 capture-pane -pe -t out:0 \
|
|
2>/dev/null
|
|
else
|
|
$TMUX2 capture-pane -pe -t out:0 2>/dev/null
|
|
fi
|
|
)
|
|
rc=$?
|
|
bounded "capture-pane -e" "$out"
|
|
[ "$rc" -eq 0 ] || fail "capture-pane -e failed"
|
|
printf '%s\n' "$out"
|
|
}
|
|
|
|
assert_alive()
|
|
{
|
|
tmux_run "server alive ($1)" display-message -p alive >/dev/null
|
|
}
|
|
|
|
wait_for()
|
|
{
|
|
marker=$1
|
|
i=0
|
|
while [ "$i" -lt 50 ]; do
|
|
if capture | grep -F "$marker" >/dev/null 2>&1; then
|
|
sleep 0.1
|
|
return 0
|
|
fi
|
|
sleep 0.2
|
|
i=$((i + 1))
|
|
done
|
|
fail "timed out waiting for $marker"
|
|
}
|
|
|
|
render_status_options()
|
|
{
|
|
label=$1
|
|
fmt=$2
|
|
|
|
tmux_run "$label status-left" \
|
|
set-option -g status-left "SL$label: $fmt" >/dev/null
|
|
tmux_run "$label clear status-right" \
|
|
set-option -g status-right '' >/dev/null
|
|
tmux_run "$label status-format left" \
|
|
set-option -g status-format[0] '#{E:status-left}' >/dev/null
|
|
tmux_run "$label refresh status-left" refresh-client -S >/dev/null
|
|
wait_for "SL$label:"
|
|
|
|
tmux_run "$label clear status-left" \
|
|
set-option -g status-left '' >/dev/null
|
|
tmux_run "$label status-right" \
|
|
set-option -g status-right "SR$label: $fmt" >/dev/null
|
|
tmux_run "$label status-format right" \
|
|
set-option -g status-format[0] \
|
|
'#[align=right]#{E:status-right}' >/dev/null
|
|
tmux_run "$label refresh status-right" refresh-client -S >/dev/null
|
|
wait_for "SR$label:"
|
|
assert_alive "$label status-left/right"
|
|
}
|
|
|
|
render_status_format()
|
|
{
|
|
label=$1
|
|
fmt=$2
|
|
|
|
tmux_run "$label status-format" \
|
|
set-option -g status-format[0] "SF$label: $fmt" >/dev/null
|
|
tmux_run "$label refresh status-format" refresh-client -S >/dev/null
|
|
wait_for "SF$label:"
|
|
assert_alive "$label status-format"
|
|
}
|
|
|
|
render_message()
|
|
{
|
|
label=$1
|
|
fmt=$2
|
|
|
|
tmux_run "$label display-message" \
|
|
display-message -t fmt:0 -d 1000 "DM$label: $fmt" >/dev/null
|
|
wait_for "DM$label:"
|
|
assert_alive "$label display-message"
|
|
}
|
|
|
|
render_choose_tree()
|
|
{
|
|
label=$1
|
|
fmt=$2
|
|
|
|
tmux_run "$label choose-tree" \
|
|
choose-tree -t fmt:0 -F "CT$label: $fmt" >/dev/null
|
|
wait_for "CT$label:"
|
|
tmux_run "$label quit choose-tree" send-keys -t fmt:0 q >/dev/null
|
|
assert_alive "$label choose-tree"
|
|
}
|
|
|
|
render_customize()
|
|
{
|
|
label=$1
|
|
fmt=$2
|
|
|
|
tmux_run "$label customize-mode" \
|
|
customize-mode -t fmt:0 -F "CM$label: $fmt" >/dev/null
|
|
sleep 0.5
|
|
out=$(capture)
|
|
bounded "$label customize-mode capture" "$out"
|
|
tmux_run "$label quit customize-mode" send-keys -t fmt:0 q >/dev/null
|
|
assert_alive "$label customize-mode"
|
|
}
|
|
|
|
render_list_output()
|
|
{
|
|
label=$1
|
|
fmt=$2
|
|
|
|
tmux_run "$label bind-key" \
|
|
bind-key -T root F12 display-message "LK$label: $fmt" >/dev/null
|
|
out=$(tmux_run "$label list-keys" list-keys -T root F12)
|
|
bounded "$label list-keys" "$out"
|
|
printf '%s' "$out" | grep -F "LK$label:" >/dev/null 2>&1 ||
|
|
fail "$label list-keys missing rendered command"
|
|
|
|
tmux_run "$label set show option" \
|
|
set-option -g "@format_render_$label" "SO$label: $fmt" >/dev/null
|
|
out=$(tmux_run "$label show-options" show-options -g "@format_render_$label")
|
|
bounded "$label show-options" "$out"
|
|
printf '%s' "$out" | grep -F "SO$label:" >/dev/null 2>&1 ||
|
|
fail "$label show-options missing option"
|
|
|
|
assert_alive "$label list output"
|
|
}
|
|
|
|
run_corpus()
|
|
{
|
|
label=$1
|
|
fmt=$2
|
|
|
|
render_status_options "$label" "$fmt"
|
|
render_status_format "$label" "$fmt"
|
|
render_message "$label" "$fmt"
|
|
render_choose_tree "$label" "$fmt"
|
|
render_customize "$label" "$fmt"
|
|
render_list_output "$label" "$fmt"
|
|
}
|
|
|
|
check_sgr_sanity()
|
|
{
|
|
esc=$(printf '\033')
|
|
|
|
tmux_run "set message style fill" \
|
|
set-option -g message-style \
|
|
"fg=#080808,bg=#ffff00,fill=#ffff00,bold" >/dev/null
|
|
tmux_run "show filled message" \
|
|
display-message -t fmt:0 -d 1000 \
|
|
'#[bg=blue,italics] hello, #[fg=#080808,bg=default] world!' \
|
|
>/dev/null
|
|
wait_for "hello, world!"
|
|
|
|
out=$(capture_esc)
|
|
printf '%s' "$out" | grep -F 'world!' >/dev/null 2>&1 ||
|
|
fail "message text missing from SGR capture"
|
|
printf '%s' "$out" | grep "$esc" >/dev/null 2>&1 ||
|
|
fail "SGR capture has no escapes"
|
|
|
|
world_sgr=$(
|
|
printf '%s\n' "$out" |
|
|
awk -v esc="$esc" '
|
|
/world!/ {
|
|
i = index($0, "world!")
|
|
pre = substr($0, 1, i - 1)
|
|
n = split(pre, parts, esc "\\[")
|
|
print parts[n]
|
|
exit
|
|
}'
|
|
)
|
|
|
|
case "$world_sgr" in
|
|
*'48;'*) ;;
|
|
*) fail "world segment missing explicit background SGR: $world_sgr" ;;
|
|
esac
|
|
case "$world_sgr" in
|
|
*'49'*)
|
|
fail "world segment used default background instead of message fill: $world_sgr"
|
|
;;
|
|
esac
|
|
|
|
assert_alive "message SGR sanity"
|
|
}
|
|
|
|
wide_fmt()
|
|
{
|
|
printf 'wide: \0316\0225\0316\0273\0316\0273\0316\0267\0316\0275\0316\0271\0316\0272\0316\0254 \0344\0270\0255\0346\0226\0207 #{=12:\0344\0270\0255\0346\0226\0207abc}'
|
|
}
|
|
|
|
long_style_fmt()
|
|
{
|
|
printf '%s' '#[fg=colour1,bg=colour2,us=colour3,acs,bright,dim,underscore,blink,reverse,hidden,italics,strikethrough,double-underscore,curly-underscore,dotted-underscore,dashed-underscore,overline,range=user|aaaaaaaaaaaaaaaa,align=absolute-centre,list=on,fill=colour200,width=4294967295,pad=4294967295]OVERLONG-STYLE#[default]'
|
|
}
|
|
|
|
trap cleanup 0 1 15
|
|
cleanup
|
|
|
|
tmux_run "new inner session" \
|
|
new-session -d -s fmt -x 100 -y 30 "exec sleep 1000" >/dev/null
|
|
tmux_run "new inner window" \
|
|
new-window -t fmt -n second "exec sleep 1000" >/dev/null
|
|
tmux_run "select first window" select-window -t fmt:0 >/dev/null
|
|
tmux_run "status interval" set-option -g status-interval 1 >/dev/null
|
|
tmux_run "base status" set-option -g status on >/dev/null
|
|
tmux_run "nested option" \
|
|
set-option -g @nested 'NESTED-#{session_name}-#{window_index}' >/dev/null
|
|
|
|
run_cmd $TMUX2 new-session -d -s out -x 100 -y 30 "$TMUX attach -t fmt" \
|
|
>/dev/null 2>&1 || fail "failed to start outer client"
|
|
|
|
i=0
|
|
while [ "$i" -lt 50 ]; do
|
|
c=$(tmux_run "wait clients" list-clients -F x | grep -c x)
|
|
[ "$c" -eq 1 ] && break
|
|
sleep 0.2
|
|
i=$((i + 1))
|
|
done
|
|
[ "$i" -lt 50 ] || fail "inner client did not attach"
|
|
|
|
run_corpus A 'plain #{session_name}:#{window_index} #{@nested}'
|
|
run_corpus B "$(wide_fmt)"
|
|
run_corpus C '#[fg=colour10,bg=colour17,bold,italics]styled #{pane_current_command}#[default]'
|
|
run_corpus D '#[push-default]#[fg=red,bg=blue]push #{?pane_active,active,inactive}#[pop-default] after'
|
|
run_corpus E "$(long_style_fmt)"
|
|
|
|
check_sgr_sanity
|
|
|
|
cleanup
|
|
exit 0
|