1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Deserialize, Serialize, Clone)]
5#[serde(untagged)]
6pub enum LayoutItem {
7 Break(String),
8 Module(ModuleEntry),
9}
10
11#[derive(Debug, Deserialize, Serialize, Clone)]
13pub struct Flags {
14 #[serde(default)]
15 pub ascii_distro: String,
16 #[serde(default)]
17 pub ascii_colors: String,
18 #[serde(default)]
19 pub battery_display: String,
20 #[serde(default)]
21 pub color_blocks: String,
22 #[serde(default)]
23 pub cpu_brand: bool,
24 #[serde(default)]
25 pub cpu_cores: bool,
26 #[serde(default)]
27 pub cpu_frequency: bool,
28 #[serde(default)]
29 pub cpu_speed: bool,
30 #[serde(
31 default,
32 alias = "cpu_show_temp",
33 deserialize_with = "deserialize_cpu_temp"
34 )]
35 pub cpu_temp: String,
36 #[serde(default)]
37 pub custom_logo_path: String,
38 #[serde(default)]
39 pub de_version: bool,
40 #[serde(default)]
41 pub disk_display: String,
42 #[serde(default)]
43 pub disk_percent: bool,
44 #[serde(default)]
45 pub disk_show: String,
46 #[serde(default)]
47 pub disk_subtitle: String,
48 #[serde(default, alias = "distro_display")]
49 pub distro_shorthand: String,
50 #[serde(default)]
51 pub gpu_brand: bool,
52 #[serde(default)]
53 pub gpu_type: String,
54 #[serde(default)]
55 pub kernel_shorthand: bool,
56 #[serde(default)]
57 pub memory_percent: bool,
58 #[serde(default)]
59 pub memory_unit: String,
60 #[serde(default)]
61 pub os_age_shorthand: String,
62 #[serde(default)]
63 pub package_managers: String,
64 #[serde(default)]
65 pub shell_path: bool,
66 #[serde(default)]
67 pub shell_version: bool,
68 #[serde(default)]
69 pub speed_shorthand: bool,
70 #[serde(default)]
71 pub uptime_shorthand: String,
72}
73
74#[derive(Debug, Deserialize, Serialize, Clone)]
76pub struct Config {
77 #[serde(default, rename = "$schema")]
78 #[allow(dead_code)]
79 pub schema: Option<String>,
80 #[serde(default)]
81 #[allow(dead_code)]
82 pub logo: Option<Logo>,
83 #[serde(default)]
84 pub flags: Flags,
85 #[serde(default, alias = "layout", alias = "modules")]
86 pub layout: Vec<LayoutItem>,
87}
88
89#[derive(Debug, Deserialize, Serialize, Clone, Default)]
91pub struct Logo {
92 #[serde(rename = "type", default)]
93 #[allow(dead_code)]
94 pub logo_type: Option<String>,
95 #[serde(default)]
96 #[allow(dead_code)]
97 pub source: Option<String>,
98}
99
100#[derive(Debug, Deserialize, Serialize, Clone, Default)]
102pub struct ModuleEntry {
103 #[serde(rename = "type", default)]
104 pub module_type: Option<String>,
105 #[serde(default)]
106 pub key: Option<String>,
107 #[serde(default)]
108 pub label: Option<String>,
109 #[serde(default)]
110 pub field: Option<String>,
111 #[serde(default)]
112 pub format: Option<String>,
113 #[serde(default)]
114 pub text: Option<String>,
115}
116
117impl ModuleEntry {
118 pub fn field_name(&self) -> Option<&str> {
119 self.module_type
120 .as_deref()
121 .or(self.field.as_deref())
122 .map(str::trim)
123 .filter(|value| !value.is_empty())
124 }
125
126 pub fn label(&self) -> Option<&str> {
127 self.key.as_deref().or(self.label.as_deref())
128 }
129
130 pub fn is_custom(&self) -> bool {
131 self.field_name()
132 .map(|field| field.eq_ignore_ascii_case("custom"))
133 .unwrap_or(false)
134 }
135}
136
137fn deserialize_cpu_temp<'de, D>(deserializer: D) -> Result<String, D::Error>
138where
139 D: serde::Deserializer<'de>,
140{
141 struct CpuTempVisitor;
142
143 impl<'de> serde::de::Visitor<'de> for CpuTempVisitor {
144 type Value = String;
145
146 fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
147 f.write_str("\"C\", \"F\", \"off\", true, or false")
148 }
149
150 fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<String, E> {
151 match v.to_lowercase().as_str() {
152 "c" | "f" => Ok(v.to_uppercase()),
153 "off" => Ok("off".to_string()),
154 _ => Err(serde::de::Error::custom(format!("invalid cpu_temp: {v}"))),
155 }
156 }
157
158 fn visit_bool<E: serde::de::Error>(self, v: bool) -> Result<String, E> {
159 Ok(if v {
160 "C".to_string()
161 } else {
162 "off".to_string()
163 })
164 }
165 }
166
167 deserializer.deserialize_any(CpuTempVisitor)
168}
169
170impl Default for Flags {
171 fn default() -> Self {
172 Self {
173 ascii_distro: "auto".into(),
174 ascii_colors: "distro".into(),
175 custom_logo_path: String::new(),
176 battery_display: "barinfo".into(),
177 color_blocks: "███".into(),
178 cpu_brand: true,
179 cpu_cores: true,
180 cpu_frequency: true,
181 cpu_speed: true,
182 cpu_temp: "C".into(),
183 de_version: true,
184 disk_display: "barinfo".into(),
185 disk_percent: true,
186 disk_show: "/".into(),
187 disk_subtitle: "dir".into(),
188 distro_shorthand: "name".into(),
189 gpu_brand: true,
190 gpu_type: "all".into(),
191 kernel_shorthand: true,
192 memory_percent: true,
193 memory_unit: "mib".into(),
194 os_age_shorthand: "full".into(),
195 package_managers: "tiny".into(),
196 shell_path: true,
197 shell_version: true,
198 speed_shorthand: false,
199 uptime_shorthand: "full".into(),
200 }
201 }
202}