Compare commits

...
Sign in to create a new pull request.

3 commits

Author SHA1 Message Date
Michael Sloan
1c2df4a5c6
Instead try to output something close to taffy api usage 2025-08-15 16:57:59 -06:00
Michael Sloan
9d9b625483
Simplify open router config to make layout structure simpler 2025-08-15 16:56:57 -06:00
Michael Sloan
297fd858e8
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
2025-08-14 19:10:19 -06:00
5 changed files with 117 additions and 29 deletions

View file

@ -121,7 +121,7 @@ smallvec.workspace = true
smol.workspace = true smol.workspace = true
strum.workspace = true strum.workspace = true
sum_tree.workspace = true sum_tree.workspace = true
taffy = "=0.9.0" taffy = { version = "=0.9.0", features = ["serde"] }
thiserror.workspace = true thiserror.workspace = true
util.workspace = true util.workspace = true
uuid.workspace = true uuid.workspace = true

View file

@ -34,7 +34,7 @@
use crate::{ use crate::{
App, ArenaBox, AvailableSpace, Bounds, Context, DispatchNodeId, ELEMENT_ARENA, ElementId, App, ArenaBox, AvailableSpace, Bounds, Context, DispatchNodeId, ELEMENT_ARENA, ElementId,
FocusHandle, InspectorElementId, LayoutId, Pixels, Point, Size, Style, Window, FocusHandle, InspectorElementId, LayoutId, Pixels, Point, Size, Style, Window,
util::FluentBuilder, taffy::LOG_TAFFY, util::FluentBuilder,
}; };
use derive_more::{Deref, DerefMut}; use derive_more::{Deref, DerefMut};
pub(crate) use smallvec::SmallVec; pub(crate) use smallvec::SmallVec;
@ -372,6 +372,22 @@ impl<E: Element> Drawable<E> {
inspector_id = None; 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( let (layout_id, request_layout) = self.element.request_layout(
global_id.as_ref(), global_id.as_ref(),
inspector_id.as_ref(), inspector_id.as_ref(),
@ -379,6 +395,14 @@ impl<E: Element> Drawable<E> {
cx, 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() { if global_id.is_some() {
window.element_id_stack.pop(); window.element_id_stack.pop();
} }

View file

@ -23,6 +23,7 @@ use crate::{
MouseClickEvent, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Overflow, ParentElement, Pixels, MouseClickEvent, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Overflow, ParentElement, Pixels,
Point, Render, ScrollWheelEvent, SharedString, Size, Style, StyleRefinement, Styled, Task, Point, Render, ScrollWheelEvent, SharedString, Size, Style, StyleRefinement, Styled, Task,
TooltipId, Visibility, Window, WindowControlArea, point, px, size, TooltipId, Visibility, Window, WindowControlArea, point, px, size,
taffy::{CONTAINER_LAYOUT_ID_TO_DEBUG, LAYOUT_ID_TO_DEBUG, LOG_TAFFY},
}; };
use collections::HashMap; use collections::HashMap;
use refineable::Refineable; use refineable::Refineable;
@ -1316,6 +1317,17 @@ impl Element for Div {
window: &mut Window, window: &mut Window,
cx: &mut App, cx: &mut App,
) -> Option<Hitbox> { ) -> Option<Hitbox> {
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 has_prepaint_listener = self.prepaint_listener.is_some();
let mut children_bounds = Vec::with_capacity(if has_prepaint_listener { let mut children_bounds = Vec::with_capacity(if has_prepaint_listener {
request_layout.child_layout_ids.len() request_layout.child_layout_ids.len()

View file

@ -3,7 +3,7 @@ use crate::{
}; };
use collections::{FxHashMap, FxHashSet}; use collections::{FxHashMap, FxHashSet};
use smallvec::SmallVec; use smallvec::SmallVec;
use std::{fmt::Debug, ops::Range}; use std::{cell::RefCell, fmt::Debug, ops::Range};
use taffy::{ use taffy::{
TaffyTree, TraversePartialTree as _, TaffyTree, TraversePartialTree as _,
geometry::{Point as TaffyPoint, Rect as TaffyRect, Size as TaffySize}, geometry::{Point as TaffyPoint, Rect as TaffyRect, Size as TaffySize},
@ -11,6 +11,18 @@ use taffy::{
tree::NodeId, tree::NodeId,
}; };
thread_local! {
pub static LAYOUT_ID_TO_DEBUG: RefCell<Option<LayoutId>> = const { RefCell::new(None) };
}
thread_local! {
pub static CONTAINER_LAYOUT_ID_TO_DEBUG: RefCell<Option<LayoutId>> = const { RefCell::new(None) };
}
thread_local! {
pub static LOG_TAFFY: RefCell<bool> = const { RefCell::new(false) };
}
type NodeMeasureFn = Box< type NodeMeasureFn = Box<
dyn FnMut(Size<Option<Pixels>>, Size<AvailableSpace>, &mut Window, &mut App) -> Size<Pixels>, dyn FnMut(Size<Option<Pixels>>, Size<AvailableSpace>, &mut Window, &mut App) -> Size<Pixels>,
>; >;
@ -26,6 +38,11 @@ pub struct TaffyLayoutEngine {
const EXPECT_MESSAGE: &str = "we should avoid taffy layout errors by construction if possible"; 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 { impl TaffyLayoutEngine {
pub fn new() -> Self { pub fn new() -> Self {
let mut taffy = TaffyTree::new(); let mut taffy = TaffyTree::new();
@ -49,12 +66,23 @@ impl TaffyLayoutEngine {
rem_size: Pixels, rem_size: Pixels,
children: &[LayoutId], children: &[LayoutId],
) -> LayoutId { ) -> LayoutId {
let should_log = LOG_TAFFY.with_borrow(|log_taffy| *log_taffy);
let taffy_style = style.to_taffy(rem_size); let taffy_style = style.to_taffy(rem_size);
let layout_id = if children.is_empty() { let layout_id = if children.is_empty() {
self.taffy let layout_id = self
.taffy
.new_leaf(taffy_style) .new_leaf(taffy_style)
.expect(EXPECT_MESSAGE) .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 { } else {
let parent_id = self let parent_id = self
.taffy .taffy
@ -64,6 +92,19 @@ impl TaffyLayoutEngine {
}) })
.expect(EXPECT_MESSAGE) .expect(EXPECT_MESSAGE)
.into(); .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::<Vec<_>>()
.join(", ")
);
}
parent_id parent_id
}; };
layout_id layout_id
@ -73,7 +114,7 @@ impl TaffyLayoutEngine {
&mut self, &mut self,
style: Style, style: Style,
rem_size: Pixels, rem_size: Pixels,
measure: impl FnMut( mut measure: impl FnMut(
Size<Option<Pixels>>, Size<Option<Pixels>>,
Size<AvailableSpace>, Size<AvailableSpace>,
&mut Window, &mut Window,
@ -83,16 +124,33 @@ impl TaffyLayoutEngine {
) -> LayoutId { ) -> LayoutId {
let taffy_style = style.to_taffy(rem_size); let taffy_style = style.to_taffy(rem_size);
let should_log = LOG_TAFFY.with_borrow(|log_taffy| *log_taffy);
let layout_id = self let layout_id = self
.taffy .taffy
.new_leaf_with_context( .new_leaf_with_context(
taffy_style, taffy_style,
NodeContext { 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) .expect(EXPECT_MESSAGE)
.into(); .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 layout_id
} }
@ -198,6 +256,16 @@ impl TaffyLayoutEngine {
) )
.expect(EXPECT_MESSAGE); .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()); // println!("compute_layout took {:?}", started_at.elapsed());
} }

View file

@ -853,25 +853,15 @@ impl Render for ConfigurationView {
div().child(Label::new("Loading credentials...")).into_any() div().child(Label::new("Loading credentials...")).into_any()
} else if self.should_render_editor(cx) { } else if self.should_render_editor(cx) {
v_flex() v_flex()
.id("open-router-container")
.size_full() .size_full()
.on_action(cx.listener(Self::save_api_key)) .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( .child(
List::new() div()
.child(InstructionListItem::new( .id("api-key-editor")
"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()
.w_full() .w_full()
.my_2() .my_2()
.px_2() .px_2()
@ -882,12 +872,6 @@ impl Render for ConfigurationView {
.rounded_sm() .rounded_sm()
.child(self.render_api_key_editor(cx)), .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() .into_any()
} else { } else {
h_flex() h_flex()