c0471242
test: the pager leg reads its own anchor and asserts exactly 24 rows on both OSes
a73x 2026-09-04 10:16
Commit message
test/e2e_08_mouse.sh
| Old | New | ||
|---|---|---|---|
| @@ -199,21 +199,29 @@ ok "an application that asked for the mouse gets the wheel, and the client does | |||
| 199 | # consumed by the mouse filter and then dropped. Measured on this very | 199 | # consumed by the mouse filter and then dropped. Measured on this very |
| 200 | # scenario before the fix: four notches, grid unmoved. | 200 | # scenario before the fix: four notches, grid unmoved. |
| 201 | # | 201 | # |
| 202 | # `less +178g` on 200 lines: line 178 is put at the TOP of the screen, so a | 202 | # `less +G` on 200 lines: the view starts at the END, so a wheel-UP is the |
| 203 | # wheel-UP has 177 rows to go and the leg knows where it started. Eight | 203 | # direction with somewhere to go. Eight notches at less's default of three |
| 204 | # notches at less's default of three rows a notch is 24 rows, one | 204 | # rows a notch is 24 rows, one screenful, so the top row moves back by 24 |
| 205 | # screenful, so the top moves to 154 and 178 leaves the screen entirely — | 205 | # and the row that was at the top leaves the screen entirely — a needle and |
| 206 | # a needle and its negative. | 206 | # its negative. |
| 207 | # | 207 | # |
| 208 | # The `178g` is typed INTO the pager after the attach, and it is what makes | 208 | # The top row is READ off the grid rather than written down here, and the |
| 209 | # 178 a fact rather than a hope. Attaching makes less repaint, and the | 209 | # read is taken between two attaches so that nothing is racing it. Where a |
| 210 | # repaint does not always land where the flag put it: measured on this | 210 | # pager parks the end of a file is the pager's business and the builds |
| 211 | # scenario, less 704 (Debian) held the top at 178 while less 668 (macOS 26) | 211 | # disagree: attaching makes less repaint, and how many of the 24 rows the |
| 212 | # moved it to 179, so a leg that read the top before the attach, or wrote | 212 | # build spends on its own status line decides where the repainted view |
| 213 | # it down, was off by one row on the Mac while the wheel worked perfectly. | 213 | # starts. less 704 leaves the top at 178 and less 668, the one macOS 26 |
| 214 | # Re-anchoring after the repaint leaves nothing for a build to differ | 214 | # ships, at 179 — measured on this scenario, three runs each. So a leg that |
| 215 | # about. The `+178g` flag is still there so the wait loop below has a page | 215 | # spelled 154 failed on the Mac by one row while the wheel worked |
| 216 | # to look for. | 216 | # perfectly, and one that accepted 154 OR 155 stopped being able to fail on |
| 217 | # a wheel that moved 23 rows, which is what a lost keystroke looks like. | ||
| 218 | # | ||
| 219 | # The short attach below is what makes 24 an exact number on both. It | ||
| 220 | # attaches, waits for the paint, and detaches, which leaves the daemon's | ||
| 221 | # grid holding the REPAINTED view; the dump after it is therefore the same | ||
| 222 | # top row the wheel is about to move, read while no client is attached and | ||
| 223 | # nothing can change it. A second attach at the same size repaints to the | ||
| 224 | # same place, measured three times on each OS. | ||
| 217 | # | 225 | # |
| 218 | # LESS is cleared in the script rather than trusted: an operator with | 226 | # LESS is cleared in the script rather than trusted: an operator with |
| 219 | # `LESS=--mouse` exported would have a pager that DOES ask for the mouse, | 227 | # `LESS=--mouse` exported would have a pager that DOES ask for the mouse, |
| @@ -224,7 +232,7 @@ cat > "$LESSSH" <<EOF | |||
| 224 | #!/bin/sh | 232 | #!/bin/sh |
| 225 | LESS= | 233 | LESS= |
| 226 | export LESS | 234 | export LESS |
| 227 | exec less +178g $LESSDATA | 235 | exec less +G $LESSDATA |
| 228 | EOF | 236 | EOF |
| 229 | chmod +x "$LESSSH" | 237 | chmod +x "$LESSSH" |
| 230 | start_daemon "$SOCK35" "$OUT.pgr.d" "pager daemon never bound" --shell "$LESSSH" | 238 | start_daemon "$SOCK35" "$OUT.pgr.d" "pager daemon never bound" --shell "$LESSSH" |
| @@ -233,8 +241,8 @@ D32PID=$DPID | |||
| 233 | # of the file's lines, so a half-painted `19` does not pass) and the dump | 241 | # of the file's lines, so a half-painted `19` does not pass) and the dump |
| 234 | # is trimmed to the last rows, because a pager's whole grid is 24 rows of | 242 | # is trimmed to the last rows, because a pager's whole grid is 24 rows of |
| 235 | # numbers that say nothing about why it stopped short. 190 rather than the | 243 | # numbers that say nothing about why it stopped short. 190 rather than the |
| 236 | # top row 178: it is well inside the page either build draws, so the needle | 244 | # file's last line: it is well inside the page either build draws, so the |
| 237 | # does not depend on the height question the comment above settles. | 245 | # needle does not depend on the height question the comment above settles. |
| 238 | i=0 | 246 | i=0 |
| 239 | until "$MUX" d dump --sock "$SOCK35" | grep -qx "190"; do | 247 | until "$MUX" d dump --sock "$SOCK35" | grep -qx "190"; do |
| 240 | i=$((i+1)); [ "$i" -lt $(( 100 * TIME_SCALE )) ] || { | 248 | i=$((i+1)); [ "$i" -lt $(( 100 * TIME_SCALE )) ] || { |
| @@ -242,14 +250,38 @@ until "$MUX" d dump --sock "$SOCK35" | grep -qx "190"; do | |||
| 242 | "$MUX" d dump --sock "$SOCK35" | tail -3; exit 1; } | 250 | "$MUX" d dump --sock "$SOCK35" | tail -3; exit 1; } |
| 243 | sleep 0.1 | 251 | sleep 0.1 |
| 244 | done | 252 | done |
| 253 | # The anchoring attach. Same size as the one that follows it, because the | ||
| 254 | # thing being fixed is where a repaint at THIS size lands. | ||
| 245 | set +e | 255 | set +e |
| 246 | hostroom pager | 256 | hostroom pager |
| 257 | XDG_STATE_HOME="$HOSTROOM" timeout 40 "$PTYCLIENT" --cols 80 --rows 24 \ | ||
| 258 | --out "$OUT.pgranchor" --err "$OUT.pgranchor.err" \ | ||
| 259 | -- "$MUX" --sock "$SOCK35" > "$OUT.pgranchor.log" 2>&1 <<'EOF' | ||
| 260 | expect 199 15000 | ||
| 261 | settle 800 15000 | ||
| 262 | send \x1cd | ||
| 263 | waitexit 10000 | ||
| 264 | EOF | ||
| 265 | RC=$? | ||
| 266 | set -e | ||
| 267 | rc0 "pager: the anchoring attach exited $RC:" "$OUT.pgranchor.log" | ||
| 268 | PGRTOP=$("$MUX" d dump --sock "$SOCK35" | sed -n '1p') | ||
| 269 | # Refused rather than trusted: an anchor that is not a line number, or one | ||
| 270 | # with no room for a screenful above it, would make the arithmetic below | ||
| 271 | # assert nothing. Both would mean the pager is not where this leg thinks. | ||
| 272 | case "$PGRTOP" in | ||
| 273 | ''|*[!0-9]*) | ||
| 274 | echo "e2e FAIL: pager: the top row after the anchoring attach is not a line number: '$PGRTOP'" | ||
| 275 | "$MUX" d dump --sock "$SOCK35" | head -3; exit 1 ;; | ||
| 276 | esac | ||
| 277 | [ "$PGRTOP" -gt 24 ] || { | ||
| 278 | echo "e2e FAIL: pager: top row $PGRTOP leaves no room for a screenful of wheel" | ||
| 279 | "$MUX" d dump --sock "$SOCK35" | head -3; exit 1; } | ||
| 280 | |||
| 281 | set +e | ||
| 247 | XDG_STATE_HOME="$HOSTROOM" timeout 40 "$PTYCLIENT" --cols 80 --rows 24 --out "$OUT.pgr" --err "$OUT.pgr.err" \ | 282 | XDG_STATE_HOME="$HOSTROOM" timeout 40 "$PTYCLIENT" --cols 80 --rows 24 --out "$OUT.pgr" --err "$OUT.pgr.err" \ |
| 248 | -- "$MUX" --sock "$SOCK35" > "$OUT.pgr.log" 2>&1 <<'EOF' | 283 | -- "$MUX" --sock "$SOCK35" > "$OUT.pgr.log" 2>&1 <<'EOF' |
| 249 | expect 199 15000 | 284 | expect 199 15000 |
| 250 | settle 400 15000 | ||
| 251 | send 178g | ||
| 252 | settle 600 15000 | ||
| 253 | send \x1b[<64;10;5M\x1b[<64;10;5M\x1b[<64;10;5M\x1b[<64;10;5M\x1b[<64;10;5M\x1b[<64;10;5M\x1b[<64;10;5M\x1b[<64;10;5M | 285 | send \x1b[<64;10;5M\x1b[<64;10;5M\x1b[<64;10;5M\x1b[<64;10;5M\x1b[<64;10;5M\x1b[<64;10;5M\x1b[<64;10;5M\x1b[<64;10;5M |
| 254 | settle 800 15000 | 286 | settle 800 15000 |
| 255 | send \x1cd | 287 | send \x1cd |
| @@ -266,12 +298,12 @@ rc0 "pager: ptyclient leg exited $RC:" "$OUT.pgr.log" | |||
| 266 | "$MUX" d dump --sock "$SOCK35" > "$OUT.pgrcap" 2>&1 | 298 | "$MUX" d dump --sock "$SOCK35" > "$OUT.pgrcap" 2>&1 |
| 267 | # A whole line, because the pager's status line carries the file's PATH — | 299 | # A whole line, because the pager's status line carries the file's PATH — |
| 268 | # which holds this run's pid and could spell any short number. | 300 | # which holds this run's pid and could spell any short number. |
| 269 | grep -qx "154" "$OUT.pgrcap" || { | 301 | grep -qx "$(( PGRTOP - 24 ))" "$OUT.pgrcap" || { |
| 270 | echo "e2e FAIL: pager: the wheel did not move the alternate screen back a screenful" | 302 | echo "e2e FAIL: pager: the wheel did not move the alternate screen back 24 rows" |
| 271 | echo " (top was 178, so row 154 should be on screen):" | 303 | echo " (the top was $PGRTOP, so row $(( PGRTOP - 24 )) should be on screen):" |
| 272 | cat "$OUT.pgrcap"; exit 1; } | 304 | cat "$OUT.pgrcap"; exit 1; } |
| 273 | grep -qx "178" "$OUT.pgrcap" && { | 305 | grep -qx "$PGRTOP" "$OUT.pgrcap" && { |
| 274 | echo "e2e FAIL: pager: the old top row is still on screen, so the view did not move a screenful:" | 306 | echo "e2e FAIL: pager: the old top row $PGRTOP is still on screen, so the view did not move a screenful:" |
| 275 | cat "$OUT.pgrcap"; exit 1; } | 307 | cat "$OUT.pgrcap"; exit 1; } |
| 276 | # The pager never asked for the mouse, so it must never have SEEN a mouse | 308 | # The pager never asked for the mouse, so it must never have SEEN a mouse |
| 277 | # report: what reached it was arrow keys, which leave no text behind. | 309 | # report: what reached it was arrow keys, which leave no text behind. |