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 BellIndicator,
50 CurrentCommand,
52 UpdateAvailable,
54 Custom(String),
56}
57
58impl WidgetId {
59 pub fn label(&self) -> &str {
61 match self {
62 WidgetId::Clock => "Clock",
63 WidgetId::UsernameHostname => "User@Host",
64 WidgetId::CurrentDirectory => "Directory",
65 WidgetId::GitBranch => "Git Branch",
66 WidgetId::CpuUsage => "CPU Usage",
67 WidgetId::MemoryUsage => "Memory Usage",
68 WidgetId::NetworkStatus => "Network Status",
69 WidgetId::BellIndicator => "Bell Indicator",
70 WidgetId::CurrentCommand => "Current Command",
71 WidgetId::UpdateAvailable => "Update Available",
72 WidgetId::Custom(name) => name.as_str(),
73 }
74 }
75
76 pub fn icon(&self) -> &str {
78 match self {
79 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::BellIndicator => "\u{1f514}", WidgetId::CurrentCommand => "\u{25b6}", WidgetId::UpdateAvailable => "\u{2b06}", WidgetId::Custom(_) => "\u{2699}", }
91 }
92
93 pub fn needs_system_monitor(&self) -> bool {
95 matches!(
96 self,
97 WidgetId::CpuUsage | WidgetId::MemoryUsage | WidgetId::NetworkStatus
98 )
99 }
100
101 fn as_key(&self) -> String {
104 match self {
105 WidgetId::Clock => "clock".to_string(),
106 WidgetId::UsernameHostname => "username_hostname".to_string(),
107 WidgetId::CurrentDirectory => "current_directory".to_string(),
108 WidgetId::GitBranch => "git_branch".to_string(),
109 WidgetId::CpuUsage => "cpu_usage".to_string(),
110 WidgetId::MemoryUsage => "memory_usage".to_string(),
111 WidgetId::NetworkStatus => "network_status".to_string(),
112 WidgetId::BellIndicator => "bell_indicator".to_string(),
113 WidgetId::CurrentCommand => "current_command".to_string(),
114 WidgetId::UpdateAvailable => "update_available".to_string(),
115 WidgetId::Custom(name) => format!("custom:{name}"),
116 }
117 }
118
119 fn from_key(key: &str) -> Option<WidgetId> {
122 if let Some(name) = key.strip_prefix("custom:") {
123 return Some(WidgetId::Custom(name.to_string()));
124 }
125 Some(match key {
126 "clock" => WidgetId::Clock,
127 "username_hostname" => WidgetId::UsernameHostname,
128 "current_directory" => WidgetId::CurrentDirectory,
129 "git_branch" => WidgetId::GitBranch,
130 "cpu_usage" => WidgetId::CpuUsage,
131 "memory_usage" => WidgetId::MemoryUsage,
132 "network_status" => WidgetId::NetworkStatus,
133 "bell_indicator" => WidgetId::BellIndicator,
134 "current_command" => WidgetId::CurrentCommand,
135 "update_available" => WidgetId::UpdateAvailable,
136 _ => return None,
137 })
138 }
139}
140
141impl Serialize for WidgetId {
142 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
143 where
144 S: Serializer,
145 {
146 serializer.serialize_str(&self.as_key())
147 }
148}
149
150impl<'de> Deserialize<'de> for WidgetId {
151 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
152 where
153 D: Deserializer<'de>,
154 {
155 let key = String::deserialize(deserializer)?;
156 WidgetId::from_key(&key)
157 .ok_or_else(|| de::Error::custom(format!("unknown status bar widget id: `{key}`")))
158 }
159}
160
161#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
163pub struct StatusBarWidgetConfig {
164 pub id: WidgetId,
166 #[serde(default = "default_true")]
168 pub enabled: bool,
169 #[serde(default)]
171 pub section: StatusBarSection,
172 #[serde(default)]
174 pub order: i32,
175 #[serde(default, skip_serializing_if = "Option::is_none")]
177 pub format: Option<String>,
178}
179
180fn default_true() -> bool {
181 true
182}
183
184pub fn default_widgets() -> Vec<StatusBarWidgetConfig> {
190 vec![
191 StatusBarWidgetConfig {
192 id: WidgetId::UsernameHostname,
193 enabled: true,
194 section: StatusBarSection::Left,
195 order: 0,
196 format: None,
197 },
198 StatusBarWidgetConfig {
199 id: WidgetId::CurrentDirectory,
200 enabled: true,
201 section: StatusBarSection::Left,
202 order: 1,
203 format: None,
204 },
205 StatusBarWidgetConfig {
206 id: WidgetId::GitBranch,
207 enabled: true,
208 section: StatusBarSection::Left,
209 order: 2,
210 format: None,
211 },
212 StatusBarWidgetConfig {
213 id: WidgetId::CurrentCommand,
214 enabled: true,
215 section: StatusBarSection::Center,
216 order: 0,
217 format: None,
218 },
219 StatusBarWidgetConfig {
220 id: WidgetId::CpuUsage,
221 enabled: false,
222 section: StatusBarSection::Right,
223 order: 0,
224 format: None,
225 },
226 StatusBarWidgetConfig {
227 id: WidgetId::MemoryUsage,
228 enabled: false,
229 section: StatusBarSection::Right,
230 order: 1,
231 format: None,
232 },
233 StatusBarWidgetConfig {
234 id: WidgetId::NetworkStatus,
235 enabled: false,
236 section: StatusBarSection::Right,
237 order: 2,
238 format: None,
239 },
240 StatusBarWidgetConfig {
241 id: WidgetId::BellIndicator,
242 enabled: true,
243 section: StatusBarSection::Right,
244 order: 3,
245 format: None,
246 },
247 StatusBarWidgetConfig {
248 id: WidgetId::Clock,
249 enabled: true,
250 section: StatusBarSection::Right,
251 order: 4,
252 format: None,
253 },
254 StatusBarWidgetConfig {
255 id: WidgetId::UpdateAvailable,
256 enabled: true,
257 section: StatusBarSection::Right,
258 order: 5,
259 format: None,
260 },
261 ]
262}