From aa57a4cfbc0c2548c0028f5aa7e7c1750fd0c7ff Mon Sep 17 00:00:00 2001 From: Mikayla Date: Sun, 21 Jan 2024 14:26:45 -0800 Subject: [PATCH] Document / lockdown more of GPUI --- crates/gpui/src/element.rs | 6 +- crates/gpui/src/elements/img.rs | 7 ++ crates/gpui/src/elements/list.rs | 39 +++++++- crates/gpui/src/elements/overlay.rs | 15 +++ crates/gpui/src/elements/svg.rs | 3 + crates/gpui/src/elements/text.rs | 7 ++ crates/gpui/src/elements/uniform_list.rs | 14 +++ crates/gpui/src/executor.rs | 16 ++- crates/gpui/src/gpui.rs | 78 ++++++++++++--- crates/gpui/src/image_cache.rs | 6 +- crates/gpui/src/input.rs | 17 +++- crates/gpui/src/interactive.rs | 120 +++++++++++++++++++---- crates/gpui/src/key_dispatch.rs | 2 +- crates/gpui/src/keymap/binding.rs | 6 ++ crates/gpui/src/keymap/context.rs | 56 +++++++++++ crates/gpui/src/keymap/keymap.rs | 8 ++ crates/gpui/src/keymap/matcher.rs | 21 ++-- crates/gpui/src/keymap/mod.rs | 2 +- crates/gpui/src/prelude.rs | 4 + crates/gpui/src/scene.rs | 27 ++--- crates/gpui/src/shared_string.rs | 2 + crates/gpui/src/subscription.rs | 5 + crates/gpui/src/svg_renderer.rs | 4 +- crates/gpui/src/taffy.rs | 2 + crates/gpui/src/test.rs | 4 + crates/gpui/src/text_system.rs | 2 +- crates/gpui/src/text_system/line.rs | 1 + 27 files changed, 399 insertions(+), 75 deletions(-) diff --git a/crates/gpui/src/element.rs b/crates/gpui/src/element.rs index 0c98820d30..01bb8ba6bf 100644 --- a/crates/gpui/src/element.rs +++ b/crates/gpui/src/element.rs @@ -8,13 +8,13 @@ //! # Element Basics //! //! Elements are constructed by calling [`Render::render()`] on the root view of the window, which -//! which recursively constructs the element tree from the current state of the application. +//! which recursively constructs the element tree from the current state of the application,. //! These elements are then laid out by Taffy, and painted to the screen according to their own //! implementation of [`Element::paint()`]. Before the start of the next frame, the entire element //! tree and any callbacks they have registered with GPUI are dropped and the process repeats. //! //! But some state is too simple and voluminous to store in every view that needs it, e.g. -//! whether a hover has been started or not. For this, GPUI provides the [`Element::State`], type. +//! whether a hover has been started or not. For this, GPUI provides the [`Element::State`], associated type. //! If an element returns an [`ElementId`] from [`IntoElement::element_id()`], and that element id //! appears in the same place relative to other views and ElementIds in the frame, then the previous //! frame's state will be passed to the element's layout and paint methods. @@ -30,7 +30,7 @@ //! //! However, most of the time, you won't need to implement your own elements. GPUI provides a number of //! elements that should cover most common use cases out of the box and it's recommended that you use those -//! to construct `components`, using the `RenderOnce` trait and the `#[derive(IntoElement)]` macro. Only implement +//! to construct `components`, using the [`RenderOnce`] trait and the `#[derive(IntoElement)]` macro. Only implement //! elements when you need to take manual control of the layout and painting process, such as when using //! your own custom layout algorithm or rendering a code editor. diff --git a/crates/gpui/src/elements/img.rs b/crates/gpui/src/elements/img.rs index 5a656db9fb..e9a2e0676d 100644 --- a/crates/gpui/src/elements/img.rs +++ b/crates/gpui/src/elements/img.rs @@ -9,11 +9,15 @@ use futures::FutureExt; use media::core_video::CVImageBuffer; use util::ResultExt; +/// A source of image content. #[derive(Clone, Debug)] pub enum ImageSource { /// Image content will be loaded from provided URI at render time. Uri(SharedUrl), + /// Cached image data Data(Arc), + // TODO: move surface definitions into mac platform module + /// A CoreVideo image buffer Surface(CVImageBuffer), } @@ -47,12 +51,14 @@ impl From for ImageSource { } } +/// An image element. pub struct Img { interactivity: Interactivity, source: ImageSource, grayscale: bool, } +/// Create a new image element. pub fn img(source: impl Into) -> Img { Img { interactivity: Interactivity::default(), @@ -62,6 +68,7 @@ pub fn img(source: impl Into) -> Img { } impl Img { + /// Set the image to be displayed in grayscale. pub fn grayscale(mut self, grayscale: bool) -> Self { self.grayscale = grayscale; self diff --git a/crates/gpui/src/elements/list.rs b/crates/gpui/src/elements/list.rs index 2921d90a10..a3ed95ef33 100644 --- a/crates/gpui/src/elements/list.rs +++ b/crates/gpui/src/elements/list.rs @@ -1,3 +1,11 @@ +//! A list element that can be used to render a large number of differently sized elements +//! efficiently. Clients of this API need to ensure that elements outside of the scrolled +//! area do not change their height for this element to function correctly. In order to minimize +//! re-renders, this element's state is stored intrusively on your own views, so that your code +//! can coordinate directly with the list element's cached state. +//! +//! If all of your elements are the same height, see [`UniformList`] for a simpler API + use crate::{ point, px, AnyElement, AvailableSpace, BorrowAppContext, BorrowWindow, Bounds, ContentMask, DispatchPhase, Element, IntoElement, Pixels, Point, ScrollWheelEvent, Size, Style, @@ -8,6 +16,7 @@ use refineable::Refineable as _; use std::{cell::RefCell, ops::Range, rc::Rc}; use sum_tree::{Bias, SumTree}; +/// Construct a new list element pub fn list(state: ListState) -> List { List { state, @@ -15,11 +24,13 @@ pub fn list(state: ListState) -> List { } } +/// A list element pub struct List { state: ListState, style: StyleRefinement, } +/// The list state that views must hold on behalf of the list element. #[derive(Clone)] pub struct ListState(Rc>); @@ -35,15 +46,24 @@ struct StateInner { scroll_handler: Option>, } +/// Whether the list is scrolling from top to bottom or bottom to top. #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum ListAlignment { + /// The list is scrolling from top to bottom, like most lists. Top, + /// The list is scrolling from bottom to top, like a chat log. Bottom, } +/// A scroll event that has been converted to be in terms of the list's items. pub struct ListScrollEvent { + /// The range of items currently visible in the list, after applying the scroll event. pub visible_range: Range, + + /// The number of items that are currently visible in the list, after applying the scroll event. pub count: usize, + + /// Whether the list has been scrolled. pub is_scrolled: bool, } @@ -74,6 +94,11 @@ struct UnrenderedCount(usize); struct Height(Pixels); impl ListState { + /// Construct a new list state, for storage on a view. + /// + /// the overdraw parameter controls how much extra space is rendered + /// above and below the visible area. This can help ensure that the list + /// doesn't flicker or pop in when scrolling. pub fn new( element_count: usize, orientation: ListAlignment, @@ -111,10 +136,13 @@ impl ListState { .extend((0..element_count).map(|_| ListItem::Unrendered), &()); } + /// The number of items in this list. pub fn item_count(&self) -> usize { self.0.borrow().items.summary().count } + /// Register with the list state that the items in `old_range` have been replaced + /// by `count` new items that must be recalculated. pub fn splice(&self, old_range: Range, count: usize) { let state = &mut *self.0.borrow_mut(); @@ -141,6 +169,7 @@ impl ListState { state.items = new_heights; } + /// Set a handler that will be called when the list is scrolled. pub fn set_scroll_handler( &self, handler: impl FnMut(&ListScrollEvent, &mut WindowContext) + 'static, @@ -148,10 +177,12 @@ impl ListState { self.0.borrow_mut().scroll_handler = Some(Box::new(handler)) } + /// Get the current scroll offset, in terms of the list's items. pub fn logical_scroll_top(&self) -> ListOffset { self.0.borrow().logical_scroll_top() } + /// Scroll the list to the given offset pub fn scroll_to(&self, mut scroll_top: ListOffset) { let state = &mut *self.0.borrow_mut(); let item_count = state.items.summary().count; @@ -163,6 +194,7 @@ impl ListState { state.logical_scroll_top = Some(scroll_top); } + /// Scroll the list to the given item, such that the item is fully visible. pub fn scroll_to_reveal_item(&self, ix: usize) { let state = &mut *self.0.borrow_mut(); @@ -193,7 +225,8 @@ impl ListState { state.logical_scroll_top = Some(scroll_top); } - /// Get the bounds for the given item in window coordinates. + /// Get the bounds for the given item in window coordinates, if it's + /// been rendered. pub fn bounds_for_item(&self, ix: usize) -> Option> { let state = &*self.0.borrow(); @@ -310,9 +343,13 @@ impl std::fmt::Debug for ListItem { } } +/// An offset into the list's items, in terms of the item index and the number +/// of pixels off the top left of the item. #[derive(Debug, Clone, Copy, Default)] pub struct ListOffset { + /// The index of an item in the list pub item_ix: usize, + /// The number of pixels to offset from the item index. pub offset_in_item: Pixels, } diff --git a/crates/gpui/src/elements/overlay.rs b/crates/gpui/src/elements/overlay.rs index 0ba90864e7..7840cfbd63 100644 --- a/crates/gpui/src/elements/overlay.rs +++ b/crates/gpui/src/elements/overlay.rs @@ -6,10 +6,13 @@ use crate::{ Point, Size, Style, WindowContext, }; +/// The state that the overlay element uses to track its children. pub struct OverlayState { child_layout_ids: SmallVec<[LayoutId; 4]>, } +/// An overlay element that can be used to display UI that +/// floats on top of other UI elements. pub struct Overlay { children: SmallVec<[AnyElement; 2]>, anchor_corner: AnchorCorner, @@ -191,15 +194,21 @@ enum Axis { Vertical, } +/// Which algorithm to use when fitting the overlay to be inside the window. #[derive(Copy, Clone, PartialEq)] pub enum OverlayFitMode { + /// Snap the overlay to the window edge SnapToWindow, + /// Switch which corner anchor this overlay is attached to SwitchAnchor, } +/// Which algorithm to use when positioning the overlay. #[derive(Copy, Clone, PartialEq)] pub enum OverlayPositionMode { + /// Position the overlay relative to the window Window, + /// Position the overlay relative to its parent Local, } @@ -226,11 +235,16 @@ impl OverlayPositionMode { } } +/// Which corner of the overlay should be considered the anchor. #[derive(Clone, Copy, PartialEq, Eq)] pub enum AnchorCorner { + /// The top left corner TopLeft, + /// The top right corner TopRight, + /// The bottom left corner BottomLeft, + /// The bottom right corner BottomRight, } @@ -255,6 +269,7 @@ impl AnchorCorner { Bounds { origin, size } } + /// Get the point corresponding to this anchor corner in `bounds`. pub fn corner(&self, bounds: Bounds) -> Point { match self { Self::TopLeft => bounds.origin, diff --git a/crates/gpui/src/elements/svg.rs b/crates/gpui/src/elements/svg.rs index 5ea7f9bd78..370b4788f1 100644 --- a/crates/gpui/src/elements/svg.rs +++ b/crates/gpui/src/elements/svg.rs @@ -4,11 +4,13 @@ use crate::{ }; use util::ResultExt; +/// An SVG element. pub struct Svg { interactivity: Interactivity, path: Option, } +/// Create a new SVG element. pub fn svg() -> Svg { Svg { interactivity: Interactivity::default(), @@ -17,6 +19,7 @@ pub fn svg() -> Svg { } impl Svg { + /// Set the path to the SVG file for this element. pub fn path(mut self, path: impl Into) -> Self { self.path = Some(path.into()); self diff --git a/crates/gpui/src/elements/text.rs b/crates/gpui/src/elements/text.rs index 37736f7f93..cf8b9477ce 100644 --- a/crates/gpui/src/elements/text.rs +++ b/crates/gpui/src/elements/text.rs @@ -87,6 +87,7 @@ pub struct StyledText { } impl StyledText { + /// Construct a new styled text element from the given string. pub fn new(text: impl Into) -> Self { StyledText { text: text.into(), @@ -94,6 +95,8 @@ impl StyledText { } } + /// Set the styling attributes for the given text, as well as + /// as any ranges of text that have had their style customized. pub fn with_highlights( mut self, default_style: &TextStyle, @@ -151,6 +154,7 @@ impl IntoElement for StyledText { } } +#[doc(hidden)] #[derive(Default, Clone)] pub struct TextState(Arc>>); @@ -290,6 +294,7 @@ impl TextState { } } +/// A text element that can be interacted with. pub struct InteractiveText { element_id: ElementId, text: StyledText, @@ -305,6 +310,7 @@ struct InteractiveTextClickEvent { mouse_up_index: usize, } +#[doc(hidden)] pub struct InteractiveTextState { text_state: TextState, mouse_down_index: Rc>>, @@ -314,6 +320,7 @@ pub struct InteractiveTextState { /// InteractiveTest is a wrapper around StyledText that adds mouse interactions. impl InteractiveText { + /// Creates a new InteractiveText from the given text. pub fn new(id: impl Into, text: StyledText) -> Self { Self { element_id: id.into(), diff --git a/crates/gpui/src/elements/uniform_list.rs b/crates/gpui/src/elements/uniform_list.rs index 77ef7df10c..e92d920666 100644 --- a/crates/gpui/src/elements/uniform_list.rs +++ b/crates/gpui/src/elements/uniform_list.rs @@ -1,3 +1,9 @@ +//! A scrollable list of elements with uniform height, optimized for large lists. +//! Rather than use the full taffy layout system, uniform_list simply measures +//! the first element and then lays out all remaining elements in a line based on that +//! measurement. This is much faster than the full layout system, but only works for +//! elements with uniform height. + use crate::{ point, px, size, AnyElement, AvailableSpace, BorrowWindow, Bounds, ContentMask, Element, ElementId, InteractiveElement, InteractiveElementState, Interactivity, IntoElement, LayoutId, @@ -53,6 +59,7 @@ where } } +/// A list element for efficiently laying out and displaying a list of uniform-height elements. pub struct UniformList { id: ElementId, item_count: usize, @@ -63,18 +70,22 @@ pub struct UniformList { scroll_handle: Option, } +/// A handle for controlling the scroll position of a uniform list. +/// This should be stored in your view and passed to the uniform_list on each frame. #[derive(Clone, Default)] pub struct UniformListScrollHandle { deferred_scroll_to_item: Rc>>, } impl UniformListScrollHandle { + /// Create a new scroll handle to bind to a uniform list. pub fn new() -> Self { Self { deferred_scroll_to_item: Rc::new(RefCell::new(None)), } } + /// Scroll the list to the given item index. pub fn scroll_to_item(&mut self, ix: usize) { self.deferred_scroll_to_item.replace(Some(ix)); } @@ -86,6 +97,7 @@ impl Styled for UniformList { } } +#[doc(hidden)] #[derive(Default)] pub struct UniformListState { interactive: InteractiveElementState, @@ -262,6 +274,7 @@ impl IntoElement for UniformList { } impl UniformList { + /// Selects a specific list item for measurement. pub fn with_width_from_item(mut self, item_index: Option) -> Self { self.item_to_measure_index = item_index.unwrap_or(0); self @@ -284,6 +297,7 @@ impl UniformList { item_to_measure.measure(available_space, cx) } + /// Track and render scroll state of this list with reference to the given scroll handle. pub fn track_scroll(mut self, handle: UniformListScrollHandle) -> Self { self.scroll_handle = Some(handle); self diff --git a/crates/gpui/src/executor.rs b/crates/gpui/src/executor.rs index 88e46c28c4..1ca3c494ed 100644 --- a/crates/gpui/src/executor.rs +++ b/crates/gpui/src/executor.rs @@ -21,11 +21,15 @@ use waker_fn::waker_fn; #[cfg(any(test, feature = "test-support"))] use rand::rngs::StdRng; +/// A pointer to the executor that is currently running, +/// for spawning background tasks. #[derive(Clone)] pub struct BackgroundExecutor { dispatcher: Arc, } +/// A pointer to the executor that is currently running, +/// for spawning tasks on the main thread. #[derive(Clone)] pub struct ForegroundExecutor { dispatcher: Arc, @@ -37,11 +41,14 @@ pub struct ForegroundExecutor { /// It implements [`Future`] so you can `.await` on it. /// /// If you drop a task it will be cancelled immediately. Calling [`Task::detach`] allows -/// the task to continue running in the background, but with no way to return a value. +/// the task to continue running, but with no way to return a value. #[must_use] #[derive(Debug)] pub enum Task { + /// A task that is ready to return a value Ready(Option), + + /// A task that is currently running. Spawned(async_task::Task), } @@ -87,6 +94,8 @@ impl Future for Task { } } +/// A task label is an opaque identifier that you can use to +/// refer to a task in tests. #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] pub struct TaskLabel(NonZeroUsize); @@ -97,6 +106,7 @@ impl Default for TaskLabel { } impl TaskLabel { + /// Construct a new task label. pub fn new() -> Self { static NEXT_TASK_LABEL: AtomicUsize = AtomicUsize::new(1); Self(NEXT_TASK_LABEL.fetch_add(1, SeqCst).try_into().unwrap()) @@ -363,6 +373,7 @@ impl BackgroundExecutor { /// ForegroundExecutor runs things on the main thread. impl ForegroundExecutor { + /// Creates a new ForegroundExecutor from the given PlatformDispatcher. pub fn new(dispatcher: Arc) -> Self { Self { dispatcher, @@ -411,13 +422,14 @@ impl<'a> Scope<'a> { } } + /// Spawn a future into this scope. pub fn spawn(&mut self, f: F) where F: Future + Send + 'a, { let tx = self.tx.clone().unwrap(); - // Safety: The 'a lifetime is guaranteed to outlive any of these futures because + // SAFETY: The 'a lifetime is guaranteed to outlive any of these futures because // dropping this `Scope` blocks until all of the futures have resolved. let f = unsafe { mem::transmute::< diff --git a/crates/gpui/src/gpui.rs b/crates/gpui/src/gpui.rs index 6f5e30149d..5bdece07e7 100644 --- a/crates/gpui/src/gpui.rs +++ b/crates/gpui/src/gpui.rs @@ -1,3 +1,33 @@ +//! # Welcome to GPUI! +//! +//! GPUI is a hybrid immedate and retained mode, GPU accelerated, UI framework +//! for Rust, designed to support a wide variety of applications. GPUI is currently +//! being actively developed and improved for the [Zed code editor](https://zed.dev/), and new versions +//! will have breaking changes. You'll probably need to use the latest stable version +//! of rust to use GPUI. +//! +//! # Getting started with GPUI +//! +//! TODO: Write a code sample showing how to create a window and render a simple +//! div +//! +//! # Drawing interesting things +//! +//! TODO: Expand demo to show how to draw a more interesting scene, with +//! a counter to store state and a button to increment it. +//! +//! # Interacting with your application state +//! +//! TODO: Expand demo to show GPUI entity interactions, like subscriptions and entities +//! maybe make a network request to show async stuff? +//! +//! # Conclusion +//! +//! TODO: Wrap up with a conclusion and links to other places? Zed / GPUI website? +//! Discord for chatting about it? Other tutorials or references? + +#![deny(missing_docs)] + #[macro_use] mod action; mod app; @@ -58,10 +88,10 @@ pub use elements::*; pub use executor::*; pub use geometry::*; pub use gpui_macros::{register_action, test, IntoElement, Render}; -pub use image_cache::*; +use image_cache::*; pub use input::*; pub use interactive::*; -pub use key_dispatch::*; +use key_dispatch::*; pub use keymap::*; pub use platform::*; pub use refineable::*; @@ -73,7 +103,7 @@ pub use smol::Timer; pub use style::*; pub use styled::*; pub use subscription::*; -pub use svg_renderer::*; +use svg_renderer::*; pub use taffy::{AvailableSpace, LayoutId}; #[cfg(any(test, feature = "test-support"))] pub use test::*; @@ -82,20 +112,23 @@ pub use util::arc_cow::ArcCow; pub use view::*; pub use window::*; -use std::{ - any::{Any, TypeId}, - borrow::BorrowMut, -}; +use std::{any::Any, borrow::BorrowMut}; use taffy::TaffyLayoutEngine; +/// The context trait, allows the different contexts in GPUI to be used +/// interchangeably for certain operations. pub trait Context { + /// The result type for this context, used for async contexts that + /// can't hold a direct reference to the application context. type Result; + /// Create a new model in the app context. fn new_model( &mut self, build_model: impl FnOnce(&mut ModelContext<'_, T>) -> T, ) -> Self::Result>; + /// Update a model in the app context. fn update_model( &mut self, handle: &Model, @@ -104,6 +137,7 @@ pub trait Context { where T: 'static; + /// Read a model from the app context. fn read_model( &self, handle: &Model, @@ -112,10 +146,12 @@ pub trait Context { where T: 'static; + /// Update a window for the given handle. fn update_window(&mut self, window: AnyWindowHandle, f: F) -> Result where F: FnOnce(AnyView, &mut WindowContext<'_>) -> T; + /// Read a window off of the application context. fn read_window( &self, window: &WindowHandle, @@ -125,7 +161,10 @@ pub trait Context { T: 'static; } +/// This trait is used for the different visual contexts in GPUI that +/// require a window to be present. pub trait VisualContext: Context { + /// Construct a new view in the window referenced by this context. fn new_view( &mut self, build_view: impl FnOnce(&mut ViewContext<'_, V>) -> V, @@ -133,12 +172,14 @@ pub trait VisualContext: Context { where V: 'static + Render; + /// Update a view with the given callback fn update_view( &mut self, view: &View, update: impl FnOnce(&mut V, &mut ViewContext<'_, V>) -> R, ) -> Self::Result; + /// Replace the root view of a window with a new view. fn replace_root_view( &mut self, build_view: impl FnOnce(&mut ViewContext<'_, V>) -> V, @@ -146,38 +187,47 @@ pub trait VisualContext: Context { where V: 'static + Render; + /// Focus a view in the window, if it implements the [`FocusableView`] trait. fn focus_view(&mut self, view: &View) -> Self::Result<()> where V: FocusableView; + /// Dismiss a view in the window, if it implements the [`ManagedView`] trait. fn dismiss_view(&mut self, view: &View) -> Self::Result<()> where V: ManagedView; } +/// A trait that allows models and views to be interchangeable in certain operations pub trait Entity: Sealed { + /// The weak reference type for this entity. type Weak: 'static; + /// The ID for this entity fn entity_id(&self) -> EntityId; + + /// Downgrade this entity to a weak reference. fn downgrade(&self) -> Self::Weak; + + /// Upgrade this entity from a weak reference. fn upgrade_from(weak: &Self::Weak) -> Option where Self: Sized; } +/// A trait for tying together the types of a GPUI entity and the events it can +/// emit. pub trait EventEmitter: 'static {} -pub enum GlobalKey { - Numeric(usize), - View(EntityId), - Type(TypeId), -} - +/// A helper trait for auto-implementing certain methods on contexts that +/// can be used interchangeably. pub trait BorrowAppContext { + /// Run a closure with a text style pushed onto the context. fn with_text_style(&mut self, style: Option, f: F) -> R where F: FnOnce(&mut Self) -> R; + /// Set a global value on the context. fn set_global(&mut self, global: T); } @@ -204,7 +254,9 @@ where } } +/// A flatten equivalent for anyhow `Result`s. pub trait Flatten { + /// Convert this type into a simple `Result`. fn flatten(self) -> Result; } diff --git a/crates/gpui/src/image_cache.rs b/crates/gpui/src/image_cache.rs index 0d6ec81557..dd7b7b571e 100644 --- a/crates/gpui/src/image_cache.rs +++ b/crates/gpui/src/image_cache.rs @@ -11,12 +11,12 @@ use thiserror::Error; use util::http::{self, HttpClient}; #[derive(PartialEq, Eq, Hash, Clone)] -pub struct RenderImageParams { +pub(crate) struct RenderImageParams { pub(crate) image_id: ImageId, } #[derive(Debug, Error, Clone)] -pub enum Error { +pub(crate) enum Error { #[error("http error: {0}")] Client(#[from] http::Error), #[error("IO error: {0}")] @@ -42,7 +42,7 @@ impl From for Error { } } -pub struct ImageCache { +pub(crate) struct ImageCache { client: Arc, images: Arc>>, } diff --git a/crates/gpui/src/input.rs b/crates/gpui/src/input.rs index 3440d08ef3..440d6d17fd 100644 --- a/crates/gpui/src/input.rs +++ b/crates/gpui/src/input.rs @@ -3,20 +3,33 @@ use std::ops::Range; /// Implement this trait to allow views to handle textual input when implementing an editor, field, etc. /// -/// Once your view `V` implements this trait, you can use it to construct an [`ElementInputHandler`]. +/// Once your view implements this trait, you can use it to construct an [`ElementInputHandler`]. /// This input handler can then be assigned during paint by calling [`WindowContext::handle_input`]. +/// +/// See [`InputHandler`] for details on how to implement each method. pub trait ViewInputHandler: 'static + Sized { + /// See [`InputHandler::text_for_range`] for details fn text_for_range(&mut self, range: Range, cx: &mut ViewContext) -> Option; + + /// See [`InputHandler::selected_text_range`] for details fn selected_text_range(&mut self, cx: &mut ViewContext) -> Option>; + + /// See [`InputHandler::marked_text_range`] for details fn marked_text_range(&self, cx: &mut ViewContext) -> Option>; + + /// See [`InputHandler::unmark_text`] for details fn unmark_text(&mut self, cx: &mut ViewContext); + + /// See [`InputHandler::replace_text_in_range`] for details fn replace_text_in_range( &mut self, range: Option>, text: &str, cx: &mut ViewContext, ); + + /// See [`InputHandler::replace_and_mark_text_in_range`] for details fn replace_and_mark_text_in_range( &mut self, range: Option>, @@ -24,6 +37,8 @@ pub trait ViewInputHandler: 'static + Sized { new_selected_range: Option>, cx: &mut ViewContext, ); + + /// See [`InputHandler::bounds_for_range`] for details fn bounds_for_range( &mut self, range_utf16: Range, diff --git a/crates/gpui/src/interactive.rs b/crates/gpui/src/interactive.rs index 86e0a6378e..4faa92ce04 100644 --- a/crates/gpui/src/interactive.rs +++ b/crates/gpui/src/interactive.rs @@ -4,15 +4,25 @@ use crate::{ use smallvec::SmallVec; use std::{any::Any, fmt::Debug, ops::Deref, path::PathBuf}; +/// An event from a platform input source. pub trait InputEvent: Sealed + 'static { + /// Convert this event into the platform input enum. fn to_platform_input(self) -> PlatformInput; } + +/// A key event from the platform. pub trait KeyEvent: InputEvent {} + +/// A mouse event from the platform. pub trait MouseEvent: InputEvent {} +/// The key down event equivalent for the platform. #[derive(Clone, Debug, Eq, PartialEq)] pub struct KeyDownEvent { + /// The keystroke that was generated. pub keystroke: Keystroke, + + /// Whether the key is currently held down. pub is_held: bool, } @@ -24,8 +34,10 @@ impl InputEvent for KeyDownEvent { } impl KeyEvent for KeyDownEvent {} +/// The key up event equivalent for the platform. #[derive(Clone, Debug)] pub struct KeyUpEvent { + /// The keystroke that was released. pub keystroke: Keystroke, } @@ -37,8 +49,10 @@ impl InputEvent for KeyUpEvent { } impl KeyEvent for KeyUpEvent {} +/// The modifiers changed event equivalent for the platform. #[derive(Clone, Debug, Default)] pub struct ModifiersChangedEvent { + /// The new state of the modifier keys pub modifiers: Modifiers, } @@ -62,17 +76,28 @@ impl Deref for ModifiersChangedEvent { /// Based on the winit enum of the same name. #[derive(Clone, Copy, Debug, Default)] pub enum TouchPhase { + /// The touch started. Started, + /// The touch event is moving. #[default] Moved, + /// The touch phase has ended Ended, } +/// A mouse down event from the platform #[derive(Clone, Debug, Default)] pub struct MouseDownEvent { + /// Which mouse button was pressed. pub button: MouseButton, + + /// The position of the mouse on the window. pub position: Point, + + /// The modifiers that were held down when the mouse was pressed. pub modifiers: Modifiers, + + /// The number of times the button has been clicked. pub click_count: usize, } @@ -84,11 +109,19 @@ impl InputEvent for MouseDownEvent { } impl MouseEvent for MouseDownEvent {} +/// A mouse up event from the platform #[derive(Clone, Debug, Default)] pub struct MouseUpEvent { + /// Which mouse button was released. pub button: MouseButton, + + /// The position of the mouse on the window. pub position: Point, + + /// The modifiers that were held down when the mouse was released. pub modifiers: Modifiers, + + /// The number of times the button has been clicked. pub click_count: usize, } @@ -100,21 +133,34 @@ impl InputEvent for MouseUpEvent { } impl MouseEvent for MouseUpEvent {} +/// A click event, generated when a mouse button is pressed and released. #[derive(Clone, Debug, Default)] pub struct ClickEvent { + /// The mouse event when the button was pressed. pub down: MouseDownEvent, + + /// The mouse event when the button was released. pub up: MouseUpEvent, } +/// An enum representing the mouse button that was pressed. #[derive(Hash, PartialEq, Eq, Copy, Clone, Debug)] pub enum MouseButton { + /// The left mouse button. Left, + + /// The right mouse button. Right, + + /// The middle mouse button. Middle, + + /// A navigation button, such as back or forward. Navigate(NavigationDirection), } impl MouseButton { + /// Get all the mouse buttons in a list. pub fn all() -> Vec { vec![ MouseButton::Left, @@ -132,9 +178,13 @@ impl Default for MouseButton { } } +/// A navigation direction, such as back or forward. #[derive(Hash, PartialEq, Eq, Copy, Clone, Debug)] pub enum NavigationDirection { + /// The back button. Back, + + /// The forward button. Forward, } @@ -144,10 +194,16 @@ impl Default for NavigationDirection { } } +/// A mouse move event from the platform #[derive(Clone, Debug, Default)] pub struct MouseMoveEvent { + /// The position of the mouse on the window. pub position: Point, + + /// The mouse button that was pressed, if any. pub pressed_button: Option, + + /// The modifiers that were held down when the mouse was moved. pub modifiers: Modifiers, } @@ -160,16 +216,25 @@ impl InputEvent for MouseMoveEvent { impl MouseEvent for MouseMoveEvent {} impl MouseMoveEvent { + /// Returns true if the left mouse button is currently held down. pub fn dragging(&self) -> bool { self.pressed_button == Some(MouseButton::Left) } } +/// A mouse wheel event from the platform #[derive(Clone, Debug, Default)] pub struct ScrollWheelEvent { + /// The position of the mouse on the window. pub position: Point, + + /// The change in scroll wheel position for this event. pub delta: ScrollDelta, + + /// The modifiers that were held down when the mouse was moved. pub modifiers: Modifiers, + + /// The phase of the touch event. pub touch_phase: TouchPhase, } @@ -189,9 +254,12 @@ impl Deref for ScrollWheelEvent { } } +/// The scroll delta for a scroll wheel event. #[derive(Clone, Copy, Debug)] pub enum ScrollDelta { + /// An exact scroll delta in pixels. Pixels(Point), + /// An inexact scroll delta in lines. Lines(Point), } @@ -202,6 +270,7 @@ impl Default for ScrollDelta { } impl ScrollDelta { + /// Returns true if this is a precise scroll delta in pixels. pub fn precise(&self) -> bool { match self { ScrollDelta::Pixels(_) => true, @@ -209,6 +278,7 @@ impl ScrollDelta { } } + /// Converts this scroll event into exact pixels. pub fn pixel_delta(&self, line_height: Pixels) -> Point { match self { ScrollDelta::Pixels(delta) => *delta, @@ -216,6 +286,7 @@ impl ScrollDelta { } } + /// Combines two scroll deltas into one. pub fn coalesce(self, other: ScrollDelta) -> ScrollDelta { match (self, other) { (ScrollDelta::Pixels(px_a), ScrollDelta::Pixels(px_b)) => { @@ -231,10 +302,15 @@ impl ScrollDelta { } } +/// A mouse exit event from the platform, generated when the mouse leaves the window. +/// The position generated should be just outside of the window's bounds. #[derive(Clone, Debug, Default)] pub struct MouseExitEvent { + /// The position of the mouse relative to the window. pub position: Point, + /// The mouse button that was pressed, if any. pub pressed_button: Option, + /// The modifiers that were held down when the mouse was moved. pub modifiers: Modifiers, } @@ -254,10 +330,12 @@ impl Deref for MouseExitEvent { } } +/// A collection of paths from the platform, such as from a file drop. #[derive(Debug, Clone, Default)] pub struct ExternalPaths(pub(crate) SmallVec<[PathBuf; 2]>); impl ExternalPaths { + /// Convert this collection of paths into a slice. pub fn paths(&self) -> &[PathBuf] { &self.0 } @@ -269,18 +347,27 @@ impl Render for ExternalPaths { } } +/// A file drop event from the platform, generated when files are dragged and dropped onto the window. #[derive(Debug, Clone)] pub enum FileDropEvent { + /// The files have entered the window. Entered { + /// The position of the mouse relative to the window. position: Point, + /// The paths of the files that are being dragged. paths: ExternalPaths, }, + /// The files are being dragged over the window Pending { + /// The position of the mouse relative to the window. position: Point, }, + /// The files have been dropped onto the window. Submit { + /// The position of the mouse relative to the window. position: Point, }, + /// The user has stopped dragging the files over the window. Exited, } @@ -292,40 +379,31 @@ impl InputEvent for FileDropEvent { } impl MouseEvent for FileDropEvent {} +/// An enum corresponding to all kinds of platform input events. #[derive(Clone, Debug)] pub enum PlatformInput { + /// A key was pressed. KeyDown(KeyDownEvent), + /// A key was released. KeyUp(KeyUpEvent), + /// The keyboard modifiers were changed. ModifiersChanged(ModifiersChangedEvent), + /// The mouse was pressed. MouseDown(MouseDownEvent), + /// The mouse was released. MouseUp(MouseUpEvent), + /// The mouse was moved. MouseMove(MouseMoveEvent), + /// The mouse exited the window. MouseExited(MouseExitEvent), + /// The scroll wheel was used. ScrollWheel(ScrollWheelEvent), + /// Files were dragged and dropped onto the window. FileDrop(FileDropEvent), } impl PlatformInput { - pub fn position(&self) -> Option> { - match self { - PlatformInput::KeyDown { .. } => None, - PlatformInput::KeyUp { .. } => None, - PlatformInput::ModifiersChanged { .. } => None, - PlatformInput::MouseDown(event) => Some(event.position), - PlatformInput::MouseUp(event) => Some(event.position), - PlatformInput::MouseMove(event) => Some(event.position), - PlatformInput::MouseExited(event) => Some(event.position), - PlatformInput::ScrollWheel(event) => Some(event.position), - PlatformInput::FileDrop(FileDropEvent::Exited) => None, - PlatformInput::FileDrop( - FileDropEvent::Entered { position, .. } - | FileDropEvent::Pending { position, .. } - | FileDropEvent::Submit { position, .. }, - ) => Some(*position), - } - } - - pub fn mouse_event(&self) -> Option<&dyn Any> { + pub(crate) fn mouse_event(&self) -> Option<&dyn Any> { match self { PlatformInput::KeyDown { .. } => None, PlatformInput::KeyUp { .. } => None, @@ -339,7 +417,7 @@ impl PlatformInput { } } - pub fn keyboard_event(&self) -> Option<&dyn Any> { + pub(crate) fn keyboard_event(&self) -> Option<&dyn Any> { match self { PlatformInput::KeyDown(event) => Some(event), PlatformInput::KeyUp(event) => Some(event), diff --git a/crates/gpui/src/key_dispatch.rs b/crates/gpui/src/key_dispatch.rs index 85a67168e5..875d7a5b2b 100644 --- a/crates/gpui/src/key_dispatch.rs +++ b/crates/gpui/src/key_dispatch.rs @@ -13,7 +13,7 @@ use std::{ }; #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] -pub struct DispatchNodeId(usize); +pub(crate) struct DispatchNodeId(usize); pub(crate) struct DispatchTree { node_stack: Vec, diff --git a/crates/gpui/src/keymap/binding.rs b/crates/gpui/src/keymap/binding.rs index 766e54f473..3f9f09f31b 100644 --- a/crates/gpui/src/keymap/binding.rs +++ b/crates/gpui/src/keymap/binding.rs @@ -2,6 +2,7 @@ use crate::{Action, KeyBindingContextPredicate, KeyMatch, Keystroke}; use anyhow::Result; use smallvec::SmallVec; +/// A keybinding and it's associated metadata, from the keymap. pub struct KeyBinding { pub(crate) action: Box, pub(crate) keystrokes: SmallVec<[Keystroke; 2]>, @@ -19,10 +20,12 @@ impl Clone for KeyBinding { } impl KeyBinding { + /// Construct a new keybinding from the given data. pub fn new(keystrokes: &str, action: A, context_predicate: Option<&str>) -> Self { Self::load(keystrokes, Box::new(action), context_predicate).unwrap() } + /// Load a keybinding from the given raw data. pub fn load(keystrokes: &str, action: Box, context: Option<&str>) -> Result { let context = if let Some(context) = context { Some(KeyBindingContextPredicate::parse(context)?) @@ -42,6 +45,7 @@ impl KeyBinding { }) } + /// Check if the given keystrokes match this binding. pub fn match_keystrokes(&self, pending_keystrokes: &[Keystroke]) -> KeyMatch { if self.keystrokes.as_ref().starts_with(pending_keystrokes) { // If the binding is completed, push it onto the matches list @@ -55,10 +59,12 @@ impl KeyBinding { } } + /// Get the keystrokes associated with this binding pub fn keystrokes(&self) -> &[Keystroke] { self.keystrokes.as_slice() } + /// Get the action associated with this binding pub fn action(&self) -> &dyn Action { self.action.as_ref() } diff --git a/crates/gpui/src/keymap/context.rs b/crates/gpui/src/keymap/context.rs index bfa97b7afe..8d2ddbb63d 100644 --- a/crates/gpui/src/keymap/context.rs +++ b/crates/gpui/src/keymap/context.rs @@ -3,6 +3,10 @@ use anyhow::{anyhow, Result}; use smallvec::SmallVec; use std::fmt; +/// A datastructure for resolving whether an action should be dispatched +/// at this point in the element tree. Contains a set of identifiers +/// and/or key value pairs representing the current context for the +/// keymap. #[derive(Clone, Default, Eq, PartialEq, Hash)] pub struct KeyContext(SmallVec<[ContextEntry; 1]>); @@ -21,6 +25,11 @@ impl<'a> TryFrom<&'a str> for KeyContext { } impl KeyContext { + /// Parse a key context from a string. + /// The key context format is very simple: + /// - either a single identifier, such as `StatusBar` + /// - or a key value pair, such as `mode = visible` + /// - seperated by whitespace, such as `StatusBar mode = visible` pub fn parse(source: &str) -> Result { let mut context = Self::default(); let source = skip_whitespace(source); @@ -53,14 +62,17 @@ impl KeyContext { Self::parse_expr(source, context) } + /// Check if this context is empty. pub fn is_empty(&self) -> bool { self.0.is_empty() } + /// Clear this context. pub fn clear(&mut self) { self.0.clear(); } + /// Extend this context with another context. pub fn extend(&mut self, other: &Self) { for entry in &other.0 { if !self.contains(&entry.key) { @@ -69,6 +81,7 @@ impl KeyContext { } } + /// Add an identifier to this context, if it's not already in this context. pub fn add>(&mut self, identifier: I) { let key = identifier.into(); @@ -77,6 +90,7 @@ impl KeyContext { } } + /// Set a key value pair in this context, if it's not already set. pub fn set, S2: Into>(&mut self, key: S1, value: S2) { let key = key.into(); if !self.contains(&key) { @@ -87,10 +101,12 @@ impl KeyContext { } } + /// Check if this context contains a given identifier or key. pub fn contains(&self, key: &str) -> bool { self.0.iter().any(|entry| entry.key.as_ref() == key) } + /// Get the associated value for a given identifier or key. pub fn get(&self, key: &str) -> Option<&SharedString> { self.0 .iter() @@ -117,20 +133,31 @@ impl fmt::Debug for KeyContext { } } +/// A datastructure for resolving whether an action should be dispatched +/// Representing a small language for describing which contexts correspond +/// to which actions. #[derive(Clone, Debug, Eq, PartialEq, Hash)] pub enum KeyBindingContextPredicate { + /// A predicate that will match a given identifier. Identifier(SharedString), + /// A predicate that will match a given key-value pair. Equal(SharedString, SharedString), + /// A predicate that will match a given key-value pair not being present. NotEqual(SharedString, SharedString), + /// A predicate that will match a given predicate appearing below another predicate. + /// in the element tree Child( Box, Box, ), + /// Predicate that will invert another predicate. Not(Box), + /// A predicate that will match if both of its children match. And( Box, Box, ), + /// A predicate that will match if either of its children match. Or( Box, Box, @@ -138,6 +165,34 @@ pub enum KeyBindingContextPredicate { } impl KeyBindingContextPredicate { + /// Parse a string in the same format as the keymap's context field. + /// + /// A basic equivalence check against a set of identifiers can performed by + /// simply writing a string: + /// + /// `StatusBar` -> A predicate that will match a context with the identifier `StatusBar` + /// + /// You can also specify a key-value pair: + /// + /// `mode == visible` -> A predicate that will match a context with the key `mode` + /// with the value `visible` + /// + /// And a logical operations combining these two checks: + /// + /// `StatusBar && mode == visible` -> A predicate that will match a context with the + /// identifier `StatusBar` and the key `mode` + /// with the value `visible` + /// + /// + /// There is also a special child `>` operator that will match a predicate that is + /// below another predicate: + /// + /// `StatusBar > mode == visible` -> A predicate that will match a context identifier `StatusBar` + /// and a child context that has the key `mode` with the + /// value `visible` + /// + /// This syntax supports `!=`, `||` and `&&` as logical operators. + /// You can also preface an operation or check with a `!` to negate it. pub fn parse(source: &str) -> Result { let source = skip_whitespace(source); let (predicate, rest) = Self::parse_expr(source, 0)?; @@ -148,6 +203,7 @@ impl KeyBindingContextPredicate { } } + /// Eval a predicate against a set of contexts, arranged from lowest to highest. pub fn eval(&self, contexts: &[KeyContext]) -> bool { let Some(context) = contexts.last() else { return false; diff --git a/crates/gpui/src/keymap/keymap.rs b/crates/gpui/src/keymap/keymap.rs index 8c74e12e08..2eefbb841e 100644 --- a/crates/gpui/src/keymap/keymap.rs +++ b/crates/gpui/src/keymap/keymap.rs @@ -6,9 +6,12 @@ use std::{ collections::HashMap, }; +/// An opaque identifier of which version of the keymap is currently active. +/// The keymap's version is changed whenever bindings are added or removed. #[derive(Copy, Clone, Eq, PartialEq, Default)] pub struct KeymapVersion(usize); +/// A collection of key bindings for the user's application. #[derive(Default)] pub struct Keymap { bindings: Vec, @@ -19,16 +22,19 @@ pub struct Keymap { } impl Keymap { + /// Create a new keymap with the given bindings. pub fn new(bindings: Vec) -> Self { let mut this = Self::default(); this.add_bindings(bindings); this } + /// Get the current version of the keymap. pub fn version(&self) -> KeymapVersion { self.version } + /// Add more bindings to the keymap. pub fn add_bindings>(&mut self, bindings: T) { let no_action_id = (NoAction {}).type_id(); @@ -51,6 +57,7 @@ impl Keymap { self.version.0 += 1; } + /// Reset this keymap to its initial state. pub fn clear(&mut self) { self.bindings.clear(); self.binding_indices_by_action_id.clear(); @@ -77,6 +84,7 @@ impl Keymap { .filter(move |binding| binding.action().partial_eq(action)) } + /// Check if the given binding is enabled, given a certain key context. pub fn binding_enabled(&self, binding: &KeyBinding, context: &[KeyContext]) -> bool { // If binding has a context predicate, it must match the current context, if let Some(predicate) = &binding.context_predicate { diff --git a/crates/gpui/src/keymap/matcher.rs b/crates/gpui/src/keymap/matcher.rs index 934becb0d1..9f8759b2a9 100644 --- a/crates/gpui/src/keymap/matcher.rs +++ b/crates/gpui/src/keymap/matcher.rs @@ -2,7 +2,7 @@ use crate::{Action, KeyContext, Keymap, KeymapVersion, Keystroke}; use parking_lot::Mutex; use std::sync::Arc; -pub struct KeystrokeMatcher { +pub(crate) struct KeystrokeMatcher { pending_keystrokes: Vec, keymap: Arc>, keymap_version: KeymapVersion, @@ -35,7 +35,7 @@ impl KeystrokeMatcher { /// - KeyMatch::Complete(matches) => /// One or more bindings have received the necessary key presses. /// Bindings added later will take precedence over earlier bindings. - pub fn match_keystroke( + pub(crate) fn match_keystroke( &mut self, keystroke: &Keystroke, context_stack: &[KeyContext], @@ -85,6 +85,10 @@ impl KeystrokeMatcher { } } +/// The result of matching a keystroke against a given keybinding. +/// - KeyMatch::None => No match is valid for this key given any pending keystrokes. +/// - KeyMatch::Pending => There exist bindings that is still waiting for more keys. +/// - KeyMatch::Some(matches) => One or more bindings have received the necessary key presses. #[derive(Debug)] pub enum KeyMatch { None, @@ -92,19 +96,6 @@ pub enum KeyMatch { Some(Vec>), } -impl KeyMatch { - pub fn is_some(&self) -> bool { - matches!(self, KeyMatch::Some(_)) - } - - pub fn matches(self) -> Option>> { - match self { - KeyMatch::Some(matches) => Some(matches), - _ => None, - } - } -} - impl PartialEq for KeyMatch { fn eq(&self, other: &Self) -> bool { match (self, other) { diff --git a/crates/gpui/src/keymap/mod.rs b/crates/gpui/src/keymap/mod.rs index 09e222c095..6f1a018322 100644 --- a/crates/gpui/src/keymap/mod.rs +++ b/crates/gpui/src/keymap/mod.rs @@ -6,4 +6,4 @@ mod matcher; pub use binding::*; pub use context::*; pub use keymap::*; -pub use matcher::*; +pub(crate) use matcher::*; diff --git a/crates/gpui/src/prelude.rs b/crates/gpui/src/prelude.rs index 218cbd0e28..2ab115fa62 100644 --- a/crates/gpui/src/prelude.rs +++ b/crates/gpui/src/prelude.rs @@ -1,3 +1,7 @@ +//! The GPUI prelude is a collection of traits and types that are widely used +//! throughout the library. It is recommended to import this prelude into your +//! application to avoid having to import each trait individually. + pub use crate::{ util::FluentBuilder, BorrowAppContext, BorrowWindow, Context, Element, FocusableElement, InteractiveElement, IntoElement, ParentElement, Refineable, Render, RenderOnce, diff --git a/crates/gpui/src/scene.rs b/crates/gpui/src/scene.rs index b69c10c752..d0b00f71c8 100644 --- a/crates/gpui/src/scene.rs +++ b/crates/gpui/src/scene.rs @@ -10,12 +10,12 @@ pub(crate) type PointF = Point; #[allow(non_camel_case_types, unused)] pub(crate) type PathVertex_ScaledPixels = PathVertex; -pub type LayerId = u32; -pub type DrawOrder = u32; +pub(crate) type LayerId = u32; +pub(crate) type DrawOrder = u32; #[derive(Default, Copy, Clone, Debug, Eq, PartialEq, Hash)] #[repr(C)] -pub struct ViewId { +pub(crate) struct ViewId { low_bits: u32, high_bits: u32, } @@ -38,7 +38,7 @@ impl From for EntityId { } #[derive(Default)] -pub struct Scene { +pub(crate) struct Scene { layers_by_order: BTreeMap, orders_by_layer: BTreeMap, pub(crate) shadows: Vec, @@ -429,7 +429,7 @@ impl<'a> Iterator for BatchIterator<'a> { } #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Default)] -pub enum PrimitiveKind { +pub(crate) enum PrimitiveKind { Shadow, #[default] Quad, @@ -495,7 +495,7 @@ pub(crate) enum PrimitiveBatch<'a> { #[derive(Default, Debug, Clone, Eq, PartialEq)] #[repr(C)] -pub struct Quad { +pub(crate) struct Quad { pub view_id: ViewId, pub layer_id: LayerId, pub order: DrawOrder, @@ -527,7 +527,7 @@ impl From for Primitive { #[derive(Debug, Clone, Eq, PartialEq)] #[repr(C)] -pub struct Underline { +pub(crate) struct Underline { pub view_id: ViewId, pub layer_id: LayerId, pub order: DrawOrder, @@ -558,7 +558,7 @@ impl From for Primitive { #[derive(Debug, Clone, Eq, PartialEq)] #[repr(C)] -pub struct Shadow { +pub(crate) struct Shadow { pub view_id: ViewId, pub layer_id: LayerId, pub order: DrawOrder, @@ -655,7 +655,7 @@ impl From for Primitive { } #[derive(Clone, Debug, Eq, PartialEq)] -pub struct Surface { +pub(crate) struct Surface { pub view_id: ViewId, pub layer_id: LayerId, pub order: DrawOrder, @@ -685,6 +685,7 @@ impl From for Primitive { #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub(crate) struct PathId(pub(crate) usize); +/// A line made up of a series of vertices and control points. #[derive(Debug)] pub struct Path { pub(crate) id: PathId, @@ -701,6 +702,7 @@ pub struct Path { } impl Path { + /// Create a new path with the given starting point. pub fn new(start: Point) -> Self { Self { id: PathId(0), @@ -720,6 +722,7 @@ impl Path { } } + /// Scale this path by the given factor. pub fn scale(&self, factor: f32) -> Path { Path { id: self.id, @@ -740,6 +743,7 @@ impl Path { } } + /// Draw a straight line from the current point to the given point. pub fn line_to(&mut self, to: Point) { self.contour_count += 1; if self.contour_count > 1 { @@ -751,6 +755,7 @@ impl Path { self.current = to; } + /// Draw a curve from the current point to the given point, using the given control point. pub fn curve_to(&mut self, to: Point, ctrl: Point) { self.contour_count += 1; if self.contour_count > 1 { @@ -833,7 +838,7 @@ impl From> for Primitive { #[derive(Clone, Debug)] #[repr(C)] -pub struct PathVertex { +pub(crate) struct PathVertex { pub(crate) xy_position: Point

, pub(crate) st_position: Point, pub(crate) content_mask: ContentMask

, @@ -850,4 +855,4 @@ impl PathVertex { } #[derive(Copy, Clone, Debug)] -pub struct AtlasId(pub(crate) usize); +pub(crate) struct AtlasId(pub(crate) usize); diff --git a/crates/gpui/src/shared_string.rs b/crates/gpui/src/shared_string.rs index 97db4bd191..d196b19636 100644 --- a/crates/gpui/src/shared_string.rs +++ b/crates/gpui/src/shared_string.rs @@ -3,6 +3,8 @@ use serde::{Deserialize, Serialize}; use std::{borrow::Borrow, sync::Arc}; use util::arc_cow::ArcCow; +/// A shared string is an immutable string that can be cheaply cloned in GPUI +/// tasks. Essentially an abstraction over an Arc and &'static str, #[derive(Deref, DerefMut, Eq, PartialEq, Hash, Clone)] pub struct SharedString(ArcCow<'static, str>); diff --git a/crates/gpui/src/subscription.rs b/crates/gpui/src/subscription.rs index 887283d094..9dca2e3a48 100644 --- a/crates/gpui/src/subscription.rs +++ b/crates/gpui/src/subscription.rs @@ -147,12 +147,17 @@ where } } +/// A handle to a subscription created by GPUI. When dropped, the subscription +/// is cancelled and the callback will no longer be invoked. #[must_use] pub struct Subscription { unsubscribe: Option>, } impl Subscription { + /// Detaches the subscription from this handle. The callback will + /// continue to be invoked until the views or models it has been + /// subscribed to are dropped pub fn detach(mut self) { self.unsubscribe.take(); } diff --git a/crates/gpui/src/svg_renderer.rs b/crates/gpui/src/svg_renderer.rs index 96e6658ab1..978d5a626b 100644 --- a/crates/gpui/src/svg_renderer.rs +++ b/crates/gpui/src/svg_renderer.rs @@ -3,12 +3,12 @@ use anyhow::anyhow; use std::{hash::Hash, sync::Arc}; #[derive(Clone, PartialEq, Hash, Eq)] -pub struct RenderSvgParams { +pub(crate) struct RenderSvgParams { pub(crate) path: SharedString, pub(crate) size: Size, } -pub struct SvgRenderer { +pub(crate) struct SvgRenderer { asset_source: Arc, } diff --git a/crates/gpui/src/taffy.rs b/crates/gpui/src/taffy.rs index 26d5a2e69e..ea7a4575cc 100644 --- a/crates/gpui/src/taffy.rs +++ b/crates/gpui/src/taffy.rs @@ -229,6 +229,7 @@ impl TaffyLayoutEngine { } } +/// A unique identifier for a layout node, generated when requesting a layout from Taffy #[derive(Copy, Clone, Eq, PartialEq, Debug)] #[repr(transparent)] pub struct LayoutId(NodeId); @@ -440,6 +441,7 @@ where } } +/// The space available for an element to be laid out in #[derive(Copy, Clone, Default, Debug, Eq, PartialEq)] pub enum AvailableSpace { /// The amount of space available is the specified number of pixels diff --git a/crates/gpui/src/test.rs b/crates/gpui/src/test.rs index f53d19fdc8..d8c81d52b8 100644 --- a/crates/gpui/src/test.rs +++ b/crates/gpui/src/test.rs @@ -34,6 +34,9 @@ use std::{ panic::{self, RefUnwindSafe}, }; +/// Run the given test function with the confifured paremeters. +/// This is intended for use with the `gpui::test` macro +/// and generally should not be used directly. pub fn run_test( mut num_iterations: u64, max_retries: usize, @@ -78,6 +81,7 @@ pub fn run_test( } } +/// A test struct for converting an observation callback into a stream. pub struct Observation { rx: channel::Receiver, _subscription: Subscription, diff --git a/crates/gpui/src/text_system.rs b/crates/gpui/src/text_system.rs index 1c9de5ea04..cadc000f9a 100644 --- a/crates/gpui/src/text_system.rs +++ b/crates/gpui/src/text_system.rs @@ -377,7 +377,7 @@ impl TextSystem { Ok(lines) } - pub fn finish_frame(&self, reused_views: &FxHashSet) { + pub(crate) fn finish_frame(&self, reused_views: &FxHashSet) { self.line_layout_cache.finish_frame(reused_views) } diff --git a/crates/gpui/src/text_system/line.rs b/crates/gpui/src/text_system/line.rs index a58d77f585..a89fa30dfa 100644 --- a/crates/gpui/src/text_system/line.rs +++ b/crates/gpui/src/text_system/line.rs @@ -24,6 +24,7 @@ pub struct ShapedLine { } impl ShapedLine { + /// The length of the line in utf-8 bytes. pub fn len(&self) -> usize { self.layout.len }