mirror of
https://github.com/tmux/tmux.git
synced 2026-10-13 14:24:28 +00:00
Implement generalised image support
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.
This commit is contained in:
142
regress/image-scroll-uses-region.sh
Executable file
142
regress/image-scroll-uses-region.sh
Executable file
@@ -0,0 +1,142 @@
|
||||
#!/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
|
||||
Reference in New Issue
Block a user