use serde::de::{self, Deserializer};
use serde::ser::Serializer;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, Default)]
#[serde(rename_all = "lowercase")]
pub enum StatusBarSection {
#[default]
Left,
Center,
Right,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum WidgetId {
Clock,
UsernameHostname,
CurrentDirectory,
GitBranch,
CpuUsage,
MemoryUsage,
NetworkStatus,
BellIndicator,
CurrentCommand,
UpdateAvailable,
Custom(String),
}
impl WidgetId {
pub fn label(&self) -> &str {
match self {
WidgetId::Clock => "Clock",
WidgetId::UsernameHostname => "User@Host",
WidgetId::CurrentDirectory => "Directory",
WidgetId::GitBranch => "Git Branch",
WidgetId::CpuUsage => "CPU Usage",
WidgetId::MemoryUsage => "Memory Usage",
WidgetId::NetworkStatus => "Network Status",
WidgetId::BellIndicator => "Bell Indicator",
WidgetId::CurrentCommand => "Current Command",
WidgetId::UpdateAvailable => "Update Available",
WidgetId::Custom(name) => name.as_str(),
}
}
pub fn icon(&self) -> &str {
match self {
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}", }
}
pub fn needs_system_monitor(&self) -> bool {
matches!(
self,
WidgetId::CpuUsage | WidgetId::MemoryUsage | WidgetId::NetworkStatus
)
}
fn as_key(&self) -> String {
match self {
WidgetId::Clock => "clock".to_string(),
WidgetId::UsernameHostname => "username_hostname".to_string(),
WidgetId::CurrentDirectory => "current_directory".to_string(),
WidgetId::GitBranch => "git_branch".to_string(),
WidgetId::CpuUsage => "cpu_usage".to_string(),
WidgetId::MemoryUsage => "memory_usage".to_string(),
WidgetId::NetworkStatus => "network_status".to_string(),
WidgetId::BellIndicator => "bell_indicator".to_string(),
WidgetId::CurrentCommand => "current_command".to_string(),
WidgetId::UpdateAvailable => "update_available".to_string(),
WidgetId::Custom(name) => format!("custom:{name}"),
}
}
fn from_key(key: &str) -> Option<WidgetId> {
if let Some(name) = key.strip_prefix("custom:") {
return Some(WidgetId::Custom(name.to_string()));
}
Some(match key {
"clock" => WidgetId::Clock,
"username_hostname" => WidgetId::UsernameHostname,
"current_directory" => WidgetId::CurrentDirectory,
"git_branch" => WidgetId::GitBranch,
"cpu_usage" => WidgetId::CpuUsage,
"memory_usage" => WidgetId::MemoryUsage,
"network_status" => WidgetId::NetworkStatus,
"bell_indicator" => WidgetId::BellIndicator,
"current_command" => WidgetId::CurrentCommand,
"update_available" => WidgetId::UpdateAvailable,
_ => return None,
})
}
}
impl Serialize for WidgetId {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.as_key())
}
}
impl<'de> Deserialize<'de> for WidgetId {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let key = String::deserialize(deserializer)?;
WidgetId::from_key(&key)
.ok_or_else(|| de::Error::custom(format!("unknown status bar widget id: `{key}`")))
}
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct StatusBarWidgetConfig {
pub id: WidgetId,
#[serde(default = "default_true")]
pub enabled: bool,
#[serde(default)]
pub section: StatusBarSection,
#[serde(default)]
pub order: i32,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub format: Option<String>,
}
fn default_true() -> bool {
true
}
pub fn default_widgets() -> Vec<StatusBarWidgetConfig> {
vec![
StatusBarWidgetConfig {
id: WidgetId::UsernameHostname,
enabled: true,
section: StatusBarSection::Left,
order: 0,
format: None,
},
StatusBarWidgetConfig {
id: WidgetId::CurrentDirectory,
enabled: true,
section: StatusBarSection::Left,
order: 1,
format: None,
},
StatusBarWidgetConfig {
id: WidgetId::GitBranch,
enabled: true,
section: StatusBarSection::Left,
order: 2,
format: None,
},
StatusBarWidgetConfig {
id: WidgetId::CurrentCommand,
enabled: true,
section: StatusBarSection::Center,
order: 0,
format: None,
},
StatusBarWidgetConfig {
id: WidgetId::CpuUsage,
enabled: false,
section: StatusBarSection::Right,
order: 0,
format: None,
},
StatusBarWidgetConfig {
id: WidgetId::MemoryUsage,
enabled: false,
section: StatusBarSection::Right,
order: 1,
format: None,
},
StatusBarWidgetConfig {
id: WidgetId::NetworkStatus,
enabled: false,
section: StatusBarSection::Right,
order: 2,
format: None,
},
StatusBarWidgetConfig {
id: WidgetId::BellIndicator,
enabled: true,
section: StatusBarSection::Right,
order: 3,
format: None,
},
StatusBarWidgetConfig {
id: WidgetId::Clock,
enabled: true,
section: StatusBarSection::Right,
order: 4,
format: None,
},
StatusBarWidgetConfig {
id: WidgetId::UpdateAvailable,
enabled: true,
section: StatusBarSection::Right,
order: 5,
format: None,
},
]
}