oxwm

https://git.tonybtw.com/oxwm.git git://git.tonybtw.com/oxwm.git
1,967 bytes raw
1
use super::Block;
2
use crate::errors::BlockError;
3
use std::process::Command;
4
use std::time::{Duration, Instant};
5
6
pub struct ShellBlock {
7
    format: String,
8
    command: String,
9
    interval: Duration,
10
    color: u32,
11
    cached_output: Option<String>,
12
    last_run: Option<Instant>,
13
}
14
15
impl ShellBlock {
16
    pub fn new(format: &str, command: &str, interval_secs: u64, color: u32) -> Self {
17
        Self {
18
            format: format.to_string(),
19
            command: command.to_string(),
20
            interval: Duration::from_secs(interval_secs),
21
            color,
22
            cached_output: None,
23
            last_run: None,
24
        }
25
    }
26
27
    fn execute(&mut self) -> Result<String, BlockError> {
28
        let output = Command::new("sh")
29
            .arg("-c")
30
            .arg(&self.command)
31
            .output()
32
            .map_err(|e| BlockError::CommandFailed(format!("Failed to execute command: {}", e)))?;
33
34
        if !output.status.success() {
35
            return Err(BlockError::CommandFailed(format!(
36
                "Command exited with status: {}",
37
                output.status
38
            )));
39
        }
40
41
        let result = String::from_utf8_lossy(&output.stdout).trim().to_string();
42
        let formatted = self.format.replace("{}", &result);
43
44
        self.cached_output = Some(formatted.clone());
45
        self.last_run = Some(Instant::now());
46
47
        Ok(formatted)
48
    }
49
}
50
51
impl Block for ShellBlock {
52
    fn content(&mut self) -> Result<String, BlockError> {
53
        let should_refresh = match self.last_run {
54
            None => true,
55
            Some(last) => last.elapsed() >= self.interval,
56
        };
57
58
        if should_refresh {
59
            return self.execute();
60
        }
61
62
        self.cached_output
63
            .clone()
64
            .ok_or_else(|| BlockError::CommandFailed("No cached output".to_string()))
65
    }
66
67
    fn interval(&self) -> Duration {
68
        self.interval
69
    }
70
71
    fn color(&self) -> u32 {
72
        self.color
73
    }
74
}