mirror of
https://github.com/tmux/tmux.git
synced 2026-10-07 01:55:49 +00:00
670 lines
19 KiB
Bash
670 lines
19 KiB
Bash
#!/bin/sh
|
|
|
|
# A pane can be hidden (minimised) and shown again, returning to exactly its
|
|
# previous state: tiled, floating and zoomed panes alike.
|
|
#
|
|
# This exercises:
|
|
# - resize-pane -H toggling a tiled pane, with its space given to a neighbour
|
|
# and returned unchanged when it is shown;
|
|
# - hiding floating and zoomed panes and hiding every pane in a window;
|
|
# - activating a hidden pane showing it, and next/previous skipping hidden
|
|
# panes;
|
|
# - resize-pane -a -H hiding every visible float and zoomed pane and showing
|
|
# only the panes it hid;
|
|
# - floating, tiling, swapping and killing hidden panes.
|
|
|
|
PATH=/bin:/usr/bin
|
|
TERM=screen
|
|
|
|
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
|
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
|
$TMUX kill-server 2>/dev/null
|
|
trap '$TMUX kill-server 2>/dev/null' 0
|
|
trap 'exit 1' 1 2 15
|
|
|
|
fail()
|
|
{
|
|
echo "$*" >&2
|
|
exit 1
|
|
}
|
|
|
|
run()
|
|
{
|
|
$TMUX "$@" || fail "failed: $*"
|
|
}
|
|
|
|
# check $target $format $expected
|
|
check()
|
|
{
|
|
got=$(run display-message -p -t "$1" "$2") || exit 1
|
|
[ "$got" = "$3" ] || fail "$1 $2: got '$got', expected '$3'"
|
|
}
|
|
|
|
# hidden $pane $expected
|
|
hidden()
|
|
{
|
|
check "$1" '#{pane_hidden_flag}' "$2"
|
|
}
|
|
|
|
# geometry $pane $expected
|
|
geometry()
|
|
{
|
|
check "$1" '#{pane_left}:#{pane_top}:#{pane_width}:#{pane_height}' "$2"
|
|
}
|
|
|
|
# layout $target: the window layout ignoring which panes are active or last.
|
|
layout()
|
|
{
|
|
got=$(run display-message -p -t "$1" '#{window_layout}') || exit 1
|
|
echo "$got" | sed 's/"a":true,//g; s/"l":[0-9]*,//g'
|
|
}
|
|
|
|
# same_layout $target: is the layout the same as when the test started?
|
|
same_layout()
|
|
{
|
|
got=$(layout "$1")
|
|
[ "$got" = "$layout" ] || fail "layout changed: $got, expected $layout"
|
|
}
|
|
|
|
reset()
|
|
{
|
|
$TMUX kill-server 2>/dev/null
|
|
run new-session -d -x 80 -y 24
|
|
A=$(run display-message -p '#{pane_id}') || exit 1
|
|
B=$(run split-window -dPF '#{pane_id}') || exit 1
|
|
layout=$(layout "$A")
|
|
}
|
|
|
|
# A tiled pane gives its space away and gets it back unchanged.
|
|
reset
|
|
hidden "$B" 0
|
|
run resize-pane -H -t "$B"
|
|
hidden "$B" 1
|
|
check "$A" '#{pane_height}' 24
|
|
run resize-pane -H -t "$B"
|
|
hidden "$B" 0
|
|
same_layout "$A"
|
|
|
|
# Selecting a hidden pane shows it and makes it active.
|
|
run resize-pane -H -t "$B"
|
|
run select-pane -t "$B"
|
|
hidden "$B" 0
|
|
check "$B" '#{pane_active}' 1
|
|
same_layout "$A"
|
|
|
|
# Hiding the active pane moves the focus to a visible pane.
|
|
run resize-pane -H -t "$B"
|
|
check "$A" '#{pane_active}' 1
|
|
|
|
# Next and previous skip hidden panes.
|
|
reset
|
|
C=$(run split-window -dPF '#{pane_id}') || exit 1
|
|
run select-pane -t "$A"
|
|
run resize-pane -H -t "$B"
|
|
run select-pane -t :.+
|
|
check "$C" '#{pane_active}' 1
|
|
run select-pane -t :.-
|
|
check "$A" '#{pane_active}' 1
|
|
|
|
# Every tiled pane can be hidden and shown again.
|
|
reset
|
|
run resize-pane -H -t "$B"
|
|
run resize-pane -H -t "$A"
|
|
hidden "$A" 1
|
|
hidden "$B" 1
|
|
run display-message -p ok >/dev/null
|
|
run select-pane -t "$A"
|
|
run select-pane -t "$B"
|
|
hidden "$A" 0
|
|
hidden "$B" 0
|
|
same_layout "$A"
|
|
|
|
# A floating pane keeps its geometry and stacking position.
|
|
reset
|
|
X=$(run new-pane -dPF '#{pane_id}' -t "$A" -x 20 -y 8 -X 8 -Y 3 '') || exit 1
|
|
Y=$(run new-pane -dPF '#{pane_id}' -t "$A" -x 20 -y 8 -X 30 -Y 6 '') || exit 1
|
|
gx=$(run display-message -p -t "$X" '#{pane_left}:#{pane_top}:#{pane_width}:#{pane_height}')
|
|
zx=$(run display-message -p -t "$X" '#{pane_z}')
|
|
run resize-pane -H -t "$X"
|
|
hidden "$X" 1
|
|
check "$X" '#{pane_floating_flag}' 1
|
|
run select-pane -t "$X"
|
|
hidden "$X" 0
|
|
check "$X" '#{pane_active}' 1
|
|
geometry "$X" "$gx"
|
|
check "$Y" '#{pane_z}' 1
|
|
|
|
# A zoomed pane stays zoomed while hidden and when shown.
|
|
reset
|
|
run resize-pane -Z -t "$A"
|
|
run resize-pane -H -t "$A"
|
|
hidden "$A" 1
|
|
check "$A" '#{pane_zoomed_flag}' 1
|
|
run resize-pane -H -t "$A"
|
|
hidden "$A" 0
|
|
check "$A" '#{pane_zoomed_flag}:#{window_zoomed_flag}' '1:1'
|
|
|
|
# Hiding every pane in a window, floating ones included, leaves an empty
|
|
# window that still works.
|
|
reset
|
|
X=$(run new-pane -dPF '#{pane_id}' -t "$A" -x 20 -y 8 -X 8 -Y 3 '') || exit 1
|
|
for p in "$X" "$A" "$B"; do
|
|
run resize-pane -H -t "$p"
|
|
done
|
|
for p in "$X" "$A" "$B"; do
|
|
hidden "$p" 1
|
|
done
|
|
run display-message -p '#{window_layout}' >/dev/null
|
|
run select-pane -t "$B"
|
|
hidden "$B" 0
|
|
check "$B" '#{pane_active}' 1
|
|
|
|
# resize-pane -a -H hides every visible float and zoomed pane and later calls
|
|
# show only those, floats first, leaving panes that were already hidden alone.
|
|
reset
|
|
X=$(run new-pane -dPF '#{pane_id}' -t "$A" -x 20 -y 8 -X 8 -Y 3 '') || exit 1
|
|
Y=$(run new-pane -dPF '#{pane_id}' -t "$A" -x 20 -y 8 -X 30 -Y 6 '') || exit 1
|
|
run resize-pane -H -t "$Y"
|
|
run resize-pane -a -H -t "$A"
|
|
hidden "$X" 1
|
|
hidden "$Y" 1
|
|
hidden "$A" 0
|
|
hidden "$B" 0
|
|
run resize-pane -a -H -t "$A"
|
|
hidden "$X" 0
|
|
hidden "$Y" 1
|
|
hidden "$A" 0
|
|
run resize-pane -Z -t "$B"
|
|
run resize-pane -a -H -t "$A"
|
|
hidden "$B" 1
|
|
hidden "$X" 1
|
|
run resize-pane -a -H -t "$A"
|
|
hidden "$X" 0
|
|
hidden "$B" 1
|
|
run resize-pane -a -H -t "$A"
|
|
hidden "$B" 0
|
|
check "$B" '#{pane_zoomed_flag}' 1
|
|
|
|
# With two zoomed panes and a float the calls cycle: hide all, show the float,
|
|
# show the zooms, hide all again. Hidden zoomed panes are not a zoomed window.
|
|
reset
|
|
run resize-pane -Z -t "$A"
|
|
run resize-pane -Z -t "$B"
|
|
X=$(run new-pane -dPF '#{pane_id}' -t "$A" -x 20 -y 8 -X 8 -Y 3 '') || exit 1
|
|
check "$A" '#{window_zoomed_flag}' 1
|
|
for i in 1 2; do
|
|
run resize-pane -a -H -t "$A"
|
|
for p in "$A" "$B" "$X"; do
|
|
hidden "$p" 1
|
|
done
|
|
check "$A" '#{window_zoomed_flag}:#{pane_zoomed_flag}' '0:1'
|
|
check "$A" '#{window_flags}' '*'
|
|
run resize-pane -a -H -t "$A"
|
|
hidden "$X" 0
|
|
hidden "$A" 1
|
|
hidden "$B" 1
|
|
check "$A" '#{window_zoomed_flag}' 0
|
|
run resize-pane -a -H -t "$A"
|
|
for p in "$A" "$B" "$X"; do
|
|
hidden "$p" 0
|
|
done
|
|
check "$A" '#{window_zoomed_flag}:#{window_flags}' '1:*Z'
|
|
done
|
|
|
|
# A stage with nothing to show is skipped, so every call changes something.
|
|
reset
|
|
run resize-pane -Z -t "$A"
|
|
run resize-pane -a -H -t "$A"
|
|
hidden "$A" 1
|
|
run resize-pane -a -H -t "$A"
|
|
hidden "$A" 0
|
|
reset
|
|
X=$(run new-pane -dPF '#{pane_id}' -t "$A" -x 20 -y 8 -X 8 -Y 3 '') || exit 1
|
|
run resize-pane -a -H -t "$A"
|
|
hidden "$X" 1
|
|
run resize-pane -a -H -t "$A"
|
|
hidden "$X" 0
|
|
|
|
# Showing a pane by hand takes it out of the cycle.
|
|
reset
|
|
run resize-pane -Z -t "$A"
|
|
X=$(run new-pane -dPF '#{pane_id}' -t "$A" -x 20 -y 8 -X 8 -Y 3 '') || exit 1
|
|
run resize-pane -a -H -t "$A"
|
|
run select-pane -t "$X"
|
|
hidden "$X" 0
|
|
hidden "$A" 1
|
|
run resize-pane -a -H -t "$A"
|
|
hidden "$A" 0
|
|
hidden "$X" 0
|
|
|
|
# Activating a tiled pane that is covered by zoomed panes hides them, as the
|
|
# desktop does: they stay zoomed, the tiles are shown and the pane is active.
|
|
reset
|
|
C=$(run split-window -dPF '#{pane_id}') || exit 1
|
|
run resize-pane -Z -t "$A"
|
|
run resize-pane -Z -t "$B"
|
|
run select-pane -t "$C"
|
|
check "$C" '#{pane_active}' 1
|
|
for p in "$A" "$B"; do
|
|
hidden "$p" 1
|
|
check "$p" '#{pane_zoomed_flag}' 1
|
|
done
|
|
hidden "$C" 0
|
|
check "$C" '#{window_zoomed_flag}' 0
|
|
# The last pane brings back the one that was zoomed.
|
|
run select-pane -l
|
|
check "$B" '#{pane_active}:#{pane_hidden_flag}:#{window_zoomed_flag}' '1:0:1'
|
|
# The desktop shows the others, and the active pane is not left covered.
|
|
run select-pane -t "$C"
|
|
run resize-pane -a -H -t "$A"
|
|
for p in "$A" "$B"; do
|
|
hidden "$p" 0
|
|
done
|
|
check "$A" '#{window_zoomed_flag}' 1
|
|
visible=$(run list-panes -F '#{pane_active}#{pane_zoomed_flag}' | grep -c '^11$')
|
|
[ "$visible" = 1 ] || fail "active pane is covered after the desktop"
|
|
|
|
# select-pane -Z moves the zoom to a covered tiled pane without hiding the old
|
|
# one, and so do last-pane -Z and rotate-window -Z.
|
|
reset
|
|
run resize-pane -Z -t "$A"
|
|
run select-pane -Z -t "$B"
|
|
check "$B" '#{pane_zoomed_flag}:#{pane_active}' '1:1'
|
|
check "$A" '#{pane_zoomed_flag}:#{pane_hidden_flag}' '0:0'
|
|
run select-pane -Z -t "$A"
|
|
run select-pane -Z -l
|
|
check "$B" '#{pane_zoomed_flag}:#{pane_hidden_flag}' '1:0'
|
|
check "$A" '#{pane_zoomed_flag}:#{pane_hidden_flag}' '0:0'
|
|
run rotate-window -Z
|
|
check "$A" '#{pane_hidden_flag}' 0
|
|
check "$B" '#{pane_hidden_flag}' 0
|
|
|
|
# Hiding every pane, then showing and closing them one by one, leaves the last
|
|
# pane hidden as the only pane in the window; showing it must not crash.
|
|
reset
|
|
C=$(run split-window -dPF '#{pane_id}') || exit 1
|
|
for p in "$A" "$B" "$C"; do
|
|
run resize-pane -H -t "$p"
|
|
done
|
|
for p in "$A" "$B"; do
|
|
run select-pane -t "$p"
|
|
hidden "$p" 0
|
|
run kill-pane -t "$p"
|
|
done
|
|
hidden "$C" 1
|
|
check "$C" '#{window_panes}' 1
|
|
run select-pane -t "$C"
|
|
hidden "$C" 0
|
|
check "$C" '#{pane_active}:#{pane_width}x#{pane_height}' '1:80x24'
|
|
run resize-pane -H -t "$C"
|
|
run resize-pane -H -t "$C"
|
|
hidden "$C" 0
|
|
|
|
# Floating and tiling a hidden pane keeps it hidden.
|
|
reset
|
|
run resize-pane -H -t "$B"
|
|
run break-pane -W -s "$B"
|
|
hidden "$B" 1
|
|
check "$B" '#{pane_floating_flag}' 1
|
|
run join-pane -s "$B" -t "$B"
|
|
hidden "$B" 1
|
|
check "$B" '#{pane_floating_flag}' 0
|
|
run select-pane -t "$B"
|
|
hidden "$B" 0
|
|
check "$B" '#{pane_floating_flag}' 0
|
|
|
|
# A hidden pane can be swapped and killed. The hidden state belongs to the
|
|
# position in the layout.
|
|
reset
|
|
C=$(run split-window -dPF '#{pane_id}') || exit 1
|
|
run resize-pane -H -t "$B"
|
|
run swap-pane -s "$A" -t "$B"
|
|
hidden "$A" 1
|
|
hidden "$B" 0
|
|
run kill-pane -t "$A"
|
|
run display-message -p -t "$B" ok >/dev/null
|
|
check "$B" '#{window_panes}' 2
|
|
|
|
# Splitting a hidden tiled pane shows it first.
|
|
reset
|
|
run resize-pane -H -t "$B"
|
|
run split-window -d -t "$B"
|
|
hidden "$B" 0
|
|
check "$B" '#{window_panes}' 3
|
|
|
|
# Resizing a hidden tiled pane shows it first, but a hidden float is resized
|
|
# without being shown.
|
|
reset
|
|
run resize-pane -H -t "$B"
|
|
run resize-pane -t "$B" -y 5
|
|
hidden "$B" 0
|
|
X=$(run new-pane -dPF '#{pane_id}' -t "$A" -x 20 -y 8 -X 8 -Y 3 '') || exit 1
|
|
run resize-pane -H -t "$X"
|
|
run resize-pane -t "$X" -x 30
|
|
hidden "$X" 1
|
|
run select-pane -t "$X"
|
|
check "$X" '#{pane_width}' 28
|
|
|
|
# A hidden pane moved to another window is shown there.
|
|
reset
|
|
C=$(run split-window -dPF '#{pane_id}') || exit 1
|
|
run resize-pane -H -t "$C"
|
|
run break-pane -d -s "$C"
|
|
hidden "$C" 0
|
|
check "$C" '#{window_panes}' 1
|
|
check "$A" '#{window_panes}' 2
|
|
|
|
# Layouts record hidden floating panes and leave hidden tiled panes out; a
|
|
# saved layout puts the hidden state back.
|
|
reset
|
|
X=$(run new-pane -dPF '#{pane_id}' -t "$A" -x 20 -y 8 -X 8 -Y 3 '') || exit 1
|
|
run resize-pane -H -t "$X"
|
|
saved=$(run display-message -p -t "$A" '#{window_layout}') || exit 1
|
|
case "$saved" in
|
|
*'"H":true'*) ;;
|
|
*) fail "hidden floating pane not in layout: $saved" ;;
|
|
esac
|
|
run select-pane -t "$X"
|
|
hidden "$X" 0
|
|
run select-layout -t "$A" "$saved"
|
|
hidden "$X" 1
|
|
run resize-pane -H -t "$B"
|
|
out=$(run display-message -p -t "$A" '#{window_layout}') || exit 1
|
|
case "$out" in
|
|
*"\"$B\""*) fail "hidden tiled pane in layout: $out" ;;
|
|
*) ;;
|
|
esac
|
|
|
|
# Swapping with the next or previous pane when the only tiled pane is hidden
|
|
# has nothing to swap with and does nothing.
|
|
reset
|
|
X=$(run new-pane -dPF '#{pane_id}' -t "$A" -x 20 -y 8 -X 8 -Y 3 '') || exit 1
|
|
run kill-pane -t "$B"
|
|
run resize-pane -H -t "$A"
|
|
run swap-pane -D -t "$A"
|
|
run swap-pane -U -t "$A"
|
|
hidden "$A" 1
|
|
check "$X" '#{window_panes}' 2
|
|
|
|
# Preset layouts lay out only the tiled panes that are not hidden and leave the
|
|
# hidden ones hidden.
|
|
reset
|
|
C=$(run split-window -dPF '#{pane_id}') || exit 1
|
|
run resize-pane -H -t "$B"
|
|
for layout in tiled even-horizontal even-vertical main-horizontal \
|
|
main-vertical; do
|
|
run select-layout -t "$A" $layout
|
|
hidden "$B" 1
|
|
hidden "$A" 0
|
|
hidden "$C" 0
|
|
done
|
|
run next-layout -t "$A"
|
|
hidden "$B" 1
|
|
run resize-pane -H -t "$C"
|
|
run select-layout -t "$A" tiled
|
|
run next-layout -t "$A"
|
|
hidden "$C" 1
|
|
check "$A" '#{pane_width}:#{pane_height}' '80:24'
|
|
|
|
# The size a hidden tiled pane gets back follows the window size, so showing it
|
|
# after the window shrank does not squeeze its neighbours out.
|
|
reset
|
|
run kill-server
|
|
run new-session -d -x 80 -y 30
|
|
A=$(run display-message -p '#{pane_id}') || exit 1
|
|
B=$(run split-window -dPF '#{pane_id}') || exit 1
|
|
C=$(run split-window -dPF '#{pane_id}') || exit 1
|
|
run select-layout even-vertical
|
|
before=$(run display-message -p -t "$B" '#{pane_height}') || exit 1
|
|
run resize-pane -H -t "$B"
|
|
run resize-window -x 80 -y 16
|
|
run select-pane -t "$B"
|
|
hidden "$B" 0
|
|
for p in "$A" "$B" "$C"; do
|
|
h=$(run display-message -p -t "$p" '#{pane_height}') || exit 1
|
|
[ "$h" -ge 3 ] || fail "$p is only $h lines high after showing"
|
|
done
|
|
h=$(run display-message -p -t "$B" '#{pane_height}') || exit 1
|
|
[ "$h" -lt "$before" ] || fail "shown pane is $h lines, was $before"
|
|
|
|
# Without the window changing it gets back exactly the size it had.
|
|
run resize-window -x 80 -y 30
|
|
run select-layout even-vertical
|
|
run resize-pane -t "$A" -y 6
|
|
sizes=$(run list-panes -F '#{pane_id}:#{pane_height}') || exit 1
|
|
run resize-pane -H -t "$B"
|
|
run resize-pane -H -t "$B"
|
|
check "$A" '#{pane_height}' 6
|
|
after=$(run list-panes -F '#{pane_id}:#{pane_height}') || exit 1
|
|
[ "$sizes" = "$after" ] || fail "sizes changed: '$sizes' became '$after'"
|
|
|
|
# Showing a hidden pane only resizes it when it does not already have the right
|
|
# size, so a plain hide and show announces a layout change once each.
|
|
$TMUX kill-server 2>/dev/null
|
|
run new-session -d -x 80 -y 23
|
|
A=$(run display-message -p '#{pane_id}') || exit 1
|
|
B=$(run split-window -dPF '#{pane_id}') || exit 1
|
|
sizes=$(run list-panes -F '#{pane_id}:#{pane_height}') || exit 1
|
|
run set -g @count 0
|
|
run set-hook -g window-layout-changed "set -gF @count '#{e|+:#{@count},1}'"
|
|
run resize-pane -H -t "$B"
|
|
count=$(run show -gv @count) || exit 1
|
|
run resize-pane -H -t "$B"
|
|
got=$(run show -gv @count) || exit 1
|
|
[ $((got - count)) -eq 1 ] ||
|
|
fail "showing the pane fired $((got - count)) layout changes, expected 1"
|
|
after=$(run list-panes -F '#{pane_id}:#{pane_height}') || exit 1
|
|
[ "$sizes" = "$after" ] || fail "sizes changed: '$sizes' became '$after'"
|
|
run set-hook -gu window-layout-changed
|
|
|
|
# Zooming a pane shows it, even if it is hidden and already the active pane.
|
|
reset
|
|
run resize-pane -H -t "$A"
|
|
run resize-pane -H -t "$B"
|
|
act=$(run display-message -p -t "$A" '#{?pane_active,1,0}') || exit 1
|
|
if [ "$act" = 1 ]; then
|
|
p=$A
|
|
else
|
|
p=$B
|
|
fi
|
|
hidden "$p" 1
|
|
run resize-pane -Z -t "$p"
|
|
hidden "$p" 0
|
|
check "$p" '#{pane_zoomed_flag}:#{pane_active}' '1:1'
|
|
|
|
# Moving to the pane at the left or right skips a hidden floating pane. The
|
|
# floating pane is flush with the right edge so moving left from the tiled pane
|
|
# wraps round to it.
|
|
reset
|
|
$TMUX kill-server 2>/dev/null
|
|
run new-session -d -x 80 -y 24
|
|
A=$(run display-message -p '#{pane_id}') || exit 1
|
|
X=$(run new-pane -dPF '#{pane_id}' -t "$A" -x 18 -y 6 -X 63 -Y 5 '') || exit 1
|
|
run select-pane -t "$A"
|
|
run select-pane -L -t "$A"
|
|
check "$X" '#{pane_active}' 1
|
|
run select-pane -t "$A"
|
|
run resize-pane -H -t "$X"
|
|
run select-pane -L -t "$A"
|
|
check "$A" '#{pane_active}' 1
|
|
hidden "$X" 1
|
|
|
|
# Mixed vertical and horizontal splits, including three or more panes side by
|
|
# side. Hiding and showing each pane puts every pane back where it was. Hiding
|
|
# several panes and showing them again in the reverse order they were hidden
|
|
# leaves every pane within two cells of where it was. In the same order the panes
|
|
# have the wrong neighbours when they are shown so their sizes cannot be exact,
|
|
# but every pane must be back, tiled and not squeezed. Floating panes, including
|
|
# ones that were never tiled, are part of this: they are not moved by hiding
|
|
# other panes and tile somewhere in the layout without squeezing it.
|
|
#
|
|
# geom: id, left, top, width and height of every pane, sorted by id.
|
|
geom()
|
|
{
|
|
run list-panes -F '#{pane_id} #{pane_left} #{pane_top} #{pane_width} #{pane_height}' |
|
|
sort
|
|
}
|
|
|
|
# near $name $base $now $tolerance
|
|
near()
|
|
{
|
|
echo "$2
|
|
$3" | awk -v tol="$4" -v name="$1" '
|
|
NF == 5 && ($1 in seen) {
|
|
for (i = 2; i <= 5; i++) {
|
|
d = $i - seen[$1, i]
|
|
if (d < 0) d = -d
|
|
if (d > tol) {
|
|
printf "%s: %s differs by %d (%s became %s)\n", name, $1, d, seen[$1, 0], $0
|
|
bad = 1
|
|
}
|
|
}
|
|
next
|
|
}
|
|
NF == 5 { seen[$1] = 1; for (i = 2; i <= 5; i++) seen[$1, i] = $i; seen[$1, 0] = $0 }
|
|
END { exit bad }' || fail "layout not restored"
|
|
}
|
|
|
|
# usable $name $panes $minimum: the panes are tiled, shown and at least the
|
|
# minimum size in both directions.
|
|
usable()
|
|
{
|
|
for p in $2; do
|
|
check "$p" '#{pane_floating_flag}:#{pane_hidden_flag}' 0:0
|
|
w=$(run display-message -p -t "$p" '#{pane_width}') || exit 1
|
|
h=$(run display-message -p -t "$p" '#{pane_height}') || exit 1
|
|
[ "$w" -ge "$3" ] && [ "$h" -ge "$3" ] ||
|
|
fail "$1: $p is only ${w}x$h"
|
|
done
|
|
}
|
|
|
|
# build $size $splits...: a window made of splits, each a flag and a target.
|
|
build()
|
|
{
|
|
size=$1
|
|
shift
|
|
$TMUX kill-server 2>/dev/null
|
|
run new-session -d -x "${size%x*}" -y "${size#*x}" cat
|
|
while [ $# -gt 0 ]; do
|
|
run split-window -d "$1" -t "$2" ''
|
|
shift 2
|
|
done
|
|
}
|
|
|
|
mixed()
|
|
{
|
|
name=$1
|
|
size=$2
|
|
shift 2
|
|
splits="$*"
|
|
build $size $splits
|
|
base=$(geom)
|
|
ids=$(run list-panes -F '#{pane_id}' | sort)
|
|
n=$(echo "$ids" | wc -l)
|
|
last=$(echo "$ids" | tail -1)
|
|
|
|
# Each pane in turn.
|
|
for p in $ids; do
|
|
run resize-pane -H -t "$p"
|
|
hidden "$p" 1
|
|
run resize-pane -H -t "$p"
|
|
hidden "$p" 0
|
|
near "$name hiding $p" "$base" "$(geom)" 0
|
|
done
|
|
|
|
# Every pane but the last, shown in the reverse and in the same order.
|
|
for order in reverse forward; do
|
|
hide=
|
|
for p in $ids; do
|
|
[ "$p" = "$last" ] && continue
|
|
hide="$hide $p"
|
|
run resize-pane -H -t "$p"
|
|
done
|
|
show=$hide
|
|
if [ "$order" = reverse ]; then
|
|
show=
|
|
for p in $hide; do
|
|
show="$p $show"
|
|
done
|
|
fi
|
|
for p in $show; do
|
|
run resize-pane -H -t "$p"
|
|
done
|
|
for p in $ids; do
|
|
hidden "$p" 0
|
|
done
|
|
if [ "$order" = reverse ]; then
|
|
near "$name hiding $((n - 1)) panes, $order" "$base" "$(geom)" 2
|
|
else
|
|
usable "$name hiding $((n - 1)) panes, $order" "$ids" 1
|
|
fi
|
|
done
|
|
|
|
# Any two panes, hidden and shown in the same order, even if they are
|
|
# next to each other: nothing is squeezed.
|
|
if [ "$size" = 120x40 ]; then
|
|
for p in $ids; do
|
|
for q in $ids; do
|
|
[ "$p" = "$q" ] && continue
|
|
build $size $splits
|
|
run resize-pane -H -t "$p"
|
|
run resize-pane -H -t "$q"
|
|
run resize-pane -H -t "$p"
|
|
run resize-pane -H -t "$q"
|
|
usable "$name hiding $p and $q" "$ids" 2
|
|
done
|
|
done
|
|
fi
|
|
|
|
# A floating pane that was never tiled: hiding and showing it, or any
|
|
# tiled pane, changes nothing else.
|
|
build $size $splits
|
|
f=$(run new-pane -dPF '#{pane_id}' -x 20 -y 6 -X 5 -Y 5 '') || exit 1
|
|
base=$(geom)
|
|
for p in $ids $f; do
|
|
run resize-pane -H -t "$p"
|
|
run resize-pane -H -t "$p"
|
|
near "$name with a float, hiding $p" "$base" "$(geom)" 0
|
|
done
|
|
check "$f" '#{pane_floating_flag}' 1
|
|
|
|
# Tiling it puts it in the layout without squeezing the others, and it
|
|
# can be floated and tiled again.
|
|
run join-pane -s "$f" -t "$f"
|
|
usable "$name tiling a new float" "$ids $f" 1
|
|
run break-pane -W -s "$f"
|
|
check "$f" '#{pane_floating_flag}' 1
|
|
run join-pane -s "$f" -t "$f"
|
|
usable "$name tiling the float again" "$ids $f" 1
|
|
|
|
# Floating, hiding and tiling panes together.
|
|
for p in $ids; do
|
|
[ "$p" = "$last" ] && continue
|
|
build $size $splits
|
|
f=$(run new-pane -dPF '#{pane_id}' -x 20 -y 6 -X 5 -Y 5 '') || exit 1
|
|
run break-pane -d -W -s "$p"
|
|
run resize-pane -H -t "$last"
|
|
run resize-pane -H -t "$last"
|
|
run join-pane -d -s "$p" -t "$p"
|
|
run join-pane -d -s "$f" -t "$f"
|
|
usable "$name floating $p, hiding $last, tiling both" "$ids $f" 1
|
|
done
|
|
}
|
|
|
|
for size in 80x24 120x40; do
|
|
mixed "A|(B/C) $size" $size -h %0 -v %1
|
|
mixed "A/(B|C) $size" $size -v %0 -h %1
|
|
mixed "(A|C)/B $size" $size -v %0 -h %0
|
|
mixed "(A/C)|B $size" $size -h %0 -v %0
|
|
mixed "2x2 $size" $size -v %0 -h %0 -h %1
|
|
mixed "A|(B/(C|D)) $size" $size -h %0 -v %1 -h %2
|
|
mixed "A/(B|(C/D)) $size" $size -v %0 -h %1 -v %2
|
|
done
|
|
# Three or more side by side need room.
|
|
mixed "A/(B|C|D)/E 120x40" 120x40 -v %0 -v %1 -v %2 -h %1 -h %1
|
|
mixed "(A/B/C)|(D|E) 120x40" 120x40 -h %0 -v %0 -v %0 -h %1
|
|
mixed "A|(B/C/D)|E 120x40" 120x40 -h %0 -h %1 -v %1 -v %1
|
|
mixed "A/(B|(C/D|E))/F 120x40" 120x40 -v %0 -v %1 -h %1 -v %3 -h %3
|
|
|
|
exit 0
|