diff --git a/crates/client2/src/client2.rs b/crates/client2/src/client2.rs
index 6494e0350bb3fe48e0fc5a477537bec058ee95ed..4a1c5f321c375a097a89252830bd17c572d0c648 100644
--- a/crates/client2/src/client2.rs
+++ b/crates/client2/src/client2.rs
@@ -15,8 +15,8 @@ use futures::{
TryStreamExt,
};
use gpui::{
- serde_json, AnyModel, AnyWeakModel, AppContext, AsyncAppContext, Model, SemanticVersion, Task,
- WeakModel,
+ actions, serde_json, AnyModel, AnyWeakModel, AppContext, AsyncAppContext, Model,
+ SemanticVersion, Task, WeakModel,
};
use lazy_static::lazy_static;
use parking_lot::RwLock;
@@ -70,14 +70,7 @@ pub const ZED_SECRET_CLIENT_TOKEN: &str = "618033988749894";
pub const INITIAL_RECONNECTION_DELAY: Duration = Duration::from_millis(100);
pub const CONNECTION_TIMEOUT: Duration = Duration::from_secs(5);
-#[derive(Clone, Default, PartialEq, Deserialize)]
-pub struct SignIn;
-
-#[derive(Clone, Default, PartialEq, Deserialize)]
-pub struct SignOut;
-
-#[derive(Clone, Default, PartialEq, Deserialize)]
-pub struct Reconnect;
+actions!(SignIn, SignOut, Reconnect);
pub fn init_settings(cx: &mut AppContext) {
TelemetrySettings::register(cx);
diff --git a/crates/gpui2/src/action.rs b/crates/gpui2/src/action.rs
index 84843c98762572e591d76c774360fe48b21ee148..393a3feda6ba8a2a3ef1317f715ee08c8e12227e 100644
--- a/crates/gpui2/src/action.rs
+++ b/crates/gpui2/src/action.rs
@@ -4,7 +4,7 @@ use collections::{HashMap, HashSet};
use serde::Deserialize;
use std::any::{type_name, Any};
-pub trait Action: 'static {
+pub trait Action: std::fmt::Debug + 'static {
fn qualified_name() -> SharedString
where
Self: Sized;
@@ -17,12 +17,39 @@ pub trait Action: 'static {
fn as_any(&self) -> &dyn Any;
}
+// actions defines structs that can be used as actions.
+#[macro_export]
+macro_rules! actions {
+ () => {};
+
+ ( $name:ident ) => {
+ #[derive(::std::clone::Clone, ::std::default::Default, ::std::fmt::Debug, ::std::cmp::PartialEq, $crate::serde::Deserialize)]
+ struct $name;
+ };
+
+ ( $name:ident { $($token:tt)* } ) => {
+ #[derive(::std::clone::Clone, ::std::default::Default, ::std::fmt::Debug, ::std::cmp::PartialEq, $crate::serde::Deserialize)]
+ struct $name { $($token)* }
+ };
+
+ ( $name:ident, $($rest:tt)* ) => {
+ actions!($name);
+ actions!($($rest)*);
+ };
+
+ ( $name:ident { $($token:tt)* }, $($rest:tt)* ) => {
+ actions!($name { $($token)* });
+ actions!($($rest)*);
+ };
+}
+
impl Action for A
where
- A: for<'a> Deserialize<'a> + PartialEq + Clone + Default + 'static,
+ A: for<'a> Deserialize<'a> + PartialEq + Clone + Default + std::fmt::Debug + 'static,
{
fn qualified_name() -> SharedString {
- type_name::().into()
+ // todo!() remove the 2 replacement when migration is done
+ type_name::().replace("2::", "::").into()
}
fn build(params: Option) -> Result>
@@ -292,6 +319,25 @@ mod tests {
use super::*;
use DispatchContextPredicate::*;
+ #[test]
+ fn test_actions_definition() {
+ {
+ actions!(A, B { field: i32 }, C, D, E, F {}, G);
+ }
+
+ {
+ actions!(
+ A,
+ B { field: i32 },
+ C,
+ D,
+ E,
+ F {},
+ G, // Don't wrap, test the trailing comma
+ );
+ }
+ }
+
#[test]
fn test_parse_context() {
let mut expected = DispatchContext::default();
diff --git a/crates/gpui2/src/gpui2.rs b/crates/gpui2/src/gpui2.rs
index 49cc3cebc23bf2d61f7615a02e48a77b7d11ba2a..348da17356dd3f48d1a507cfcb0c8d19a4413d2b 100644
--- a/crates/gpui2/src/gpui2.rs
+++ b/crates/gpui2/src/gpui2.rs
@@ -1,3 +1,4 @@
+#[macro_use]
mod action;
mod app;
mod assets;
diff --git a/crates/gpui2/src/interactive.rs b/crates/gpui2/src/interactive.rs
index c6506f388e560d6ab4cdc2c473f67b7b2b53b2a1..0725a10aca05ef01a39144982146d36167bc366c 100644
--- a/crates/gpui2/src/interactive.rs
+++ b/crates/gpui2/src/interactive.rs
@@ -1233,8 +1233,6 @@ pub type KeyListener = Box<
#[cfg(test)]
mod test {
- use serde_derive::Deserialize;
-
use crate::{
self as gpui, div, Div, FocusHandle, KeyBinding, Keystroke, ParentElement, Render,
StatefulInteraction, StatelessInteractive, TestAppContext, VisualContext,
@@ -1246,8 +1244,7 @@ mod test {
focus_handle: FocusHandle,
}
- #[derive(PartialEq, Clone, Default, Deserialize)]
- struct TestAction;
+ actions!(TestAction);
impl Render for TestView {
type Element = Div>;
diff --git a/crates/storybook2/src/stories/focus.rs b/crates/storybook2/src/stories/focus.rs
index 16c03f87d5421af9d9336e462692102c4cb632bb..0f580d0cbf171ef32b2c83465ad8601785304227 100644
--- a/crates/storybook2/src/stories/focus.rs
+++ b/crates/storybook2/src/stories/focus.rs
@@ -1,18 +1,10 @@
use gpui::{
- div, Div, FocusEnabled, Focusable, KeyBinding, ParentElement, Render, StatefulInteraction,
- StatelessInteractive, Styled, View, VisualContext, WindowContext,
+ actions, div, Div, FocusEnabled, Focusable, KeyBinding, ParentElement, Render,
+ StatefulInteraction, StatelessInteractive, Styled, View, VisualContext, WindowContext,
};
-use serde::Deserialize;
use theme2::ActiveTheme;
-#[derive(Clone, Default, PartialEq, Deserialize)]
-struct ActionA;
-
-#[derive(Clone, Default, PartialEq, Deserialize)]
-struct ActionB;
-
-#[derive(Clone, Default, PartialEq, Deserialize)]
-struct ActionC;
+actions!(ActionA, ActionB, ActionC);
pub struct FocusStory {}