i3status_rs/themes/
xresources.rs

1use log::debug;
2use regex::Regex;
3
4use std::collections::HashMap;
5use std::sync::LazyLock;
6
7use crate::errors::*;
8
9#[cfg(not(test))]
10use std::{env, path::PathBuf};
11
12#[cfg(not(test))]
13fn read_xresources() -> std::io::Result<String> {
14    let home = env::var("HOME").map_err(|_| std::io::Error::other("HOME env var was not set"))?;
15    let xresources = PathBuf::from(home + "/.Xresources");
16    debug!(".Xresources @ {:?}", xresources);
17    std::fs::read_to_string(xresources)
18}
19
20#[cfg(test)]
21use tests::read_xresources;
22
23static COLOR_REGEX: LazyLock<Regex> = LazyLock::new(|| {
24    Regex::new(r"^\s*\*(?<name>[^: ]+)\s*:\s*(?<color>#[a-f0-9]{6,8}).*$").unwrap()
25});
26
27static COLORS: LazyLock<Result<HashMap<String, String>, Error>> = LazyLock::new(|| {
28    let content = read_xresources().error("could not read .Xresources")?;
29    debug!(".Xresources content:\n{}", content);
30    Ok(HashMap::from_iter(content.lines().filter_map(|line| {
31        COLOR_REGEX
32            .captures(line)
33            .map(|caps| (caps["name"].to_string(), caps["color"].to_string()))
34    })))
35});
36
37pub fn get_color(name: &str) -> Result<Option<&String>, Error> {
38    COLORS
39        .as_ref()
40        .map(|cmap| cmap.get(name))
41        .map_err(Clone::clone)
42}
43
44#[cfg(test)]
45mod tests {
46    use super::*;
47    use std::io::Result;
48
49    #[allow(clippy::unnecessary_wraps)]
50    pub(crate) fn read_xresources() -> Result<String> {
51        static XRESOURCES: &str = "\
52        ! this is a comment\n\
53        \n\
54        *color4 : #feedda\n\
55    \n\
56        *background: #ee33aa99\n\
57        ";
58        Ok(XRESOURCES.to_string())
59    }
60
61    #[test]
62    fn test_reading_colors() {
63        let colors = COLORS.as_ref().unwrap();
64        assert_eq!(colors.get("color4"), Some(&"#feedda".to_string()));
65        assert_eq!(colors.get("background"), Some(&"#ee33aa99".to_string()));
66        assert_eq!(2, colors.len());
67    }
68
69    #[test]
70    fn test_deserializing_xcolors() {
71        use super::super::color::*;
72        let mut parsed_color = "x:color4".parse::<Color>().unwrap();
73        assert_eq!(
74            parsed_color,
75            Color::Rgba(Rgba {
76                r: 254,
77                g: 237,
78                b: 218,
79                a: 255
80            })
81        );
82        parsed_color = "x:background".parse::<Color>().unwrap();
83        assert_eq!(
84            parsed_color,
85            Color::Rgba(Rgba {
86                r: 238,
87                g: 51,
88                b: 170,
89                a: 153,
90            })
91        );
92    }
93}