1use serde::de::{self, Deserializer};
7use serde::ser::Serializer;
8use serde::{Deserialize, Serialize};
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, Default)]
12#[serde(rename_all = "lowercase")]
13pub enum StatusBarSection {
14 #[default]
16 Left,
17 Center,
19 Right,
21}
22
23#[derive(Debug, Clone, PartialEq, Eq, Hash)]
33pub enum WidgetId {
34 Clock,
36 UsernameHostname,
38 CurrentDirectory,
40 GitBranch,
42 CpuUsage,
44 MemoryUsage,
46 NetworkStatus,
48 DiskFree,
50 BellIndicator,
52 CurrentCommand,
54 UpdateAvailable,
56 Custom(String),
58}
59
60impl WidgetId {
61 pub fn label(&self) -> &str {
63 match self {
64 WidgetId::Clock => "Clock",
65 WidgetId::UsernameHostname => "User@Host",
66 WidgetId::CurrentDirectory => "Directory",
67 WidgetId::GitBranch => "Git Branch",
68 WidgetId::CpuUsage => "CPU Usage",
69 WidgetId::MemoryUsage => "Memory Usage",
70 WidgetId::NetworkStatus => "Network Status",
71 WidgetId::DiskFree => "Disk Free",
72 WidgetId::BellIndicator => "Bell Indicator",
73 WidgetId::CurrentCommand => "Current Command",
74 WidgetId::UpdateAvailable => "Update Available",
75 WidgetId::Custom(name) => name.as_str(),
76 }
77 }
78
79 pub fn icon(&self) -> &str {
81 match self {
82 WidgetId::Clock => "\u{1f551}", WidgetId::UsernameHostname => "\u{1f464}", WidgetId::CurrentDirectory => "\u{1f4c2}", WidgetId::GitBranch => "\u{1f500}", WidgetId::CpuUsage => "\u{1f4bb}", WidgetId::MemoryUsage => "\u{1f4be}", WidgetId::NetworkStatus => "\u{1f310}", WidgetId::DiskFree => "\u{1f4bf}", WidgetId::BellIndicator => "\u{1f514}", WidgetId::CurrentCommand => "\u{25b6}", WidgetId::UpdateAvailable => "\u{2b06}", WidgetId::Custom(_) => "\u{2699}", }
95 }
96
97 pub fn needs_system_monitor(&self) -> bool {
99 matches!(
100 self,
101 WidgetId::CpuUsage | WidgetId::MemoryUsage | WidgetId::NetworkStatus
102 )
103 }
104
105 pub fn needs_disk_monitor(&self) -> bool {
107 matches!(self, WidgetId::DiskFree)
108 }
109
110 fn as_key(&self) -> String {
113 match self {
114 WidgetId::Clock => "clock".to_string(),
115 WidgetId::UsernameHostname => "username_hostname".to_string(),
116 WidgetId::CurrentDirectory => "current_directory".to_string(),
117 WidgetId::GitBranch => "git_branch".to_string(),
118 WidgetId::CpuUsage => "cpu_usage".to_string(),
119 WidgetId::MemoryUsage => "memory_usage".to_string(),
120 WidgetId::NetworkStatus => "network_status".to_string(),
121 WidgetId::DiskFree => "disk_free".to_string(),
122 WidgetId::BellIndicator => "bell_indicator".to_string(),
123 WidgetId::CurrentCommand => "current_command".to_string(),
124 WidgetId::UpdateAvailable => "update_available".to_string(),
125 WidgetId::Custom(name) => format!("custom:{name}"),
126 }
127 }
128
129 fn from_key(key: &str) -> Option<WidgetId> {
132 if let Some(name) = key.strip_prefix("custom:") {
133 return Some(WidgetId::Custom(name.to_string()));
134 }
135 Some(match key {
136 "clock" => WidgetId::Clock,
137 "username_hostname" => WidgetId::UsernameHostname,
138 "current_directory" => WidgetId::CurrentDirectory,
139 "git_branch" => WidgetId::GitBranch,
140 "cpu_usage" => WidgetId::CpuUsage,
141 "memory_usage" => WidgetId::MemoryUsage,
142 "network_status" => WidgetId::NetworkStatus,
143 "disk_free" => WidgetId::DiskFree,
144 "bell_indicator" => WidgetId::BellIndicator,
145 "current_command" => WidgetId::CurrentCommand,
146 "update_available" => WidgetId::UpdateAvailable,
147 _ => return None,
148 })
149 }
150}
151
152impl Serialize for WidgetId {
153 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
154 where
155 S: Serializer,
156 {
157 serializer.serialize_str(&self.as_key())
158 }
159}
160
161impl<'de> Deserialize<'de> for WidgetId {
162 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
163 where
164 D: Deserializer<'de>,
165 {
166 let key = String::deserialize(deserializer)?;
167 WidgetId::from_key(&key)
168 .ok_or_else(|| de::Error::custom(format!("unknown status bar widget id: `{key}`")))
169 }
170}
171
172#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
174pub struct StatusBarWidgetConfig {
175 pub id: WidgetId,
177 #[serde(default = "default_true")]
179 pub enabled: bool,
180 #[serde(default)]
182 pub section: StatusBarSection,
183 #[serde(default)]
185 pub order: i32,
186 #[serde(default, skip_serializing_if = "Option::is_none")]
188 pub format: Option<String>,
189}
190
191fn default_true() -> bool {
192 true
193}
194
195pub fn default_widgets() -> Vec<StatusBarWidgetConfig> {
201 vec![
202 StatusBarWidgetConfig {
203 id: WidgetId::UsernameHostname,
204 enabled: true,
205 section: StatusBarSection::Left,
206 order: 0,
207 format: None,
208 },
209 StatusBarWidgetConfig {
210 id: WidgetId::CurrentDirectory,
211 enabled: true,
212 section: StatusBarSection::Left,
213 order: 1,
214 format: None,
215 },
216 StatusBarWidgetConfig {
217 id: WidgetId::GitBranch,
218 enabled: true,
219 section: StatusBarSection::Left,
220 order: 2,
221 format: None,
222 },
223 StatusBarWidgetConfig {
224 id: WidgetId::CurrentCommand,
225 enabled: true,
226 section: StatusBarSection::Center,
227 order: 0,
228 format: None,
229 },
230 StatusBarWidgetConfig {
231 id: WidgetId::CpuUsage,
232 enabled: false,
233 section: StatusBarSection::Right,
234 order: 0,
235 format: None,
236 },
237 StatusBarWidgetConfig {
238 id: WidgetId::MemoryUsage,
239 enabled: false,
240 section: StatusBarSection::Right,
241 order: 1,
242 format: None,
243 },
244 StatusBarWidgetConfig {
245 id: WidgetId::NetworkStatus,
246 enabled: false,
247 section: StatusBarSection::Right,
248 order: 2,
249 format: None,
250 },
251 StatusBarWidgetConfig {
252 id: WidgetId::DiskFree,
253 enabled: false,
254 section: StatusBarSection::Right,
255 order: 3,
256 format: None,
257 },
258 StatusBarWidgetConfig {
259 id: WidgetId::BellIndicator,
260 enabled: true,
261 section: StatusBarSection::Right,
262 order: 4,
263 format: None,
264 },
265 StatusBarWidgetConfig {
266 id: WidgetId::Clock,
267 enabled: true,
268 section: StatusBarSection::Right,
269 order: 5,
270 format: None,
271 },
272 StatusBarWidgetConfig {
273 id: WidgetId::UpdateAvailable,
274 enabled: true,
275 section: StatusBarSection::Right,
276 order: 6,
277 format: None,
278 },
279 ]
280}