Cargo.lock 🔗
@@ -9514,7 +9514,7 @@ dependencies = [
[[package]]
name = "zed"
-version = "0.119.0"
+version = "0.120.0"
dependencies = [
"activity_indicator",
"ai",
Conrad Irwin created
Cargo.lock | 2
crates/gpui/src/app/test_context.rs | 132 +++----------------
crates/gpui/src/platform/test/platform.rs | 16 +
crates/gpui/src/platform/test/window.rs | 165 ++++++++++++++++++++----
4 files changed, 171 insertions(+), 144 deletions(-)
@@ -9514,7 +9514,7 @@ dependencies = [
[[package]]
name = "zed"
-version = "0.119.0"
+version = "0.120.0"
dependencies = [
"activity_indicator",
"ai",
@@ -1,14 +1,13 @@
use crate::{
div, Action, AnyView, AnyWindowHandle, AppCell, AppContext, AsyncAppContext,
- BackgroundExecutor, Bounds, ClipboardItem, Context, Entity, EventEmitter, ForegroundExecutor,
- InputEvent, IntoElement, KeyDownEvent, Keystroke, Model, ModelContext, Pixels, Platform,
- PlatformWindow, Point, Render, Result, Size, Task, TestDispatcher, TestPlatform, TestWindow,
- TestWindowHandlers, TextSystem, View, ViewContext, VisualContext, WindowBounds, WindowContext,
- WindowHandle, WindowOptions,
+ BackgroundExecutor, ClipboardItem, Context, Entity, EventEmitter, ForegroundExecutor,
+ IntoElement, Keystroke, Model, ModelContext, Pixels, Platform, Render, Result, Size, Task,
+ TestDispatcher, TestPlatform, TestWindow, TextSystem, View, ViewContext, VisualContext,
+ WindowContext, WindowHandle, WindowOptions,
};
use anyhow::{anyhow, bail};
use futures::{Stream, StreamExt};
-use std::{future::Future, mem, ops::Deref, rc::Rc, sync::Arc, time::Duration};
+use std::{future::Future, ops::Deref, rc::Rc, sync::Arc, time::Duration};
#[derive(Clone)]
pub struct TestAppContext {
@@ -185,42 +184,7 @@ impl TestAppContext {
}
pub fn simulate_window_resize(&self, window_handle: AnyWindowHandle, size: Size<Pixels>) {
- let (mut handlers, scale_factor) = self
- .app
- .borrow_mut()
- .update_window(window_handle, |_, cx| {
- let platform_window = cx.window.platform_window.as_test().unwrap();
- let scale_factor = platform_window.scale_factor();
- match &mut platform_window.bounds {
- WindowBounds::Fullscreen | WindowBounds::Maximized => {
- platform_window.bounds = WindowBounds::Fixed(Bounds {
- origin: Point::default(),
- size: size.map(|pixels| f64::from(pixels).into()),
- });
- }
- WindowBounds::Fixed(bounds) => {
- bounds.size = size.map(|pixels| f64::from(pixels).into());
- }
- }
-
- (
- mem::take(&mut platform_window.handlers.lock().resize),
- scale_factor,
- )
- })
- .unwrap();
-
- for handler in &mut handlers {
- handler(size, scale_factor);
- }
-
- self.app
- .borrow_mut()
- .update_window(window_handle, |_, cx| {
- let platform_window = cx.window.platform_window.as_test().unwrap();
- platform_window.handlers.lock().resize = handlers;
- })
- .unwrap();
+ self.test_window(window_handle).simulate_resize(size);
}
pub fn spawn<Fut, R>(&self, f: impl FnOnce(AsyncAppContext) -> Fut) -> Task<R>
@@ -313,41 +277,22 @@ impl TestAppContext {
keystroke: Keystroke,
is_held: bool,
) {
- let keystroke2 = keystroke.clone();
- let handled = window
- .update(self, |_, cx| {
- cx.dispatch_event(InputEvent::KeyDown(KeyDownEvent { keystroke, is_held }))
- })
- .is_ok_and(|handled| handled);
- if handled {
- return;
- }
-
- let input_handler = self.update_test_window(window, |window| window.input_handler.clone());
- let Some(input_handler) = input_handler else {
- panic!(
- "dispatch_keystroke {:?} failed to dispatch action or input",
- &keystroke2
- );
- };
- let text = keystroke2.ime_key.unwrap_or(keystroke2.key);
- input_handler.lock().replace_text_in_range(None, &text);
+ self.test_window(window)
+ .simulate_keystroke(keystroke, is_held)
}
- pub fn update_test_window<R>(
- &mut self,
- window: AnyWindowHandle,
- f: impl FnOnce(&mut TestWindow) -> R,
- ) -> R {
- window
- .update(self, |_, cx| {
- f(cx.window
- .platform_window
- .as_any_mut()
- .downcast_mut::<TestWindow>()
- .unwrap())
- })
+ pub fn test_window(&self, window: AnyWindowHandle) -> TestWindow {
+ self.app
+ .borrow_mut()
+ .windows
+ .get_mut(window.id)
+ .unwrap()
+ .as_mut()
.unwrap()
+ .platform_window
+ .as_test()
+ .unwrap()
+ .clone()
}
pub fn notifications<T: 'static>(&mut self, entity: &impl Entity<T>) -> impl Stream<Item = ()> {
@@ -563,11 +508,7 @@ impl<'a> VisualTestContext<'a> {
}
pub fn window_title(&mut self) -> Option<String> {
- self.cx
- .update_window(self.window, |_, cx| {
- cx.window.platform_window.as_test().unwrap().title.clone()
- })
- .unwrap()
+ self.cx.test_window(self.window).0.lock().title.clone()
}
pub fn simulate_keystrokes(&mut self, keystrokes: &str) {
@@ -579,36 +520,15 @@ impl<'a> VisualTestContext<'a> {
}
pub fn simulate_activation(&mut self) {
- self.simulate_window_events(&mut |handlers| {
- handlers
- .active_status_change
- .iter_mut()
- .for_each(|f| f(true));
- })
+ self.cx
+ .test_window(self.window)
+ .simulate_active_status_change(true)
}
pub fn simulate_deactivation(&mut self) {
- self.simulate_window_events(&mut |handlers| {
- handlers
- .active_status_change
- .iter_mut()
- .for_each(|f| f(false));
- })
- }
-
- fn simulate_window_events(&mut self, f: &mut dyn FnMut(&mut TestWindowHandlers)) {
- let handlers = self
- .cx
- .update_window(self.window, |_, cx| {
- cx.window
- .platform_window
- .as_test()
- .unwrap()
- .handlers
- .clone()
- })
- .unwrap();
- f(&mut *handlers.lock());
+ self.cx
+ .test_window(self.window)
+ .simulate_active_status_change(false)
}
}
@@ -19,7 +19,7 @@ pub struct TestPlatform {
background_executor: BackgroundExecutor,
foreground_executor: ForegroundExecutor,
- active_window: Arc<Mutex<Option<AnyWindowHandle>>>,
+ pub(crate) active_window: RefCell<Option<TestWindow>>,
active_display: Rc<dyn PlatformDisplay>,
active_cursor: Mutex<CursorStyle>,
current_clipboard_item: Mutex<Option<ClipboardItem>>,
@@ -106,7 +106,7 @@ impl Platform for TestPlatform {
}
fn activate(&self, _ignoring_other_apps: bool) {
- unimplemented!()
+ //
}
fn hide(&self) {
@@ -130,7 +130,10 @@ impl Platform for TestPlatform {
}
fn active_window(&self) -> Option<crate::AnyWindowHandle> {
- self.active_window.lock().clone()
+ self.active_window
+ .borrow()
+ .as_ref()
+ .map(|window| window.0.lock().handle)
}
fn open_window(
@@ -139,12 +142,13 @@ impl Platform for TestPlatform {
options: WindowOptions,
_draw: Box<dyn FnMut() -> Result<Scene>>,
) -> Box<dyn crate::PlatformWindow> {
- *self.active_window.lock() = Some(handle);
- Box::new(TestWindow::new(
+ let window = TestWindow::new(
options,
+ handle,
self.weak.clone(),
self.active_display.clone(),
- ))
+ );
+ Box::new(window)
}
fn set_display_link_output_callback(
@@ -1,7 +1,8 @@
use crate::{
- px, AtlasKey, AtlasTextureId, AtlasTile, Pixels, PlatformAtlas, PlatformDisplay,
- PlatformInputHandler, PlatformWindow, Point, Size, TestPlatform, TileId, WindowAppearance,
- WindowBounds, WindowOptions,
+ px, AnyWindowHandle, AtlasKey, AtlasTextureId, AtlasTile, Bounds, InputEvent, KeyDownEvent,
+ Keystroke, Pixels, Platform, PlatformAtlas, PlatformDisplay, PlatformInputHandler,
+ PlatformWindow, Point, Size, TestPlatform, TileId, WindowAppearance, WindowBounds,
+ WindowOptions,
};
use collections::HashMap;
use parking_lot::Mutex;
@@ -10,51 +11,122 @@ use std::{
sync::{self, Arc},
};
-#[derive(Default)]
-pub(crate) struct TestWindowHandlers {
- pub(crate) active_status_change: Vec<Box<dyn FnMut(bool)>>,
- pub(crate) input: Vec<Box<dyn FnMut(crate::InputEvent) -> bool>>,
- pub(crate) moved: Vec<Box<dyn FnMut()>>,
- pub(crate) resize: Vec<Box<dyn FnMut(Size<Pixels>, f32)>>,
-}
-
-pub struct TestWindow {
+pub struct TestWindowState {
pub(crate) bounds: WindowBounds,
+ pub(crate) handle: AnyWindowHandle,
display: Rc<dyn PlatformDisplay>,
pub(crate) title: Option<String>,
pub(crate) edited: bool,
- pub(crate) input_handler: Option<Arc<Mutex<Box<dyn PlatformInputHandler>>>>,
- pub(crate) handlers: Arc<Mutex<TestWindowHandlers>>,
platform: Weak<TestPlatform>,
sprite_atlas: Arc<dyn PlatformAtlas>,
+
+ input_callback: Option<Box<dyn FnMut(InputEvent) -> bool>>,
+ active_status_change_callback: Option<Box<dyn FnMut(bool)>>,
+ resize_callback: Option<Box<dyn FnMut(Size<Pixels>, f32)>>,
+ moved_callback: Option<Box<dyn FnMut()>>,
+ input_handler: Option<Box<dyn PlatformInputHandler>>,
}
+#[derive(Clone)]
+pub struct TestWindow(pub(crate) Arc<Mutex<TestWindowState>>);
+
impl TestWindow {
pub fn new(
options: WindowOptions,
+ handle: AnyWindowHandle,
platform: Weak<TestPlatform>,
display: Rc<dyn PlatformDisplay>,
) -> Self {
- Self {
+ Self(Arc::new(Mutex::new(TestWindowState {
bounds: options.bounds,
display,
platform,
- input_handler: None,
+ handle,
sprite_atlas: Arc::new(TestAtlas::new()),
- handlers: Default::default(),
title: Default::default(),
edited: false,
+
+ input_callback: None,
+ active_status_change_callback: None,
+ resize_callback: None,
+ moved_callback: None,
+ input_handler: None,
+ })))
+ }
+
+ pub fn simulate_resize(&mut self, size: Size<Pixels>) {
+ let scale_factor = self.scale_factor();
+ let mut lock = self.0.lock();
+ let Some(mut callback) = lock.resize_callback.take() else {
+ return;
+ };
+ match &mut lock.bounds {
+ WindowBounds::Fullscreen | WindowBounds::Maximized => {
+ lock.bounds = WindowBounds::Fixed(Bounds {
+ origin: Point::default(),
+ size: size.map(|pixels| f64::from(pixels).into()),
+ });
+ }
+ WindowBounds::Fixed(bounds) => {
+ bounds.size = size.map(|pixels| f64::from(pixels).into());
+ }
}
+ drop(lock);
+ callback(size, scale_factor);
+ self.0.lock().resize_callback = Some(callback);
+ }
+
+ pub fn simulate_active_status_change(&self, active: bool) {
+ let mut lock = self.0.lock();
+ let Some(mut callback) = lock.active_status_change_callback.take() else {
+ return;
+ };
+ drop(lock);
+ callback(active);
+ self.0.lock().active_status_change_callback = Some(callback);
+ }
+
+ pub fn simulate_input(&mut self, event: InputEvent) -> bool {
+ let mut lock = self.0.lock();
+ let Some(mut callback) = lock.input_callback.take() else {
+ return false;
+ };
+ drop(lock);
+ let result = callback(event);
+ self.0.lock().input_callback = Some(callback);
+ result
+ }
+
+ pub fn simulate_keystroke(&mut self, keystroke: Keystroke, is_held: bool) {
+ if self.simulate_input(InputEvent::KeyDown(KeyDownEvent {
+ keystroke: keystroke.clone(),
+ is_held,
+ })) {
+ return;
+ }
+
+ let mut lock = self.0.lock();
+ let Some(mut input_handler) = lock.input_handler.take() else {
+ panic!(
+ "simulate_keystroke {:?} input event was not handled and there was no active input",
+ &keystroke
+ );
+ };
+ drop(lock);
+ let text = keystroke.ime_key.unwrap_or(keystroke.key);
+ input_handler.replace_text_in_range(None, &text);
+
+ self.0.lock().input_handler = Some(input_handler);
}
}
impl PlatformWindow for TestWindow {
fn bounds(&self) -> WindowBounds {
- self.bounds
+ self.0.lock().bounds
}
fn content_size(&self) -> Size<Pixels> {
- let bounds = match self.bounds {
+ let bounds = match self.bounds() {
WindowBounds::Fixed(bounds) => bounds,
WindowBounds::Maximized | WindowBounds::Fullscreen => self.display().bounds(),
};
@@ -74,7 +146,7 @@ impl PlatformWindow for TestWindow {
}
fn display(&self) -> std::rc::Rc<dyn crate::PlatformDisplay> {
- self.display.clone()
+ self.0.lock().display.clone()
}
fn mouse_position(&self) -> Point<Pixels> {
@@ -90,11 +162,11 @@ impl PlatformWindow for TestWindow {
}
fn set_input_handler(&mut self, input_handler: Box<dyn crate::PlatformInputHandler>) {
- self.input_handler = Some(Arc::new(Mutex::new(input_handler)));
+ self.0.lock().input_handler = Some(input_handler);
}
fn clear_input_handler(&mut self) {
- self.input_handler = None;
+ self.0.lock().input_handler = None;
}
fn prompt(
@@ -103,19 +175,50 @@ impl PlatformWindow for TestWindow {
_msg: &str,
_answers: &[&str],
) -> futures::channel::oneshot::Receiver<usize> {
- self.platform.upgrade().expect("platform dropped").prompt()
+ self.0
+ .lock()
+ .platform
+ .upgrade()
+ .expect("platform dropped")
+ .prompt()
}
fn activate(&self) {
- unimplemented!()
+ let this = self.clone();
+ let executor = self
+ .0
+ .lock()
+ .platform
+ .upgrade()
+ .unwrap()
+ .foreground_executor()
+ .clone();
+
+ executor
+ .spawn(async move {
+ let state = this.0.lock();
+ let platform = state.platform.upgrade().unwrap();
+ let previous_window = platform.active_window.borrow_mut().replace(this.clone());
+ drop(state);
+ drop(platform);
+ if let Some(previous_window) = previous_window {
+ if Arc::ptr_eq(&previous_window.0, &this.0) {
+ return;
+ }
+ previous_window.simulate_active_status_change(false);
+ }
+
+ this.simulate_active_status_change(true);
+ })
+ .detach();
}
fn set_title(&mut self, title: &str) {
- self.title = Some(title.to_owned());
+ self.0.lock().title = Some(title.to_owned());
}
fn set_edited(&mut self, edited: bool) {
- self.edited = edited;
+ self.0.lock().edited = edited;
}
fn show_character_palette(&self) {
@@ -135,15 +238,15 @@ impl PlatformWindow for TestWindow {
}
fn on_input(&self, callback: Box<dyn FnMut(crate::InputEvent) -> bool>) {
- self.handlers.lock().input.push(callback)
+ self.0.lock().input_callback = Some(callback)
}
fn on_active_status_change(&self, callback: Box<dyn FnMut(bool)>) {
- self.handlers.lock().active_status_change.push(callback)
+ self.0.lock().active_status_change_callback = Some(callback)
}
fn on_resize(&self, callback: Box<dyn FnMut(Size<Pixels>, f32)>) {
- self.handlers.lock().resize.push(callback)
+ self.0.lock().resize_callback = Some(callback)
}
fn on_fullscreen(&self, _callback: Box<dyn FnMut(bool)>) {
@@ -151,7 +254,7 @@ impl PlatformWindow for TestWindow {
}
fn on_moved(&self, callback: Box<dyn FnMut()>) {
- self.handlers.lock().moved.push(callback)
+ self.0.lock().moved_callback = Some(callback)
}
fn on_should_close(&self, _callback: Box<dyn FnMut() -> bool>) {
@@ -175,7 +278,7 @@ impl PlatformWindow for TestWindow {
}
fn sprite_atlas(&self) -> sync::Arc<dyn crate::PlatformAtlas> {
- self.sprite_atlas.clone()
+ self.0.lock().sprite_atlas.clone()
}
fn as_test(&mut self) -> Option<&mut TestWindow> {