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.
111 lines
4.7 KiB
Bash
Executable File
111 lines
4.7 KiB
Bash
Executable File
#!/bin/sh
|
|
|
|
# Regression test: an image wider than the pane at the time it was
|
|
# displayed must show more of itself once the pane grows wide enough,
|
|
# instead of staying clipped to its original width forever.
|
|
#
|
|
# image_write() (image.c) clips an image's width to whatever fit in the
|
|
# pane when it was first displayed, and never revisits that decision -
|
|
# unlike height, which recovers naturally through ordinary scrollback,
|
|
# there is no "scroll right", so the clipped columns were permanently
|
|
# discarded. window_pane_resize() (window.c) now calls
|
|
# image_grid_resize_width() after a pane grows wider, which extends each
|
|
# existing placement's spans - using the image's own retained, immutable
|
|
# pixel data - up to whichever is smaller: the image's full width or the
|
|
# new pane width. See tmux-image-redraw-known-bugs.md for the full
|
|
# write-up.
|
|
#
|
|
# This is checked via the SIXEL raster widths reported in the client's raw
|
|
# output before and after widening the window. The redraw triggered by the
|
|
# resize is damage-based (only the newly-uncovered columns are dirtied), so
|
|
# it does not redraw the whole row as one wider raster - it sends the
|
|
# already-correct clipped portion's width again untouched, plus a *second*,
|
|
# separate raster covering just the newly-added columns. So rather than
|
|
# looking for a single wider raster, this checks that the widths seen
|
|
# across both redraws, added together, account for the fixture's full
|
|
# pixel width - i.e. the previously-clipped remainder actually appeared.
|
|
|
|
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$$ -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
|
|
|
|
TMP=$(mktemp)
|
|
trap "cleanup; rm -f $TMP" 0 1 15
|
|
|
|
FIXTURE=$(pwd)/monkey-2.sixel.txt
|
|
FULL=$(grep -oa '"1;1;[0-9]*;[0-9]*' $FIXTURE | head -1 | cut -d';' -f3)
|
|
[ -n "$FULL" ] || fail "could not read fixture's own raster width"
|
|
|
|
# The fixture is 360px wide - narrow enough that a 12-column pane clips it,
|
|
# comfortably below the 360px it would take to show in full.
|
|
$TMUX new-session -d -s inner -x 12 -y 40 "cat '$FIXTURE'; exec sh" || exit 1
|
|
sleep 0.5
|
|
|
|
[ "$($TMUX display-message -p '#{image_support}')" = 0 ] && exit 0
|
|
$TMUX set -as terminal-features ',*:sixel' || exit 1
|
|
|
|
# Start the outer session with a plain shell, then start capturing before
|
|
# triggering the attach - starting the attach as the outer pane's initial
|
|
# command would mean pipe-pane only starts after the attach-driven initial
|
|
# redraw (which sends the image) has already happened, missing it.
|
|
$TMUX2 new-session -d -x 12 -y 40 || exit 1
|
|
OUTER=$($TMUX2 list-panes -F '#{pane_id}' | head -1)
|
|
[ -n "$OUTER" ] || fail "No outer pane."
|
|
# The outer client is just another tmux client receiving raw PTY output
|
|
# that happens to contain sixel DCS sequences - left alone, it would
|
|
# independently decode and place its own second, differently-sized image
|
|
# on top of the inner session's, confounding the raster-width measurement
|
|
# below. Disable sixel on the outer client so only the inner session's
|
|
# placement exists.
|
|
$TMUX2 set -as terminal-features ',*:sixel@' || fail "disable outer sixel failed"
|
|
$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
|
|
|
|
before=$(grep -oa '"1;1;[0-9]*;' $TMP | grep -o '[0-9]*' | sort -n | tail -1)
|
|
[ -n "$before" ] || fail "sanity: image never reached the client"
|
|
[ "$before" -lt 360 ] || fail "sanity: image was not clipped by the narrow pane ($before)"
|
|
: >$TMP
|
|
|
|
# Widen the window well past the image's full width - resize the outer
|
|
# client, since the inner session's displayed size follows whatever
|
|
# terminal size its attached client actually has.
|
|
$TMUX2 resize-window -t "$OUTER" -x 30 -y 40 || fail "resize-window failed"
|
|
sleep 1
|
|
$TMUX refresh-client || fail "refresh-client failed"
|
|
sleep 1
|
|
|
|
# The widths seen after the resize, added together (deduplicated - the
|
|
# same chunk may legitimately be retransmitted), should account for the
|
|
# fixture's full pixel width: this is expected to fail before the fix,
|
|
# where the newly-uncovered columns are never redrawn at all and only the
|
|
# original clipped width ever appears - see the header comment.
|
|
after_total=$(grep -oa '"1;1;[0-9]*;' $TMP | grep -o '[0-9]*' | sort -nu |
|
|
awk '{s+=$1} END{print s+0}')
|
|
[ "$after_total" -gt 0 ] ||
|
|
fail "no image raster was sent at all after widening the window"
|
|
[ "$after_total" -ge $((FULL - 20)) ] ||
|
|
fail "image stayed clipped at ${before}px after widening the window (widths summed to only ${after_total}px, expected close to ${FULL}px)"
|
|
|
|
exit 0
|