diff --git a/regress/screen-redraw-cache.sh b/regress/screen-redraw-cache.sh new file mode 100644 index 00000000..5f0a1ddf --- /dev/null +++ b/regress/screen-redraw-cache.sh @@ -0,0 +1,147 @@ +#!/bin/sh + +# Exercise the scene caching in screen-redraw.c. A scene is built once and reused +# until it is invalidated; redraw_get_scene rebuilds it when the window changes, +# the generation number is bumped (panes moved/resized/swapped), or the offset +# changes. These tests make such a change in place and capture afterwards: if the +# matching invalidation did not fire, the stale cached scene would be drawn and +# the capture would not match the golden. +# +# Each scene is rendered in an inner tmux attached inside an outer tmux pane. The +# outer pane is captured and compared with a golden in screen-redraw-results/. +# +# Run with GENERATE=1 to (re)create the golden files. + +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 -Ltest -f/dev/null" +TMUX2="$TEST_TMUX -Ltest2 -f/dev/null" +RESULTS=screen-redraw-results + +TMP=$(mktemp) +trap "rm -f $TMP; $TMUX kill-server 2>/dev/null; $TMUX2 kill-server 2>/dev/null" \ + 0 1 15 + +fail() { + echo "$*" >&2 + exit 1 +} + +compare() { + sleep 1 + $TMUX capturep -p >$TMP || exit 1 + if [ -n "$GENERATE" ]; then + cp $TMP "$RESULTS/$1.result" || exit 1 + echo "generated $1" + else + cmp -s $TMP "$RESULTS/$1.result" || \ + fail "scene $1 differs from $RESULTS/$1.result" + fi +} + +new_scene() { + $TMUX2 neww -d "sh -c 'exec sleep 100'" || exit 1 + $TMUX2 selectw -t:\$ || exit 1 + $TMUX2 resizew -x40 -y14 || exit 1 +} + +C="sh -c 'exec sleep 100'" + +$TMUX kill-server 2>/dev/null +$TMUX2 kill-server 2>/dev/null + +$TMUX2 new -d -x40 -y14 "sh -c 'exec sleep 100'" || exit 1 +$TMUX2 set -g status off || exit 1 +$TMUX2 set -g window-size manual || exit 1 + +$TMUX new -d -x40 -y14 || exit 1 +$TMUX set -g status off || exit 1 +$TMUX set -g window-size manual || exit 1 +$TMUX set -g default-terminal "tmux-256color" || exit 1 +$TMUX send -l "$TMUX2 attach" || exit 1 +$TMUX send Enter || exit 1 +sleep 1 + +# --- Generation change: a pane is resized in place. --- + +# Two columns; first capture pins the initial divider position. The scene is +# built here and cached. +new_scene +$TMUX2 splitw -h "$C" || exit 1 +$TMUX2 selectp -t0 || exit 1 +compare cache-resize-before + +# Move the divider left. resize-pane bumps the generation, so the cached scene +# must be rebuilt and the divider must appear in its new position. +$TMUX2 resize-pane -t0 -L 6 || exit 1 +compare cache-resize-after + +# --- Generation change: panes are swapped/rotated in place. --- + +# Three columns, each pane titled so the order is visible. The pane status line +# makes a swap show up in the captured scene. +new_scene +$TMUX2 setw pane-border-format " #{pane_title} " || exit 1 +$TMUX2 setw pane-border-status top || exit 1 +$TMUX2 splitw -h "$C" || exit 1 +$TMUX2 selectp -t0 || exit 1 +$TMUX2 splitw -h "$C" || exit 1 +$TMUX2 selectp -t:.0 -T AAA || exit 1 +$TMUX2 selectp -t:.1 -T BBB || exit 1 +$TMUX2 selectp -t:.2 -T CCC || exit 1 +$TMUX2 selectp -t:.0 || exit 1 +compare cache-rotate-before + +# Rotate the panes; the titles must move with them in the rebuilt scene. +# rotate-window keeps the cell geometry, so only its scene invalidation makes +# this differ from cache-rotate-before. +$TMUX2 rotate-window || exit 1 +$TMUX2 selectp -t:.0 || exit 1 +compare cache-rotate-after + +# --- Generation change: two panes swapped in place. --- + +# swap-pane likewise moves panes between cells without changing geometry; the +# swapped titles must appear in the rebuilt scene. +new_scene +$TMUX2 setw pane-border-format " #{pane_title} " || exit 1 +$TMUX2 setw pane-border-status top || exit 1 +$TMUX2 splitw -h "$C" || exit 1 +$TMUX2 selectp -t:.0 -T LEFT || exit 1 +$TMUX2 selectp -t:.1 -T RIGHT || exit 1 +$TMUX2 selectp -t:.0 || exit 1 +compare cache-swap-before + +$TMUX2 swap-pane -d -s:.0 -t:.1 || exit 1 +$TMUX2 selectp -t:.0 || exit 1 +compare cache-swap-after + +# --- Window change: the client switches between two differently laid out +# windows and back. The scene is keyed on the window, so each must show its own +# layout and switching back must not show the other window's cached scene. --- + +# Window A: a single pane (no internal border). +$TMUX2 neww -d "sh -c 'exec sleep 100'" || exit 1 +$TMUX2 selectw -t:\$ || exit 1 +$TMUX2 resizew -x40 -y14 || exit 1 +A=$($TMUX2 display -p '#{window_id}') || exit 1 + +# Window B: a top/bottom split (a horizontal border). +$TMUX2 neww -d "sh -c 'exec sleep 100'" || exit 1 +$TMUX2 selectw -t:\$ || exit 1 +$TMUX2 resizew -x40 -y14 || exit 1 +$TMUX2 splitw -v "$C" || exit 1 +B=$($TMUX2 display -p '#{window_id}') || exit 1 + +$TMUX2 selectw -t$A || exit 1 +compare cache-window-a +$TMUX2 selectw -t$B || exit 1 +compare cache-window-b +$TMUX2 selectw -t$A || exit 1 +compare cache-window-a-again + +exit 0 diff --git a/regress/screen-redraw-floating.sh b/regress/screen-redraw-floating.sh index c5b9d460..a60cdb40 100644 --- a/regress/screen-redraw-floating.sh +++ b/regress/screen-redraw-floating.sh @@ -95,6 +95,13 @@ $TMUX2 new-pane -x28 -y8 -X4 -Y1 -B double \ "sh -c 'printf FLOAT; exec sleep 100'" || exit 1 compare floating-border-double +# Floating pane with no border lines: redraw_mark_pane_borders returns early so +# the float has no border at all, only its (clipped) content over the base pane. +new_scene 40 12 +$TMUX2 new-pane -x20 -y6 -X10 -Y3 -B none \ + "sh -c 'printf NOBORDER; exec sleep 100'" || exit 1 +compare floating-noborder + # Floating pane positioned past the right and bottom edges: must clip. new_scene 40 12 $TMUX2 new-pane -x20 -y6 -X30 -Y8 "sh -c 'printf CLIP; exec sleep 100'" || exit 1 diff --git a/regress/screen-redraw-indicators.sh b/regress/screen-redraw-indicators.sh index f24ea400..60bf652b 100644 --- a/regress/screen-redraw-indicators.sh +++ b/regress/screen-redraw-indicators.sh @@ -125,6 +125,42 @@ $TMUX2 splitw -v "$C" || exit 1 $TMUX2 selectp -t0 || exit 1 compare two-pane-colour-horizontal -e +# The colour split only applies with exactly two tiled panes. With three panes +# the split is suppressed: the whole border uses the active pane's colour and +# there is no coloured half (redraw_check_two_pane_colours returns 0). +new_scene +$TMUX2 setw pane-active-border-style fg=red || exit 1 +$TMUX2 setw pane-border-style fg=green || exit 1 +$TMUX2 splitw -h "$C" || exit 1 +$TMUX2 selectp -t0 || exit 1 +$TMUX2 splitw -h "$C" || exit 1 +$TMUX2 selectp -t0 || exit 1 +compare colour-three-suppressed -e + +# A floating pane is ignored by the two-pane count, so two tiled panes plus a +# float still split. The float itself is never coloured by the indicator. +new_scene +$TMUX2 setw pane-active-border-style fg=red || exit 1 +$TMUX2 setw pane-border-style fg=green || exit 1 +$TMUX2 splitw -h "$C" || exit 1 +$TMUX2 selectp -t0 || exit 1 +$TMUX2 new-pane -x16 -y6 -X10 -Y2 "$C" || exit 1 +$TMUX2 selectp -t0 || exit 1 +compare colour-two-plus-float -e + +# --- Both indicators together. --- + +# pane-border-indicators both enables the arrow and the colour split at once +# (it satisfies both the arrow and the colour branches). Two panes so the colour +# split also applies. +$TMUX2 set -g pane-border-indicators both || exit 1 +new_scene +$TMUX2 setw pane-active-border-style fg=red || exit 1 +$TMUX2 setw pane-border-style fg=green || exit 1 +$TMUX2 splitw -h "$C" || exit 1 +$TMUX2 selectp -t0 || exit 1 +compare indicators-both -e + # --- Marked pane. --- # A marked pane (select-pane -m) has its border drawn reversed. Captured with -e diff --git a/regress/screen-redraw-results/cache-resize-after.result b/regress/screen-redraw-results/cache-resize-after.result new file mode 100644 index 00000000..3153e9bc --- /dev/null +++ b/regress/screen-redraw-results/cache-resize-after.result @@ -0,0 +1,14 @@ + │ + │ + │ + │ + │ + │ + │ + │ + │ + │ + │ + │ + │ + │ diff --git a/regress/screen-redraw-results/bidi-isolates.result b/regress/screen-redraw-results/cache-resize-before.result similarity index 100% rename from regress/screen-redraw-results/bidi-isolates.result rename to regress/screen-redraw-results/cache-resize-before.result diff --git a/regress/screen-redraw-results/cache-rotate-after.result b/regress/screen-redraw-results/cache-rotate-after.result new file mode 100644 index 00000000..14f859e9 --- /dev/null +++ b/regress/screen-redraw-results/cache-rotate-after.result @@ -0,0 +1,14 @@ +── BBB ───┬── CCC ──┬── AAA ──────────── + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ diff --git a/regress/screen-redraw-results/cache-rotate-before.result b/regress/screen-redraw-results/cache-rotate-before.result new file mode 100644 index 00000000..95deb8e1 --- /dev/null +++ b/regress/screen-redraw-results/cache-rotate-before.result @@ -0,0 +1,14 @@ +── AAA ───┬── BBB ──┬── CCC ──────────── + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ diff --git a/regress/screen-redraw-results/pane-status-mixed.result b/regress/screen-redraw-results/cache-swap-after.result similarity index 76% rename from regress/screen-redraw-results/pane-status-mixed.result rename to regress/screen-redraw-results/cache-swap-after.result index 7d8e1456..34e3b502 100644 --- a/regress/screen-redraw-results/pane-status-mixed.result +++ b/regress/screen-redraw-results/cache-swap-after.result @@ -1,4 +1,4 @@ - │ +── RIGHT ───────────┬── LEFT ─────────── │ │ │ diff --git a/regress/screen-redraw-results/cache-swap-before.result b/regress/screen-redraw-results/cache-swap-before.result new file mode 100644 index 00000000..50aadd6d --- /dev/null +++ b/regress/screen-redraw-results/cache-swap-before.result @@ -0,0 +1,14 @@ +── LEFT ────────────┬── RIGHT ────────── + │ + │ + │ + │ + │ + │ + │ + │ + │ + │ + │ + │ + │ diff --git a/regress/screen-redraw-results/cache-window-a-again.result b/regress/screen-redraw-results/cache-window-a-again.result new file mode 100644 index 00000000..5cf5d3dc --- /dev/null +++ b/regress/screen-redraw-results/cache-window-a-again.result @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/regress/screen-redraw-results/cache-window-a.result b/regress/screen-redraw-results/cache-window-a.result new file mode 100644 index 00000000..5cf5d3dc --- /dev/null +++ b/regress/screen-redraw-results/cache-window-a.result @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/regress/screen-redraw-results/cache-window-b.result b/regress/screen-redraw-results/cache-window-b.result new file mode 100644 index 00000000..3a6144ae --- /dev/null +++ b/regress/screen-redraw-results/cache-window-b.result @@ -0,0 +1,14 @@ + + + + + + + +──────────────────────────────────────── + + + + + + diff --git a/regress/screen-redraw-results/colour-three-suppressed.result b/regress/screen-redraw-results/colour-three-suppressed.result new file mode 100644 index 00000000..718cf036 --- /dev/null +++ b/regress/screen-redraw-results/colour-three-suppressed.result @@ -0,0 +1,12 @@ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ diff --git a/regress/screen-redraw-results/colour-two-plus-float.result b/regress/screen-redraw-results/colour-two-plus-float.result new file mode 100644 index 00000000..74ea83e1 --- /dev/null +++ b/regress/screen-redraw-results/colour-two-plus-float.result @@ -0,0 +1,12 @@ + │ + ┌────────────────┐ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + └────────────────┘ + │ + │ + │ diff --git a/regress/screen-redraw-results/floating-noborder.result b/regress/screen-redraw-results/floating-noborder.result new file mode 100644 index 00000000..f15e2401 --- /dev/null +++ b/regress/screen-redraw-results/floating-noborder.result @@ -0,0 +1,12 @@ +base + + + NOBORDER + + + + + + + + diff --git a/regress/screen-redraw-results/indicators-both.result b/regress/screen-redraw-results/indicators-both.result new file mode 100644 index 00000000..4c9e76e7 --- /dev/null +++ b/regress/screen-redraw-results/indicators-both.result @@ -0,0 +1,12 @@ + │ + ← + │ + │ + │ + │ + │ + │ + │ + │ + │ + │ diff --git a/regress/screen-redraw-results/scrollbar-split-left.result b/regress/screen-redraw-results/scrollbar-split-left.result new file mode 100644 index 00000000..8108a471 --- /dev/null +++ b/regress/screen-redraw-results/scrollbar-split-left.result @@ -0,0 +1,12 @@ + base │ base +  │  +  │  +  │  +  │  +  │  +  │  +  │  +  │  +  │  +  │  +  │  diff --git a/regress/screen-redraw-results/scrollbar-split-right.result b/regress/screen-redraw-results/scrollbar-split-right.result new file mode 100644 index 00000000..b49abd2f --- /dev/null +++ b/regress/screen-redraw-results/scrollbar-split-right.result @@ -0,0 +1,12 @@ +base  │base  +  │  +  │  +  │  +  │  +  │  +  │  +  │  +  │  +  │  +  │  +  │  diff --git a/regress/screen-redraw-scrollbars.sh b/regress/screen-redraw-scrollbars.sh index aa44bfb8..926a4a11 100644 --- a/regress/screen-redraw-scrollbars.sh +++ b/regress/screen-redraw-scrollbars.sh @@ -106,6 +106,27 @@ $TMUX2 setw pane-scrollbars-style "bg=black,fg=white,width=1,pad=0" || exit 1 $TMUX2 new-pane -x20 -y6 -X8 -Y3 "sh -c 'printf FLOAT; exec sleep 100'" || exit 1 compare scrollbar-floating +# Two tiled panes side by side, each with a right scrollbar. The left pane's +# scrollbar sits between its content and the shared border, so the border is +# extended outward over the scrollbar gap (the right += sb_w path in +# redraw_mark_pane_borders) and must still join cleanly. The right pane's +# scrollbar abuts the window edge. +new_scene +$TMUX2 setw pane-scrollbars-position right || exit 1 +$TMUX2 setw pane-scrollbars-style "bg=black,fg=white,width=1,pad=0" || exit 1 +$TMUX2 splitw -h "sh -c 'printf base; exec sleep 100'" || exit 1 +$TMUX2 selectp -t0 || exit 1 +compare scrollbar-split-right + +# Same split with the scrollbars on the left: the right pane's scrollbar now sits +# between the shared border and its content (the left -= sb_w path). +new_scene +$TMUX2 setw pane-scrollbars-position left || exit 1 +$TMUX2 setw pane-scrollbars-style "bg=black,fg=white,width=1,pad=0" || exit 1 +$TMUX2 splitw -h "sh -c 'printf base; exec sleep 100'" || exit 1 +$TMUX2 selectp -t0 || exit 1 +compare scrollbar-split-left + # Scrollbar slider in copy mode: with scrollback the slider is shorter than the # track, so this exercises the slider geometry (which only runs when the pane is # in a mode). copy-mode -H hides the position indicator, which is not stable.