Cache view's type id and keymap context into a separate map

During `layout`, we now pass a mutable reference to the element's
parent view. This is a recursive process that causes the view to
be removed from `AppContext` and then re-inserted back into it once
the layout is complete.

As such, querying parent views during `layout` does not work as such
views will have been removed from `AppContext` and not yet re-inserted
into it. This caused a bug in `KeystrokeLabel`, which used the `keystrokes_for_action`
method to query its ancestors to determine their type id and keymap context.

Now, any time a view notifies, we will cache its keymap context so that
we don't need to query the parent view during `layout`.
This commit is contained in:
Antonio Scandurra 2023-05-04 10:35:13 +02:00
parent 053b34875b
commit 18e39ef2fa
2 changed files with 38 additions and 17 deletions

View file

@ -440,6 +440,7 @@ type WindowShouldCloseSubscriptionCallback = Box<dyn FnMut(&mut AppContext) -> b
pub struct AppContext {
models: HashMap<usize, Box<dyn AnyModel>>,
views: HashMap<(usize, usize), Box<dyn AnyView>>,
views_metadata: HashMap<(usize, usize), ViewMetadata>,
pub(crate) parents: HashMap<(usize, usize), ParentId>,
windows: HashMap<usize, Window>,
globals: HashMap<TypeId, Box<dyn Any>>,
@ -502,6 +503,7 @@ impl AppContext {
Self {
models: Default::default(),
views: Default::default(),
views_metadata: Default::default(),
parents: Default::default(),
windows: Default::default(),
globals: Default::default(),
@ -727,9 +729,9 @@ impl AppContext {
}
pub fn view_type_id(&self, window_id: usize, view_id: usize) -> Option<TypeId> {
self.views
self.views_metadata
.get(&(window_id, view_id))
.map(|view| view.as_any().type_id())
.map(|metadata| metadata.type_id)
}
pub fn active_labeled_tasks<'a>(
@ -1045,9 +1047,10 @@ impl AppContext {
.read_window(window_id, |cx| {
if let Some(focused_view_id) = cx.focused_view_id() {
for view_id in cx.ancestors(focused_view_id) {
if let Some(view) = cx.views.get(&(window_id, view_id)) {
let view_type = view.as_any().type_id();
if let Some(actions) = cx.actions.get(&view_type) {
if let Some(view_metadata) =
cx.views_metadata.get(&(window_id, view_id))
{
if let Some(actions) = cx.actions.get(&view_metadata.type_id) {
if actions.contains_key(&action_type) {
return true;
}
@ -1448,6 +1451,7 @@ impl AppContext {
for (window_id, view_id) in dropped_views {
self.subscriptions.remove(view_id);
self.observations.remove(view_id);
self.views_metadata.remove(&(window_id, view_id));
let mut view = self.views.remove(&(window_id, view_id)).unwrap();
view.release(self);
let change_focus_to = self.windows.get_mut(&window_id).and_then(|window| {
@ -1779,9 +1783,11 @@ impl AppContext {
observed_window_id: usize,
observed_view_id: usize,
) {
if self
let view_key = (observed_window_id, observed_view_id);
if let Some((view, mut view_metadata)) = self
.views
.contains_key(&(observed_window_id, observed_view_id))
.remove(&view_key)
.zip(self.views_metadata.remove(&view_key))
{
if let Some(window) = self.windows.get_mut(&observed_window_id) {
window
@ -1791,6 +1797,10 @@ impl AppContext {
.insert(observed_view_id);
}
view_metadata.keymap_context = view.keymap_context(self);
self.views.insert(view_key, view);
self.views_metadata.insert(view_key, view_metadata);
let mut observations = self.observations.clone();
observations.emit(observed_view_id, |callback| callback(self));
}
@ -2037,6 +2047,11 @@ pub enum ParentId {
Root,
}
struct ViewMetadata {
type_id: TypeId,
keymap_context: KeymapContext,
}
#[derive(Default, Clone)]
pub struct WindowInvalidation {
pub updated: HashSet<usize>,
@ -2437,11 +2452,10 @@ where
cx.handle().into_any()
} else {
let focused_type = cx
.views
.views_metadata
.get(&(cx.window_id, focused_id))
.unwrap()
.as_any()
.type_id();
.type_id;
AnyViewHandle::new(
cx.window_id,
focused_id,
@ -2458,11 +2472,10 @@ where
cx.handle().into_any()
} else {
let blurred_type = cx
.views
.views_metadata
.get(&(cx.window_id, blurred_id))
.unwrap()
.as_any()
.type_id();
.type_id;
AnyViewHandle::new(
cx.window_id,
blurred_id,

View file

@ -34,7 +34,7 @@ use std::{
use util::ResultExt;
use uuid::Uuid;
use super::Reference;
use super::{Reference, ViewMetadata};
pub struct Window {
pub(crate) root_view: Option<AnyViewHandle>,
@ -369,13 +369,13 @@ impl<'a> WindowContext<'a> {
let mut contexts = Vec::new();
let mut handler_depth = None;
for (i, view_id) in self.ancestors(view_id).enumerate() {
if let Some(view) = self.views.get(&(window_id, view_id)) {
if let Some(actions) = self.actions.get(&view.as_any().type_id()) {
if let Some(view_metadata) = self.views_metadata.get(&(window_id, view_id)) {
if let Some(actions) = self.actions.get(&view_metadata.type_id) {
if actions.contains_key(&action.as_any().type_id()) {
handler_depth = Some(i);
}
}
contexts.push(view.keymap_context(self));
contexts.push(view_metadata.keymap_context.clone());
}
}
@ -1177,6 +1177,14 @@ impl<'a> WindowContext<'a> {
self.parents.insert((window_id, view_id), parent_id);
let mut cx = ViewContext::mutable(self, view_id);
let handle = if let Some(view) = build_view(&mut cx) {
let keymap_context = view.keymap_context(cx.app_context());
self.views_metadata.insert(
(window_id, view_id),
ViewMetadata {
type_id: TypeId::of::<T>(),
keymap_context,
},
);
self.views.insert((window_id, view_id), Box::new(view));
self.window
.invalidation