Merge branch 'main' into implicit-ancestry

This commit is contained in:
Antonio Scandurra 2023-05-04 14:39:58 +02:00
commit da19edc3e3
33 changed files with 746 additions and 392 deletions

View file

@ -84,14 +84,15 @@ pub trait View: Entity + Sized {
false
}
fn keymap_context(&self, _: &AppContext) -> keymap_matcher::KeymapContext {
Self::default_keymap_context()
fn update_keymap_context(&self, keymap: &mut keymap_matcher::KeymapContext, _: &AppContext) {
Self::reset_to_default_keymap_context(keymap);
}
fn default_keymap_context() -> keymap_matcher::KeymapContext {
let mut cx = keymap_matcher::KeymapContext::default();
cx.add_identifier(Self::ui_name());
cx
fn reset_to_default_keymap_context(keymap: &mut keymap_matcher::KeymapContext) {
keymap.clear();
keymap.add_identifier(Self::ui_name());
}
fn debug_json(&self, _: &AppContext) -> serde_json::Value {
serde_json::Value::Null
}
@ -450,6 +451,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>,
windows: HashMap<usize, Window>,
globals: HashMap<TypeId, Box<dyn Any>>,
element_states: HashMap<ElementStateId, Box<dyn Any>>,
@ -511,6 +513,7 @@ impl AppContext {
Self {
models: Default::default(),
views: Default::default(),
views_metadata: Default::default(),
windows: Default::default(),
globals: Default::default(),
element_states: Default::default(),
@ -735,9 +738,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>(
@ -1053,9 +1056,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;
}
@ -1444,6 +1448,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| {
@ -1775,9 +1780,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
@ -1787,6 +1794,10 @@ impl AppContext {
.insert(observed_view_id);
}
view.update_keymap_context(&mut view_metadata.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));
}
@ -2033,6 +2044,11 @@ pub enum ParentId {
Root,
}
struct ViewMetadata {
type_id: TypeId,
keymap_context: KeymapContext,
}
#[derive(Default, Clone)]
pub struct WindowInvalidation {
pub updated: HashSet<usize>,
@ -2361,7 +2377,7 @@ pub trait AnyView {
cx: &mut WindowContext,
view_id: usize,
) -> bool;
fn keymap_context(&self, cx: &AppContext) -> KeymapContext;
fn update_keymap_context(&self, keymap: &mut KeymapContext, cx: &AppContext);
fn debug_json(&self, cx: &WindowContext) -> serde_json::Value;
fn text_for_range(&self, range: Range<usize>, cx: &WindowContext) -> Option<String>;
@ -2433,11 +2449,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,
@ -2454,11 +2469,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,
@ -2489,8 +2503,8 @@ where
View::modifiers_changed(self, event, &mut cx)
}
fn keymap_context(&self, cx: &AppContext) -> KeymapContext {
View::keymap_context(self, cx)
fn update_keymap_context(&self, keymap: &mut KeymapContext, cx: &AppContext) {
View::update_keymap_context(self, keymap, cx)
}
fn debug_json(&self, cx: &WindowContext) -> serde_json::Value {
@ -3234,7 +3248,6 @@ impl<'a, 'b, 'c, V: View> LayoutContext<'a, 'b, 'c, V> {
/// Return keystrokes that would dispatch the given action on the given view.
pub(crate) fn keystrokes_for_action(
&mut self,
view: &V,
view_id: usize,
action: &dyn Action,
) -> Option<SmallVec<[Keystroke; 2]>> {
@ -3244,21 +3257,13 @@ impl<'a, 'b, 'c, V: View> LayoutContext<'a, 'b, 'c, V> {
let mut contexts = Vec::new();
let mut handler_depth = None;
for (i, view_id) in self.ancestors(view_id).enumerate() {
let view = if view_id == self.view_id {
Some(view as _)
} else {
self.views
.get(&(window_id, view_id))
.map(|view| view.as_ref())
};
if let Some(view) = view {
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());
}
}
@ -5687,8 +5692,8 @@ mod tests {
"View"
}
fn keymap_context(&self, _: &AppContext) -> KeymapContext {
self.keymap_context.clone()
fn update_keymap_context(&self, keymap: &mut KeymapContext, _: &AppContext) {
*keymap = self.keymap_context.clone();
}
}
@ -5852,52 +5857,51 @@ mod tests {
});
let view_1_id = view_1.id();
view_1.update(cx, |view_1, cx| {
// Sanity check
let mut new_parents = Default::default();
let mut notify_views_if_parents_change = Default::default();
let mut layout_cx = LayoutContext::new(
cx,
&mut new_parents,
&mut notify_views_if_parents_change,
false,
);
assert_eq!(
layout_cx
.keystrokes_for_action(view_1, view_1_id, &Action1)
.unwrap()
.as_slice(),
&[Keystroke::parse("a").unwrap()]
);
assert_eq!(
layout_cx
.keystrokes_for_action(view_1, view_2.id(), &Action2)
.unwrap()
.as_slice(),
&[Keystroke::parse("b").unwrap()]
);
view_1.update(cx, |_, cx| {
view_2.update(cx, |_, cx| {
// Sanity check
let mut new_parents = Default::default();
let mut notify_views_if_parents_change = Default::default();
let mut layout_cx = LayoutContext::new(
cx,
&mut new_parents,
&mut notify_views_if_parents_change,
false,
);
assert_eq!(
layout_cx
.keystrokes_for_action(view_1_id, &Action1)
.unwrap()
.as_slice(),
&[Keystroke::parse("a").unwrap()]
);
assert_eq!(
layout_cx
.keystrokes_for_action(view_2.id(), &Action2)
.unwrap()
.as_slice(),
&[Keystroke::parse("b").unwrap()]
);
// The 'a' keystroke propagates up the view tree from view_2
// to view_1. The action, Action1, is handled by view_1.
assert_eq!(
layout_cx
.keystrokes_for_action(view_1, view_2.id(), &Action1)
.unwrap()
.as_slice(),
&[Keystroke::parse("a").unwrap()]
);
// The 'a' keystroke propagates up the view tree from view_2
// to view_1. The action, Action1, is handled by view_1.
assert_eq!(
layout_cx
.keystrokes_for_action(view_2.id(), &Action1)
.unwrap()
.as_slice(),
&[Keystroke::parse("a").unwrap()]
);
// Actions that are handled below the current view don't have bindings
assert_eq!(
layout_cx.keystrokes_for_action(view_1, view_1_id, &Action2),
None
);
// Actions that are handled below the current view don't have bindings
assert_eq!(layout_cx.keystrokes_for_action(view_1_id, &Action2), None);
// Actions that are handled in other branches of the tree should not have a binding
assert_eq!(
layout_cx.keystrokes_for_action(view_1, view_2.id(), &GlobalAction),
None
);
// Actions that are handled in other branches of the tree should not have a binding
assert_eq!(
layout_cx.keystrokes_for_action(view_2.id(), &GlobalAction),
None
);
});
});
// Check that global actions do not have a binding, even if a binding does exist in another view