mirror of
https://github.com/tmux/tmux.git
synced 2026-10-08 19:14:20 +00:00
144 lines
3.4 KiB
Bash
144 lines
3.4 KiB
Bash
#!/bin/sh
|
|
|
|
# An Escape followed by a focus report must remain a separate key. The
|
|
# report's leading Escape must not be consumed as the second half of M-Escape,
|
|
# and the focus change must still reach the client and the pane.
|
|
|
|
PATH=/bin:/usr/bin
|
|
TERM=screen
|
|
export PATH TERM
|
|
|
|
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
|
INNER="$TEST_TMUX -LtestI$$ -f/dev/null"
|
|
OUTER="$TEST_TMUX -LtestO$$ -f/dev/null"
|
|
|
|
fail()
|
|
{
|
|
echo "$*" >&2
|
|
exit 1
|
|
}
|
|
|
|
cleanup()
|
|
{
|
|
$OUTER kill-server 2>/dev/null
|
|
$INNER kill-server 2>/dev/null
|
|
}
|
|
trap cleanup 0
|
|
trap 'exit 1' 1 2 15
|
|
|
|
$INNER new-session -d -s inner -x80 -y10 \
|
|
"printf '\033[?1004h'; stty raw -echo; exec cat -v" || exit 1
|
|
$INNER set-option -g status off || exit 1
|
|
$INNER set-option -g assume-paste-time 0 || exit 1
|
|
$INNER set-option -g focus-events on || exit 1
|
|
$INNER set-option -s escape-time 1000 || exit 1
|
|
$INNER unbind-key -a -T root || exit 1
|
|
$OUTER new-session -d -s outer -x80 -y10 "$INNER attach -t inner" || exit 1
|
|
$OUTER set-option -g assume-paste-time 0 || exit 1
|
|
|
|
i=0
|
|
while [ -z "$($INNER list-clients -F '#{client_name}')" ]; do
|
|
[ "$i" -lt 100 ] || fail 'inner client did not attach'
|
|
sleep 0.05
|
|
i=$((i + 1))
|
|
done
|
|
|
|
bind_key()
|
|
{
|
|
$INNER bind-key -n "$1" send-keys -l "$2" || exit 1
|
|
}
|
|
bind_key Escape E
|
|
bind_key M-Escape A
|
|
bind_key M-Up U
|
|
|
|
send_raw()
|
|
{
|
|
# Hex arguments avoid command separators in a partial sequence.
|
|
bytes=$(printf '%s' "$1" | od -An -v -tx1)
|
|
$OUTER send-keys -H $bytes || exit 1
|
|
}
|
|
|
|
capture()
|
|
{
|
|
$INNER capture-pane -p | tr -d '\n'
|
|
}
|
|
|
|
focused()
|
|
{
|
|
case $($INNER list-clients -F '#{client_flags}') in
|
|
*focused*)
|
|
echo yes
|
|
;;
|
|
*)
|
|
echo no
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# Start unfocused, whatever the state after attaching, once the pane has
|
|
# enabled focus reporting.
|
|
i=0
|
|
while :; do
|
|
send_raw "$(printf '\033[I\033[O')"
|
|
sleep 0.05
|
|
case $(capture) in
|
|
*'^[[O')
|
|
[ "$(focused)" = no ] && break
|
|
;;
|
|
esac
|
|
[ "$i" -lt 100 ] || fail 'pane did not receive focus reports'
|
|
i=$((i + 1))
|
|
done
|
|
expected_output=$(capture)
|
|
|
|
# A focus report is forwarded to the pane directly, while the Escape binding
|
|
# runs from the command queue, so the pane may see them in either order. The
|
|
# second expected output, if not empty, is that other order.
|
|
assert_events()
|
|
{
|
|
name=$1
|
|
expected=$expected_output$2
|
|
if [ -n "$3" ]; then
|
|
alternative=$expected_output$3
|
|
else
|
|
alternative=$expected
|
|
fi
|
|
expected_focus=$4
|
|
send_raw "$5"
|
|
if [ "$#" -eq 6 ]; then
|
|
sleep 0.05
|
|
send_raw "$6"
|
|
fi
|
|
i=0
|
|
while [ "$i" -lt 100 ]; do
|
|
actual=$(capture)
|
|
actual_focus=$(focused)
|
|
if [ "$actual" = "$expected" ] ||
|
|
[ "$actual" = "$alternative" ]; then
|
|
if [ "$actual_focus" = "$expected_focus" ]; then
|
|
expected_output=$actual
|
|
return 0
|
|
fi
|
|
fi
|
|
sleep 0.05
|
|
i=$((i + 1))
|
|
done
|
|
fail "$name: got '$actual' focused=$actual_focus," \
|
|
"expected '$expected' focused=$expected_focus"
|
|
}
|
|
|
|
assert_events 'FocusIn' '^[[I' '' yes "$(printf '\033[I')"
|
|
assert_events 'FocusOut' '^[[O' '' no "$(printf '\033[O')"
|
|
assert_events 'Escape and FocusIn' 'E^[[I' '^[[IE' yes \
|
|
"$(printf '\033\033[I')"
|
|
assert_events 'Escape and FocusOut' 'E^[[O' '^[[OE' no \
|
|
"$(printf '\033\033[O')"
|
|
assert_events 'split FocusIn' 'E^[[I' '^[[IE' yes \
|
|
"$(printf '\033\033[')" 'I'
|
|
assert_events 'FocusOut split after two Escapes' 'E^[[O' '^[[OE' no \
|
|
"$(printf '\033\033')" '[O'
|
|
assert_events 'M-Escape' A '' no "$(printf '\033\033')"
|
|
assert_events 'M-Up' U '' no "$(printf '\033\033[A')"
|
|
|
|
exit 0
|