The settle loop still had an rAF after it -- the horizontal scroll awaited a frame before point()
measured, so the highlight upgrade could detach the glyphs in that window and reproduce the same
bogus clipped-or-covered error. Nothing scrolls smoothly here (no scroll-behavior: smooth in our
CSS or Pierre's) and getBoundingClientRect forces sync layout, so the await bought nothing: drop
it and keep everything from the settle loop to measurement synchronous.
point() now re-asserts liveness and reports detachment as itself rather than as pane geometry,
which is what sent three rounds of fixes chasing viewport width. contentEl() is no longer
non-null-asserted -- the deref sat inside the JSON.stringify building the diagnostic, so a
container swap would have replaced the numbers with a TypeError -- and the never-settled error
now names the synthetic-newline endpoint case too.
The previous commit checked the glyph rects before the scrollIntoView frames, so on the common
path it passed with freshly walked nodes and the highlight upgrade then detached them during
those very frames -- every later measurement read an all-zero rect and the CI flake survived.
Move the settle loop after the scrolls, name the failure so a detached node no longer surfaces
as a bogus pane-geometry error, and re-query [data-content] per collect in case the upgrade
replaces the container rather than its rows.
A variant that retried the whole scroll-and-measure cycle was tried and reverted: it failed 2 of
8 runs and took the pair from 1.4m to 9.7m.
CI's diagnostics showed the assumption behind the earlier width fixes was wrong: the window was
1600x900 and the pane 485px, with room to spare for a 91px selection. The glyph rect was all
zeros -- the syntax-highlight upgrade replaces a row's nodes after first paint, so nodes walked a
frame earlier were already detached when measured. Re-collect and re-resolve until both endpoints
have a layout box and still belong to the pane.
A side-by-side pane stacks two sticky line-number columns, so an inset measured from the first
alone left the drag start underneath the second -- which is what CI kept hitting after the window
resize, because its display clamps the window narrower than a dev machine. Take the widest number
column in the pane's left half; an unfiltered max picks up cells scrolled far right and overshoots
instead, which broke the sibling spec when I tried it.
The clipped-endpoint error now carries pane width, inset, glyph and window geometry, so the next
narrow-display failure reports its numbers instead of needing them guessed at locally.
page.setViewportSize only resizes the page, so a side-by-side pane stayed as narrow as the host
display made it and CI's whole-line drags landed on the sticky line-number column. Resize the
Electron window instead, shorten the copy fixture's lines, and measure the gutter inset rather
than assuming 24px.
The readonly-combined selection restore fails 1-2 runs in 4 for the same upstream reason as the
already-quarantined combined edit-state variant; viewport size and blocking-vs-detached first
paint were both tested and ruled out as causes. Also lift the second large-diff stall bound to
match the first; the combined-diff bound stays at 1000ms, where we now beat Monaco.
CI runs a narrower window than a dev machine, so a side-by-side pane was too narrow to expose
both ends of a whole-line selection and the drag landed on the sticky line-number column. Pin the
viewport in both specs, scroll the target rows into view vertically, and measure the gutter inset
instead of assuming 24px.