Skip to content

plot: Keep finished appears across remounts with PlotAppearScope - #3308

Merged
madcodelife merged 1 commit into
mainfrom
plot-appear-scope
Sep 29, 2026
Merged

madcodelife merged 1 commit into
mainfrom
plot-appear-scope

Conversation

@madcodelife

@madcodelife madcodelife commented Sep 29, 2026 •

Copy link
Copy Markdown
Member

Summary

A plot's appear (#3296) lives in its element state. GPUI drops element state for anything not painted in a frame, so a plot inside a virtual list — list, uniform_list, a List row — forgets its appear once it scrolls past the overdraw and draws in again every time it comes back. The only workaround so far was .appear(false), which gives up the appear entirely.

PlotAppearScope wraps the region that repaints its plots on and off:

PlotAppearScope::new(("transcript", conversation_id), list(state, render_row).flex_1())
  • A plot inside it that finished appearing is remembered by its global element id and appear generation. Painted again after a gap, it gets PlotAppear::complete() straight away: no Presence tracking and no frames, and hover is not held back.
  • A new appear_generation still replays, and a plot taken away mid-appear draws in again from the start.
  • The memory is the scope's own element state, so it lasts exactly while the scope is painted every frame. Closing the view, or giving the scope another id (name it after the content), draws its plots in afresh.
  • The innermost scope wins. The scope takes no part in layout: it hands on its child's LayoutId, so a self-sizing child such as list(..).flex_1() keeps working unchanged.
  • Without a scope, behavior is unchanged.

It works for every Plot: the built-in charts and hand-written plots, since the check sits in track_appear, which PlotElement already calls.

Public API

gpui-base

pub struct PlotAppearScope                                              // remembers finished appears across remounts
impl PlotAppearScope {
    pub fn new(id: impl Into<ElementId>, child: impl IntoElement) -> Self
}
impl IntoElement for PlotAppearScope
impl Element for PlotAppearScope

Re-exported as gpui_component::plot::PlotAppearScope.

Breaking Changes

None.

Test plan

  • cargo test -p gpui-base -p gpui-component
  • New tests in plot::appear:
    • A remount inside a scope after the appear finished is complete at once and asks for no frames.
    • A new generation still replays.
    • A remount before the appear finished replays.
    • A renamed scope, or one that stops being painted, forgets.
    • Without a scope, a remount replays as before.
  • cargo clippy -p gpui-base -p gpui-component --lib --tests -- --deny warnings
  • Docs: website/base/plot.md, website/component/chart.md (en + zh-CN), release-notes.md

This is a gpui-base change: the appear state it extends already lives there.

A plot's appear lives in its element state, so a plot that stops being
painted, such as a row a virtual list scrolled away, draws in again when it
comes back. `PlotAppearScope` remembers, in its own element state, which
plots inside it finished appearing (by global element id and appear
generation) and hands those a complete appear at once, asking for no
frames. The memory goes with the scope, so closing the view or renaming the
scope draws its plots in afresh. Without a scope nothing changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@madcodelife
madcodelife merged commit 2ec5696 into main Sep 29, 2026
12 checks passed
@madcodelife
madcodelife deleted the plot-appear-scope branch September 29, 2026 03:36
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