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            type Result<T> = T;
32
33            fn window_handle(&self) -> gpui::AnyWindowHandle {
34                self.#window_variable.window_handle()
35            }
36
37            fn update_window_entity<T: 'static, R>(
38                &mut self,
39                entity: &gpui::Entity<T>,
40                update: impl FnOnce(&mut T, &mut gpui::Window, &mut gpui::Context<T>) -> R,
41            ) -> R {
42                gpui::AppContext::update_entity(self.#app_variable, entity, |entity, cx| update(entity, self.#window_variable, cx))
43            }
44
45            fn new_window_entity<T: 'static>(
46                &mut self,
47                build_entity: impl FnOnce(&mut gpui::Window, &mut gpui::Context<'_, T>) -> T,
48            ) -> gpui::Entity<T> {
49                gpui::AppContext::new(self.#app_variable, |cx| build_entity(self.#window_variable, cx))
50            }
51
52            fn replace_root_view<V>(
53                &mut self,
54                build_view: impl FnOnce(&mut gpui::Window, &mut gpui::Context<V>) -> V,
55            ) -> gpui::Entity<V>
56            where
57                V: 'static + gpui::Render,
58            {
59                self.#window_variable.replace_root(self.#app_variable, build_view)
60            }
61
62            fn focus<V>(&mut self, entity: &gpui::Entity<V>)
63            where
64                V: gpui::Focusable,
65            {
66                let focus_handle = gpui::Focusable::focus_handle(entity, self.#app_variable);
67                self.#window_variable.focus(&focus_handle, self.#app_variable);
68            }
69        }
70    };
71
72    r#gen.into()
73}