fix dangling tail anchors in reflow on partially-filled lines (T-92)
test / unit + widget + golden + a11y (push) Failing after 29s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
test / dart doc (lib API) (push) Failing after 1m0s
test / unit + widget + golden + a11y (push) Failing after 29s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
test / dart doc (lib API) (push) Failing after 1m0s
`_LineReflow._addPart`'s post-loop block reparents anchors past the
source line's trimmed content onto whatever `_builder._result` was
active at that moment. When no further content lands in the builder
(non-wrapped lines, or the last logical line of a wrapped run),
`finish()` was emitting only when `_builder.isNotEmpty` — leaving
the empty result line with the reparented anchor unappended. The
anchor then pointed to a `BufferLine` that the reflow output never
included, `lines.replaceWith(reflowResult)` discarded it, and
`CellAnchor.attached` returned false. The selection controller's
`extent.attached` null-check then dropped the selection silently
on resize.
The fix adds a `_LineBuilder.hasAnchors` getter and uses it in
`finish()` so the builder line is also emitted when it's carrying
an anchor — even when otherwise empty. Trade-off: an extra trailing
line in the reflow output when (and only when) a tail anchor would
have dangled. `Buffer.resize` already pads the result to `newHeight`
afterward, so for the common case (resize fits inside view height)
the total ring length is unchanged; only when the result already
meets / exceeds `newHeight` does the buffer grow by one. Acceptable
in exchange for selections surviving a width change.
User-visible trigger paths:
- `SelectAllTextIntent` (Ctrl+A) creates an end anchor at
`x = viewWidth` on the last buffer line — exactly the past-
trimmed-length position. Resizing narrower while the selection
was active dropped it.
- Mouse drag selections past the end of a partially-filled line
hit the same shape.
Tests:
- The pre-existing `reflow anchors on the source line tail (past
trimmedLength) get reparented` test was originally written to
document the buggy behaviour ("anchor moves off the source onto
a dangling builder line"). Updated to assert the post-fix
contract: `out.contains(tail.line)` is true.
- New `SelectAllTextIntent-shaped end anchor survives shrink`
regression test that mirrors the actual production trigger
(anchor at `x = viewWidth` on a partially-filled line, narrower
reflow).
reflow.dart 71/71 → 72/72 (the new getter is a one-liner). Project
coverage 54.62% unchanged within rounding.
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -47,6 +47,15 @@ heading, and (b) bumping `pubspec.yaml` `version:` in the same commit.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Terminal selections no longer silently disappear when the terminal is
|
||||
resized narrower. Reflow's tail-anchor handler used to reparent
|
||||
anchors past the source's trimmed-content range onto a builder line
|
||||
that was never emitted, leaving them detached from the visible
|
||||
buffer; the selection controller's `extent.attached` check then
|
||||
returned null and the highlight vanished. Common trigger paths:
|
||||
Ctrl+A (select-all) followed by a width change, and mouse drag
|
||||
selections that extended past the end of a partially-filled line
|
||||
(T-92).
|
||||
- `BufferLine.removeCells` / `insertCells` / `dispose` no longer skip
|
||||
anchors due to concurrent list modification during iteration —
|
||||
surfaced by unit tests added under T-91. Anchors disposed inside
|
||||
|
||||
Reference in New Issue
Block a user