mirror of
https://github.com/tmux/tmux.git
synced 2026-07-09 02:49:30 +00:00
-k/empty panes tests.
This commit is contained in:
171
regress/mode-kill.sh
Executable file
171
regress/mode-kill.sh
Executable file
@@ -0,0 +1,171 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Tests of the -k flag on the mode-entering commands (cmd-copy-mode.c and
|
||||
# cmd-choose-tree.c). With -k the pane is killed when the mode is exited: this
|
||||
# is stored on the mode entry in window_pane_set_mode() and acted on in
|
||||
# window_pane_reset_mode() (window.c). It is exercised here for:
|
||||
#
|
||||
# - copy-mode -k (window-copy.c);
|
||||
# - choose-tree -k (window-tree.c);
|
||||
# - choose-buffer -k (window-buffer.c).
|
||||
#
|
||||
# choose-tree and choose-buffer share cmd_choose_tree_exec(), which also backs
|
||||
# choose-client and customize-mode, so those are not repeated.
|
||||
#
|
||||
# Each mode is entered in the active pane of a two-pane window: exiting with
|
||||
# -k must remove that pane and leave the other. copy-mode is left with the
|
||||
# server-side "-X cancel" and needs no client, so those tests run first. The
|
||||
# tree modes only act on a key once the client has drawn the mode, so - as in
|
||||
# choose-tree.sh - a second server then provides a client (an inner "tmux
|
||||
# attach") and its pane is captured to wait until the mode has rendered before
|
||||
# the exit key is sent.
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMP=$(mktemp -d) || exit 1
|
||||
TMUX_TMPDIR="$TMP"
|
||||
export TMUX_TMPDIR
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -LtestB$$ -f/dev/null"
|
||||
|
||||
cleanup()
|
||||
{
|
||||
$TMUX kill-server 2>/dev/null
|
||||
$TMUX2 kill-server 2>/dev/null
|
||||
rm -rf "$TMP"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
fail()
|
||||
{
|
||||
echo "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# capture the screen rendered by the inner client.
|
||||
capture()
|
||||
{
|
||||
$TMUX2 capture-pane -p -t out:0 2>/dev/null
|
||||
}
|
||||
|
||||
# wait_clients $n: wait until the test server has exactly $n clients.
|
||||
wait_clients()
|
||||
{
|
||||
i=0
|
||||
while [ "$i" -lt 50 ]; do
|
||||
c=$($TMUX list-clients -F x 2>/dev/null | grep -c x)
|
||||
[ "$c" -eq "$1" ] && return 0
|
||||
sleep 0.2
|
||||
i=$((i + 1))
|
||||
done
|
||||
fail "expected $1 clients, have $c"
|
||||
}
|
||||
|
||||
# wait_mode $target $state: wait until a pane enters (1) or leaves (0) mode.
|
||||
wait_mode()
|
||||
{
|
||||
i=0
|
||||
while [ "$i" -lt 50 ]; do
|
||||
got=$($TMUX display-message -p -t "$1" '#{pane_in_mode}' \
|
||||
2>/dev/null)
|
||||
[ "$got" = "$2" ] && return 0
|
||||
sleep 0.2
|
||||
i=$((i + 1))
|
||||
done
|
||||
fail "pane $1 mode state is '$got', expected '$2'"
|
||||
}
|
||||
|
||||
# wait_for $marker: wait until the rendered screen contains $marker.
|
||||
wait_for()
|
||||
{
|
||||
i=0
|
||||
while [ "$i" -lt 50 ]; do
|
||||
capture | grep -F -q "$1" && return 0
|
||||
sleep 0.2
|
||||
i=$((i + 1))
|
||||
done
|
||||
fail "timed out waiting for '$1' to render"
|
||||
}
|
||||
|
||||
# pane_gone $pane-id: true if the pane no longer exists. (display-message -t
|
||||
# on a missing pane id falls back to a default target and succeeds, so the
|
||||
# pane list is searched instead.)
|
||||
pane_gone()
|
||||
{
|
||||
! $TMUX list-panes -s -t m -F '#{pane_id}' 2>/dev/null | \
|
||||
grep -q -x "$1"
|
||||
}
|
||||
|
||||
# open_window: make a fresh two-pane window and leave the new (active) pane
|
||||
# as $active and the other as $other.
|
||||
open_window()
|
||||
{
|
||||
$TMUX new-window -t m: -n w 'cat' || fail "new-window failed"
|
||||
$TMUX split-window -t m:w 'cat' || fail "split-window failed"
|
||||
other=$($TMUX display-message -p -t m:w.0 '#{pane_id}')
|
||||
active=$($TMUX display-message -p -t m:w '#{pane_id}')
|
||||
}
|
||||
|
||||
# check_killed $label: wait for the active pane to be killed, leaving only the
|
||||
# other pane, then drop the window.
|
||||
check_killed()
|
||||
{
|
||||
i=0
|
||||
while [ "$i" -lt 50 ]; do
|
||||
pane_gone "$active" && break
|
||||
sleep 0.2
|
||||
i=$((i + 1))
|
||||
done
|
||||
pane_gone "$active" || fail "$1: pane not killed on exit"
|
||||
panes=$($TMUX list-panes -t m:w -F '#{pane_id}' | tr '\n' ' ')
|
||||
[ "$panes" = "$other " ] || \
|
||||
fail "$1: expected only $other left, have $panes"
|
||||
$TMUX kill-window -t m:w 2>/dev/null
|
||||
}
|
||||
|
||||
# Session m; window 0 keeps a live pane so the session (and later the client)
|
||||
# survives each test killing a pane.
|
||||
$TMUX new-session -d -s m -x 80 -y 24 'cat' || exit 1
|
||||
|
||||
# --- copy-mode -k kills the pane, plain copy-mode does not -------------------
|
||||
#
|
||||
# copy-mode is exited with the server-side "-X cancel", so no client is needed
|
||||
# and none is attached yet.
|
||||
open_window
|
||||
$TMUX copy-mode -k -t m:w || fail "copy-mode -k failed"
|
||||
wait_mode "$active" 1
|
||||
$TMUX send-keys -t m:w -X cancel || fail "copy cancel failed"
|
||||
check_killed 'copy-mode -k'
|
||||
|
||||
open_window
|
||||
$TMUX copy-mode -t m:w || fail "copy-mode failed"
|
||||
wait_mode "$active" 1
|
||||
$TMUX send-keys -t m:w -X cancel || fail "copy cancel failed"
|
||||
wait_mode "$active" 0
|
||||
pane_gone "$active" && fail 'copy-mode: pane killed without -k'
|
||||
$TMUX kill-window -t m:w 2>/dev/null
|
||||
|
||||
# --- choose-tree -k and choose-buffer -k kill the pane ----------------------
|
||||
#
|
||||
# These need the client to draw the mode before a key acts, so attach one now.
|
||||
# A paste buffer is needed for choose-buffer to have something to show, and a
|
||||
# distinct -F marker per call is waited for in the capture so the exit key is
|
||||
# only sent once the mode is drawn.
|
||||
$TMUX set-buffer 'mode-kill buffer' || exit 1
|
||||
$TMUX2 new-session -d -s out -x 80 -y 24 "$TMUX attach -t m" || exit 1
|
||||
wait_clients 1
|
||||
open_window
|
||||
$TMUX choose-tree -k -F 'TREEMARK' -t m:w || fail "choose-tree -k failed"
|
||||
wait_for 'TREEMARK'
|
||||
$TMUX send-keys -t m:w q || fail "choose-tree exit failed"
|
||||
check_killed 'choose-tree -k'
|
||||
|
||||
open_window
|
||||
$TMUX choose-buffer -k -F 'BUFMARK' -t m:w || fail "choose-buffer -k failed"
|
||||
wait_for 'BUFMARK'
|
||||
$TMUX send-keys -t m:w q || fail "choose-buffer exit failed"
|
||||
check_killed 'choose-buffer -k'
|
||||
|
||||
exit 0
|
||||
@@ -399,6 +399,19 @@ check_fmt 'P:9.0' '#{pane_pid}' ''
|
||||
check_fail 'command cannot be given for empty pane' \
|
||||
new-window -d -E -t P:10 -n empty 'true'
|
||||
|
||||
# An empty string as the sole argument is equivalent to -E: the pane is
|
||||
# created empty, running no command.
|
||||
check_ok new-window -d -t P:12 -n empty-str ''
|
||||
check_fmt 'P:12.0' '#{pane_dead}' '0'
|
||||
check_fmt 'P:12.0' '#{pane_pid}' ''
|
||||
check_ok kill-window -t P:12
|
||||
|
||||
# A missing command (rather than an empty one) runs the default command, so
|
||||
# the pane is not empty and has a process.
|
||||
check_ok new-window -d -t P:12 -n default-cmd
|
||||
check_fmt 'P:12.0' '#{?pane_pid,live,empty}' 'live'
|
||||
check_ok kill-window -t P:12
|
||||
|
||||
# respawn-pane -E stores the command and cwd without starting it.
|
||||
tmp=${TMPDIR:-/tmp}/tmux-pane-ops-empty-$$
|
||||
rm -f "$tmp"
|
||||
@@ -453,6 +466,13 @@ check_fmt 'P:2' '#{window_panes}' '2'
|
||||
check_fail 'command cannot be given for empty pane' \
|
||||
split-window -d -E -t P:2.0 'sleep 5'
|
||||
|
||||
# An empty string as the sole argument splits with an empty pane, like -E.
|
||||
eid=$($TMUX split-window -d -P -F '#{pane_id}' -t P:2.0 '')
|
||||
check_fmt "$eid" '#{pane_dead}' '0'
|
||||
check_fmt "$eid" '#{pane_pid}' ''
|
||||
check_ok kill-pane -t "$eid"
|
||||
check_fmt 'P:2' '#{window_panes}' '2'
|
||||
|
||||
# -e adds to the new pane's environment.
|
||||
eid=$($TMUX split-window -d -P -F '#{pane_id}' -e GREETING=hello -t P:2.0 \
|
||||
'echo $GREETING; exec cat')
|
||||
|
||||
Reference in New Issue
Block a user