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