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
strum.workspace = true
sum_tree.workspace = true
taffy = "=0.9.0"
taffy = { version = "=0.9.0", features = ["serde"] }
thiserror.workspace = true
util.workspace = true
uuid.workspace = true

View file

@ -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<E: Element> Drawable<E> {
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<E: Element> Drawable<E> {
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();
}

View file

@ -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, LOG_TAFFY},
};
use collections::HashMap;
use refineable::Refineable;
@ -1316,6 +1317,17 @@ impl Element for Div {
window: &mut Window,
cx: &mut App,
) -> 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 mut children_bounds = Vec::with_capacity(if has_prepaint_listener {
request_layout.child_layout_ids.len()

View file

@ -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,18 @@ use taffy::{
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<
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";
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();
@ -49,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
@ -64,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::<Vec<_>>()
.join(", ")
);
}
parent_id
};
layout_id
@ -73,7 +114,7 @@ impl TaffyLayoutEngine {
&mut self,
style: Style,
rem_size: Pixels,
measure: impl FnMut(
mut measure: impl FnMut(
Size<Option<Pixels>>,
Size<AvailableSpace>,
&mut Window,
@ -83,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
}
@ -198,6 +256,16 @@ 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());
}

View file

@ -853,25 +853,15 @@ 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:"))
.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()
.px_2()
@ -882,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()