WIP
This commit is contained in:
@@ -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]
|
||||
|
||||
@@ -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::*;
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
Reference in New Issue
Block a user