2022-08-14 14:30:13 +01:00
|
|
|
use crate::modules::clock::ClockModule;
|
2022-08-14 20:40:11 +01:00
|
|
|
use crate::modules::focused::FocusedModule;
|
2022-08-14 14:30:13 +01:00
|
|
|
use crate::modules::launcher::LauncherModule;
|
|
|
|
use crate::modules::mpd::MpdModule;
|
|
|
|
use crate::modules::script::ScriptModule;
|
|
|
|
use crate::modules::sysinfo::SysInfoModule;
|
|
|
|
use crate::modules::tray::TrayModule;
|
|
|
|
use crate::modules::workspaces::WorkspacesModule;
|
|
|
|
use dirs::config_dir;
|
|
|
|
use serde::Deserialize;
|
2022-08-15 17:06:42 +01:00
|
|
|
use std::collections::HashMap;
|
|
|
|
use std::path::{Path, PathBuf};
|
|
|
|
use std::{env, fs};
|
2022-08-14 14:30:13 +01:00
|
|
|
|
|
|
|
#[derive(Debug, Deserialize, Clone)]
|
|
|
|
#[serde(tag = "type", rename_all = "kebab-case")]
|
|
|
|
pub enum ModuleConfig {
|
|
|
|
Clock(ClockModule),
|
|
|
|
Mpd(MpdModule),
|
|
|
|
Tray(TrayModule),
|
|
|
|
Workspaces(WorkspacesModule),
|
|
|
|
SysInfo(SysInfoModule),
|
|
|
|
Launcher(LauncherModule),
|
|
|
|
Script(ScriptModule),
|
2022-08-14 20:40:11 +01:00
|
|
|
Focused(FocusedModule),
|
2022-08-14 14:30:13 +01:00
|
|
|
}
|
|
|
|
|
2022-08-15 17:06:42 +01:00
|
|
|
#[derive(Debug, Deserialize, Clone)]
|
|
|
|
#[serde(untagged)]
|
|
|
|
pub enum MonitorConfig {
|
|
|
|
Single(Config),
|
|
|
|
Multiple(Vec<Config>),
|
|
|
|
}
|
|
|
|
|
2022-08-14 20:40:11 +01:00
|
|
|
#[derive(Debug, Deserialize, Clone, PartialEq, Eq)]
|
2022-08-14 15:56:21 +01:00
|
|
|
#[serde(rename_all = "kebab-case")]
|
|
|
|
pub enum BarPosition {
|
|
|
|
Top,
|
2022-08-14 20:40:11 +01:00
|
|
|
Bottom,
|
2022-08-14 15:56:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for BarPosition {
|
|
|
|
fn default() -> Self {
|
|
|
|
BarPosition::Bottom
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-14 14:30:13 +01:00
|
|
|
#[derive(Debug, Deserialize, Clone, Default)]
|
|
|
|
pub struct Config {
|
2022-08-14 15:56:21 +01:00
|
|
|
#[serde(default = "default_bar_position")]
|
|
|
|
pub position: BarPosition,
|
2022-08-14 20:41:38 +01:00
|
|
|
#[serde(default = "default_bar_height")]
|
|
|
|
pub height: i32,
|
2022-08-14 15:56:21 +01:00
|
|
|
|
2022-08-14 14:30:13 +01:00
|
|
|
pub left: Option<Vec<ModuleConfig>>,
|
|
|
|
pub center: Option<Vec<ModuleConfig>>,
|
|
|
|
pub right: Option<Vec<ModuleConfig>>,
|
|
|
|
|
2022-08-15 17:06:42 +01:00
|
|
|
pub monitors: Option<HashMap<String, MonitorConfig>>,
|
2022-08-14 14:30:13 +01:00
|
|
|
}
|
|
|
|
|
2022-08-14 15:56:21 +01:00
|
|
|
const fn default_bar_position() -> BarPosition {
|
|
|
|
BarPosition::Bottom
|
|
|
|
}
|
|
|
|
|
2022-08-14 20:41:38 +01:00
|
|
|
const fn default_bar_height() -> i32 {
|
|
|
|
42
|
|
|
|
}
|
|
|
|
|
2022-08-14 14:30:13 +01:00
|
|
|
impl Config {
|
|
|
|
pub fn load() -> Option<Self> {
|
2022-08-15 17:06:42 +01:00
|
|
|
if let Ok(config_path) = env::var("IRONBAR_CONFIG") {
|
|
|
|
let path = PathBuf::from(config_path);
|
|
|
|
Config::load_file(&path, path.extension().unwrap_or_default().to_str().unwrap_or_default())
|
|
|
|
} else {
|
|
|
|
let config_dir = config_dir().expect("Failed to locate user config dir");
|
2022-08-14 14:30:13 +01:00
|
|
|
|
2022-08-15 17:06:42 +01:00
|
|
|
let extensions = vec!["json", "toml", "yaml", "yml", "corn"];
|
2022-08-14 14:30:13 +01:00
|
|
|
|
2022-08-15 17:06:42 +01:00
|
|
|
extensions.into_iter().find_map(|extension| {
|
|
|
|
let full_path = config_dir
|
|
|
|
.join("ironbar")
|
|
|
|
.join(format!("config.{extension}"));
|
|
|
|
|
|
|
|
Config::load_file(&full_path, extension)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2022-08-14 14:30:13 +01:00
|
|
|
|
2022-08-15 17:06:42 +01:00
|
|
|
fn load_file(path: &Path, extension: &str) -> Option<Self> {
|
|
|
|
if path.exists() {
|
|
|
|
let file = fs::read(path).expect("Failed to read config file");
|
|
|
|
Some(match extension {
|
|
|
|
"json" => serde_json::from_slice(&file).expect("Invalid JSON config"),
|
|
|
|
"toml" => toml::from_slice(&file).expect("Invalid TOML config"),
|
|
|
|
"yaml" | "yml" => serde_yaml::from_slice(&file).expect("Invalid YAML config"),
|
|
|
|
"corn" => {
|
|
|
|
// corn doesn't support deserialization yet
|
|
|
|
// so serialize the interpreted result then deserialize that
|
|
|
|
let file = String::from_utf8(file).expect("Config file contains invalid UTF-8");
|
|
|
|
let config = cornfig::parse(&file).expect("Invalid corn config").value;
|
|
|
|
serde_json::from_str(&serde_json::to_string(&config).unwrap()).unwrap()
|
|
|
|
}
|
|
|
|
_ => unreachable!(),
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
2022-08-14 14:30:13 +01:00
|
|
|
}
|
|
|
|
}
|
2022-08-14 20:40:11 +01:00
|
|
|
|
|
|
|
pub const fn default_false() -> bool {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
pub const fn default_true() -> bool {
|
|
|
|
true
|
|
|
|
}
|