P0 RESIZE VIDEOS A3b: a divider drag keeps terminal text in place and reflows once when it lands

LA
4d ago
+151-6

Summary

During a divider drag, each terminal's text wrapped again on every frame (RESIZE VIDEOS A3b). The end-result film of the fast column drag on a feat build with #31613 (build 0269a3a2, feat 158013731a1) shows the left column's wrap point moving in every frame of the drag. The judge counts 34 and 35 text layouts in 35 motion frames in each of 2 rounds; evidence is in handoff/resize-videos/fixes/. #31613 made the drag resize each PTY once, so a program no longer redraws at each size. But the surface still took the pane's size on every drag event and drew its grid reflowed to it (Ghostty's reflow preview).

Fix: on the drag's first move the terminal keeps its surface size in its host (TerminalHostView.holdSurface, the hold a split's spring already uses). The surface is clipped where the pane is narrower and has the terminal background beside it where the pane is wider, the way a Chromium page keeps its size through a drag. A release that springs moves the hold to its final size at the spring's start and lets it go when it lands. A release that does not spring lets it go when the drag ends. The terminal reflows once. A terminal that leaves its window mid-drag lets the hold go.

Setting (lead 06:5xZ): Debug Settings → Terminal Drag → "Hold terminal text during a divider drag" (TerminalDragTunables.holdsSurfaceDuringDrag), on by default. Turning it off brings back live reflow on every drag frame; the PTY still resizes only once. Release and RC keep the default.

Testing

GUI proof at head 4e0c17efeef4da8cf79713375962c18d1a5b57f1: gui-session-v1 job 037bcda0f8957a02f7080d94 PASSED

Red/green on the fleet, DividerDragTerminalSteadyTests (new; two real terminal sessions behind the app's ResizeCoordinator; a 30-event divider drag): p1's surface keeps one width through the whole drag although its pane narrows by more than 100 pt. After the landing the surface fits its pane again, narrower.

  • Red at 805fa37c2108 (test only, base): step fc7945b36aa369424c357305 failed as expected. p1's surface took about 30 widths during the drag (448, 488, 384, 440, ...).
  • Green at 4e0c17efeef4 (display worker cmux14, gui-session-v1, 1 screen): step 037bcda0f8957a02f7080d94 passed. 5 suites: DividerDragTerminalSteadyTests (2 tests), DividerDragTerminalResizeCountTests, SplitTerminalResizeCountTests, PaneResizeGestureTests, TerminalPaneMotionFinalGridTests.
  • Red at 28ff7f611802 (swap test only, on the hold): step c31000ecdebe201217c1bc93 failed as expected. A surface installed mid-drag kept the held width: DividerDragTerminalSteadyTests.swift:89: Expectation failed: (fresh.frame.width → 600.0) < (before.width - 100 → 500.0) and :96: abs(fresh.frame.width - host.bounds.width) → 160.0 < 40.
  • Compile: cmux-ci compile-check f1fc92e7f23792b48709a878 (app + CmuxNext, recipe 2) passed.

Observed / Not run

Observed:

  • The steps above.

  • scripts/cmux-next/prepush-gate.py reported no new violations.

  • The before film: 5 rounds of video-col-drag on build 0269a3a2, at 120 Hz with the shared kit.

  • The after film: 5 rounds of video-col-drag on recording build f28cbb298a253b93bcfa188f (8a804e1f431, the hold and its setting, plus the bench configuration), 120 Hz 1x, cmux23 and cmux24. In 5 of 5 rounds the left column keeps its wrap in each drag frame and reflows one time in the landing frame. The judge's "content stretched" defect (before: 24 frames) is not found. Pacing p50/p95/max 8.33 ms, 0 dropped.

Not run:

  • A film at this head. The two commits after 8a804e1f431 only let the hold go when a surface leaves its host mid-drag (a swap or a window close); the filmed drag does neither.
  • The judge's "text layouts" count stays 12-35 per pane with the hold, because the moving clip edge changes pixels each frame. The eye check of the wrap column is the proof.
  • Not fixed here, found before and after: the judge's "shown geometry not in the model", "half-pixel blend" and a -81 px "jump" at the drag start.

Changelog

Changed: Terminal text stays in place while you drag a pane divider and reflows once when you let go

Proof

No capture: the proof is the 120 Hz real-app film, not a still. Before: handoff/resize-videos/fixes/feat-1580137-fix31613-r1/col-drag-fast.mov and a3-col-drag-fast-r1-left-column-frames158-196-every3.png. After: handoff/resize-videos/fixes/feat-steady-8a804e1-after-r{1..5}/col-drag-fast.mov and a3b-AFTER-col-drag-fast-r{1..5}-left-column-*.png.


Summary by cubic

Keeps terminal text in place during a divider drag. Previously each terminal reflowed its text to the pane on every drag frame; now it holds its surface size—clipped where the pane narrows, padded by terminal background where wider—and reflows once when the drag lands.

  • Adds a Debug Settings toggle (TerminalDragTunables.holdsSurfaceDuringDrag, under Terminal Drag) to restore per-frame reflow; on by default.
  • Releases the hold when a surface leaves its host mid-drag, so a surface swapped in during a drag takes its pane's size instead of the drag start's.