Skip to content

text: remeasure list items when a document is replaced with an equal block count - #2946

Merged
huacnlee merged 2 commits into
longbridge:mainfrom
kossoy:fix/remeasure-on-document-replace
Sep 4, 2026
Merged

text: remeasure list items when a document is replaced with an equal block count#2946
huacnlee merged 2 commits into
longbridge:mainfrom
kossoy:fix/remeasure-on-document-replace

Conversation

@kossoy

@kossoy kossoy commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Document::render_root only calls ListState::reset when the block count
changes. The full-measure pass enabled by measure_all is a one-shot latch that
only reset, remeasure_items, or a width change re-arms. So replacing a
document with one that happens to have the same number of blocks leaves every
cached height belonging to the previous document.

The list summary height stays wrong, and since the wheel clamps against that
summary, the blocks past the false bottom can never scroll into view to be
re-measured. The clamp seals itself.

Reproduction (deterministic)

  1. Open a document with 96 short blocks (e.g. 96 one-line paragraphs).
    max_off ≈ 3 024 px.
  2. Replace it with a document that also has 96 blocks but is 132 KB long.
  3. max_off is now ≈ 3 503 px instead of the true ≈ 21 314 px. Wheel-scrolling
    stops at 16 % of the document. Resizing the window "fixes" it, because a
    width change re-arms the latch — which is why this is hard to notice
    interactively.

Fix

Call remeasure_items(0..count) at the two places parsed_content is replaced
(sync and async full-parse paths). remeasure_items re-arms the latch and marks
items unmeasured while keeping the old sizes as hints, so the scrollbar does not
collapse for a frame.

Placement matters: hooking increment_update instead races on the async path —
a prepaint can land between the invalidation and the arrival of the new blocks
and re-latch against the old content. Both hooks sit at the exact instant
parsed_content is replaced; the async one is gated on full_parse so streaming
appends are unaffected.

Verified: the same repro after the fix ends at max_off = 21 314, the true
height, and a 500-tick wheel sweep reaches the final block. No gpui core change;
crates/base/src/text/state.rs only, +25 lines.

kossoy and others added 2 commits September 4, 2026 09:50
Drive a real frame in a windowed test so the list actually measures,
then replace the document with one of the same block count and assert
the scroll extent grows to match the taller content.

Verified by disabling both `invalidate_measured_heights` call sites:
the extent reports 1546px instead of 18888px -- about 8% of the true
height, which is what seals the wheel clamp.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DJzGY5rMeCxE2r5L6MFzAS
@huacnlee
huacnlee enabled auto-merge (squash) September 4, 2026 11:46
@huacnlee
huacnlee merged commit 65db562 into longbridge:main Sep 4, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants