mirror of
https://github.com/tmux/tmux.git
synced 2026-10-10 04:04:27 +00:00
Merge branch 'master' into local_windows
This commit is contained in:
77
regress/control-client-exit-stalled.sh
Executable file
77
regress/control-client-exit-stalled.sh
Executable file
@@ -0,0 +1,77 @@
|
||||
#!/bin/sh
|
||||
|
||||
# A control client whose terminal has stopped accepting output (for example
|
||||
# its ssh connection or terminal emulator died) never drains the output that
|
||||
# server_client_check_exit waits on before sending MSG_EXIT, and may then
|
||||
# never close its socket either. This must not prevent the server from
|
||||
# exiting: after kill-server the server previously stayed alive forever with
|
||||
# server_exit set, closing every new connection immediately, so every new
|
||||
# client failed with "server exited unexpectedly" until the server was killed
|
||||
# by hand. The server now bounds the exit handshake: it discards output it
|
||||
# can never deliver and drops the client if it still does not close.
|
||||
#
|
||||
# The stalled terminal is simulated by a fifo whose read end is held open but
|
||||
# never read.
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
DIR=$(mktemp -d)
|
||||
FIFO=$DIR/fifo
|
||||
SERVER=
|
||||
|
||||
mkfifo "$FIFO" || exit 1
|
||||
|
||||
cleanup() {
|
||||
[ -n "$SERVER" ] && kill -9 "$SERVER" 2>/dev/null
|
||||
$TMUX kill-server 2>/dev/null
|
||||
exec 8<&- 2>/dev/null
|
||||
rm -rf "$DIR"
|
||||
}
|
||||
trap cleanup 0 1 15
|
||||
|
||||
# A detached session whose pane floods printable output forever.
|
||||
$TMUX -f/dev/null new -d -x 80 -y 24 -s rt 'cat /dev/zero | tr "\000" x' || exit 1
|
||||
SERVER=$($TMUX display -pt rt '#{pid}')
|
||||
|
||||
# Attach a control client with output down the fifo; stdin held open by sleep
|
||||
# so it stays attached. The fifo fills and is never read, so a backlog forms
|
||||
# in the server that can never be delivered.
|
||||
( sleep 60 ) | $TMUX -f/dev/null -C attach -t rt >"$FIFO" 2>&1 &
|
||||
exec 8<"$FIFO"
|
||||
|
||||
n=0
|
||||
while [ $n -lt 50 ]; do
|
||||
$TMUX lsc -F '#{client_name}' 2>/dev/null | grep -q . && break
|
||||
sleep 0.1
|
||||
n=$((n + 1))
|
||||
done
|
||||
$TMUX lsc -F '#{client_name}' 2>/dev/null | grep -q . ||
|
||||
{ echo "control client did not attach"; exit 1; }
|
||||
|
||||
# Let the pane flood fill the fifo so the client's output is stuck.
|
||||
sleep 2
|
||||
|
||||
# Ask the server to exit. This sets CLIENT_EXIT on the stalled client, whose
|
||||
# output can never drain.
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
# The server must exit within the exit timeout (10 seconds) plus slack,
|
||||
# rather than staying in limbo forever rejecting new clients.
|
||||
n=0
|
||||
while [ $n -lt 100 ]; do
|
||||
if ! kill -0 "$SERVER" 2>/dev/null; then
|
||||
SERVER=
|
||||
exit 0
|
||||
fi
|
||||
sleep 0.2
|
||||
n=$((n + 1))
|
||||
done
|
||||
|
||||
echo "server did not exit after kill-server; new clients see:"
|
||||
$TMUX ls 2>&1
|
||||
exit 1
|
||||
158
regress/control-notify-guard.sh
Executable file
158
regress/control-notify-guard.sh
Executable file
@@ -0,0 +1,158 @@
|
||||
#!/bin/sh
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
LC_ALL=C.UTF-8
|
||||
LANG=C.UTF-8
|
||||
export TERM LC_ALL LANG
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
|
||||
TMPDIR=$(mktemp -d)
|
||||
IN="$TMPDIR/in"
|
||||
OUT="$TMPDIR/out"
|
||||
BADCFG="$TMPDIR/bad.conf"
|
||||
PID=
|
||||
|
||||
cleanup()
|
||||
{
|
||||
exec 3>&- 2>/dev/null
|
||||
[ -n "$PID" ] && kill "$PID" 2>/dev/null
|
||||
$TMUX kill-server 2>/dev/null
|
||||
rm -rf "$TMPDIR"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
fail()
|
||||
{
|
||||
echo "$1" >&2
|
||||
[ -s "$OUT" ] && cat "$OUT" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
wait_for()
|
||||
{
|
||||
pattern=$1
|
||||
timeout=${2:-60}
|
||||
i=0
|
||||
|
||||
while [ "$i" -lt "$timeout" ]; do
|
||||
grep -F -- "$pattern" "$OUT" >/dev/null 2>&1 && return 0
|
||||
sleep 0.1
|
||||
i=$((i + 1))
|
||||
done
|
||||
fail "missing: $pattern"
|
||||
}
|
||||
|
||||
wait_for_count()
|
||||
{
|
||||
pattern=$1
|
||||
expected=$2
|
||||
timeout=${3:-60}
|
||||
i=0
|
||||
|
||||
while [ "$i" -lt "$timeout" ]; do
|
||||
count=$(grep -F -c -- "$pattern" "$OUT" 2>/dev/null)
|
||||
[ "$count" -ge "$expected" ] && return 0
|
||||
sleep 0.1
|
||||
i=$((i + 1))
|
||||
done
|
||||
fail "missing count $expected for: $pattern"
|
||||
}
|
||||
|
||||
send()
|
||||
{
|
||||
printf '%s\n' "$1" >&3 || fail "failed to send: $1"
|
||||
}
|
||||
|
||||
# A notification is a standalone protocol message. It must never be part of
|
||||
# the response between the real %begin and matching %end or %error for a
|
||||
# command. Ignore guard-looking command output while a real guard is open.
|
||||
check_guards()
|
||||
{
|
||||
awk '
|
||||
function notification(line) {
|
||||
return line ~ /^%(sessions-changed|session-changed |unlinked-window-add )/ ||
|
||||
line ~ /^%(pause |continue |config-error )/
|
||||
}
|
||||
!open && $0 ~ /^%begin [0-9]+ [0-9]+ [0-9]+$/ {
|
||||
open = 1
|
||||
time = $2
|
||||
number = $3
|
||||
flags = $4
|
||||
next
|
||||
}
|
||||
open && ($0 == "%end " time " " number " " flags ||
|
||||
$0 == "%error " time " " number " " flags) {
|
||||
open = 0
|
||||
next
|
||||
}
|
||||
notification($0) {
|
||||
seen[$1]++
|
||||
if (open) {
|
||||
print "notification inside guard: " $0 > "/dev/stderr"
|
||||
bad = 1
|
||||
}
|
||||
}
|
||||
END {
|
||||
if (open) {
|
||||
print "unterminated command guard" > "/dev/stderr"
|
||||
bad = 1
|
||||
}
|
||||
if (seen["%sessions-changed"] < 2 ||
|
||||
seen["%session-changed"] < 1 ||
|
||||
seen["%unlinked-window-add"] < 2 ||
|
||||
seen["%pause"] < 1 || seen["%continue"] < 1 ||
|
||||
seen["%config-error"] < 1) {
|
||||
print "missing expected notification" > "/dev/stderr"
|
||||
bad = 1
|
||||
}
|
||||
exit bad
|
||||
}' "$OUT" || fail "bad control protocol notification ordering"
|
||||
}
|
||||
|
||||
$TMUX kill-server 2>/dev/null
|
||||
$TMUX new-session -d -s guard -x 80 -y 24 || exit 1
|
||||
pane=$($TMUX display-message -p -t guard:0.0 '#{pane_id}') || exit 1
|
||||
|
||||
mkfifo "$IN" || exit 1
|
||||
: >"$OUT"
|
||||
$TMUX -C attach-session -t guard <"$IN" >"$OUT" 2>&1 &
|
||||
PID=$!
|
||||
exec 3>"$IN"
|
||||
|
||||
# Attaching generates a session notification synchronously from inside the
|
||||
# attach command. It must follow the closing guard.
|
||||
wait_for '%session-changed '
|
||||
|
||||
# Guard-looking output is arbitrary command output, not protocol state. Make
|
||||
# new-session both generate notifications and print an unmatched fake %begin;
|
||||
# it must not leave those notifications permanently deferred.
|
||||
send "set-option -g @fake-begin '%begin 1 2 3'"
|
||||
send "new-session -d -P -F '#{@fake-begin}' -s fake-begin"
|
||||
wait_for_count '%sessions-changed' 1
|
||||
|
||||
# Likewise, fake %end output from a command that generates multiple
|
||||
# notifications must not flush them before the command actually ends.
|
||||
send "set-option -g @fake-end '%end 1 2 3'"
|
||||
send "new-session -d -P -F '#{@fake-end}' -s fake-end"
|
||||
wait_for_count '%sessions-changed' 2
|
||||
|
||||
# Exercise notification paths outside control-notify.c.
|
||||
send "refresh-client -A '$pane:pause'"
|
||||
wait_for "%pause $pane"
|
||||
send "refresh-client -A '$pane:continue'"
|
||||
wait_for "%continue $pane"
|
||||
|
||||
printf '%s\n' 'not-a-command' >"$BADCFG"
|
||||
send "source-file '$BADCFG'"
|
||||
wait_for '%config-error '
|
||||
|
||||
# A final command guarantees all earlier command guards have completed before
|
||||
# the transcript is checked.
|
||||
send "display-message -p 'guard-check-done'"
|
||||
wait_for 'guard-check-done'
|
||||
check_guards
|
||||
|
||||
exit 0
|
||||
@@ -114,5 +114,30 @@ $TMUX send-keys -X next-space-end
|
||||
$TMUX send-keys -X copy-selection
|
||||
[ "$($TMUX show-buffer)" = "500xyz" ] || exit 1
|
||||
|
||||
# Test that vi cursor movement does not stop on the padding cell of a wide
|
||||
# character at the end of a line.
|
||||
$TMUX kill-server 2>/dev/null
|
||||
sleep 1
|
||||
$TMUX new -d -x20 -y5 \
|
||||
"printf 'abc中\nxyz\n'; exec cat" || exit 1
|
||||
$TMUX set-window-option -g mode-keys vi
|
||||
$TMUX copy-mode
|
||||
$TMUX send-keys -X history-top
|
||||
$TMUX send-keys -X start-of-line
|
||||
$TMUX send-keys -X cursor-right
|
||||
$TMUX send-keys -X cursor-right
|
||||
$TMUX send-keys -X cursor-right
|
||||
[ "$($TMUX display -p '#{copy_cursor_x},#{copy_cursor_y}')" = "3,0" ] ||
|
||||
exit 1
|
||||
$TMUX send-keys -X cursor-right
|
||||
[ "$($TMUX display -p '#{copy_cursor_x},#{copy_cursor_y}')" = "0,1" ] ||
|
||||
exit 1
|
||||
$TMUX send-keys -X cursor-left
|
||||
[ "$($TMUX display -p '#{copy_cursor_x},#{copy_cursor_y}')" = "3,0" ] ||
|
||||
exit 1
|
||||
$TMUX send-keys -X cursor-left
|
||||
[ "$($TMUX display -p '#{copy_cursor_x},#{copy_cursor_y}')" = "2,0" ] ||
|
||||
exit 1
|
||||
|
||||
$TMUX kill-server 2>/dev/null
|
||||
exit 0
|
||||
|
||||
@@ -280,6 +280,7 @@ test_user_hook()
|
||||
settle
|
||||
assert_equals "$($TMUX show-option -qv @cm_hook)" \
|
||||
"display-message hook" "add user hook"
|
||||
$TMUX set-hook -E @cm_hook || fail "fire user hook failed"
|
||||
|
||||
send q
|
||||
wait_mode 0
|
||||
@@ -287,7 +288,10 @@ test_user_hook()
|
||||
repeat_key j 3
|
||||
send Right j
|
||||
settle
|
||||
assert_contains "$(capture)" "@cm_hook" "user hook shown as hook"
|
||||
screen=$(capture)
|
||||
assert_contains "$screen" "@cm_hook" "user hook shown as hook"
|
||||
assert_contains "$screen" "This hook has been fired 1 times, last " \
|
||||
"user hook fire count and time"
|
||||
|
||||
send u y
|
||||
settle
|
||||
@@ -302,10 +306,17 @@ test_hook_array()
|
||||
|
||||
$TMUX set-hook -g 'after-new-session[0]' 'display-message old' ||
|
||||
fail "set hook array failed"
|
||||
$TMUX set-hook -g -R after-new-session || fail "fire hook array failed"
|
||||
|
||||
open_customize '#{==:#{option_name},after-new-session}'
|
||||
repeat_key j 3
|
||||
send Right j Right j
|
||||
send Right j
|
||||
settle
|
||||
screen=$(capture)
|
||||
assert_contains "$screen" "This hook has been fired " \
|
||||
"array hook fire count"
|
||||
assert_contains "$screen" ", last " "array hook fire time"
|
||||
send Right j
|
||||
settle
|
||||
|
||||
send a
|
||||
|
||||
109
regress/format-animation.sh
Normal file
109
regress/format-animation.sh
Normal file
@@ -0,0 +1,109 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Exercise the A format modifier (format_cycle in format.c). It is expanded
|
||||
# only in a status format and arms the client cycle timer to redraw the status
|
||||
# line as the frames advance, so the only place its behaviour shows is a
|
||||
# rendered status line.
|
||||
#
|
||||
# The status line is rendered by an inner tmux attached inside an outer tmux
|
||||
# pane; capturing the outer pane shows what the inner tmux drew. The inner
|
||||
# window runs sleep and every other status line is blanked, so the capture
|
||||
# contains the frame and nothing else.
|
||||
#
|
||||
# Each frame lasts 700 milliseconds and the capture is repeated once a second,
|
||||
# so consecutive samples always land on a different frame: no exact period is
|
||||
# assumed and nothing in the test asks for a redraw, so seeing the frame change
|
||||
# means the status line animated on its own.
|
||||
|
||||
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"
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
# Capture the outer pane and return the text the inner tmux drew.
|
||||
capture() {
|
||||
$TMUX capturep -p >$TMP || fail "capture failed"
|
||||
tr -d '[:space:]' <$TMP
|
||||
}
|
||||
|
||||
$TMUX kill-server 2>/dev/null
|
||||
$TMUX2 kill-server 2>/dev/null
|
||||
|
||||
# Inner: a window which draws nothing and a status line which is only the
|
||||
# animation, so the outer capture is the current frame on its own.
|
||||
$TMUX2 new -d -x30 -y8 "sh -c 'exec sleep 100'" || exit 1
|
||||
$TMUX2 set -g window-size latest || exit 1
|
||||
i=1
|
||||
while [ $i -le 4 ]; do
|
||||
$TMUX2 set -g status-format[$i] "" || exit 1
|
||||
i=$((i + 1))
|
||||
done
|
||||
$TMUX2 set -g status-format[0] "#{A/7:AAAA,BBBB,CCCC}" || exit 1
|
||||
|
||||
$TMUX new -d -x30 -y8 || 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
|
||||
|
||||
# Sample the frames. Every sample must be one of the frames and at least two
|
||||
# different ones must be seen; status-interval is 15 seconds so only the cycle
|
||||
# timer can have redrawn the status line.
|
||||
seen=""
|
||||
i=0
|
||||
while [ $i -lt 4 ]; do
|
||||
[ $i -eq 0 ] || sleep 1
|
||||
frame=$(capture)
|
||||
case "$frame" in
|
||||
AAAA|BBBB|CCCC) ;;
|
||||
*) fail "status line is '$frame', not a frame" ;;
|
||||
esac
|
||||
case " $seen " in
|
||||
*" $frame "*) ;;
|
||||
*) seen="$seen $frame" ;;
|
||||
esac
|
||||
i=$((i + 1))
|
||||
done
|
||||
set -- $seen
|
||||
[ $# -ge 2 ] || fail "status line did not animate, only saw$seen"
|
||||
|
||||
# Outside a status format there is no animation at all.
|
||||
out=$($TMUX2 display-message -p "#{A:ZZZZ,YYYY}") || exit 1
|
||||
[ -z "$out" ] || fail "display-message gave '$out', want empty"
|
||||
out=$($TMUX2 list-panes -F "#{A:ZZZZ,YYYY}") || exit 1
|
||||
[ -z "$out" ] || fail "list-panes gave '$out', want empty"
|
||||
|
||||
# Nor inside #(), where the frames would change the command on every frame.
|
||||
$TMUX2 set -g status-format[0] '#(echo "[#{A:ZZZZ,YYYY}]")' || exit 1
|
||||
sleep 1
|
||||
out=$(capture)
|
||||
case "$out" in
|
||||
*ZZZZ*|*YYYY*) fail "job command saw a frame: '$out'" ;;
|
||||
*"[]"*) ;;
|
||||
*) fail "job output is '$out', want []" ;;
|
||||
esac
|
||||
|
||||
# Empty frames and a missing or bad count must not upset the server.
|
||||
for f in '#{A:}' '#{A/0:a,b}' '#{A/x:a,b}' '#{A:,,,}'; do
|
||||
$TMUX2 set -g status-format[0] "$f" || fail "setting $f failed"
|
||||
$TMUX2 has-session >/dev/null 2>&1 || fail "server lost with $f"
|
||||
done
|
||||
sleep 1
|
||||
$TMUX2 has-session >/dev/null 2>&1 || fail "server lost after empty frames"
|
||||
|
||||
exit 0
|
||||
@@ -85,6 +85,24 @@ echo "$shown" | grep -q '^session-created\[0\]' ||
|
||||
fail "missing first array item: $shown"
|
||||
echo "$shown" | grep -q '^session-created\[1\]' ||
|
||||
fail "missing second array item: $shown"
|
||||
shown=$($TMUX show-hooks -gF '#{option_name}:#{hook_fire_count}:#{t/p:hook_fire_time}' \
|
||||
session-created) ||
|
||||
fail "show-hooks -gF failed"
|
||||
echo "$shown" | grep -q '^session-created:[1-9][0-9]*:[^-][^ ]*$' ||
|
||||
fail "missing hook fire formats: $shown"
|
||||
|
||||
# User hooks are options, but show-hooks should list only registered @ hooks
|
||||
# and not ordinary user options.
|
||||
$TMUX set -g @not-a-hook value || fail "set @not-a-hook failed"
|
||||
$TMUX set-hook -g @user-hook 'lsk' ||
|
||||
fail "set-hook @user-hook failed"
|
||||
shown=$($TMUX show-hooks -g) ||
|
||||
fail "show-hooks -g all failed"
|
||||
echo "$shown" | grep -q '^@user-hook lsk$' ||
|
||||
fail "missing user hook: $shown"
|
||||
if echo "$shown" | grep -q '^@not-a-hook '; then
|
||||
fail "show-hooks listed user option: $shown"
|
||||
fi
|
||||
|
||||
# Unsetting removes the whole hook.
|
||||
$TMUX set-hook -gu session-created || fail "set-hook -gu failed"
|
||||
|
||||
@@ -174,3 +174,17 @@ check_raw_matches()
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
check_raw_no_matches()
|
||||
{
|
||||
name=$1
|
||||
shift
|
||||
|
||||
capture_raw "$name" >"$TMP"
|
||||
for unexpected in "$@"; do
|
||||
if grep -Eq "$unexpected" "$TMP"; then
|
||||
printf "%s\n" "$unexpected" >"$EXP"
|
||||
fail "$name raw unexpected"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
@@ -22,6 +22,16 @@ check_capture rename 'X'
|
||||
start_pane apc-title 20 3 '\033_test-title\033\\X\n'
|
||||
check_capture apc-title 'X'
|
||||
|
||||
cmd='i=0; while [ "$i" -lt 12 ]; do '
|
||||
cmd="${cmd}printf '\\033[22;0t'; i=\$((i + 1)); done; "
|
||||
cmd="${cmd}printf X; sleep 2"
|
||||
start_cmd title-stack 20 3 "$cmd"
|
||||
check_capture title-stack 'X'
|
||||
$TMUX respawn-pane -k -t title-stack: \
|
||||
"printf '\\033[22;0tY'; sleep 2" || exit 1
|
||||
sleep 0.3
|
||||
check_capture title-stack 'Y'
|
||||
|
||||
$TMUX kill-server 2>/dev/null
|
||||
sleep 0.1
|
||||
$TMUX new-session -d -x 20 -y 3 -s osc52 "sleep 2" || exit 1
|
||||
|
||||
@@ -41,5 +41,9 @@ start_pane combining-left 10 3 '\314\201A\n'
|
||||
check_capture combining-left 'A'
|
||||
check_cursor combining-left '0,1'
|
||||
|
||||
start_pane combining-overflow 10 3 'u\314\245\314\245\314\245\314\245\314\245\314\245\314\245\314\245\314\245\314\245\314\245\314\245\314\245\314\245\314\245\314\245\n'
|
||||
check_raw_matches combining-overflow '^ C 0,0 data=\(1,31,u'
|
||||
check_raw_no_matches combining-overflow 'data=\(0,'
|
||||
|
||||
$TMUX kill-server 2>/dev/null
|
||||
exit $exit_status
|
||||
|
||||
66
regress/menu-mouse.sh
Normal file
66
regress/menu-mouse.sh
Normal file
@@ -0,0 +1,66 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Check that mouse selection in an active menu uses the correct coordinates
|
||||
# when the status line is at the top.
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -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
|
||||
}
|
||||
|
||||
# click COL ROW
|
||||
#
|
||||
# Write an SGR mouse press then release at a 1-based position to the outer pane
|
||||
# holding the inner client.
|
||||
click()
|
||||
{
|
||||
col="$1"
|
||||
row="$2"
|
||||
|
||||
seq=$(printf '\033[<0;%s;%sM\033[<0;%s;%sm' \
|
||||
"$col" "$row" "$col" "$row")
|
||||
$TMUX2 send-keys -t "$OUTER" -l "$seq" 2>/dev/null
|
||||
sleep 1
|
||||
}
|
||||
|
||||
cleanup
|
||||
|
||||
$TMUX new-session -d -s inner -x 80 -y 24 'sleep 100' || exit 1
|
||||
$TMUX set -g mouse on || exit 1
|
||||
$TMUX set -g status-position top || exit 1
|
||||
$TMUX set -g @menu-choice '' || exit 1
|
||||
|
||||
$TMUX2 new-session -d -x 80 -y 24 "$TMUX attach -t inner" || exit 1
|
||||
sleep 1
|
||||
OUTER=$($TMUX2 list-panes -F '#{pane_id}' | head -1)
|
||||
[ -n "$OUTER" ] || fail "No outer pane."
|
||||
|
||||
$TMUX display-menu -M -x 5 -y 7 \
|
||||
"First item" f "set -g @menu-choice first" \
|
||||
"Second item" s "set -g @menu-choice second" || exit 1
|
||||
sleep 1
|
||||
|
||||
# -y is the bottom of the menu, so with four menu lines this puts the menu at
|
||||
# window y=3. The first item is then at window y=4. With one status line at the
|
||||
# top, this is terminal row 6 in SGR's 1-based coordinates.
|
||||
click 8 6
|
||||
|
||||
choice=$($TMUX show -gv @menu-choice 2>/dev/null)
|
||||
[ "$choice" = "first" ] || fail "got '$choice', expected 'first'"
|
||||
|
||||
cleanup
|
||||
exit 0
|
||||
@@ -269,6 +269,22 @@ test_customize_mode()
|
||||
assert_alive "customize-mode exit"
|
||||
}
|
||||
|
||||
test_customize_break_pane()
|
||||
{
|
||||
start_client option-break
|
||||
side=$($TMUX split-window -d -P -F '#{pane_id}' \
|
||||
-t option-break:0 'cat') || fail "customize split failed"
|
||||
|
||||
$TMUX customize-mode -t "$side" || fail "customize-mode failed"
|
||||
wait_mode "$side" 1
|
||||
$TMUX break-pane -d -s "$side" || fail "customize break-pane failed"
|
||||
|
||||
assert_alive "customize-mode break-pane"
|
||||
wait_mode "$side" 1
|
||||
$TMUX send-keys -t "$side" q || fail "customize-mode quit failed"
|
||||
wait_mode "$side" 0
|
||||
}
|
||||
|
||||
test_copy_mode()
|
||||
{
|
||||
start_client copy-a 'i=0; while [ $i -lt 200 ]; do echo "copy mutation line $i"; i=$((i + 1)); done; cat'
|
||||
@@ -302,6 +318,7 @@ test_choose_tree
|
||||
test_choose_buffer
|
||||
test_choose_client
|
||||
test_customize_mode
|
||||
test_customize_break_pane
|
||||
test_copy_mode
|
||||
cleanup
|
||||
exit 0
|
||||
|
||||
@@ -49,11 +49,33 @@ drag()
|
||||
sleep 1
|
||||
}
|
||||
|
||||
# right_click COL ROW KEY
|
||||
#
|
||||
# Open the right-click menu at a 1-based position and choose KEY.
|
||||
right_click()
|
||||
{
|
||||
col="$1"
|
||||
row="$2"
|
||||
key="$3"
|
||||
|
||||
seq=$(printf '\033[<2;%s;%sM' "$col" "$row")
|
||||
$TMUX2 send-keys -t "$OUTER" -l "$seq" 2>/dev/null
|
||||
sleep 0.2
|
||||
$TMUX2 send-keys -t "$OUTER" "$key" 2>/dev/null
|
||||
sleep 1
|
||||
}
|
||||
|
||||
cleanup
|
||||
|
||||
$TMUX new-session -d -s inner -x 80 -y 24 || exit 1
|
||||
$TMUX set -g mouse on
|
||||
$TMUX set -g default-command 'sleep 100'
|
||||
keys=$($TMUX list-keys -T root -F '#{key_command}' MouseDown3Empty) ||
|
||||
fail "list MouseDown3Empty failed"
|
||||
case "$keys" in
|
||||
*"New Pane"*"New Window"*) ;;
|
||||
*) fail "missing empty-area menu binding: $keys" ;;
|
||||
esac
|
||||
|
||||
$TMUX2 new-session -d -x 80 -y 24 "$TMUX attach -t inner" || exit 1
|
||||
sleep 1
|
||||
@@ -80,6 +102,17 @@ $TMUX break-pane -W -s "$BASE" || fail "break base pane failed"
|
||||
$TMUX resize-pane -t "$BASE" -x10 -y4 || fail "resize floating base failed"
|
||||
$TMUX move-pane -t "$BASE" -P top-left || fail "move floating base failed"
|
||||
|
||||
# Right-click in empty window space and choose New Pane. This creates a new
|
||||
# floating pane and tiles it.
|
||||
right_click 20 8 p
|
||||
|
||||
id=$($TMUX list-panes -F '#{?pane_active,#{pane_id},}' | tail -n 1)
|
||||
[ -n "$id" ] || fail "no pane created from empty-area menu"
|
||||
[ "$id" != "$BASE" ] || fail "empty-area menu did not create a new pane"
|
||||
|
||||
must_equal "$($TMUX display-message -p -t "$id" '#{pane_floating_flag}')" 0
|
||||
$TMUX kill-pane -t "$id" || fail "kill empty-area menu pane failed"
|
||||
|
||||
# Drag in empty window space with no tiled pane underneath.
|
||||
drag 40 10 50 15
|
||||
|
||||
@@ -92,6 +125,12 @@ must_equal "$($TMUX display-message -p -t "$id" '#{pane_top}')" 10
|
||||
must_equal "$($TMUX display-message -p -t "$id" '#{pane_width}')" 9
|
||||
must_equal "$($TMUX display-message -p -t "$id" '#{pane_height}')" 4
|
||||
|
||||
TILED=$($TMUX new-pane -PF '#{pane_id}' 'sleep 100') ||
|
||||
fail "new pane from only floating panes failed"
|
||||
$TMUX join-pane -t "$TILED" ||
|
||||
fail "tile new pane from only floating panes failed"
|
||||
must_equal "$($TMUX display-message -p -t "$TILED" '#{pane_floating_flag}')" 0
|
||||
|
||||
TILED=$($TMUX new-window -dPF '#{pane_id}' 'sleep 100') ||
|
||||
fail "new tiled window failed"
|
||||
$TMUX new-pane -d -M -L -t "$TILED" 'sleep 100' || fail "new-pane -M -L failed"
|
||||
|
||||
@@ -140,6 +140,24 @@ update-environment[notify] EEE"
|
||||
# sorts by ascending numeric key and keeps the gap at [1].
|
||||
check_ok set -g status-format ""
|
||||
check_array "-g status-format" "status-format"
|
||||
out=$($TMUX show -gF \
|
||||
'#{option_name}:#{option_has_value}:#{option_value}:#{option_is_array}:#{option_has_array_key}:#{option_array_key}' \
|
||||
status-format 2>&1)
|
||||
[ "$out" = "status-format:0::1:0:" ] || {
|
||||
echo "show -F empty status-format failed."
|
||||
echo "Expected: 'status-format:0::1:0:'"
|
||||
echo "But got: '$out'"
|
||||
exit 1
|
||||
}
|
||||
out=$($TMUX show -gvF \
|
||||
'#{option_name}:#{option_value_only}:#{option_has_value}:#{option_value}' \
|
||||
status-format 2>&1)
|
||||
[ "$out" = "status-format:1:0:" ] || {
|
||||
echo "show -vF empty status-format failed."
|
||||
echo "Expected: 'status-format:1:0:'"
|
||||
echo "But got: '$out'"
|
||||
exit 1
|
||||
}
|
||||
check_ok set -g status-format[5] "five"
|
||||
check_ok set -g status-format[0] "zero"
|
||||
check_ok set -g status-format[2] "two"
|
||||
@@ -154,6 +172,21 @@ status-format[5] five
|
||||
status-format[foo-bar] foo-bar
|
||||
status-format[xterm-256color] xterm
|
||||
status-format[zoom] zoom"
|
||||
out=$($TMUX show -gF \
|
||||
'#{option_name}:#{option_array_key}:#{option_is_array}:#{option_has_value}:#{option_has_array_key}:#{option_value}' \
|
||||
status-format 2>&1)
|
||||
[ "$out" = "$(printf '%s' 'status-format:0:1:1:1:zero
|
||||
status-format:1:1:1:1:one
|
||||
status-format:2:1:1:1:two
|
||||
status-format:5:1:1:1:five
|
||||
status-format:foo-bar:1:1:1:foo-bar
|
||||
status-format:xterm-256color:1:1:1:xterm
|
||||
status-format:zoom:1:1:1:zoom')" ] || {
|
||||
echo "show -F status-format failed."
|
||||
echo "Expected formatted array output"
|
||||
echo "But got:"; printf '%s\n' "$out"
|
||||
exit 1
|
||||
}
|
||||
check_value "-gv status-format[01]" "one"
|
||||
check_ok set -gu status-format[zoom]
|
||||
check_value "-gv status-format[zoom]" ""
|
||||
|
||||
@@ -168,6 +168,30 @@ check_ok set -g @str "foo"
|
||||
check_ok set -ga @str "bar"
|
||||
check_value "-gv @str" "foobar"
|
||||
|
||||
# --- show -F custom format ------------------------------------------------
|
||||
#
|
||||
# show-options and show-hooks use a format for their output, with the default
|
||||
# format preserving the traditional output.
|
||||
check_ok set -g @str "two words"
|
||||
check_value "-g @str" '@str "two words"'
|
||||
out=$($TMUX show -gF \
|
||||
'#{option_name}=#{option_value}=#{option_is_user}=#{option_is_string}=#{option_value_only}' \
|
||||
@str 2>&1)
|
||||
[ "$out" = "@str=two words=1=1=0" ] || {
|
||||
echo "show -F @str failed."
|
||||
echo "Expected: '@str=two words=1=1=0'"
|
||||
echo "But got: '$out'"
|
||||
exit 1
|
||||
}
|
||||
out=$($TMUX show -gvF '#{option_name}=#{option_value}=#{option_value_only}' \
|
||||
@str 2>&1)
|
||||
[ "$out" = "@str=two words=1" ] || {
|
||||
echo "show -vF @str failed."
|
||||
echo "Expected: '@str=two words=1'"
|
||||
echo "But got: '$out'"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# --- -F expands at set time -----------------------------------------------
|
||||
#
|
||||
# With -F the value is expanded as a format once, at set time; without -F it is
|
||||
|
||||
@@ -192,13 +192,13 @@ check_fail "invalid window name: $(printf 'a\377b')" \
|
||||
break-pane -d -n "$(printf 'a\377b')" -s "$p1" -t P:
|
||||
|
||||
# join-pane can move a pane from one window to another without destroying
|
||||
# the source window if other panes remain. (On this branch move-pane is
|
||||
# reserved for floating panes, covered by floating-pane-geometry.sh.)
|
||||
# the source window if other panes remain. move-pane does the same when no
|
||||
# floating-pane movement flags are given.
|
||||
check_ok new-window -d -t P:5 -n other
|
||||
check_ok join-pane -d -s "$p1" -t P:5.0
|
||||
check_fmt 'P:5' '#{window_panes}' '2'
|
||||
check_fmt 'P:0' '#{window_panes}' '3'
|
||||
check_ok join-pane -d -v -s "$p1" -t "$p2"
|
||||
check_ok move-pane -d -v -s "$p1" -t "$p2"
|
||||
check_fmt 'P:0' '#{window_panes}' '4'
|
||||
check_fmt 'P:5' '#{window_panes}' '1'
|
||||
|
||||
|
||||
52
regress/pipe-pane.sh
Normal file
52
regress/pipe-pane.sh
Normal file
@@ -0,0 +1,52 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Tests of pipe-pane behaviour.
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
LANG=C.UTF-8
|
||||
LC_ALL=C.UTF-8
|
||||
export TERM LANG LC_ALL
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
fail()
|
||||
{
|
||||
echo "$1"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
exit 1
|
||||
}
|
||||
|
||||
check_ok()
|
||||
{
|
||||
if ! $TMUX "$@"; then
|
||||
fail "Command failed: $*"
|
||||
fi
|
||||
}
|
||||
|
||||
check_alive()
|
||||
{
|
||||
if [ "$($TMUX display-message -p alive 2>&1)" != "alive" ]; then
|
||||
fail "Server died"
|
||||
fi
|
||||
}
|
||||
|
||||
# A pipe-pane -I child may write after the pane process has exited. With
|
||||
# remain-on-exit, the pane stays around but its bufferevent has been freed.
|
||||
check_ok new-session -d -s pipe -x 80 -y 24 'sleep 1'
|
||||
check_ok set-option -t pipe:0 remain-on-exit on
|
||||
check_ok pipe-pane -t pipe:0.0 -I 'sleep 2; printf x'
|
||||
|
||||
i=0
|
||||
while [ "$($TMUX display-message -p -t pipe:0.0 '#{pane_dead}')" != "1" ]; do
|
||||
i=$((i + 1))
|
||||
[ "$i" -gt 50 ] && fail "Pane did not die"
|
||||
sleep 0.1
|
||||
done
|
||||
|
||||
sleep 2
|
||||
check_alive
|
||||
|
||||
$TMUX kill-server 2>/dev/null
|
||||
@@ -11,7 +11,7 @@ TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
TMP=$(mktemp)
|
||||
trap "rm -f $TMP" 0 1 15
|
||||
trap "$TMUX kill-server 2>/dev/null; rm -f $TMP" 0 1 15
|
||||
|
||||
$TMUX -f/dev/null new -d "$TMUX run 'echo foo' >$TMP; sleep 10" || exit 1
|
||||
sleep 1 && [ "$(cat $TMP)" = "foo" ] || exit 1
|
||||
@@ -20,6 +20,15 @@ $TMUX -f/dev/null new -d "$TMUX run -t: 'echo foo' >$TMP; sleep 10" || exit 1
|
||||
sleep 1 && [ "$(cat $TMP)" = "" ] || exit 1
|
||||
[ "$($TMUX display -p '#{pane_mode}')" = "view-mode" ] || exit 1
|
||||
|
||||
$TMUX -f/dev/null new -d -s t1 'sleep 10' || exit 1
|
||||
$TMUX -f/dev/null run -d 1 'echo delayed' >$TMP 2>&1 &
|
||||
pid=$!
|
||||
sleep 0.2
|
||||
kill -9 "$pid" 2>/dev/null
|
||||
wait "$pid" 2>/dev/null
|
||||
sleep 2
|
||||
$TMUX has-session -t t1 || exit 1
|
||||
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
exit 0
|
||||
|
||||
63
regress/screen-redraw-fill-character.sh
Normal file
63
regress/screen-redraw-fill-character.sh
Normal file
@@ -0,0 +1,63 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Exercise fill-character as a format. The window is smaller than the attached
|
||||
# client so OUTSIDE spans exist, then the only tiled pane is removed so EMPTY
|
||||
# spans exist inside the window around a floating pane.
|
||||
|
||||
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"
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
must_equal() {
|
||||
if [ "$1" != "$2" ]; then
|
||||
fail "expected '$2', got '$1'"
|
||||
fi
|
||||
}
|
||||
|
||||
$TMUX kill-server 2>/dev/null
|
||||
$TMUX2 kill-server 2>/dev/null
|
||||
|
||||
$TMUX2 new -d -x40 -y12 "sh -c 'printf base; exec sleep 100'" || exit 1
|
||||
$TMUX2 set -g status off || exit 1
|
||||
$TMUX2 set -g window-size manual || exit 1
|
||||
$TMUX2 setw fill-character '#{?is_inside,I,#{?is_outside,O,X}}' || exit 1
|
||||
$TMUX2 resizew -x28 -y8 || exit 1
|
||||
$TMUX2 new-pane -x12 -y4 -X8 -Y2 "sh -c 'printf FLOAT; exec sleep 100'" || exit 1
|
||||
tiled=$($TMUX2 list-panes -F '#{pane_floating_flag} #{pane_id}' | \
|
||||
awk '$1==0{print $2; exit}') || exit 1
|
||||
$TMUX2 kill-pane -t "$tiled" || exit 1
|
||||
|
||||
$TMUX new -d -x40 -y12 || 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
|
||||
|
||||
$TMUX capturep -p >$TMP || exit 1
|
||||
|
||||
must_equal "$(sed -n '1p' $TMP | cut -c1-28)" \
|
||||
"IIIIIIIIIIIIIIIIIIIIIIIIIIII"
|
||||
must_equal "$(sed -n '1p' $TMP | cut -c29-40)" "OOOOOOOOOOOO"
|
||||
must_equal "$(sed -n '9p' $TMP)" "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"
|
||||
|
||||
if grep -q X "$TMP"; then
|
||||
fail "fill-character used neither inside nor outside"
|
||||
fi
|
||||
|
||||
exit 0
|
||||
@@ -125,6 +125,13 @@ new_scene 28 8
|
||||
$TMUX2 new-pane -x16 -y5 -X18 -Y4 "sh -c 'printf OUT; exec sleep 100'" || exit 1
|
||||
compare floating-outside
|
||||
|
||||
# Floating pane whose right border is exactly on the window right edge. The
|
||||
# floating pane is clipped so the tiled pane's right border remains unbroken.
|
||||
new_scene 28 8
|
||||
$TMUX2 respawnp -k "sh -c 'i=0; while [ \$i -lt 8 ]; do printf \"%02d:abcdefghijklmnopq\n\" \$i; i=\$((i + 1)); done; exec sleep 100'" || exit 1
|
||||
$TMUX2 new-pane -x10 -y5 -X19 -Y2 "sh -c 'printf EDGE; exec sleep 100'" || exit 1
|
||||
compare floating-clip-window-edge
|
||||
|
||||
# Floating pane clipped at the top-left corner (negative offsets).
|
||||
new_scene 40 12
|
||||
$TMUX2 new-pane -x18 -y6 -X-4 -Y-2 "sh -c 'printf TL; exec sleep 100'" || exit 1
|
||||
@@ -208,9 +215,9 @@ $TMUX2 new-pane -x20 -y6 -X8 -Y7 "sh -c 'printf OVERST; exec sleep 100'" || exit
|
||||
compare floating-over-status
|
||||
|
||||
# A window left with only a floating pane: killing the single tiled pane removes
|
||||
# it from the layout, so the area it occupied is no longer owned by any pane and
|
||||
# is drawn as EMPTY cells (middle dots) around the float. This is the only way to
|
||||
# produce a REDRAW_SPAN_EMPTY span.
|
||||
# it from the layout, so the area it occupied is no longer owned by any pane.
|
||||
# Use a visible fill character for the EMPTY cells around the float.
|
||||
$TMUX2 set -g fill-character '#[acs]~' || exit 1
|
||||
new_scene 40 12
|
||||
$TMUX2 new-pane -x20 -y6 -X8 -Y3 "sh -c 'printf FLOAT; exec sleep 100'" || exit 1
|
||||
tiled=$($TMUX2 list-panes -F '#{pane_floating_flag} #{pane_id}' | \
|
||||
@@ -218,4 +225,11 @@ tiled=$($TMUX2 list-panes -F '#{pane_floating_flag} #{pane_id}' | \
|
||||
$TMUX2 kill-pane -t "$tiled" || exit 1
|
||||
compare floating-empty
|
||||
|
||||
# Same after pane-border-lines is set to none: empty window background is not a
|
||||
# pane border and should still use the dotted window fill.
|
||||
new_scene 40 12
|
||||
$TMUX2 breakp -W || exit 1
|
||||
$TMUX2 set pane-border-lines none || exit 1
|
||||
compare floating-empty-noborder
|
||||
|
||||
exit 0
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
01:abcdefghijklmnopq │···········
|
||||
02:abcdefghijklmnopq │···········
|
||||
03:abcdefghijklmnop┌────────│···········
|
||||
04:abcdefghijklmnop│EDGE │···········
|
||||
05:abcdefghijklmnop│ │···········
|
||||
06:abcdefghijklmnop│ │···········
|
||||
07:abcdefghijklmnop└────────│···········
|
||||
│···········
|
||||
────────────────────────────┘···········
|
||||
········································
|
||||
········································
|
||||
········································
|
||||
12
regress/screen-redraw-results/floating-empty-noborder.result
Normal file
12
regress/screen-redraw-results/floating-empty-noborder.result
Normal file
@@ -0,0 +1,12 @@
|
||||
········································
|
||||
········································
|
||||
····base ················
|
||||
···· ················
|
||||
···· ················
|
||||
········································
|
||||
········································
|
||||
········································
|
||||
········································
|
||||
········································
|
||||
········································
|
||||
|
||||
@@ -6,7 +6,7 @@ base │···········
|
||||
│OUT │···········
|
||||
│ │···········
|
||||
│ │···········
|
||||
──────────────────└─────────┘···········
|
||||
────────────────────────────┘···········
|
||||
········································
|
||||
········································
|
||||
········································
|
||||
|
||||
49
regress/server-socket-error.sh
Executable file
49
regress/server-socket-error.sh
Executable file
@@ -0,0 +1,49 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Server socket creation failures must produce a nonzero client exit status.
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
export TERM
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
|
||||
# Root bypasses directory mode bits, so it cannot trigger this failure.
|
||||
[ "$(id -u)" -eq 0 ] && exit 0
|
||||
|
||||
TMP=$(mktemp -d) || exit 1
|
||||
SOCKET="$TMP/ro/socket"
|
||||
|
||||
cleanup()
|
||||
{
|
||||
chmod 700 "$TMP/ro" 2>/dev/null
|
||||
rm -rf "$TMP"
|
||||
}
|
||||
|
||||
fail()
|
||||
{
|
||||
echo "$1" >&2
|
||||
cleanup
|
||||
exit 1
|
||||
}
|
||||
|
||||
mkdir "$TMP/ro" || exit 1
|
||||
chmod 500 "$TMP/ro" || exit 1
|
||||
trap cleanup 0 1 15
|
||||
|
||||
check_failure()
|
||||
{
|
||||
output=$($TEST_TMUX -S "$SOCKET" -f/dev/null "$@" 2>&1)
|
||||
retval=$?
|
||||
|
||||
[ "$retval" -ne 0 ] || fail "tmux $* exited zero: $output"
|
||||
case "$output" in
|
||||
"error creating $SOCKET ("*) ;;
|
||||
*) fail "tmux $* produced unexpected error: $output" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
check_failure start-server
|
||||
check_failure new-session -d
|
||||
|
||||
exit 0
|
||||
@@ -67,10 +67,25 @@ shown=$($TMUX show-hooks -g -B @session-name) ||
|
||||
fail "show-hooks -B failed"
|
||||
[ "$shown" = '@session-name::#{session_name}' ] ||
|
||||
fail "unexpected show-hooks -B output: $shown"
|
||||
shown=$($TMUX show-hooks -g -BF \
|
||||
'#{option_name}:#{hook_monitor_target}:#{hook_monitor_format}:#{option_value}:#{option_is_hook}:#{option_is_user}' \
|
||||
@session-name) ||
|
||||
fail "show-hooks -BF failed"
|
||||
[ "$shown" = '@session-name::#{session_name}:@session-name::#{session_name}:1:1' ] ||
|
||||
fail "unexpected show-hooks -BF output: $shown"
|
||||
shown=$($TMUX show-hooks -g) ||
|
||||
fail "show-hooks -g failed"
|
||||
echo "$shown" | grep -q '^@session-name ' ||
|
||||
fail "show-hooks -g did not show monitor hook: $shown"
|
||||
assert_unchanged @seen 0
|
||||
|
||||
$TMUX rename-session two || fail "rename-session two failed"
|
||||
wait_for @seen '@session-name:two'
|
||||
shown=$($TMUX show-hooks -g -BF '#{hook_fire_count}:#{t/p:hook_fire_time}' \
|
||||
@session-name) ||
|
||||
fail "show-hooks -BF fire failed"
|
||||
echo "$shown" | grep -q '^1:[^-][^ ]*$' ||
|
||||
fail "unexpected show-hooks -BF fire output: $shown"
|
||||
|
||||
$TMUX set -g @seen-last 0 || fail "set @seen-last failed"
|
||||
$TMUX set-hook -g -B '@session-name::#{session_name}' \
|
||||
@@ -112,6 +127,11 @@ $TMUX set -g @pane-seen 0 || fail "set @pane-seen failed"
|
||||
$TMUX set-hook -g -B "@pane:%$pane_number:#{pane_width}" \
|
||||
'set -g @pane-seen "#{hook_session}:#{hook_window}:#{hook_window_index}:#{hook_pane}:#{hook_value}"' ||
|
||||
fail "set-hook -B pane selector failed"
|
||||
shown=$($TMUX show-hooks -g -BF \
|
||||
'#{option_name}:#{hook_monitor_target}:#{hook_monitor_format}' @pane) ||
|
||||
fail "show-hooks -BF pane failed"
|
||||
[ "$shown" = "@pane:%$pane_number:#{pane_width}" ] ||
|
||||
fail "unexpected show-hooks -BF pane output: $shown"
|
||||
assert_unchanged @pane-seen 0
|
||||
$TMUX set-hook -g -B "@pane:%$pane_number:#{@pane-value}" \
|
||||
'set -g @pane-seen "#{hook_session}:#{hook_window}:#{hook_window_index}:#{hook_pane}:#{hook_value}"' ||
|
||||
|
||||
136
regress/show-options-output.sh
Normal file
136
regress/show-options-output.sh
Normal file
@@ -0,0 +1,136 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Tests of the default output from show-options and show-hooks. This is
|
||||
# intended to guard the output compatibility when the implementation is changed
|
||||
# to use formats internally, so it deliberately does not use show -F.
|
||||
|
||||
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
|
||||
|
||||
check_value()
|
||||
{
|
||||
out=$($TMUX show $1 2>&1)
|
||||
if [ "$out" != "$(printf '%s' "$2")" ]; then
|
||||
echo "show $1 failed."
|
||||
echo "Expected:"; printf '%s\n' "$2"
|
||||
echo "But got:"; printf '%s\n' "$out"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
check_hooks()
|
||||
{
|
||||
out=$($TMUX show-hooks $1 2>&1)
|
||||
if [ "$out" != "$(printf '%s' "$2")" ]; then
|
||||
echo "show-hooks $1 failed."
|
||||
echo "Expected:"; printf '%s\n' "$2"
|
||||
echo "But got:"; printf '%s\n' "$out"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
check_ok()
|
||||
{
|
||||
if ! $TMUX "$@"; then
|
||||
echo "Command failed (expected success): $*"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
assert_alive()
|
||||
{
|
||||
if [ "$($TMUX display-message -p alive)" != "alive" ]; then
|
||||
echo "Server died: $1"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
$TMUX new-session -d -s main -x 80 -y 24 || exit 1
|
||||
|
||||
# Scalar options: strings are escaped, non-strings are not, and -v suppresses
|
||||
# the option name.
|
||||
check_ok set -g @words "two words"
|
||||
check_value "-g @words" '@words "two words"'
|
||||
check_value "-gv @words" 'two words'
|
||||
check_ok set -g display-time 1234
|
||||
check_value "-g display-time" 'display-time 1234'
|
||||
check_value "-gv display-time" '1234'
|
||||
|
||||
# Inherited options shown with -A are marked with an asterisk.
|
||||
check_ok set -g status-left "GLOBAL"
|
||||
check_ok set -u status-left
|
||||
out=$($TMUX show -A 2>/dev/null | grep '^status-left\*')
|
||||
if [ "$out" != "status-left* GLOBAL" ]; then
|
||||
echo "show -A did not mark inherited status-left."
|
||||
echo "But got:"; printf '%s\n' "$out"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Arrays: an empty array prints just the name unless -v is used; populated
|
||||
# arrays include every key, including key 0.
|
||||
check_ok set -g status-format ""
|
||||
check_value "-g status-format" 'status-format'
|
||||
check_value "-gv status-format" ''
|
||||
out=$($TMUX show -A 2>/dev/null | grep '^status-format\*')
|
||||
if [ "$out" != "status-format*" ]; then
|
||||
echo "show -A did not mark inherited empty status-format."
|
||||
echo "But got:"; printf '%s\n' "$out"
|
||||
exit 1
|
||||
fi
|
||||
check_value "-A status-format" 'status-format'
|
||||
check_ok set -g update-environment "AAA BBB,CCC"
|
||||
check_value "-g update-environment" 'update-environment[0] AAA
|
||||
update-environment[1] BBB
|
||||
update-environment[2] CCC'
|
||||
check_value "-gv update-environment[0]" 'AAA'
|
||||
|
||||
# Hooks use the same array output style, and monitor hooks have their own
|
||||
# default output form.
|
||||
check_ok set-hook -g window-renamed[first] "display-message renamed"
|
||||
check_hooks "-g window-renamed" 'window-renamed[first] display-message renamed'
|
||||
check_ok set-hook -g -B '@monitor:%*:#{pane_width}'
|
||||
check_hooks "-g -B @monitor" '@monitor:%*:#{pane_width}'
|
||||
check_ok set-hook -g @user-hook "display-message user"
|
||||
check_hooks "-g @user-hook" '@user-hook "display-message user"'
|
||||
out=$($TMUX show -g 2>&1)
|
||||
echo "$out" | grep -q "^@monitor ''$" && {
|
||||
echo "show -g showed monitor hook without -H."
|
||||
echo "But got:"; printf '%s\n' "$out"
|
||||
exit 1
|
||||
}
|
||||
echo "$out" | grep -q '^@user-hook "display-message user"$' && {
|
||||
echo "show -g showed user hook without -H."
|
||||
echo "But got:"; printf '%s\n' "$out"
|
||||
exit 1
|
||||
}
|
||||
out=$($TMUX show -gH 2>&1)
|
||||
echo "$out" | grep -q "^@monitor ''$" || {
|
||||
echo "show -gH did not show monitor hook."
|
||||
echo "But got:"; printf '%s\n' "$out"
|
||||
exit 1
|
||||
}
|
||||
echo "$out" | grep -q '^@user-hook "display-message user"$' || {
|
||||
echo "show -gH did not show user hook."
|
||||
echo "But got:"; printf '%s\n' "$out"
|
||||
exit 1
|
||||
}
|
||||
out=$($TMUX show-hooks -g 2>&1)
|
||||
echo "$out" | grep -q "^@monitor ''$" || {
|
||||
echo "show-hooks -g did not show monitor hook."
|
||||
echo "But got:"; printf '%s\n' "$out"
|
||||
exit 1
|
||||
}
|
||||
echo "$out" | grep -q '^@user-hook "display-message user"$' || {
|
||||
echo "show-hooks -g did not show user hook."
|
||||
echo "But got:"; printf '%s\n' "$out"
|
||||
exit 1
|
||||
}
|
||||
|
||||
assert_alive "after show-options output tests"
|
||||
|
||||
$TMUX kill-server 2>/dev/null
|
||||
exit 0
|
||||
43
regress/tab-cell-background.sh
Executable file
43
regress/tab-cell-background.sh
Executable file
@@ -0,0 +1,43 @@
|
||||
#!/bin/sh
|
||||
|
||||
# When a write breaks up a wide character or a tab, the columns it covered must
|
||||
# keep the background colour, both in the grid and on the terminal. The second
|
||||
# server is attached to the first so that what is actually sent is checked, not
|
||||
# just what tmux has stored.
|
||||
|
||||
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
|
||||
TMUX2="$TEST_TMUX -LtestB$$ -f/dev/null"
|
||||
$TMUX2 kill-server 2>/dev/null
|
||||
|
||||
TMP=$(mktemp)
|
||||
trap "rm -f $TMP" 0 1 15
|
||||
|
||||
# 1. Write inside a tab. 2. Overwrite the right half of a wide character.
|
||||
# 3. Two tabs of different colours, the first partly deleted so that padding
|
||||
# from both ends up next to each other, then written over.
|
||||
# The sleep is so that the client is attached before anything is written and
|
||||
# the changes are sent as they happen rather than as one redraw.
|
||||
$TMUX2 -f/dev/null new -d -x24 -y3 "
|
||||
sleep 2
|
||||
printf '\033[44m\033[K\t\033[4GX'
|
||||
printf '\033[2;1H\033[44m\033[K\344\270\226\033[2GX'
|
||||
printf '\033[3;1H\033[42m\033[K\t\033[43m\033[K\t\033[0m\033[4G\033[8P\rx'
|
||||
cat" || exit 1
|
||||
$TMUX2 set -g status off || exit 1
|
||||
|
||||
$TMUX -f/dev/null new -x24 -y4 -d "$TMUX2 attach" || exit 1
|
||||
sleep 4
|
||||
|
||||
$TMUX capturep -pe -S0 -E2 >$TMP || exit 1
|
||||
$TMUX kill-server 2>/dev/null
|
||||
$TMUX2 kill-server 2>/dev/null
|
||||
|
||||
printf '\033[44m X\n X\n\033[49mx\033[42m \033[43m \033[49m\n' |
|
||||
cmp - $TMP || exit 1
|
||||
|
||||
exit 0
|
||||
@@ -34,6 +34,18 @@ captureen() {
|
||||
$TMUX capturep -peNS0 -E- >$TMP || exit 1
|
||||
}
|
||||
|
||||
timed() {
|
||||
if command -v timeout >/dev/null 2>&1; then
|
||||
timeout 5 "$@"
|
||||
else
|
||||
"$@"
|
||||
fi
|
||||
}
|
||||
|
||||
capture_timed() {
|
||||
timed $TMUX capturep -pS0 -E- >$TMP || exit 1
|
||||
}
|
||||
|
||||
check_line() {
|
||||
line=$1
|
||||
want=$2
|
||||
@@ -81,6 +93,8 @@ $TMUX2 neww -d \
|
||||
"printf '\033(0x\033(B'; exec sleep 100" || exit 1
|
||||
$TMUX2 neww -d \
|
||||
"awk 'BEGIN { for (i = 0; i < 1100; i++) printf \"a\" }'; exec sleep 100" || exit 1
|
||||
$TMUX2 neww -d \
|
||||
"printf 'u\314\245\314\245\314\245\314\245\314\245\314\245\314\245\314\245\314\245\314\245\314\245\314\245\314\245\314\245\314\245\314\245'; exec sleep 100" || exit 1
|
||||
$TMUX2 selectw -t:0 || exit 1
|
||||
|
||||
$TMUX -f/dev/null new -d -x20 -y6 || exit 1
|
||||
@@ -245,4 +259,12 @@ capture
|
||||
len=$(sed -n 1p $TMP | wc -c)
|
||||
[ "$len" -ge 1100 ] || fail "long same-style line was truncated"
|
||||
|
||||
# Too many combining marks on one base character must not leave a standalone
|
||||
# width-zero cell that can make tty_draw_line loop forever on redraw.
|
||||
$TMUX resizew -x20 -y6 || exit 1
|
||||
timed $TMUX2 selectw -t:13 || fail "zero-width overflow select hung"
|
||||
sleep 1
|
||||
capture_timed
|
||||
check_grep '^u'
|
||||
|
||||
exit 0
|
||||
|
||||
Reference in New Issue
Block a user