Skip to main content

gpui/
gpui.rs

1#![doc = include_str!("../docs/crate.md")]
2#![warn(missing_docs)]
3#![allow(clippy::type_complexity)] // Not useful, GPUI makes heavy use of callbacks
4#![allow(clippy::collapsible_else_if)] // False positives in platform specific code
5#![allow(unused_mut)] // False positives in platform specific code
6
7extern crate self as gpui;
8#[macro_use]
9mod action;
10mod animated;
11mod app;
12
13mod arena;
14mod asset_cache;
15mod assets;
16mod bounds_tree;
17mod color;
18/// The default colors used by GPUI.
19pub mod colors;
20#[cfg(feature = "profiler")]
21mod debug_overlay;
22mod element;
23mod elements;
24mod executor;
25mod platform_scheduler;
26pub(crate) use platform_scheduler::PlatformScheduler;
27/// Criterion measurements beyond wall time, for benchmarks built on GPUI.
28#[cfg(feature = "bench-support")]
29pub mod bench_metrics;
30mod geometry;
31mod gestures;
32mod global;
33mod input;
34mod inspector;
35mod interactive;
36mod key_dispatch;
37mod keymap;
38mod lerp;
39mod motion;
40mod path_builder;
41mod platform;
42pub mod prelude;
43/// Profiling utilities for task, frame, and thread performance tracking.
44pub mod profiler;
45#[cfg(any(
46    test,
47    target_os = "windows",
48    target_os = "linux",
49    target_family = "wasm",
50    feature = "test-support",
51    feature = "bench-support"
52))]
53pub mod queue;
54/// A seeded, mutable element tree for benchmarks and tests of GPUI rendering.
55#[cfg(any(test, feature = "bench-support"))]
56pub mod randomized_element_tree;
57mod resize;
58mod scene;
59#[cfg(any(test, feature = "test-support", feature = "bench-support"))]
60mod seeds;
61mod shared_uri;
62mod spring;
63mod style;
64mod style_transitions;
65mod styled;
66mod subscription;
67mod svg_renderer;
68mod tab_stop;
69mod taffy;
70#[cfg(any(test, feature = "test-support"))]
71pub mod test;
72mod text_system;
73mod transition;
74mod util;
75mod view;
76mod window;
77
78#[cfg(any(test, feature = "test-support"))]
79pub use proptest;
80#[cfg(any(test, feature = "test-support", feature = "bench-support"))]
81pub use seeds::calculate_seeds;
82
83pub mod _documentation;
84
85/// Do not touch, here be dragons for use by gpui_macros and such.
86#[doc(hidden)]
87pub mod private {
88    pub use anyhow;
89    pub use inventory;
90    pub use rand;
91    pub use schemars;
92    pub use serde;
93    pub use serde_json;
94}
95
96mod seal {
97    /// A mechanism for restricting implementations of a trait to only those in GPUI.
98    /// See: <https://predr.ag/blog/definitive-guide-to-sealed-traits-in-rust/>
99    pub trait Sealed {}
100}
101
102pub use accesskit;
103pub use accesskit::Action as AccessibleAction;
104pub use accesskit::{Orientation, Role, Toggled};
105pub use action::*;
106pub use animated::*;
107pub use anyhow::Result;
108pub use app::*;
109pub(crate) use arena::*;
110pub use asset_cache::*;
111pub use assets::*;
112pub use color::*;
113pub use ctor::ctor;
114#[cfg(feature = "profiler")]
115pub use debug_overlay::*;
116pub use element::*;
117pub use elements::*;
118pub use executor::*;
119pub use geometry::*;
120pub use gestures::*;
121pub use global::*;
122pub use gpui_macros::{
123    AppContext, InteractiveElement, IntoElement, ParentElement, Render, StatefulInteractiveElement,
124    Styled, VisualContext, bench, property_test, register_action, test,
125};
126pub use resize::*;
127pub use spring::*;
128
129/// Defines a Criterion benchmark group for benchmarks annotated with [`gpui::bench`].
130///
131/// It takes the same arguments as `criterion::criterion_group!`, so GPUI benchmark
132/// files keep the shape of ordinary Criterion benchmarks.
133///
134/// The group measures with the `gpui::BenchMeasurement` configured by `BENCH_MEASUREMENT` (see
135/// `BenchMeasurement::from_env`). By default Criterion analyzes wall time
136/// while retired instructions, cycles, IPC, context switches, and the other
137/// counters this machine supports are printed per iteration in the GPUI bench
138/// report. `BENCH_MEASUREMENT=instructions` makes Criterion analyze
139/// process-wide instructions instead, `foreground-instructions` the benchmark
140/// thread's alone, and `wall-time` disables all counters. A
141/// `config = ...` expression may set any other Criterion option; its
142/// measurement is replaced. To measure with something else, call
143/// `criterion::criterion_group!` directly with
144/// `config = criterion::Criterion::default().with_measurement(gpui::BenchMeasurement::new(...))`.
145///
146/// [`gpui::bench`]: crate::bench
147#[macro_export]
148macro_rules! bench_group {
149    (name = $name:ident; config = $config:expr; targets = $($target:path),+ $(,)?) => {
150        criterion::criterion_group! {
151            name = $name;
152            config = ($config).with_measurement($crate::BenchMeasurement::from_env_or_exit());
153            targets = $($target),+
154        }
155    };
156    ($name:ident, $($target:path),+ $(,)?) => {
157        $crate::bench_group! {
158            name = $name;
159            config = criterion::Criterion::default();
160            targets = $($target),+
161        }
162    };
163}
164
165/// Defines the entry point for GPUI Criterion benchmark groups.
166///
167/// This mirrors `criterion::criterion_main!` so GPUI benchmark files can keep the
168/// same shape as ordinary Criterion benchmarks. It also installs
169/// `CountingAllocator` as the binary's global allocator, so reports include
170/// heap allocations per iteration. It wraps the system allocator by default;
171/// `allocator = Path;` wraps another unit-struct allocator instead, e.g. to
172/// compare allocators, which pay the same small counting cost:
173///
174/// ```ignore
175/// gpui::bench_main!(allocator = mimalloc::MiMalloc; benches);
176/// ```
177///
178/// `allocator = none;` installs no global allocator, leaving Rust's default and
179/// dropping the allocation metrics from reports.
180#[macro_export]
181macro_rules! bench_main {
182    (allocator = none; $($groups:tt)*) => {
183        criterion::criterion_main!($($groups)*);
184    };
185    (allocator = $allocator:path; $($groups:tt)*) => {
186        #[global_allocator]
187        static GPUI_BENCH_ALLOCATOR: $crate::CountingAllocator<$allocator> =
188            $crate::CountingAllocator::new($allocator);
189
190        criterion::criterion_main!($($groups)*);
191    };
192    ($($groups:tt)*) => {
193        $crate::bench_main!(allocator = ::std::alloc::System; $($groups)*);
194    };
195}
196pub use gpui_shared_string::*;
197pub use gpui_util::arc_cow::ArcCow;
198/// HTTP client abstraction for making requests.
199pub mod http_client;
200pub use input::*;
201pub use inspector::*;
202pub use interactive::*;
203use key_dispatch::*;
204pub use keymap::*;
205pub use lerp::*;
206pub use motion::*;
207pub use path_builder::*;
208pub use platform::*;
209pub use profiler::*;
210#[cfg(any(target_os = "windows", target_os = "linux", target_family = "wasm"))]
211pub use queue::{PriorityQueueReceiver, PriorityQueueSender};
212pub use refineable::*;
213pub use scene::*;
214pub use shared_uri::*;
215use std::{any::Any, future::Future};
216pub use style::*;
217pub use style_transitions::*;
218pub use styled::*;
219pub use subscription::*;
220pub use svg_renderer::*;
221pub(crate) use tab_stop::*;
222use taffy::TaffyLayoutEngine;
223pub use taffy::{AvailableSpace, LayoutId};
224#[cfg(any(test, feature = "test-support"))]
225pub use test::*;
226pub use text_system::*;
227pub use transition::*;
228pub use util::{FutureExt, TextRangeExt, Timeout};
229pub use view::*;
230pub use window::*;
231
232#[cfg(not(target_family = "wasm"))]
233pub use pollster::block_on;
234
235/// Operations shared by GPUI's app, entity and async contexts.
236///
237/// Write a helper against this trait when it needs only entities, globals or the
238/// app. Operations that need a window are on [`VisualContext`]. See
239/// [contexts](crate::_documentation::concepts::contexts).
240///
241/// # Examples
242///
243/// ```
244/// use gpui::{AppContext, Entity};
245///
246/// fn reset<C: AppContext>(count: &Entity<u64>, cx: &mut C) {
247///     count.update(cx, |count, cx| {
248///         *count = 0;
249///         cx.notify();
250///     });
251/// }
252/// # gpui::TestApp::new().update(|cx| {
253/// #     let count = cx.new(|_| 5_u64);
254/// #     reset(&count, cx);
255/// #     assert_eq!(*count.read(cx), 0);
256/// # });
257/// ```
258pub trait AppContext {
259    /// Creates an entity from `build_entity`, and returns a handle to it.
260    ///
261    /// `build_entity` receives a [`Context`] for the new entity, so it can subscribe to
262    /// other entities or start work of its own. The entity lives as long as a handle to
263    /// it exists, or as long as it's stored with [`AppContext::insert_global_entity`].
264    #[expect(
265        clippy::wrong_self_convention,
266        reason = "`App::new` is an ubiquitous function for creating entities"
267    )]
268    fn new<T: 'static>(&mut self, build_entity: impl FnOnce(&mut Context<T>) -> T) -> Entity<T>;
269
270    /// Reserves an entity slot, and returns a [`Reservation`] for it.
271    ///
272    /// The reservation's [`EntityId`] is known now, so you can refer to the entity before
273    /// it exists. Create the entity later with [`AppContext::insert_entity`].
274    ///
275    /// # Examples
276    ///
277    /// ```
278    /// use gpui::{AppContext, TestApp};
279    ///
280    /// let mut app = TestApp::new();
281    /// app.update(|cx| {
282    ///     let reservation = cx.reserve_entity::<u32>();
283    ///     let id = reservation.entity_id();
284    ///     let number = cx.insert_entity(reservation, |_| 7);
285    ///     assert_eq!(number.entity_id(), id);
286    ///     assert_eq!(*number.read(cx), 7);
287    /// });
288    /// ```
289    fn reserve_entity<T: 'static>(&mut self) -> Reservation<T>;
290
291    /// Creates the entity for a [`Reservation`] from [`AppContext::reserve_entity`].
292    ///
293    /// The entity gets the reservation's [`EntityId`], and `build_entity` runs with a
294    /// [`Context`] for it.
295    fn insert_entity<T: 'static>(
296        &mut self,
297        reservation: Reservation<T>,
298        build_entity: impl FnOnce(&mut Context<T>) -> T,
299    ) -> Entity<T>;
300
301    /// Runs `update` with the entity and a [`Context`] for it, and returns the result.
302    ///
303    /// Effects queued by `update`, such as notifications, run when the outermost update
304    /// finishes.
305    fn update_entity<T, R>(
306        &mut self,
307        handle: &Entity<T>,
308        update: impl FnOnce(&mut T, &mut Context<T>) -> R,
309    ) -> R
310    where
311        T: 'static;
312
313    /// Borrows the entity mutably, without a closure.
314    ///
315    /// The returned [`GpuiBorrow`] dereferences to the entity. Dropping it notifies
316    /// observers of the entity. Prefer [`AppContext::update_entity`], which ends the
317    /// borrow when its closure returns. Use this when you need to hold the borrow across
318    /// several statements.
319    ///
320    /// # Panics
321    ///
322    /// Panics in [`AsyncApp`] and [`AsyncWindowContext`], which can't hold a borrow of
323    /// the app across an `.await`. Call `update` there instead.
324    fn as_mut<'a, T>(&'a mut self, handle: &Entity<T>) -> GpuiBorrow<'a, T>
325    where
326        T: 'static;
327
328    /// Reads the entity with a shared borrow, and returns the result of `read`.
329    ///
330    /// `read` also receives the app, so it can read other state at the same time.
331    fn read_entity<T, R>(&self, handle: &Entity<T>, read: impl FnOnce(&T, &App) -> R) -> R
332    where
333        T: 'static;
334
335    /// Tells GPUI that the entity with `entity_id` changed. Its observers run and windows
336    /// that show it redraw.
337    ///
338    /// Inside an entity's update, [`Context::notify`] is more convenient.
339    fn notify(&mut self, entity_id: EntityId);
340
341    /// Emits `event` from `entity`.
342    ///
343    /// Subscribers registered with [`Context::subscribe`] or [`AsyncApp::subscribe`]
344    /// receive it when the current update finishes. Inside an entity's update,
345    /// [`Context::emit`] is more convenient.
346    fn emit<EntityType, EventType>(&mut self, entity: &Entity<EntityType>, event: EventType)
347    where
348        EntityType: EventEmitter<EventType>,
349        EventType: 'static;
350
351    /// Runs `f` with the window's root view, the window and the app, and returns the
352    /// result.
353    ///
354    /// # Errors
355    ///
356    /// Returns an error if the window has closed. Async contexts also return an error when
357    /// the app is already borrowed.
358    fn update_window<T, F>(&mut self, window: AnyWindowHandle, f: F) -> Result<T>
359    where
360        F: FnOnce(AnyView, &mut Window, &mut App) -> T;
361
362    /// Runs `f` with the window that most recently rendered the entity `entity_id`, and
363    /// returns the result.
364    ///
365    /// Returns `None` if no window has rendered the entity, or if that window isn't
366    /// available.
367    fn with_window<R>(
368        &mut self,
369        entity_id: EntityId,
370        f: impl FnOnce(&mut Window, &mut App) -> R,
371    ) -> Option<R>;
372
373    /// Reads the root view of `window` with the app, and returns the result.
374    ///
375    /// # Errors
376    ///
377    /// Returns an error if the window has closed.
378    fn read_window<T, R>(
379        &self,
380        window: &WindowHandle<T>,
381        read: impl FnOnce(Entity<T>, &App) -> R,
382    ) -> Result<R>
383    where
384        T: 'static;
385
386    /// Runs `future` on the background executor and returns a task for its result.
387    ///
388    /// Native builds use worker threads; single-threaded web builds use the browser's main
389    /// thread. The future and its result must be `Send + 'static`. No app context is supplied,
390    /// so return to a foreground task to update entities. Dropping the task cancels the future.
391    /// See [`BackgroundExecutor::spawn`] and the [executor concept](crate::_documentation::concepts::executors).
392    fn background_spawn<R>(&self, future: impl Future<Output = R> + Send + 'static) -> Task<R>
393    where
394        R: Send + 'static;
395
396    /// Calls `callback` with the global of type `G` and the app, and returns the result.
397    ///
398    /// # Panics
399    ///
400    /// Panics if no global of type `G` has been set.
401    fn read_global<G, R>(&self, callback: impl FnOnce(&G, &App) -> R) -> R
402    where
403        G: Global;
404
405    /// Keeps `entity` alive without a handle to it.
406    ///
407    /// The entity stays alive until the app is dropped, or until
408    /// [`AppContext::remove_global_entity`] removes it and no other handle refers to it.
409    fn insert_global_entity<T: 'static>(&mut self, entity: Entity<T>);
410
411    /// Stops keeping `entity` alive. It's dropped once no other handle refers to it.
412    fn remove_global_entity<T: 'static>(&mut self, entity: &Entity<T>);
413
414    /// Returns the entities stored with [`AppContext::insert_global_entity`] whose type is
415    /// `T`.
416    fn global_entities<T: 'static>(&self) -> impl Iterator<Item = Entity<T>>;
417}
418
419/// A slot for an entity that doesn't exist yet.
420///
421/// Get one from [`AppContext::reserve_entity`], and pass it to
422/// [`AppContext::insert_entity`] to create the entity.
423pub struct Reservation<T>(pub(crate) Slot<T>);
424
425impl<T: 'static> Reservation<T> {
426    /// Returns the [`EntityId`] the entity will have once it's inserted.
427    pub fn entity_id(&self) -> EntityId {
428        self.0.entity_id()
429    }
430}
431
432/// Operations that need a window.
433///
434/// Contexts that have a window implement this, including [`AsyncWindowContext`].
435/// Import it along with [`AppContext`] from [`gpui::prelude`](crate::prelude).
436pub trait VisualContext: AppContext {
437    /// The return type of window operations.
438    ///
439    /// [`AsyncWindowContext`] uses [`Result`], because the window may have closed by the
440    /// time the call runs.
441    type Result<T>;
442
443    /// Returns the handle of the window this context works in.
444    fn window_handle(&self) -> AnyWindowHandle;
445
446    /// Runs `update` with the entity, its window and a [`Context`] for the entity, and
447    /// returns the result, wrapped in [`VisualContext::Result`](Self::Result).
448    fn update_window_entity<T: 'static, R>(
449        &mut self,
450        entity: &Entity<T>,
451        update: impl FnOnce(&mut T, &mut Window, &mut Context<T>) -> R,
452    ) -> Self::Result<R>;
453
454    /// Creates an entity with access to the window.
455    ///
456    /// `build_entity` receives the window and a [`Context`] for the new entity.
457    fn new_window_entity<T: 'static>(
458        &mut self,
459        build_entity: impl FnOnce(&mut Window, &mut Context<T>) -> T,
460    ) -> Self::Result<Entity<T>>;
461
462    /// Replaces the root view of the window with the view that `build_view` creates, and
463    /// returns a handle to the new view.
464    fn replace_root_view<V>(
465        &mut self,
466        build_view: impl FnOnce(&mut Window, &mut Context<V>) -> V,
467    ) -> Self::Result<Entity<V>>
468    where
469        V: 'static + Render;
470
471    /// Moves keyboard focus to `entity`, using its [`Focusable::focus_handle`].
472    fn focus<V>(&mut self, entity: &Entity<V>) -> Self::Result<()>
473    where
474        V: Focusable;
475}
476
477/// Declares that an entity type emits events of type `E`.
478///
479/// Implement it with an empty `impl`. Then emit events with [`Context::emit`], and
480/// receive them with [`Context::subscribe`].
481///
482/// # Examples
483///
484/// ```
485/// use gpui::{AppContext, Context, EventEmitter, TestApp};
486///
487/// struct Counter {
488///     count: usize,
489/// }
490///
491/// struct Incremented(usize);
492///
493/// impl EventEmitter<Incremented> for Counter {}
494///
495/// impl Counter {
496///     fn add(&mut self, amount: usize, cx: &mut Context<Self>) {
497///         self.count += amount;
498///         cx.emit(Incremented(amount));
499///         cx.notify();
500///     }
501/// }
502///
503/// let mut app = TestApp::new();
504/// let (counter, total, _subscription) = app.update(|cx| {
505///     let counter = cx.new(|_| Counter { count: 0 });
506///     let total = cx.new(|_| 0_usize);
507///     let total_for_subscriber = total.clone();
508///     let subscription = cx.subscribe(&counter, move |_, event: &Incremented, cx| {
509///         total_for_subscriber.update(cx, |total, _| *total += event.0);
510///     });
511///     (counter, total, subscription)
512/// });
513/// app.update(|cx| counter.update(cx, |counter, cx| counter.add(2, cx)));
514/// app.read(|cx| assert_eq!(*total.read(cx), 2));
515/// ```
516pub trait EventEmitter<E: Any>: 'static {}
517
518/// Helpers for changing globals from any context that can reach the [`App`].
519///
520/// Implemented for every type that implements `BorrowMut<App>`, including [`App`] and
521/// [`Context`].
522///
523/// # Examples
524///
525/// ```
526/// use gpui::{AppContext, BorrowAppContext, Global, TestApp};
527///
528/// struct Scale(f32);
529///
530/// impl Global for Scale {}
531///
532/// let mut app = TestApp::new();
533/// app.update(|cx| {
534///     cx.set_global(Scale(1.5));
535///     cx.update_global(|scale: &mut Scale, _cx| scale.0 *= 2.0);
536///     assert_eq!(cx.read_global(|scale: &Scale, _cx| scale.0), 3.0);
537/// });
538/// ```
539pub trait BorrowAppContext {
540    /// Sets the global of type `T` to `global`, replacing any previous value. Observers of
541    /// the global are notified when the current update finishes.
542    fn set_global<T: Global>(&mut self, global: T);
543    /// Updates the global of type `G` with `f`, and returns the result of `f`.
544    ///
545    /// `f` also receives the context. While `f` runs, the global is taken out of the app,
546    /// so reading it through the context panics. Change it only through the reference
547    /// that `f` receives. Observers of the global are notified when the update ends.
548    ///
549    /// # Panics
550    ///
551    /// Panics if no global of type `G` has been set.
552    fn update_global<G, R>(&mut self, f: impl FnOnce(&mut G, &mut Self) -> R) -> R
553    where
554        G: Global;
555    /// Like [`BorrowAppContext::update_global`], but first sets `G::default()` if no
556    /// global of type `G` has been set.
557    fn update_default_global<G, R>(&mut self, f: impl FnOnce(&mut G, &mut Self) -> R) -> R
558    where
559        G: Global + Default;
560}
561
562impl<C> BorrowAppContext for C
563where
564    C: std::borrow::BorrowMut<App>,
565{
566    fn set_global<G: Global>(&mut self, global: G) {
567        self.borrow_mut().set_global(global)
568    }
569
570    #[track_caller]
571    fn update_global<G, R>(&mut self, f: impl FnOnce(&mut G, &mut Self) -> R) -> R
572    where
573        G: Global,
574    {
575        let mut global = self.borrow_mut().lease_global::<G>();
576        let result = f(&mut global, self);
577        self.borrow_mut().end_global_lease(global);
578        result
579    }
580
581    fn update_default_global<G, R>(&mut self, f: impl FnOnce(&mut G, &mut Self) -> R) -> R
582    where
583        G: Global + Default,
584    {
585        self.borrow_mut().default_global::<G>();
586        self.update_global(f)
587    }
588}
589
590/// Describes the GPU that GPUI renders with.
591///
592/// Get it from [`Window::gpu_specs`], which returns `None` when the platform doesn't
593/// report it.
594#[derive(Default, Debug, serde::Serialize, serde::Deserialize, Clone)]
595pub struct GpuSpecs {
596    /// Whether the GPU is a software renderer, such as `llvmpipe`, running on the CPU.
597    pub is_software_emulated: bool,
598    /// The name of the device, as reported by the graphics backend.
599    pub device_name: String,
600    /// The name of the driver, as reported by the graphics backend.
601    pub driver_name: String,
602    /// Further information about the driver, as reported by the graphics backend.
603    pub driver_info: String,
604}