1
0
Fork 0
mirror of https://github.com/Zedfrigg/ironbar.git synced 2025-07-03 03:31:03 +02:00
ironbar/src/dynamic_string.rs

141 lines
4.1 KiB
Rust
Raw Normal View History

2022-12-11 21:31:45 +00:00
use crate::error;
use crate::script::{OutputStream, Script};
use gtk::prelude::*;
use indexmap::IndexMap;
use std::sync::{Arc, Mutex};
use tokio::spawn;
#[derive(Debug)]
2022-11-30 22:27:56 +00:00
enum DynamicStringSegment {
Static(String),
Dynamic(Script),
}
2022-12-11 21:31:45 +00:00
pub struct DynamicString;
2022-11-30 22:27:56 +00:00
impl DynamicString {
pub fn new<F>(input: &str, f: F) -> Self
where
F: FnMut(String) -> Continue + 'static,
{
let mut segments = vec![];
let mut chars = input.chars().collect::<Vec<_>>();
while !chars.is_empty() {
let char = &chars[..=1];
let (token, skip) = if let ['{', '{'] = char {
const SKIP_BRACKETS: usize = 4;
let str = chars
.iter()
.skip(2)
.enumerate()
.take_while(|(i, &c)| c != '}' && chars[i + 1] != '}')
.map(|(_, c)| c)
.collect::<String>();
let len = str.len();
(
2022-11-30 22:27:56 +00:00
DynamicStringSegment::Dynamic(Script::from(str.as_str())),
len + SKIP_BRACKETS,
)
} else {
let str = chars
.iter()
.enumerate()
.take_while(|(i, &c)| !(c == '{' && chars[i + 1] == '{'))
.map(|(_, c)| c)
.collect::<String>();
let len = str.len();
2022-11-30 22:27:56 +00:00
(DynamicStringSegment::Static(str), len)
};
assert_ne!(skip, 0);
segments.push(token);
chars.drain(..skip);
}
let label_parts = Arc::new(Mutex::new(IndexMap::new()));
let (tx, rx) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
for (i, segment) in segments.into_iter().enumerate() {
match segment {
2022-11-30 22:27:56 +00:00
DynamicStringSegment::Static(str) => {
label_parts
.lock()
2022-12-11 21:31:45 +00:00
.expect(error::ERR_MUTEX_LOCK)
.insert(i, str);
}
2022-11-30 22:27:56 +00:00
DynamicStringSegment::Dynamic(script) => {
let tx = tx.clone();
let label_parts = label_parts.clone();
spawn(async move {
script
.run(|(out, _)| {
if let OutputStream::Stdout(out) = out {
2022-12-11 21:31:45 +00:00
let mut label_parts =
label_parts.lock().expect(error::ERR_MUTEX_LOCK);
2022-11-30 22:27:56 +00:00
label_parts
// .lock()
// .expect("Failed to get lock on label parts")
.insert(i, out);
2022-11-30 22:27:56 +00:00
let string = label_parts
.iter()
.map(|(_, part)| part.as_str())
.collect::<String>();
2022-12-11 21:31:45 +00:00
tx.send(string).expect(error::ERR_CHANNEL_SEND);
}
})
.await;
});
}
}
}
2022-11-30 22:27:56 +00:00
// initialize
{
2022-11-30 22:27:56 +00:00
let label_parts = label_parts
.lock()
2022-12-11 21:31:45 +00:00
.expect(error::ERR_MUTEX_LOCK)
2022-11-30 22:27:56 +00:00
.iter()
.map(|(_, part)| part.as_str())
.collect::<String>();
2022-12-11 21:31:45 +00:00
tx.send(label_parts).expect(error::ERR_CHANNEL_SEND);
}
2022-11-30 22:27:56 +00:00
rx.attach(None, f);
2022-12-11 21:31:45 +00:00
Self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test() {
// TODO: see if we can run gtk tests in ci
if gtk::init().is_ok() {
let label = gtk::Label::new(None);
2022-11-30 22:27:56 +00:00
DynamicString::new(
"Uptime: {{1000:uptime -p | cut -d ' ' -f2-}}",
move |string| {
label.set_label(&string);
2022-11-30 22:27:56 +00:00
Continue(true)
},
);
}
}
}