perf(ui-gpui): simplify ProjectBox render, confirm 3% is hierarchy depth cost
Each blink = ~15ms CPU (1-2 ticks/500ms). Cost is Entity dispatch tree walk through 4 levels (Workspace→ProjectGrid→ProjectBox→StatusDotView), not div count. Zed achieves ~5ms with 3 levels. To match: flatten hierarchy.
This commit is contained in:
parent
5d69f6b28f
commit
ddec12db3f
1 changed files with 20 additions and 70 deletions
|
|
@ -47,22 +47,14 @@ fn project_status_dot(status: AgentStatus) -> Div {
|
|||
|
||||
// ── Tab Button ──────────────────────────────────────────────────────
|
||||
|
||||
fn tab_button(label: &str, active: bool, accent: Rgba) -> Div {
|
||||
let fg = if active { accent } else { theme::SUBTEXT0 };
|
||||
|
||||
fn tab_button(label: &'static str, active: bool, accent: Rgba) -> Div {
|
||||
let mut tab = div()
|
||||
.px(px(10.0))
|
||||
.px(px(8.0))
|
||||
.py(px(4.0))
|
||||
.text_size(px(11.0))
|
||||
.text_color(fg)
|
||||
.cursor_pointer()
|
||||
.hover(|s| s.text_color(theme::TEXT));
|
||||
|
||||
if active {
|
||||
tab = tab.border_b_2().border_color(accent);
|
||||
}
|
||||
|
||||
tab.child(label.to_string())
|
||||
.text_color(if active { accent } else { theme::SUBTEXT0 })
|
||||
.cursor_pointer();
|
||||
if active { tab = tab.border_b_2().border_color(accent); }
|
||||
tab.child(label) // &'static str → no allocation
|
||||
}
|
||||
|
||||
// ── ProjectBox View ─────────────────────────────────────────────────
|
||||
|
|
@ -155,35 +147,19 @@ impl Render for ProjectBox {
|
|||
.flex()
|
||||
.flex_col();
|
||||
|
||||
// Agent pane (upper portion) — cached: only re-renders on new messages
|
||||
// Agent pane — cached (0% on blink)
|
||||
if let Some(ref pane) = self.agent_pane {
|
||||
model_content = model_content.child(
|
||||
div()
|
||||
.flex_1()
|
||||
.w_full()
|
||||
.child(pane.clone().into_cached_flex()),
|
||||
);
|
||||
model_content = model_content.child(pane.clone().into_cached_flex());
|
||||
}
|
||||
|
||||
// Resize handle
|
||||
// Resize handle (1 div)
|
||||
model_content = model_content.child(
|
||||
div()
|
||||
.id(self.id_resize.clone())
|
||||
.w_full()
|
||||
.h(px(4.0))
|
||||
.bg(theme::SURFACE0)
|
||||
.cursor_pointer()
|
||||
div().id(self.id_resize.clone()).w_full().h(px(4.0))
|
||||
.bg(theme::SURFACE0).cursor_pointer()
|
||||
.hover(|s| s.bg(theme::SURFACE1)),
|
||||
);
|
||||
|
||||
// Terminal view — cached: only re-renders on PTY output
|
||||
// Terminal — cached (0% on blink)
|
||||
if let Some(ref term) = self.terminal_view {
|
||||
model_content = model_content.child(
|
||||
div()
|
||||
.w_full()
|
||||
.h(px(180.0))
|
||||
.child(term.clone().into_cached_flex()),
|
||||
);
|
||||
model_content = model_content.child(term.clone().into_cached_flex());
|
||||
}
|
||||
|
||||
model_content
|
||||
|
|
@ -250,63 +226,37 @@ impl Render for ProjectBox {
|
|||
.border_1()
|
||||
.border_color(theme::SURFACE0)
|
||||
.overflow_hidden()
|
||||
// ── Header ──────────────────────────────────────────
|
||||
// ── Header (minimal divs: 1 row + accent stripe + dot entity) ──
|
||||
.child(
|
||||
div()
|
||||
.w_full()
|
||||
.h(px(36.0))
|
||||
.flex()
|
||||
.flex_row()
|
||||
.items_center()
|
||||
.px(px(12.0))
|
||||
.gap(px(8.0))
|
||||
.bg(theme::MANTLE)
|
||||
.border_b_1()
|
||||
.border_color(theme::SURFACE0)
|
||||
// Accent stripe on left
|
||||
.child(
|
||||
div()
|
||||
.w(px(3.0))
|
||||
.h(px(20.0))
|
||||
.rounded(px(2.0))
|
||||
.bg(accent),
|
||||
)
|
||||
// Status dot — separate Entity that reads BlinkState.
|
||||
// ProjectBox does NOT read BlinkState → doesn't re-render on blink.
|
||||
// Only StatusDotView (1 div, 8x8px) re-renders 2x/sec.
|
||||
.child(div().w(px(3.0)).h(px(20.0)).rounded(px(2.0)).bg(accent))
|
||||
.children(self.status_dot_view.clone())
|
||||
// Project name
|
||||
.child(
|
||||
div()
|
||||
.text_size(px(13.0))
|
||||
.text_color(theme::TEXT)
|
||||
.child(self.cached_name.clone()),
|
||||
)
|
||||
.child(self.cached_name.clone())
|
||||
.child(div().flex_1())
|
||||
// CWD (ellipsized)
|
||||
.child(
|
||||
div()
|
||||
.text_size(px(10.0))
|
||||
.text_color(theme::OVERLAY0)
|
||||
.max_w(px(200.0))
|
||||
.overflow_hidden()
|
||||
.whitespace_nowrap()
|
||||
.child(self.cached_cwd.clone()),
|
||||
),
|
||||
.child(self.cached_cwd.clone()),
|
||||
)
|
||||
// ── Tab Bar ─────────────────────────────────────────
|
||||
// ── Tab Bar (1 div + 3 inline tab labels) ──
|
||||
.child(
|
||||
div()
|
||||
.w_full()
|
||||
.h(px(32.0))
|
||||
.h(px(28.0))
|
||||
.flex()
|
||||
.flex_row()
|
||||
.items_center()
|
||||
.px(px(8.0))
|
||||
.gap(px(2.0))
|
||||
.bg(theme::MANTLE)
|
||||
.border_b_1()
|
||||
.border_color(theme::SURFACE0)
|
||||
.text_size(px(11.0))
|
||||
.child(tab_button("Model", active_tab == ProjectTab::Model, accent))
|
||||
.child(tab_button("Docs", active_tab == ProjectTab::Docs, accent))
|
||||
.child(tab_button("Files", active_tab == ProjectTab::Files, accent)),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue