1#[doc(hidden)]
2#[macro_export]
3macro_rules! option_settings {
4 ($option_type:ident, $option_name:ident, $description:literal, $default:literal $(,)?) => {
5 $crate::paste::expr! {
6 weechat::config::[<$option_type OptionSettings>]::new(stringify!($option_name))
7 .description($description)
8 .default_value($default)
9 }
10 };
11 (Integer, $option_name:ident, $description:literal, $default:literal, $min:literal..$max:literal $(,)?) => {
12 weechat::config::IntegerOptionSettings::new(stringify!($option_name))
13 .description($description)
14 .default_value($default)
15 .min($min)
16 .max($max)
17 };
18 (Enum, $option_name:ident, $description:literal, $out_type:ty $(,)?) => {
19 weechat::config::IntegerOptionSettings::new(stringify!($option_name))
20 .description($description)
21 .default_value(<$out_type>::default() as i32)
22 .string_values(
23 <$out_type>::VARIANTS
24 .iter()
25 .map(|v| v.to_string())
26 .collect::<Vec<String>>(),
27 );
28 };
29}
30
31#[doc(hidden)]
32#[macro_export]
33macro_rules! option_create {
34 ($option_type:ident, $option_weechat_type:ident, $option_name:ident, $($args:tt)*) => {
35 $crate::paste::item! {
36 fn [<create_option_ $option_name>](section: &mut weechat::config::SectionHandleMut) {
37 let option_settings = $crate::option_settings!($option_type, $option_name, $($args)*);
38 section.[<new_ $option_weechat_type:lower _option>](option_settings)
39 .expect(&format!("Can't create option {}", stringify!($option_name)));
40 }
41 }
42 };
43}
44
45#[doc(hidden)]
46#[macro_export]
47macro_rules! option_getter {
48 ($option_type:ident, $name:ident, $string_name:expr, $description:literal, $output_type:ty) => {
49 $crate::paste::item! {
50 pub fn [<$name>](&self) -> $output_type {
51 if let weechat::config::ConfigOption::[<$option_type>](o) = self.0.search_option($string_name)
52 .expect(&format!("Couldn't find option {} in section {}",
53 $string_name, self.0.name()))
54 {
55 $output_type::from(o.value())
56 } else {
57 panic!("Incorect option type for option {} in section {}",
58 $string_name, self.0.name());
59 }
60 }
61 }
62 };
63
64 (EvaluatedString, $name:ident, $string_name:expr, $description:literal) => {
65 $crate::paste::item! {
66 pub fn [<$name>](&self) -> String {
67 let option = self.0.search_option($string_name)
68 .expect(&format!("Couldn't find option {} in section {}",
69 $string_name, self.0.name()));
70
71 if let weechat::config::ConfigOption::String(o) = option {
72 weechat::Weechat::eval_string_expression(&o.value())
73 .expect(&format!(
74 "Can't evaluate string expression for option {} in section {}",
75 $string_name,
76 self.0.name())
77 )
78 } else {
79 panic!("Incorect option type for option {} in section {}",
80 $string_name, self.0.name());
81 }
82 }
83 }
84 };
85}
86
87#[doc(hidden)]
88#[macro_export]
89macro_rules! option {
90 (String, $name:ident, $description:literal, $($args:tt)*) => {
91 $crate::option_create!(String, String, $name, $description, $($args)*);
92 $crate::option_getter!(String, $name, stringify!($name), $description, String);
93 };
94
95 (Color, $name:ident, $description:literal, $($args:tt)*) => {
96 $crate::option_create!(Color, Color, $name, $description, $($args)*);
97 $crate::option_getter!(Color, $name, stringify!($name), $description, String);
98 };
99
100 (bool, $name:ident, $description:literal, $($args:tt)*) => {
101 $crate::option_create!(Boolean, Boolean, $name, $description, $($args)*);
102 $crate::option_getter!(Boolean, $name, stringify!($name), $description, bool);
103 };
104
105 (Integer, $name:ident, $description:literal, $($args:tt)*) => {
106 $crate::option_create!(Integer, Integer, $name, $description, $($args)*);
107 $crate::option_getter!(Integer, $name, stringify!($name), $description, i64);
108 };
109
110 (Enum, $name:ident, $description:literal, $out_type:ty $(,)?) => {
111 $crate::option_create!(Enum, Integer, $name, $description, $out_type);
112 $crate::option_getter!(Integer, $name, stringify!($name), $description, $out_type);
113 };
114
115 (EvaluatedString, $name:ident, $description:literal, $($args:tt)*) => {
116 $crate::option_create!(String, String, $name, $description, $($args)*);
117 $crate::option_getter!(EvaluatedString, $name, stringify!($name), $description);
118 };
119}
120
121#[doc(hidden)]
122#[macro_export]
123macro_rules! section {
124 ($section:ident { $($option_name:ident: $option_type:ident {$($option:tt)*}), * $(,)? }) => {
125 $crate::paste::item! {
126 pub struct [<$section:camel Section>]<'a>(weechat::config::SectionHandle<'a>);
127
128 impl<'a> [<$section:camel Section>]<'a> {
129 fn create(config: &mut Config) {
130 let section_settings = weechat::config::ConfigSectionSettings::new(stringify!($section));
131
132 let mut $section = config.new_section(section_settings)
133 .expect(&format!("Can't create config section {}", stringify!($section)));
134
135 [<$section:camel Section>]::create_options(&mut $section);
136 }
137
138 fn create_options(section: &mut weechat::config::SectionHandleMut) {
139 $(
140 [<$section:camel Section>]::[<create_option_ $option_name>](section);
141 )*
142 }
143
144 $(
145 $crate::option!($option_type, $option_name, $($option)*);
146 )*
147 }
148 }
149 }
150}
151
152#[doc(hidden)]
153#[macro_export]
154macro_rules! section_getter {
155 ($section:ident, $section_name:expr) => {
156 $crate::paste::item! {
157 pub fn $section(&self) -> [<$section:camel Section>] {
158 let section = self.0.search_section($section_name)
159 .expect(&format!("Couldn't find section {}", $section_name));
160
161 $crate::paste::item! { [<$section:camel Section>](section) }
162 }
163 }
164 };
165}
166
167#[cfg(feature = "config_macro")]
280#[cfg_attr(feature = "docs", doc(cfg(config_macro)))]
281#[macro_export]
282macro_rules! config {
283 ($config_name:literal, $(Section $section:ident { $($option:tt)* }), * $(,)?) => {
284 #[allow(unused_imports)]
285 use weechat::strum::VariantNames;
286 #[allow(unused_imports)]
287 pub struct Config(weechat::config::Config);
288
289 impl std::ops::Deref for Config {
290 type Target = weechat::config::Config;
291
292 fn deref(&self) -> &Self::Target {
293 &self.0
294 }
295 }
296
297 impl std::ops::DerefMut for Config {
298 fn deref_mut(&mut self) -> &mut Self::Target {
299 &mut self.0
300 }
301 }
302
303 impl Config {
304 pub fn new() -> Result<Self, ()> {
307 let config = weechat::config::Config::new($config_name)?;
308 let mut config = Config(config);
309
310 config.create_sections();
311
312 Ok(config)
313 }
314
315 pub fn new_with_callback(
318 reload_callback: impl weechat::config::ConfigReloadCallback,
319 ) -> Result<Self, ()> {
320 let config = weechat::config::Config::new_with_callback(
321 $config_name,
322 reload_callback
323 )?;
324 let mut config = Config(config);
325
326 config.create_sections();
327
328 Ok(config)
329 }
330
331
332 $crate::paste::item! {
333 fn create_sections(&mut self) {
334 $(
335 $crate::paste::expr! { [<$section:camel Section>]::create(self) };
336 )*
337 }
338 }
339
340 $(
341 $crate::section_getter!($section, stringify!($section));
342 )*
343 }
344
345 $(
346 $crate::section!($section { $($option)* });
347 )*
348 }
349}