Skip to content

text, resizable: Stop notifying state that did not change - #3418

Merged
huacnlee merged 1 commit into
mainfrom
perf/no-redundant-notifies
Oct 8, 2026
Merged

huacnlee merged 1 commit into
mainfrom
perf/no-redundant-notifies

Conversation

@huacnlee

@huacnlee huacnlee commented Oct 8, 2026

Copy link
Copy Markdown
Member

Description

Follow-up to #3407. Two more places update an entity even though nothing in it changed. Under GPUI Fast, a view that read that entity is then counted as changed and built again, even when it is retained.

  • TextViewState: a markdown text that is parsed synchronously when it is set still receives an acknowledgement (baseline_ack) from the background parser. commit_parsed_update discarded it, but only after weak_self.update, which already marked the state as updated. The receive task now checks first, with read_with and the new TextViewState::commits, and skips results that commit nothing. commit_parsed_update uses the same check.
  • ResizablePanelGroup / ResizablePanel: both report their bounds in on_prepaint on every frame they are drawn, and updated ResizableState every time, even when the bounds were the same. Every view that read the state was rebuilt on every frame. They now return early when nothing would change: same group bounds, or ResizableState::panel_size_changes (crate-private) is false.

Behaviour is unchanged: the skipped updates were no-ops.

Before / After

Measured by the new tests (gpui-fast feature), counting renders of a view that reads the state:

Case Before After
Reader of a TextViewState after the parser acknowledges a synchronous parse 2 renders 1 render
Reader of a ResizableState while its panels are redrawn at the same bounds (3 extra frames) 11 renders 5 renders

Tests

  • text::state::tests::parse_ack::acknowledging_a_parse_leaves_its_readers_retained
  • resizable::tests::redrawing_panels_where_they_were_leaves_their_readers_retained

Both fail without the fix and pass with it. cargo fmt --check and cargo clippy -p gpui-base -- --deny warnings (with and without gpui-fast) are clean. cargo test -p gpui-base --lib passes, 1323 tests. With --features gpui-fast the same 14 tests fail on main as on this branch, so this change neither causes nor fixes them.

🤖 Generated with Claude Code

A markdown text view parsed synchronously as its text is set still gets
an acknowledgement from the background parser. Committing it changed
nothing but updated the state, so GPUI Fast took every view reading the
state as changed and built it again. The receive task now skips results
that commit nothing.

Resizable panels and their group reported their bounds on every
prepaint and updated the state even when the bounds were the same, so
every view reading the state was built again on every frame. They now
update it only when the bounds or size range change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@huacnlee
huacnlee merged commit 2ef9968 into main Oct 8, 2026
16 checks passed
@huacnlee
huacnlee deleted the perf/no-redundant-notifies branch October 8, 2026 08:19
linruohan pushed a commit to linruohan/gpui-component that referenced this pull request Oct 9, 2026
…#3418)

## Description

Follow-up to longbridge#3407. Two more places update an entity even though nothing
in it changed. Under GPUI Fast, a view that read that entity is then
counted as changed and built again, even when it is retained.

- **`TextViewState`**: a markdown text that is parsed synchronously when
it is set still receives an acknowledgement (`baseline_ack`) from the
background parser. `commit_parsed_update` discarded it, but only after
`weak_self.update`, which already marked the state as updated. The
receive task now checks first, with `read_with` and the new
`TextViewState::commits`, and skips results that commit nothing.
`commit_parsed_update` uses the same check.
- **`ResizablePanelGroup` / `ResizablePanel`**: both report their bounds
in `on_prepaint` on every frame they are drawn, and updated
`ResizableState` every time, even when the bounds were the same. Every
view that read the state was rebuilt on every frame. They now return
early when nothing would change: same group bounds, or
`ResizableState::panel_size_changes` (crate-private) is false.

Behaviour is unchanged: the skipped updates were no-ops.

## Before / After

Measured by the new tests (`gpui-fast` feature), counting renders of a
view that reads the state:

| Case | Before | After |
| --- | --- | --- |
| Reader of a `TextViewState` after the parser acknowledges a
synchronous parse | 2 renders | 1 render |
| Reader of a `ResizableState` while its panels are redrawn at the same
bounds (3 extra frames) | 11 renders | 5 renders |

## Tests

-
`text::state::tests::parse_ack::acknowledging_a_parse_leaves_its_readers_retained`
-
`resizable::tests::redrawing_panels_where_they_were_leaves_their_readers_retained`

Both fail without the fix and pass with it. `cargo fmt --check` and
`cargo clippy -p gpui-base -- --deny warnings` (with and without
`gpui-fast`) are clean. `cargo test -p gpui-base --lib` passes, 1323
tests. With `--features gpui-fast` the same 14 tests fail on `main` as
on this branch, so this change neither causes nor fixes them.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@huacnlee huacnlee mentioned this pull request Oct 12, 2026
huacnlee added a commit that referenced this pull request Oct 12, 2026
## Description

Prepare v0.7.2 on `stable` from the PRs merged into `main` since v0.7.1,
leaving out every change that breaks existing consumers. `stable`
already carries #3371 and #3373; this adds the remaining compatible PRs
with `git cherry-pick -x` and bumps the workspace to 0.7.2.

### Included

- kit: Add optional gpui-fast backend (#3375)
- tooltip: Make show delay and grace period configurable with
`TooltipDefaults` (#3376)
- docs: Explain recovering focus when the focused element stops
rendering (#3386)
- diff: Add readonly patch viewer (#3378)
- kit: Use one Windows manifest with GPUI Fast (#3380)
- test: Make Progress and TitleBar findable in UI tests (#3383)
- input: Preserve selection, focus ring and context menu actions (#3382)
- diff: Add a Git history example and complete review APIs (#3388)
- text_view: Ignore gestures that stay inside one block plugin (#3390)
- text_view: Round the first and last table rows to the frame radius
(#3309)
- menu: Open a context menu with a long press on touch (#3393)
- text_view: Keep narrow table columns on one line (#3399)
- settings: Keep focus rings inside the list viewport (#3394)
- scrollable_mask: Keep rounded scroll-table corners clean at any scroll
offset (#3400)
- dialog: Add margin_top to AlertDialog (#3404)
- input: Add InputState::add_selection for programmatic multi-cursor
(#3403)
- text_selection: Stop writing selection state on every frame (#3407)
- table: Make the sort icon a labelled button (#3396)
- table: Report visible row ranges of one row or none (#3397)
- dialog: Support configurable entrance animations (#3405)
- docs: Explain the open_dialog builder and footer contracts (#3406)
- dock: Hand the focus to the tab that replaces a closed one (#3409)
- dropdown_button: Add A11y names for the menu trigger (#3410)
- text, resizable: Stop notifying state that did not change (#3418)
- editor: Add on-demand completion commands (#3411)
- table: Clear a right-clicked cell's outline on the next click (#3413)
- tab: Scroll a clicked tab into view with the next one peeking (#3419)
- table: Allow a header row height separate from the body (#3420)
- menu: Focus a context menu before its first frame (#3422)
- text: Preserve logical selection across presentation changes (#3421)
- text: Keep inline HTML mark highlights in Markdown (#3425)
- input: Anchor completion/code-action popups to the current frame's
caret (#3412)
- input: Run custom context menu builders after releasing the input
(#3433)
- input: Keep auto-grow rows fitted when the limits change (#3430)
- text: Paint TextView selection under the glyphs (#3439)

Already on `stable`: #3371, #3373.

### Excluded (Breaking Changes)

- #3432 motion: `Easing::sample` now returns values outside `[0, 1]` for
overshooting curves.
- #3415 tab: new `TabVariant::Folder` breaks exhaustive matches.
- #3402 kit: pointer helpers now keep held modifiers; nested
context-menu behavior changes in tests.
- #3384 test: `TestWindowExt` gains required methods.
- #3302 resizable: `ResizeHandle::on_drag` takes `&T` instead of
`Rc<T>`.
- #3389, #3395, #3398 webview: wrapper API changes, `gpui-wry` →
`gpui-webview` rename, and the GPUI Fast requirement.

#3411, #3405 and #3396 have a Breaking Changes section that reads "None"
and are included. #3376 only deprecates `TooltipRequest::placement`, and
#3397 / #3382 change behavior compatibly, so they are included too.

### Adaptations

- `crates/kit/tests/collections.rs` and `crates/kit/tests/rendering.rs`:
conflict resolutions drop the tests that belong to #3402 and keep each
backported PR's own test.
- `test: Keep backported tests on the v0.7.1 test API`: the menu and
completion tests from #3422 and #3412 used `find_all` and
`pointer_down`/`pointer_up` from #3384/#3402. They now query
`gpui_kit::base::test_support::snapshots` and dispatch mouse events
directly.
- `kit: Prepare v0.7.2`: workspace version bump; `Cargo.lock` only
updates workspace members.

## Public API

No new public API beyond what the included PRs add; each lists its items
in its own `## Public API` section (notably #3375, #3376, #3378, #3388,
#3403, #3404, #3405, #3411, #3420).

## How to Test

- `cargo clippy --workspace --all-targets -- --deny warnings` passes on
Linux.
- `cargo test -p gpui-kit --features "test-support component assets"
--test collections --test menu --test input` passes on Linux.
- The macOS-only `rendering` test (#3439 adds one case, the count is
updated to 11) was not run.

AI-assisted: the backport, conflict resolution and test adaptations were
done with Claude Code.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Floyd Wang <codelife721@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Gustave <gustavel@gmail.com>
Co-authored-by: luren <84951845+lurenjia534@users.noreply.github.com>
Co-authored-by: Ylin <ylinwind@gmail.com>
Co-authored-by: ihavecoke <mixboip@gmail.com>
Co-authored-by: Lorenzo <150276837+Bombatomica64@users.noreply.github.com>
Co-authored-by: MR. XIE <113512030+xxww0098@users.noreply.github.com>
Co-authored-by: xxww0098 <shefkie1957@gmail.com>
Co-authored-by: Sola 🌙🤖 <266175376+sola-ryu@users.noreply.github.com>
Co-authored-by: Sola <sola-ryu@users.noreply.github.com>
Co-authored-by: Andy Hsu <i@nn.ci>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Floyd Wang <gassnake999@gmail.com>
Co-authored-by: Daiki Tomioka <20753105+TomiXRM@users.noreply.github.com>
Co-authored-by: Henrik Øgård <henrik@ogard.no>
Co-authored-by: Henrik Øgård <henrikogaard@users.noreply.github.com>
Co-authored-by: Endless <endless@longbridge.com>
Co-authored-by: John Costa <costajohnt@gmail.com>
Co-authored-by: Alexander <87220898+sneffets@users.noreply.github.com>
Co-authored-by: Cesar Talén <154442565+cesartalen@users.noreply.github.com>
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.

1 participant