Detailed changes
@@ -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
@@ -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",
]
@@ -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<dyn gpui::Action> { 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<Box<dyn gpui::Action>> {
+/// # unimplemented!()
+/// # }
/// }
+///
/// register_action!(Paste);
/// ```
pub trait Action: Any + Send {
@@ -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);
@@ -102,7 +102,7 @@ pub struct Point<T: Clone + Debug + Default + PartialEq> {
/// # 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<T: Clone + Debug + Default + PartialEq> Point<T> {
/// # 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<T: Clone + Debug + Default + PartialEq> Point<T> {
/// 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<U: Clone + Debug + Default + PartialEq>(&self, f: impl Fn(T) -> U) -> Point<U> {
Point {
x: f(self.x.clone()),
@@ -418,7 +420,7 @@ impl<T: Clone + Debug + Default + PartialEq> Size<T> {
/// # 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<T> {
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<T>) -> Bounds<T> {
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<T>) -> bool {
point.x >= self.origin.x
@@ -1565,6 +1569,7 @@ impl<T: PartialOrd + Clone + Debug + Default + PartialEq> Bounds<T> {
/// # 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<Pixels> {
/// # 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<Pixels> {
/// 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<ScaledPixels> {
@@ -1847,7 +1858,7 @@ impl Edges<Length> {
/// # 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<Length> {
/// # Examples
///
/// ```
- /// # use gpui::Edges;
- /// let no_edges = Edges::zero();
+ /// # use gpui::{DefiniteLength, Edges, Length, Pixels};
+ /// let no_edges = Edges::<Length>::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<DefiniteLength> {
/// # Examples
///
/// ```
- /// # use gpui::{px, Edges};
- /// let no_edges = Edges::zero();
+ /// # use gpui::{px, DefiniteLength, Edges};
+ /// let no_edges = Edges::<DefiniteLength>::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<DefiniteLength> {
/// # 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<AbsoluteLength> {
/// # Examples
///
/// ```
- /// # use gpui::Edges;
- /// let no_edges = Edges::zero();
+ /// # use gpui::{AbsoluteLength, Edges, Pixels};
+ /// let no_edges = Edges::<AbsoluteLength>::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<AbsoluteLength> {
/// # 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<Pixels> {
/// # 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<Pixels> for Edges<Pixels> {
}
/// 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<AbsoluteLength> {
/// # 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<AbsoluteLength> {
/// 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<Pixels> {
/// # 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<Pixels> {
/// 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<ScaledPixels> {
Corners {
top_left: self.top_left.scale(factor),
@@ -2325,6 +2340,7 @@ impl Corners<Pixels> {
/// # 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<T: Div<f32, Output = T> + 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<T>) -> Corners<T> {
let max = cmp::min(size.width, size.height) / 2.;
Corners {
@@ -2372,7 +2389,7 @@ impl<T: Clone + Debug + Default + PartialEq> Corners<T> {
/// # 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<T: Clone + Debug + Default + PartialEq> Corners<T> {
/// bottom_left: Rems(2.5),
/// });
/// ```
+ #[must_use]
pub fn map<U>(&self, f: impl Fn(&T) -> U) -> Corners<U>
where
U: Clone + Debug + Default + PartialEq,
@@ -2526,14 +2544,14 @@ impl From<Percentage> 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<usize> 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);
@@ -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" }
//! ```
//!
@@ -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<Self>) { ... }
-/// fn redo(&mut self, _: &Redo, _window: &mut Window, _cx: &mut Context<Self>) { ... }
-/// }
-///
-/// impl Render for Editor {
-/// fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> 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<Self>) { ... }
+//! fn redo(&mut self, _: &Redo, _window: &mut Window, _cx: &mut Context<Self>) { ... }
+//! }
+//!
+//! impl Render for Editor {
+//! fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> 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,
@@ -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);
@@ -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();
@@ -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"),
/// }
/// ```
///
@@ -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,
@@ -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!".
///
@@ -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 <https://specs.frictionlessdata.io/tabular-data-resource/>
+/// specification for data interchange.
pub struct TableView {
pub table: TabularDataResource,
pub widths: Vec<Pixels>,
@@ -21,3 +21,6 @@ proc-macro2.workspace = true
quote.workspace = true
syn.workspace = true
workspace-hack.workspace = true
+
+[dev-dependencies]
+settings.workspace = true
@@ -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")]
@@ -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");
/// ```
@@ -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)
/// ```
///
@@ -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);
/// ```
@@ -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 {
@@ -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
/// });
@@ -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)]
@@ -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 {
@@ -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 {
@@ -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<SharedString>,
@@ -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<SharedString>) -> 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<SharedString>) -> 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<Option<Pixels>>) -> Self {
self.size = size.into();
@@ -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();
@@ -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
@@ -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
@@ -19,6 +19,7 @@ pub fn derive_dynamic_spacing(input: TokenStream) -> TokenStream {
/// # Example
///
/// ```
+/// use ui::Component;
/// use ui_macros::RegisterComponent;
///
/// #[derive(RegisterComponent)]