This commit is contained in:
Nathan Sobo
2023-11-07 20:23:02 -07:00
parent 4bf3a4e3d4
commit 80630cd4d9
5 changed files with 93 additions and 0 deletions
+24
View File
@@ -1,6 +1,8 @@
use crate::SharedString;
use anyhow::{anyhow, Context, Result};
use collections::{HashMap, HashSet};
use ctor::ctor;
use parking_lot::Mutex;
use serde::Deserialize;
use std::any::{type_name, Any};
@@ -17,17 +19,38 @@ pub trait Action: std::fmt::Debug + 'static {
fn as_any(&self) -> &dyn Any;
}
type ActionBuilder = fn(json: Option<serde_json::Value>) -> anyhow::Result<Box<dyn Action>>;
#[ctor]
static ACTION_BUILDERS: Mutex<HashMap<SharedString, ActionBuilder>> = Mutex::default();
/// Register an action type to allow it to be referenced in keymaps.
pub fn register_action<A: Action>() {
ACTION_BUILDERS.lock().insert(A::qualified_name(), A::build);
}
/// Construct an action based on its name and optional JSON parameters sourced from the keymap.
pub fn build_action(name: &str, params: Option<serde_json::Value>) -> Result<Box<dyn Action>> {
let lock = &ACTION_BUILDERS.lock();
let build_action = lock
.get(name)
.ok_or_else(|| anyhow!("no action type registered for {}", name))?;
(build_action)(params)
}
// actions defines structs that can be used as actions.
#[macro_export]
macro_rules! actions {
() => {};
( $name:ident ) => {
#[gpui::register_action]
#[derive(::std::clone::Clone, ::std::default::Default, ::std::fmt::Debug, ::std::cmp::PartialEq, $crate::serde::Deserialize)]
pub struct $name;
};
( $name:ident { $($token:tt)* } ) => {
#[gpui::register_action]
#[derive(::std::clone::Clone, ::std::default::Default, ::std::fmt::Debug, ::std::cmp::PartialEq, $crate::serde::Deserialize)]
pub struct $name { $($token)* }
};
@@ -317,6 +340,7 @@ fn skip_whitespace(source: &str) -> &str {
#[cfg(test)]
mod tests {
use super::*;
use crate as gpui;
use DispatchContextPredicate::*;
#[test]
+1
View File
@@ -36,6 +36,7 @@ pub use anyhow::Result;
pub use app::*;
pub use assets::*;
pub use color::*;
pub use ctor::ctor;
pub use element::*;
pub use elements::*;
pub use executor::*;
+30
View File
@@ -0,0 +1,30 @@
// Input:
//
// #[action]
// struct Foo {}
// Output:
//
// #[gpui::register_action]
// #[derive(gpui::serde::Deserialize, std::cmp::PartialEq, std::clone::Clone, std::default::Default, std::fmt::Debug)]
// struct Foo {}
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput};
pub fn action(_attr: TokenStream, item: TokenStream) -> TokenStream {
let input = parse_macro_input!(item as DeriveInput);
let name = &input.ident;
let data = &input.data;
let data_tokens = quote! { #data }.into();
let expanded = quote! {
#[gpui::register_action]
#[derive(gpui::serde::Deserialize, std::cmp::PartialEq, std::clone::Clone, std::default::Default, std::fmt::Debug)]
struct #name { #data }
};
TokenStream::from(expanded)
}
+6
View File
@@ -1,6 +1,7 @@
use proc_macro::TokenStream;
mod derive_component;
mod register_action;
mod style_helpers;
mod test;
@@ -9,6 +10,11 @@ pub fn style_helpers(args: TokenStream) -> TokenStream {
style_helpers::style_helpers(args)
}
#[proc_macro_attribute]
pub fn register_action(attr: TokenStream, item: TokenStream) -> TokenStream {
register_action::register_action(attr, item)
}
#[proc_macro_derive(Component, attributes(component))]
pub fn derive_component(input: TokenStream) -> TokenStream {
derive_component::derive_component(input)
@@ -0,0 +1,32 @@
// Input:
//
// struct Foo {}
// Output:
//
// struct Foo {}
//
// #[allow(non_snake_case)]
// #[gpui2::ctor]
// fn register_Foo_builder() {
// gpui2::register_action_builder::<Foo>()
// }
use proc_macro::TokenStream;
use quote::{format_ident, quote};
use syn::{parse_macro_input, DeriveInput};
pub fn register_action(_attr: TokenStream, item: TokenStream) -> TokenStream {
let input = parse_macro_input!(item as DeriveInput);
let type_name = &input.ident;
let ctor_fn_name = format_ident!("register_{}_builder", type_name);
let expanded = quote! {
#input
#[allow(non_snake_case)]
#[gpui::ctor]
fn #ctor_fn_name() {
gpui::register_action::<#type_name>()
}
};
TokenStream::from(expanded)
}