Make TextArea measurement side-effect free. [fork-internal review]#1
Conversation
DRAFT — NOT FOR DIRECT SUBMISSION
Suggested titleMake Draft body (raw material — rewrite before any upstream use)
This implements the TODO. The new test ( Notes:
The hack dates from the new layout system (linebender#1560). Factual development notes for Lane's disclosure paragraphHow this change was developed, for the up-front LLM disclosure the policy
|
Pure refactor: `TextLayout` and the caching logic introduced for `Label` move verbatim to a new crate-private `widgets::text_layout_cache` module, parameterized on the text and styles instead of reading `Label`'s fields. This makes the cache usable by `TextArea` measurement in the next commit. No behavior change; `Label`'s render snapshot tests are unchanged.
Previously `TextArea::measure` did its layout work through the live `PlainEditor`, temporarily changing its width and then changing it back, relayouting twice in the process. Beyond the wasted work, the restore isn't faithful: every relayout nudges the editor's generation and refreshes the selection against the transient layout, so a speculative measure invalidates editor state that `measure` must leave untouched. Instead, measure through a `TextLayoutCache` (the same caching that `Label` uses) built from the editor's current text and styles, with no alignment, which doesn't affect the measured size. The cache is cleared whenever text, styles, or fonts change, mirroring `Label`. The editor is no longer touched during measurement, resolving the layout-system TODO about side-effect free measurement. The first new test fails on the previous commit: a parent measuring its child at min- and max-content nudged the editor generation on every layout pass. The second test guards the cache invalidation: inserting text must grow the measured max-content width.
53b648f to
835d541
Compare
DRAFT — NOT FOR DIRECT SUBMISSION (rev 2, house-pattern rework)
Suggested titleMake Draft body (raw material — rewrite before any upstream use)
This implements the TODO using the caching approach
Measurement also gets Two new tests:
Notes:
The hack dates from the new layout system (linebender#1560); the caching it now uses Factual development notes for Lane's disclosure paragraphHow this change was developed, for the up-front LLM disclosure the policy
|
|
Disposition: further Label/TextArea unification (Lane asked whether to push for it) Checked: no anchor issue exists on linebender/xilem or linebender/parley for text-widget unification — only the two in-code TODOs. Recommendation is to sequence, not expand this PR:
Strategic note: c0k's fork burden is fully discharged when THIS PR merges + pin bump (patch 05 retires). Deeper unification doesn't reduce carried divergence — it's goodwill work, best attempted after a merged contribution establishes standing. 🤖 Generated with Claude Code |
|
Draft delta (rev 2.1): the "deliberately stops short" note in 🤖 Generated with Claude Code |
Fork-internal review PR — do not merge into upstream from here. Base and head are both in
0k-dot-computer/xilem; upstream (linebender/xilem) cannot see this. The real PR is opened only after sign-off on the exact text.What this is
Re-derivation of our masonry fork patch
05-text-area-measure-cache.patchon upstream HEAD (5d72ad41), targeting upstream's own TODO inTextArea::measure:// TODO: Remove this hack and do efficient side-effect free measurement with no alignment.Two commits, each buildable and green:
Label's text layout cache into a sharedTextLayoutCache. Pure refactor —TextLayout+ the caching logic from ImproveLabeltext layout caching. linebender/xilem#1665 move verbatim fromlabel.rsto a crate-privatewidgets/text_layout_cache.rs, parameterized on text/styles instead of readingLabel's fields. Label render snapshots unchanged (234/234 tests green at this commit).TextAreameasurement side-effect free.measuregoes through its ownTextLayoutCachebuilt from the editor's current text and styles (no alignment — doesn't affect measured size); the livePlainEditoris never touched during measurement. Cache cleared wherever text/styles/fonts change, mirroringLabel::clear_cache(style setters,reset_text, keyboard/IME/paste edit paths,FontsChanged).Validation evidence
measure_does_not_mutate_editorfails on pristine HEAD (speculative measure at min/max-content nudges the editor generation every layout pass), passes with the fix.measure_reflects_editsguards the invalidation: typing must grow max-content width. Counterfactually verified — removing oneclear_measure_cache()call makes it fail.cargo test -p masonry: 236 passed incl. all render snapshots (pixel parity for both Label and TextArea);cargo fmt --check,cargo clippy -p masonry --all-features --tests(0 warnings),cargo check --workspace --all-features: clean.Why the house pattern (vs the minimal fix)
The maintainer (xStrom) solved this exact problem for
Labelin linebender#1665 with a multi-entry cache keyed bymax_advance(satisfies/more_constrainedreuse logic). Measuring through the shared cache gives TextArea the same layout reuse — min/max-content probes and repeated measures hit the cache instead of rebuilding — and is a concrete step toward the existing TODO about unifying TextArea's and Label's measure paths.Cost: correctness now depends on invalidation completeness (the clear sites). Mitigated by mirroring Label's discipline exactly + the counterfactually-verified test.
Things for Lane to weigh
pr-body-draft.mdcomment below — you must rewrite and own it.TextArea: onIme::Disabledusefinish_compose()instead ofclear_compose()linebender/xilem#1692 (IME) and masonry: adopt ui-events text input events linebender/xilem#1700 (ui-events adoption) touch. Mergeable today; expect rebases if those land first.masonry_core, or unifying themax_advancecalculation too (we deliberately stopped short).🤖 Generated with Claude Code