fixed formatting to be dynamic
This commit is contained in:
13
Cargo.lock
generated
13
Cargo.lock
generated
@@ -148,6 +148,7 @@ dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"fs4",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sysinfo",
|
||||
@@ -312,6 +313,18 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.14"
|
||||
|
||||
@@ -7,6 +7,7 @@ edition = "2024"
|
||||
anyhow = "1.0.102"
|
||||
clap = { version = "4.6.0", features = ["derive"] }
|
||||
fs4 = "0.13.1"
|
||||
regex = "1.10"
|
||||
serde = { version = "1.0.228", features = ["derive"] }
|
||||
serde_json = "1.0.149"
|
||||
sysinfo = "0.38.4"
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
# fluxo-rs example configuration
|
||||
# place this at ~/.config/fluxo/config.toml
|
||||
|
||||
# Note: All tokens support standard alignment, padding, and precision specifiers dynamically.
|
||||
# For example, you can change {rx:>5.2} to {rx:<8.1} or {used} to {used:^4.0} directly here.
|
||||
|
||||
[general]
|
||||
# command used for interactive menus (e.g., bluetooth device selection)
|
||||
# tokens: {prompt}
|
||||
|
||||
@@ -2,6 +2,7 @@ use crate::config::Config;
|
||||
use crate::modules::WaybarModule;
|
||||
use crate::output::WaybarOutput;
|
||||
use crate::state::SharedState;
|
||||
use crate::utils::{format_template, TokenValue};
|
||||
use anyhow::{Result, anyhow};
|
||||
use std::process::Command;
|
||||
|
||||
@@ -58,7 +59,14 @@ impl AudioModule {
|
||||
let (text, class) = if muted {
|
||||
let icon = if target_type == "sink" { "" } else { "" };
|
||||
let format_str = if target_type == "sink" { &config.audio.format_sink_muted } else { &config.audio.format_source_muted };
|
||||
(format_str.replace("{name}", &name).replace("{icon}", icon), "muted")
|
||||
let t = format_template(
|
||||
format_str,
|
||||
&[
|
||||
("name", TokenValue::String(&name)),
|
||||
("icon", TokenValue::String(icon)),
|
||||
]
|
||||
);
|
||||
(t, "muted")
|
||||
} else {
|
||||
let icon = if target_type == "sink" {
|
||||
if display_vol <= 30 { "" }
|
||||
@@ -68,11 +76,14 @@ impl AudioModule {
|
||||
""
|
||||
};
|
||||
let format_str = if target_type == "sink" { &config.audio.format_sink_unmuted } else { &config.audio.format_source_unmuted };
|
||||
let t = format_str
|
||||
.replace("{name}", &name)
|
||||
.replace("{icon}", icon)
|
||||
.replace("{volume:>3}", &format!("{:>3}", display_vol))
|
||||
.replace("{volume}", &format!("{}", display_vol));
|
||||
let t = format_template(
|
||||
format_str,
|
||||
&[
|
||||
("name", TokenValue::String(&name)),
|
||||
("icon", TokenValue::String(icon)),
|
||||
("volume", TokenValue::Int(display_vol as i64)),
|
||||
]
|
||||
);
|
||||
(t, "unmuted")
|
||||
};
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ use crate::config::Config;
|
||||
use crate::modules::WaybarModule;
|
||||
use crate::output::WaybarOutput;
|
||||
use crate::state::SharedState;
|
||||
use crate::utils::{format_template, TokenValue};
|
||||
use anyhow::Result;
|
||||
use std::process::Command;
|
||||
|
||||
@@ -63,7 +64,10 @@ impl WaybarModule for BtModule {
|
||||
battery.map(|b| format!("{}%", b)).unwrap_or_else(|| "N/A".to_string())
|
||||
);
|
||||
|
||||
let text = config.bt.format_connected.replace("{alias}", &alias);
|
||||
let text = format_template(
|
||||
&config.bt.format_connected,
|
||||
&[("alias", TokenValue::String(&alias))]
|
||||
);
|
||||
|
||||
Ok(WaybarOutput {
|
||||
text,
|
||||
|
||||
@@ -2,6 +2,7 @@ use crate::config::Config;
|
||||
use crate::modules::WaybarModule;
|
||||
use crate::output::WaybarOutput;
|
||||
use crate::state::SharedState;
|
||||
use crate::utils::{format_template, TokenValue};
|
||||
use anyhow::Result;
|
||||
use sysinfo::Disks;
|
||||
|
||||
@@ -43,11 +44,13 @@ impl WaybarModule for BtrfsModule {
|
||||
"normal"
|
||||
};
|
||||
|
||||
let text = config.pool.format
|
||||
.replace("{used:>4.0}", &format!("{:>4.0}", used_gb))
|
||||
.replace("{total:>4.0}", &format!("{:>4.0}", size_gb))
|
||||
.replace("{used}", &format!("{:.0}", used_gb))
|
||||
.replace("{total}", &format!("{:.0}", size_gb));
|
||||
let text = format_template(
|
||||
&config.pool.format,
|
||||
&[
|
||||
("used", TokenValue::Float(used_gb)),
|
||||
("total", TokenValue::Float(size_gb)),
|
||||
]
|
||||
);
|
||||
|
||||
Ok(WaybarOutput {
|
||||
text,
|
||||
|
||||
@@ -2,6 +2,7 @@ use crate::config::Config;
|
||||
use crate::modules::WaybarModule;
|
||||
use crate::output::WaybarOutput;
|
||||
use crate::state::SharedState;
|
||||
use crate::utils::{format_template, TokenValue};
|
||||
use anyhow::Result;
|
||||
use std::process::Command;
|
||||
|
||||
@@ -101,10 +102,14 @@ impl WaybarModule for BudsModule {
|
||||
_ => ("?", "anc-unknown"),
|
||||
};
|
||||
|
||||
let text = config.buds.format
|
||||
.replace("{left}", &left_display)
|
||||
.replace("{right}", &right_display)
|
||||
.replace("{anc}", anc_icon);
|
||||
let text = format_template(
|
||||
&config.buds.format,
|
||||
&[
|
||||
("left", TokenValue::String(&left_display)),
|
||||
("right", TokenValue::String(&right_display)),
|
||||
("anc", TokenValue::String(anc_icon)),
|
||||
]
|
||||
);
|
||||
|
||||
Ok(WaybarOutput {
|
||||
text,
|
||||
|
||||
@@ -2,6 +2,7 @@ use crate::config::Config;
|
||||
use crate::modules::WaybarModule;
|
||||
use crate::output::WaybarOutput;
|
||||
use crate::state::SharedState;
|
||||
use crate::utils::{format_template, TokenValue};
|
||||
use anyhow::Result;
|
||||
|
||||
pub struct CpuModule;
|
||||
@@ -20,11 +21,13 @@ impl WaybarModule for CpuModule {
|
||||
}
|
||||
};
|
||||
|
||||
let text = config.cpu.format
|
||||
.replace("{usage:>4.1}", &format!("{:>4.1}", usage))
|
||||
.replace("{temp:>4.1}", &format!("{:>4.1}", temp))
|
||||
.replace("{usage}", &format!("{:.1}", usage))
|
||||
.replace("{temp}", &format!("{:.1}", temp));
|
||||
let text = format_template(
|
||||
&config.cpu.format,
|
||||
&[
|
||||
("usage", TokenValue::Float(usage)),
|
||||
("temp", TokenValue::Float(temp)),
|
||||
]
|
||||
);
|
||||
|
||||
let class = if usage > 95.0 {
|
||||
"max"
|
||||
|
||||
@@ -2,6 +2,7 @@ use crate::config::Config;
|
||||
use crate::modules::WaybarModule;
|
||||
use crate::output::WaybarOutput;
|
||||
use crate::state::SharedState;
|
||||
use crate::utils::{format_template, TokenValue};
|
||||
use anyhow::Result;
|
||||
use sysinfo::Disks;
|
||||
|
||||
@@ -32,12 +33,14 @@ impl WaybarModule for DiskModule {
|
||||
"normal"
|
||||
};
|
||||
|
||||
let text = config.disk.format
|
||||
.replace("{mount}", mountpoint)
|
||||
.replace("{used:>5.1}", &format!("{:>5.1}", used_gb))
|
||||
.replace("{total:>5.1}", &format!("{:>5.1}", total_gb))
|
||||
.replace("{used}", &format!("{:.1}", used_gb))
|
||||
.replace("{total}", &format!("{:.1}", total_gb));
|
||||
let text = format_template(
|
||||
&config.disk.format,
|
||||
&[
|
||||
("mount", TokenValue::String(mountpoint)),
|
||||
("used", TokenValue::Float(used_gb)),
|
||||
("total", TokenValue::Float(total_gb)),
|
||||
]
|
||||
);
|
||||
|
||||
return Ok(WaybarOutput {
|
||||
text,
|
||||
|
||||
@@ -2,6 +2,7 @@ use crate::config::Config;
|
||||
use crate::modules::WaybarModule;
|
||||
use crate::output::WaybarOutput;
|
||||
use crate::state::SharedState;
|
||||
use crate::utils::{format_template, TokenValue};
|
||||
use anyhow::Result;
|
||||
|
||||
pub struct GpuModule;
|
||||
@@ -47,15 +48,15 @@ impl WaybarModule for GpuModule {
|
||||
_ => &config.gpu.format_amd,
|
||||
};
|
||||
|
||||
let text = format_str
|
||||
.replace("{usage:>3.0}", &format!("{:>3.0}", usage))
|
||||
.replace("{vram_used:>4.1}", &format!("{:>4.1}", vram_used))
|
||||
.replace("{vram_total:>4.1}", &format!("{:>4.1}", vram_total))
|
||||
.replace("{temp:>4.1}", &format!("{:>4.1}", temp))
|
||||
.replace("{usage}", &format!("{:.0}", usage))
|
||||
.replace("{vram_used}", &format!("{:.1}", vram_used))
|
||||
.replace("{vram_total}", &format!("{:.1}", vram_total))
|
||||
.replace("{temp}", &format!("{:.1}", temp));
|
||||
let text = format_template(
|
||||
format_str,
|
||||
&[
|
||||
("usage", TokenValue::Float(usage)),
|
||||
("vram_used", TokenValue::Float(vram_used)),
|
||||
("vram_total", TokenValue::Float(vram_total)),
|
||||
("temp", TokenValue::Float(temp)),
|
||||
]
|
||||
);
|
||||
|
||||
let tooltip = if vendor == "Intel" {
|
||||
format!("Model: {}\nApprox Usage: {:.0}%", model, usage)
|
||||
|
||||
@@ -2,6 +2,7 @@ use crate::config::Config;
|
||||
use crate::modules::WaybarModule;
|
||||
use crate::output::WaybarOutput;
|
||||
use crate::state::SharedState;
|
||||
use crate::utils::{format_template, TokenValue};
|
||||
use anyhow::Result;
|
||||
|
||||
pub struct MemoryModule;
|
||||
@@ -21,11 +22,13 @@ impl WaybarModule for MemoryModule {
|
||||
|
||||
let ratio = if total_gb > 0.0 { (used_gb / total_gb) * 100.0 } else { 0.0 };
|
||||
|
||||
let text = config.memory.format
|
||||
.replace("{used:>5.2}", &format!("{:>5.2}", used_gb))
|
||||
.replace("{total:>5.2}", &format!("{:>5.2}", total_gb))
|
||||
.replace("{used}", &format!("{:.2}", used_gb))
|
||||
.replace("{total}", &format!("{:.2}", total_gb));
|
||||
let text = format_template(
|
||||
&config.memory.format,
|
||||
&[
|
||||
("used", TokenValue::Float(used_gb)),
|
||||
("total", TokenValue::Float(total_gb)),
|
||||
]
|
||||
);
|
||||
|
||||
let class = if ratio > 95.0 {
|
||||
"max"
|
||||
|
||||
@@ -2,10 +2,10 @@ use crate::config::Config;
|
||||
use crate::modules::WaybarModule;
|
||||
use crate::output::WaybarOutput;
|
||||
use crate::state::SharedState;
|
||||
use crate::utils::{format_template, TokenValue};
|
||||
use anyhow::Result;
|
||||
use std::fs;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
use tracing::{debug, warn};
|
||||
|
||||
pub struct NetworkModule;
|
||||
|
||||
@@ -101,15 +101,15 @@ impl WaybarModule for NetworkModule {
|
||||
}
|
||||
};
|
||||
|
||||
let mut output_text = config
|
||||
.network
|
||||
.format
|
||||
.replace("{interface}", &interface)
|
||||
.replace("{ip}", &ip)
|
||||
.replace("{rx:>5.2}", &format!("{:>5.2}", rx_mbps))
|
||||
.replace("{tx:>5.2}", &format!("{:>5.2}", tx_mbps))
|
||||
.replace("{rx}", &format!("{:.2}", rx_mbps))
|
||||
.replace("{tx}", &format!("{:.2}", tx_mbps));
|
||||
let mut output_text = format_template(
|
||||
&config.network.format,
|
||||
&[
|
||||
("interface", TokenValue::String(&interface)),
|
||||
("ip", TokenValue::String(&ip)),
|
||||
("rx", TokenValue::Float(rx_mbps)),
|
||||
("tx", TokenValue::Float(tx_mbps)),
|
||||
]
|
||||
);
|
||||
|
||||
if interface.starts_with("tun")
|
||||
|| interface.starts_with("wg")
|
||||
|
||||
@@ -2,6 +2,7 @@ use crate::config::Config;
|
||||
use crate::modules::WaybarModule;
|
||||
use crate::output::WaybarOutput;
|
||||
use crate::state::SharedState;
|
||||
use crate::utils::{format_template, TokenValue};
|
||||
use anyhow::Result;
|
||||
use std::fs;
|
||||
|
||||
@@ -89,10 +90,13 @@ impl WaybarModule for PowerModule {
|
||||
)
|
||||
};
|
||||
|
||||
let text = config.power.format
|
||||
.replace("{percentage:>3}", &format!("{:>3}", percentage))
|
||||
.replace("{percentage}", &format!("{}", percentage))
|
||||
.replace("{icon}", icon);
|
||||
let text = format_template(
|
||||
&config.power.format,
|
||||
&[
|
||||
("percentage", TokenValue::Int(percentage as i64)),
|
||||
("icon", TokenValue::String(icon)),
|
||||
]
|
||||
);
|
||||
|
||||
Ok(WaybarOutput {
|
||||
text,
|
||||
|
||||
@@ -2,6 +2,7 @@ use crate::config::Config;
|
||||
use crate::modules::WaybarModule;
|
||||
use crate::output::WaybarOutput;
|
||||
use crate::state::SharedState;
|
||||
use crate::utils::{format_template, TokenValue};
|
||||
use anyhow::Result;
|
||||
|
||||
pub struct SysModule;
|
||||
@@ -30,14 +31,15 @@ impl WaybarModule for SysModule {
|
||||
format!("{}m", minutes)
|
||||
};
|
||||
|
||||
let text = config.sys.format
|
||||
.replace("{uptime}", &uptime_str)
|
||||
.replace("{load1:>4.2}", &format!("{:>4.2}", load1))
|
||||
.replace("{load5:>4.2}", &format!("{:>4.2}", load5))
|
||||
.replace("{load15:>4.2}", &format!("{:>4.2}", load15))
|
||||
.replace("{load1}", &format!("{:.2}", load1))
|
||||
.replace("{load5}", &format!("{:.2}", load5))
|
||||
.replace("{load15}", &format!("{:.2}", load15));
|
||||
let text = format_template(
|
||||
&config.sys.format,
|
||||
&[
|
||||
("uptime", TokenValue::String(&uptime_str)),
|
||||
("load1", TokenValue::Float(load1)),
|
||||
("load5", TokenValue::Float(load5)),
|
||||
("load15", TokenValue::Float(load15)),
|
||||
]
|
||||
);
|
||||
|
||||
Ok(WaybarOutput {
|
||||
text,
|
||||
|
||||
62
src/utils.rs
62
src/utils.rs
@@ -30,3 +30,65 @@ pub fn show_menu(prompt: &str, items: &[String], menu_cmd: &str) -> Result<Strin
|
||||
|
||||
Ok(selected)
|
||||
}
|
||||
|
||||
use regex::Regex;
|
||||
use std::sync::LazyLock;
|
||||
|
||||
pub enum TokenValue<'a> {
|
||||
Float(f64),
|
||||
Int(i64),
|
||||
String(&'a str),
|
||||
}
|
||||
|
||||
pub fn format_template(template: &str, values: &[(&str, TokenValue)]) -> String {
|
||||
static RE: LazyLock<Regex> = LazyLock::new(|| {
|
||||
Regex::new(r"\{([a-zA-Z0-9_]+)(?::([<>\^])?(\d+)?(?:\.(\d+))?)?\}").unwrap()
|
||||
});
|
||||
|
||||
RE.replace_all(template, |caps: ®ex::Captures| {
|
||||
let name = &caps[1];
|
||||
if let Some((_, val)) = values.iter().find(|(k, _)| *k == name) {
|
||||
let align = caps.get(2).map(|m| m.as_str()).unwrap_or(">");
|
||||
let width = caps.get(3).map(|m| m.as_str().parse::<usize>().unwrap_or(0)).unwrap_or(0);
|
||||
let precision = caps.get(4).map(|m| m.as_str().parse::<usize>().unwrap_or(0));
|
||||
|
||||
match val {
|
||||
TokenValue::Float(f) => format_float(*f, align, width, precision),
|
||||
TokenValue::Int(i) => format_int(*i, align, width),
|
||||
TokenValue::String(s) => format_str(s, align, width),
|
||||
}
|
||||
} else {
|
||||
caps[0].to_string()
|
||||
}
|
||||
}).into_owned()
|
||||
}
|
||||
|
||||
fn format_float(f: f64, align: &str, width: usize, precision: Option<usize>) -> String {
|
||||
match (align, precision) {
|
||||
("<", Some(p)) => format!("{:<width$.p$}", f, width=width, p=p),
|
||||
("^", Some(p)) => format!("{:^width$.p$}", f, width=width, p=p),
|
||||
(">", Some(p)) => format!("{:>width$.p$}", f, width=width, p=p),
|
||||
("<", None) => format!("{:<width$}", f, width=width),
|
||||
("^", None) => format!("{:^width$}", f, width=width),
|
||||
(">", None) => format!("{:>width$}", f, width=width),
|
||||
_ => format!("{}", f),
|
||||
}
|
||||
}
|
||||
|
||||
fn format_int(i: i64, align: &str, width: usize) -> String {
|
||||
match align {
|
||||
"<" => format!("{:<width$}", i, width=width),
|
||||
"^" => format!("{:^width$}", i, width=width),
|
||||
">" => format!("{:>width$}", i, width=width),
|
||||
_ => format!("{}", i),
|
||||
}
|
||||
}
|
||||
|
||||
fn format_str(s: &str, align: &str, width: usize) -> String {
|
||||
match align {
|
||||
"<" => format!("{:<width$}", s, width=width),
|
||||
"^" => format!("{:^width$}", s, width=width),
|
||||
">" => format!("{:>width$}", s, width=width),
|
||||
_ => format!("{}", s),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user