use crate::{ AnyWindowHandle, BackgroundExecutor, ClipboardItem, CursorStyle, DisplayId, ForegroundExecutor, Platform, PlatformDisplay, PlatformTextSystem, TestDisplay, TestWindow, WindowOptions, }; use anyhow::{anyhow, Result}; use collections::VecDeque; use futures::channel::oneshot; use parking_lot::Mutex; use std::{ cell::RefCell, path::PathBuf, rc::{Rc, Weak}, sync::Arc, }; pub struct TestPlatform { background_executor: BackgroundExecutor, foreground_executor: ForegroundExecutor, active_window: Arc>>, active_display: Rc, active_cursor: Mutex, current_clipboard_item: Mutex>, pub(crate) prompts: RefCell, weak: Weak, } #[derive(Default)] pub(crate) struct TestPrompts { multiple_choice: VecDeque>, new_path: VecDeque<(PathBuf, oneshot::Sender>)>, } impl TestPlatform { pub fn new(executor: BackgroundExecutor, foreground_executor: ForegroundExecutor) -> Rc { Rc::new_cyclic(|weak| TestPlatform { background_executor: executor, foreground_executor, prompts: Default::default(), active_cursor: Default::default(), active_display: Rc::new(TestDisplay::new()), active_window: Default::default(), current_clipboard_item: Mutex::new(None), weak: weak.clone(), }) } pub(crate) fn simulate_new_path_selection( &self, select_path: impl FnOnce(&std::path::Path) -> Option, ) { let (path, tx) = self .prompts .borrow_mut() .new_path .pop_front() .expect("no pending new path prompt"); tx.send(select_path(&path)).ok(); } pub(crate) fn simulate_prompt_answer(&self, response_ix: usize) { let tx = self .prompts .borrow_mut() .multiple_choice .pop_front() .expect("no pending multiple choice prompt"); tx.send(response_ix).ok(); } pub(crate) fn has_pending_prompt(&self) -> bool { !self.prompts.borrow().multiple_choice.is_empty() } pub(crate) fn prompt(&self) -> oneshot::Receiver { let (tx, rx) = oneshot::channel(); self.prompts.borrow_mut().multiple_choice.push_back(tx); rx } } // todo!("implement out what our tests needed in GPUI 1") impl Platform for TestPlatform { fn background_executor(&self) -> BackgroundExecutor { self.background_executor.clone() } fn foreground_executor(&self) -> ForegroundExecutor { self.foreground_executor.clone() } fn text_system(&self) -> Arc { Arc::new(crate::platform::mac::MacTextSystem::new()) } fn run(&self, _on_finish_launching: Box) { unimplemented!() } fn quit(&self) {} fn restart(&self) { unimplemented!() } fn activate(&self, _ignoring_other_apps: bool) { unimplemented!() } fn hide(&self) { unimplemented!() } fn hide_other_apps(&self) { unimplemented!() } fn unhide_other_apps(&self) { unimplemented!() } fn displays(&self) -> Vec> { vec![self.active_display.clone()] } fn display(&self, id: DisplayId) -> Option> { self.displays().iter().find(|d| d.id() == id).cloned() } fn active_window(&self) -> Option { unimplemented!() } fn open_window( &self, handle: AnyWindowHandle, options: WindowOptions, ) -> Box { *self.active_window.lock() = Some(handle); Box::new(TestWindow::new( options, self.weak.clone(), self.active_display.clone(), )) } fn set_display_link_output_callback( &self, _display_id: DisplayId, _callback: Box, ) { unimplemented!() } fn start_display_link(&self, _display_id: DisplayId) { unimplemented!() } fn stop_display_link(&self, _display_id: DisplayId) { unimplemented!() } fn open_url(&self, _url: &str) { unimplemented!() } fn on_open_urls(&self, _callback: Box)>) { unimplemented!() } fn prompt_for_paths( &self, _options: crate::PathPromptOptions, ) -> oneshot::Receiver>> { unimplemented!() } fn prompt_for_new_path( &self, directory: &std::path::Path, ) -> oneshot::Receiver> { let (tx, rx) = oneshot::channel(); self.prompts .borrow_mut() .new_path .push_back((directory.to_path_buf(), tx)); rx } fn reveal_path(&self, _path: &std::path::Path) { unimplemented!() } fn on_become_active(&self, _callback: Box) {} fn on_resign_active(&self, _callback: Box) {} fn on_quit(&self, _callback: Box) {} fn on_reopen(&self, _callback: Box) { unimplemented!() } fn on_event(&self, _callback: Box bool>) { unimplemented!() } fn on_app_menu_action(&self, _callback: Box) { unimplemented!() } fn on_will_open_app_menu(&self, _callback: Box) { unimplemented!() } fn on_validate_app_menu_command(&self, _callback: Box bool>) { unimplemented!() } fn os_name(&self) -> &'static str { "test" } fn os_version(&self) -> Result { Err(anyhow!("os_version called on TestPlatform")) } fn app_version(&self) -> Result { Err(anyhow!("app_version called on TestPlatform")) } fn app_path(&self) -> Result { unimplemented!() } fn local_timezone(&self) -> time::UtcOffset { unimplemented!() } fn path_for_auxiliary_executable(&self, _name: &str) -> Result { unimplemented!() } fn set_cursor_style(&self, style: crate::CursorStyle) { *self.active_cursor.lock() = style; } fn should_auto_hide_scrollbars(&self) -> bool { // todo() true } fn write_to_clipboard(&self, item: ClipboardItem) { *self.current_clipboard_item.lock() = Some(item); } fn read_from_clipboard(&self) -> Option { self.current_clipboard_item.lock().clone() } fn write_credentials(&self, _url: &str, _username: &str, _password: &[u8]) -> Result<()> { Ok(()) } fn read_credentials(&self, _url: &str) -> Result)>> { Ok(None) } fn delete_credentials(&self, _url: &str) -> Result<()> { Ok(()) } }