mirror of
https://mzte.de/git/LordMZTE/dotfiles.git
synced 2024-12-14 10:53:42 +01:00
add custom i3status
This commit is contained in:
parent
3d69167fdb
commit
42fa35e223
7 changed files with 261 additions and 0 deletions
2
i3status/.gitignore
vendored
Normal file
2
i3status/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
target
|
||||||
|
Cargo.lock
|
19
i3status/Cargo.toml
Normal file
19
i3status/Cargo.toml
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
[package]
|
||||||
|
name = "i3status"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
heim = "0.0.11"
|
||||||
|
serde_json = "1.0.66"
|
||||||
|
chrono = "0.4.19"
|
||||||
|
|
||||||
|
[dependencies.serde]
|
||||||
|
version = "1.0.127"
|
||||||
|
features = ["derive"]
|
||||||
|
|
||||||
|
[dependencies.tokio]
|
||||||
|
version = "1.9.0"
|
||||||
|
features = ["macros", "rt-multi-thread", "time", "sync", "process"]
|
3
i3status/README.md
Normal file
3
i3status/README.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# i3status
|
||||||
|
custom i3status replacement.
|
||||||
|
to use with my config, build this and move it to `~/.config/i3/i3status`
|
11
i3status/src/colors.rs
Normal file
11
i3status/src/colors.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#![allow(dead_code)]
|
||||||
|
pub const CYAN: &str = "#8be9fd";
|
||||||
|
pub const GREEN: &str = "#50fa7b";
|
||||||
|
pub const GREY: &str = "#6272a4";
|
||||||
|
pub const ORANGE: &str = "#ffb86c";
|
||||||
|
pub const PINK: &str = "#ff79c6";
|
||||||
|
pub const PURPLE: &str = "#bd93f9";
|
||||||
|
pub const RED: &str = "#ff5555";
|
||||||
|
pub const WHITE: &str = "#f8f8f2";
|
||||||
|
pub const YELLOW: &str = "#f1fa8c";
|
||||||
|
|
7
i3status/src/json.rs
Normal file
7
i3status/src/json.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
use serde::Serialize;
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
pub struct Block {
|
||||||
|
pub full_text: String,
|
||||||
|
// this is always a const color string, so this is fine for now
|
||||||
|
pub color: &'static str,
|
||||||
|
}
|
65
i3status/src/main.rs
Normal file
65
i3status/src/main.rs
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
use std::{sync::Arc, time::Duration};
|
||||||
|
use tokio::sync::RwLock;
|
||||||
|
|
||||||
|
use crate::json::Block;
|
||||||
|
|
||||||
|
mod colors;
|
||||||
|
mod json;
|
||||||
|
mod workers;
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
let mut int = tokio::time::interval(Duration::from_millis(100));
|
||||||
|
let bar = Arc::new(RwLock::new(Bar::default()));
|
||||||
|
|
||||||
|
spawn_workers(Arc::clone(&bar)).await;
|
||||||
|
|
||||||
|
println!("{}\n[[]", r#"{ "version": 1 }"#);
|
||||||
|
loop {
|
||||||
|
int.tick().await;
|
||||||
|
let bar = bar.read().await;
|
||||||
|
|
||||||
|
let blocks = vec![
|
||||||
|
Block {
|
||||||
|
full_text: format!("龍 {:>7}", &bar.cpu_freq),
|
||||||
|
color: colors::CYAN,
|
||||||
|
},
|
||||||
|
Block {
|
||||||
|
full_text: format!(" {}", &bar.ram),
|
||||||
|
color: colors::PURPLE,
|
||||||
|
},
|
||||||
|
Block {
|
||||||
|
full_text: format!("{:>5}", &bar.vol),
|
||||||
|
color: colors::ORANGE,
|
||||||
|
},
|
||||||
|
Block {
|
||||||
|
full_text: format!("{:>5}", &bar.battery),
|
||||||
|
color: colors::GREEN,
|
||||||
|
},
|
||||||
|
Block {
|
||||||
|
full_text: bar.time.clone(),
|
||||||
|
color: colors::WHITE,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
let json = serde_json::to_string(&blocks).expect("failed to create json");
|
||||||
|
println!(",{}", json);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn spawn_workers(bar: Arc<RwLock<Bar>>) {
|
||||||
|
tokio::spawn(workers::ram(Arc::clone(&bar)));
|
||||||
|
tokio::spawn(workers::time(Arc::clone(&bar)));
|
||||||
|
tokio::spawn(workers::pulseaudio_vol(Arc::clone(&bar)));
|
||||||
|
tokio::spawn(workers::cpu_freq(Arc::clone(&bar)));
|
||||||
|
tokio::spawn(workers::battery(Arc::clone(&bar)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct Bar {
|
||||||
|
ram: String,
|
||||||
|
time: String,
|
||||||
|
vol: String,
|
||||||
|
cpu_freq: String,
|
||||||
|
battery: String,
|
||||||
|
}
|
154
i3status/src/workers.rs
Normal file
154
i3status/src/workers.rs
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
use crate::Bar;
|
||||||
|
use chrono::Local;
|
||||||
|
use heim::units::frequency::megahertz;
|
||||||
|
use heim::{memory::os::linux::MemoryExt, units::information::megabyte};
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::time::Duration;
|
||||||
|
use tokio::process::Command;
|
||||||
|
use tokio::sync::RwLock;
|
||||||
|
|
||||||
|
pub(crate) async fn ram(bar: Arc<RwLock<Bar>>) {
|
||||||
|
let mut int = tokio::time::interval(Duration::from_secs(1));
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let mem = heim::memory::memory().await;
|
||||||
|
let ram;
|
||||||
|
if let Ok(mem) = mem {
|
||||||
|
ram = format!(
|
||||||
|
"{}MB/{}MB",
|
||||||
|
mem.used().get::<megabyte>(),
|
||||||
|
mem.free().get::<megabyte>()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
ram = String::from("error reading ram :(");
|
||||||
|
}
|
||||||
|
bar.write().await.ram = ram;
|
||||||
|
int.tick().await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn time(bar: Arc<RwLock<Bar>>) {
|
||||||
|
let mut int = tokio::time::interval(Duration::from_millis(200));
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let time = Local::now().format("%a %d.%m.%Y %T").to_string();
|
||||||
|
|
||||||
|
bar.write().await.time = time;
|
||||||
|
int.tick().await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn pulseaudio_vol(bar: Arc<RwLock<Bar>>) {
|
||||||
|
let mut int = tokio::time::interval(Duration::from_secs(2));
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let res = Command::new("pactl")
|
||||||
|
.arg("get-sink-volume")
|
||||||
|
.arg("@DEFAULT_SINK@")
|
||||||
|
.output()
|
||||||
|
.await
|
||||||
|
.ok()
|
||||||
|
.and_then(|o| String::from_utf8(o.stdout).ok());
|
||||||
|
|
||||||
|
let mute = Command::new("pactl")
|
||||||
|
.arg("get-sink-mute")
|
||||||
|
.arg("@DEFAULT_SINK@")
|
||||||
|
.output()
|
||||||
|
.await
|
||||||
|
.map(|o| o.stdout.contains(&b'y'))
|
||||||
|
.unwrap_or(false);
|
||||||
|
|
||||||
|
let msg;
|
||||||
|
|
||||||
|
match res {
|
||||||
|
Some(out) => {
|
||||||
|
// get first line
|
||||||
|
let out = out.lines().next().unwrap_or(&out);
|
||||||
|
let volumes = out
|
||||||
|
.split(' ')
|
||||||
|
.filter(|s| s.contains('%'))
|
||||||
|
.map(|s| s.trim().replace('%', "").parse::<u8>())
|
||||||
|
.collect::<Result<Vec<_>, _>>()
|
||||||
|
.unwrap_or_else(|_| vec![]);
|
||||||
|
|
||||||
|
let mut avg = 0u8;
|
||||||
|
for v in &volumes {
|
||||||
|
avg += v / volumes.len() as u8;
|
||||||
|
}
|
||||||
|
|
||||||
|
let symbol = if mute { '遼' } else { '蓼' };
|
||||||
|
|
||||||
|
msg = format!("{} {}%", symbol, avg);
|
||||||
|
}
|
||||||
|
None => msg = String::from("PA Error :("),
|
||||||
|
}
|
||||||
|
|
||||||
|
bar.write().await.vol = msg;
|
||||||
|
int.tick().await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn cpu_freq(bar: Arc<RwLock<Bar>>) {
|
||||||
|
let mut int = tokio::time::interval(Duration::from_secs(2));
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let freq = heim::cpu::frequency().await;
|
||||||
|
let txt;
|
||||||
|
if let Ok(freq) = freq {
|
||||||
|
let freq = freq.current().get::<megahertz>();
|
||||||
|
txt = format!("{}MHz", freq);
|
||||||
|
} else {
|
||||||
|
txt = String::from("Error reading CPU frequency :(");
|
||||||
|
}
|
||||||
|
bar.write().await.cpu_freq = txt;
|
||||||
|
int.tick().await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn battery(bar: Arc<RwLock<Bar>>) {
|
||||||
|
enum BatteryState {
|
||||||
|
Charging,
|
||||||
|
Discharging,
|
||||||
|
NotCharging,
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut int = tokio::time::interval(Duration::from_secs(10));
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let out = Command::new("acpi")
|
||||||
|
.output()
|
||||||
|
.await
|
||||||
|
.ok()
|
||||||
|
.and_then(|o| String::from_utf8(o.stdout).ok());
|
||||||
|
|
||||||
|
let txt;
|
||||||
|
if let Some(s) = out {
|
||||||
|
if let Some(bat) = s.lines().next() {
|
||||||
|
let percent = bat.split(' ').find(|s| s.contains('%')).unwrap_or("0%");
|
||||||
|
let state = if bat.contains("Charging") {
|
||||||
|
BatteryState::Charging
|
||||||
|
} else if bat.contains("Discharging") {
|
||||||
|
BatteryState::Discharging
|
||||||
|
} else {
|
||||||
|
BatteryState::NotCharging
|
||||||
|
};
|
||||||
|
|
||||||
|
let icon = match state {
|
||||||
|
BatteryState::Charging => '',
|
||||||
|
BatteryState::Discharging => '',
|
||||||
|
BatteryState::NotCharging => '',
|
||||||
|
};
|
||||||
|
|
||||||
|
txt = format!("{} {}", icon, percent);
|
||||||
|
} else {
|
||||||
|
txt = String::from("No bat")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
txt = String::from("Battery Error :(");
|
||||||
|
}
|
||||||
|
|
||||||
|
bar.write().await.battery = txt;
|
||||||
|
int.tick().await;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue