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}