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 edb0f17dc1f33c4c30f5bb99c46f35ad6ba5bd36..9312d6b3f3480f6e78093625111d5553bc752139 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 a37ee7fea5801e9864ec75194f1d7dbf3359d45a..869a26b542d99d551537b579e5bad6222045fa6d 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 98de1f6a0f4d0a0b47f8876452c7d2a067967ced..2fc310e8252b88d79217e5783dea6ba3ca53a207 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 69cc55217bbcc83896257614e4b20e1650909e0a..b414a20430159ff373422240add657792687f2e9 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 a6e37097c08229f0363071823e5a2af93134a06d..844dc0502432dc2c96fabca95a92aac36ac202dd 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 86e425df411e5b028e2d64bd3b4f9c6f75c40f7b..8bc98c21aca1d7862ddd185c679ba80affc03b2a 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 2f5ad01101e38c450cf740d6faeaf4a7a463cc43..362ee34e65ce5f49053b49f92797603e169a3502 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;