Restructure action macro to assign a namespace to every action

Also, allow arbitrary types to be used as Actions via the impl_actions macro

Co-authored-by: Nathan Sobo <nathan@zed.dev>
Co-authored-by: Keith Simmons <keith@zed.dev>
This commit is contained in:
Max Brunsfeld
2022-04-07 16:20:49 -07:00
co-authored by Nathan Sobo Keith Simmons
parent 206b0f0f8c
commit 5242a3a6dc
33 changed files with 432 additions and 306 deletions
+19 -93
View File
@@ -1,3 +1,5 @@
pub mod action;
use crate::{
elements::ElementBox,
executor::{self, Task},
@@ -7,6 +9,7 @@ use crate::{
util::post_inc,
AssetCache, AssetSource, ClipboardItem, FontCache, PathPromptOptions, TextLayoutCache,
};
pub use action::*;
use anyhow::{anyhow, Result};
use collections::btree_map;
use keymap::MatchResult;
@@ -142,89 +145,6 @@ pub trait ElementStateContext: DerefMut<Target = MutableAppContext> {
}
}
pub trait Action: 'static + AnyAction {
type Argument: 'static + Clone;
}
pub trait AnyAction {
fn id(&self) -> TypeId;
fn name(&self) -> &'static str;
fn as_any(&self) -> &dyn Any;
fn boxed_clone(&self) -> Box<dyn AnyAction>;
fn boxed_clone_as_any(&self) -> Box<dyn Any>;
}
#[macro_export]
macro_rules! action {
($name:ident, $arg:ty) => {
#[derive(Clone)]
pub struct $name(pub $arg);
impl $crate::Action for $name {
type Argument = $arg;
}
impl $crate::AnyAction for $name {
fn id(&self) -> std::any::TypeId {
std::any::TypeId::of::<$name>()
}
fn name(&self) -> &'static str {
stringify!($name)
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn boxed_clone(&self) -> Box<dyn $crate::AnyAction> {
Box::new(self.clone())
}
fn boxed_clone_as_any(&self) -> Box<dyn std::any::Any> {
Box::new(self.clone())
}
}
impl From<$arg> for $name {
fn from(arg: $arg) -> Self {
Self(arg)
}
}
};
($name:ident) => {
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct $name;
impl $crate::Action for $name {
type Argument = ();
}
impl $crate::AnyAction for $name {
fn id(&self) -> std::any::TypeId {
std::any::TypeId::of::<$name>()
}
fn name(&self) -> &'static str {
stringify!($name)
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn boxed_clone(&self) -> Box<dyn $crate::AnyAction> {
Box::new(self.clone())
}
fn boxed_clone_as_any(&self) -> Box<dyn std::any::Any> {
Box::new(self.clone())
}
}
};
}
pub struct Menu<'a> {
pub name: &'a str,
pub items: Vec<MenuItem<'a>>,
@@ -234,7 +154,7 @@ pub enum MenuItem<'a> {
Action {
name: &'a str,
keystroke: Option<&'a str>,
action: Box<dyn AnyAction>,
action: Box<dyn Action>,
},
Separator,
}
@@ -787,8 +707,8 @@ impl ReadViewWith for TestAppContext {
}
type ActionCallback =
dyn FnMut(&mut dyn AnyView, &dyn AnyAction, &mut MutableAppContext, usize, usize);
type GlobalActionCallback = dyn FnMut(&dyn AnyAction, &mut MutableAppContext);
dyn FnMut(&mut dyn AnyView, &dyn Action, &mut MutableAppContext, usize, usize);
type GlobalActionCallback = dyn FnMut(&dyn Action, &mut MutableAppContext);
type SubscriptionCallback = Box<dyn FnMut(&dyn Any, &mut MutableAppContext) -> bool>;
type GlobalSubscriptionCallback = Box<dyn FnMut(&dyn Any, &mut MutableAppContext)>;
@@ -963,7 +883,7 @@ impl MutableAppContext {
{
let handler = Box::new(
move |view: &mut dyn AnyView,
action: &dyn AnyAction,
action: &dyn Action,
cx: &mut MutableAppContext,
window_id: usize,
view_id: usize| {
@@ -1009,7 +929,7 @@ impl MutableAppContext {
A: Action,
F: 'static + FnMut(&A, &mut MutableAppContext),
{
let handler = Box::new(move |action: &dyn AnyAction, cx: &mut MutableAppContext| {
let handler = Box::new(move |action: &dyn Action, cx: &mut MutableAppContext| {
let action = action.as_any().downcast_ref().unwrap();
handler(action, cx);
});
@@ -1338,7 +1258,7 @@ impl MutableAppContext {
&mut self,
window_id: usize,
path: &[usize],
action: &dyn AnyAction,
action: &dyn Action,
) -> bool {
self.update(|this| {
this.halt_action_dispatch = false;
@@ -1398,7 +1318,7 @@ impl MutableAppContext {
self.dispatch_global_action_any(&action);
}
fn dispatch_global_action_any(&mut self, action: &dyn AnyAction) -> bool {
fn dispatch_global_action_any(&mut self, action: &dyn Action) -> bool {
self.update(|this| {
if let Some((name, mut handler)) = this.global_actions.remove_entry(&action.id()) {
handler(action, this);
@@ -4655,7 +4575,7 @@ impl RefCounts {
#[cfg(test)]
mod tests {
use super::*;
use crate::elements::*;
use crate::{elements::*, impl_actions};
use smol::future::poll_once;
use std::{
cell::Cell,
@@ -5801,7 +5721,10 @@ mod tests {
}
}
action!(Action, &'static str);
#[derive(Clone)]
pub struct Action(pub &'static str);
impl_actions!(test, [Action]);
let actions = Rc::new(RefCell::new(Vec::new()));
@@ -5909,7 +5832,10 @@ mod tests {
#[crate::test(self)]
fn test_dispatch_keystroke(cx: &mut MutableAppContext) {
action!(Action, &'static str);
#[derive(Clone)]
pub struct Action(pub &'static str);
impl_actions!(test, [Action]);
struct View {
id: usize,
+56
View File
@@ -0,0 +1,56 @@
use std::any::{Any, TypeId};
pub trait Action: 'static {
fn id(&self) -> TypeId;
fn namespace(&self) -> &'static str;
fn name(&self) -> &'static str;
fn as_any(&self) -> &dyn Any;
fn boxed_clone(&self) -> Box<dyn Action>;
fn boxed_clone_as_any(&self) -> Box<dyn Any>;
}
#[macro_export]
macro_rules! impl_actions {
($namespace:path, [ $($name:ident),* $(,)? ]) => {
$(
impl $crate::action::Action for $name {
fn id(&self) -> std::any::TypeId {
std::any::TypeId::of::<$name>()
}
fn namespace(&self) -> &'static str {
stringify!($namespace)
}
fn name(&self) -> &'static str {
stringify!($name)
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn boxed_clone(&self) -> Box<dyn $crate::action::Action> {
Box::new(self.clone())
}
fn boxed_clone_as_any(&self) -> Box<dyn std::any::Any> {
Box::new(self.clone())
}
}
)*
};
}
#[macro_export]
macro_rules! actions {
($namespace:path, [ $($name:ident),* $(,)? ]) => {
$(
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct $name;
)*
$crate::impl_actions!($namespace, [ $($name),* ]);
};
}
+8 -8
View File
@@ -1,3 +1,4 @@
use crate::Action;
use anyhow::anyhow;
use std::{
any::Any,
@@ -6,8 +7,6 @@ use std::{
};
use tree_sitter::{Language, Node, Parser};
use crate::{Action, AnyAction};
extern "C" {
fn tree_sitter_context_predicate() -> Language;
}
@@ -28,7 +27,7 @@ pub struct Keymap(Vec<Binding>);
pub struct Binding {
keystrokes: Vec<Keystroke>,
action: Box<dyn AnyAction>,
action: Box<dyn Action>,
context: Option<ContextPredicate>,
}
@@ -73,7 +72,7 @@ where
pub enum MatchResult {
None,
Pending,
Action(Box<dyn AnyAction>),
Action(Box<dyn Action>),
}
impl Debug for MatchResult {
@@ -329,7 +328,7 @@ impl ContextPredicate {
#[cfg(test)]
mod tests {
use crate::action;
use crate::{actions, impl_actions};
use super::*;
@@ -420,9 +419,10 @@ mod tests {
#[test]
fn test_matcher() -> anyhow::Result<()> {
action!(A, &'static str);
action!(B);
action!(Ab);
#[derive(Clone)]
pub struct A(pub &'static str);
impl_actions!(test, [A]);
actions!(test, [B, Ab]);
impl PartialEq for A {
fn eq(&self, other: &Self) -> bool {
+2 -2
View File
@@ -15,7 +15,7 @@ use crate::{
vector::Vector2F,
},
text_layout::{LineLayout, RunStyle},
AnyAction, ClipboardItem, Menu, Scene,
Action, ClipboardItem, Menu, Scene,
};
use anyhow::Result;
use async_task::Runnable;
@@ -66,7 +66,7 @@ pub(crate) trait ForegroundPlatform {
fn on_open_files(&self, callback: Box<dyn FnMut(Vec<PathBuf>)>);
fn run(&self, on_finish_launching: Box<dyn FnOnce() -> ()>);
fn on_menu_command(&self, callback: Box<dyn FnMut(&dyn AnyAction)>);
fn on_menu_command(&self, callback: Box<dyn FnMut(&dyn Action)>);
fn set_menus(&self, menus: Vec<Menu>);
fn prompt_for_paths(
&self,
+4 -4
View File
@@ -3,7 +3,7 @@ use crate::{
executor,
keymap::Keystroke,
platform::{self, CursorStyle},
AnyAction, ClipboardItem, Event, Menu, MenuItem,
Action, ClipboardItem, Event, Menu, MenuItem,
};
use anyhow::{anyhow, Result};
use block::ConcreteBlock;
@@ -107,10 +107,10 @@ pub struct MacForegroundPlatformState {
resign_active: Option<Box<dyn FnMut()>>,
quit: Option<Box<dyn FnMut()>>,
event: Option<Box<dyn FnMut(crate::Event) -> bool>>,
menu_command: Option<Box<dyn FnMut(&dyn AnyAction)>>,
menu_command: Option<Box<dyn FnMut(&dyn Action)>>,
open_files: Option<Box<dyn FnMut(Vec<PathBuf>)>>,
finish_launching: Option<Box<dyn FnOnce() -> ()>>,
menu_actions: Vec<Box<dyn AnyAction>>,
menu_actions: Vec<Box<dyn Action>>,
}
impl MacForegroundPlatform {
@@ -235,7 +235,7 @@ impl platform::ForegroundPlatform for MacForegroundPlatform {
}
}
fn on_menu_command(&self, callback: Box<dyn FnMut(&dyn AnyAction)>) {
fn on_menu_command(&self, callback: Box<dyn FnMut(&dyn Action)>) {
self.0.borrow_mut().menu_command = Some(callback);
}
+2 -2
View File
@@ -1,7 +1,7 @@
use super::{CursorStyle, WindowBounds};
use crate::{
geometry::vector::{vec2f, Vector2F},
AnyAction, ClipboardItem,
Action, ClipboardItem,
};
use anyhow::{anyhow, Result};
use parking_lot::Mutex;
@@ -72,7 +72,7 @@ impl super::ForegroundPlatform for ForegroundPlatform {
unimplemented!()
}
fn on_menu_command(&self, _: Box<dyn FnMut(&dyn AnyAction)>) {}
fn on_menu_command(&self, _: Box<dyn FnMut(&dyn Action)>) {}
fn set_menus(&self, _: Vec<crate::Menu>) {}
+2 -2
View File
@@ -6,7 +6,7 @@ use crate::{
json::{self, ToJson},
platform::Event,
text_layout::TextLayoutCache,
Action, AnyAction, AnyModelHandle, AnyViewHandle, AnyWeakModelHandle, AssetCache, ElementBox,
Action, AnyModelHandle, AnyViewHandle, AnyWeakModelHandle, AssetCache, ElementBox,
ElementStateContext, Entity, FontSystem, ModelHandle, ReadModel, ReadView, Scene,
UpgradeModelHandle, UpgradeViewHandle, View, ViewHandle, WeakModelHandle, WeakViewHandle,
};
@@ -223,7 +223,7 @@ impl Presenter {
pub struct DispatchDirective {
pub path: Vec<usize>,
pub action: Box<dyn AnyAction>,
pub action: Box<dyn Action>,
}
pub struct LayoutContext<'a> {
+7 -4
View File
@@ -1,6 +1,6 @@
use crate::{
action, elements::*, AppContext, Entity, MutableAppContext, RenderContext, View, ViewContext,
WeakViewHandle,
actions, elements::*, impl_actions, AppContext, Entity, MutableAppContext, RenderContext, View,
ViewContext, WeakViewHandle,
};
pub struct Select {
@@ -25,8 +25,11 @@ pub enum ItemType {
Unselected,
}
action!(ToggleSelect);
action!(SelectItem, usize);
#[derive(Clone)]
pub struct SelectItem(pub usize);
actions!(select, [ToggleSelect]);
impl_actions!(select, [SelectItem]);
pub enum Event {}