From 297fd858e8f97a61dd69cd8c4801a04c2a2c8266 Mon Sep 17 00:00:00 2001 From: Michael Sloan Date: Thu, 14 Aug 2025 19:10:19 -0600 Subject: [PATCH 1/3] Code for debugging issue with no width available This commit enables extremely verbose taffy logging and adds output of the layout ids for the Open Router settings container ID and the ID for the text input that has the issue. https://gist.github.com/mgsloan/28a2d8d9c9c803fc60898eae9db1ec8e is the subsets of the logs starting with the first line with the container ID and ending with the last line that has the container ID (see the end of the logs for these IDs) Repro for the issue: * Set ui_font_size to 20 in user settings.json * Open zed agent settings * Expand Open Router settings * Resize panel until the API key input field becomes small --- crates/gpui/Cargo.toml | 2 +- crates/gpui/src/elements/div.rs | 19 ++++++++++++++++++- crates/gpui/src/taffy.rs | 18 +++++++++++++++++- .../src/provider/open_router.rs | 2 ++ 4 files changed, 38 insertions(+), 3 deletions(-) diff --git a/crates/gpui/Cargo.toml b/crates/gpui/Cargo.toml index d720dfb2a1..0bf0cd8c0f 100644 --- a/crates/gpui/Cargo.toml +++ b/crates/gpui/Cargo.toml @@ -121,7 +121,7 @@ smallvec.workspace = true smol.workspace = true strum.workspace = true sum_tree.workspace = true -taffy = "=0.9.0" +taffy = { version = "=0.9.0", features = ["debug"] } thiserror.workspace = true util.workspace = true uuid.workspace = true diff --git a/crates/gpui/src/elements/div.rs b/crates/gpui/src/elements/div.rs index 09afbff929..0669d36b2c 100644 --- a/crates/gpui/src/elements/div.rs +++ b/crates/gpui/src/elements/div.rs @@ -23,6 +23,7 @@ use crate::{ MouseClickEvent, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Overflow, ParentElement, Pixels, Point, Render, ScrollWheelEvent, SharedString, Size, Style, StyleRefinement, Styled, Task, TooltipId, Visibility, Window, WindowControlArea, point, px, size, + taffy::{CONTAINER_LAYOUT_ID_TO_DEBUG, LAYOUT_ID_TO_DEBUG}, }; use collections::HashMap; use refineable::Refineable; @@ -1298,7 +1299,23 @@ impl Element for Div { .iter_mut() .map(|child| child.request_layout(window, cx)) .collect::>(); - window.request_layout(style, child_layout_ids.iter().copied(), cx) + let layout_id = + window.request_layout(style, child_layout_ids.iter().copied(), cx); + if let Some(global_id) = global_id.as_ref() + && global_id.0.ends_with(&["api-key-editor".into()]) + { + LAYOUT_ID_TO_DEBUG.with_borrow_mut(|layout_id_to_debug| { + *layout_id_to_debug = Some(layout_id) + }); + } + if let Some(global_id) = global_id.as_ref() + && global_id.0.ends_with(&["open-router-container".into()]) + { + CONTAINER_LAYOUT_ID_TO_DEBUG.with_borrow_mut(|layout_id_to_debug| { + *layout_id_to_debug = Some(layout_id) + }); + } + layout_id }) }, ) diff --git a/crates/gpui/src/taffy.rs b/crates/gpui/src/taffy.rs index ee21ecd8c4..61736e456c 100644 --- a/crates/gpui/src/taffy.rs +++ b/crates/gpui/src/taffy.rs @@ -3,7 +3,7 @@ use crate::{ }; use collections::{FxHashMap, FxHashSet}; use smallvec::SmallVec; -use std::{fmt::Debug, ops::Range}; +use std::{cell::RefCell, fmt::Debug, ops::Range}; use taffy::{ TaffyTree, TraversePartialTree as _, geometry::{Point as TaffyPoint, Rect as TaffyRect, Size as TaffySize}, @@ -11,6 +11,14 @@ use taffy::{ tree::NodeId, }; +thread_local! { + pub static LAYOUT_ID_TO_DEBUG: RefCell> = const { RefCell::new(None) }; +} + +thread_local! { + pub static CONTAINER_LAYOUT_ID_TO_DEBUG: RefCell> = const { RefCell::new(None) }; +} + type NodeMeasureFn = Box< dyn FnMut(Size>, Size, &mut Window, &mut App) -> Size, >; @@ -198,6 +206,14 @@ impl TaffyLayoutEngine { ) .expect(EXPECT_MESSAGE); + LAYOUT_ID_TO_DEBUG.with_borrow(|layout_id_to_debug| { + println!("Layout ID Debug: {:?}", layout_id_to_debug); + }); + + CONTAINER_LAYOUT_ID_TO_DEBUG.with_borrow(|layout_id| { + println!("Container Layout ID Debug: {:?}\n", layout_id); + }); + // println!("compute_layout took {:?}", started_at.elapsed()); } diff --git a/crates/language_models/src/provider/open_router.rs b/crates/language_models/src/provider/open_router.rs index 3a492086f1..6e56bb5344 100644 --- a/crates/language_models/src/provider/open_router.rs +++ b/crates/language_models/src/provider/open_router.rs @@ -853,6 +853,7 @@ impl Render for ConfigurationView { div().child(Label::new("Loading credentials...")).into_any() } else if self.should_render_editor(cx) { v_flex() + .id("open-router-container") .size_full() .on_action(cx.listener(Self::save_api_key)) .child(Label::new("To use Zed's agent with OpenRouter, you need to add an API key. Follow these steps:")) @@ -872,6 +873,7 @@ impl Render for ConfigurationView { ) .child( h_flex() + .id("api-key-editor") .w_full() .my_2() .px_2() From 9d9b625483fb325127b47ea69d5091084ac67044 Mon Sep 17 00:00:00 2001 From: Michael Sloan Date: Fri, 15 Aug 2025 16:56:57 -0600 Subject: [PATCH 2/3] Simplify open router config to make layout structure simpler --- .../src/provider/open_router.rs | 26 +++---------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/crates/language_models/src/provider/open_router.rs b/crates/language_models/src/provider/open_router.rs index 6e56bb5344..aad113c565 100644 --- a/crates/language_models/src/provider/open_router.rs +++ b/crates/language_models/src/provider/open_router.rs @@ -856,23 +856,11 @@ impl Render for ConfigurationView { .id("open-router-container") .size_full() .on_action(cx.listener(Self::save_api_key)) - .child(Label::new("To use Zed's agent with OpenRouter, you need to add an API key. Follow these steps:")) + .child(Label::new( + "To use Zed's agent with OpenRouter, you need to add an API key.", + )) .child( - List::new() - .child(InstructionListItem::new( - "Create an API key by visiting", - Some("OpenRouter's console"), - Some("https://openrouter.ai/keys"), - )) - .child(InstructionListItem::text_only( - "Ensure your OpenRouter account has credits", - )) - .child(InstructionListItem::text_only( - "Paste your API key below and hit enter to start using the assistant", - )), - ) - .child( - h_flex() + div() .id("api-key-editor") .w_full() .my_2() @@ -884,12 +872,6 @@ impl Render for ConfigurationView { .rounded_sm() .child(self.render_api_key_editor(cx)), ) - .child( - Label::new( - format!("You can also assign the {OPENROUTER_API_KEY_VAR} environment variable and restart Zed."), - ) - .size(LabelSize::Small).color(Color::Muted), - ) .into_any() } else { h_flex() From 1c2df4a5c66472487a3f4c85056c03da52fa13bf Mon Sep 17 00:00:00 2001 From: Michael Sloan Date: Fri, 15 Aug 2025 16:57:37 -0600 Subject: [PATCH 3/3] Instead try to output something close to taffy api usage --- crates/gpui/Cargo.toml | 2 +- crates/gpui/src/element.rs | 26 +++++++++++- crates/gpui/src/elements/div.rs | 31 ++++++-------- crates/gpui/src/taffy.rs | 72 ++++++++++++++++++++++++++++----- 4 files changed, 101 insertions(+), 30 deletions(-) diff --git a/crates/gpui/Cargo.toml b/crates/gpui/Cargo.toml index 0bf0cd8c0f..72758a9dca 100644 --- a/crates/gpui/Cargo.toml +++ b/crates/gpui/Cargo.toml @@ -121,7 +121,7 @@ smallvec.workspace = true smol.workspace = true strum.workspace = true sum_tree.workspace = true -taffy = { version = "=0.9.0", features = ["debug"] } +taffy = { version = "=0.9.0", features = ["serde"] } thiserror.workspace = true util.workspace = true uuid.workspace = true diff --git a/crates/gpui/src/element.rs b/crates/gpui/src/element.rs index e5f49c7be1..31177d666b 100644 --- a/crates/gpui/src/element.rs +++ b/crates/gpui/src/element.rs @@ -34,7 +34,7 @@ use crate::{ App, ArenaBox, AvailableSpace, Bounds, Context, DispatchNodeId, ELEMENT_ARENA, ElementId, FocusHandle, InspectorElementId, LayoutId, Pixels, Point, Size, Style, Window, - util::FluentBuilder, + taffy::LOG_TAFFY, util::FluentBuilder, }; use derive_more::{Deref, DerefMut}; pub(crate) use smallvec::SmallVec; @@ -372,6 +372,22 @@ impl Drawable { inspector_id = None; } + let should_start_logging = global_id + .as_ref() + .map(|id| { + id.0.last() + .map(|last| last == &"open-router-container".into()) + .unwrap_or(false) + }) + .unwrap_or(false); + + if should_start_logging { + println!("Starting taffy logging for element"); + LOG_TAFFY.with_borrow_mut(|log_taffy| { + *log_taffy = true; + }); + } + let (layout_id, request_layout) = self.element.request_layout( global_id.as_ref(), inspector_id.as_ref(), @@ -379,6 +395,14 @@ impl Drawable { cx, ); + // Only turn off logging if this element started it + if should_start_logging { + println!("Stopping taffy logging for element"); + LOG_TAFFY.with_borrow_mut(|log_taffy| { + *log_taffy = false; + }); + } + if global_id.is_some() { window.element_id_stack.pop(); } diff --git a/crates/gpui/src/elements/div.rs b/crates/gpui/src/elements/div.rs index 0669d36b2c..4ccdb5b205 100644 --- a/crates/gpui/src/elements/div.rs +++ b/crates/gpui/src/elements/div.rs @@ -23,7 +23,7 @@ use crate::{ MouseClickEvent, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Overflow, ParentElement, Pixels, Point, Render, ScrollWheelEvent, SharedString, Size, Style, StyleRefinement, Styled, Task, TooltipId, Visibility, Window, WindowControlArea, point, px, size, - taffy::{CONTAINER_LAYOUT_ID_TO_DEBUG, LAYOUT_ID_TO_DEBUG}, + taffy::{CONTAINER_LAYOUT_ID_TO_DEBUG, LAYOUT_ID_TO_DEBUG, LOG_TAFFY}, }; use collections::HashMap; use refineable::Refineable; @@ -1299,23 +1299,7 @@ impl Element for Div { .iter_mut() .map(|child| child.request_layout(window, cx)) .collect::>(); - let layout_id = - window.request_layout(style, child_layout_ids.iter().copied(), cx); - if let Some(global_id) = global_id.as_ref() - && global_id.0.ends_with(&["api-key-editor".into()]) - { - LAYOUT_ID_TO_DEBUG.with_borrow_mut(|layout_id_to_debug| { - *layout_id_to_debug = Some(layout_id) - }); - } - if let Some(global_id) = global_id.as_ref() - && global_id.0.ends_with(&["open-router-container".into()]) - { - CONTAINER_LAYOUT_ID_TO_DEBUG.with_borrow_mut(|layout_id_to_debug| { - *layout_id_to_debug = Some(layout_id) - }); - } - layout_id + window.request_layout(style, child_layout_ids.iter().copied(), cx) }) }, ) @@ -1333,6 +1317,17 @@ impl Element for Div { window: &mut Window, cx: &mut App, ) -> Option { + if let Some(global_id) = global_id + && global_id.0.ends_with(&["open-router-container".into()]) + { + println!("open-router-container bounds = {:?}", bounds) + } + if let Some(global_id) = global_id + && global_id.0.ends_with(&["api-key-editor".into()]) + { + println!("api-key-editor bounds = {:?}", bounds) + } + let has_prepaint_listener = self.prepaint_listener.is_some(); let mut children_bounds = Vec::with_capacity(if has_prepaint_listener { request_layout.child_layout_ids.len() diff --git a/crates/gpui/src/taffy.rs b/crates/gpui/src/taffy.rs index 61736e456c..b6ee841992 100644 --- a/crates/gpui/src/taffy.rs +++ b/crates/gpui/src/taffy.rs @@ -19,6 +19,10 @@ thread_local! { pub static CONTAINER_LAYOUT_ID_TO_DEBUG: RefCell> = const { RefCell::new(None) }; } +thread_local! { + pub static LOG_TAFFY: RefCell = const { RefCell::new(false) }; +} + type NodeMeasureFn = Box< dyn FnMut(Size>, Size, &mut Window, &mut App) -> Size, >; @@ -34,6 +38,11 @@ pub struct TaffyLayoutEngine { const EXPECT_MESSAGE: &str = "we should avoid taffy layout errors by construction if possible"; +fn layout_id_to_var_name(layout_id: LayoutId) -> String { + let node_id: u64 = layout_id.clone().0.into(); + format!("node_{}", node_id) +} + impl TaffyLayoutEngine { pub fn new() -> Self { let mut taffy = TaffyTree::new(); @@ -57,12 +66,23 @@ impl TaffyLayoutEngine { rem_size: Pixels, children: &[LayoutId], ) -> LayoutId { + let should_log = LOG_TAFFY.with_borrow(|log_taffy| *log_taffy); let taffy_style = style.to_taffy(rem_size); let layout_id = if children.is_empty() { - self.taffy + let layout_id = self + .taffy .new_leaf(taffy_style) .expect(EXPECT_MESSAGE) - .into() + .into(); + if should_log { + let var_name = layout_id_to_var_name(layout_id); + println!( + "let {} = taffy.new_leaf({:?}).unwrap();", + var_name, + serde_json::to_string(&style.to_taffy(rem_size)).unwrap(), + ); + } + layout_id } else { let parent_id = self .taffy @@ -72,6 +92,19 @@ impl TaffyLayoutEngine { }) .expect(EXPECT_MESSAGE) .into(); + if should_log { + let var_name = layout_id_to_var_name(parent_id); + println!( + "let {} = taffy.new_with_children({:?}, &[{:?}]).unwrap();", + var_name, + serde_json::to_string(&style.to_taffy(rem_size)).unwrap(), + children + .iter() + .map(|id| layout_id_to_var_name(*id)) + .collect::>() + .join(", ") + ); + } parent_id }; layout_id @@ -81,7 +114,7 @@ impl TaffyLayoutEngine { &mut self, style: Style, rem_size: Pixels, - measure: impl FnMut( + mut measure: impl FnMut( Size>, Size, &mut Window, @@ -91,16 +124,33 @@ impl TaffyLayoutEngine { ) -> LayoutId { let taffy_style = style.to_taffy(rem_size); + let should_log = LOG_TAFFY.with_borrow(|log_taffy| *log_taffy); + let layout_id = self .taffy .new_leaf_with_context( taffy_style, NodeContext { - measure: Box::new(measure), + measure: Box::new(move |size, available_space, window, app| { + let result = measure(size, available_space, window, app); + if should_log { + println!("measure({:?}, {:?}) == {:?}", size, available_space, result); + } + result + }), }, ) .expect(EXPECT_MESSAGE) .into(); + + if should_log { + println!( + "let {} = taffy.new_leaf_with_context({:?}, MEASURE_CONTEXT).unwrap()", + layout_id_to_var_name(layout_id), + serde_json::to_string(&style.to_taffy(rem_size)).unwrap(), + ); + } + layout_id } @@ -206,13 +256,15 @@ impl TaffyLayoutEngine { ) .expect(EXPECT_MESSAGE); - LAYOUT_ID_TO_DEBUG.with_borrow(|layout_id_to_debug| { - println!("Layout ID Debug: {:?}", layout_id_to_debug); - }); + /* + LAYOUT_ID_TO_DEBUG.with_borrow(|layout_id_to_debug| { + println!("Layout ID Debug: {:?}", layout_id_to_debug); + }); - CONTAINER_LAYOUT_ID_TO_DEBUG.with_borrow(|layout_id| { - println!("Container Layout ID Debug: {:?}\n", layout_id); - }); + CONTAINER_LAYOUT_ID_TO_DEBUG.with_borrow(|layout_id| { + println!("Container Layout ID Debug: {:?}\n", layout_id); + }); + */ // println!("compute_layout took {:?}", started_at.elapsed()); }