Files
tmux/regress/tty-clamp-area-status-top.sh
2026-10-07 11:02:08 +01:00

128 lines
3.2 KiB
Bash
Executable File

#!/bin/sh
# Clearing an area of a pane that is only partly visible in a client smaller
# than the window must account for status lines at the top. The area is
# clamped in window coordinates but drawn in terminal coordinates, which are
# shifted down by the status lines.
#
# Phase 1: the viewport is at the top, so the bottom of the cleared area is
# hidden; the last rows on the terminal must still be cleared.
# Phase 2: the viewport is at the bottom, so the top of the cleared area is
# hidden; this used to fail with "tty_clamp_area: y too big".
PATH=/bin:/usr/bin
TERM=screen
LC_ALL=C.UTF-8
export PATH TERM LC_ALL
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
DIR=$(mktemp -d) || exit 1
INNER="$TEST_TMUX -LtestI$$ -f/dev/null"
OUTER="$TEST_TMUX -LtestO$$ -f/dev/null"
CAPTURE=$DIR/capture
fail()
{
echo "$*" >&2
exit 1
}
cleanup()
{
$OUTER kill-server 2>/dev/null
$INNER kill-server 2>/dev/null
rm -rf "$DIR"
}
trap cleanup 0 1 15
wait_for_client()
{
i=0
while [ "$i" -lt 50 ]; do
count=$($INNER list-clients 2>/dev/null | wc -l)
[ "$count" -eq 1 ] && return 0
sleep 0.1
i=$((i + 1))
done
fail "inner client did not attach"
}
wait_for_marker()
{
marker=$1
i=0
while [ "$i" -lt 50 ]; do
$INNER has-session 2>/dev/null || fail "inner server exited"
$OUTER capture-pane -p -t outer >"$CAPTURE" || exit 1
grep -q "$marker" "$CAPTURE" && return 0
sleep 0.1
i=$((i + 1))
done
fail "client did not receive $marker"
}
# Fill all 20 rows, then clear from the top and print a marker on a row that
# is visible in the current viewport.
cat >"$DIR/emitter.pl" <<'PERL'
use strict;
use warnings;
sub wait_for {
my ($file) = @_;
select undef, undef, undef, 0.01 while !-e $file;
}
$| = 1;
for my $phase (1 .. 2) {
wait_for("$ENV{TRIGGER}-fill-$phase");
print "\e[H", join("\r\n", ("FILL") x 20);
wait_for("$ENV{TRIGGER}-clear-$phase");
my $row = $phase == 1 ? 1 : 20;
print "\e[H\e[J\e[$row;1HCLEARED$phase";
}
sleep 100;
PERL
$INNER new-session -d -s inner -x 40 -y 20 \
"TRIGGER='$DIR/trigger' perl '$DIR/emitter.pl'" || exit 1
$INNER set -g window-size manual || exit 1
$INNER set -g status 2 || exit 1
$INNER set -g status-position top || exit 1
$INNER set -g status-interval 0 || exit 1
$INNER set -g automatic-rename off || exit 1
# The client is as large as the window, so with two status lines only 18
# window rows are visible.
$OUTER new-session -d -s outer -x 40 -y 20 'sleep 100' || exit 1
$OUTER set -g status off || exit 1
$OUTER set -g window-size manual || exit 1
$OUTER set -g default-terminal screen || exit 1
$OUTER respawn-pane -k -t outer "$INNER attach-session -t inner" || exit 1
wait_for_client
NAME=$($OUTER display-message -p -t outer '#{pane_tty}') || exit 1
for phase in 1 2; do
if [ "$phase" -eq 1 ]; then
PAN=-U
else
PAN=-D
fi
: >"$DIR/trigger-fill-$phase"
sleep 0.2
$INNER refresh-client -t "$NAME" $PAN 100 || exit 1
sleep 0.5
: >"$DIR/trigger-clear-$phase"
wait_for_marker "CLEARED$phase"
sleep 0.2
$INNER has-session 2>/dev/null || fail "inner server exited"
$OUTER capture-pane -p -t outer >"$CAPTURE" || exit 1
if grep -q FILL "$CAPTURE"; then
cat "$CAPTURE" >&2
fail "phase $phase left rows uncleared"
fi
done
exit 0