diff --git a/crates/git_hosting_providers/src/settings.rs b/crates/git_hosting_providers/src/settings.rs index 76fd386d5b..07831ee390 100644 --- a/crates/git_hosting_providers/src/settings.rs +++ b/crates/git_hosting_providers/src/settings.rs @@ -5,7 +5,7 @@ use git::GitHostingProviderRegistry; use gpui::App; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use settings::{SettingsUI, Settings, SettingsStore}; +use settings::{Settings, SettingsStore, SettingsUI}; use url::Url; use util::ResultExt as _; diff --git a/crates/gpui_macros/src/derive_action.rs b/crates/gpui_macros/src/derive_action.rs index 9c7f97371d..4e6c6277e4 100644 --- a/crates/gpui_macros/src/derive_action.rs +++ b/crates/gpui_macros/src/derive_action.rs @@ -16,6 +16,13 @@ pub(crate) fn derive_action(input: TokenStream) -> TokenStream { let mut deprecated = None; let mut doc_str: Option = None; + /* + * + * #[action()] + * Struct Foo { + * bar: bool // is bar considered an attribute + } + */ for attr in &input.attrs { if attr.path().is_ident("action") { attr.parse_nested_meta(|meta| { diff --git a/crates/settings/src/settings_ui.rs b/crates/settings/src/settings_ui.rs index 5150e41cf0..e405c5bd8f 100644 --- a/crates/settings/src/settings_ui.rs +++ b/crates/settings/src/settings_ui.rs @@ -11,14 +11,20 @@ pub trait SettingsUI { } pub struct SettingsUIItem { - // TODO: - // path: SmallVec<[&'static str; 8]>, + // TODO: move this back here once there isn't a None variant + // pub path: &'static str, pub item: SettingsUIItemVariant, } pub enum SettingsUIItemVariant { - Group(SettingsUIItemGroup), - Item(SettingsUIItemSingle), + Group { + path: &'static str, + group: SettingsUIItemGroup, + }, + Item { + path: &'static str, + item: SettingsUIItemSingle, + }, // TODO: remove None, } diff --git a/crates/settings_ui_macros/src/settings_ui_macros.rs b/crates/settings_ui_macros/src/settings_ui_macros.rs index 099d5246c9..1f6f8fdd4f 100644 --- a/crates/settings_ui_macros/src/settings_ui_macros.rs +++ b/crates/settings_ui_macros/src/settings_ui_macros.rs @@ -1,6 +1,6 @@ use proc_macro::TokenStream; use quote::quote; -use syn::{DeriveInput, parse_macro_input}; +use syn::{DeriveInput, LitStr, Token, parse_macro_input}; /// Derive macro for the `SettingsUI` marker trait. /// @@ -15,12 +15,13 @@ use syn::{DeriveInput, parse_macro_input}; /// use settings_ui_macros::SettingsUI; /// /// #[derive(SettingsUI)] +/// #[settings_ui(group = "Standard")] /// struct MySettings { /// enabled: bool, /// count: usize, /// } /// ``` -#[proc_macro_derive(SettingsUI)] +#[proc_macro_derive(SettingsUI, attributes(settings_ui))] pub fn derive_settings_ui(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); let name = &input.ident; @@ -28,8 +29,41 @@ pub fn derive_settings_ui(input: TokenStream) -> TokenStream { // Handle generic parameters if present let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); + let mut group_name = Option::::None; + + for attr in &input.attrs { + if attr.path().is_ident("settings_ui") { + attr.parse_nested_meta(|meta| { + if meta.path.is_ident("group") { + if group_name.is_some() { + return Err(meta.error("Only one 'group' path can be specified")); + } + meta.input.parse::()?; + let lit: LitStr = meta.input.parse()?; + group_name = Some(lit.value()); + } + Ok(()) + }) + .unwrap_or_else(|e| panic!("in #[settings_ui] attribute: {}", e)); + } + } + + let ui_item_fn_body = if let Some(group_name) = group_name { + quote! { + settings::SettingsUIItem { item: settings::SettingsUIItemVariant::Group{ path: #group_name, group: settings::SettingsUIItemGroup{ items: Default::default() } } } + } + } else { + quote! { + settings::SettingsUIItem { item: settings::SettingsUIItemVariant::None } + } + }; + let expanded = quote! { - impl #impl_generics settings::SettingsUI for #name #ty_generics #where_clause {} + impl #impl_generics settings::SettingsUI for #name #ty_generics #where_clause { + fn ui_item() -> settings::SettingsUIItem { + #ui_item_fn_body + } + } }; TokenStream::from(expanded)