diff --git a/gpui/examples/text.rs b/gpui/examples/text.rs index 14bc198270..2dad6e0786 100644 --- a/gpui/examples/text.rs +++ b/gpui/examples/text.rs @@ -1,7 +1,6 @@ use gpui::{ color::ColorU, fonts::{Properties, Weight}, - platform::{current as platform, Runner}, DebugContext, Element as _, Quad, }; use log::LevelFilter; @@ -11,13 +10,12 @@ use simplelog::SimpleLogger; fn main() { SimpleLogger::init(LevelFilter::Info, Default::default()).expect("could not initialize logger"); - let mut app = gpui::App::new(()).unwrap(); - platform::runner() - .on_finish_launching(move || { - app.platform().activate(true); - app.add_window(|_| TextView); - }) - .run(); + let app = gpui::App::new(()).unwrap(); + app.on_finish_launching(|app| { + app.platform().activate(true); + app.add_window(|_| TextView); + }) + .run(); } struct TextView; diff --git a/gpui/src/app.rs b/gpui/src/app.rs index 2c7af63af8..ab3f471e73 100644 --- a/gpui/src/app.rs +++ b/gpui/src/app.rs @@ -2,7 +2,7 @@ use crate::{ elements::ElementBox, executor, keymap::{self, Keystroke}, - platform::{self, Platform as _, WindowOptions}, + platform::{self, WindowOptions}, presenter::Presenter, util::post_inc, AssetCache, AssetSource, FontCache, TextLayoutCache, @@ -84,33 +84,10 @@ pub enum MenuItem<'a> { #[derive(Clone)] pub struct App(Rc>); -pub trait TestClosure<'a, T> { - type Result: 'a + Future; - fn run_test(self, ctx: &'a mut MutableAppContext) -> Self::Result; -} - -impl<'a, F, R, T> TestClosure<'a, T> for F -where - F: FnOnce(&mut MutableAppContext) -> R, - R: 'a + Future, -{ - type Result = R; - - fn run_test(self, ctx: &'a mut MutableAppContext) -> Self::Result { - (self)(ctx) - } -} - impl App { - pub fn test< - T, - A: AssetSource, - // F: 'static + , - // G: for<'a> FnOnce(&'a mut MutableAppContext) -> impl Future, - G: for<'a> TestClosure<'a, T>, - >( + pub fn test T>( asset_source: A, - f: G, + f: F, ) -> T { let platform = platform::test::platform(); let foreground = Rc::new(executor::Foreground::test()); @@ -121,11 +98,35 @@ impl App { ))); ctx.borrow_mut().weak_self = Some(Rc::downgrade(&ctx)); let mut ctx = ctx.borrow_mut(); - smol::block_on(foreground.run(f.run_test(&mut *ctx))) + f(&mut *ctx) + } + + pub fn test_async<'a, T, F, A: AssetSource, Fn>(asset_source: A, f: Fn) -> T + where + Fn: FnOnce(&'a mut MutableAppContext) -> F, + F: Future + 'a, + { + let platform = platform::test::platform(); + let foreground = Rc::new(executor::Foreground::test()); + let ctx = Rc::new(RefCell::new(MutableAppContext::new( + foreground.clone(), + Arc::new(platform), + asset_source, + ))); + let mut ctx_ref = ctx.borrow_mut(); + ctx_ref.weak_self = Some(Rc::downgrade(&ctx)); + let ctx = &mut *ctx_ref; + + // TODO - is there a better way of getting this to compile? + let ctx = unsafe { std::mem::transmute(ctx) }; + let future = f(ctx); + + drop(ctx_ref); + smol::block_on(foreground.run(future)) } pub fn new(asset_source: impl AssetSource) -> Result { - let platform = Arc::new(platform::current::app()); + let platform = platform::current::platform(); let foreground = Rc::new(executor::Foreground::platform(platform.dispatcher())?); let app = Self(Rc::new(RefCell::new(MutableAppContext::new( foreground, @@ -199,7 +200,7 @@ impl App { self } - pub fn run(self, callback: F) + pub fn on_finish_launching(self, callback: F) -> Self where F: 'static + FnOnce(&mut MutableAppContext), { @@ -207,7 +208,16 @@ impl App { self.0 .borrow() .platform - .run(Box::new(move || callback(&mut *ctx.borrow_mut()))); + .on_finish_launching(Box::new(move || callback(&mut *ctx.borrow_mut()))); + self + } + + pub fn set_menus(&self, menus: &[Menu]) { + self.0.borrow().platform.set_menus(menus); + } + + pub fn run(self) { + platform::current::run(); } pub fn on_window_invalidated( @@ -246,7 +256,7 @@ impl App { name: &str, arg: T, ) { - self.0.borrow_mut().dispatch_action( + self.0.borrow_mut().dispatch_action_any( window_id, &responder_chain, name, @@ -280,15 +290,6 @@ impl App { handle } - fn read_model(&self, handle: &ModelHandle, read: F) -> S - where - T: Entity, - F: FnOnce(&T, &AppContext) -> S, - { - let state = self.0.borrow(); - read(state.model(handle), &state.ctx) - } - pub fn add_window(&mut self, build_root_view: F) -> (usize, ViewHandle) where T: View, @@ -345,15 +346,6 @@ impl App { result } - fn read_view(&self, handle: &ViewHandle, read: F) -> S - where - T: View, - F: FnOnce(&T, &AppContext) -> S, - { - let state = self.0.borrow(); - read(state.view(handle), state.downgrade()) - } - pub fn finish_pending_tasks(&self) -> impl Future { self.0.borrow().finish_pending_tasks() } @@ -478,6 +470,10 @@ impl MutableAppContext { self.platform.clone() } + pub fn font_cache(&self) -> &Arc { + &self.font_cache + } + pub fn foreground_executor(&self) -> &Rc { &self.foreground } @@ -598,7 +594,24 @@ impl MutableAppContext { self.ctx.render_views(window_id) } - pub fn dispatch_action( + pub fn update T>(&mut self, callback: F) -> T { + self.pending_flushes += 1; + let result = callback(); + self.flush_effects(); + result + } + + pub fn dispatch_action( + &mut self, + window_id: usize, + responder_chain: Vec, + name: &str, + arg: T, + ) { + self.dispatch_action_any(window_id, &responder_chain, name, Box::new(arg).as_ref()); + } + + fn dispatch_action_any( &mut self, window_id: usize, path: &[usize], @@ -709,7 +722,7 @@ impl MutableAppContext { MatchResult::None => {} MatchResult::Pending => pending = true, MatchResult::Action { name, arg } => { - if self.dispatch_action( + if self.dispatch_action_any( window_id, &responder_chain[0..=i], &name, @@ -796,7 +809,7 @@ impl MutableAppContext { .borrow_mut() .dispatch_event(event, ctx.downgrade()); for action in actions { - ctx.dispatch_action( + ctx.dispatch_action_any( window_id, &action.path, action.name, @@ -1328,6 +1341,12 @@ impl UpdateView for MutableAppContext { } } +impl AsRef for MutableAppContext { + fn as_ref(&self) -> &AppContext { + &self.ctx + } +} + pub struct AppContext { models: HashMap>, windows: HashMap, @@ -2112,13 +2131,6 @@ impl ViewHandle { app.view(self) } - pub fn read<'a, F, S>(&self, app: &'a App, read: F) -> S - where - F: FnOnce(&T, &AppContext) -> S, - { - app.read_view(self, read) - } - pub fn update(&self, app: &mut A, update: F) -> S where A: UpdateView, @@ -2452,10 +2464,10 @@ mod tests { } } - App::test((), |app: &mut MutableAppContext| async move { + App::test((), |app| { let handle_1 = app.add_model(|ctx| Model::new(None, ctx)); let handle_2 = app.add_model(|ctx| Model::new(Some(handle_1.clone()), ctx)); - assert_eq!(app.0.borrow().ctx.models.len(), 2); + assert_eq!(app.ctx.models.len(), 2); handle_1.update(app, |model, ctx| { model.events.push("updated".into()); @@ -2478,11 +2490,10 @@ mod tests { model.other.take(); }); - let app_state = app.0.borrow(); - assert_eq!(app_state.ctx.models.len(), 1); - assert!(app_state.subscriptions.is_empty()); - assert!(app_state.observations.is_empty()); - }) + assert_eq!(app.ctx.models.len(), 1); + assert!(app.subscriptions.is_empty()); + assert!(app.observations.is_empty()); + }); } #[test] @@ -2496,8 +2507,7 @@ mod tests { type Event = usize; } - App::test((), |mut app| async move { - let app = &mut app; + App::test((), |app| { let handle_1 = app.add_model(|_| Model::default()); let handle_2 = app.add_model(|_| Model::default()); let handle_2b = handle_2.clone(); @@ -2513,10 +2523,10 @@ mod tests { }); handle_2.update(app, |_, c| c.emit(7)); - handle_1.read(app, |model, _| assert_eq!(model.events, vec![7])); + assert_eq!(handle_1.as_ref(app).events, vec![7]); handle_2.update(app, |_, c| c.emit(5)); - handle_1.read(app, |model, _| assert_eq!(model.events, vec![7, 10, 5])); + assert_eq!(handle_1.as_ref(app).events, vec![7, 10, 5]); }) } @@ -2532,8 +2542,7 @@ mod tests { type Event = (); } - App::test((), |mut app| async move { - let app = &mut app; + App::test((), |app| { let handle_1 = app.add_model(|_| Model::default()); let handle_2 = app.add_model(|_| Model::default()); let handle_2b = handle_2.clone(); @@ -2551,13 +2560,13 @@ mod tests { model.count = 7; c.notify() }); - handle_1.read(app, |model, _| assert_eq!(model.events, vec![7])); + assert_eq!(handle_1.as_ref(app).events, vec![7]); handle_2.update(app, |model, c| { model.count = 5; c.notify() }); - handle_1.read(app, |model, _| assert_eq!(model.events, vec![7, 10, 5])) + assert_eq!(handle_1.as_ref(app).events, vec![7, 10, 5]) }) } @@ -2572,25 +2581,25 @@ mod tests { type Event = (); } - App::test((), |mut app| async move { + App::test_async((), |app| async move { let handle = app.add_model(|_| Model::default()); handle - .update(&mut app, |_, c| { + .update(app, |_, c| { c.spawn(async { 7 }, |model, output, _| { model.count = output; }) }) .await; - handle.read(&app, |model, _| assert_eq!(model.count, 7)); + assert_eq!(handle.as_ref(app).count, 7); handle - .update(&mut app, |_, c| { + .update(app, |_, c| { c.spawn(async { 14 }, |model, output, _| { model.count = output; }) }) .await; - handle.read(&app, |model, _| assert_eq!(model.count, 14)); + assert_eq!(handle.as_ref(app).count, 14); }); } @@ -2605,10 +2614,10 @@ mod tests { type Event = (); } - App::test((), |mut app| async move { + App::test_async((), |app| async move { let handle = app.add_model(|_| Model::default()); handle - .update(&mut app, |_, c| { + .update(app, |_, c| { c.spawn_stream( smol::stream::iter(vec![1, 2, 3]), |model, output, _| { @@ -2620,10 +2629,7 @@ mod tests { ) }) .await; - - handle.read(&app, |model, _| { - assert_eq!(model.events, [Some(1), Some(2), Some(3), None]) - }); + assert_eq!(handle.as_ref(app).events, [Some(1), Some(2), Some(3), None]) }) } @@ -2662,40 +2668,34 @@ mod tests { } } - App::test((), |mut app| async move { - let app = &mut app; + App::test((), |app| { let (window_id, _) = app.add_window(|ctx| View::new(None, ctx)); let handle_1 = app.add_view(window_id, |ctx| View::new(None, ctx)); let handle_2 = app.add_view(window_id, |ctx| View::new(Some(handle_1.clone()), ctx)); - assert_eq!(app.0.borrow().ctx.windows[&window_id].views.len(), 3); + assert_eq!(app.ctx.windows[&window_id].views.len(), 3); handle_1.update(app, |view, ctx| { view.events.push("updated".into()); ctx.emit(1); ctx.emit(2); }); - handle_1.read(app, |view, _| { - assert_eq!(view.events, vec!["updated".to_string()]); - }); - handle_2.read(app, |view, _| { - assert_eq!( - view.events, - vec![ - "observed event 1".to_string(), - "observed event 2".to_string(), - ] - ); - }); + assert_eq!(handle_1.as_ref(app).events, vec!["updated".to_string()]); + assert_eq!( + handle_2.as_ref(app).events, + vec![ + "observed event 1".to_string(), + "observed event 2".to_string(), + ] + ); handle_2.update(app, |view, _| { drop(handle_1); view.other.take(); }); - let app_state = app.0.borrow(); - assert_eq!(app_state.ctx.windows[&window_id].views.len(), 2); - assert!(app_state.subscriptions.is_empty()); - assert!(app_state.observations.is_empty()); + assert_eq!(app.ctx.windows[&window_id].views.len(), 2); + assert!(app.subscriptions.is_empty()); + assert!(app.observations.is_empty()); }) } @@ -2726,8 +2726,7 @@ mod tests { type Event = usize; } - App::test((), |mut app| async move { - let app = &mut app; + App::test((), |app| { let (window_id, handle_1) = app.add_window(|_| View::default()); let handle_2 = app.add_view(window_id, |_| View::default()); let handle_2b = handle_2.clone(); @@ -2748,13 +2747,13 @@ mod tests { }); handle_2.update(app, |_, c| c.emit(7)); - handle_1.read(app, |view, _| assert_eq!(view.events, vec![7])); + assert_eq!(handle_1.as_ref(app).events, vec![7]); handle_2.update(app, |_, c| c.emit(5)); - handle_1.read(app, |view, _| assert_eq!(view.events, vec![7, 10, 5])); + assert_eq!(handle_1.as_ref(app).events, vec![7, 10, 5]); handle_3.update(app, |_, c| c.emit(9)); - handle_1.read(app, |view, _| assert_eq!(view.events, vec![7, 10, 5, 9])); + assert_eq!(handle_1.as_ref(app).events, vec![7, 10, 5, 9]); }) } @@ -2782,9 +2781,7 @@ mod tests { type Event = (); } - App::test((), |mut app| async move { - let app = &mut app; - + App::test((), |app| { let (window_id, _) = app.add_window(|_| View); let observing_view = app.add_view(window_id, |_| View); let emitting_view = app.add_view(window_id, |_| View); @@ -2799,7 +2796,7 @@ mod tests { ctx.subscribe(&observed_model, |_, _, _| {}); }); - app.update(|_| { + app.update(|| { drop(observing_view); drop(observing_model); }); @@ -2839,8 +2836,7 @@ mod tests { type Event = (); } - App::test((), |mut app| async move { - let app = &mut app; + App::test((), |app| { let (_, view) = app.add_window(|_| View::default()); let model = app.add_model(|_| Model::default()); @@ -2854,7 +2850,7 @@ mod tests { model.count = 11; c.notify(); }); - view.read(app, |view, _| assert_eq!(view.events, vec![11])); + assert_eq!(view.as_ref(app).events, vec![11]); }) } @@ -2882,9 +2878,7 @@ mod tests { type Event = (); } - App::test((), |mut app| async move { - let app = &mut app; - + App::test((), |app| { let (window_id, _) = app.add_window(|_| View); let observing_view = app.add_view(window_id, |_| View); let observing_model = app.add_model(|_| Model); @@ -2897,7 +2891,7 @@ mod tests { ctx.observe(&observed_model, |_, _, _| {}); }); - app.update(|_| { + app.update(|| { drop(observing_view); drop(observing_model); }); @@ -2937,8 +2931,7 @@ mod tests { } } - App::test((), |mut app| async move { - let app = &mut app; + App::test((), |app| { let (window_id, view_1) = app.add_window(|_| View::default()); let view_2 = app.add_view(window_id, |_| View::default()); @@ -2953,18 +2946,16 @@ mod tests { ctx.focus(&view_1); }); - view_1.read(app, |view_1, _| { - assert_eq!( - view_1.events, - [ - "self focused".to_string(), - "self blurred".to_string(), - "view 2 focused".to_string(), - "self focused".to_string(), - "view 2 blurred".to_string(), - ], - ); - }); + assert_eq!( + view_1.as_ref(app).events, + [ + "self focused".to_string(), + "self blurred".to_string(), + "view 2 focused".to_string(), + "self focused".to_string(), + "view 2 blurred".to_string(), + ], + ); }) } @@ -2989,24 +2980,24 @@ mod tests { } } - App::test((), |mut app| async move { + App::test_async((), |app| async move { let (_, handle) = app.add_window(|_| View::default()); handle - .update(&mut app, |_, c| { + .update(app, |_, c| { c.spawn(async { 7 }, |me, output, _| { me.count = output; }) }) .await; - handle.read(&app, |view, _| assert_eq!(view.count, 7)); + assert_eq!(handle.as_ref(app).count, 7); handle - .update(&mut app, |_, c| { + .update(app, |_, c| { c.spawn(async { 14 }, |me, output, _| { me.count = output; }) }) .await; - handle.read(&app, |view, _| assert_eq!(view.count, 14)); + assert_eq!(handle.as_ref(app).count, 14); }); } @@ -3031,10 +3022,10 @@ mod tests { } } - App::test((), |mut app| async move { + App::test_async((), |app| async move { let (_, handle) = app.add_window(|_| View::default()); handle - .update(&mut app, |_, c| { + .update(app, |_, c| { c.spawn_stream( smol::stream::iter(vec![1_usize, 2, 3]), |me, output, _| { @@ -3047,9 +3038,7 @@ mod tests { }) .await; - handle.read(&app, |view, _| { - assert_eq!(view.events, [Some(1), Some(2), Some(3), None]) - }); + assert_eq!(handle.as_ref(app).events, [Some(1), Some(2), Some(3), None]) }); } @@ -3095,7 +3084,7 @@ mod tests { foo: String, } - App::test((), |mut app| async move { + App::test((), |app| { let actions = Rc::new(RefCell::new(Vec::new())); let actions_clone = actions.clone(); @@ -3169,7 +3158,7 @@ mod tests { } #[test] - fn test_dispatch_keystroke() -> Result<()> { + fn test_dispatch_keystroke() { use std::cell::Cell; #[derive(Clone)] @@ -3209,7 +3198,7 @@ mod tests { } } - App::test((), |mut app| async move { + App::test((), |app| { let mut view_1 = View::new(1); let mut view_2 = View::new(2); let mut view_3 = View::new(3); @@ -3238,12 +3227,12 @@ mod tests { app.dispatch_keystroke( window_id, vec![view_1.id(), view_2.id(), view_3.id()], - &Keystroke::parse("a")?, - )?; + &Keystroke::parse("a").unwrap(), + ) + .unwrap(); assert!(handled_action.get()); - Ok(()) - }) + }); } // #[test] @@ -3266,7 +3255,7 @@ mod tests { // } // } - // App::test(|mut app| async move { + // App::test(|app| async move { // let (window_id, _) = app.add_window(|_| View { count: 3 }); // let view_1 = app.add_view(window_id, |_| View { count: 1 }); // let view_2 = app.add_view(window_id, |_| View { count: 2 }); @@ -3293,7 +3282,7 @@ mod tests { // }); // let view_2_id = view_2.id(); - // view_1.update(&mut app, |view, ctx| { + // view_1.update(app, |view, ctx| { // view.count = 7; // ctx.notify(); // drop(view_2); @@ -3304,7 +3293,7 @@ mod tests { // assert!(invalidation.updated.contains(&view_1.id())); // assert_eq!(invalidation.removed, vec![view_2_id]); - // let view_3 = view_1.update(&mut app, |_, ctx| ctx.add_view(|_| View { count: 8 })); + // let view_3 = view_1.update(app, |_, ctx| ctx.add_view(|_| View { count: 8 })); // let invalidation = window_invalidations.borrow_mut().drain(..).next().unwrap(); // assert_eq!(invalidation.updated.len(), 1); @@ -3312,7 +3301,7 @@ mod tests { // assert!(invalidation.removed.is_empty()); // view_3 - // .update(&mut app, |_, ctx| { + // .update(app, |_, ctx| { // ctx.spawn_local(async { 9 }, |me, output, ctx| { // me.count = output; // ctx.notify(); @@ -3351,49 +3340,49 @@ mod tests { type Event = (); } - App::test((), |mut app| async move { + App::test_async((), |app| async move { let model = app.add_model(|_| Model); let (_, view) = app.add_window(|_| View); - model.update(&mut app, |_, ctx| { + model.update(app, |_, ctx| { ctx.spawn(async {}, |_, _, _| {}).detach(); // Cancel this task drop(ctx.spawn(async {}, |_, _, _| {})); }); - view.update(&mut app, |_, ctx| { + view.update(app, |_, ctx| { ctx.spawn(async {}, |_, _, _| {}).detach(); // Cancel this task drop(ctx.spawn(async {}, |_, _, _| {})); }); - assert!(!app.0.borrow().future_handlers.borrow().is_empty()); + assert!(!app.future_handlers.borrow().is_empty()); app.finish_pending_tasks().await; - assert!(app.0.borrow().future_handlers.borrow().is_empty()); + assert!(app.future_handlers.borrow().is_empty()); app.finish_pending_tasks().await; // Don't block if there are no tasks - model.update(&mut app, |_, ctx| { + model.update(app, |_, ctx| { ctx.spawn_stream(smol::stream::iter(vec![1, 2, 3]), |_, _, _| {}, |_, _| {}) .detach(); // Cancel this task drop(ctx.spawn_stream(smol::stream::iter(vec![1, 2, 3]), |_, _, _| {}, |_, _| {})); }); - view.update(&mut app, |_, ctx| { + view.update(app, |_, ctx| { ctx.spawn_stream(smol::stream::iter(vec![1, 2, 3]), |_, _, _| {}, |_, _| {}) .detach(); // Cancel this task drop(ctx.spawn_stream(smol::stream::iter(vec![1, 2, 3]), |_, _, _| {}, |_, _| {})); }); - assert!(!app.0.borrow().stream_handlers.borrow().is_empty()); + assert!(!app.stream_handlers.borrow().is_empty()); app.finish_pending_tasks().await; - assert!(app.0.borrow().stream_handlers.borrow().is_empty()); + assert!(app.stream_handlers.borrow().is_empty()); app.finish_pending_tasks().await; // Don't block if there are no tasks // Tasks are considered finished when we drop handles let mut tasks = Vec::new(); - model.update(&mut app, |_, ctx| { + model.update(app, |_, ctx| { tasks.push(Box::new(ctx.spawn(async {}, |_, _, _| {}))); tasks.push(Box::new(ctx.spawn_stream( smol::stream::iter(vec![1, 2, 3]), @@ -3402,7 +3391,7 @@ mod tests { ))); }); - view.update(&mut app, |_, ctx| { + view.update(app, |_, ctx| { tasks.push(Box::new(ctx.spawn(async {}, |_, _, _| {}))); tasks.push(Box::new(ctx.spawn_stream( smol::stream::iter(vec![1, 2, 3]), @@ -3411,12 +3400,12 @@ mod tests { ))); }); - assert!(!app.0.borrow().stream_handlers.borrow().is_empty()); + assert!(!app.stream_handlers.borrow().is_empty()); let finish_pending_tasks = app.finish_pending_tasks(); drop(tasks); finish_pending_tasks.await; - assert!(app.0.borrow().stream_handlers.borrow().is_empty()); + assert!(app.stream_handlers.borrow().is_empty()); app.finish_pending_tasks().await; // Don't block if there are no tasks }); } diff --git a/gpui/src/platform/mac/mod.rs b/gpui/src/platform/mac/mod.rs index b54d148682..07ada3650a 100644 --- a/gpui/src/platform/mac/mod.rs +++ b/gpui/src/platform/mac/mod.rs @@ -5,7 +5,6 @@ mod fonts; mod geometry; mod platform; mod renderer; -mod runner; mod sprite_cache; mod window; @@ -13,15 +12,15 @@ use cocoa::base::{BOOL, NO, YES}; pub use dispatcher::Dispatcher; pub use fonts::FontSystem; use platform::MacPlatform; -pub use runner::Runner; +use std::sync::Arc; use window::Window; -pub fn app() -> impl super::Platform { +pub fn platform() -> Arc { MacPlatform::new() } -pub fn runner() -> impl super::Runner { - Runner::new() +pub fn run() { + MacPlatform::run(); } trait BoolExt { diff --git a/gpui/src/platform/mac/platform.rs b/gpui/src/platform/mac/platform.rs index d089ba26d2..40bd3566a5 100644 --- a/gpui/src/platform/mac/platform.rs +++ b/gpui/src/platform/mac/platform.rs @@ -90,13 +90,112 @@ struct Callbacks { } impl MacPlatform { - pub fn new() -> Self { - Self { + pub fn new() -> Arc { + let result = Arc::new(Self { dispatcher: Arc::new(Dispatcher), fonts: Arc::new(FontSystem::new()), callbacks: Default::default(), menu_item_actions: Default::default(), + }); + + unsafe { + let app: id = msg_send![APP_CLASS, sharedApplication]; + let app_delegate: id = msg_send![APP_DELEGATE_CLASS, new]; + let self_ptr = result.as_ref() as *const Self as *const c_void; + app.setDelegate_(app_delegate); + (*app).set_ivar(MAC_PLATFORM_IVAR, self_ptr); + (*app_delegate).set_ivar(MAC_PLATFORM_IVAR, self_ptr); } + + result + } + + pub fn run() { + unsafe { + let pool = NSAutoreleasePool::new(nil); + let app: id = msg_send![APP_CLASS, sharedApplication]; + + app.run(); + pool.drain(); + (*app).set_ivar(MAC_PLATFORM_IVAR, null_mut::()); + (*app.delegate()).set_ivar(MAC_PLATFORM_IVAR, null_mut::()); + } + } + + unsafe fn create_menu_bar(&self, menus: &[Menu]) -> id { + let menu_bar = NSMenu::new(nil).autorelease(); + let mut menu_item_actions = self.menu_item_actions.borrow_mut(); + menu_item_actions.clear(); + + for menu_config in menus { + let menu_bar_item = NSMenuItem::new(nil).autorelease(); + let menu = NSMenu::new(nil).autorelease(); + + menu.setTitle_(ns_string(menu_config.name)); + + for item_config in menu_config.items { + let item; + + match item_config { + MenuItem::Separator => { + item = NSMenuItem::separatorItem(nil); + } + MenuItem::Action { + name, + keystroke, + action, + } => { + if let Some(keystroke) = keystroke { + let keystroke = Keystroke::parse(keystroke).unwrap_or_else(|err| { + panic!( + "Invalid keystroke for menu item {}:{} - {:?}", + menu_config.name, name, err + ) + }); + + let mut mask = NSEventModifierFlags::empty(); + for (modifier, flag) in &[ + (keystroke.cmd, NSEventModifierFlags::NSCommandKeyMask), + (keystroke.ctrl, NSEventModifierFlags::NSControlKeyMask), + (keystroke.alt, NSEventModifierFlags::NSAlternateKeyMask), + ] { + if *modifier { + mask |= *flag; + } + } + + item = NSMenuItem::alloc(nil) + .initWithTitle_action_keyEquivalent_( + ns_string(name), + selector("handleGPUIMenuItem:"), + ns_string(&keystroke.key), + ) + .autorelease(); + item.setKeyEquivalentModifierMask_(mask); + } else { + item = NSMenuItem::alloc(nil) + .initWithTitle_action_keyEquivalent_( + ns_string(name), + selector("handleGPUIMenuItem:"), + ns_string(""), + ) + .autorelease(); + } + + let tag = menu_item_actions.len() as NSInteger; + let _: () = msg_send![item, setTag: tag]; + menu_item_actions.push(action.to_string()); + } + } + + menu.addItem_(item); + } + + menu_bar_item.setSubmenu_(menu); + menu_bar.addItem_(menu_bar_item); + } + + menu_bar } } @@ -121,23 +220,8 @@ impl platform::Platform for MacPlatform { self.callbacks.borrow_mut().open_files = Some(callback); } - fn run(&self, on_finish_launching: Box ()>) { - self.callbacks.borrow_mut().finish_launching = Some(on_finish_launching); - - unsafe { - let pool = NSAutoreleasePool::new(nil); - let app: id = msg_send![APP_CLASS, sharedApplication]; - let app_delegate: id = msg_send![APP_DELEGATE_CLASS, new]; - - let self_ptr = self as *const Self as *mut c_void; - (*app).set_ivar(MAC_PLATFORM_IVAR, self_ptr); - (*app_delegate).set_ivar(MAC_PLATFORM_IVAR, self_ptr); - app.setDelegate_(app_delegate); - app.run(); - pool.drain(); - (*app).set_ivar(MAC_PLATFORM_IVAR, null_mut::()); - (*app_delegate).set_ivar(MAC_PLATFORM_IVAR, null_mut::()); - } + fn on_finish_launching(&self, callback: Box ()>) { + self.callbacks.borrow_mut().finish_launching = Some(callback); } fn dispatcher(&self) -> Arc { @@ -222,84 +306,6 @@ impl platform::Platform for MacPlatform { } } -impl MacPlatform { - unsafe fn create_menu_bar(&self, menus: &[Menu]) -> id { - let menu_bar = NSMenu::new(nil).autorelease(); - let mut menu_item_actions = self.menu_item_actions.borrow_mut(); - menu_item_actions.clear(); - - for menu_config in menus { - let menu_bar_item = NSMenuItem::new(nil).autorelease(); - let menu = NSMenu::new(nil).autorelease(); - - menu.setTitle_(ns_string(menu_config.name)); - - for item_config in menu_config.items { - let item; - - match item_config { - MenuItem::Separator => { - item = NSMenuItem::separatorItem(nil); - } - MenuItem::Action { - name, - keystroke, - action, - } => { - if let Some(keystroke) = keystroke { - let keystroke = Keystroke::parse(keystroke).unwrap_or_else(|err| { - panic!( - "Invalid keystroke for menu item {}:{} - {:?}", - menu_config.name, name, err - ) - }); - - let mut mask = NSEventModifierFlags::empty(); - for (modifier, flag) in &[ - (keystroke.cmd, NSEventModifierFlags::NSCommandKeyMask), - (keystroke.ctrl, NSEventModifierFlags::NSControlKeyMask), - (keystroke.alt, NSEventModifierFlags::NSAlternateKeyMask), - ] { - if *modifier { - mask |= *flag; - } - } - - item = NSMenuItem::alloc(nil) - .initWithTitle_action_keyEquivalent_( - ns_string(name), - selector("handleGPUIMenuItem:"), - ns_string(&keystroke.key), - ) - .autorelease(); - item.setKeyEquivalentModifierMask_(mask); - } else { - item = NSMenuItem::alloc(nil) - .initWithTitle_action_keyEquivalent_( - ns_string(name), - selector("handleGPUIMenuItem:"), - ns_string(""), - ) - .autorelease(); - } - - let tag = menu_item_actions.len() as NSInteger; - let _: () = msg_send![item, setTag: tag]; - menu_item_actions.push(action.to_string()); - } - } - - menu.addItem_(item); - } - - menu_bar_item.setSubmenu_(menu); - menu_bar.addItem_(menu_bar_item); - } - - menu_bar - } -} - unsafe fn get_platform(object: &mut Object) -> &MacPlatform { let platform_ptr: *mut c_void = *object.get_ivar(MAC_PLATFORM_IVAR); assert!(!platform_ptr.is_null()); diff --git a/gpui/src/platform/mod.rs b/gpui/src/platform/mod.rs index b96bffb979..6e5d53585f 100644 --- a/gpui/src/platform/mod.rs +++ b/gpui/src/platform/mod.rs @@ -22,24 +22,13 @@ use async_task::Runnable; pub use event::Event; use std::{ops::Range, path::PathBuf, rc::Rc, sync::Arc}; -pub trait Runner { - fn on_finish_launching(self, callback: F) -> Self; - fn on_menu_command(self, callback: F) -> Self; - fn on_become_active(self, callback: F) -> Self; - fn on_resign_active(self, callback: F) -> Self; - fn on_event bool>(self, callback: F) -> Self; - fn on_open_files)>(self, callback: F) -> Self; - fn set_menus(self, menus: &[Menu]) -> Self; - fn run(self); -} - pub trait Platform { fn on_menu_command(&self, callback: Box); fn on_become_active(&self, callback: Box); fn on_resign_active(&self, callback: Box); fn on_event(&self, callback: Box bool>); fn on_open_files(&self, callback: Box)>); - fn run(&self, on_finish_launching: Box ()>); + fn on_finish_launching(&self, callback: Box ()>); fn dispatcher(&self) -> Arc; fn fonts(&self) -> Arc; diff --git a/gpui/src/platform/test.rs b/gpui/src/platform/test.rs index 08ec95ca74..1cd4399c1b 100644 --- a/gpui/src/platform/test.rs +++ b/gpui/src/platform/test.rs @@ -39,9 +39,7 @@ impl super::Platform for Platform { fn on_open_files(&self, _: Box)>) {} - fn run(&self, _on_finish_launching: Box ()>) { - unimplemented!() - } + fn on_finish_launching(&self, _: Box ()>) {} fn dispatcher(&self) -> Arc { self.dispatcher.clone() @@ -61,8 +59,7 @@ impl super::Platform for Platform { Ok(Box::new(Window::new(options.bounds.size()))) } - fn set_menus(&self, _menus: &[crate::Menu]) { - } + fn set_menus(&self, _menus: &[crate::Menu]) {} fn quit(&self) {} diff --git a/zed/src/editor/buffer/mod.rs b/zed/src/editor/buffer/mod.rs index 827da6be9d..9807b8ef97 100644 --- a/zed/src/editor/buffer/mod.rs +++ b/zed/src/editor/buffer/mod.rs @@ -2193,13 +2193,13 @@ mod tests { #[test] fn test_edit_events() { - App::test((), |mut app| async move { + App::test((), |app| { let buffer_1_events = Rc::new(RefCell::new(Vec::new())); let buffer_2_events = Rc::new(RefCell::new(Vec::new())); let buffer1 = app.add_model(|_| Buffer::new(0, "abcdef")); let buffer2 = app.add_model(|_| Buffer::new(1, "abcdef")); - let ops = buffer1.update(&mut app, |buffer, ctx| { + let ops = buffer1.update(app, |buffer, ctx| { let buffer_1_events = buffer_1_events.clone(); ctx.subscribe(&buffer1, move |_, event, _| { buffer_1_events.borrow_mut().push(event.clone()) @@ -2211,7 +2211,7 @@ mod tests { buffer.edit(Some(2..4), "XYZ", Some(ctx)).unwrap() }); - buffer2.update(&mut app, |buffer, ctx| { + buffer2.update(app, |buffer, ctx| { buffer.apply_ops(ops, Some(ctx)).unwrap(); }); @@ -2715,12 +2715,12 @@ mod tests { #[test] fn test_is_modified() -> Result<()> { - App::test((), |mut app| async move { + App::test((), |app| { let model = app.add_model(|_| Buffer::new(0, "abc")); let events = Rc::new(RefCell::new(Vec::new())); // initially, the buffer isn't dirty. - model.update(&mut app, |buffer, ctx| { + model.update(app, |buffer, ctx| { ctx.subscribe(&model, { let events = events.clone(); move |_, event, _| events.borrow_mut().push(event.clone()) @@ -2733,7 +2733,7 @@ mod tests { }); // after the first edit, the buffer is dirty, and emits a dirtied event. - model.update(&mut app, |buffer, ctx| { + model.update(app, |buffer, ctx| { assert!(buffer.text() == "ac"); assert!(buffer.is_dirty()); assert_eq!( @@ -2752,7 +2752,7 @@ mod tests { }); // after saving, the buffer is not dirty, and emits a saved event. - model.update(&mut app, |buffer, ctx| { + model.update(app, |buffer, ctx| { assert!(!buffer.is_dirty()); assert_eq!(*events.borrow(), &[Event::Saved]); events.borrow_mut().clear(); @@ -2762,7 +2762,7 @@ mod tests { }); // after editing again, the buffer is dirty, and emits another dirty event. - model.update(&mut app, |buffer, ctx| { + model.update(app, |buffer, ctx| { assert!(buffer.text() == "aBDc"); assert!(buffer.is_dirty()); assert_eq!( @@ -2788,7 +2788,7 @@ mod tests { assert!(buffer.is_dirty()); }); - model.update(&mut app, |_, _| { + model.update(app, |_, _| { assert_eq!( *events.borrow(), &[Event::Edited(vec![Edit { diff --git a/zed/src/editor/buffer_view.rs b/zed/src/editor/buffer_view.rs index fbd6c8cc83..b7974a3a2e 100644 --- a/zed/src/editor/buffer_view.rs +++ b/zed/src/editor/buffer_view.rs @@ -6,7 +6,7 @@ use crate::{settings::Settings, watch, workspace}; use anyhow::Result; use futures_core::future::LocalBoxFuture; use gpui::{ - fonts::Properties as FontProperties, keymap::Binding, text_layout, App, AppContext, Element, + fonts::Properties as FontProperties, keymap::Binding, text_layout, AppContext, Element, ElementBox, Entity, FontCache, ModelHandle, MutableAppContext, View, ViewContext, WeakViewHandle, }; @@ -1240,112 +1240,125 @@ mod tests { use super::*; use crate::{editor::Point, settings, test::sample_text}; use anyhow::Error; + use gpui::App; use unindent::Unindent; #[test] fn test_selection_with_mouse() { - App::test((), |mut app| async move { + App::test((), |app| { let buffer = app.add_model(|_| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n")); let settings = settings::channel(&app.font_cache()).unwrap().1; let (_, buffer_view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx)); - buffer_view.update(&mut app, |view, ctx| { + buffer_view.update(app, |view, ctx| { view.begin_selection(DisplayPoint::new(2, 2), false, ctx); }); - buffer_view.read(&app, |view, app| { - let selections = view - .selections_in_range(DisplayPoint::zero()..view.max_point(app), app) - .collect::>(); - assert_eq!( - selections, - [DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2)] - ); - }); + let view = buffer_view.as_ref(app); + let selections = view + .selections_in_range( + DisplayPoint::zero()..view.max_point(app.as_ref()), + app.as_ref(), + ) + .collect::>(); + assert_eq!( + selections, + [DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2)] + ); - buffer_view.update(&mut app, |view, ctx| { + buffer_view.update(app, |view, ctx| { view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), ctx); }); - buffer_view.read(&app, |view, app| { - let selections = view - .selections_in_range(DisplayPoint::zero()..view.max_point(app), app) - .collect::>(); - assert_eq!( - selections, - [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)] - ); - }); + let view = buffer_view.as_ref(app); + let selections = view + .selections_in_range( + DisplayPoint::zero()..view.max_point(app.as_ref()), + app.as_ref(), + ) + .collect::>(); + assert_eq!( + selections, + [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)] + ); - buffer_view.update(&mut app, |view, ctx| { + buffer_view.update(app, |view, ctx| { view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), ctx); }); - buffer_view.read(&app, |view, app| { - let selections = view - .selections_in_range(DisplayPoint::zero()..view.max_point(app), app) - .collect::>(); - assert_eq!( - selections, - [DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1)] - ); - }); + let view = buffer_view.as_ref(app); + let selections = view + .selections_in_range( + DisplayPoint::zero()..view.max_point(app.as_ref()), + app.as_ref(), + ) + .collect::>(); + assert_eq!( + selections, + [DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1)] + ); - buffer_view.update(&mut app, |view, ctx| { + buffer_view.update(app, |view, ctx| { view.end_selection(ctx); view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), ctx); }); - buffer_view.read(&app, |view, app| { - let selections = view - .selections_in_range(DisplayPoint::zero()..view.max_point(app), app) - .collect::>(); - assert_eq!( - selections, - [DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1)] - ); - }); + let view = buffer_view.as_ref(app); + let selections = view + .selections_in_range( + DisplayPoint::zero()..view.max_point(app.as_ref()), + app.as_ref(), + ) + .collect::>(); + assert_eq!( + selections, + [DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1)] + ); - buffer_view.update(&mut app, |view, ctx| { + buffer_view.update(app, |view, ctx| { view.begin_selection(DisplayPoint::new(3, 3), true, ctx); view.update_selection(DisplayPoint::new(0, 0), Vector2F::zero(), ctx); }); - buffer_view.read(&app, |view, app| { - let selections = view - .selections_in_range(DisplayPoint::zero()..view.max_point(app), app) - .collect::>(); - assert_eq!( - selections, - [ - DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1), - DisplayPoint::new(3, 3)..DisplayPoint::new(0, 0) - ] - ); - }); + let view = buffer_view.as_ref(app); + let selections = view + .selections_in_range( + DisplayPoint::zero()..view.max_point(app.as_ref()), + app.as_ref(), + ) + .collect::>(); + assert_eq!( + selections, + [ + DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1), + DisplayPoint::new(3, 3)..DisplayPoint::new(0, 0) + ] + ); - buffer_view.update(&mut app, |view, ctx| { + buffer_view.update(app, |view, ctx| { view.end_selection(ctx); }); - buffer_view.read(&app, |view, app| { - let selections = view - .selections_in_range(DisplayPoint::zero()..view.max_point(app), app) - .collect::>(); - assert_eq!( - selections, - [DisplayPoint::new(3, 3)..DisplayPoint::new(0, 0)] - ); - }); + let view = buffer_view.as_ref(app); + let selections = view + .selections_in_range( + DisplayPoint::zero()..view.max_point(app.as_ref()), + app.as_ref(), + ) + .collect::>(); + assert_eq!( + selections, + [DisplayPoint::new(3, 3)..DisplayPoint::new(0, 0)] + ); }); } #[test] - fn test_layout_line_numbers() -> Result<()> { - App::test((), |mut app| async move { + fn test_layout_line_numbers() { + App::test((), |app| { let layout_cache = TextLayoutCache::new(app.platform().fonts()); - let font_cache = app.font_cache(); + let font_cache = app.font_cache().clone(); let buffer = app.add_model(|_| Buffer::new(0, sample_text(6, 6))); @@ -1353,19 +1366,17 @@ mod tests { let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx)); - view.read(&app, |view, app| { - let layouts = view.layout_line_numbers(1000.0, &font_cache, &layout_cache, app)?; - assert_eq!(layouts.len(), 6); - Result::<()>::Ok(()) - })?; - - Ok(()) + let layouts = view + .as_ref(app) + .layout_line_numbers(1000.0, &font_cache, &layout_cache, app.as_ref()) + .unwrap(); + assert_eq!(layouts.len(), 6); }) } #[test] - fn test_fold() -> Result<()> { - App::test((), |mut app| async move { + fn test_fold() { + App::test((), |app| { let buffer = app.add_model(|_| { Buffer::new( 0, @@ -1393,8 +1404,9 @@ mod tests { let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx)); - view.update(&mut app, |view, ctx| { - view.select_ranges(&[DisplayPoint::new(8, 0)..DisplayPoint::new(12, 0)], ctx)?; + view.update(app, |view, ctx| { + view.select_ranges(&[DisplayPoint::new(8, 0)..DisplayPoint::new(12, 0)], ctx) + .unwrap(); view.fold(&(), ctx); assert_eq!( view.text(ctx.app()), @@ -1449,23 +1461,19 @@ mod tests { view.unfold(&(), ctx); assert_eq!(view.text(ctx.app()), buffer.as_ref(ctx).text()); - - Ok::<(), Error>(()) - })?; - - Ok(()) - }) + }); + }); } #[test] fn test_move_cursor() -> Result<()> { - App::test((), |mut app| async move { + App::test((), |app| { let buffer = app.add_model(|_| Buffer::new(0, sample_text(6, 6))); let settings = settings::channel(&app.font_cache()).unwrap().1; let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx)); - buffer.update(&mut app, |buffer, ctx| { + buffer.update(app, |buffer, ctx| { buffer.edit( vec![ Point::new(1, 0)..Point::new(1, 0), @@ -1476,7 +1484,7 @@ mod tests { ) })?; - view.update(&mut app, |view, ctx| { + view.update(app, |view, ctx| { view.move_down(&(), ctx); assert_eq!( view.selections(ctx.app()), @@ -1495,8 +1503,8 @@ mod tests { } #[test] - fn test_backspace() -> Result<()> { - App::test((), |mut app| async move { + fn test_backspace() { + App::test((), |app| { let buffer = app.add_model(|_| { Buffer::new(0, "one two three\nfour five six\nseven eight nine\nten\n") }); @@ -1504,7 +1512,7 @@ mod tests { let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx)); - view.update(&mut app, |view, ctx| -> Result<()> { + view.update(app, |view, ctx| { view.select_ranges( &[ // an empty selection - the preceding character is deleted @@ -1515,17 +1523,15 @@ mod tests { DisplayPoint::new(2, 6)..DisplayPoint::new(3, 0), ], ctx, - )?; + ) + .unwrap(); view.backspace(&(), ctx); - Ok(()) - })?; + }); - buffer.read(&mut app, |buffer, _| -> Result<()> { - assert_eq!(buffer.text(), "oe two three\nfou five six\nseven ten\n"); - Ok(()) - })?; - - Ok(()) + assert_eq!( + buffer.as_ref(app).text(), + "oe two three\nfou five six\nseven ten\n" + ); }) } diff --git a/zed/src/editor/display_map/fold_map.rs b/zed/src/editor/display_map/fold_map.rs index f5d76636ff..d67b4b510e 100644 --- a/zed/src/editor/display_map/fold_map.rs +++ b/zed/src/editor/display_map/fold_map.rs @@ -469,115 +469,106 @@ mod tests { use gpui::App; #[test] - fn test_basic_folds() -> Result<()> { - App::test((), |mut app| async move { + fn test_basic_folds() { + App::test((), |app| { let buffer = app.add_model(|_| Buffer::new(0, sample_text(5, 6))); - let mut map = app.read(|app| FoldMap::new(buffer.clone(), app)); + let mut map = FoldMap::new(buffer.clone(), app.as_ref()); - app.read(|app| { - map.fold( - vec![ - Point::new(0, 2)..Point::new(2, 2), - Point::new(2, 4)..Point::new(4, 1), - ], - app, - )?; - assert_eq!(map.text(app), "aa…cc…eeeee"); - Ok::<(), anyhow::Error>(()) - })?; + map.fold( + vec![ + Point::new(0, 2)..Point::new(2, 2), + Point::new(2, 4)..Point::new(4, 1), + ], + app.as_ref(), + ) + .unwrap(); + assert_eq!(map.text(app.as_ref()), "aa…cc…eeeee"); - let edits = buffer.update(&mut app, |buffer, ctx| { + let edits = buffer.update(app, |buffer, ctx| { let start_version = buffer.version.clone(); - buffer.edit( - vec![ - Point::new(0, 0)..Point::new(0, 1), - Point::new(2, 3)..Point::new(2, 3), - ], - "123", - Some(ctx), - )?; - Ok::<_, anyhow::Error>(buffer.edits_since(start_version).collect::>()) - })?; + buffer + .edit( + vec![ + Point::new(0, 0)..Point::new(0, 1), + Point::new(2, 3)..Point::new(2, 3), + ], + "123", + Some(ctx), + ) + .unwrap(); + buffer.edits_since(start_version).collect::>() + }); - app.read(|app| { - map.apply_edits(&edits, app)?; - assert_eq!(map.text(app), "123a…c123c…eeeee"); - Ok::<(), anyhow::Error>(()) - })?; + map.apply_edits(&edits, app.as_ref()).unwrap(); + assert_eq!(map.text(app.as_ref()), "123a…c123c…eeeee"); - let edits = buffer.update(&mut app, |buffer, ctx| { + let edits = buffer.update(app, |buffer, ctx| { let start_version = buffer.version.clone(); - buffer.edit(Some(Point::new(2, 6)..Point::new(4, 3)), "456", Some(ctx))?; - Ok::<_, anyhow::Error>(buffer.edits_since(start_version).collect::>()) - })?; + buffer + .edit(Some(Point::new(2, 6)..Point::new(4, 3)), "456", Some(ctx)) + .unwrap(); + buffer.edits_since(start_version).collect::>() + }); - app.read(|app| { - map.apply_edits(&edits, app)?; - assert_eq!(map.text(app), "123a…c123456eee"); + map.apply_edits(&edits, app.as_ref()).unwrap(); + assert_eq!(map.text(app.as_ref()), "123a…c123456eee"); - map.unfold(Some(Point::new(0, 4)..Point::new(0, 4)), app)?; - assert_eq!(map.text(app), "123aaaaa\nbbbbbb\nccc123456eee"); + map.unfold(Some(Point::new(0, 4)..Point::new(0, 4)), app.as_ref()) + .unwrap(); + assert_eq!(map.text(app.as_ref()), "123aaaaa\nbbbbbb\nccc123456eee"); + }); + } - Ok(()) - }) + #[test] + fn test_overlapping_folds() { + App::test((), |app| { + let buffer = app.add_model(|_| Buffer::new(0, sample_text(5, 6))); + let mut map = FoldMap::new(buffer.clone(), app.as_ref()); + map.fold( + vec![ + Point::new(0, 2)..Point::new(2, 2), + Point::new(0, 4)..Point::new(1, 0), + Point::new(1, 2)..Point::new(3, 2), + Point::new(3, 1)..Point::new(4, 1), + ], + app.as_ref(), + ) + .unwrap(); + assert_eq!(map.text(app.as_ref()), "aa…eeeee"); }) } #[test] - fn test_overlapping_folds() -> Result<()> { - App::test((), |mut app| async move { + fn test_merging_folds_via_edit() { + App::test((), |app| { let buffer = app.add_model(|_| Buffer::new(0, sample_text(5, 6))); - app.read(|app| { - let mut map = FoldMap::new(buffer.clone(), app); - map.fold( - vec![ - Point::new(0, 2)..Point::new(2, 2), - Point::new(0, 4)..Point::new(1, 0), - Point::new(1, 2)..Point::new(3, 2), - Point::new(3, 1)..Point::new(4, 1), - ], - app, - )?; - assert_eq!(map.text(app), "aa…eeeee"); - Ok(()) - }) - }) - } + let mut map = FoldMap::new(buffer.clone(), app.as_ref()); - #[test] - fn test_merging_folds_via_edit() -> Result<()> { - App::test((), |mut app| async move { - let buffer = app.add_model(|_| Buffer::new(0, sample_text(5, 6))); - let mut map = app.read(|app| FoldMap::new(buffer.clone(), app)); + map.fold( + vec![ + Point::new(0, 2)..Point::new(2, 2), + Point::new(3, 1)..Point::new(4, 1), + ], + app.as_ref(), + ) + .unwrap(); + assert_eq!(map.text(app.as_ref()), "aa…cccc\nd…eeeee"); - app.read(|app| { - map.fold( - vec![ - Point::new(0, 2)..Point::new(2, 2), - Point::new(3, 1)..Point::new(4, 1), - ], - app, - )?; - assert_eq!(map.text(app), "aa…cccc\nd…eeeee"); - Ok::<(), anyhow::Error>(()) - })?; - - let edits = buffer.update(&mut app, |buffer, ctx| { + let edits = buffer.update(app, |buffer, ctx| { let start_version = buffer.version.clone(); - buffer.edit(Some(Point::new(2, 2)..Point::new(3, 1)), "", Some(ctx))?; - Ok::<_, anyhow::Error>(buffer.edits_since(start_version).collect::>()) - })?; + buffer + .edit(Some(Point::new(2, 2)..Point::new(3, 1)), "", Some(ctx)) + .unwrap(); + buffer.edits_since(start_version).collect::>() + }); - app.read(|app| { - map.apply_edits(&edits, app)?; - assert_eq!(map.text(app), "aa…eeeee"); - Ok(()) - }) - }) + map.apply_edits(&edits, app.as_ref()).unwrap(); + assert_eq!(map.text(app.as_ref()), "aa…eeeee"); + }); } #[test] - fn test_random_folds() -> Result<()> { + fn test_random_folds() { use crate::editor::ToPoint; use crate::util::RandomCharIter; use rand::prelude::*; @@ -597,15 +588,15 @@ mod tests { println!("{:?}", seed); let mut rng = StdRng::seed_from_u64(seed); - App::test((), |mut app| async move { + App::test((), |app| { let buffer = app.add_model(|_| { let len = rng.gen_range(0..10); let text = RandomCharIter::new(&mut rng).take(len).collect::(); Buffer::new(0, text) }); - let mut map = app.read(|app| FoldMap::new(buffer.clone(), app)); + let mut map = FoldMap::new(buffer.clone(), app.as_ref()); - app.read(|app| { + { let buffer = buffer.as_ref(app); let fold_count = rng.gen_range(0..10); @@ -616,93 +607,83 @@ mod tests { fold_ranges.push(start..end); } - map.fold(fold_ranges, app)?; + map.fold(fold_ranges, app.as_ref()).unwrap(); let mut expected_text = buffer.text(); - for fold_range in map.merged_fold_ranges(app).into_iter().rev() { + for fold_range in map.merged_fold_ranges(app.as_ref()).into_iter().rev() { expected_text.replace_range(fold_range.start..fold_range.end, "…"); } - assert_eq!(map.text(app), expected_text); + assert_eq!(map.text(app.as_ref()), expected_text); - for fold_range in map.merged_fold_ranges(app) { + for fold_range in map.merged_fold_ranges(app.as_ref()) { let display_point = map.to_display_point(fold_range.start.to_point(buffer).unwrap()); assert!(map.is_line_folded(display_point.row())); } + } - Ok::<(), anyhow::Error>(()) - })?; - - let edits = buffer.update(&mut app, |buffer, ctx| { + let edits = buffer.update(app, |buffer, ctx| { let start_version = buffer.version.clone(); let edit_count = rng.gen_range(1..10); buffer.randomly_edit(&mut rng, edit_count, Some(ctx)); - Ok::<_, anyhow::Error>(buffer.edits_since(start_version).collect::>()) - })?; + buffer.edits_since(start_version).collect::>() + }); - app.read(|app| { - map.apply_edits(&edits, app)?; + map.apply_edits(&edits, app.as_ref()).unwrap(); - let buffer = map.buffer.as_ref(app); - let mut expected_text = buffer.text(); - let mut expected_buffer_rows = Vec::new(); - let mut next_row = buffer.max_point().row; - for fold_range in map.merged_fold_ranges(app).into_iter().rev() { - let fold_start = buffer.point_for_offset(fold_range.start).unwrap(); - let fold_end = buffer.point_for_offset(fold_range.end).unwrap(); - expected_buffer_rows.extend((fold_end.row + 1..=next_row).rev()); - next_row = fold_start.row; + let buffer = map.buffer.as_ref(app); + let mut expected_text = buffer.text(); + let mut expected_buffer_rows = Vec::new(); + let mut next_row = buffer.max_point().row; + for fold_range in map.merged_fold_ranges(app.as_ref()).into_iter().rev() { + let fold_start = buffer.point_for_offset(fold_range.start).unwrap(); + let fold_end = buffer.point_for_offset(fold_range.end).unwrap(); + expected_buffer_rows.extend((fold_end.row + 1..=next_row).rev()); + next_row = fold_start.row; - expected_text.replace_range(fold_range.start..fold_range.end, "…"); - } - expected_buffer_rows.extend((0..=next_row).rev()); - expected_buffer_rows.reverse(); + expected_text.replace_range(fold_range.start..fold_range.end, "…"); + } + expected_buffer_rows.extend((0..=next_row).rev()); + expected_buffer_rows.reverse(); - assert_eq!(map.text(app), expected_text); + assert_eq!(map.text(app.as_ref()), expected_text); - for (idx, buffer_row) in expected_buffer_rows.iter().enumerate() { - let display_row = map.to_display_point(Point::new(*buffer_row, 0)).row(); - assert_eq!( - map.buffer_rows(display_row).unwrap().collect::>(), - expected_buffer_rows[idx..], - ); - } - - Ok::<(), anyhow::Error>(()) - })?; - - Ok::<(), anyhow::Error>(()) - })?; + for (idx, buffer_row) in expected_buffer_rows.iter().enumerate() { + let display_row = map.to_display_point(Point::new(*buffer_row, 0)).row(); + assert_eq!( + map.buffer_rows(display_row).unwrap().collect::>(), + expected_buffer_rows[idx..], + ); + } + }); } - - Ok(()) } #[test] - fn test_buffer_rows() -> Result<()> { - App::test((), |mut app| async move { + fn test_buffer_rows() { + App::test((), |app| { let text = sample_text(6, 6) + "\n"; let buffer = app.add_model(|_| Buffer::new(0, text)); - app.read(|app| { - let mut map = FoldMap::new(buffer.clone(), app); + let mut map = FoldMap::new(buffer.clone(), app.as_ref()); - map.fold( - vec![ - Point::new(0, 2)..Point::new(2, 2), - Point::new(3, 1)..Point::new(4, 1), - ], - app, - )?; + map.fold( + vec![ + Point::new(0, 2)..Point::new(2, 2), + Point::new(3, 1)..Point::new(4, 1), + ], + app.as_ref(), + ) + .unwrap(); - assert_eq!(map.text(app), "aa…cccc\nd…eeeee\nffffff\n"); - assert_eq!(map.buffer_rows(0)?.collect::>(), vec![0, 3, 5, 6]); - assert_eq!(map.buffer_rows(3)?.collect::>(), vec![6]); - - Ok(()) - }) - }) + assert_eq!(map.text(app.as_ref()), "aa…cccc\nd…eeeee\nffffff\n"); + assert_eq!( + map.buffer_rows(0).unwrap().collect::>(), + vec![0, 3, 5, 6] + ); + assert_eq!(map.buffer_rows(3).unwrap().collect::>(), vec![6]); + }); } impl FoldMap { diff --git a/zed/src/editor/display_map/mod.rs b/zed/src/editor/display_map/mod.rs index 2679766aa1..7bc17627dd 100644 --- a/zed/src/editor/display_map/mod.rs +++ b/zed/src/editor/display_map/mod.rs @@ -292,52 +292,51 @@ pub fn collapse_tabs( mod tests { use super::*; use crate::test::*; - use anyhow::Error; use gpui::App; #[test] - fn test_chars_at() -> Result<()> { - App::test((), |mut app| async move { + fn test_chars_at() { + App::test((), |app| { let text = sample_text(6, 6); let buffer = app.add_model(|_| Buffer::new(0, text)); let map = app.add_model(|ctx| DisplayMap::new(buffer.clone(), 4, ctx)); - buffer.update(&mut app, |buffer, ctx| { - buffer.edit( - vec![ - Point::new(1, 0)..Point::new(1, 0), - Point::new(1, 1)..Point::new(1, 1), - Point::new(2, 1)..Point::new(2, 1), - ], - "\t", - Some(ctx), - ) - })?; + buffer + .update(app, |buffer, ctx| { + buffer.edit( + vec![ + Point::new(1, 0)..Point::new(1, 0), + Point::new(1, 1)..Point::new(1, 1), + Point::new(2, 1)..Point::new(2, 1), + ], + "\t", + Some(ctx), + ) + }) + .unwrap(); - map.read(&app, |map, ctx| { - assert_eq!( - map.chars_at(DisplayPoint::new(1, 0), ctx)? - .take(10) - .collect::(), - " b bb" - ); - assert_eq!( - map.chars_at(DisplayPoint::new(1, 2), ctx)? - .take(10) - .collect::(), - " b bbbb" - ); - assert_eq!( - map.chars_at(DisplayPoint::new(1, 6), ctx)? - .take(13) - .collect::(), - " bbbbb\nc c" - ); - - Ok::<(), Error>(()) - })?; - - Ok(()) - }) + let map = map.as_ref(app); + assert_eq!( + map.chars_at(DisplayPoint::new(1, 0), app.as_ref()) + .unwrap() + .take(10) + .collect::(), + " b bb" + ); + assert_eq!( + map.chars_at(DisplayPoint::new(1, 2), app.as_ref()) + .unwrap() + .take(10) + .collect::(), + " b bbbb" + ); + assert_eq!( + map.chars_at(DisplayPoint::new(1, 6), app.as_ref()) + .unwrap() + .take(13) + .collect::(), + " bbbbb\nc c" + ); + }); } #[test] @@ -364,14 +363,14 @@ mod tests { } #[test] - fn test_max_point() -> Result<()> { - App::test((), |mut app| async move { + fn test_max_point() { + App::test((), |app| { let buffer = app.add_model(|_| Buffer::new(0, "aaa\n\t\tbbb")); let map = app.add_model(|ctx| DisplayMap::new(buffer.clone(), 4, ctx)); - map.read(&app, |map, app| { - assert_eq!(map.max_point(app), DisplayPoint::new(1, 11)) - }); - Ok(()) - }) + assert_eq!( + map.as_ref(app).max_point(app.as_ref()), + DisplayPoint::new(1, 11) + ) + }); } } diff --git a/zed/src/file_finder.rs b/zed/src/file_finder.rs index 28a0ae0360..d03ce43294 100644 --- a/zed/src/file_finder.rs +++ b/zed/src/file_finder.rs @@ -11,7 +11,7 @@ use gpui::{ fonts::{Properties, Weight}, geometry::vector::vec2f, keymap::{self, Binding}, - App, AppContext, Axis, Border, Entity, ModelHandle, MutableAppContext, View, ViewContext, + AppContext, Axis, Border, Entity, ModelHandle, MutableAppContext, View, ViewContext, ViewHandle, WeakViewHandle, }; use std::cmp; @@ -394,20 +394,23 @@ mod tests { editor, settings, workspace::{Workspace, WorkspaceView}, }; - use anyhow::Result; use gpui::App; use smol::fs; use tempdir::TempDir; #[test] - fn test_matching_paths() -> Result<()> { - App::test((), |mut app| async move { - let tmp_dir = TempDir::new("example")?; - fs::create_dir(tmp_dir.path().join("a")).await?; - fs::write(tmp_dir.path().join("a/banana"), "banana").await?; - fs::write(tmp_dir.path().join("a/bandana"), "bandana").await?; - super::init(&mut app); - editor::init(&mut app); + fn test_matching_paths() { + App::test_async((), |app| async move { + let tmp_dir = TempDir::new("example").unwrap(); + fs::create_dir(tmp_dir.path().join("a")).await.unwrap(); + fs::write(tmp_dir.path().join("a/banana"), "banana") + .await + .unwrap(); + fs::write(tmp_dir.path().join("a/bandana"), "bandana") + .await + .unwrap(); + super::init(app); + editor::init(app); let settings = settings::channel(&app.font_cache()).unwrap().1; let workspace = app.add_model(|ctx| Workspace::new(vec![tmp_dir.path().into()], ctx)); @@ -420,16 +423,15 @@ mod tests { "file_finder:toggle".into(), (), ); - let (finder, query_buffer) = workspace_view.read(&app, |view, ctx| { - let finder = view - .modal() - .cloned() - .unwrap() - .downcast::() - .unwrap(); - let query_buffer = finder.as_ref(ctx).query_buffer.clone(); - (finder, query_buffer) - }); + + let finder = workspace_view + .as_ref(app) + .modal() + .cloned() + .unwrap() + .downcast::() + .unwrap(); + let query_buffer = finder.as_ref(app).query_buffer.clone(); let chain = vec![finder.id(), query_buffer.id()]; app.dispatch_action(window_id, chain.clone(), "buffer:insert", "b".to_string()); @@ -452,7 +454,7 @@ mod tests { // (), // ); // app.finish_pending_tasks().await; // Load Buffer and open BufferView. - // let active_pane = workspace_view.read(&app, |view, _| view.active_pane().clone()); + // let active_pane = workspace_view.as_ref(app).active_pane().clone(); // assert_eq!( // active_pane.state(&app), // pane::State { @@ -462,7 +464,6 @@ mod tests { // }] // } // ); - Ok(()) - }) + }); } } diff --git a/zed/src/main.rs b/zed/src/main.rs index f7e4f0346b..6d171a5a29 100644 --- a/zed/src/main.rs +++ b/zed/src/main.rs @@ -1,5 +1,5 @@ use fs::OpenOptions; -use gpui::platform::{current as platform, PathPromptOptions, Runner as _}; +use gpui::platform::PathPromptOptions; use log::LevelFilter; use simplelog::SimpleLogger; use std::{fs, path::PathBuf}; @@ -13,6 +13,7 @@ fn main() { let app = gpui::App::new(assets::Assets).unwrap(); let (_, settings_rx) = settings::channel(&app.font_cache()).unwrap(); + app.set_menus(menus::MENUS); app.on_menu_command({ let settings_rx = settings_rx.clone(); move |command, ctx| match command { @@ -34,7 +35,7 @@ fn main() { _ => ctx.dispatch_global_action(command, ()), } }) - .run(move |ctx| { + .on_finish_launching(move |ctx| { workspace::init(ctx); editor::init(ctx); file_finder::init(ctx); @@ -53,7 +54,8 @@ fn main() { }, ); } - }); + }) + .run(); } fn init_logger() { diff --git a/zed/src/workspace/mod.rs b/zed/src/workspace/mod.rs index e1a087049c..91dd99419a 100644 --- a/zed/src/workspace/mod.rs +++ b/zed/src/workspace/mod.rs @@ -9,7 +9,7 @@ pub use workspace::*; pub use workspace_view::*; use crate::{settings::Settings, watch}; -use gpui::{App, MutableAppContext}; +use gpui::MutableAppContext; use std::path::PathBuf; pub fn init(app: &mut MutableAppContext) { @@ -64,10 +64,10 @@ mod tests { #[test] fn test_open_paths_action() { - App::test((), |mut app| async move { + App::test((), |app| { let settings = settings::channel(&app.font_cache()).unwrap().1; - init(&mut app); + init(app); let dir = temp_tree(json!({ "a": { @@ -94,7 +94,7 @@ mod tests { settings: settings.clone(), }, ); - assert_eq!(app.window_ids().len(), 1); + assert_eq!(app.window_ids().count(), 1); app.dispatch_global_action( "workspace:open_paths", @@ -103,11 +103,19 @@ mod tests { settings: settings.clone(), }, ); - assert_eq!(app.window_ids().len(), 1); - let workspace_view_1 = app.root_view::(app.window_ids()[0]).unwrap(); - workspace_view_1.read(&app, |view, app| { - assert_eq!(view.workspace.as_ref(app).worktrees().len(), 2); - }); + assert_eq!(app.window_ids().count(), 1); + let workspace_view_1 = app + .root_view::(app.window_ids().next().unwrap()) + .unwrap(); + assert_eq!( + workspace_view_1 + .as_ref(app) + .workspace + .as_ref(app) + .worktrees() + .len(), + 2 + ); app.dispatch_global_action( "workspace:open_paths", @@ -119,7 +127,7 @@ mod tests { settings: settings.clone(), }, ); - assert_eq!(app.window_ids().len(), 2); + assert_eq!(app.window_ids().count(), 2); }); } } diff --git a/zed/src/workspace/pane.rs b/zed/src/workspace/pane.rs index 903292a63e..58acb86abb 100644 --- a/zed/src/workspace/pane.rs +++ b/zed/src/workspace/pane.rs @@ -5,7 +5,7 @@ use gpui::{ elements::*, geometry::{rect::RectF, vector::vec2f}, keymap::Binding, - App, AppContext, Border, Entity, MutableAppContext, Quad, View, ViewContext, + AppContext, Border, Entity, MutableAppContext, Quad, View, ViewContext, }; use std::cmp; diff --git a/zed/src/workspace/workspace.rs b/zed/src/workspace/workspace.rs index 092144791c..cc5cfec602 100644 --- a/zed/src/workspace/workspace.rs +++ b/zed/src/workspace/workspace.rs @@ -200,23 +200,22 @@ impl Entity for Workspace { #[cfg(test)] pub trait WorkspaceHandle { - fn file_entries(&self, app: &gpui::App) -> Vec<(usize, usize)>; + fn file_entries(&self, app: &mut MutableAppContext) -> Vec<(usize, usize)>; } #[cfg(test)] impl WorkspaceHandle for ModelHandle { - fn file_entries(&self, app: &gpui::App) -> Vec<(usize, usize)> { - self.read(&app, |w, app| { - w.worktrees() - .iter() - .flat_map(|tree| { - let tree_id = tree.id(); - tree.as_ref(app) - .files() - .map(move |file| (tree_id, file.entry_id)) - }) - .collect::>() - }) + fn file_entries(&self, app: &mut MutableAppContext) -> Vec<(usize, usize)> { + self.as_ref(app) + .worktrees() + .iter() + .flat_map(|tree| { + let tree_id = tree.id(); + tree.as_ref(app) + .files() + .map(move |file| (tree_id, file.entry_id)) + }) + .collect::>() } } @@ -228,8 +227,8 @@ mod tests { use serde_json::json; #[test] - fn test_open_entry() -> Result<(), Arc> { - App::test((), |mut app| async move { + fn test_open_entry() { + App::test_async((), |app| async move { let dir = temp_tree(json!({ "a": { "aa": "aa contents", @@ -241,32 +240,29 @@ mod tests { app.finish_pending_tasks().await; // Open and populate worktree. // Get the first file entry. - let entry = workspace.read(&app, |w, app| { - let tree = w.worktrees.iter().next().unwrap(); - let entry_id = tree.as_ref(app).files().next().unwrap().entry_id; - (tree.id(), entry_id) - }); + let tree = workspace.as_ref(app).worktrees.iter().next().unwrap(); + let entry_id = tree.as_ref(app).files().next().unwrap().entry_id; + let entry = (tree.id(), entry_id); // Open the same entry twice before it finishes loading. - let (future_1, future_2) = workspace.update(&mut app, |w, app| { + let (future_1, future_2) = workspace.update(app, |w, app| { ( w.open_entry(entry, app).unwrap(), w.open_entry(entry, app).unwrap(), ) }); - let handle_1 = future_1.await?; - let handle_2 = future_2.await?; + let handle_1 = future_1.await.unwrap(); + let handle_2 = future_2.await.unwrap(); assert_eq!(handle_1.id(), handle_2.id()); // Open the same entry again now that it has loaded let handle_3 = workspace - .update(&mut app, |w, app| w.open_entry(entry, app).unwrap()) - .await?; + .update(app, |w, app| w.open_entry(entry, app).unwrap()) + .await + .unwrap(); assert_eq!(handle_3.id(), handle_1.id()); - - Ok(()) }) } } diff --git a/zed/src/workspace/workspace_view.rs b/zed/src/workspace/workspace_view.rs index 32e16fc014..aaf1e9eb9a 100644 --- a/zed/src/workspace/workspace_view.rs +++ b/zed/src/workspace/workspace_view.rs @@ -2,8 +2,8 @@ use super::{pane, Pane, PaneGroup, SplitDirection, Workspace}; use crate::{settings::Settings, watch}; use futures_core::future::LocalBoxFuture; use gpui::{ - color::rgbu, elements::*, json::to_string_pretty, keymap::Binding, AnyViewHandle, App, - AppContext, Entity, ModelHandle, MutableAppContext, View, ViewContext, ViewHandle, + color::rgbu, elements::*, json::to_string_pretty, keymap::Binding, AnyViewHandle, AppContext, + Entity, ModelHandle, MutableAppContext, View, ViewContext, ViewHandle, }; use log::{error, info}; use std::{collections::HashSet, path::PathBuf}; @@ -389,13 +389,12 @@ impl View for WorkspaceView { mod tests { use super::{pane, Workspace, WorkspaceView}; use crate::{settings, test::temp_tree, workspace::WorkspaceHandle as _}; - use anyhow::Result; use gpui::App; use serde_json::json; #[test] - fn test_open_entry() -> Result<()> { - App::test((), |mut app| async move { + fn test_open_entry() { + App::test_async((), |app| async move { let dir = temp_tree(json!({ "a": { "aa": "aa contents", @@ -407,64 +406,70 @@ mod tests { let settings = settings::channel(&app.font_cache()).unwrap().1; let workspace = app.add_model(|ctx| Workspace::new(vec![dir.path().into()], ctx)); app.finish_pending_tasks().await; // Open and populate worktree. - let entries = workspace.file_entries(&app); + let entries = workspace.file_entries(app); let (_, workspace_view) = app.add_window(|ctx| WorkspaceView::new(workspace.clone(), settings, ctx)); // Open the first entry - workspace_view.update(&mut app, |w, ctx| w.open_entry(entries[0], ctx)); + workspace_view.update(app, |w, ctx| w.open_entry(entries[0], ctx)); app.finish_pending_tasks().await; - workspace_view.read(&app, |w, app| { - assert_eq!(w.active_pane().as_ref(app).items().len(), 1); - }); + assert_eq!( + workspace_view + .as_ref(app) + .active_pane() + .as_ref(app) + .items() + .len(), + 1 + ); // Open the second entry - workspace_view.update(&mut app, |w, ctx| w.open_entry(entries[1], ctx)); + workspace_view.update(app, |w, ctx| w.open_entry(entries[1], ctx)); app.finish_pending_tasks().await; - workspace_view.read(&app, |w, app| { - let active_pane = w.active_pane().as_ref(app); - assert_eq!(active_pane.items().len(), 2); - assert_eq!( - active_pane.active_item().unwrap().entry_id(app), - Some(entries[1]) - ); - }); + let active_pane = workspace_view.as_ref(app).active_pane().as_ref(app); + assert_eq!(active_pane.items().len(), 2); + assert_eq!( + active_pane.active_item().unwrap().entry_id(app.as_ref()), + Some(entries[1]) + ); // Open the first entry again - workspace_view.update(&mut app, |w, ctx| w.open_entry(entries[0], ctx)); + workspace_view.update(app, |w, ctx| w.open_entry(entries[0], ctx)); app.finish_pending_tasks().await; - workspace_view.read(&app, |w, app| { - let active_pane = w.active_pane().as_ref(app); - assert_eq!(active_pane.items().len(), 2); - assert_eq!( - active_pane.active_item().unwrap().entry_id(app), - Some(entries[0]) - ); - }); + let active_pane = workspace_view.as_ref(app).active_pane().as_ref(app); + assert_eq!(active_pane.items().len(), 2); + assert_eq!( + active_pane.active_item().unwrap().entry_id(app.as_ref()), + Some(entries[0]) + ); // Open the third entry twice concurrently - workspace_view.update(&mut app, |w, ctx| { + workspace_view.update(app, |w, ctx| { w.open_entry(entries[2], ctx); w.open_entry(entries[2], ctx); }); app.finish_pending_tasks().await; - workspace_view.read(&app, |w, app| { - assert_eq!(w.active_pane().as_ref(app).items().len(), 3); - }); - - Ok(()) - }) + assert_eq!( + workspace_view + .as_ref(app) + .active_pane() + .as_ref(app) + .items() + .len(), + 3 + ); + }); } #[test] - fn test_pane_actions() -> Result<()> { - App::test((), |mut app| async move { - pane::init(&mut app); + fn test_pane_actions() { + App::test_async((), |app| async move { + pane::init(app); let dir = temp_tree(json!({ "a": { @@ -474,35 +479,37 @@ mod tests { }, })); - let settings = settings::channel(&app.font_cache()).unwrap().1; + let settings = settings::channel(app.font_cache()).unwrap().1; let workspace = app.add_model(|ctx| Workspace::new(vec![dir.path().into()], ctx)); app.finish_pending_tasks().await; // Open and populate worktree. - let entries = workspace.file_entries(&app); + let entries = workspace.file_entries(app); let (window_id, workspace_view) = app.add_window(|ctx| WorkspaceView::new(workspace.clone(), settings, ctx)); - workspace_view.update(&mut app, |w, ctx| w.open_entry(entries[0], ctx)); + workspace_view.update(app, |w, ctx| w.open_entry(entries[0], ctx)); app.finish_pending_tasks().await; - let pane_1 = workspace_view.read(&app, |w, _| w.active_pane().clone()); + let pane_1 = workspace_view.as_ref(app).active_pane().clone(); app.dispatch_action(window_id, vec![pane_1.id()], "pane:split_right", ()); - let pane_2 = workspace_view.read(&app, |w, _| w.active_pane().clone()); + let pane_2 = workspace_view.as_ref(app).active_pane().clone(); assert_ne!(pane_1, pane_2); - pane_2.read(&app, |p, app| { - assert_eq!(p.active_item().unwrap().entry_id(app), Some(entries[0])); - }); + assert_eq!( + pane_2 + .as_ref(app) + .active_item() + .unwrap() + .entry_id(app.downgrade()), + Some(entries[0]) + ); app.dispatch_action(window_id, vec![pane_2.id()], "pane:close_active_item", ()); - workspace_view.read(&app, |w, _| { - assert_eq!(w.panes.len(), 1); - assert_eq!(w.active_pane(), &pane_1) - }); - - Ok(()) - }) + let w = workspace_view.as_ref(app); + assert_eq!(w.panes.len(), 1); + assert_eq!(w.active_pane(), &pane_1); + }); } } diff --git a/zed/src/worktree/worktree.rs b/zed/src/worktree/worktree.rs index bbb264df62..27f42d904d 100644 --- a/zed/src/worktree/worktree.rs +++ b/zed/src/worktree/worktree.rs @@ -648,8 +648,8 @@ mod test { use std::os::unix; #[test] - fn test_populate_and_search() -> Result<()> { - App::test((), |mut app| async move { + fn test_populate_and_search() { + App::test_async((), |app| async move { let dir = temp_tree(json!({ "root": { "apple": "", @@ -666,33 +666,31 @@ mod test { })); let root_link_path = dir.path().join("root_link"); - unix::fs::symlink(&dir.path().join("root"), &root_link_path)?; + unix::fs::symlink(&dir.path().join("root"), &root_link_path).unwrap(); let tree = app.add_model(|ctx| Worktree::new(1, root_link_path, Some(ctx))); app.finish_pending_tasks().await; - tree.read(&app, |tree, _| { - assert_eq!(tree.file_count(), 4); - let results = match_paths(&[tree.clone()], "bna", false, false, 10) - .iter() - .map(|result| tree.entry_path(result.entry_id)) - .collect::, _>>() - .unwrap(); - assert_eq!( - results, - vec![ - PathBuf::from("root_link/banana/carrot/date"), - PathBuf::from("root_link/banana/carrot/endive"), - ] - ); - }); - Ok(()) - }) + let tree = tree.as_ref(app); + assert_eq!(tree.file_count(), 4); + let results = match_paths(&[tree.clone()], "bna", false, false, 10) + .iter() + .map(|result| tree.entry_path(result.entry_id)) + .collect::, _>>() + .unwrap(); + assert_eq!( + results, + vec![ + PathBuf::from("root_link/banana/carrot/date"), + PathBuf::from("root_link/banana/carrot/endive"), + ] + ); + }); } #[test] fn test_save_file() { - App::test((), |mut app| async move { + App::test_async((), |app| async move { let dir = temp_tree(json!({ "file1": "the old contents", })); @@ -700,24 +698,18 @@ mod test { let tree = app.add_model(|ctx| Worktree::new(1, dir.path(), Some(ctx))); app.finish_pending_tasks().await; - let file_id = tree.read(&app, |tree, _| { - let entry = tree.files().next().unwrap(); - assert_eq!(entry.path.file_name().unwrap(), "file1"); - entry.entry_id - }); + let entry = tree.as_ref(app).files().next().unwrap(); + assert_eq!(entry.path.file_name().unwrap(), "file1"); + let file_id = entry.entry_id; let buffer = Buffer::new(1, "a line of text.\n".repeat(10 * 1024)); - tree.update(&mut app, |tree, ctx| { + tree.update(app, |tree, ctx| { smol::block_on(tree.save(file_id, buffer.snapshot(), ctx.app())).unwrap() }); - let history = tree - .read(&app, |tree, _| tree.load_history(file_id)) - .await - .unwrap(); - + let history = tree.as_ref(app).load_history(file_id).await.unwrap(); assert_eq!(history.base_text, buffer.text()); - }) + }); } }