dampen_core/codegen/
application.rs1use proc_macro2::TokenStream;
4use quote::quote;
5
6use super::CodegenError;
7use super::theme::generate_theme_code;
8use crate::ir::theme::ThemeDocument;
9
10pub fn generate_application_trait(
12 model_name: &str,
13 message_name: &str,
14) -> Result<TokenStream, super::CodegenError> {
15 let model_ident = syn::Ident::new(model_name, proc_macro2::Span::call_site());
16 let message_ident = syn::Ident::new(message_name, proc_macro2::Span::call_site());
17
18 Ok(quote! {
19 impl iced::Application for #model_ident {
20 type Executor = iced::executor::Default;
21 type Flags = ();
22 type Message = #message_ident;
23
24 fn new(_flags: ()) -> (Self, iced::Task<Self::Message>) {
25 (Self::default(), iced::Task::none())
26 }
27
28 fn title(&self) -> String {
29 "Dampen Application".to_string()
30 }
31 }
32 })
33}
34
35pub fn generate_application_with_theme(
37 model_name: &str,
38 message_name: &str,
39 theme_document: Option<&ThemeDocument>,
40) -> Result<TokenStream, CodegenError> {
41 let model_ident = syn::Ident::new(model_name, proc_macro2::Span::call_site());
42 let message_ident = syn::Ident::new(message_name, proc_macro2::Span::call_site());
43
44 let theme_code = if let Some(doc) = theme_document {
45 match generate_theme_code(doc, "app") {
46 Ok(generated) => generated.code,
47 Err(e) => {
48 return Err(CodegenError::ThemeError(e));
49 }
50 }
51 } else {
52 String::new()
53 };
54
55 Ok(quote! {
56 #theme_code
57
58 impl iced::Application for #model_ident {
59 type Executor = iced::executor::Default;
60 type Flags = ();
61 type Message = #message_ident;
62
63 fn new(_flags: ()) -> (Self, iced::Task<Self::Message>) {
64 (Self::default(), iced::Task::none())
65 }
66
67 fn title(&self) -> String {
68 "Dampen Application".to_string()
69 }
70
71 fn theme(&self) -> iced::Theme {
72 app_theme()
73 }
74 }
75 })
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81 use crate::ir::style::Color;
82 use crate::ir::theme::{SpacingScale, Theme, ThemeDocument, ThemePalette, Typography};
83
84 fn create_test_palette() -> ThemePalette {
85 ThemePalette {
86 primary: Some(Color::from_hex("#3498db").unwrap()),
87 secondary: Some(Color::from_hex("#2ecc71").unwrap()),
88 success: Some(Color::from_hex("#27ae60").unwrap()),
89 warning: Some(Color::from_hex("#f39c12").unwrap()),
90 danger: Some(Color::from_hex("#e74c3c").unwrap()),
91 background: Some(Color::from_hex("#ecf0f1").unwrap()),
92 surface: Some(Color::from_hex("#ffffff").unwrap()),
93 text: Some(Color::from_hex("#2c3e50").unwrap()),
94 text_secondary: Some(Color::from_hex("#7f8c8d").unwrap()),
95 }
96 }
97
98 fn create_test_theme(name: &str) -> Theme {
99 Theme {
100 name: name.to_string(),
101 palette: create_test_palette(),
102 typography: Typography {
103 font_family: Some("sans-serif".to_string()),
104 font_size_base: Some(16.0),
105 font_size_small: Some(12.0),
106 font_size_large: Some(24.0),
107 font_weight: crate::ir::theme::FontWeight::Normal,
108 line_height: Some(1.5),
109 },
110 spacing: SpacingScale { unit: Some(8.0) },
111 base_styles: std::collections::HashMap::new(),
112 extends: None,
113 }
114 }
115
116 #[test]
117 fn test_application_trait_generation() {
118 let result = generate_application_trait("MyModel", "MyMessage").unwrap();
119 let code = result.to_string();
120
121 assert!(code.contains("impl") && code.contains("Application") && code.contains("MyModel"));
122 assert!(code.contains("Message") && code.contains("MyMessage"));
123 }
124
125 #[test]
126 fn test_application_with_theme_generation() {
127 let doc = ThemeDocument {
128 themes: std::collections::HashMap::from([(
129 "light".to_string(),
130 create_test_theme("light"),
131 )]),
132 default_theme: Some("light".to_string()),
133 follow_system: true,
134 };
135
136 let result = generate_application_with_theme("MyModel", "MyMessage", Some(&doc));
137 assert!(result.is_ok());
138 let code = result.unwrap().to_string();
139
140 assert!(code.contains("impl") && code.contains("Application"));
141 assert!(code.contains("app_theme()"));
142 assert!(code.contains("fn app_light()"));
143 }
144
145 #[test]
146 fn test_application_without_theme() {
147 let result = generate_application_with_theme("MyModel", "MyMessage", None);
148 assert!(result.is_ok());
149 let code = result.unwrap().to_string();
150
151 assert!(code.contains("impl") && code.contains("Application"));
152 }
153}