WIP

Nathan Sobo created

Change summary

Cargo.lock                                     |   4 
crates/gpui/Cargo.toml                         |   1 
crates/gpui/playground/ui/Cargo.toml           |   3 
crates/gpui/playground/ui/src/node.rs          | 287 +++++++++++--------
crates/gpui/playground/ui/src/playground_ui.rs |  36 ++
crates/gpui/playground/ui/src/tokens.rs        |  20 
crates/gpui/src/app.rs                         |   4 
crates/gpui/src/app/window.rs                  |  24 -
crates/gpui/src/color.rs                       |   2 
crates/gpui/src/elements.rs                    |  14 
crates/gpui/src/elements/text.rs               |  52 ---
crates/gpui/src/fonts.rs                       |  41 +-
12 files changed, 240 insertions(+), 248 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -3085,7 +3085,6 @@ dependencies = [
  "metal",
  "num_cpus",
  "objc",
- "optional_struct",
  "ordered-float",
  "parking",
  "parking_lot 0.11.2",
@@ -5175,7 +5174,10 @@ dependencies = [
 name = "playground_ui"
 version = "0.1.0"
 dependencies = [
+ "derive_more",
  "gpui",
+ "log",
+ "optional_struct",
 ]
 
 [[package]]

crates/gpui/Cargo.toml 🔗

@@ -31,7 +31,6 @@ itertools = "0.10"
 lazy_static.workspace = true
 log.workspace = true
 num_cpus = "1.13"
-optional_struct = "0.3.1"
 ordered-float.workspace = true
 parking = "2.0.0"
 parking_lot.workspace = true

crates/gpui/playground/ui/Cargo.toml 🔗

@@ -9,4 +9,7 @@ path = "src/playground_ui.rs"
 crate-type = ["dylib"]
 
 [dependencies]
+derive_more = "0.99.17"
 gpui = { path = "../.." }
+log.workspace = true
+optional_struct = "0.3.1"

crates/gpui/src/elements/node.rs → crates/gpui/playground/ui/src/node.rs 🔗

@@ -1,5 +1,6 @@
-use super::layout_highlighted_chunks;
-use crate::{
+use derive_more::Add;
+use gpui::elements::layout_highlighted_chunks;
+use gpui::{
     color::Color,
     fonts::HighlightStyle,
     geometry::{
@@ -11,9 +12,8 @@ use crate::{
     serde_json::Value,
     text_layout::{Line, ShapedBoundary},
     AnyElement, AppContext, Element, LayoutContext, PaintContext, Quad, SceneBuilder,
-    SizeConstraint, Vector2FExt, View, ViewContext,
+    SizeConstraint, View, ViewContext,
 };
-use derive_more::Add;
 use length::{Length, Rems};
 use log::warn;
 use optional_struct::*;
@@ -28,6 +28,7 @@ use std::{
 pub struct Node<V: View> {
     style: NodeStyle,
     children: Vec<AnyElement<V>>,
+    id: Option<Cow<'static, str>>,
 }
 
 pub fn node<V: View>(child: impl Element<V>) -> Node<V> {
@@ -44,7 +45,7 @@ pub fn row<V: View>() -> Node<V> {
             axis: Axis3d::X,
             ..Default::default()
         },
-        children: Default::default(),
+        ..Default::default()
     }
 }
 
@@ -54,7 +55,7 @@ pub fn stack<V: View>() -> Node<V> {
             axis: Axis3d::Z,
             ..Default::default()
         },
-        children: Default::default(),
+        ..Default::default()
     }
 }
 
@@ -63,11 +64,17 @@ impl<V: View> Default for Node<V> {
         Self {
             style: Default::default(),
             children: Default::default(),
+            id: None,
         }
     }
 }
 
 impl<V: View> Node<V> {
+    pub fn id(mut self, id: impl Into<Cow<'static, str>>) -> Self {
+        self.id = Some(id.into());
+        self
+    }
+
     pub fn child(mut self, child: impl Element<V>) -> Self {
         self.children.push(child.into_any());
         self
@@ -148,26 +155,65 @@ impl<V: View> Node<V> {
         view: &mut V,
         cx: &mut LayoutContext<V>,
     ) -> Vector2F {
+        eprintln!(
+            "{}: max_size = {:?}",
+            self.id.as_deref().unwrap_or(""),
+            max_size
+        );
+
+        let mut remaining_flex: f32 = 0.;
         layout.margins = self.style.margins.fixed_pixels(rem_pixels);
+        remaining_flex += self.style.margins.flex().get(axis);
         layout.padding = self.style.padding.fixed_pixels(rem_pixels);
+        remaining_flex += self.style.padding.flex().get(axis);
 
-        let padded_max =
-            max_size - layout.margins.size() - self.style.borders.width - layout.padding.size();
-        let mut remaining_length = padded_max.get(axis);
+        let mut padded_max =
+            max_size - layout.margins.size() - self.style.borders.size() - layout.padding.size();
+
+        match self.style.size.width {
+            Length::Hug => {}
+            Length::Fixed(width) => {
+                padded_max.set_x(width.to_pixels(rem_pixels));
+            }
+            Length::Auto { min, max, .. } => padded_max.set_x(
+                padded_max
+                    .x()
+                    .clamp(min.to_pixels(rem_pixels), max.to_pixels(rem_pixels)),
+            ),
+        };
+        match self.style.size.height {
+            Length::Hug => {}
+            Length::Fixed(height) => padded_max.set_y(height.to_pixels(rem_pixels)),
+            Length::Auto { min, max, .. } => padded_max.set_y(
+                padded_max
+                    .y()
+                    .clamp(min.to_pixels(rem_pixels), max.to_pixels(rem_pixels)),
+            ),
+        };
+
+        let mut remaining_length =
+            padded_max.get(axis) - self.style.size.get(axis).fixed_pixels(rem_pixels);
+        dbg!(padded_max, remaining_length);
 
         // Pass 1: Total up flex units and layout inflexible children.
         //
         // Consume the remaining length as we layout inflexible children, so that any
         // remaining length can be distributed among flexible children in the next pass.
-        let mut remaining_flex: f32 = 0.;
         let mut cross_axis_max: f32 = 0.;
         let cross_axis = axis.rotate();
 
         // Fixed children are unconstrained along the primary axis, and constrained to
         // the padded max size along the cross axis.
-        let mut child_constraint =
+        let child_constraint =
             SizeConstraint::loose(Vector2F::infinity().set(cross_axis, padded_max.get(cross_axis)));
 
+        eprintln!(
+            "{}: child_max = {:?}, remaining_length: {}",
+            self.id.as_deref().unwrap_or(""),
+            child_constraint.max,
+            remaining_length
+        );
+
         for child in &mut self.children {
             if let Some(child_flex) = child
                 .metadata::<NodeStyle>()
@@ -181,14 +227,26 @@ impl<V: View> Node<V> {
             }
         }
 
+        eprintln!(
+            "{}: child_max = {:?}, remaining_length: {}",
+            self.id.as_deref().unwrap_or(""),
+            child_constraint.max,
+            remaining_length
+        );
+
         // Pass 2: Allocate the remaining space among flexible lengths along the primary axis.
         if remaining_flex > 0. {
+            dbg!(self.id.as_deref(), remaining_length, remaining_flex);
+
             // Add flex pixels from margin and padding.
             *layout.margins.start_mut(axis) += self.style.margins.start(axis).flex_pixels(
                 rem_pixels,
                 &mut remaining_flex,
                 &mut remaining_length,
             );
+
+            dbg!(self.id.as_deref(), layout.margins.start(axis));
+
             *layout.padding.start_mut(axis) += self.style.padding.start(axis).flex_pixels(
                 rem_pixels,
                 &mut remaining_flex,
@@ -224,16 +282,6 @@ impl<V: View> Node<V> {
             );
         }
 
-        let mut size = max_size;
-
-        match self.style.size.get(axis) {
-            Length::Hug => {
-                size.set(axis, max_size.get(axis) - remaining_length);
-            }
-            Length::Fixed(_) => {}
-            Length::Auto { flex, min, max } => todo!(),
-        };
-
         let width = match self.style.size.width {
             Length::Hug => match axis {
                 Axis2d::X => max_size.get(axis) - remaining_length,
@@ -245,7 +293,7 @@ impl<V: View> Node<V> {
                 }
             },
             Length::Fixed(width) => width.to_pixels(rem_pixels),
-            Length::Auto { flex, min, max } => max_size
+            Length::Auto { min, max, .. } => max_size
                 .x()
                 .clamp(min.to_pixels(rem_pixels), max.to_pixels(rem_pixels)),
         };
@@ -261,16 +309,19 @@ impl<V: View> Node<V> {
                 }
             },
             Length::Fixed(height) => height.to_pixels(rem_pixels),
-            Length::Auto { flex, min, max } => max_size
+            Length::Auto { min, max, .. } => max_size
                 .y()
                 .clamp(min.to_pixels(rem_pixels), max.to_pixels(rem_pixels)),
         };
 
-        let length = max_size.get(axis) - remaining_length;
-        match axis {
-            Axis2d::X => vec2f(length, cross_axis_max),
-            Axis2d::Y => vec2f(cross_axis_max, length),
-        }
+        eprintln!(
+            "{}: size = {} {}",
+            self.id.as_deref().unwrap_or(""),
+            width,
+            height
+        );
+
+        vec2f(width, height)
     }
 
     fn paint_children_xy(
@@ -287,99 +338,45 @@ impl<V: View> Node<V> {
         let mut child_origin = bounds.origin();
 
         // Align all children together along the primary axis
-        let mut align_horizontally = false;
-        let mut align_vertically = false;
-        match axis {
-            Axis2d::X => align_horizontally = true,
-            Axis2d::Y => align_vertically = true,
-        }
-        align_child(
-            &mut child_origin,
-            parent_size,
-            layout.content_size,
-            self.style.align.0,
-            align_horizontally,
-            align_vertically,
-        );
+        // let mut align_horizontally = false;
+        // let mut align_vertically = false;
+        // match axis {
+        //     Axis2d::X => align_horizontally = true,
+        //     Axis2d::Y => align_vertically = true,
+        // }
+        // align_child(
+        //     &mut child_origin,
+        //     parent_size,
+        //     layout.content_size,
+        //     self.style.align.0,
+        //     align_horizontally,
+        //     align_vertically,
+        // );
 
         for child in &mut self.children {
             // Align each child along the cross axis
-            align_horizontally = !align_horizontally;
-            align_vertically = !align_vertically;
-            align_child(
-                &mut child_origin,
-                parent_size,
-                child.size(),
-                self.style.align.0,
-                align_horizontally,
-                align_vertically,
+            // align_horizontally = !align_horizontally;
+            // align_vertically = !align_vertically;
+            // align_child(
+            //     &mut child_origin,
+            //     parent_size,
+            //     child.size(),
+            //     self.style.align.0,
+            //     align_horizontally,
+            //     align_vertically,
+            // );
+            //
+            eprintln!(
+                "{}: child origin {:?}",
+                self.id.as_deref().unwrap_or(""),
+                child_origin
             );
-
             child.paint(scene, child_origin, visible_bounds, view, cx);
 
             // Advance along the primary axis by the size of this child
-            match axis {
-                Axis2d::X => child_origin.set_x(child_origin.x() + child.size().x()),
-                Axis2d::Y => child_origin.set_y(child_origin.y() + child.size().y()),
-            }
+            child_origin.set(axis, child_origin.get(axis) + child.size().get(axis));
         }
     }
-
-    // fn layout_stacked_children(
-    //     &mut self,
-    //     constraint: SizeConstraint,
-    //     view: &mut V,
-    //     cx: &mut LayoutContext<V>,
-    // ) -> Vector2F {
-    //     let mut size = Vector2F::zero();
-
-    //     for child in &mut self.children {
-    //         let child_size = child.layout(constraint, view, cx);
-    //         size.set_x(size.x().max(child_size.x()));
-    //         size.set_y(size.y().max(child_size.y()));
-    //     }
-
-    //     size
-    // }
-
-    // fn inset_size(&self, rem_size: f32) -> Vector2F {
-    //     todo!()
-    //     // self.padding_size(rem_size) + self.border_size() + self.margin_size(rem_size)
-    // }
-
-    //
-    // fn margin_fixed_size(&self, rem_size: f32) -> Vector2F {
-    //     self.style.margins.fixed().to_pixels(rem_size)
-    // }
-
-    // fn padding_size(&self, rem_size: f32) -> Vector2F {
-    //     // We need to account for auto padding
-    //     todo!()
-    //     // vec2f(
-    //     //     (self.style.padding.left + self.style.padding.right).to_pixels(rem_size),
-    //     //     (self.style.padding.top + self.style.padding.bottom).to_pixels(rem_size),
-    //     // )
-    // }
-
-    // fn border_size(&self) -> Vector2F {
-    //     let mut x = 0.0;
-    //     if self.style.borders.left {
-    //         x += self.style.borders.width;
-    //     }
-    //     if self.style.borders.right {
-    //         x += self.style.borders.width;
-    //     }
-
-    //     let mut y = 0.0;
-    //     if self.style.borders.top {
-    //         y += self.style.borders.width;
-    //     }
-    //     if self.style.borders.bottom {
-    //         y += self.style.borders.width;
-    //     }
-
-    //     vec2f(x, y)
-    // }
 }
 
 impl<V: View> Element<V> for Node<V> {
@@ -412,7 +409,8 @@ impl<V: View> Element<V> for Node<V> {
         view: &mut V,
         cx: &mut PaintContext<V>,
     ) -> Self::PaintState {
-        let rem_pixels = cx.rem_pixels();
+        dbg!(&layout);
+
         let margined_bounds = RectF::from_points(
             bounds.origin() + vec2f(layout.margins.left, layout.margins.top),
             bounds.lower_right() - vec2f(layout.margins.right, layout.margins.bottom),
@@ -442,6 +440,12 @@ impl<V: View> Element<V> for Node<V> {
         let Fill::Color(fill_color) = self.style.fill;
         let is_fill_visible = !fill_color.is_fully_transparent();
         if is_fill_visible || self.style.borders.is_visible() {
+            eprintln!(
+                "{}: paint background: {:?}",
+                self.id.as_deref().unwrap_or(""),
+                margined_bounds
+            );
+
             scene.push_quad(Quad {
                 bounds: margined_bounds,
                 background: is_fill_visible.then_some(fill_color),
@@ -688,8 +692,7 @@ impl Size<Rems> {
     }
 }
 
-// Sides?
-#[derive(Clone, Default)]
+#[derive(Clone, Default, Debug)]
 struct Edges<T> {
     top: T,
     bottom: T,
@@ -1083,7 +1086,7 @@ pub fn text<V: View>(text: impl Into<Cow<'static, str>>) -> Node<V> {
     })
 }
 
-#[derive(Default)]
+#[derive(Default, Debug)]
 pub struct NodeLayout {
     content_size: Vector2F,
     margins: Edges<f32>,
@@ -1194,6 +1197,8 @@ impl<V: View> Element<V> for Text {
         _: &mut V,
         cx: &mut PaintContext<V>,
     ) -> Self::PaintState {
+        dbg!(bounds);
+
         let mut origin = bounds.origin();
         let empty = Vec::new();
         let mut callback = |_, _, _: &mut SceneBuilder, _: &mut AppContext| {};
@@ -1375,3 +1380,53 @@ where
         (None, None) => None,
     }
 }
+
+trait Vector2FExt {
+    fn infinity() -> Self;
+    fn get(self, axis: Axis2d) -> f32;
+    fn set(&mut self, axis: Axis2d, value: f32) -> Self;
+}
+
+impl Vector2FExt for Vector2F {
+    fn infinity() -> Self {
+        vec2f(f32::INFINITY, f32::INFINITY)
+    }
+
+    fn get(self, axis: Axis2d) -> f32 {
+        match axis {
+            Axis2d::X => self.x(),
+            Axis2d::Y => self.y(),
+        }
+    }
+
+    // TODO: It's a bit weird to mutate and return.
+    fn set(&mut self, axis: Axis2d, value: f32) -> Self {
+        match axis {
+            Axis2d::X => self.set_x(value),
+            Axis2d::Y => self.set_y(value),
+        }
+        *self
+    }
+}
+
+trait ElementExt<V: View> {
+    fn margin_left(self, margin_left: impl Into<Length>) -> Node<V>
+    where
+        Self: Element<V> + Sized,
+    {
+        node(self).margin_left(margin_left)
+    }
+}
+
+impl<V, E> ElementExt<V> for E
+where
+    V: View,
+    E: Element<V>,
+{
+    fn margin_left(self, margin_left: impl Into<Length>) -> Node<V>
+    where
+        Self: Sized,
+    {
+        node(self).margin_left(margin_left)
+    }
+}

crates/gpui/playground/ui/src/playground_ui.rs 🔗

@@ -1,10 +1,12 @@
-use gpui::{
-    elements::node::{column, length::auto, row, text},
-    AnyElement, Element, LayoutContext, View, ViewContext,
+use gpui::{color::Color, AnyElement, Element, LayoutContext, View, ViewContext};
+use node::{
+    length::{auto, rems},
+    *,
 };
 use std::{borrow::Cow, cell::RefCell, marker::PhantomData, rc::Rc};
 use tokens::{margin::m4, text::lg};
 
+mod node;
 mod tokens;
 
 #[derive(Element, Clone, Default)]
@@ -13,13 +15,32 @@ pub struct Playground<V: View>(PhantomData<V>);
 impl<V: View> Playground<V> {
     pub fn render(&mut self, _: &mut V, _: &mut gpui::ViewContext<V>) -> AnyElement<V> {
         column()
+            .id("red column")
             .width(auto())
+            .height(auto())
+            .fill(Color::red())
             .child(
-                dialog("This is a dialog", "You would see a description here.")
-                    .button("Button 1", 1, Self::action_1)
-                    .button("Button 2", 2, Self::action_2),
+                row()
+                    .id("green row")
+                    .width(auto())
+                    .height(rems(20.))
+                    .margin_left(auto())
+                    .fill(Color::green()), // .child(
+                                           //     row()
+                                           //         .id("blue child")
+                                           //         .height(auto())
+                                           //         .width(rems(20.))
+                                           //         .fill(Color::blue())
+                                           //         .margin_left(auto()),
+                                           // ),
             )
             .into_any()
+
+        // .child(
+        //     dialog("This is a dialog", "You would see a description here.")
+        //         .button("Button 1", 1, Self::action_1)
+        //         .button("Button 2", 2, Self::action_2),
+        // )
     }
 
     fn action_1(_: &mut V, data: &usize, _: &mut ViewContext<V>) {
@@ -118,7 +139,8 @@ where
     F: ClickHandler<V, D>,
 {
     fn render(&mut self, _: &mut V, _: &mut LayoutContext<V>) -> AnyElement<V> {
-        todo!()
+        // TODO! Handle click etc
+        row().child(text(self.label.clone())).into_any()
     }
 }
 

crates/gpui/playground/ui/src/tokens.rs 🔗

@@ -1,13 +1,7 @@
-pub mod color {
-    use gpui::color::Color;
-
-    pub fn background(elevation: f32) -> Color {
-        todo!()
-    }
-}
+pub mod color {}
 
 pub mod text {
-    use gpui::elements::node::length::{rems, Rems};
+    use crate::node::length::{rems, Rems};
 
     pub fn xs() -> Rems {
         rems(0.75)
@@ -37,21 +31,21 @@ pub mod text {
         rems(1.875)
     }
 
-    pub fn x4l() -> Rems {
+    pub fn xxxxl() -> Rems {
         rems(2.25)
     }
 
-    pub fn x5l() -> Rems {
+    pub fn xxxxxl() -> Rems {
         rems(3.0)
     }
 
-    pub fn x6l() -> Rems {
+    pub fn xxxxxxl() -> Rems {
         rems(4.0)
     }
 }
 
 pub mod padding {
-    use gpui::elements::node::length::{rems, Rems};
+    use crate::node::length::{rems, Rems};
 
     pub fn p1() -> Rems {
         rems(0.25)
@@ -107,7 +101,7 @@ pub mod padding {
 }
 
 pub mod margin {
-    use gpui::elements::node::length::{rems, Rems};
+    use crate::node::length::{rems, Rems};
 
     pub fn m1() -> Rems {
         rems(0.25)

crates/gpui/src/app.rs 🔗

@@ -3440,7 +3440,7 @@ impl<'a, 'b, 'c, V: View> LayoutContext<'a, 'b, 'c, V> {
         self.text_style_stack
             .last()
             .cloned()
-            .unwrap_or(Default::default())
+            .unwrap_or(Arc::new(TextStyle::default(&self.font_cache)))
     }
 
     pub fn with_text_style<S, F, T>(&mut self, style: S, f: F) -> T
@@ -3506,7 +3506,7 @@ impl<'a, 'b, 'c, V: View> PaintContext<'a, 'b, 'c, V> {
         self.text_style_stack
             .last()
             .cloned()
-            .unwrap_or(Default::default())
+            .unwrap_or(Arc::new(TextStyle::default(&self.font_cache)))
     }
 
     pub fn with_text_style<S, F, T>(&mut self, style: S, f: F) -> T

crates/gpui/src/app/window.rs 🔗

@@ -1,5 +1,5 @@
 use crate::{
-    elements::{node::Axis2d, AnyRootElement},
+    elements::AnyRootElement,
     geometry::rect::RectF,
     json::ToJson,
     keymap_matcher::{Binding, KeymapContext, Keystroke, MatchResult},
@@ -1248,38 +1248,16 @@ impl Column for Axis {
 }
 
 pub trait Vector2FExt {
-    fn infinity() -> Self;
     fn along(self, axis: Axis) -> f32;
-    fn get(self, axis: Axis2d) -> f32;
-    fn set(&mut self, axis: Axis2d, value: f32) -> Self;
 }
 
 impl Vector2FExt for Vector2F {
-    fn infinity() -> Self {
-        Self::new(f32::INFINITY, f32::INFINITY)
-    }
-
     fn along(self, axis: Axis) -> f32 {
         match axis {
             Axis::Horizontal => self.x(),
             Axis::Vertical => self.y(),
         }
     }
-
-    fn get(self, axis: Axis2d) -> f32 {
-        match axis {
-            Axis2d::X => self.x(),
-            Axis2d::Y => self.y(),
-        }
-    }
-
-    fn set(&mut self, axis: Axis2d, value: f32) -> Self {
-        match axis {
-            Axis2d::X => self.set_x(value),
-            Axis2d::Y => self.set_y(value),
-        }
-        *self
-    }
 }
 
 pub trait RectFExt {

crates/gpui/src/color.rs 🔗

@@ -18,7 +18,7 @@ use serde_json::json;
 pub struct Color(#[schemars(with = "String")] ColorU);
 
 pub fn color(rgba: u32) -> Color {
-    color(rgba)
+    Color::from_u32(rgba)
 }
 
 pub fn rgb(r: f32, g: f32, b: f32) -> Color {

crates/gpui/src/elements.rs 🔗

@@ -12,7 +12,6 @@ mod keystroke_label;
 mod label;
 mod list;
 mod mouse_event_handler;
-pub mod node;
 mod overlay;
 mod resizable;
 mod stack;
@@ -28,11 +27,7 @@ pub use self::{
 };
 pub use crate::window::ChildView;
 
-use self::{
-    clipped::Clipped,
-    expanded::Expanded,
-    node::{length::Length, node, Node},
-};
+use self::{clipped::Clipped, expanded::Expanded};
 use crate::{
     geometry::{
         rect::RectF,
@@ -204,13 +199,6 @@ pub trait Element<V: View>: 'static {
     {
         MouseEventHandler::for_child(self.into_any(), region_id)
     }
-
-    fn margin_left(self, margin_left: impl Into<Length>) -> Node<V>
-    where
-        Self: Sized,
-    {
-        node(self).margin_left(margin_left)
-    }
 }
 
 trait AnyElementState<V: View> {

crates/gpui/src/elements/text.rs 🔗

@@ -400,58 +400,6 @@ pub fn layout_highlighted_chunks<'a>(
     layouts
 }
 
-// Need to figure out how fonts flow through the tree to implement this.
-impl<V: View> Element<V> for Cow<'static, str> {
-    type LayoutState = ();
-
-    type PaintState = ();
-
-    fn layout(
-        &mut self,
-        constraint: SizeConstraint,
-        view: &mut V,
-        cx: &mut LayoutContext<V>,
-    ) -> (Vector2F, Self::LayoutState) {
-        todo!()
-    }
-
-    fn paint(
-        &mut self,
-        scene: &mut SceneBuilder,
-        bounds: RectF,
-        visible_bounds: RectF,
-        layout: &mut Self::LayoutState,
-        view: &mut V,
-        cx: &mut PaintContext<V>,
-    ) -> Self::PaintState {
-        todo!()
-    }
-
-    fn rect_for_text_range(
-        &self,
-        range_utf16: Range<usize>,
-        bounds: RectF,
-        visible_bounds: RectF,
-        layout: &Self::LayoutState,
-        paint: &Self::PaintState,
-        view: &V,
-        cx: &ViewContext<V>,
-    ) -> Option<RectF> {
-        todo!()
-    }
-
-    fn debug(
-        &self,
-        bounds: RectF,
-        layout: &Self::LayoutState,
-        paint: &Self::PaintState,
-        view: &V,
-        cx: &ViewContext<V>,
-    ) -> crate::serde_json::Value {
-        todo!()
-    }
-}
-
 #[cfg(test)]
 mod tests {
     use super::*;

crates/gpui/src/fonts.rs 🔗

@@ -223,6 +223,27 @@ impl TextStyle {
         })
     }
 
+    pub fn default(font_cache: &FontCache) -> Self {
+        let font_family_id = font_cache.known_existing_family();
+        let font_id = font_cache
+            .select_font(font_family_id, &Default::default())
+            .expect("did not have any font in system-provided family");
+        let font_family_name = font_cache
+            .family_name(font_family_id)
+            .expect("we loaded this family from the font cache, so this should work");
+
+        Self {
+            color: Color::default(),
+            font_family_name,
+            font_family_id,
+            font_id,
+            font_size: 14.,
+            font_properties: Default::default(),
+            underline: Default::default(),
+            soft_wrap: true,
+        }
+    }
+
     pub fn with_font_size(mut self, font_size: f32) -> Self {
         self.font_size = font_size;
         self
@@ -350,25 +371,7 @@ impl Default for TextStyle {
             let font_cache = font_cache
                 .as_ref()
                 .expect("TextStyle::default can only be called within a call to with_font_cache");
-
-            let font_family_id = font_cache.known_existing_family();
-            let font_id = font_cache
-                .select_font(font_family_id, &Default::default())
-                .expect("did not have any font in system-provided family");
-            let font_family_name = font_cache
-                .family_name(font_family_id)
-                .expect("we loaded this family from the font cache, so this should work");
-
-            Self {
-                color: Color::default(),
-                font_family_name,
-                font_family_id,
-                font_id,
-                font_size: 14.,
-                font_properties: Default::default(),
-                underline: Default::default(),
-                soft_wrap: true,
-            }
+            Self::default(font_cache)
         })
     }
 }