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 type Result<T> = T;
25
26 fn new<T: 'static>(
27 &mut self,
28 build_entity: impl FnOnce(&mut gpui::Context<'_, T>) -> T,
29 ) -> Self::Result<gpui::Entity<T>> {
30 self.#app_variable.new(build_entity)
31 }
32
33 fn reserve_entity<T: 'static>(&mut self) -> Self::Result<gpui::Reservation<T>> {
34 self.#app_variable.reserve_entity()
35 }
36
37 fn insert_entity<T: 'static>(
38 &mut self,
39 reservation: gpui::Reservation<T>,
40 build_entity: impl FnOnce(&mut gpui::Context<'_, T>) -> T,
41 ) -> Self::Result<gpui::Entity<T>> {
42 self.#app_variable.insert_entity(reservation, build_entity)
43 }
44
45 fn update_entity<T, R>(
46 &mut self,
47 handle: &gpui::Entity<T>,
48 update: impl FnOnce(&mut T, &mut gpui::Context<'_, T>) -> R,
49 ) -> Self::Result<R>
50 where
51 T: 'static,
52 {
53 self.#app_variable.update_entity(handle, update)
54 }
55
56 fn as_mut<'y, 'z, T>(
57 &'y mut self,
58 handle: &'z gpui::Entity<T>,
59 ) -> Self::Result<gpui::GpuiBorrow<'y, T>>
60 where
61 T: 'static,
62 {
63 self.#app_variable.as_mut(handle)
64 }
65
66 fn read_entity<T, R>(
67 &self,
68 handle: &gpui::Entity<T>,
69 read: impl FnOnce(&T, &gpui::App) -> R,
70 ) -> Self::Result<R>
71 where
72 T: 'static,
73 {
74 self.#app_variable.read_entity(handle, read)
75 }
76
77 fn update_window<T, F>(&mut self, window: gpui::AnyWindowHandle, f: F) -> gpui::Result<T>
78 where
79 F: FnOnce(gpui::AnyView, &mut gpui::Window, &mut gpui::App) -> T,
80 {
81 self.#app_variable.update_window(window, f)
82 }
83
84 fn read_window<T, R>(
85 &self,
86 window: &gpui::WindowHandle<T>,
87 read: impl FnOnce(gpui::Entity<T>, &gpui::App) -> R,
88 ) -> gpui::Result<R>
89 where
90 T: 'static,
91 {
92 self.#app_variable.read_window(window, read)
93 }
94
95 fn background_spawn<R>(&self, future: impl std::future::Future<Output = R> + Send + 'static) -> gpui::Task<R>
96 where
97 R: Send + 'static,
98 {
99 self.#app_variable.background_spawn(future)
100 }
101
102 fn read_global<G, R>(&self, callback: impl FnOnce(&G, &gpui::App) -> R) -> Self::Result<R>
103 where
104 G: gpui::Global,
105 {
106 self.#app_variable.read_global(callback)
107 }
108 }
109 };
110
111 r#gen.into()
112}