From 11285f3762d96cd7433ae24b86fabeb985897f9c Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 23 Jul 2021 10:52:08 -0600 Subject: [PATCH] Pass a MutableAppContext to Element::layout and ::dispatch_event We need to mutate the app in these cases to relay layout state, so this just makes things easier. We won't be able to perform layout in parallel but it's questionable whether we'll ever actually do that. If we do, we can revisit. Co-Authored-By: Antonio Scandurra Co-Authored-By: Max Brunsfeld --- gpui/src/app.rs | 53 +++++++++++++++++++----- gpui/src/elements.rs | 4 +- gpui/src/elements/mouse_event_handler.rs | 4 +- gpui/src/elements/uniform_list.rs | 5 +-- gpui/src/presenter.rs | 10 ++--- zed/src/editor/element.rs | 42 +++++++++---------- zed/src/file_finder.rs | 1 + 7 files changed, 75 insertions(+), 44 deletions(-) diff --git a/gpui/src/app.rs b/gpui/src/app.rs index edb0f17dc1..9312d6b3f3 100644 --- a/gpui/src/app.rs +++ b/gpui/src/app.rs @@ -5,7 +5,8 @@ use crate::{ platform::{self, Platform, PromptLevel, WindowOptions}, presenter::Presenter, util::{post_inc, timeout}, - AssetCache, AssetSource, ClipboardItem, FontCache, PathPromptOptions, TextLayoutCache, + AssetCache, AssetSource, ClipboardItem, EventContext, FontCache, PathPromptOptions, + TextLayoutCache, }; use anyhow::{anyhow, Result}; use async_task::Task; @@ -22,6 +23,7 @@ use std::{ fmt::{self, Debug}, hash::{Hash, Hasher}, marker::PhantomData, + ops::Deref, path::{Path, PathBuf}, rc::{self, Rc}, sync::{Arc, Weak}, @@ -1476,6 +1478,14 @@ impl AsRef for MutableAppContext { } } +impl Deref for MutableAppContext { + type Target = AppContext; + + fn deref(&self) -> &Self::Target { + &self.cx + } +} + pub struct AppContext { models: HashMap>, views: HashMap<(usize, usize), Box>, @@ -1534,8 +1544,10 @@ impl AppContext { pub fn value(&self, id: usize) -> ValueHandle { let key = (TypeId::of::(), id); - let mut values = self.values.write(); - values.entry(key).or_insert_with(|| Box::new(T::default())); + self.values + .write() + .entry(key) + .or_insert_with(|| Box::new(T::default())); ValueHandle::new(TypeId::of::(), id, &self.ref_counts) } } @@ -2090,6 +2102,14 @@ impl AsRef for ViewContext<'_, M> { } } +impl Deref for ViewContext<'_, M> { + type Target = MutableAppContext; + + fn deref(&self) -> &Self::Target { + &self.app + } +} + impl AsMut for ViewContext<'_, M> { fn as_mut(&mut self) -> &mut MutableAppContext { self.app @@ -2633,8 +2653,7 @@ impl WeakViewHandle { } } - pub fn upgrade(&self, cx: impl AsRef) -> Option> { - let cx = cx.as_ref(); + pub fn upgrade(&self, cx: &AppContext) -> Option> { if cx.ref_counts.lock().is_entity_alive(self.view_id) { Some(ViewHandle::new( self.window_id, @@ -2684,13 +2703,25 @@ impl ValueHandle { .unwrap()) } - pub fn update(&self, cx: &AppContext, f: impl FnOnce(&mut T) -> R) -> R { - f(cx.values + pub fn update( + &self, + cx: &mut EventContext, + f: impl FnOnce(&mut T, &mut EventContext) -> R, + ) -> R { + let mut value = cx + .app + .cx + .values .write() - .get_mut(&(self.tag_type_id, self.id)) - .unwrap() - .downcast_mut() - .unwrap()) + .remove(&(self.tag_type_id, self.id)) + .unwrap(); + let result = f(value.downcast_mut().unwrap(), cx); + cx.app + .cx + .values + .write() + .insert((self.tag_type_id, self.id), value); + result } } diff --git a/gpui/src/elements.rs b/gpui/src/elements.rs index a37ee7fea5..869a26b542 100644 --- a/gpui/src/elements.rs +++ b/gpui/src/elements.rs @@ -29,8 +29,8 @@ pub use uniform_list::*; use crate::{ geometry::{rect::RectF, vector::Vector2F}, - json, AfterLayoutContext, AppContext, DebugContext, Event, EventContext, LayoutContext, - PaintContext, SizeConstraint, + json, AfterLayoutContext, DebugContext, Event, EventContext, LayoutContext, PaintContext, + SizeConstraint, }; use core::panic; use json::ToJson; diff --git a/gpui/src/elements/mouse_event_handler.rs b/gpui/src/elements/mouse_event_handler.rs index 98de1f6a0f..2fc310e825 100644 --- a/gpui/src/elements/mouse_event_handler.rs +++ b/gpui/src/elements/mouse_event_handler.rs @@ -24,7 +24,7 @@ impl MouseEventHandler { F: FnOnce(MouseState) -> ElementBox, { let state_handle = cx.value::(id); - let state = state_handle.read(cx, |state| *state); + let state = state_handle.read(cx.as_ref(), |state| *state); let child = render_child(state); Self { state: state_handle, @@ -81,7 +81,7 @@ impl Element for MouseEventHandler { let handled_in_child = self.child.dispatch_event(event, cx); - self.state.update(cx.app, |state| match event { + self.state.update(cx, |state, cx| match event { Event::MouseMoved { position } => { let mouse_in = bounds.contains_point(*position); if state.hovered != mouse_in { diff --git a/gpui/src/elements/uniform_list.rs b/gpui/src/elements/uniform_list.rs index 69cc55217b..b414a20430 100644 --- a/gpui/src/elements/uniform_list.rs +++ b/gpui/src/elements/uniform_list.rs @@ -1,6 +1,5 @@ use super::{ - AfterLayoutContext, AppContext, Element, Event, EventContext, LayoutContext, PaintContext, - SizeConstraint, + AfterLayoutContext, Element, Event, EventContext, LayoutContext, PaintContext, SizeConstraint, }; use crate::{ geometry::{ @@ -8,7 +7,7 @@ use crate::{ vector::{vec2f, Vector2F}, }, json::{self, json}, - ElementBox, + AppContext, ElementBox, }; use json::ToJson; use parking_lot::Mutex; diff --git a/gpui/src/presenter.rs b/gpui/src/presenter.rs index a6e37097c0..844dc05024 100644 --- a/gpui/src/presenter.rs +++ b/gpui/src/presenter.rs @@ -76,7 +76,7 @@ impl Presenter { let mut scene = Scene::new(scale_factor); if let Some(root_view_id) = cx.root_view_id(self.window_id) { - self.layout(window_size, cx.as_ref()); + self.layout(window_size, cx); self.after_layout(cx); let mut paint_cx = PaintContext { scene: &mut scene, @@ -98,7 +98,7 @@ impl Presenter { scene } - fn layout(&mut self, size: Vector2F, cx: &AppContext) { + fn layout(&mut self, size: Vector2F, cx: &mut MutableAppContext) { if let Some(root_view_id) = cx.root_view_id(self.window_id) { let mut layout_ctx = LayoutContext { rendered_views: &mut self.rendered_views, @@ -138,7 +138,7 @@ impl Presenter { text_layout_cache: &self.text_layout_cache, view_stack: Default::default(), invalidated_views: Default::default(), - app: cx.as_ref(), + app: cx, }; event_cx.dispatch_event(root_view_id, &event); @@ -184,7 +184,7 @@ pub struct LayoutContext<'a> { pub font_cache: &'a FontCache, pub text_layout_cache: &'a TextLayoutCache, pub asset_cache: &'a AssetCache, - pub app: &'a AppContext, + pub app: &'a mut MutableAppContext, view_stack: Vec, } @@ -240,7 +240,7 @@ pub struct EventContext<'a> { actions: Vec, pub font_cache: &'a FontCache, pub text_layout_cache: &'a TextLayoutCache, - pub app: &'a AppContext, + pub app: &'a mut MutableAppContext, view_stack: Vec, invalidated_views: HashSet, } diff --git a/zed/src/editor/element.rs b/zed/src/editor/element.rs index 86e425df41..8bc98c21ac 100644 --- a/zed/src/editor/element.rs +++ b/zed/src/editor/element.rs @@ -38,8 +38,9 @@ impl EditorElement { cx: &mut EventContext, ) -> bool { if paint.text_bounds.contains_point(position) { - let view = self.view(cx.app); - let position = paint.point_for_position(view, layout, position, cx.font_cache, cx.app); + let view = self.view(cx.app.as_ref()); + let position = + paint.point_for_position(view, layout, position, cx.font_cache, cx.app.as_ref()); cx.dispatch_action("buffer:select", SelectAction::Begin { position, add: cmd }); true } else { @@ -48,7 +49,7 @@ impl EditorElement { } fn mouse_up(&self, _position: Vector2F, cx: &mut EventContext) -> bool { - if self.view(cx.app).is_selecting() { + if self.view(cx.app.as_ref()).is_selecting() { cx.dispatch_action("buffer:select", SelectAction::End); true } else { @@ -63,7 +64,7 @@ impl EditorElement { paint: &mut PaintState, cx: &mut EventContext, ) -> bool { - let view = self.view(cx.app); + let view = self.view(cx.app.as_ref()); if view.is_selecting() { let rect = paint.text_bounds; @@ -93,22 +94,21 @@ impl EditorElement { )) } - cx.dispatch_action( - "buffer:select", - SelectAction::Update { - position: paint.point_for_position( - view, - layout, - position, - cx.font_cache, - cx.app, - ), - scroll_position: (view.scroll_position() + scroll_delta).clamp( - Vector2F::zero(), - layout.scroll_max(view, cx.font_cache, cx.text_layout_cache, cx.app), - ), - }, - ); + let action = SelectAction::Update { + position: paint.point_for_position( + view, + layout, + position, + cx.font_cache, + cx.app.as_ref(), + ), + scroll_position: (view.scroll_position() + scroll_delta).clamp( + Vector2F::zero(), + layout.scroll_max(view, cx.font_cache, cx.text_layout_cache, cx.app), + ), + }; + + cx.dispatch_action("buffer:select", action); true } else { false @@ -326,7 +326,7 @@ impl Element for EditorElement { constraint: SizeConstraint, cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { - let app = cx.app; + let app = &mut cx.app; let mut size = constraint.max; if size.y().is_infinite() { let view = self.view(app); diff --git a/zed/src/file_finder.rs b/zed/src/file_finder.rs index 2f5ad01101..362ee34e65 100644 --- a/zed/src/file_finder.rs +++ b/zed/src/file_finder.rs @@ -124,6 +124,7 @@ impl FileFinder { self.list_state.clone(), self.matches.len(), move |mut range, items, cx| { + let cx = cx.as_ref(); let finder = handle.upgrade(cx).unwrap(); let finder = finder.read(cx); let start = range.start;