mirror of
https://github.com/tmux/tmux.git
synced 2026-10-08 10:54:28 +00:00
Support Kitty and SIXEL input and output with grid-resident image layers, history and copy-mode integration, text fallback rendering, and damage-rectangle redraws. Consolidate the image work through 250f96b4b onto the redraw-damage-rectangles-new base, excluding the superseded redraw implementation and its historical merges. The original history is preserved in backup/4902-image-support-before-master-rebase-20261003.
143 lines
6.0 KiB
Bash
Executable File
143 lines
6.0 KiB
Bash
Executable File
#!/bin/sh
|
|
|
|
# Regression test: with imagescroll granted, does tmux actually use a native
|
|
# scrolling-region command (DECSTBM, and DECSLRM if the pane isn't full
|
|
# width) to perform the scroll, rather than tty_redraw_region()'s fallback
|
|
# full manual repaint? This directly checks the concern raised in PR review
|
|
# that tmux "isn't using scrolling regions" for an image-bearing pane -
|
|
# imagescroll only makes sense to grant a terminal if tmux is actually
|
|
# relying on a real native scroll to carry the image along, not silently
|
|
# falling back to redrawing every line by hand while still skipping the
|
|
# image retransmission (which would just lose the image for nothing).
|
|
#
|
|
# tty_redraw_region() (tty.c) logs one of two lines whenever it runs at
|
|
# all - "%s large region redraw" or "%s small region redraw" - so their
|
|
# total absence after the scroll proves the native path
|
|
# (tty_cmd_linefeed()/scrollup()/scrolldown()/reverseindex()) was taken
|
|
# instead. Combined with image-sixel-region-scroll.sh's own check (the
|
|
# image is not retransmitted), this proves imagescroll's trust is actually
|
|
# backed by a real native scroll, not a coincidence.
|
|
#
|
|
# Phase 2 is the deliberate opposite case, and is what PR review's concern
|
|
# actually described: pane-scrollbars makes this pane less than full width,
|
|
# and without margins granted, tty_cmd_*()'s own
|
|
# "(!tty_full_width(tty, ctx) && !tty_use_margin(tty))" check has no native
|
|
# scrolling-region option left and must fall back - proving phase 1 wasn't
|
|
# trivially passing, and that redraw_image_scroll_result()'s failure path
|
|
# correctly also stops imagescroll's trust from applying when that happens
|
|
# (the image must be retransmitted here, exactly as
|
|
# image-sixel-region-scroll.sh's own phase 2 already separately proves).
|
|
#
|
|
# A real attached client is needed for any of this redraw code to run at
|
|
# all, so this uses the same nested inner/outer tmux pattern as
|
|
# image-sixel-region-scroll.sh.
|
|
|
|
PATH=/bin:/usr/bin
|
|
TERM=screen
|
|
LC_ALL=C.UTF-8
|
|
export TERM LC_ALL
|
|
|
|
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
|
TMUX="$TEST_TMUX -LtestA$$ -vv -f/dev/null"
|
|
TMUX2="$TEST_TMUX -LtestB$$ -f/dev/null"
|
|
|
|
cleanup()
|
|
{
|
|
$TMUX kill-server >/dev/null 2>&1
|
|
$TMUX2 kill-server >/dev/null 2>&1
|
|
}
|
|
fail()
|
|
{
|
|
echo "$*" >&2
|
|
cleanup
|
|
exit 1
|
|
}
|
|
|
|
cleanup
|
|
|
|
DIR=$(mktemp -d) || exit 1
|
|
cd "$DIR" || exit 1
|
|
trap "cleanup; cd /; rm -rf $DIR" 0 1 15
|
|
|
|
WIDTH=40
|
|
HEIGHT=20
|
|
|
|
HEADER='\033Pq"1;1;26;26#0;2;100;100;100#0!26~-!26~-!26~-!26~-!26B\033\\'
|
|
|
|
$TMUX new-session -d -s inner -x $WIDTH -y $HEIGHT \
|
|
"printf '$HEADER'; exec sh" || exit 1
|
|
sleep 0.3
|
|
|
|
[ "$($TMUX display-message -p '#{image_support}')" = 0 ] && exit 0
|
|
$TMUX set -g pane-scrollbars on || exit 1
|
|
$TMUX set -as terminal-features ',*:sixel' || exit 1
|
|
$TMUX set -as terminal-features ',*:imagescroll' || exit 1
|
|
|
|
$TMUX2 new-session -d -x $WIDTH -y $HEIGHT || exit 1
|
|
OUTER=$($TMUX2 list-panes -F '#{pane_id}' | head -1)
|
|
[ -n "$OUTER" ] || fail "No outer pane."
|
|
$TMUX2 set -as terminal-features ',*:sixel@' || fail "disable outer sixel failed"
|
|
TMP=$(mktemp)
|
|
$TMUX2 pipe-pane -t "$OUTER" -O "cat >$TMP" || fail "pipe-pane failed"
|
|
$TMUX2 send-keys -t "$OUTER" -l "$TMUX attach -t inner" || fail "send attach failed"
|
|
$TMUX2 send-keys -t "$OUTER" Enter || fail "send enter failed"
|
|
sleep 1
|
|
|
|
grep -qa '"1;1;26;26' "$TMP" || fail "sanity: image never reached the client"
|
|
|
|
LOG=$(ls tmux-server*.log 2>/dev/null | head -1)
|
|
[ -n "$LOG" ] || fail "sanity: no server -vv log was produced"
|
|
|
|
run_scroll()
|
|
{
|
|
label=$1
|
|
BEFORE=$(wc -l <"$LOG")
|
|
: >"$TMP"
|
|
|
|
$TMUX send-keys -t inner -l "yes | head -n 10" || fail "$label: send scroll failed"
|
|
$TMUX send-keys -t inner Enter || fail "$label: send enter failed"
|
|
sleep 1
|
|
|
|
n_dcs=$(grep -ac "$(printf '\033P')" "$TMP")
|
|
n_redraw=$(tail -n +$((BEFORE + 1)) "$LOG" | grep -c "region redraw")
|
|
}
|
|
|
|
# --- Phase 1: margins granted - real native scrolling region expected,
|
|
# image never retransmitted. ---
|
|
$TMUX set -as terminal-features ',*:margins' || fail "grant margins failed"
|
|
sleep 0.3
|
|
$TMUX display-message -p '#{client_termfeatures}' |
|
|
grep -q imagescroll || fail "sanity: imagescroll was not granted to the client"
|
|
|
|
run_scroll "phase 1 (margins granted)"
|
|
[ "$n_dcs" -eq 0 ] ||
|
|
fail "phase 1: image was retransmitted ($n_dcs times) - imagescroll's trust did not engage, so this run cannot test what it is meant to"
|
|
[ "$n_redraw" -eq 0 ] ||
|
|
fail "phase 1: tty_redraw_region() fired ($n_redraw times) while scrolling an image-bearing pane with margins+imagescroll granted - tmux fell back to a full manual repaint instead of a real native scroll, so trusting the terminal to have moved the image was never justified"
|
|
|
|
# --- Phase 2: margins revoked - the pane still isn't full width
|
|
# (pane-scrollbars is on), so this is the scenario PR review's "not using
|
|
# scrolling regions" concern actually described: no native scrolling-region
|
|
# option is available, tty_redraw_region() must fire, and
|
|
# redraw_image_scroll_result()'s failure path must in turn stop
|
|
# imagescroll's trust from applying, so the image is retransmitted instead
|
|
# of silently lost. Resend the image first - phase 1's scrolling already
|
|
# pushed the original one (26 pixels tall, a couple of rows at most) out of
|
|
# the pane, so without this there would be nothing left to retransmit
|
|
# either way, and the check below would pass for the wrong reason. ---
|
|
$TMUX set -as terminal-features ',*:margins@' || fail "revoke margins failed"
|
|
sleep 0.3
|
|
: >"$TMP"
|
|
$TMUX send-keys -t inner -l "printf '$HEADER'" || fail "resend image failed"
|
|
$TMUX send-keys -t inner Enter || fail "send enter failed"
|
|
sleep 1.5
|
|
grep -qa '"1;1;26;26' "$TMP" || fail "sanity: image did not reappear before phase 2"
|
|
|
|
run_scroll "phase 2 (margins revoked)"
|
|
[ "$n_redraw" -gt 0 ] ||
|
|
fail "sanity: without margins, scrolling a scrollbar-enabled image-bearing pane never fell back to tty_redraw_region() - this scenario no longer exercises the bug phase 1 checks for"
|
|
[ "$n_dcs" -gt 0 ] ||
|
|
fail "phase 2: image was not retransmitted after tty_redraw_region() fired - imagescroll's trust incorrectly stayed engaged despite the fallback, which would silently lose the image"
|
|
|
|
exit 0
|