derive_visual_context.rs

 1use proc_macro::TokenStream;
 2use quote::quote;
 3use syn::{DeriveInput, parse_macro_input};
 4
 5use super::get_simple_attribute_field;
 6
 7pub fn derive_visual_context(input: TokenStream) -> TokenStream {
 8    let ast = parse_macro_input!(input as DeriveInput);
 9
10    let Some(window_variable) = get_simple_attribute_field(&ast, "window") else {
11        return quote! {
12            compile_error!("Derive must have a #[window] attribute to detect the &mut Window field");
13        }
14        .into();
15    };
16
17    let Some(app_variable) = get_simple_attribute_field(&ast, "app") else {
18        return quote! {
19            compile_error!("Derive must have a #[app] attribute to detect the &mut App field");
20        }
21        .into();
22    };
23
24    let type_name = &ast.ident;
25    let (impl_generics, type_generics, where_clause) = ast.generics.split_for_impl();
26
27    let r#gen = quote! {
28        impl #impl_generics gpui::VisualContext for #type_name #type_generics
29        #where_clause
30        {
31            fn window_handle(&self) -> gpui::AnyWindowHandle {
32                self.#window_variable.window_handle()
33            }
34
35            fn update_window_entity<T: 'static, R>(
36                &mut self,
37                entity: &gpui::Entity<T>,
38                update: impl FnOnce(&mut T, &mut gpui::Window, &mut gpui::Context<T>) -> R,
39            ) -> Self::Result<R> {
40                gpui::AppContext::update_entity(self.#app_variable, entity, |entity, cx| update(entity, self.#window_variable, cx))
41            }
42
43            fn new_window_entity<T: 'static>(
44                &mut self,
45                build_entity: impl FnOnce(&mut gpui::Window, &mut gpui::Context<'_, T>) -> T,
46            ) -> Self::Result<gpui::Entity<T>> {
47                gpui::AppContext::new(self.#app_variable, |cx| build_entity(self.#window_variable, cx))
48            }
49
50            fn replace_root_view<V>(
51                &mut self,
52                build_view: impl FnOnce(&mut gpui::Window, &mut gpui::Context<V>) -> V,
53            ) -> Self::Result<gpui::Entity<V>>
54            where
55                V: 'static + gpui::Render,
56            {
57                self.#window_variable.replace_root(self.#app_variable, build_view)
58            }
59
60            fn focus<V>(&mut self, entity: &gpui::Entity<V>) -> Self::Result<()>
61            where
62                V: gpui::Focusable,
63            {
64                let focus_handle = gpui::Focusable::focus_handle(entity, self.#app_variable);
65                self.#window_variable.focus(&focus_handle)
66            }
67        }
68    };
69
70    r#gen.into()
71}