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}