cu_consolemon/
sysinfo.rs

1use libmacchina::{
2    traits::GeneralReadout as _, traits::KernelReadout as _, traits::MemoryReadout as _,
3    traits::PackageReadout as _, GeneralReadout, KernelReadout, MemoryReadout, PackageReadout,
4};
5
6use pfetch_logo_parser::{Color, Logo, LogoPart};
7use std::{env, fmt::Display, str::FromStr};
8
9#[derive(Debug, PartialEq)]
10pub enum PfetchInfo {
11    Ascii,
12    Title,
13    Os,
14    Host,
15    Kernel,
16    Uptime,
17    Cpu,
18    Memory,
19    Shell,
20    Editor,
21    Wm,
22    De,
23    Palette,
24    BlankLine,
25}
26
27impl Display for PfetchInfo {
28    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29        write!(f, "{}", format!("{self:?}").to_lowercase())
30    }
31}
32
33impl FromStr for PfetchInfo {
34    type Err = String;
35
36    fn from_str(info: &str) -> Result<Self, Self::Err> {
37        match info {
38            "ascii" => Ok(PfetchInfo::Ascii),
39            "title" => Ok(PfetchInfo::Title),
40            "os" => Ok(PfetchInfo::Os),
41            "host" => Ok(PfetchInfo::Host),
42            "kernel" => Ok(PfetchInfo::Kernel),
43            "uptime" => Ok(PfetchInfo::Uptime),
44            "cpu" => Ok(PfetchInfo::Cpu),
45            "memory" => Ok(PfetchInfo::Memory),
46            "shell" => Ok(PfetchInfo::Shell),
47            "editor" => Ok(PfetchInfo::Editor),
48            "wm" => Ok(PfetchInfo::Wm),
49            "de" => Ok(PfetchInfo::De),
50            "palette" => Ok(PfetchInfo::Palette),
51            unknown_info => Err(format!("Unknown pfetch info: {unknown_info}")),
52        }
53    }
54}
55
56// Struct for the various readouts
57pub struct Readouts {
58    pub general_readout: GeneralReadout,
59    pub package_readout: PackageReadout,
60    pub memory_readout: MemoryReadout,
61    pub kernel_readout: KernelReadout,
62}
63
64impl Default for Readouts {
65    fn default() -> Self {
66        Readouts {
67            general_readout: GeneralReadout::new(),
68            package_readout: PackageReadout::new(),
69            memory_readout: MemoryReadout::new(),
70            kernel_readout: KernelReadout::new(),
71        }
72    }
73}
74
75pub fn get_info(info: &PfetchInfo, readouts: &Readouts) -> Option<String> {
76    match info {
77        PfetchInfo::Ascii => None,
78        PfetchInfo::Title => pfetch::user_at_hostname(
79            &readouts.general_readout,
80            &dotenvy::var("USER").ok(),
81            &dotenvy::var("HOSTNAME").ok(),
82        ),
83        PfetchInfo::Os => pfetch::os(&readouts.general_readout),
84        PfetchInfo::Host => pfetch::host(&readouts.general_readout),
85        PfetchInfo::Kernel => pfetch::kernel(&readouts.kernel_readout),
86        PfetchInfo::Uptime => pfetch::uptime(&readouts.general_readout),
87        PfetchInfo::Cpu => pfetch::cpu(&readouts.general_readout),
88        PfetchInfo::Memory => pfetch::memory(&readouts.memory_readout),
89        PfetchInfo::Shell => pfetch::shell(&readouts.general_readout),
90        PfetchInfo::Editor => Some(env::var("EDITOR").unwrap_or_else(|_| "nvim".into())),
91        PfetchInfo::Wm => pfetch::wm(&readouts.general_readout),
92        PfetchInfo::De => pfetch::de(&readouts.general_readout),
93        PfetchInfo::Palette => Some("Color Palette".into()), // Simplified palette display
94        PfetchInfo::BlankLine => Some("".into()),
95    }
96}
97
98// Function to render the gathered info along with ASCII logo
99pub fn pfetch_info() -> String {
100    let readouts = Readouts::default();
101
102    let os = pfetch::os(&GeneralReadout::new()).unwrap_or_default();
103
104    let all_infos = [
105        PfetchInfo::Os,
106        PfetchInfo::Host,
107        PfetchInfo::Kernel,
108        PfetchInfo::Uptime,
109        PfetchInfo::Cpu,
110        PfetchInfo::Memory,
111        PfetchInfo::Shell,
112        PfetchInfo::Editor,
113        PfetchInfo::Wm,
114        PfetchInfo::De,
115    ];
116
117    let logo = pfetch::logo(&os);
118    let gathered_pfetch_info: Vec<(Color, String, String)> = all_infos
119        .iter()
120        .filter_map(|info| match info {
121            PfetchInfo::Os => Some((logo.primary_color, info.to_string(), os.clone())),
122            _ => get_info(info, &readouts).map(|info_str| match info {
123                PfetchInfo::Title => (logo.secondary_color, info_str, "".into()),
124                PfetchInfo::BlankLine => (logo.primary_color, "".into(), "".into()),
125                _ => (logo.primary_color, info.to_string(), info_str),
126            }),
127        })
128        .collect();
129
130    pfetch(gathered_pfetch_info, logo, true)
131}
132
133fn pfetch(info: Vec<(Color, String, String)>, logo: Logo, logo_enabled: bool) -> String {
134    let raw_logo = if logo_enabled {
135        logo.logo_parts
136            .iter()
137            .map(|LogoPart { content, .. }| content.as_ref())
138            .collect::<String>()
139    } else {
140        "".into()
141    };
142    let color_enabled = dotenvy::var("PF_COLOR").unwrap_or_default() != "0";
143    let logo = if color_enabled {
144        logo.to_string()
145    } else {
146        format!("{logo:#}")
147    };
148    let mut logo_lines = logo.lines();
149    let raw_logo_lines: Vec<_> = raw_logo.lines().collect();
150    let logo_width = raw_logo_lines
151        .iter()
152        .map(|line| line.chars().count())
153        .max()
154        .unwrap_or(0);
155    let line_amount = usize::max(raw_logo_lines.len(), info.len());
156
157    let info1_width = info
158        .iter()
159        .skip(1)
160        .map(|(_, line, _)| {
161            if line.starts_with("\x1b[4") {
162                // exclude palette from info1 width
163                0
164            } else {
165                line.len()
166            }
167        })
168        .max()
169        .unwrap_or(0);
170
171    let padding1 = match dotenvy::var("PF_PAD1") {
172        Ok(padding0) => padding0.parse::<usize>().unwrap_or(0),
173        Err(_) => 0,
174    };
175    let padding2 = match dotenvy::var("PF_PAD2") {
176        Ok(padding1) => padding1.parse::<usize>().unwrap_or(0),
177        Err(_) => 3,
178    };
179    let padding3 = match dotenvy::var("PF_PAD3") {
180        Ok(padding2) => padding2.parse::<usize>().unwrap_or(0),
181        Err(_) => 1,
182    };
183
184    let mut pfetch_str = String::new();
185
186    for l in 0..line_amount {
187        pfetch_str += &format!(
188            "{padding1}{bold}{logo}{padding2}{color}{info1}{nobold}{separator}{padding3}{color2}{info2}\n",
189            padding1 = " ".repeat(padding1),
190            bold = if color_enabled {"\x1b[1m"} else {""},
191            logo = if logo_enabled {
192                logo_lines.next().unwrap_or("")
193            } else {
194                ""
195            },
196            padding2 = " ".repeat(
197                logo_width - raw_logo_lines.get(l).map_or(0, |line| line.chars().count())
198                    + if logo_enabled { padding2 } else { 0 }
199            ),
200            color = if color_enabled {
201                info.get(l).map_or("".to_owned(), |line| {
202                    let (color, _, _) = line;
203                    color.to_string()
204                }
205                )
206            } else {
207                "".into()
208            },
209            info1 = info.get(l).map_or("", |line| &line.1),
210            nobold = if color_enabled {"\x1b[0m"} else {""},
211            separator = info.get(l).map_or("".into(), |line|
212                if ! &line.2.is_empty() {
213                    dotenvy::var("PF_SEP").unwrap_or_default()
214                } else { "".into() }
215            ),
216            padding3 = " ".repeat(
217                info1_width.saturating_sub(info.get(l).map_or(0, |(_, line, _)| line.len()))
218                    + padding3
219            ),
220            color2 = if color_enabled {match dotenvy::var("PF_COL2") {
221                Ok(newcolor) => {
222                    match Color::from_str(&newcolor) {
223                        Ok(newcolor) => format!("{newcolor}"),
224                        Err(_) => "".into(),
225                    }
226                },
227                Err(_) => "".into()
228            }} else {"".into()},
229            info2 = info.get(l).map_or("", |line| &line.2)
230        )
231    }
232
233    pfetch_str
234}