diff --git a/src/bar.rs b/src/bar.rs index 4b6f4a1..7fb0ac2 100644 --- a/src/bar.rs +++ b/src/bar.rs @@ -20,6 +20,7 @@ use env_logger::Env; use serde_json; use std::thread; +pub mod config; pub mod module; pub fn start() { @@ -28,10 +29,18 @@ pub fn start() { thread::spawn(handle_input); let mods: Vec> = vec![ - crate::bar::module::window::BarModuleWindow::init(), - crate::bar::module::sysinfo::BarModuleSysInfo::init(), - crate::bar::module::battery::BarModuleBattery::init(), - crate::bar::module::date::BarModuleDate::init(), + module::window::BarModuleWindow::create( + module::window::BarModuleWindow::default_config("0".to_owned()), + ), + module::sysinfo::BarModuleSysInfo::create( + module::sysinfo::BarModuleSysInfo::default_config("0".to_owned()), + ), + module::battery::BarModuleBattery::create( + module::battery::BarModuleBattery::default_config("0".to_owned()), + ), + module::date::BarModuleDate::create( + module::date::BarModuleDate::default_config("0".to_owned()), + ), ]; generate_status(&mods); } diff --git a/src/bar/config.rs b/src/bar/config.rs new file mode 100644 index 0000000..8549ce1 --- /dev/null +++ b/src/bar/config.rs @@ -0,0 +1,43 @@ +// Copyright (C) 2022 Tassilo Horn +// +// This program is free software: you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +// more details. +// +// You should have received a copy of the GNU General Public License along with +// this program. If not, see . + +//! TOML configuration for swayrbar. + +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize)] +pub struct Config { + pub refresh_interval: f32, + pub modules: Vec, + pub module_configs: Vec, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct ModuleConfig { + pub module_type: String, + pub instance: String, + pub format: String, + pub html_escape: bool, +} + +impl Default for Config { + fn default() -> Self { + Config { + refresh_interval: 1.0, + modules: vec!["date/0".to_owned()], + module_configs: vec![], + } + } +} diff --git a/src/bar/module.rs b/src/bar/module.rs index 5d8238f..b873e88 100644 --- a/src/bar/module.rs +++ b/src/bar/module.rs @@ -13,6 +13,7 @@ // You should have received a copy of the GNU General Public License along with // this program. If not, see . +use crate::bar::config; use swaybar_types as s; pub mod battery; @@ -21,12 +22,15 @@ pub mod sysinfo; pub mod window; pub trait BarModuleFn { - fn init() -> Box + fn create(config: config::ModuleConfig) -> Box where Self: Sized; - fn name() -> String + fn default_config(instance: String) -> config::ModuleConfig where Self: Sized; - fn instance(&self) -> String; + fn name() -> &'static str + where + Self: Sized; + fn instance(&self) -> &str; fn build(&self) -> s::Block; } diff --git a/src/bar/module/battery.rs b/src/bar/module/battery.rs index dce7185..65f1eed 100644 --- a/src/bar/module/battery.rs +++ b/src/bar/module/battery.rs @@ -15,6 +15,7 @@ //! The date `swayrbar` module. +use crate::bar::config; use crate::bar::module::BarModuleFn; use crate::fmt_replace::fmt_replace; use battery as bat; @@ -22,7 +23,7 @@ use std::cell::RefCell; use swaybar_types as s; pub struct BarModuleBattery { - pub instance: String, + config: config::ModuleConfig, manager: RefCell, } @@ -42,23 +43,25 @@ fn get_refreshed_batteries( Ok(bats) } -fn get_text(manager: &RefCell, fmt: &str) -> String { +fn get_text( + manager: &RefCell, + cfg: &config::ModuleConfig, +) -> String { match get_refreshed_batteries(manager) { Ok(bats) => { - fmt_replace!(&fmt, false, { + fmt_replace!(&cfg.format, cfg.html_escape, { "state_of_charge" => bats.iter() .map(|b| b.state_of_charge().value) .sum::() - / bats.len() as f32 * 100 as f32, + / bats.len() as f32 * 100_f32, "state_of_health" => bats.iter() .map(|b| b.state_of_health().value) .sum::() - / bats.len() as f32 * 100 as f32, - + / bats.len() as f32 * 100_f32, "state" => bats.iter() .map(|b| format!("{:?}", b.state())) .next() - .unwrap_or(String::new()), + .unwrap_or_default(), }) } Err(err) => format!("{}", err), @@ -66,30 +69,37 @@ fn get_text(manager: &RefCell, fmt: &str) -> String { } impl BarModuleFn for BarModuleBattery { - fn init() -> Box { + fn create(config: config::ModuleConfig) -> Box { Box::new(BarModuleBattery { - instance: "0".to_string(), + config, manager: RefCell::new( bat::Manager::new().expect("Could not create Manager"), ), }) } - fn name() -> String { - String::from("battery") + fn default_config(instance: String) -> config::ModuleConfig { + config::ModuleConfig { + module_type: Self::name().to_owned(), + instance, + format: "🔋 Bat: {state_of_charge:{:5.1}}%, {state}, Health: {state_of_health:{:5.1}}%".to_owned(), + html_escape: true, + } + } + + fn name() -> &'static str { + "battery" } - fn instance(&self) -> String { - self.instance.clone() + fn instance(&self) -> &str { + &self.config.instance } fn build(&self) -> s::Block { - let fmt = - "🔋 Bat: {state_of_charge:{:5.1}}%, {state}, Health: {state_of_health:{:5.1}}%"; - let text = get_text(&self.manager, fmt); + let text = get_text(&self.manager, &self.config); s::Block { - name: Some(Self::name()), - instance: Some(self.instance.clone()), + name: Some(Self::name().to_owned()), + instance: Some(self.config.instance.clone()), full_text: text, align: Some(s::Align::Right), markup: Some(s::Markup::Pango), diff --git a/src/bar/module/date.rs b/src/bar/module/date.rs index ec92625..77e5300 100644 --- a/src/bar/module/date.rs +++ b/src/bar/module/date.rs @@ -15,34 +15,42 @@ //! The date `swayrbar` module. +use crate::bar::module::config; use crate::bar::module::BarModuleFn; use swaybar_types as s; pub struct BarModuleDate { - pub instance: String, + config: config::ModuleConfig, } impl BarModuleFn for BarModuleDate { - fn init() -> Box { - Box::new(BarModuleDate { - instance: "0".to_string(), - }) + fn default_config(instance: String) -> config::ModuleConfig { + config::ModuleConfig { + module_type: "date".to_owned(), + instance, + format: "⏰ %F %X".to_owned(), + html_escape: false, + } + } + + fn create(cfg: config::ModuleConfig) -> Box { + Box::new(BarModuleDate { config: cfg }) } - fn name() -> String { - String::from("date") + fn name() -> &'static str { + "date" } - fn instance(&self) -> String { - self.instance.clone() + fn instance(&self) -> &str { + &self.config.instance } fn build(&self) -> s::Block { - let d = chrono::Local::now().format("⏰ %F %X").to_string(); + let text = chrono::Local::now().format(&self.config.format).to_string(); s::Block { - name: Some(Self::name()), - instance: Some(self.instance.clone()), - full_text: d, + name: Some(Self::name().to_owned()), + instance: Some(self.config.instance.clone()), + full_text: text, align: Some(s::Align::Right), markup: Some(s::Markup::Pango), short_text: None, diff --git a/src/bar/module/sysinfo.rs b/src/bar/module/sysinfo.rs index 1bb8845..a41adea 100644 --- a/src/bar/module/sysinfo.rs +++ b/src/bar/module/sysinfo.rs @@ -15,6 +15,7 @@ //! The date `swayrbar` module. +use crate::bar::config; use crate::bar::module::BarModuleFn; use crate::fmt_replace::fmt_replace; use std::cell::RefCell; @@ -25,18 +26,18 @@ use sysinfo::ProcessorExt; use sysinfo::SystemExt; pub struct BarModuleSysInfo { - pub instance: String, + config: config::ModuleConfig, system: RefCell, } -struct Updater { +struct OnceRefresher { cpu: Once, memory: Once, } -impl Updater { - fn new() -> Updater { - Updater { +impl OnceRefresher { + fn new() -> OnceRefresher { + OnceRefresher { cpu: Once::new(), memory: Once::new(), } @@ -51,15 +52,15 @@ impl Updater { } } -fn get_cpu_usage(sys: &RefCell, upd: &Updater) -> f32 { +fn get_cpu_usage(sys: &RefCell, upd: &OnceRefresher) -> f32 { upd.refresh_cpu(sys); sys.borrow().global_processor_info().cpu_usage() } -fn get_memory_usage(sys: &RefCell, upd: &Updater) -> f64 { +fn get_memory_usage(sys: &RefCell, upd: &OnceRefresher) -> f64 { upd.refresh_memory(sys); let sys = sys.borrow(); - sys.used_memory() as f64 * 100 as f64 / sys.total_memory() as f64 + sys.used_memory() as f64 * 100_f64 / sys.total_memory() as f64 } #[derive(Debug)] @@ -72,7 +73,7 @@ enum LoadAvg { fn get_load_average( sys: &RefCell, avg: LoadAvg, - upd: &Updater, + upd: &OnceRefresher, ) -> f64 { upd.refresh_cpu(sys); let load_avg = sys.borrow().load_average(); @@ -84,28 +85,27 @@ fn get_load_average( } impl BarModuleFn for BarModuleSysInfo { - fn init() -> Box { + fn create(config: config::ModuleConfig) -> Box { Box::new(BarModuleSysInfo { - instance: "0".to_string(), + config, system: RefCell::new(si::System::new_all()), }) } - fn name() -> String { - String::from("sysinfo") + fn name() -> &'static str { + "sysinfo" } - fn instance(&self) -> String { - self.instance.clone() + fn instance(&self) -> &str { + &self.config.instance } fn build(&self) -> s::Block { - let fmt = "💻 CPU: {cpu_usage:{:4.1}}% Mem: {mem_usage:{:4.1}}% Load: {load_avg_1:{:4.2}} / {load_avg_5:{:4.2}} / {load_avg_15:{:4.2}}"; - let updater = Updater::new(); + let updater = OnceRefresher::new(); s::Block { - name: Some(Self::name()), - instance: Some(self.instance.clone()), - full_text: fmt_replace!(fmt, true, { + name: Some(Self::name().to_owned()), + instance: Some(self.config.instance.clone()), + full_text: fmt_replace!(&self.config.format, self.config.html_escape, { "cpu_usage" => get_cpu_usage(&self.system, &updater), "mem_usage" => get_memory_usage(&self.system, &updater), "load_avg_1" => get_load_average(&self.system, @@ -131,4 +131,12 @@ impl BarModuleFn for BarModuleSysInfo { separator_block_width: None, } } + + fn default_config(instance: String) -> config::ModuleConfig { + config::ModuleConfig { + module_type: "sysinfo".to_owned(), + instance, + format: "💻 CPU: {cpu_usage:{:4.1}}% Mem: {mem_usage:{:4.1}}% Load: {load_avg_1:{:4.2}} / {load_avg_5:{:4.2}} / {load_avg_15:{:4.2}}".to_owned(), + html_escape: true } + } } diff --git a/src/bar/module/window.rs b/src/bar/module/window.rs index 8b377c3..2022d23 100644 --- a/src/bar/module/window.rs +++ b/src/bar/module/window.rs @@ -15,6 +15,7 @@ //! The window `swayrbar` module. +use crate::bar::config; use crate::bar::module::BarModuleFn; use crate::fmt_replace::fmt_replace; use crate::ipc; @@ -22,40 +23,48 @@ use crate::ipc::NodeMethods; use swaybar_types as s; pub struct BarModuleWindow { - pub instance: String, + config: config::ModuleConfig, } impl BarModuleFn for BarModuleWindow { - fn init() -> Box { - Box::new(BarModuleWindow { - instance: "0".to_string(), - }) + fn create(config: config::ModuleConfig) -> Box { + Box::new(BarModuleWindow { config }) } - fn name() -> String { - String::from("window") + fn default_config(instance: String) -> config::ModuleConfig { + config::ModuleConfig { + module_type: Self::name().to_owned(), + instance, + format: "🪟 {title} — {app_name}".to_owned(), + html_escape: true, + } + } + + fn name() -> &'static str { + "window" } - fn instance(&self) -> String { - self.instance.clone() + fn instance(&self) -> &str { + &self.config.instance } fn build(&self) -> s::Block { - let fmt = "🪟 {title} — {app_name}"; let root = ipc::get_root_node(false); let focused_win = root .iter() .find(|n| n.focused && n.get_type() == ipc::Type::Window); let text = match focused_win { - Some(win) => fmt_replace!(&fmt, false, { - "title" |"name" => win.get_name(), - "app_name" => win.get_app_name(), - }), + Some(win) => { + fmt_replace!(&self.config.format, self.config.html_escape, { + "title" |"name" => win.get_name(), + "app_name" => win.get_app_name(), + }) + } None => String::new(), }; s::Block { - name: Some(Self::name()), - instance: Some(self.instance.clone()), + name: Some(Self::name().to_owned()), + instance: Some(self.config.instance.clone()), full_text: text, align: Some(s::Align::Left), markup: Some(s::Markup::Pango), diff --git a/src/fmt_replace.rs b/src/fmt_replace.rs index f24f41e..7a71d1a 100644 --- a/src/fmt_replace.rs +++ b/src/fmt_replace.rs @@ -34,7 +34,7 @@ pub fn maybe_html_escape(do_it: bool, text: String) -> String { } macro_rules! fmt_replace { - ( $fmt_str:expr, $html_escape:ident, + ( $fmt_str:expr, $html_escape:expr, { $( $($pat:pat)|+ => $exp:expr, )+ } ) => { $crate::fmt_replace::PLACEHOLDER_RX