From 458c672a720cdb106548afbd3423e234c0ec60a8 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 9 Jan 2024 11:16:34 -0700 Subject: [PATCH] Add more API docs Co-Authored-By: Conrad --- crates/gpui/src/app/test_context.rs | 35 +++++++++++++++++++++++++++-- crates/gpui/src/window.rs | 23 +++++++++++++++++-- 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/crates/gpui/src/app/test_context.rs b/crates/gpui/src/app/test_context.rs index 587d3f3fec4b5f6d278b4bd1e7272e5b6bf3d356..7c95f75d96cf1a1456971b122f9807783a80785c 100644 --- a/crates/gpui/src/app/test_context.rs +++ b/crates/gpui/src/app/test_context.rs @@ -1,3 +1,5 @@ +#![deny(missing_docs)] + use crate::{ div, Action, AnyView, AnyWindowHandle, AppCell, AppContext, AsyncAppContext, BackgroundExecutor, ClipboardItem, Context, Entity, EventEmitter, ForegroundExecutor, @@ -255,6 +257,8 @@ impl TestAppContext { lock.update_global(update) } + /// Returns an `AsyncAppContext` which can be used to run tasks that expect to be on a background + /// thread on the current thread in tests. pub fn to_async(&self) -> AsyncAppContext { AsyncAppContext { app: Rc::downgrade(&self.app), @@ -263,6 +267,7 @@ impl TestAppContext { } } + /// Simulate dispatching an action to the currently focused node in the window. pub fn dispatch_action(&mut self, window: AnyWindowHandle, action: A) where A: Action, @@ -276,7 +281,8 @@ impl TestAppContext { /// simulate_keystrokes takes a space-separated list of keys to type. /// cx.simulate_keystrokes("cmd-shift-p b k s p enter") - /// will run backspace on the current editor through the command palette. + /// in Zed, this will run backspace on the current editor through the command palette. + /// This will also run the background executor until it's parked. pub fn simulate_keystrokes(&mut self, window: AnyWindowHandle, keystrokes: &str) { for keystroke in keystrokes .split(" ") @@ -291,7 +297,8 @@ impl TestAppContext { /// simulate_input takes a string of text to type. /// cx.simulate_input("abc") - /// will type abc into your current editor. + /// will type abc into your current editor + /// This will also run the background executor until it's parked. pub fn simulate_input(&mut self, window: AnyWindowHandle, input: &str) { for keystroke in input.split("").map(Keystroke::parse).map(Result::unwrap) { self.dispatch_keystroke(window, keystroke.into(), false); @@ -300,6 +307,7 @@ impl TestAppContext { self.background_executor.run_until_parked() } + /// dispatches a single Keystroke (see also `simulate_keystrokes` and `simulate_input`) pub fn dispatch_keystroke( &mut self, window: AnyWindowHandle, @@ -310,6 +318,7 @@ impl TestAppContext { .simulate_keystroke(keystroke, is_held) } + /// Returns the `TestWindow` backing the given handle. pub fn test_window(&self, window: AnyWindowHandle) -> TestWindow { self.app .borrow_mut() @@ -324,6 +333,7 @@ impl TestAppContext { .clone() } + /// Returns a stream of notifications whenever the View or Model is updated. pub fn notifications(&mut self, entity: &impl Entity) -> impl Stream { let (tx, rx) = futures::channel::mpsc::unbounded(); self.update(|cx| { @@ -340,6 +350,7 @@ impl TestAppContext { rx } + /// Retuens a stream of events emitted by the given Model. pub fn events>( &mut self, entity: &Model, @@ -358,6 +369,8 @@ impl TestAppContext { rx } + /// Runs until the given condition becomes true. (Prefer `run_until_parked` if you + /// don't need to jump in at a specific time). pub async fn condition( &mut self, model: &Model, @@ -387,6 +400,7 @@ impl TestAppContext { } impl Model { + /// Block until the next event is emitted by the model, then return it. pub fn next_event(&self, cx: &mut TestAppContext) -> Evt where Evt: Send + Clone + 'static, @@ -416,6 +430,7 @@ impl Model { } impl View { + /// Returns a future that resolves when the view is next updated. pub fn next_notification(&self, cx: &TestAppContext) -> impl Future { use postage::prelude::{Sink as _, Stream as _}; @@ -442,6 +457,7 @@ impl View { } impl View { + /// Returns a future that resolves when the condition becomes true. pub fn condition( &self, cx: &TestAppContext, @@ -506,6 +522,8 @@ impl View { } } +/// A VisualTestContext is the test-equivalent of a `WindowContext`. It allows you to +/// run window-specific test code. use derive_more::{Deref, DerefMut}; #[derive(Deref, DerefMut, Clone)] pub struct VisualTestContext { @@ -520,6 +538,9 @@ impl<'a> VisualTestContext { self.cx.update_window(self.window, |_, cx| f(cx)).unwrap() } + /// Create a new VisualTestContext. You would typically shadow the passed in + /// TestAppContext with this, as this is typically more useful. + /// `let cx = VisualTestContext::from_window(window, cx);` pub fn from_window(window: AnyWindowHandle, cx: &TestAppContext) -> Self { Self { cx: cx.clone(), @@ -527,10 +548,12 @@ impl<'a> VisualTestContext { } } + /// Wait until there are no more pending tasks. pub fn run_until_parked(&self) { self.cx.background_executor.run_until_parked(); } + /// Dispatch the action to the currently focused node. pub fn dispatch_action(&mut self, action: A) where A: Action, @@ -538,24 +561,32 @@ impl<'a> VisualTestContext { self.cx.dispatch_action(self.window, action) } + /// Read the title off the window (set by `WindowContext#set_window_title`) pub fn window_title(&mut self) -> Option { self.cx.test_window(self.window).0.lock().title.clone() } + /// Simulate a sequence of keystrokes `cx.simulate_keystrokes("cmd-p escape")` + /// Automatically runs until parked. pub fn simulate_keystrokes(&mut self, keystrokes: &str) { self.cx.simulate_keystrokes(self.window, keystrokes) } + /// Simulate typing text `cx.simulate_input("hello")` + /// Automatically runs until parked. pub fn simulate_input(&mut self, input: &str) { self.cx.simulate_input(self.window, input) } + /// Simulates the user blurring the window. pub fn deactivate_window(&mut self) { if Some(self.window) == self.test_platform.active_window() { self.test_platform.set_active_window(None) } self.background_executor.run_until_parked(); } + + /// Simulates the user closing the window. /// Returns true if the window was closed. pub fn simulate_close(&mut self) -> bool { let handler = self diff --git a/crates/gpui/src/window.rs b/crates/gpui/src/window.rs index dd567a83f6baee9ae65b57def9d7576b84bad89f..9b657a3f71c8fe226008d4ed56b787f17bc65a8c 100644 --- a/crates/gpui/src/window.rs +++ b/crates/gpui/src/window.rs @@ -238,6 +238,7 @@ impl Drop for FocusHandle { /// FocusableView allows users of your view to easily /// focus it (using cx.focus_view(view)) pub trait FocusableView: 'static + Render { + /// Returns the focus handle associated with this view. fn focus_handle(&self, cx: &AppContext) -> FocusHandle; } @@ -251,6 +252,7 @@ impl> ManagedView for M {} pub struct DismissEvent; // Holds the state for a specific window. +#[doc(hidden)] pub struct Window { pub(crate) handle: AnyWindowHandle, pub(crate) removed: bool, @@ -442,6 +444,7 @@ impl Window { #[derive(Clone, Debug, Default, PartialEq, Eq)] #[repr(C)] pub struct ContentMask { + /// The bounds pub bounds: Bounds

, } @@ -1788,7 +1791,7 @@ impl<'a> WindowContext<'a> { .available_actions(node_id) } - /// Returns any key bindings that invoke the given action. + /// Returns key bindings that invoke the given action on the currently focused element. pub fn bindings_for_action(&self, action: &dyn Action) -> Vec { self.window .rendered_frame @@ -1799,6 +1802,7 @@ impl<'a> WindowContext<'a> { ) } + /// Returns any bindings that would invoke the given action on the given focus handle if it were focused. pub fn bindings_for_action_in( &self, action: &dyn Action, @@ -1817,6 +1821,7 @@ impl<'a> WindowContext<'a> { dispatch_tree.bindings_for_action(action, &context_stack) } + /// Returns a generic event listener that invokes the given listener with the view and context associated with the given view handle. pub fn listener_for( &self, view: &View, @@ -1828,6 +1833,7 @@ impl<'a> WindowContext<'a> { } } + /// Returns a generic handler that invokes the given handler with the view and context associated with the given view handle. pub fn handler_for( &self, view: &View, @@ -1839,7 +1845,8 @@ impl<'a> WindowContext<'a> { } } - //========== ELEMENT RELATED FUNCTIONS =========== + /// Invoke the given function with the given focus handle present on the key dispatch stack. + /// If you want an element to participate in key dispatch, use this method to push its key context and focus handle into the stack during paint. pub fn with_key_dispatch( &mut self, context: Option, @@ -1878,6 +1885,8 @@ impl<'a> WindowContext<'a> { } } + /// Register a callback that can interrupt the closing of the current window based the returned boolean. + /// If the callback returns false, the window won't be closed. pub fn on_window_should_close(&mut self, f: impl Fn(&mut WindowContext) -> bool + 'static) { let mut this = self.to_async(); self.window @@ -2052,19 +2061,24 @@ impl<'a> BorrowMut for WindowContext<'a> { } } +/// This trait contains functionality that is shared across [ViewContext] and [WindowContext] pub trait BorrowWindow: BorrowMut + BorrowMut { + #[doc(hidden)] fn app_mut(&mut self) -> &mut AppContext { self.borrow_mut() } + #[doc(hidden)] fn app(&self) -> &AppContext { self.borrow() } + #[doc(hidden)] fn window(&self) -> &Window { self.borrow() } + #[doc(hidden)] fn window_mut(&mut self) -> &mut Window { self.borrow_mut() } @@ -3111,10 +3125,15 @@ impl AnyWindowHandle { /// as other internal representations. #[derive(Clone, Debug, Eq, PartialEq, Hash)] pub enum ElementId { + /// The id of a View element View(EntityId), + /// An integer id Integer(usize), + /// A string based id Name(SharedString), + /// An id that's equated with a focus handle FocusHandle(FocusId), + /// A combination of a name and an integer NamedInteger(SharedString, usize), }