1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{DeriveInput, parse_macro_input};
4
5use crate::get_simple_attribute_field;
6
7pub fn derive_app_context(input: TokenStream) -> TokenStream {
8 let ast = parse_macro_input!(input as DeriveInput);
9
10 let Some(app_variable) = get_simple_attribute_field(&ast, "app") else {
11 return quote! {
12 compile_error!("Derive must have an #[app] attribute to detect the &mut App field");
13 }
14 .into();
15 };
16
17 let type_name = &ast.ident;
18 let (impl_generics, type_generics, where_clause) = ast.generics.split_for_impl();
19
20 let r#gen = quote! {
21 impl #impl_generics gpui::AppContext for #type_name #type_generics
22 #where_clause
23 {
24 fn new<T: 'static>(
25 &mut self,
26 build_entity: impl FnOnce(&mut gpui::Context<'_, T>) -> T,
27 ) -> gpui::Entity<T> {
28 self.#app_variable.new(build_entity)
29 }
30
31 fn reserve_entity<T: 'static>(&mut self) -> gpui::Reservation<T> {
32 self.#app_variable.reserve_entity()
33 }
34
35 fn insert_entity<T: 'static>(
36 &mut self,
37 reservation: gpui::Reservation<T>,
38 build_entity: impl FnOnce(&mut gpui::Context<'_, T>) -> T,
39 ) -> gpui::Entity<T> {
40 self.#app_variable.insert_entity(reservation, build_entity)
41 }
42
43 fn update_entity<T, R>(
44 &mut self,
45 handle: &gpui::Entity<T>,
46 update: impl FnOnce(&mut T, &mut gpui::Context<'_, T>) -> R,
47 ) -> R
48 where
49 T: 'static,
50 {
51 self.#app_variable.update_entity(handle, update)
52 }
53
54 fn as_mut<'y, 'z, T>(
55 &'y mut self,
56 handle: &'z gpui::Entity<T>,
57 ) -> gpui::GpuiBorrow<'y, T>
58 where
59 T: 'static,
60 {
61 self.#app_variable.as_mut(handle)
62 }
63
64 fn read_entity<T, R>(
65 &self,
66 handle: &gpui::Entity<T>,
67 read: impl FnOnce(&T, &gpui::App) -> R,
68 ) -> R
69 where
70 T: 'static,
71 {
72 self.#app_variable.read_entity(handle, read)
73 }
74
75 fn update_window<T, F>(&mut self, window: gpui::AnyWindowHandle, f: F) -> gpui::Result<T>
76 where
77 F: FnOnce(gpui::AnyView, &mut gpui::Window, &mut gpui::App) -> T,
78 {
79 self.#app_variable.update_window(window, f)
80 }
81
82 fn read_window<T, R>(
83 &self,
84 window: &gpui::WindowHandle<T>,
85 read: impl FnOnce(gpui::Entity<T>, &gpui::App) -> R,
86 ) -> gpui::Result<R>
87 where
88 T: 'static,
89 {
90 self.#app_variable.read_window(window, read)
91 }
92
93 fn background_spawn<R>(&self, future: impl std::future::Future<Output = R> + Send + 'static) -> gpui::Task<R>
94 where
95 R: Send + 'static,
96 {
97 self.#app_variable.background_spawn(future)
98 }
99
100 fn read_global<G, R>(&self, callback: impl FnOnce(&G, &gpui::App) -> R) -> R
101 where
102 G: gpui::Global,
103 {
104 self.#app_variable.read_global(callback)
105 }
106 }
107 };
108
109 r#gen.into()
110}