catfood-bar 0.3.0

A system bar component of the catfood utility suite
Documentation
use crate::logging;
use ratatui::{prelude::Stylize, style::Color, text::Span};
use regex::Regex;
use std::process::Command;

static BRIGHTNESS_REGEX: std::sync::LazyLock<Regex> =
    std::sync::LazyLock::new(|| Regex::new(r"\d+%").unwrap());

#[derive(Debug)]
pub struct Brightness {
    pub level: String,
    cached_span_content: String,
}

impl Default for Brightness {
    fn default() -> Self {
        Self::new()
    }
}

impl Brightness {
    pub fn new() -> Self {
        let level = get_system_brightness().unwrap_or_default();
        let cached_span_content = format!("󰃠 {}", level);
        Self {
            level,
            cached_span_content,
        }
    }

    pub fn update(&mut self) {
        self.level = get_system_brightness().unwrap_or_default();
        self.cached_span_content = format!("󰃠 {}", self.level);
    }

    pub fn render_as_spans(&self, colorize: bool) -> Vec<Span<'_>> {
        let span = Span::raw(&self.cached_span_content);
        if colorize {
            vec![span.fg(Color::White)]
        } else {
            vec![span]
        }
    }
}

fn get_system_brightness() -> Option<String> {
    let output = Command::new("brightnessctl")
        .output()
        .expect("failed to get brightness");

    if output.status.success() {
        let brightness_str = str::from_utf8(&output.stdout).unwrap();

        let re = &BRIGHTNESS_REGEX;

        if let Some(brightness) = re.find(brightness_str).map(|m| m.as_str()) {
            return Some(brightness.to_string());
        }

        logging::log_component_error(
            "BRIGHTNESS",
            &format!("Failed to parse brightness from output: {}", brightness_str),
        );
    } else {
        logging::log_component_error(
            "BRIGHTNESS",
            str::from_utf8(&output.stderr).unwrap_or("unknown error"),
        );
    }

    None
}