From b9cf5886e43f548442031f3e28b70507b3f0f67e Mon Sep 17 00:00:00 2001 From: Martin Pool Date: Fri, 12 Sep 2025 13:24:04 -0700 Subject: [PATCH] Run doctests in CI and fix up existing doctests (#37851) Follows on from https://github.com/zed-industries/zed/pull/37716#pullrequestreview-3195695110 by @SomeoneToIgnore After this the doctests will be run in CI to check that the examples are still accurate. Note that doctests aren't run by Nextest: you can run them locally with `cargo test --doc`. Summary: * Run tests from CI * Loosen an exact float comparison to match approximately (otherwise it fails) * Fixed one actual bug in the tests for `dilate` where the test code assumed that `dilate` mutates `self` rather than returning a new object * Add some `must_use` on some functions that seemed at risk of similar bugs, following the Rust stdlib style to add it where ignoring the result is almost certainly a bug. * Fix some cases where the doc examples seem to have gone out of date with the code * Add imports to doctests that need them * Add some dev-dependencies to make the tests build * Fix the `key_dispatch` module docstring, which was accidentally attached to objects within that module * Skip some doctest examples that seem like they need an async environment or that just looked hard to get running AI usage: I asked Claude to do some of the repetitive tests. I checked the output and fixed up some things that seemed to not be in the right spirit of the test, or too longwinded. I think we could reasonably run the tests on only Linux to save CI CPU-seconds and latency, but I haven't done that yet, partly because of how it's implemented in the action. Release Notes: - N/A --- .github/actions/run_tests/action.yml | 5 + Cargo.lock | 3 + crates/gpui/src/action.rs | 15 ++- crates/gpui/src/color.rs | 6 +- crates/gpui/src/geometry.rs | 85 +++++++++------ crates/gpui/src/gpui.rs | 3 +- crates/gpui/src/key_dispatch.rs | 102 +++++++++--------- crates/gpui/src/taffy.rs | 1 + crates/gpui/src/window.rs | 4 +- crates/proto/src/error.rs | 10 +- crates/refineable/src/refineable.rs | 7 +- crates/repl/src/outputs/plain.rs | 6 +- crates/repl/src/outputs/table.rs | 4 +- crates/settings_ui_macros/Cargo.toml | 3 + .../src/settings_ui_macros.rs | 2 +- crates/telemetry/src/telemetry.rs | 1 + crates/terminal/src/terminal.rs | 3 +- crates/ui/src/components/avatar.rs | 5 +- crates/ui/src/components/banner.rs | 11 +- crates/ui/src/components/button/button.rs | 12 +-- crates/ui/src/components/callout.rs | 11 +- crates/ui/src/components/chip.rs | 4 +- crates/ui/src/components/facepile.rs | 8 +- crates/ui/src/components/keybinding_hint.rs | 79 +++++++++++--- crates/ui/src/components/label/label.rs | 9 +- crates/ui/src/components/toggle.rs | 5 +- crates/ui_macros/Cargo.toml | 4 + crates/ui_macros/src/ui_macros.rs | 1 + 28 files changed, 262 insertions(+), 147 deletions(-) diff --git a/.github/actions/run_tests/action.yml b/.github/actions/run_tests/action.yml index e46bc26945e4b5f94ad9f98a882aaa51fc6189af..7a4d3e948bb4d205412ca93fa5cc0e1351e65ebd 100644 --- a/.github/actions/run_tests/action.yml +++ b/.github/actions/run_tests/action.yml @@ -21,3 +21,8 @@ runs: - name: Run tests shell: bash -euxo pipefail {0} run: cargo nextest run --workspace --no-fail-fast + + - name: Run doctests + shell: bash -euxo pipefail {0} + # Nextest currently doesn't support doctests + run: cargo test --workspace --doc --no-fail-fast diff --git a/Cargo.lock b/Cargo.lock index 987114a61bda04fb2a606d184a6b9c4ae1a85a40..ae72bbdff315dfe1dd7073458afa9260ad4a35c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14941,6 +14941,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", + "settings", "syn 2.0.101", "workspace-hack", ] @@ -17660,8 +17661,10 @@ dependencies = [ name = "ui_macros" version = "0.1.0" dependencies = [ + "component", "quote", "syn 2.0.101", + "ui", "workspace-hack", ] diff --git a/crates/gpui/src/action.rs b/crates/gpui/src/action.rs index 0b824fec34aee7abcb2dbba285265c79b6851d16..38e94aa356dcb7ea1f0f988d1407471bfc0d3a84 100644 --- a/crates/gpui/src/action.rs +++ b/crates/gpui/src/action.rs @@ -13,6 +13,7 @@ use std::{ /// For example: /// /// ``` +/// use gpui::actions; /// actions!(editor, [MoveUp, MoveDown, MoveLeft, MoveRight, Newline]); /// ``` /// @@ -45,6 +46,7 @@ macro_rules! actions { /// struct action for each listed action name in the given namespace. /// /// ``` +/// use gpui::actions; /// actions!(editor, [MoveUp, MoveDown, MoveLeft, MoveRight, Newline]); /// ``` /// @@ -55,6 +57,7 @@ macro_rules! actions { /// More complex data types can also be actions, by using the derive macro for `Action`: /// /// ``` +/// use gpui::Action; /// #[derive(Clone, PartialEq, serde::Deserialize, schemars::JsonSchema, Action)] /// #[action(namespace = editor)] /// pub struct SelectNext { @@ -93,14 +96,22 @@ macro_rules! actions { /// `main`. /// /// ``` -/// #[derive(gpui::private::serde::Deserialize, std::cmp::PartialEq, std::clone::Clone)] +/// use gpui::{SharedString, register_action}; +/// #[derive(Clone, PartialEq, Eq, serde::Deserialize, schemars::JsonSchema)] /// pub struct Paste { /// pub content: SharedString, /// } /// /// impl gpui::Action for Paste { -/// ///... +/// # fn boxed_clone(&self) -> Box { unimplemented!()} +/// # fn partial_eq(&self, other: &dyn gpui::Action) -> bool { unimplemented!() } +/// # fn name(&self) -> &'static str { "Paste" } +/// # fn name_for_type() -> &'static str { "Paste" } +/// # fn build(value: serde_json::Value) -> anyhow::Result> { +/// # unimplemented!() +/// # } /// } +/// /// register_action!(Paste); /// ``` pub trait Action: Any + Send { diff --git a/crates/gpui/src/color.rs b/crates/gpui/src/color.rs index 93c69744a6f9f3cc74e7696e9edf49001587376b..c6c4cdc77b133105a7c233417efae06d5c7aa220 100644 --- a/crates/gpui/src/color.rs +++ b/crates/gpui/src/color.rs @@ -537,9 +537,10 @@ impl Hsla { /// /// Example: /// ``` - /// let color = hlsa(0.7, 1.0, 0.5, 0.7); // A saturated blue + /// use gpui::hsla; + /// let color = hsla(0.7, 1.0, 0.5, 0.7); // A saturated blue /// let faded_color = color.opacity(0.16); - /// assert_eq!(faded_color.a, 0.112); + /// assert!((faded_color.a - 0.112).abs() < 1e-6); /// ``` /// /// This will return a blue color with around ~10% opacity, @@ -568,6 +569,7 @@ impl Hsla { /// /// Example: /// ``` + /// use gpui::hsla; /// let color = hsla(0.7, 1.0, 0.5, 0.7); // A saturated blue /// let faded_color = color.alpha(0.25); /// assert_eq!(faded_color.a, 0.25); diff --git a/crates/gpui/src/geometry.rs b/crates/gpui/src/geometry.rs index 87cabc8cd9f446fddcb5c98dafbdf956eb1efea2..8b98bab2cda655d66d76c39a8570d9b4ffa3d93b 100644 --- a/crates/gpui/src/geometry.rs +++ b/crates/gpui/src/geometry.rs @@ -102,7 +102,7 @@ pub struct Point { /// # Examples /// /// ``` -/// # use gpui::Point; +/// use gpui::point; /// let p = point(10, 20); /// assert_eq!(p.x, 10); /// assert_eq!(p.y, 20); @@ -122,6 +122,7 @@ impl Point { /// # Examples /// /// ``` + /// use gpui::Point; /// let p = Point::new(10, 20); /// assert_eq!(p.x, 10); /// assert_eq!(p.y, 20); @@ -148,6 +149,7 @@ impl Point { /// let p_float = p.map(|coord| coord as f32); /// assert_eq!(p_float, Point { x: 3.0, y: 4.0 }); /// ``` + #[must_use] pub fn map(&self, f: impl Fn(T) -> U) -> Point { Point { x: f(self.x.clone()), @@ -418,7 +420,7 @@ impl Size { /// # Examples /// /// ``` -/// # use gpui::Size; +/// use gpui::size; /// let my_size = size(10, 20); /// assert_eq!(my_size.width, 10); /// assert_eq!(my_size.height, 20); @@ -1025,12 +1027,13 @@ where /// origin: Point { x: 10, y: 10 }, /// size: Size { width: 10, height: 10 }, /// }; - /// bounds.dilate(5); - /// assert_eq!(bounds, Bounds { + /// let expanded_bounds = bounds.dilate(5); + /// assert_eq!(expanded_bounds, Bounds { /// origin: Point { x: 5, y: 5 }, /// size: Size { width: 20, height: 20 }, /// }); /// ``` + #[must_use] pub fn dilate(&self, amount: T) -> Bounds { let double_amount = amount.clone() + amount.clone(); Bounds { @@ -1040,6 +1043,7 @@ where } /// Extends the bounds different amounts in each direction. + #[must_use] pub fn extend(&self, amount: Edges) -> Bounds { Bounds { origin: self.origin.clone() - point(amount.left.clone(), amount.top.clone()), @@ -1359,7 +1363,7 @@ where /// # Examples /// /// ``` - /// # use zed::{Bounds, Corner, Point, Size}; + /// use gpui::{Bounds, Corner, Point, Size}; /// let bounds = Bounds { /// origin: Point { x: 0, y: 0 }, /// size: Size { width: 10, height: 20 }, @@ -1399,7 +1403,7 @@ where /// # Examples /// /// ``` - /// # use gpui::{Point, Bounds}; + /// # use gpui::{Point, Bounds, Size}; /// let bounds = Bounds { /// origin: Point { x: 0, y: 0 }, /// size: Size { width: 10, height: 10 }, @@ -1407,8 +1411,8 @@ where /// let inside_point = Point { x: 5, y: 5 }; /// let outside_point = Point { x: 15, y: 15 }; /// - /// assert!(bounds.contains_point(&inside_point)); - /// assert!(!bounds.contains_point(&outside_point)); + /// assert!(bounds.contains(&inside_point)); + /// assert!(!bounds.contains(&outside_point)); /// ``` pub fn contains(&self, point: &Point) -> bool { point.x >= self.origin.x @@ -1565,6 +1569,7 @@ impl Bounds { /// # Returns /// /// Returns `true` if either the width or the height of the bounds is less than or equal to zero, indicating an empty area. + #[must_use] pub fn is_empty(&self) -> bool { self.size.width <= T::default() || self.size.height <= T::default() } @@ -1621,7 +1626,7 @@ impl Bounds { /// # Examples /// /// ``` - /// # use gpui::{Bounds, Point, Size, Pixels}; + /// # use gpui::{Bounds, Point, Size, Pixels, ScaledPixels, DevicePixels}; /// let bounds = Bounds { /// origin: Point { x: Pixels(10.0), y: Pixels(20.0) }, /// size: Size { width: Pixels(30.0), height: Pixels(40.0) }, @@ -1629,8 +1634,14 @@ impl Bounds { /// let display_scale_factor = 2.0; /// let scaled_bounds = bounds.scale(display_scale_factor); /// assert_eq!(scaled_bounds, Bounds { - /// origin: Point { x: ScaledPixels(20.0), y: ScaledPixels(40.0) }, - /// size: Size { width: ScaledPixels(60.0), height: ScaledPixels(80.0) }, + /// origin: Point { + /// x: ScaledPixels(20.0), + /// y: ScaledPixels(40.0), + /// }, + /// size: Size { + /// width: ScaledPixels(60.0), + /// height: ScaledPixels(80.0) + /// }, /// }); /// ``` pub fn scale(&self, factor: f32) -> Bounds { @@ -1847,7 +1858,7 @@ impl Edges { /// # Examples /// /// ``` - /// # use gpui::Edges; + /// # use gpui::{Edges, Length}; /// let auto_edges = Edges::auto(); /// assert_eq!(auto_edges.top, Length::Auto); /// assert_eq!(auto_edges.right, Length::Auto); @@ -1875,8 +1886,8 @@ impl Edges { /// # Examples /// /// ``` - /// # use gpui::Edges; - /// let no_edges = Edges::zero(); + /// # use gpui::{DefiniteLength, Edges, Length, Pixels}; + /// let no_edges = Edges::::zero(); /// assert_eq!(no_edges.top, Length::Definite(DefiniteLength::from(Pixels(0.)))); /// assert_eq!(no_edges.right, Length::Definite(DefiniteLength::from(Pixels(0.)))); /// assert_eq!(no_edges.bottom, Length::Definite(DefiniteLength::from(Pixels(0.)))); @@ -1905,8 +1916,8 @@ impl Edges { /// # Examples /// /// ``` - /// # use gpui::{px, Edges}; - /// let no_edges = Edges::zero(); + /// # use gpui::{px, DefiniteLength, Edges}; + /// let no_edges = Edges::::zero(); /// assert_eq!(no_edges.top, DefiniteLength::from(px(0.))); /// assert_eq!(no_edges.right, DefiniteLength::from(px(0.))); /// assert_eq!(no_edges.bottom, DefiniteLength::from(px(0.))); @@ -1938,7 +1949,7 @@ impl Edges { /// # Examples /// /// ``` - /// # use gpui::{Edges, DefiniteLength, px, AbsoluteLength, Size}; + /// # use gpui::{Edges, DefiniteLength, px, AbsoluteLength, rems, Size}; /// let edges = Edges { /// top: DefiniteLength::Absolute(AbsoluteLength::Pixels(px(10.0))), /// right: DefiniteLength::Fraction(0.5), @@ -1980,8 +1991,8 @@ impl Edges { /// # Examples /// /// ``` - /// # use gpui::Edges; - /// let no_edges = Edges::zero(); + /// # use gpui::{AbsoluteLength, Edges, Pixels}; + /// let no_edges = Edges::::zero(); /// assert_eq!(no_edges.top, AbsoluteLength::Pixels(Pixels(0.0))); /// assert_eq!(no_edges.right, AbsoluteLength::Pixels(Pixels(0.0))); /// assert_eq!(no_edges.bottom, AbsoluteLength::Pixels(Pixels(0.0))); @@ -2012,7 +2023,7 @@ impl Edges { /// # Examples /// /// ``` - /// # use gpui::{Edges, AbsoluteLength, Pixels, px}; + /// # use gpui::{Edges, AbsoluteLength, Pixels, px, rems}; /// let edges = Edges { /// top: AbsoluteLength::Pixels(px(10.0)), /// right: AbsoluteLength::Rems(rems(1.0)), @@ -2053,7 +2064,7 @@ impl Edges { /// # Examples /// /// ``` - /// # use gpui::{Edges, Pixels}; + /// # use gpui::{Edges, Pixels, ScaledPixels}; /// let edges = Edges { /// top: Pixels(10.0), /// right: Pixels(20.0), @@ -2104,7 +2115,7 @@ impl From for Edges { } /// Identifies a corner of a 2d box. -#[derive(Clone, Copy, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Corner { /// The top left corner TopLeft, @@ -2122,9 +2133,10 @@ impl Corner { /// # Examples /// /// ``` - /// # use zed::Corner; + /// # use gpui::Corner; /// assert_eq!(Corner::TopLeft.opposite_corner(), Corner::BottomRight); /// ``` + #[must_use] pub fn opposite_corner(self) -> Self { match self { Corner::TopLeft => Corner::BottomRight, @@ -2139,10 +2151,11 @@ impl Corner { /// # Examples /// /// ``` - /// # use zed::Corner; + /// # use gpui::{Axis, Corner}; /// let result = Corner::TopLeft.other_side_corner_along(Axis::Horizontal); /// assert_eq!(result, Corner::TopRight); /// ``` + #[must_use] pub fn other_side_corner_along(self, axis: Axis) -> Self { match axis { Axis::Vertical => match self { @@ -2224,7 +2237,7 @@ where /// # Examples /// /// ``` - /// # use zed::{Corner, Corners}; + /// # use gpui::{Corner, Corners}; /// let corners = Corners { /// top_left: 1, /// top_right: 2, @@ -2233,6 +2246,7 @@ where /// }; /// assert_eq!(corners.corner(Corner::BottomLeft), 3); /// ``` + #[must_use] pub fn corner(&self, corner: Corner) -> T { match corner { Corner::TopLeft => self.top_left.clone(), @@ -2257,7 +2271,7 @@ impl Corners { /// # Examples /// /// ``` - /// # use gpui::{Corners, AbsoluteLength, Pixels, Size}; + /// # use gpui::{Corners, AbsoluteLength, Pixels, Rems, Size}; /// let corners = Corners { /// top_left: AbsoluteLength::Pixels(Pixels(15.0)), /// top_right: AbsoluteLength::Rems(Rems(1.0)), @@ -2265,7 +2279,7 @@ impl Corners { /// bottom_left: AbsoluteLength::Rems(Rems(2.0)), /// }; /// let rem_size = Pixels(16.0); - /// let corners_in_pixels = corners.to_pixels(size, rem_size); + /// let corners_in_pixels = corners.to_pixels(rem_size); /// /// assert_eq!(corners_in_pixels.top_left, Pixels(15.0)); /// assert_eq!(corners_in_pixels.top_right, Pixels(16.0)); // 1 rem converted to pixels @@ -2298,7 +2312,7 @@ impl Corners { /// # Examples /// /// ``` - /// # use gpui::{Corners, Pixels}; + /// # use gpui::{Corners, Pixels, ScaledPixels}; /// let corners = Corners { /// top_left: Pixels(10.0), /// top_right: Pixels(20.0), @@ -2311,6 +2325,7 @@ impl Corners { /// assert_eq!(scaled_corners.bottom_right, ScaledPixels(60.0)); /// assert_eq!(scaled_corners.bottom_left, ScaledPixels(80.0)); /// ``` + #[must_use] pub fn scale(&self, factor: f32) -> Corners { Corners { top_left: self.top_left.scale(factor), @@ -2325,6 +2340,7 @@ impl Corners { /// # Returns /// /// The maximum `Pixels` value among all four corners. + #[must_use] pub fn max(&self) -> Pixels { self.top_left .max(self.top_right) @@ -2343,6 +2359,7 @@ impl + Ord + Clone + Debug + Default + PartialEq> Corner /// # Returns /// /// Corner radii values clamped to fit. + #[must_use] pub fn clamp_radii_for_quad_size(self, size: Size) -> Corners { let max = cmp::min(size.width, size.height) / 2.; Corners { @@ -2372,7 +2389,7 @@ impl Corners { /// # Examples /// /// ``` - /// # use gpui::{Corners, Pixels}; + /// # use gpui::{Corners, Pixels, Rems}; /// let corners = Corners { /// top_left: Pixels(10.0), /// top_right: Pixels(20.0), @@ -2387,6 +2404,7 @@ impl Corners { /// bottom_left: Rems(2.5), /// }); /// ``` + #[must_use] pub fn map(&self, f: impl Fn(&T) -> U) -> Corners where U: Clone + Debug + Default + PartialEq, @@ -2526,14 +2544,14 @@ impl From for Radians { /// # Examples /// /// ``` -/// use gpui::Pixels; +/// use gpui::{Pixels, ScaledPixels}; /// /// // Define a length of 10 pixels /// let length = Pixels(10.0); /// /// // Define a length and scale it by a factor of 2 /// let scaled_length = length.scale(2.0); -/// assert_eq!(scaled_length, Pixels(20.0)); +/// assert_eq!(scaled_length, ScaledPixels(20.0)); /// ``` #[derive( Clone, @@ -2687,6 +2705,7 @@ impl Pixels { /// /// The resulting `ScaledPixels` represent the scaled value which can be used for rendering /// calculations where display scaling is considered. + #[must_use] pub fn scale(&self, factor: f32) -> ScaledPixels { ScaledPixels(self.0 * factor) } @@ -2926,7 +2945,7 @@ impl From for DevicePixels { /// display resolutions. #[derive(Clone, Copy, Default, Add, AddAssign, Sub, SubAssign, Div, DivAssign, PartialEq)] #[repr(transparent)] -pub struct ScaledPixels(pub(crate) f32); +pub struct ScaledPixels(pub f32); impl ScaledPixels { /// Floors the `ScaledPixels` value to the nearest whole number. @@ -3160,7 +3179,7 @@ impl AbsoluteLength { /// # Examples /// /// ``` - /// # use gpui::{AbsoluteLength, Pixels}; + /// # use gpui::{AbsoluteLength, Pixels, Rems}; /// let length_in_pixels = AbsoluteLength::Pixels(Pixels(42.0)); /// let length_in_rems = AbsoluteLength::Rems(Rems(2.0)); /// let rem_size = Pixels(16.0); diff --git a/crates/gpui/src/gpui.rs b/crates/gpui/src/gpui.rs index 3c4ee41c16ab7cfc5e42007291e330282b330ecb..7cc56265bd0401eac67305b636ba29ccec6df9ea 100644 --- a/crates/gpui/src/gpui.rs +++ b/crates/gpui/src/gpui.rs @@ -8,7 +8,8 @@ //! GPUI is still in active development as we work on the Zed code editor and isn't yet on crates.io. //! You'll also need to use the latest version of stable rust. Add the following to your Cargo.toml: //! -//! ``` +//! ```toml +//! [dependencies] //! gpui = { git = "https://github.com/zed-industries/zed" } //! ``` //! diff --git a/crates/gpui/src/key_dispatch.rs b/crates/gpui/src/key_dispatch.rs index 63cfa680c0d158811a92cddfda390ff82fb7db5c..03ee31fdad5bdfc48e10dbf74a2557ea7ee0036e 100644 --- a/crates/gpui/src/key_dispatch.rs +++ b/crates/gpui/src/key_dispatch.rs @@ -1,54 +1,54 @@ -/// KeyDispatch is where GPUI deals with binding actions to key events. -/// -/// The key pieces to making a key binding work are to define an action, -/// implement a method that takes that action as a type parameter, -/// and then to register the action during render on a focused node -/// with a keymap context: -/// -/// ```rust -/// actions!(editor,[Undo, Redo]); -/// -/// impl Editor { -/// fn undo(&mut self, _: &Undo, _window: &mut Window, _cx: &mut Context) { ... } -/// fn redo(&mut self, _: &Redo, _window: &mut Window, _cx: &mut Context) { ... } -/// } -/// -/// impl Render for Editor { -/// fn render(&mut self, window: &mut Window, cx: &mut Context) -> impl IntoElement { -/// div() -/// .track_focus(&self.focus_handle(cx)) -/// .key_context("Editor") -/// .on_action(cx.listener(Editor::undo)) -/// .on_action(cx.listener(Editor::redo)) -/// ... -/// } -/// } -///``` -/// -/// The keybindings themselves are managed independently by calling cx.bind_keys(). -/// (Though mostly when developing Zed itself, you just need to add a new line to -/// assets/keymaps/default-{platform}.json). -/// -/// ```rust -/// cx.bind_keys([ -/// KeyBinding::new("cmd-z", Editor::undo, Some("Editor")), -/// KeyBinding::new("cmd-shift-z", Editor::redo, Some("Editor")), -/// ]) -/// ``` -/// -/// With all of this in place, GPUI will ensure that if you have an Editor that contains -/// the focus, hitting cmd-z will Undo. -/// -/// In real apps, it is a little more complicated than this, because typically you have -/// several nested views that each register keyboard handlers. In this case action matching -/// bubbles up from the bottom. For example in Zed, the Workspace is the top-level view, which contains Pane's, which contain Editors. If there are conflicting keybindings defined -/// then the Editor's bindings take precedence over the Pane's bindings, which take precedence over the Workspace. -/// -/// In GPUI, keybindings are not limited to just single keystrokes, you can define -/// sequences by separating the keys with a space: -/// -/// KeyBinding::new("cmd-k left", pane::SplitLeft, Some("Pane")) -/// +//! KeyDispatch is where GPUI deals with binding actions to key events. +//! +//! The key pieces to making a key binding work are to define an action, +//! implement a method that takes that action as a type parameter, +//! and then to register the action during render on a focused node +//! with a keymap context: +//! +//! ```ignore +//! actions!(editor,[Undo, Redo]); +//! +//! impl Editor { +//! fn undo(&mut self, _: &Undo, _window: &mut Window, _cx: &mut Context) { ... } +//! fn redo(&mut self, _: &Redo, _window: &mut Window, _cx: &mut Context) { ... } +//! } +//! +//! impl Render for Editor { +//! fn render(&mut self, window: &mut Window, cx: &mut Context) -> impl IntoElement { +//! div() +//! .track_focus(&self.focus_handle(cx)) +//! .key_context("Editor") +//! .on_action(cx.listener(Editor::undo)) +//! .on_action(cx.listener(Editor::redo)) +//! ... +//! } +//! } +//!``` +//! +//! The keybindings themselves are managed independently by calling cx.bind_keys(). +//! (Though mostly when developing Zed itself, you just need to add a new line to +//! assets/keymaps/default-{platform}.json). +//! +//! ```ignore +//! cx.bind_keys([ +//! KeyBinding::new("cmd-z", Editor::undo, Some("Editor")), +//! KeyBinding::new("cmd-shift-z", Editor::redo, Some("Editor")), +//! ]) +//! ``` +//! +//! With all of this in place, GPUI will ensure that if you have an Editor that contains +//! the focus, hitting cmd-z will Undo. +//! +//! In real apps, it is a little more complicated than this, because typically you have +//! several nested views that each register keyboard handlers. In this case action matching +//! bubbles up from the bottom. For example in Zed, the Workspace is the top-level view, which contains Pane's, which contain Editors. If there are conflicting keybindings defined +//! then the Editor's bindings take precedence over the Pane's bindings, which take precedence over the Workspace. +//! +//! In GPUI, keybindings are not limited to just single keystrokes, you can define +//! sequences by separating the keys with a space: +//! +//! KeyBinding::new("cmd-k left", pane::SplitLeft, Some("Pane")) + use crate::{ Action, ActionRegistry, App, DispatchPhase, EntityId, FocusId, KeyBinding, KeyContext, Keymap, Keystroke, ModifiersChangedEvent, Window, diff --git a/crates/gpui/src/taffy.rs b/crates/gpui/src/taffy.rs index 58386ad1f5031e1427baad05c4db075df1b2d761..465928d024172d9cadff1a6c45348f550516120f 100644 --- a/crates/gpui/src/taffy.rs +++ b/crates/gpui/src/taffy.rs @@ -490,6 +490,7 @@ impl AvailableSpace { /// # Examples /// /// ``` + /// use gpui::AvailableSpace; /// let min_content_size = AvailableSpace::min_size(); /// assert_eq!(min_content_size.width, AvailableSpace::MinContent); /// assert_eq!(min_content_size.height, AvailableSpace::MinContent); diff --git a/crates/gpui/src/window.rs b/crates/gpui/src/window.rs index c230a4c7aa58af3d89c71b4093cd7c6b8816252a..1c4532fda2adcdc5e995a6486a6366875c1f3b44 100644 --- a/crates/gpui/src/window.rs +++ b/crates/gpui/src/window.rs @@ -580,7 +580,7 @@ pub enum HitboxBehavior { /// For mouse handlers that check those hitboxes, this behaves the same as registering a /// bubble-phase handler for every mouse event type: /// - /// ``` + /// ```ignore /// window.on_mouse_event(move |_: &EveryMouseEventTypeHere, phase, window, cx| { /// if phase == DispatchPhase::Capture && hitbox.is_hovered(window) { /// cx.stop_propagation(); @@ -604,7 +604,7 @@ pub enum HitboxBehavior { /// For mouse handlers that check those hitboxes, this behaves the same as registering a /// bubble-phase handler for every mouse event type **except** `ScrollWheelEvent`: /// - /// ``` + /// ```ignore /// window.on_mouse_event(move |_: &EveryMouseEventTypeExceptScroll, phase, window, cx| { /// if phase == DispatchPhase::Bubble && hitbox.should_handle_scroll(window) { /// cx.stop_propagation(); diff --git a/crates/proto/src/error.rs b/crates/proto/src/error.rs index 1724a7021750c2fb13c5dab504aad24a75a74c12..c2fdfcf8204e40abe317ec1404e62eb5caf2bdac 100644 --- a/crates/proto/src/error.rs +++ b/crates/proto/src/error.rs @@ -22,12 +22,14 @@ /// When handling an error you can use .error_code() to match which error it was /// and .error_tag() to read any tags. /// -/// ``` +/// ```ignore +/// use proto::{ErrorCode, ErrorExt}; +/// /// match err.error_code() { -/// ErrorCode::Forbidden => alert("I'm sorry I can't do that.") +/// ErrorCode::Forbidden => alert("I'm sorry I can't do that."), /// ErrorCode::WrongReleaseChannel => -/// alert(format!("You need to be on the {} release channel.", err.error_tag("required").unwrap())) -/// ErrorCode::Internal => alert("Sorry, something went wrong") +/// alert(format!("You need to be on the {} release channel.", err.error_tag("required").unwrap())), +/// ErrorCode::Internal => alert("Sorry, something went wrong"), /// } /// ``` /// diff --git a/crates/refineable/src/refineable.rs b/crates/refineable/src/refineable.rs index 9d5da10ac7458203a820b637c46b4db7af0d04ee..930f80dbefada3ee15b9c6a1ca2fabed78b21034 100644 --- a/crates/refineable/src/refineable.rs +++ b/crates/refineable/src/refineable.rs @@ -19,7 +19,10 @@ pub use derive_refineable::Refineable; /// /// ## Example /// -/// ```rust +/// ``` +/// use derive_refineable::Refineable as _; +/// use refineable::Refineable; +/// /// #[derive(Refineable, Clone, Default)] /// struct Example { /// color: String, @@ -36,7 +39,7 @@ pub use derive_refineable::Refineable; /// /// /// fn example() { -/// let mut example = Example::default(); +/// let mut base_style = Example::default(); /// let refinement = ExampleRefinement { /// color: Some("red".to_string()), /// font_size: None, diff --git a/crates/repl/src/outputs/plain.rs b/crates/repl/src/outputs/plain.rs index ae3c728c8aad01e2aa7968423c2d3c3fdc549b19..268224fda35d6db78135f0b0154966159570dc4c 100644 --- a/crates/repl/src/outputs/plain.rs +++ b/crates/repl/src/outputs/plain.rs @@ -171,9 +171,9 @@ impl TerminalOutput { /// /// Then append_text will be called twice, with the following arguments: /// - /// ```rust - /// terminal_output.append_text("Hello,") - /// terminal_output.append_text(" world!") + /// ```ignore + /// terminal_output.append_text("Hello,"); + /// terminal_output.append_text(" world!"); /// ``` /// Resulting in a single output of "Hello, world!". /// diff --git a/crates/repl/src/outputs/table.rs b/crates/repl/src/outputs/table.rs index c94e8c26a9ff02fde0b73bf8ee09006e50fbc087..2a5864c7bca5f1bf8ac2f242e7ce694df6c00aac 100644 --- a/crates/repl/src/outputs/table.rs +++ b/crates/repl/src/outputs/table.rs @@ -66,7 +66,9 @@ use util::markdown::MarkdownEscaped; use crate::outputs::OutputContent; /// TableView renders a static table inline in a buffer. -/// It uses the https://specs.frictionlessdata.io/tabular-data-resource/ specification for data interchange. +/// +/// It uses the +/// specification for data interchange. pub struct TableView { pub table: TabularDataResource, pub widths: Vec, diff --git a/crates/settings_ui_macros/Cargo.toml b/crates/settings_ui_macros/Cargo.toml index 1561e874f4de0248db9509b899b798578a179f3c..ece6269f5999ad3ed7e08e34d3ff4c7cb97c9f63 100644 --- a/crates/settings_ui_macros/Cargo.toml +++ b/crates/settings_ui_macros/Cargo.toml @@ -21,3 +21,6 @@ proc-macro2.workspace = true quote.workspace = true syn.workspace = true workspace-hack.workspace = true + +[dev-dependencies] +settings.workspace = true diff --git a/crates/settings_ui_macros/src/settings_ui_macros.rs b/crates/settings_ui_macros/src/settings_ui_macros.rs index 7dea9fc879e9f34761e3dbfcf9e703ebf3a72d12..971adbfe4dd2356a8e19185767a121810cadd991 100644 --- a/crates/settings_ui_macros/src/settings_ui_macros.rs +++ b/crates/settings_ui_macros/src/settings_ui_macros.rs @@ -12,7 +12,7 @@ use syn::{Data, DeriveInput, LitStr, Token, parse_macro_input}; /// # Example /// /// ``` -/// use settings::SettingsUi; +/// use settings_ui_macros::SettingsUi; /// /// #[derive(SettingsUi)] /// #[settings_ui(group = "Standard")] diff --git a/crates/telemetry/src/telemetry.rs b/crates/telemetry/src/telemetry.rs index ac43457c3368dba79131dc51966e9ec7ad1d870b..e6c85169671cfcfb2ee798af2c9566b2eb548ac9 100644 --- a/crates/telemetry/src/telemetry.rs +++ b/crates/telemetry/src/telemetry.rs @@ -12,6 +12,7 @@ pub use telemetry_events::FlexibleEvent as Event; /// The properties can be any value that implements serde::Serialize. /// /// ``` +/// # let url = "https://example.com"; /// telemetry::event!("Keymap Changed", version = "1.0.0"); /// telemetry::event!("Documentation Viewed", url, source = "Extension Upsell"); /// ``` diff --git a/crates/terminal/src/terminal.rs b/crates/terminal/src/terminal.rs index bec91a787d66dcd1d5c881df794bbb71cfc792ea..d926faaf484b84dc7cf17b1ef0b816f5773ff02c 100644 --- a/crates/terminal/src/terminal.rs +++ b/crates/terminal/src/terminal.rs @@ -2160,11 +2160,12 @@ pub fn get_color_at_index(index: usize, theme: &Theme) -> Hsla { } /// Generates the RGB channels in [0, 5] for a given index into the 6x6x6 ANSI color cube. +/// /// See: [8 bit ANSI color](https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit). /// /// Wikipedia gives a formula for calculating the index for a given color: /// -/// ``` +/// ```text /// index = 16 + 36 × r + 6 × g + b (0 ≤ r, g, b ≤ 5) /// ``` /// diff --git a/crates/ui/src/components/avatar.rs b/crates/ui/src/components/avatar.rs index 3ab31acc1ba373912f154b2c95398e8375902a7a..19f7c4660bc64e756950df6f5ab0e19192f4096b 100644 --- a/crates/ui/src/components/avatar.rs +++ b/crates/ui/src/components/avatar.rs @@ -8,10 +8,9 @@ use gpui::{AnyElement, Hsla, ImageSource, Img, IntoElement, Styled, img}; /// # Examples /// /// ``` -/// use ui::{Avatar, AvatarShape}; +/// use ui::Avatar; /// /// Avatar::new("path/to/image.png") -/// .shape(AvatarShape::Circle) /// .grayscale(true) /// .border_color(gpui::red()); /// ``` @@ -39,7 +38,7 @@ impl Avatar { /// # Examples /// /// ``` - /// use ui::{Avatar, AvatarShape}; + /// use ui::Avatar; /// /// let avatar = Avatar::new("path/to/image.png").grayscale(true); /// ``` diff --git a/crates/ui/src/components/banner.rs b/crates/ui/src/components/banner.rs index 7458ad8eb07a7f9c473b18c98c902a9582db27d1..a09170f5b2693d26b2c9f3ef539e1a70d391615a 100644 --- a/crates/ui/src/components/banner.rs +++ b/crates/ui/src/components/banner.rs @@ -7,17 +7,18 @@ use gpui::{AnyElement, IntoElement, ParentElement, Styled}; /// # Usage Example /// /// ``` -/// use ui::{Banner}; +/// use ui::prelude::*; +/// use ui::{Banner, Button, IconName, IconPosition, IconSize, Label, Severity}; /// -/// Banner::new() +/// Banner::new() /// .severity(Severity::Success) -/// .children(Label::new("This is a success message")) +/// .children([Label::new("This is a success message")]) /// .action_slot( /// Button::new("learn-more", "Learn More") /// .icon(IconName::ArrowUpRight) /// .icon_size(IconSize::Small) -/// .icon_position(IconPosition::End), -/// ) +/// .icon_position(IconPosition::End) +/// ); /// ``` #[derive(IntoElement, RegisterComponent)] pub struct Banner { diff --git a/crates/ui/src/components/button/button.rs b/crates/ui/src/components/button/button.rs index cee39ac23bb1c529da99588dc02b0016a8bb9943..e0104bf54f59694eb96aa2ba43be658ebc182d2a 100644 --- a/crates/ui/src/components/button/button.rs +++ b/crates/ui/src/components/button/button.rs @@ -43,7 +43,7 @@ use super::button_icon::ButtonIcon; /// /// Button::new("button_id", "Click me!") /// .icon(IconName::Check) -/// .selected(true) +/// .toggle_state(true) /// .on_click(|event, window, cx| { /// // Handle click event /// }); @@ -56,7 +56,7 @@ use super::button_icon::ButtonIcon; /// use ui::TintColor; /// /// Button::new("button_id", "Click me!") -/// .selected(true) +/// .toggle_state(true) /// .selected_style(ButtonStyle::Tinted(TintColor::Accent)) /// .on_click(|event, window, cx| { /// // Handle click event @@ -228,7 +228,7 @@ impl Toggleable for Button { /// use ui::prelude::*; /// /// Button::new("button_id", "Click me!") - /// .selected(true) + /// .toggle_state(true) /// .on_click(|event, window, cx| { /// // Handle click event /// }); @@ -251,7 +251,7 @@ impl SelectableButton for Button { /// use ui::TintColor; /// /// Button::new("button_id", "Click me!") - /// .selected(true) + /// .toggle_state(true) /// .selected_style(ButtonStyle::Tinted(TintColor::Accent)) /// .on_click(|event, window, cx| { /// // Handle click event @@ -317,7 +317,7 @@ impl FixedWidth for Button { /// use ui::prelude::*; /// /// Button::new("button_id", "Click me!") - /// .width(px(100.).into()) + /// .width(px(100.)) /// .on_click(|event, window, cx| { /// // Handle click event /// }); @@ -381,7 +381,7 @@ impl ButtonCommon for Button { /// use ui::Tooltip; /// /// Button::new("button_id", "Click me!") - /// .tooltip(Tooltip::text_f("This is a tooltip", cx)) + /// .tooltip(Tooltip::text("This is a tooltip")) /// .on_click(|event, window, cx| { /// // Handle click event /// }); diff --git a/crates/ui/src/components/callout.rs b/crates/ui/src/components/callout.rs index b1ead18ee71fbae90bf4d2d633a980f8eb9f3638..b5d1d7f25531cc956388da9d4a977bdfd14204b9 100644 --- a/crates/ui/src/components/callout.rs +++ b/crates/ui/src/components/callout.rs @@ -13,14 +13,15 @@ pub enum BorderPosition { /// # Usage Example /// /// ``` -/// use ui::{Callout}; +/// use ui::prelude::*; +/// use ui::{Button, Callout, IconName, Label, Severity}; /// -/// Callout::new() +/// let callout = Callout::new() /// .severity(Severity::Warning) /// .icon(IconName::Warning) -/// .title(Label::new("Be aware of your subscription!")) -/// .description(Label::new("Your subscription is about to expire. Renew now!")) -/// .actions_slot(Button::new("renew", "Renew Now")) +/// .title("Be aware of your subscription!") +/// .description("Your subscription is about to expire. Renew now!") +/// .actions_slot(Button::new("renew", "Renew Now")); /// ``` /// #[derive(IntoElement, RegisterComponent)] diff --git a/crates/ui/src/components/chip.rs b/crates/ui/src/components/chip.rs index e1262875feae77b69e660c0e9da17e1e669137b7..8d0000db949fdf77353aa9a381076567f0b320f4 100644 --- a/crates/ui/src/components/chip.rs +++ b/crates/ui/src/components/chip.rs @@ -6,9 +6,9 @@ use gpui::{AnyElement, Hsla, IntoElement, ParentElement, Styled}; /// # Usage Example /// /// ``` -/// use ui::{Chip}; +/// use ui::Chip; /// -/// Chip::new("This Chip") +/// let chip = Chip::new("This Chip"); /// ``` #[derive(IntoElement, RegisterComponent)] pub struct Chip { diff --git a/crates/ui/src/components/facepile.rs b/crates/ui/src/components/facepile.rs index 83e99df7c24dab20b088bf15aeab10501e81d6ef..79a36871d60180d55492228ddb1d8cae8b943f9d 100644 --- a/crates/ui/src/components/facepile.rs +++ b/crates/ui/src/components/facepile.rs @@ -19,11 +19,13 @@ use super::Avatar; /// A default, horizontal facepile. /// /// ``` +/// use gpui::IntoElement; /// use ui::{Avatar, Facepile, EXAMPLE_FACES}; /// -/// Facepile::new( -/// EXAMPLE_FACES.iter().take(3).iter().map(|&url| -/// Avatar::new(url).into_any_element()).collect()) +/// let facepile = Facepile::new( +/// EXAMPLE_FACES.iter().take(3).map(|&url| +/// Avatar::new(url).into_any_element()).collect() +/// ); /// ``` #[derive(IntoElement, Documented, RegisterComponent)] pub struct Facepile { diff --git a/crates/ui/src/components/keybinding_hint.rs b/crates/ui/src/components/keybinding_hint.rs index d7491b27b1fdf22dd2466768d81e9a63c343b705..b24749778cba0b6398bdfc2b455ff41535a4ed2b 100644 --- a/crates/ui/src/components/keybinding_hint.rs +++ b/crates/ui/src/components/keybinding_hint.rs @@ -10,12 +10,19 @@ use theme::Appearance; /// /// # Examples /// -/// ``` +/// ```no_run +/// use gpui::{App, Hsla, KeybindingKeystroke, Keystroke}; /// use ui::prelude::*; +/// use ui::{KeyBinding, KeybindingHint}; /// -/// let hint = KeybindingHint::new(KeyBinding::from_str("Ctrl+S")) +/// # fn example(cx: &App) { +/// let hint = KeybindingHint::new( +/// KeyBinding::new(vec![KeybindingKeystroke::from_keystroke(Keystroke::parse("ctrl-s").unwrap())], cx), +/// Hsla::black() +/// ) /// .prefix("Save:") /// .size(Pixels::from(14.0)); +/// # } /// ``` #[derive(Debug, IntoElement, RegisterComponent)] pub struct KeybindingHint { @@ -34,10 +41,17 @@ impl KeybindingHint { /// /// # Examples /// - /// ``` + /// ```no_run + /// use gpui::{App, Hsla, KeybindingKeystroke, Keystroke}; /// use ui::prelude::*; + /// use ui::{KeyBinding, KeybindingHint}; /// - /// let hint = KeybindingHint::new(KeyBinding::from_str("Ctrl+C"), Hsla::new(0.0, 0.0, 0.0, 1.0)); + /// # fn example(cx: &App) { + /// let hint = KeybindingHint::new( + /// KeyBinding::new(vec![KeybindingKeystroke::from_keystroke(Keystroke::parse("ctrl-c").unwrap())], cx), + /// Hsla::black() + /// ); + /// # } /// ``` pub fn new(keybinding: KeyBinding, background_color: Hsla) -> Self { Self { @@ -56,10 +70,18 @@ impl KeybindingHint { /// /// # Examples /// - /// ``` + /// ```no_run + /// use gpui::{App, Hsla, KeybindingKeystroke, Keystroke}; /// use ui::prelude::*; + /// use ui::{KeyBinding, KeybindingHint}; /// - /// let hint = KeybindingHint::with_prefix("Copy:", KeyBinding::from_str("Ctrl+C"), Hsla::new(0.0, 0.0, 0.0, 1.0)); + /// # fn example(cx: &App) { + /// let hint = KeybindingHint::with_prefix( + /// "Copy:", + /// KeyBinding::new(vec![KeybindingKeystroke::from_keystroke(Keystroke::parse("ctrl-c").unwrap())], cx), + /// Hsla::black() + /// ); + /// # } /// ``` pub fn with_prefix( prefix: impl Into, @@ -82,10 +104,18 @@ impl KeybindingHint { /// /// # Examples /// - /// ``` + /// ```no_run + /// use gpui::{App, Hsla, KeybindingKeystroke, Keystroke}; /// use ui::prelude::*; + /// use ui::{KeyBinding, KeybindingHint}; /// - /// let hint = KeybindingHint::with_suffix(KeyBinding::from_str("Ctrl+V"), "Paste", Hsla::new(0.0, 0.0, 0.0, 1.0)); + /// # fn example(cx: &App) { + /// let hint = KeybindingHint::with_suffix( + /// KeyBinding::new(vec![KeybindingKeystroke::from_keystroke(Keystroke::parse("ctrl-v").unwrap())], cx), + /// "Paste", + /// Hsla::black() + /// ); + /// # } /// ``` pub fn with_suffix( keybinding: KeyBinding, @@ -107,11 +137,18 @@ impl KeybindingHint { /// /// # Examples /// - /// ``` + /// ```no_run + /// use gpui::{App, Hsla, KeybindingKeystroke, Keystroke}; /// use ui::prelude::*; + /// use ui::{KeyBinding, KeybindingHint}; /// - /// let hint = KeybindingHint::new(KeyBinding::from_str("Ctrl+X")) + /// # fn example(cx: &App) { + /// let hint = KeybindingHint::new( + /// KeyBinding::new(vec![KeybindingKeystroke::from_keystroke(Keystroke::parse("ctrl-x").unwrap())], cx), + /// Hsla::black() + /// ) /// .prefix("Cut:"); + /// # } /// ``` pub fn prefix(mut self, prefix: impl Into) -> Self { self.prefix = Some(prefix.into()); @@ -124,11 +161,18 @@ impl KeybindingHint { /// /// # Examples /// - /// ``` + /// ```no_run + /// use gpui::{App, Hsla, KeybindingKeystroke, Keystroke}; /// use ui::prelude::*; + /// use ui::{KeyBinding, KeybindingHint}; /// - /// let hint = KeybindingHint::new(KeyBinding::from_str("Ctrl+F")) + /// # fn example(cx: &App) { + /// let hint = KeybindingHint::new( + /// KeyBinding::new(vec![KeybindingKeystroke::from_keystroke(Keystroke::parse("ctrl-f").unwrap())], cx), + /// Hsla::black() + /// ) /// .suffix("Find"); + /// # } /// ``` pub fn suffix(mut self, suffix: impl Into) -> Self { self.suffix = Some(suffix.into()); @@ -141,11 +185,18 @@ impl KeybindingHint { /// /// # Examples /// - /// ``` + /// ```no_run + /// use gpui::{App, Hsla, KeybindingKeystroke, Keystroke}; /// use ui::prelude::*; + /// use ui::{KeyBinding, KeybindingHint}; /// - /// let hint = KeybindingHint::new(KeyBinding::from_str("Ctrl+Z")) + /// # fn example(cx: &App) { + /// let hint = KeybindingHint::new( + /// KeyBinding::new(vec![KeybindingKeystroke::from_keystroke(Keystroke::parse("ctrl-z").unwrap())], cx), + /// Hsla::black() + /// ) /// .size(Pixels::from(16.0)); + /// # } /// ``` pub fn size(mut self, size: impl Into>) -> Self { self.size = size.into(); diff --git a/crates/ui/src/components/label/label.rs b/crates/ui/src/components/label/label.rs index 019ece023e559b92181517a743e891d098b586a6..49e2de94a1f86196c10e41879797b02070517e65 100644 --- a/crates/ui/src/components/label/label.rs +++ b/crates/ui/src/components/label/label.rs @@ -27,7 +27,7 @@ use gpui::StyleRefinement; /// ``` /// use ui::prelude::*; /// -/// let my_label = Label::new("Deleted").strikethrough(true); +/// let my_label = Label::new("Deleted").strikethrough(); /// ``` #[derive(IntoElement, RegisterComponent)] pub struct Label { @@ -89,9 +89,10 @@ impl LabelCommon for Label { /// # Examples /// /// ``` + /// use gpui::FontWeight; /// use ui::prelude::*; /// - /// let my_label = Label::new("Hello, World!").weight(FontWeight::Bold); + /// let my_label = Label::new("Hello, World!").weight(FontWeight::BOLD); /// ``` fn weight(mut self, weight: gpui::FontWeight) -> Self { self.base = self.base.weight(weight); @@ -133,7 +134,7 @@ impl LabelCommon for Label { /// ``` /// use ui::prelude::*; /// - /// let my_label = Label::new("Hello, World!").strikethrough(true); + /// let my_label = Label::new("Hello, World!").strikethrough(); /// ``` fn strikethrough(mut self) -> Self { self.base = self.base.strikethrough(); @@ -147,7 +148,7 @@ impl LabelCommon for Label { /// ``` /// use ui::prelude::*; /// - /// let my_label = Label::new("Hello, World!").italic(true); + /// let my_label = Label::new("Hello, World!").italic(); /// ``` fn italic(mut self) -> Self { self.base = self.base.italic(); diff --git a/crates/ui/src/components/toggle.rs b/crates/ui/src/components/toggle.rs index 2ca635c05bbd442fe26bcee2fbda4b168ad0afeb..ae74f76b9cef8075c07dfe45e27b735e98939f8f 100644 --- a/crates/ui/src/components/toggle.rs +++ b/crates/ui/src/components/toggle.rs @@ -581,11 +581,12 @@ impl RenderOnce for Switch { /// /// ``` /// use ui::prelude::*; +/// use ui::{SwitchField, ToggleState}; /// -/// SwitchField::new( +/// let switch_field = SwitchField::new( /// "feature-toggle", /// "Enable feature", -/// "This feature adds new functionality to the app.", +/// Some("This feature adds new functionality to the app.".into()), /// ToggleState::Unselected, /// |state, window, cx| { /// // Logic here diff --git a/crates/ui_macros/Cargo.toml b/crates/ui_macros/Cargo.toml index d468c133d40ae75da9c2dea8fa466098ed7e409f..830b9dca8d5c42ec54db3c2aa323ede7d71aa5c9 100644 --- a/crates/ui_macros/Cargo.toml +++ b/crates/ui_macros/Cargo.toml @@ -16,3 +16,7 @@ proc-macro = true quote.workspace = true syn.workspace = true workspace-hack.workspace = true + +[dev-dependencies] +component.workspace = true +ui.workspace = true diff --git a/crates/ui_macros/src/ui_macros.rs b/crates/ui_macros/src/ui_macros.rs index db002e7bb3d99ec7c35e6d41eb2e48e5e8b0a438..ce48a21c1155b2414312277e59395cf50944ab69 100644 --- a/crates/ui_macros/src/ui_macros.rs +++ b/crates/ui_macros/src/ui_macros.rs @@ -19,6 +19,7 @@ pub fn derive_dynamic_spacing(input: TokenStream) -> TokenStream { /// # Example /// /// ``` +/// use ui::Component; /// use ui_macros::RegisterComponent; /// /// #[derive(RegisterComponent)]