use std::cell::RefCell; use std::rc::Rc; use std::time::Instant; use gpui::{ AppContext as _, Context, Entity, IntoElement, ParentElement as _, Render, SharedString, Styled as _, TestAppContext, Window, div, }; use gpui_native_core::command_palette::{Command, CommandPalette, CommandPaletteState}; use gpui_native_core::init; fn command(label: &'static str) -> Command { Command::new(SharedString::from(label), SharedString::from(label)) } struct Host { palette: Entity, renders: Rc>, } impl Render for Host { fn render(&mut self, _window: &mut Window, _cx: &mut Context) -> impl IntoElement { *self.renders.borrow_mut() += 1; div().size_full().child(self.palette.clone()) } } #[test] fn typing_with_the_palette_open_is_not_pathologically_slow() { let cx = TestAppContext::single(); cx.update(init); let (state, renders, window) = cx.update(|cx| { let renders = Rc::new(RefCell::new(0)); let state_cell: Rc>>> = Rc::new(RefCell::new(None)); let renders_for_host = renders.clone(); let cell = state_cell.clone(); let window = cx .open_window(gpui::WindowOptions::default(), |window, cx| { let matcher = |query: &str, commands: &[Command]| { let query = query.to_lowercase(); commands .iter() .filter(|command| command.label.to_lowercase().contains(&query)) .cloned() .collect() }; let state = cx.new(|cx| { CommandPaletteState::new( CommandPalette::new( "bench-palette", vec![ command("Open File"), command("Close Tab"), command("Save All"), command("Toggle Theme"), ], matcher, ), window, cx, ) }); let state_for_host = state.clone(); cell.borrow_mut().replace(state.clone()); cx.new(|_| Host { palette: state_for_host, renders: renders_for_host, }) }) .unwrap(); let state = state_cell.borrow().clone().expect("state captured"); (state, renders, window) }); let mut visual = gpui::VisualTestContext::from_window(window.into(), &cx); visual.update(|window, cx| { state.update(cx, |state, cx| state.open(window, cx)); window.draw(cx).clear(cx); }); let started = Instant::now(); for letter in "abcdefghijklmnopqrstuvwxyz".chars() { visual.simulate_keystrokes(&letter.to_string()); visual.update(|window, cx| { window.draw(cx).clear(cx); }); } let elapsed = started.elapsed(); let total_renders = *renders.borrow(); println!( "26 real keystrokes with the palette open: {elapsed:?}, host renders: {total_renders} ({} per keystroke)", total_renders as f32 / 26. ); assert!(elapsed.as_millis() < 2000, "typing took {elapsed:?}"); }