Skip to main content

gpui_authoring/
gpui_authoring.rs

1//! GPUI's authoring layer: the reactive store, the windows, and the declarative
2//! element DSL that composes them.
3//!
4//! This crate holds [`App`], [`Window`] and the context types, the entities and
5//! views built on them, and the element tree that renders through the engine
6//! contracts in [`gpui_engine`] onto the windowing SPI in [`gpui_platform`].
7//!
8//! The element DSL is not separable from the runtime: an element is laid out and
9//! painted with a concrete [`Window`] and [`App`], so both tiers described in the
10//! [authoring guide](crate::_authoring) live here. What *is* swappable sits
11//! underneath, behind [`LayoutEngine`], [`SceneRenderer`] and [`Platform`], or
12//! rides along in [`Style::custom`]. How a frame itself is built and paced is
13//! swappable too, through the [`FramePipeline`] a window draws with — see the
14//! [frame pipeline guide](crate::_frame_pipeline).
15//!
16//! Above this crate sits `gpui_runtime`, which holds `Application` — how a host
17//! program builds, configures and starts an app — and above that, the `gpui`
18//! crate: a thin facade re-exporting this, the runtime, and the platform
19//! backends, so applications keep importing `gpui`.
20
21#![warn(missing_docs)]
22#![allow(clippy::type_complexity)] // Not useful, GPUI makes heavy use of callbacks
23#![allow(clippy::collapsible_else_if)] // False positives in platform specific code
24#![allow(unused_mut)] // False positives in platform specific code
25
26// Macros generated by `gpui_macros` name `gpui::` paths, so within this crate
27// `gpui` is an alias for `gpui_authoring`.
28extern crate self as gpui;
29
30#[macro_use]
31mod action;
32mod app;
33
34mod arena;
35mod asset_cache;
36mod assets;
37/// The default colors used by GPUI.
38pub mod colors;
39#[cfg(feature = "profiler")]
40mod debug_overlay;
41mod element;
42mod elements;
43mod engine_layout;
44mod executor;
45mod gestures;
46mod global;
47mod input;
48mod inspector;
49mod interactive;
50mod key_dispatch;
51mod keymap;
52mod path_builder;
53mod platform;
54pub mod prelude;
55/// Profiling utilities for task, frame, and thread performance tracking.
56pub mod profiler;
57mod shared_uri;
58mod spring;
59mod style;
60mod styled;
61mod subscription;
62mod svg_renderer;
63mod tab_stop;
64#[cfg(any(test, feature = "test-support"))]
65pub mod test;
66mod text_system;
67mod util;
68mod view;
69mod window;
70
71#[cfg(any(test, feature = "test-support"))]
72pub use proptest;
73
74/// Accessibility guide: exposing UI state to assistive technology.
75pub mod _accessibility;
76/// Authoring guide: the two public tiers of the UI API.
77pub mod _authoring;
78/// Frame pipeline guide: how to write and install one.
79pub mod _frame_pipeline;
80/// How GPUI's ownership and data-flow model works.
81pub mod _ownership_and_data_flow;
82
83/// Do not touch, here be dragons for use by gpui_macros and such.
84#[doc(hidden)]
85pub mod private {
86    pub use anyhow;
87    pub use inventory;
88    pub use schemars;
89    pub use serde;
90    pub use serde_json;
91}
92
93mod seal {
94    /// A mechanism for restricting implementations of a trait to only those in GPUI.
95    /// See: <https://predr.ag/blog/definitive-guide-to-sealed-traits-in-rust/>
96    pub trait Sealed {}
97}
98
99pub use accesskit;
100pub use accesskit::Action as AccessibleAction;
101pub use accesskit::{Orientation, Role, Toggled};
102pub use action::*;
103pub use anyhow::Result;
104pub use app::*;
105pub(crate) use arena::*;
106pub use asset_cache::*;
107pub use assets::*;
108pub use ctor::ctor;
109#[cfg(feature = "profiler")]
110pub use debug_overlay::*;
111pub use element::*;
112pub use elements::*;
113pub use executor::*;
114pub use gestures::*;
115pub use global::*;
116pub use gpui_macros::{
117    AppContext, IntoElement, Render, VisualContext, bench, property_test, register_action, test,
118};
119pub use spring::*;
120
121pub use gpui_engine::*;
122pub use gpui_engine_default::*;
123pub use gpui_platform::*;
124pub use gpui_util::arc_cow::ArcCow;
125pub use http_client;
126pub use input::*;
127pub use inspector::*;
128pub use interactive::*;
129use key_dispatch::*;
130pub use keymap::*;
131pub use path_builder::*;
132pub use platform::*;
133pub use profiler::*;
134pub use refineable::*;
135pub use shared_uri::*;
136use std::{any::Any, future::Future};
137pub use style::*;
138pub use styled::*;
139pub use subscription::*;
140pub use svg_renderer::*;
141pub(crate) use tab_stop::*;
142#[cfg(any(test, feature = "test-support"))]
143pub use test::*;
144pub use text_system::*;
145pub use util::{FluentBuilder, FutureExt, Timeout};
146pub use view::*;
147pub use window::*;
148
149#[cfg(not(target_family = "wasm"))]
150pub use pollster::block_on;
151
152/// Extension methods on [`Bounds`] that need to resolve the application's displays.
153///
154/// These live here rather than in `gpui_types` because they require [`App`], while
155/// the base [`Bounds`] type is defined in the platform-agnostic `gpui_types` crate.
156pub trait BoundsExt: Sized {
157    /// Generate a centered bounds for the given display or primary display if none is provided
158    fn centered(display_id: Option<DisplayId>, size: Size<Pixels>, cx: &App) -> Self;
159
160    /// Generate maximized bounds for the given display or primary display if none is provided
161    fn maximized(display_id: Option<DisplayId>, cx: &App) -> Self;
162}
163
164impl BoundsExt for Bounds<Pixels> {
165    fn centered(display_id: Option<DisplayId>, size: Size<Pixels>, cx: &App) -> Self {
166        let display = display_id
167            .and_then(|id| cx.find_display(id))
168            .or_else(|| cx.primary_display());
169
170        display
171            .map(|display| Bounds::centered_at(display.bounds().center(), size))
172            .unwrap_or_else(|| Bounds {
173                origin: point(px(0.), px(0.)),
174                size,
175            })
176    }
177
178    fn maximized(display_id: Option<DisplayId>, cx: &App) -> Self {
179        let display = display_id
180            .and_then(|id| cx.find_display(id))
181            .or_else(|| cx.primary_display());
182
183        display
184            .map(|display| display.bounds())
185            .unwrap_or_else(|| Bounds {
186                origin: point(px(0.), px(0.)),
187                size: size(px(1024.), px(768.)),
188            })
189    }
190}
191
192impl HasRemSize for Window<'_> {
193    fn rem_size(&self) -> Pixels {
194        Window::rem_size(self)
195    }
196}
197
198/// The context trait, allows the different contexts in GPUI to be used
199/// interchangeably for certain operations.
200pub trait AppContext {
201    /// Create a new entity in the app context.
202    #[expect(
203        clippy::wrong_self_convention,
204        reason = "`App::new` is an ubiquitous function for creating entities"
205    )]
206    fn new<T: 'static>(&mut self, build_entity: impl FnOnce(&mut Context<T>) -> T) -> Entity<T>;
207
208    /// Reserve a slot for a entity to be inserted later.
209    /// The returned [Reservation] allows you to obtain the [EntityId] for the future entity.
210    fn reserve_entity<T: 'static>(&mut self) -> Reservation<T>;
211
212    /// Insert a new entity in the app context based on a [Reservation] previously obtained from [`reserve_entity`].
213    ///
214    /// [`reserve_entity`]: Self::reserve_entity
215    fn insert_entity<T: 'static>(
216        &mut self,
217        reservation: Reservation<T>,
218        build_entity: impl FnOnce(&mut Context<T>) -> T,
219    ) -> Entity<T>;
220
221    /// Update a entity in the app context.
222    fn update_entity<T, R>(
223        &mut self,
224        handle: &Entity<T>,
225        update: impl FnOnce(&mut T, &mut Context<T>) -> R,
226    ) -> R
227    where
228        T: 'static;
229
230    /// Update a entity in the app context.
231    fn as_mut<'a, T>(&'a mut self, handle: &Entity<T>) -> GpuiBorrow<'a, T>
232    where
233        T: 'static;
234
235    /// Read a entity from the app context.
236    fn read_entity<T, R>(&self, handle: &Entity<T>, read: impl FnOnce(&T, &App) -> R) -> R
237    where
238        T: 'static;
239
240    /// Update a window for the given handle.
241    fn update_window<T, F>(&mut self, window: AnyWindowHandle, f: F) -> Result<T>
242    where
243        F: FnOnce(AnyView, &mut Window, &mut App) -> T;
244
245    /// Run `f` against the entity's *current* window — the most recently
246    /// rendered window that referenced the entity. Returns `None` if the
247    /// entity has no current window or that window is unavailable. See
248    /// [`App::with_window`] for the underlying lookup.
249    fn with_window<R>(
250        &mut self,
251        entity_id: EntityId,
252        f: impl FnOnce(&mut Window, &mut App) -> R,
253    ) -> Option<R>;
254
255    /// Read a window off of the application context.
256    fn read_window<T, R>(
257        &self,
258        window: &WindowHandle<T>,
259        read: impl FnOnce(Entity<T>, &App) -> R,
260    ) -> Result<R>
261    where
262        T: 'static;
263
264    /// Spawn a future on a background thread
265    fn background_spawn<R>(&self, future: impl Future<Output = R> + Send + 'static) -> Task<R>
266    where
267        R: Send + 'static;
268
269    /// Read a global from this app context
270    fn read_global<G, R>(&self, callback: impl FnOnce(&G, &App) -> R) -> R
271    where
272        G: Global;
273}
274
275/// Returned by [Context::reserve_entity] to later be passed to [Context::insert_entity].
276/// Allows you to obtain the [EntityId] for a entity before it is created.
277pub struct Reservation<T>(pub(crate) Slot<T>);
278
279impl<T: 'static> Reservation<T> {
280    /// Returns the [EntityId] that will be associated with the entity once it is inserted.
281    pub fn entity_id(&self) -> EntityId {
282        self.0.entity_id()
283    }
284}
285
286/// This trait is used for the different visual contexts in GPUI that
287/// require a window to be present.
288pub trait VisualContext: AppContext {
289    /// The result type for window operations.
290    type Result<T>;
291
292    /// Returns the handle of the window associated with this context.
293    fn window_handle(&self) -> AnyWindowHandle;
294
295    /// Update a view with the given callback
296    fn update_window_entity<T: 'static, R>(
297        &mut self,
298        entity: &Entity<T>,
299        update: impl FnOnce(&mut T, &mut Window, &mut Context<T>) -> R,
300    ) -> Self::Result<R>;
301
302    /// Create a new entity, with access to `Window`.
303    fn new_window_entity<T: 'static>(
304        &mut self,
305        build_entity: impl FnOnce(&mut Window, &mut Context<T>) -> T,
306    ) -> Self::Result<Entity<T>>;
307
308    /// Replace the root view of a window with a new view.
309    fn replace_root_view<V>(
310        &mut self,
311        build_view: impl FnOnce(&mut Window, &mut Context<V>) -> V,
312    ) -> Self::Result<Entity<V>>
313    where
314        V: 'static + Render;
315
316    /// Focus a entity in the window, if it implements the [`Focusable`] trait.
317    fn focus<V>(&mut self, entity: &Entity<V>) -> Self::Result<()>
318    where
319        V: Focusable;
320}
321
322/// A trait for tying together the types of a GPUI entity and the events it can
323/// emit.
324pub trait EventEmitter<E: Any>: 'static {}
325
326/// A helper trait for auto-implementing certain methods on contexts that
327/// can be used interchangeably.
328pub trait BorrowAppContext {
329    /// Set a global value on the context.
330    fn set_global<T: Global>(&mut self, global: T);
331    /// Updates the global state of the given type.
332    fn update_global<G, R>(&mut self, f: impl FnOnce(&mut G, &mut Self) -> R) -> R
333    where
334        G: Global;
335    /// Updates the global state of the given type, creating a default if it didn't exist before.
336    fn update_default_global<G, R>(&mut self, f: impl FnOnce(&mut G, &mut Self) -> R) -> R
337    where
338        G: Global + Default;
339}
340
341impl<C> BorrowAppContext for C
342where
343    C: std::borrow::BorrowMut<App>,
344{
345    fn set_global<G: Global>(&mut self, global: G) {
346        self.borrow_mut().set_global(global)
347    }
348
349    #[track_caller]
350    fn update_global<G, R>(&mut self, f: impl FnOnce(&mut G, &mut Self) -> R) -> R
351    where
352        G: Global,
353    {
354        let mut global = self.borrow_mut().lease_global::<G>();
355        let result = f(&mut global, self);
356        self.borrow_mut().end_global_lease(global);
357        result
358    }
359
360    fn update_default_global<G, R>(&mut self, f: impl FnOnce(&mut G, &mut Self) -> R) -> R
361    where
362        G: Global + Default,
363    {
364        self.borrow_mut().default_global::<G>();
365        self.update_global(f)
366    }
367}