1use crate::cli::Cli;
2use crate::config::Config;
3use crate::fetch::SystemInfo;
4use crate::logo;
5use crate::theme::Theme;
6
7impl SystemInfo {
8 pub fn display(&self, cli: &Cli, _config: &Config) -> anyhow::Result<()> {
9 let theme_name = _config.theme.as_deref().or(cli.theme.as_deref());
10 let mut theme = match theme_name {
11 Some(name) => Theme::from_name(name),
12 None => Theme::detect_system_theme(), };
14
15 if let Some(custom) = &_config.custom_theme {
17 theme = Theme::with_custom_overrides(theme, custom);
18 }
19
20 let show_logo = _config.show_logo.unwrap_or(true) && !cli.no_logo;
21 if show_logo {
22 #[cfg(feature = "graphics")]
23 let mut printed_logo = false;
24 #[cfg(not(feature = "graphics"))]
25 let printed_logo = false;
26
27 if !cli.ascii_only {
28 let user_logo = if let Some(config_dir) = dirs::config_dir() {
30 let p = config_dir.join("retch").join("logo.png");
31 if p.exists() {
32 Some(p)
33 } else {
34 None
35 }
36 } else {
37 None
38 };
39
40 #[cfg(feature = "graphics")]
42 if !printed_logo && logo::supports_graphical_logo() {
43 if let Some(path) = &user_logo {
44 logo::print_graphical_logo_from_path(path);
45 printed_logo = true;
46 } else if let Some(distro) = logo::detect_distro() {
47 if let Some(bytes) = logo::get_embedded_logo(Some(&distro)) {
48 logo::print_graphical_logo(bytes);
49 printed_logo = true;
50 }
51 }
52 }
53
54 if !printed_logo && logo::chafa_available() {
56 if let Some(path) = &user_logo {
57 if logo::print_with_chafa(path) {
58 printed_logo = true;
59 }
60 } else if logo::detect_distro().is_some() {
61 }
64 }
65 }
66
67 if !printed_logo {
69 let distro_hint = logo::detect_distro();
70 logo::print_distro_logo_with_ascii(distro_hint.as_deref(), cli.ascii_only);
72 }
73 println!(); }
75
76 let allowed_fields: Option<Vec<String>> = if cli.long {
78 None } else if cli.short {
80 Some(vec![
81 "os".to_string(),
82 "kernel".to_string(),
83 "host".to_string(),
84 "cpu".to_string(),
85 "gpu".to_string(),
86 "memory".to_string(),
87 "disk".to_string(),
88 ])
89 } else if let Some(fields) = &_config.fields {
90 Some(fields.iter().map(|s| s.to_lowercase()).collect())
91 } else {
92 Some(vec![
94 "os".to_string(),
95 "kernel".to_string(),
96 "host".to_string(),
97 "cpu".to_string(),
98 "gpu".to_string(),
99 "memory".to_string(),
100 "swap".to_string(),
101 "load".to_string(),
102 "disk".to_string(),
103 "net".to_string(),
104 "uptime".to_string(),
105 ])
106 };
107
108 let should_show = |label: &str| -> bool {
109 match &allowed_fields {
110 Some(fields) => fields.contains(&label.to_lowercase()),
111 None => true,
112 }
113 };
114
115 let label_width = 10;
117 let print_line = |label: &str, value: &str| {
118 if should_show(label) {
119 println!(
120 "{:>width$}{} {}",
121 theme.color_label(label),
122 theme.color_separator(":"),
123 theme.color_value(value),
124 width = label_width
125 );
126 }
127 };
128
129 print_line("OS", &self.os);
130 if let Some(kernel) = &self.kernel {
131 print_line("Kernel", kernel);
132 }
133 if let Some(host) = &self.hostname {
134 print_line("Host", host);
135 }
136 if let Some(user) = &self.current_user {
137 print_line("User", user);
138 }
139 print_line("Arch", &self.arch);
140 print_line("CPU", &format!("{} ({} cores)", self.cpu, self.cpu_cores));
141 if let Some(freq) = &self.cpu_freq {
142 print_line("CPU Freq", freq);
143 }
144 if should_show("GPU") {
145 for gpu in &self.gpu {
146 print_line("GPU", gpu);
147 }
148 }
149 print_line("Memory", &self.memory);
150 print_line("Swap", &self.swap);
151 print_line("Procs", &self.processes.to_string());
152 if let Some(load) = &self.load_avg {
153 print_line("Load", load);
154 }
155
156 if should_show("Disk") {
157 for disk in &self.disks {
158 print_line("Disk", disk);
159 }
160 }
161
162 if should_show("Temp") {
163 for temp in &self.temps {
164 print_line("Temp", temp);
165 }
166 }
167
168 if should_show("Net") {
169 for net in &self.networks {
170 print_line("Net", net);
171 }
172 }
173
174 let uptime_str = format_uptime(&self.uptime);
176 let boot_display = format!("{} since {}", uptime_str, self.boot_time);
177 print_line("Uptime", &boot_display);
178
179 if let Some(bat) = &self.battery {
180 print_line("Battery", bat);
181 }
182
183 if let Some(shell) = &self.shell {
184 print_line("Shell", shell);
185 }
186 if let Some(term) = &self.terminal {
187 print_line("Terminal", term);
188 }
189 if let Some(de) = &self.desktop {
190 print_line("Desktop", de);
191 }
192 print_line("Users", &self.users.to_string());
193 if let Some(pkgs) = self.packages {
194 if pkgs > 0 {
195 print_line("Packages", &pkgs.to_string());
196 }
197 }
198
199 Ok(())
200 }
201}
202
203fn format_uptime(uptime: &str) -> String {
204 let seconds: u64 = uptime.trim_end_matches('s').parse().unwrap_or(0);
206
207 let years = seconds / (365 * 24 * 3600);
208 let days = (seconds % (365 * 24 * 3600)) / (24 * 3600);
209 let hours = (seconds % (24 * 3600)) / 3600;
210 let minutes = (seconds % 3600) / 60;
211 let secs = seconds % 60;
212
213 let mut parts = Vec::new();
214 if years > 0 {
215 parts.push(format!("{}y", years));
216 }
217 if days > 0 {
218 parts.push(format!("{}d", days));
219 }
220 if hours > 0 {
221 parts.push(format!("{}h", hours));
222 }
223 if minutes > 0 {
224 parts.push(format!("{}m", minutes));
225 }
226 if secs > 0 || parts.is_empty() {
227 parts.push(format!("{}s", secs));
228 }
229
230 parts.join(" ")
231}