diff --git a/regress/control-notify-events.sh b/regress/control-notify-events.sh new file mode 100644 index 000000000..ab696f5e8 --- /dev/null +++ b/regress/control-notify-events.sh @@ -0,0 +1,102 @@ +#!/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" +PID= + +cleanup() +{ + [ -n "$PID" ] && kill "$PID" 2>/dev/null + $TMUX kill-server 2>/dev/null + rm -rf "$TMPDIR" +} +trap cleanup EXIT + +wait_for() +{ + pattern=$1 + timeout=${2:-6} + i=0 + + while [ "$i" -lt "$timeout" ]; do + if grep -F -- "$pattern" "$OUT" >/dev/null 2>&1; then + return 0 + fi + sleep 1 + i=$((i + 1)) + done + echo "missing: $pattern" + cat "$OUT" + return 1 +} + +wait_for_count() +{ + pattern=$1 + expected=$2 + timeout=${3:-6} + i=0 + + while [ "$i" -lt "$timeout" ]; do + count=$(grep -F -- "$pattern" "$OUT" 2>/dev/null | wc -l) + if [ "$count" -ge "$expected" ]; then + return 0 + fi + sleep 1 + i=$((i + 1)) + done + echo "missing count $expected for: $pattern" + cat "$OUT" + return 1 +} + +send() +{ + printf '%s\n' "$*" >&3 +} + +$TMUX kill-server 2>/dev/null +$TMUX new-session -d -s notify -x 80 -y 24 || exit 1 +wid=$($TMUX display-message -p -t notify:0 '#{window_id}') || exit 1 +pane=$($TMUX display-message -p -t notify:0.0 '#{pane_id}') || exit 1 + +mkfifo "$IN" +: >"$OUT" +$TMUX -C attach-session -t notify <"$IN" >"$OUT" 2>&1 & +PID=$! +exec 3>"$IN" + +send 'display-message -p ready' +wait_for 'ready' 3 || exit 1 + +send 'rename-window notify-renamed' +wait_for "%window-renamed $wid notify-renamed" || exit 1 + +send 'split-window -h' +wait_for "%layout-change $wid " || exit 1 + +send 'select-pane -t:.0' +wait_for "%window-pane-changed $wid $pane" || exit 1 + +send 'copy-mode -t:.0' +wait_for "%pane-mode-changed $pane" || exit 1 + +sessions_changed=$(grep -F -- '%sessions-changed' "$OUT" 2>/dev/null | \ + wc -l) +send 'new-session -d -s notify-extra' +wait_for_count '%sessions-changed' $((sessions_changed + 1)) || exit 1 + +send 'kill-session -t notify-extra' +wait_for_count '%sessions-changed' $((sessions_changed + 2)) || exit 1 + +exit 0 diff --git a/regress/hooks-notify.sh b/regress/hooks-notify.sh index 41916248c..37d1cd651 100644 --- a/regress/hooks-notify.sh +++ b/regress/hooks-notify.sh @@ -181,6 +181,99 @@ $TMUX set-hook -gu pane-title-changed || fail "unset pane-title-changed failed" $TMUX killp -t "$pane" || fail "kill-pane title failed" +# pane-created payload from a command pane, an empty pane, and a respawn. +$TMUX set -g @pc 0 || fail "set @pc failed" +$TMUX set-hook -g pane-created \ + 'set -gF @pc "#{hook}:#{hook_pane}:#{hook_pane_command}:#{hook_created_empty}:#{hook_created_respawn}"' || + fail "set-hook pane-created failed" +pane=$($TMUX splitw -d -t main:0 -P -F '#{pane_id}' 'sleep 30') || + fail "split-window pane-created command failed" +wait_for @pc "pane-created:$pane:\"sleep 30\":0:0" +$TMUX killp -t "$pane" || fail "kill-pane pane-created command failed" + +$TMUX set -g @pc 0 || fail "reset @pc failed" +empty_command=$($TMUX show -gqv default-shell) || + fail "show default-shell failed" +pane=$($TMUX splitw -d -E -t main:0 -P -F '#{pane_id}') || + fail "split-window pane-created empty failed" +wait_for @pc "pane-created:$pane:$empty_command:1:0" + +$TMUX set -g @pc 0 || fail "reset @pc respawn failed" +$TMUX respawnp -k -t "$pane" 'sleep 30' || fail "respawn-pane failed" +wait_for @pc "pane-created:$pane:\"sleep 30\":0:1" +$TMUX killp -t "$pane" || fail "kill-pane pane-created respawn failed" +$TMUX set-hook -gu pane-created || fail "unset pane-created failed" + +# pane-resized carries old and new dimensions. +pane=$($TMUX splitw -d -t main:0 -P -F '#{pane_id}' 'sleep 30') || + fail "split-window pane-resized failed" +old_size=$($TMUX display -pt "$pane" '#{pane_width},#{pane_height}') || + fail "display old pane size failed" +$TMUX set -g @pr 0 || fail "set @pr failed" +$TMUX set-hook -g pane-resized \ + 'set -gF @pr "#{hook}:#{hook_pane}:#{hook_old_width},#{hook_old_height}->#{hook_width},#{hook_height}"' || + fail "set-hook pane-resized failed" +$TMUX resizep -t "$pane" -x 20 -y 10 || fail "resize-pane failed" +new_size=$($TMUX display -pt "$pane" '#{pane_width},#{pane_height}') || + fail "display new pane size failed" +wait_for @pr "pane-resized:$pane:$old_size->$new_size" +$TMUX set-hook -gu pane-resized || fail "unset pane-resized failed" +$TMUX killp -t "$pane" || fail "kill-pane pane-resized failed" + +# pane-mode-entered and pane-mode-exited expose split transition payloads. +$TMUX set -g @me 0 || fail "set @me failed" +$TMUX set -g @mx 0 || fail "set @mx failed" +pane=$($TMUX splitw -d -t main:0 -P -F '#{pane_id}' 'sleep 30') || + fail "split-window pane-mode failed" +$TMUX set-hook -g pane-mode-entered \ + 'set -gF @me "#{hook}:#{hook_pane}:#{hook_mode_entered}:#{hook_current_mode}:#{hook_previous_mode}"' || + fail "set-hook pane-mode-entered failed" +$TMUX set-hook -g pane-mode-exited \ + 'set -gF @mx "#{hook}:#{hook_pane}:#{hook_mode_entered}:#{hook_current_mode}:#{hook_previous_mode}"' || + fail "set-hook pane-mode-exited failed" +$TMUX copy-mode -t "$pane" || fail "copy-mode split event failed" +wait_for @me "pane-mode-entered:$pane:1:copy-mode:" +$TMUX send-keys -t "$pane" -X cancel || fail "cancel split mode failed" +wait_for @mx "pane-mode-exited:$pane:0::copy-mode" +$TMUX set-hook -gu pane-mode-entered || fail "unset pane-mode-entered failed" +$TMUX set-hook -gu pane-mode-exited || fail "unset pane-mode-exited failed" +$TMUX killp -t "$pane" || fail "kill-pane pane-mode failed" + +# marked-pane-changed carries the new/old marked pane and marked flag. +$TMUX set -g @mk 0 || fail "set @mk failed" +pane=$($TMUX splitw -d -t main:0 -P -F '#{pane_id}' 'sleep 30') || + fail "split-window marked-pane failed" +$TMUX set-hook -g marked-pane-changed \ + 'set -gF @mk "#{hook}:#{hook_marked}:#{hook_pane}:#{hook_new_pane}:#{hook_old_pane}"' || + fail "set-hook marked-pane-changed failed" +$TMUX selectp -t "$pane" -m || fail "mark pane failed" +wait_for @mk "marked-pane-changed:1:$pane:$pane:" +$TMUX selectp -t "$pane" -m || fail "unmark pane failed" +wait_for @mk "marked-pane-changed:0:$pane::$pane" +$TMUX set-hook -gu marked-pane-changed || + fail "unset marked-pane-changed failed" +$TMUX killp -t "$pane" || fail "kill-pane marked-pane failed" + +# window-zoomed and window-unzoomed fire on resize-pane -Z. +$TMUX set -g @zoom 0 || fail "set @zoom failed" +pane=$($TMUX splitw -d -t main:0 -P -F '#{pane_id}' 'sleep 30') || + fail "split-window zoom failed" +window=$($TMUX display -pt "$pane" '#{window_id}') || + fail "display zoom window failed" +$TMUX set-hook -g window-zoomed \ + 'set -gF @zoom "#{hook}:#{hook_window}"' || + fail "set-hook window-zoomed failed" +$TMUX set-hook -g window-unzoomed \ + 'set -gF @zoom "#{hook}:#{hook_window}"' || + fail "set-hook window-unzoomed failed" +$TMUX resizep -Z -t "$pane" || fail "zoom pane failed" +wait_for @zoom "window-zoomed:$window" +$TMUX resizep -Z -t "$pane" || fail "unzoom pane failed" +wait_for @zoom "window-unzoomed:$window" +$TMUX set-hook -gu window-zoomed || fail "unset window-zoomed failed" +$TMUX set-hook -gu window-unzoomed || fail "unset window-unzoomed failed" +$TMUX killp -t "$pane" || fail "kill-pane zoom failed" + # client-attached and client-detached using a control client. $TMUX set -g @a 0 || fail "set @a failed" $TMUX set-hook -g client-attached 'set -gF @a "#{hook}"' || diff --git a/regress/options-array.sh b/regress/options-array.sh index d9751c94c..fbaff6ae2 100644 --- a/regress/options-array.sh +++ b/regress/options-array.sh @@ -36,6 +36,21 @@ check_value() fi } +check_wait_value() +{ + i=0 + while [ "$i" -lt 30 ]; do + out=$($TMUX show $1 2>&1) + [ "$out" = "$2" ] && return 0 + i=$((i + 1)) + sleep 0.2 + done + echo "show $1 failed." + echo "Expected: '$2'" + echo "But got: '$out'" + exit 1 +} + # check_array $args $expected # # Compare the full (multi-line) show output for an array option with a @@ -162,6 +177,39 @@ check_ok set-hook -g window-renamed[notify] "display-message renamed" check_value "-gv window-renamed[notify]" "display-message renamed" check_ok set-hook -gu window-renamed[notify] check_value "-gv window-renamed[notify]" "" +check_ok set -g @hook_first 0 +check_ok set -g @hook_second 0 +check_ok set-hook -g window-renamed[first] "set -g @hook_first 1" +check_ok set-hook -g window-renamed[second] "set -g @hook_second 1" +shown=$($TMUX show-hooks -g window-renamed) || { + echo "show-hooks -g window-renamed failed" + exit 1 +} +echo "$shown" | grep -q '^window-renamed\[first\]' || { + echo "missing first hook key: $shown" + exit 1 +} +echo "$shown" | grep -q '^window-renamed\[second\]' || { + echo "missing second hook key: $shown" + exit 1 +} +check_ok rename-window -t main:0 array-hooks +check_wait_value "-gqv @hook_first" "1" +check_wait_value "-gqv @hook_second" "1" +check_ok set-hook -gu window-renamed[first] +shown=$($TMUX show-hooks -g window-renamed) || { + echo "show-hooks -g window-renamed after unset failed" + exit 1 +} +echo "$shown" | grep -q '^window-renamed\[first\]' && { + echo "first hook key was not unset: $shown" + exit 1 +} +echo "$shown" | grep -q '^window-renamed\[second\]' || { + echo "second hook key did not remain: $shown" + exit 1 +} +check_ok set-hook -gu window-renamed[second] # --- colour-type array ---------------------------------------------------- # diff --git a/regress/prompt-mechanics.sh b/regress/prompt-mechanics.sh index 55bd17a69..9e57d7a55 100644 --- a/regress/prompt-mechanics.sh +++ b/regress/prompt-mechanics.sh @@ -49,6 +49,19 @@ status_line() { got() { $IN show -gv @r } +wait_opt() { + option=$1 + expected=$2 + i=0 + + while [ $i -lt 30 ]; do + value=$($IN show -gqv "$option" 2>/dev/null || true) + [ "$value" = "$expected" ] && return 0 + i=$((i + 1)) + sleep 0.2 + done + fail "expected $option to be '$expected' but got '$value'" +} reset() { $IN set -g @r "SENTINEL" || exit 1 } @@ -85,6 +98,12 @@ $IN bind -n M-j command-prompt -P -I hello -p '(pre)' "set -g @r '%%'" || e $IN bind -n M-m command-prompt -p 'first,second' "set -g @r '%1/%2'" || exit 1 $IN bind -n M-c command-prompt -p '(cmd)' "set -g @r '%%'" || exit 1 $IN bind -n M-h command-prompt -T search -p '(srch)' "set -g @r '%%'" || exit 1 +$IN set-hook -g pane-prompt-opened \ + 'set -gF @prompt_open "#{hook}:#{hook_pane}:#{hook_prompt_type}"' || + exit 1 +$IN set-hook -g pane-prompt-closed \ + 'set -gF @prompt_close "#{hook}:#{hook_pane}:#{hook_prompt_type}"' || + exit 1 # --- Outer session: attach the inner one inside its pane. ------------------- $OUT new -d -x80 -y24 || exit 1 @@ -111,14 +130,17 @@ settle # --- 1b. window.c: drawn over the pane, not on the status line. --- reset +pane=$($IN display-message -p '#{pane_id}') || exit 1 $OUT send-keys M-p || exit 1 settle +wait_opt @prompt_open "pane-prompt-opened:$pane:command" capture | grep -qF '(pane)' || fail "pane prompt not drawn in the pane" status_line | grep -qF '(pane)' && \ fail "pane prompt drawn on the status line, not over the pane" $OUT send-keys -l "deep" || exit 1 $OUT send-keys Enter || exit 1 settle +wait_opt @prompt_close "pane-prompt-closed:$pane:command" [ "$(got)" = "deep" ] || fail "pane prompt accept recovered '$(got)', wanted 'deep'" # --- 1c. mode-tree.c: search prompt drawn in the pane. --- diff --git a/regress/wait-for-E.sh b/regress/wait-for-E.sh index 5080587fe..f58437a34 100644 --- a/regress/wait-for-E.sh +++ b/regress/wait-for-E.sh @@ -187,4 +187,20 @@ $TMUX rename-window -t wf2:0 renamed-again || fail "rename-window renamed-again failed" wait_channel wf-hook-renamed +$TMUX set -g @builtin_filtered 0 || fail "set @builtin_filtered failed" +target=$($TMUX splitw -d -t wf2:0 -P -F '#{pane_id}' 'sleep 30') || + fail "split-window target failed" +$TMUX wait-for -E -F "#{==:#{pane},$target}" pane-exited \; \ + set -g @builtin_filtered 1 \; wait-for -S wf-builtin-filtered & +builtin_filtered_pid=$! +assert_unchanged @builtin_filtered 0 5 + +$TMUX splitw -d -t wf2:0 'true' || fail "split-window nonmatching failed" +assert_unchanged @builtin_filtered 0 5 + +$TMUX send-keys -t "$target" C-c || fail "send C-c to target failed" +wait_channel wf-builtin-filtered +wait "$builtin_filtered_pid" || + fail "filtered wait-for -E pane-exited command failed" + exit 0