gpui: Make style macros more composable (#14007)

This PR begins the process of breaking up the `style_helpers!` macro
into smaller macros that can be used to generate methods for a related
subset of styles.

The style method macros also now accept an optional `visibility`
parameter to control the visibility of the generated methods. This
allows for adding these methods to a struct instead of a just a trait.

For example, to expose just the padding styles on a `Facepile` we can do
this:

```rs
impl Facepile {
    fn style(&mut self) -> &mut StyleRefinement {
        self.base.style()
    }

    gpui::padding_style_methods!({
        visibility: pub
    });
}
```

Release Notes:

- N/A
This commit is contained in:
Marshall Bowers 2024-07-09 13:52:52 -04:00 committed by GitHub
parent 8203b6875b
commit 3cdd465226
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 335 additions and 203 deletions

View file

@ -27,13 +27,34 @@ pub fn derive_render(input: TokenStream) -> TokenStream {
derive_render::derive_render(input)
}
/// Used by gpui to generate the style helpers.
/// Used by GPUI to generate the style helpers.
#[proc_macro]
#[doc(hidden)]
pub fn style_helpers(input: TokenStream) -> TokenStream {
style_helpers::style_helpers(input)
}
/// Generates methods for margin styles.
#[proc_macro]
#[doc(hidden)]
pub fn margin_style_methods(input: TokenStream) -> TokenStream {
style_helpers::margin_style_methods(input)
}
/// Generates methods for padding styles.
#[proc_macro]
#[doc(hidden)]
pub fn padding_style_methods(input: TokenStream) -> TokenStream {
style_helpers::padding_style_methods(input)
}
/// Generates methods for position styles.
#[proc_macro]
#[doc(hidden)]
pub fn position_style_methods(input: TokenStream) -> TokenStream {
style_helpers::position_style_methods(input)
}
/// #[gpui::test] can be used to annotate test functions that run with GPUI support.
/// it supports both synchronous and asynchronous tests, and can provide you with
/// as many `TestAppContext` instances as you need.

View file

@ -2,15 +2,38 @@ use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;
use quote::{format_ident, quote};
use syn::{
braced,
parse::{Parse, ParseStream, Result},
parse_macro_input,
parse_macro_input, Token, Visibility,
};
struct StyleableMacroInput;
#[derive(Debug)]
struct StyleableMacroInput {
method_visibility: Visibility,
}
impl Parse for StyleableMacroInput {
fn parse(_input: ParseStream) -> Result<Self> {
Ok(StyleableMacroInput)
fn parse(input: ParseStream) -> Result<Self> {
if !input.peek(syn::token::Brace) {
return Ok(Self {
method_visibility: Visibility::Inherited,
});
}
let content;
braced!(content in input);
let mut method_visibility = None;
let ident: syn::Ident = content.parse()?;
if ident == "visibility" {
let _colon: Token![:] = content.parse()?;
method_visibility = Some(content.parse()?);
}
Ok(Self {
method_visibility: method_visibility.unwrap_or(Visibility::Inherited),
})
}
}
@ -24,11 +47,110 @@ pub fn style_helpers(input: TokenStream) -> TokenStream {
output.into()
}
fn generate_methods() -> Vec<TokenStream2> {
pub fn margin_style_methods(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as StyleableMacroInput);
let methods = generate_box_style_methods(
margin_box_style_prefixes(),
box_style_suffixes(),
input.method_visibility,
);
let output = quote! {
#(#methods)*
};
output.into()
}
pub fn padding_style_methods(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as StyleableMacroInput);
let methods = generate_box_style_methods(
padding_box_style_prefixes(),
box_style_suffixes(),
input.method_visibility,
);
let output = quote! {
#(#methods)*
};
output.into()
}
pub fn position_style_methods(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as StyleableMacroInput);
let visibility = input.method_visibility;
let methods = generate_box_style_methods(
position_box_style_prefixes(),
box_style_suffixes(),
visibility.clone(),
);
let output = quote! {
/// Sets the position of the element to `relative`.
/// [Docs](https://tailwindcss.com/docs/position)
#visibility fn relative(mut self) -> Self {
self.style().position = Some(gpui::Position::Relative);
self
}
/// Sets the position of the element to `absolute`.
/// [Docs](https://tailwindcss.com/docs/position)
#visibility fn absolute(mut self) -> Self {
self.style().position = Some(gpui::Position::Absolute);
self
}
#(#methods)*
};
output.into()
}
struct BoxStylePrefix {
prefix: &'static str,
auto_allowed: bool,
fields: Vec<TokenStream2>,
doc_string_prefix: &'static str,
}
struct BoxStyleSuffix {
suffix: &'static str,
length_tokens: TokenStream2,
doc_string_suffix: &'static str,
}
struct CornerStylePrefix {
prefix: &'static str,
fields: Vec<TokenStream2>,
doc_string_prefix: &'static str,
}
struct CornerStyleSuffix {
suffix: &'static str,
radius_tokens: TokenStream2,
doc_string_suffix: &'static str,
}
struct BorderStylePrefix {
prefix: &'static str,
fields: Vec<TokenStream2>,
doc_string_prefix: &'static str,
}
struct BorderStyleSuffix {
suffix: &'static str,
width_tokens: TokenStream2,
doc_string_suffix: &'static str,
}
fn generate_box_style_methods(
prefixes: Vec<BoxStylePrefix>,
suffixes: Vec<BoxStyleSuffix>,
visibility: Visibility,
) -> Vec<TokenStream2> {
let mut methods = Vec::new();
for box_style_prefix in box_prefixes() {
for box_style_prefix in prefixes {
methods.push(generate_custom_value_setter(
visibility.clone(),
box_style_prefix.prefix,
if box_style_prefix.auto_allowed {
quote! { Length }
@ -39,9 +161,10 @@ fn generate_methods() -> Vec<TokenStream2> {
&box_style_prefix.doc_string_prefix,
));
for box_style_suffix in box_suffixes() {
for box_style_suffix in &suffixes {
if box_style_suffix.suffix != "auto" || box_style_prefix.auto_allowed {
methods.push(generate_predefined_setter(
visibility.clone(),
box_style_prefix.prefix,
box_style_suffix.suffix,
&box_style_prefix.fields,
@ -57,6 +180,7 @@ fn generate_methods() -> Vec<TokenStream2> {
if box_style_suffix.suffix != "auto" {
methods.push(generate_predefined_setter(
visibility.clone(),
box_style_prefix.prefix,
box_style_suffix.suffix,
&box_style_prefix.fields,
@ -72,8 +196,17 @@ fn generate_methods() -> Vec<TokenStream2> {
}
}
methods
}
fn generate_methods() -> Vec<TokenStream2> {
let visibility = Visibility::Inherited;
let mut methods =
generate_box_style_methods(box_prefixes(), box_style_suffixes(), visibility.clone());
for corner_style_prefix in corner_prefixes() {
methods.push(generate_custom_value_setter(
visibility.clone(),
corner_style_prefix.prefix,
quote! { AbsoluteLength },
&corner_style_prefix.fields,
@ -82,6 +215,7 @@ fn generate_methods() -> Vec<TokenStream2> {
for corner_style_suffix in corner_suffixes() {
methods.push(generate_predefined_setter(
visibility.clone(),
corner_style_prefix.prefix,
corner_style_suffix.suffix,
&corner_style_prefix.fields,
@ -98,6 +232,7 @@ fn generate_methods() -> Vec<TokenStream2> {
for border_style_prefix in border_prefixes() {
methods.push(generate_custom_value_setter(
visibility.clone(),
border_style_prefix.prefix,
quote! { AbsoluteLength },
&border_style_prefix.fields,
@ -106,6 +241,7 @@ fn generate_methods() -> Vec<TokenStream2> {
for border_style_suffix in border_suffixes() {
methods.push(generate_predefined_setter(
visibility.clone(),
border_style_prefix.prefix,
border_style_suffix.suffix,
&border_style_prefix.fields,
@ -123,6 +259,7 @@ fn generate_methods() -> Vec<TokenStream2> {
}
fn generate_predefined_setter(
visibility: Visibility,
name: &'static str,
length: &'static str,
fields: &[TokenStream2],
@ -153,7 +290,7 @@ fn generate_predefined_setter(
let method = quote! {
#[doc = #doc_string]
fn #method_name(mut self) -> Self {
#visibility fn #method_name(mut self) -> Self {
let style = self.style();
#(#field_assignments)*
self
@ -164,6 +301,7 @@ fn generate_predefined_setter(
}
fn generate_custom_value_setter(
visibility: Visibility,
prefix: &str,
length_type: TokenStream2,
fields: &[TokenStream2],
@ -186,7 +324,7 @@ fn generate_custom_value_setter(
let method = quote! {
#[doc = #doc_string]
fn #method_name(mut self, length: impl std::clone::Clone + Into<gpui::#length_type>) -> Self {
#visibility fn #method_name(mut self, length: impl std::clone::Clone + Into<gpui::#length_type>) -> Self {
let style = self.style();
#(#field_assignments)*
self
@ -196,11 +334,148 @@ fn generate_custom_value_setter(
method
}
struct BoxStylePrefix {
prefix: &'static str,
auto_allowed: bool,
fields: Vec<TokenStream2>,
doc_string_prefix: &'static str,
fn margin_box_style_prefixes() -> Vec<BoxStylePrefix> {
vec![
BoxStylePrefix {
prefix: "m",
auto_allowed: true,
fields: vec![
quote! { margin.top },
quote! { margin.bottom },
quote! { margin.left },
quote! { margin.right },
],
doc_string_prefix: "Sets the margin of the element. [Docs](https://tailwindcss.com/docs/margin)",
},
BoxStylePrefix {
prefix: "mt",
auto_allowed: true,
fields: vec![quote! { margin.top }],
doc_string_prefix: "Sets the top margin of the element. [Docs](https://tailwindcss.com/docs/margin#add-margin-to-a-single-side)",
},
BoxStylePrefix {
prefix: "mb",
auto_allowed: true,
fields: vec![quote! { margin.bottom }],
doc_string_prefix: "Sets the bottom margin of the element. [Docs](https://tailwindcss.com/docs/margin#add-margin-to-a-single-side)",
},
BoxStylePrefix {
prefix: "my",
auto_allowed: true,
fields: vec![quote! { margin.top }, quote! { margin.bottom }],
doc_string_prefix: "Sets the vertical margin of the element. [Docs](https://tailwindcss.com/docs/margin#add-vertical-margin)",
},
BoxStylePrefix {
prefix: "mx",
auto_allowed: true,
fields: vec![quote! { margin.left }, quote! { margin.right }],
doc_string_prefix: "Sets the horizontal margin of the element. [Docs](https://tailwindcss.com/docs/margin#add-horizontal-margin)",
},
BoxStylePrefix {
prefix: "ml",
auto_allowed: true,
fields: vec![quote! { margin.left }],
doc_string_prefix: "Sets the left margin of the element. [Docs](https://tailwindcss.com/docs/margin#add-margin-to-a-single-side)",
},
BoxStylePrefix {
prefix: "mr",
auto_allowed: true,
fields: vec![quote! { margin.right }],
doc_string_prefix: "Sets the right margin of the element. [Docs](https://tailwindcss.com/docs/margin#add-margin-to-a-single-side)",
},
]
}
fn padding_box_style_prefixes() -> Vec<BoxStylePrefix> {
vec![
BoxStylePrefix {
prefix: "p",
auto_allowed: false,
fields: vec![
quote! { padding.top },
quote! { padding.bottom },
quote! { padding.left },
quote! { padding.right },
],
doc_string_prefix: "Sets the padding of the element. [Docs](https://tailwindcss.com/docs/padding)",
},
BoxStylePrefix {
prefix: "pt",
auto_allowed: false,
fields: vec![quote! { padding.top }],
doc_string_prefix: "Sets the top padding of the element. [Docs](https://tailwindcss.com/docs/padding#add-padding-to-a-single-side)",
},
BoxStylePrefix {
prefix: "pb",
auto_allowed: false,
fields: vec![quote! { padding.bottom }],
doc_string_prefix: "Sets the bottom padding of the element. [Docs](https://tailwindcss.com/docs/padding#add-padding-to-a-single-side)",
},
BoxStylePrefix {
prefix: "px",
auto_allowed: false,
fields: vec![quote! { padding.left }, quote! { padding.right }],
doc_string_prefix: "Sets the horizontal padding of the element. [Docs](https://tailwindcss.com/docs/padding#add-horizontal-padding)",
},
BoxStylePrefix {
prefix: "py",
auto_allowed: false,
fields: vec![quote! { padding.top }, quote! { padding.bottom }],
doc_string_prefix: "Sets the vertical padding of the element. [Docs](https://tailwindcss.com/docs/padding#add-vertical-padding)",
},
BoxStylePrefix {
prefix: "pl",
auto_allowed: false,
fields: vec![quote! { padding.left }],
doc_string_prefix: "Sets the left padding of the element. [Docs](https://tailwindcss.com/docs/padding#add-padding-to-a-single-side)",
},
BoxStylePrefix {
prefix: "pr",
auto_allowed: false,
fields: vec![quote! { padding.right }],
doc_string_prefix: "Sets the right padding of the element. [Docs](https://tailwindcss.com/docs/padding#add-padding-to-a-single-side)",
},
]
}
fn position_box_style_prefixes() -> Vec<BoxStylePrefix> {
vec![
BoxStylePrefix {
prefix: "inset",
auto_allowed: true,
fields: vec![
quote! { inset.top },
quote! { inset.right },
quote! { inset.bottom },
quote! { inset.left },
],
doc_string_prefix: "Sets the top, right, bottom, and left values of a positioned element. [Docs](https://tailwindcss.com/docs/top-right-bottom-left)",
},
BoxStylePrefix {
prefix: "top",
auto_allowed: true,
fields: vec![quote! { inset.top }],
doc_string_prefix: "Sets the top value of a positioned element. [Docs](https://tailwindcss.com/docs/top-right-bottom-left)",
},
BoxStylePrefix {
prefix: "bottom",
auto_allowed: true,
fields: vec![quote! { inset.bottom }],
doc_string_prefix: "Sets the bottom value of a positioned element. [Docs](https://tailwindcss.com/docs/top-right-bottom-left)",
},
BoxStylePrefix {
prefix: "left",
auto_allowed: true,
fields: vec![quote! { inset.left }],
doc_string_prefix: "Sets the left value of a positioned element. [Docs](https://tailwindcss.com/docs/top-right-bottom-left)",
},
BoxStylePrefix {
prefix: "right",
auto_allowed: true,
fields: vec![quote! { inset.right }],
doc_string_prefix: "Sets the right value of a positioned element. [Docs](https://tailwindcss.com/docs/top-right-bottom-left)",
},
]
}
fn box_prefixes() -> Vec<BoxStylePrefix> {
@ -255,135 +530,6 @@ fn box_prefixes() -> Vec<BoxStylePrefix> {
fields: vec![quote! { max_size.height }],
doc_string_prefix: "Sets the maximum height of the element. [Docs](https://tailwindcss.com/docs/max-height)",
},
BoxStylePrefix {
prefix: "m",
auto_allowed: true,
fields: vec![
quote! { margin.top },
quote! { margin.bottom },
quote! { margin.left },
quote! { margin.right },
],
doc_string_prefix: "Sets the margin of the element. [Docs](https://tailwindcss.com/docs/margin)",
},
BoxStylePrefix {
prefix: "mt",
auto_allowed: true,
fields: vec![quote! { margin.top }],
doc_string_prefix: "Sets the top margin of the element. [Docs](https://tailwindcss.com/docs/margin#add-margin-to-a-single-side)",
},
BoxStylePrefix {
prefix: "mb",
auto_allowed: true,
fields: vec![quote! { margin.bottom }],
doc_string_prefix: "Sets the bottom margin of the element. [Docs](https://tailwindcss.com/docs/margin#add-margin-to-a-single-side)",
},
BoxStylePrefix {
prefix: "my",
auto_allowed: true,
fields: vec![quote! { margin.top }, quote! { margin.bottom }],
doc_string_prefix: "Sets the vertical margin of the element. [Docs](https://tailwindcss.com/docs/margin#add-vertical-margin)",
},
BoxStylePrefix {
prefix: "mx",
auto_allowed: true,
fields: vec![quote! { margin.left }, quote! { margin.right }],
doc_string_prefix: "Sets the horizontal margin of the element. [Docs](https://tailwindcss.com/docs/margin#add-horizontal-margin)",
},
BoxStylePrefix {
prefix: "ml",
auto_allowed: true,
fields: vec![quote! { margin.left }],
doc_string_prefix: "Sets the left margin of the element. [Docs](https://tailwindcss.com/docs/margin#add-margin-to-a-single-side)",
},
BoxStylePrefix {
prefix: "mr",
auto_allowed: true,
fields: vec![quote! { margin.right }],
doc_string_prefix: "Sets the right margin of the element. [Docs](https://tailwindcss.com/docs/margin#add-margin-to-a-single-side)",
},
BoxStylePrefix {
prefix: "p",
auto_allowed: false,
fields: vec![
quote! { padding.top },
quote! { padding.bottom },
quote! { padding.left },
quote! { padding.right },
],
doc_string_prefix: "Sets the padding of the element. [Docs](https://tailwindcss.com/docs/padding)",
},
BoxStylePrefix {
prefix: "pt",
auto_allowed: false,
fields: vec![quote! { padding.top }],
doc_string_prefix: "Sets the top padding of the element. [Docs](https://tailwindcss.com/docs/padding#add-padding-to-a-single-side)",
},
BoxStylePrefix {
prefix: "pb",
auto_allowed: false,
fields: vec![quote! { padding.bottom }],
doc_string_prefix: "Sets the bottom padding of the element. [Docs](https://tailwindcss.com/docs/padding#add-padding-to-a-single-side)",
},
BoxStylePrefix {
prefix: "px",
auto_allowed: false,
fields: vec![quote! { padding.left }, quote! { padding.right }],
doc_string_prefix: "Sets the horizontal padding of the element. [Docs](https://tailwindcss.com/docs/padding#add-horizontal-padding)",
},
BoxStylePrefix {
prefix: "py",
auto_allowed: false,
fields: vec![quote! { padding.top }, quote! { padding.bottom }],
doc_string_prefix: "Sets the vertical padding of the element. [Docs](https://tailwindcss.com/docs/padding#add-vertical-padding)",
},
BoxStylePrefix {
prefix: "pl",
auto_allowed: false,
fields: vec![quote! { padding.left }],
doc_string_prefix: "Sets the left padding of the element. [Docs](https://tailwindcss.com/docs/padding#add-padding-to-a-single-side)",
},
BoxStylePrefix {
prefix: "pr",
auto_allowed: false,
fields: vec![quote! { padding.right }],
doc_string_prefix: "Sets the right padding of the element. [Docs](https://tailwindcss.com/docs/padding#add-padding-to-a-single-side)",
},
BoxStylePrefix {
prefix: "inset",
auto_allowed: true,
fields: vec![
quote! { inset.top },
quote! { inset.right },
quote! { inset.bottom },
quote! { inset.left },
],
doc_string_prefix: "Sets the top, right, bottom, and left values of a positioned element. [Docs](https://tailwindcss.com/docs/top-right-bottom-left)",
},
BoxStylePrefix {
prefix: "top",
auto_allowed: true,
fields: vec![quote! { inset.top }],
doc_string_prefix: "Sets the top value of a positioned element. [Docs](https://tailwindcss.com/docs/top-right-bottom-left)",
},
BoxStylePrefix {
prefix: "bottom",
auto_allowed: true,
fields: vec![quote! { inset.bottom }],
doc_string_prefix: "Sets the bottom value of a positioned element. [Docs](https://tailwindcss.com/docs/top-right-bottom-left)",
},
BoxStylePrefix {
prefix: "left",
auto_allowed: true,
fields: vec![quote! { inset.left }],
doc_string_prefix: "Sets the left value of a positioned element. [Docs](https://tailwindcss.com/docs/top-right-bottom-left)",
},
BoxStylePrefix {
prefix: "right",
auto_allowed: true,
fields: vec![quote! { inset.right }],
doc_string_prefix: "Sets the right value of a positioned element. [Docs](https://tailwindcss.com/docs/top-right-bottom-left)",
},
BoxStylePrefix {
prefix: "gap",
auto_allowed: false,
@ -405,13 +551,7 @@ fn box_prefixes() -> Vec<BoxStylePrefix> {
]
}
struct BoxStyleSuffix {
suffix: &'static str,
length_tokens: TokenStream2,
doc_string_suffix: &'static str,
}
fn box_suffixes() -> Vec<BoxStyleSuffix> {
fn box_style_suffixes() -> Vec<BoxStyleSuffix> {
vec![
BoxStyleSuffix {
suffix: "0",
@ -646,12 +786,6 @@ fn box_suffixes() -> Vec<BoxStyleSuffix> {
]
}
struct CornerStylePrefix {
prefix: &'static str,
fields: Vec<TokenStream2>,
doc_string_prefix: &'static str,
}
fn corner_prefixes() -> Vec<CornerStylePrefix> {
vec![
CornerStylePrefix {
@ -719,12 +853,6 @@ fn corner_prefixes() -> Vec<CornerStylePrefix> {
]
}
struct CornerStyleSuffix {
suffix: &'static str,
radius_tokens: TokenStream2,
doc_string_suffix: &'static str,
}
fn corner_suffixes() -> Vec<CornerStyleSuffix> {
vec![
CornerStyleSuffix {
@ -770,12 +898,6 @@ fn corner_suffixes() -> Vec<CornerStyleSuffix> {
]
}
struct BorderStylePrefix {
prefix: &'static str,
fields: Vec<TokenStream2>,
doc_string_prefix: &'static str,
}
fn border_prefixes() -> Vec<BorderStylePrefix> {
vec![
BorderStylePrefix {
@ -827,12 +949,6 @@ fn border_prefixes() -> Vec<BorderStylePrefix> {
]
}
struct BorderStyleSuffix {
suffix: &'static str,
width_tokens: TokenStream2,
doc_string_suffix: &'static str,
}
fn border_suffixes() -> Vec<BorderStyleSuffix> {
vec![
BorderStyleSuffix {