1#[cfg(feature = "graphics")]
21pub fn get_embedded_logo(distro: Option<&str>) -> Option<&'static [u8]> {
22 let d = distro.map(|s| s.to_lowercase());
23 match d.as_deref() {
24 Some("arch") => Some(include_bytes!("../assets/logos/arch.png")),
25 Some("debian") => Some(include_bytes!("../assets/logos/debian.png")),
26 Some("fedora") => Some(include_bytes!("../assets/logos/fedora.png")),
27 Some("nixos") => Some(include_bytes!("../assets/logos/nixos.png")),
28 Some("ubuntu") => Some(include_bytes!("../assets/logos/ubuntu.png")),
29 Some("pop") => Some(include_bytes!("../assets/logos/pop.png")),
30 Some("manjaro") => Some(include_bytes!("../assets/logos/manjaro.png")),
31 Some("endeavouros") => Some(include_bytes!("../assets/logos/endeavouros.png")),
32 Some("opensuse") | Some("opensuse-leap") | Some("opensuse-tumbleweed") => {
33 Some(include_bytes!("../assets/logos/opensuse.png"))
34 }
35 Some("mx") => Some(include_bytes!("../assets/logos/mx.png")),
36 Some("linuxmint") => Some(include_bytes!("../assets/logos/linuxmint.png")),
37 Some("kali") => Some(include_bytes!("../assets/logos/kali.png")),
38 Some("zorin") => Some(include_bytes!("../assets/logos/zorin.png")),
39 Some("garuda") => Some(include_bytes!("../assets/logos/garuda.png")),
40 Some("macos") => Some(include_bytes!("../assets/logos/macos.png")),
41 Some("windows") => Some(include_bytes!("../assets/logos/windows.png")),
42 _ => Some(include_bytes!("../assets/logos/tux.png")),
43 }
44}
45
46#[cfg(not(feature = "graphics"))]
48pub fn get_embedded_logo(_distro: Option<&str>) -> Option<&'static [u8]> {
49 Some(include_bytes!("../assets/logos/tux.png"))
50}
51
52pub fn detect_distro() -> Option<String> {
54 #[cfg(target_os = "macos")]
55 {
56 Some("macos".to_string())
57 }
58 #[cfg(target_os = "windows")]
59 {
60 Some("windows".to_string())
61 }
62 #[cfg(not(any(target_os = "macos", target_os = "windows")))]
63 {
64 if let Ok(content) = std::fs::read_to_string("/etc/os-release") {
65 for line in content.lines() {
66 if line.starts_with("ID=") {
67 let id = line.trim_start_matches("ID=").trim_matches('"');
68 return Some(id.to_string());
69 }
70 }
71 }
72 None
73 }
74}
75
76pub fn get_ascii_logo(distro: Option<&str>) -> Vec<String> {
80 let d = distro.map(|s| s.to_lowercase());
81
82 match d.as_deref() {
83 Some("arch") => {
84 let logo = include_str!("../assets/logos/arch.txt");
85 logo.lines().map(|s| s.to_string()).collect()
86 }
87 Some("debian") => {
88 let logo = include_str!("../assets/logos/debian.txt");
89 logo.lines().map(|s| s.to_string()).collect()
90 }
91 Some("fedora") => {
92 let logo = include_str!("../assets/logos/fedora.txt");
93 logo.lines().map(|s| s.to_string()).collect()
94 }
95 Some("nixos") => {
96 let logo = include_str!("../assets/logos/nixos.txt");
97 logo.lines().map(|s| s.to_string()).collect()
98 }
99 Some("ubuntu") => {
100 let logo = include_str!("../assets/logos/ubuntu.txt");
101 logo.lines().map(|s| s.to_string()).collect()
102 }
103 Some("pop") => {
104 let logo = include_str!("../assets/logos/pop.txt");
105 logo.lines().map(|s| s.to_string()).collect()
106 }
107 Some("manjaro") => {
108 let logo = include_str!("../assets/logos/manjaro.txt");
109 logo.lines().map(|s| s.to_string()).collect()
110 }
111 Some("endeavouros") => {
112 let logo = include_str!("../assets/logos/endeavouros.txt");
113 logo.lines().map(|s| s.to_string()).collect()
114 }
115 Some("opensuse") | Some("opensuse-leap") | Some("opensuse-tumbleweed") => {
116 let logo = include_str!("../assets/logos/opensuse.txt");
117 logo.lines().map(|s| s.to_string()).collect()
118 }
119 Some("mx") => {
120 let logo = include_str!("../assets/logos/mx.txt");
121 logo.lines().map(|s| s.to_string()).collect()
122 }
123 Some("linuxmint") => {
124 let logo = include_str!("../assets/logos/linuxmint.txt");
125 logo.lines().map(|s| s.to_string()).collect()
126 }
127 Some("kali") => {
128 let logo = include_str!("../assets/logos/kali.txt");
129 logo.lines().map(|s| s.to_string()).collect()
130 }
131 Some("zorin") => {
132 let logo = include_str!("../assets/logos/zorin.txt");
133 logo.lines().map(|s| s.to_string()).collect()
134 }
135 Some("garuda") => {
136 let logo = include_str!("../assets/logos/garuda.txt");
137 logo.lines().map(|s| s.to_string()).collect()
138 }
139 Some("macos") => {
140 let logo = include_str!("../assets/logos/macos.txt");
141 logo.lines().map(|s| s.to_string()).collect()
142 }
143 Some("windows") => {
144 let logo = include_str!("../assets/logos/windows.txt");
145 logo.lines().map(|s| s.to_string()).collect()
146 }
147
148 _ => {
150 let logo = include_str!("../assets/logos/tux.txt");
151 logo.lines().map(|s| s.to_string()).collect()
152 }
153 }
154}
155
156pub fn get_distro_colors(distro: Option<&str>) -> Vec<&'static str> {
158 let d = distro.map(|s| s.to_lowercase());
159 match d.as_deref() {
160 Some("arch") => vec!["\x1b[36m", "\x1b[37m"],
161 Some("debian") => vec!["\x1b[31m", "\x1b[37m"],
162 Some("fedora") => vec!["\x1b[34m", "\x1b[37m"],
163 Some("nixos") => vec![
164 "\x1b[34m", "\x1b[36m", "\x1b[34m", "\x1b[36m", "\x1b[34m", "\x1b[36m",
165 ],
166 Some("ubuntu") => vec!["\x1b[33m", "\x1b[31m"],
167 Some("pop") => vec!["\x1b[36m", "\x1b[37m"],
168 Some("manjaro") => vec!["\x1b[32m"],
169 Some("endeavouros") => vec!["\x1b[35m", "\x1b[31m", "\x1b[34m"],
170 Some("opensuse") | Some("opensuse-leap") | Some("opensuse-tumbleweed") => {
171 vec!["\x1b[32m", "\x1b[37m"]
172 }
173 Some("mx") => vec!["\x1b[34m", "\x1b[37m"],
174 Some("linuxmint") => vec!["\x1b[32m", "\x1b[37m"],
175 Some("kali") => vec!["\x1b[34m", "\x1b[37m"],
176 Some("zorin") => vec!["\x1b[36m", "\x1b[37m"],
177 Some("garuda") => vec!["\x1b[35m", "\x1b[36m"],
178 Some("macos") => vec![
181 "\x1b[38;5;252m",
182 "\x1b[38;5;250m",
183 "\x1b[38;5;248m",
184 "\x1b[38;5;246m",
185 "\x1b[38;5;244m",
186 ],
187 Some("windows") => vec!["\x1b[36m"],
188 _ => vec!["\x1b[30m", "\x1b[37m", "\x1b[33m"], }
190}
191
192pub fn get_distro_logo_lines(distro: Option<&str>) -> Vec<String> {
194 let raw_lines = get_ascii_logo(distro);
195 let colors = get_distro_colors(distro);
196 let default_color = colors.first().copied().unwrap_or("\x1b[0m");
197
198 raw_lines
199 .into_iter()
200 .map(|line| {
201 let mut formatted = line;
202 for i in 1..=9 {
203 let color_val = colors.get(i - 1).copied().unwrap_or("\x1b[0m");
204 let placeholder = format!("${{{}}}", i);
205 formatted = formatted.replace(&placeholder, color_val);
206 let placeholder_short = format!("${}", i);
207 formatted = formatted.replace(&placeholder_short, color_val);
208 }
209 if !formatted.is_empty() {
210 format!("{}{}\x1b[0m", default_color, formatted)
211 } else {
212 formatted
213 }
214 })
215 .collect()
216}
217
218pub fn supports_kitty() -> bool {
220 std::env::var("TERM")
221 .map(|t| t == "xterm-kitty")
222 .unwrap_or(false)
223 || std::env::var("TERMINAL_EMULATOR")
224 .map(|t| t == "iterm-kitty" || t == "iTerm.app")
225 .unwrap_or(false)
226 || std::env::var("TERM_PROGRAM")
227 .map(|t| t == "rio")
228 .unwrap_or(false)
229}
230
231pub fn supports_iterm2() -> bool {
233 if let Ok(prog) = std::env::var("TERM_PROGRAM") {
234 if prog == "iTerm.app" || prog == "WezTerm" || prog == "rio" {
235 return true;
236 }
237 }
238 false
239}
240
241pub fn supports_sixel() -> bool {
243 if let Ok(term) = std::env::var("TERM") {
244 let term = term.to_lowercase();
245 if term.contains("sixel") || term.contains("foot") || term.contains("mlterm") {
246 return true;
247 }
248 }
249
250 if let Ok(prog) = std::env::var("TERM_PROGRAM") {
251 if prog == "WezTerm" || prog == "iTerm.app" || prog == "rio" {
252 return true;
253 }
254 }
255
256 if std::env::var("WT_SESSION").is_ok() {
257 return true;
258 }
259
260 false
261}
262
263static CHAFA_SUPPORTS_PROBE: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
264
265pub fn chafa_supports_probe() -> bool {
267 *CHAFA_SUPPORTS_PROBE.get_or_init(|| {
268 std::process::Command::new("chafa")
269 .args(["--probe", "off", "--version"])
270 .output()
271 .map(|o| o.status.success())
272 .unwrap_or(false)
273 })
274}
275
276pub fn chafa_available() -> bool {
278 std::process::Command::new("chafa")
279 .arg("--version")
280 .output()
281 .map(|o| o.status.success())
282 .unwrap_or(false)
283}
284
285fn write_temp_logo(bytes: &[u8]) -> std::io::Result<std::path::PathBuf> {
287 let temp_path = std::env::temp_dir().join(format!("retch_logo_{}.png", std::process::id()));
288 std::fs::write(&temp_path, bytes)?;
289 Ok(temp_path)
290}
291
292pub fn print_with_chafa(path: &std::path::Path) -> bool {
297 let mut cmd = std::process::Command::new("chafa");
298 cmd.arg("--format")
299 .arg("symbols")
300 .arg("--size")
301 .arg("28x10");
302
303 if chafa_supports_probe() {
304 cmd.arg("--probe").arg("off");
305 }
306
307 let output = cmd.arg(path).output();
308
309 match output {
310 Ok(out) if out.status.success() => {
311 print!("{}", String::from_utf8_lossy(&out.stdout));
312 true
313 }
314 Ok(out) => {
315 eprintln!("warning: chafa failed with status: {}", out.status);
316 false
317 }
318 Err(e) => {
319 eprintln!("warning: failed to execute chafa: {}", e);
320 false
321 }
322 }
323}
324
325pub fn get_chafa_logo_lines(path: &std::path::Path) -> Option<Vec<String>> {
327 let mut cmd = std::process::Command::new("chafa");
328 cmd.arg("--format")
329 .arg("symbols")
330 .arg("--size")
331 .arg("28x10");
332
333 if chafa_supports_probe() {
334 cmd.arg("--probe").arg("off");
335 }
336
337 let output = cmd.arg(path).output().ok()?;
338 if output.status.success() {
339 let content = String::from_utf8_lossy(&output.stdout);
340 Some(content.lines().map(|s| s.to_string()).collect())
341 } else {
342 None
343 }
344}
345
346pub fn print_distro_logo(distro: Option<&str>) {
351 print_distro_logo_with_ascii(distro, false, false);
352}
353
354pub fn print_distro_logo_with_ascii(distro: Option<&str>, ascii_only: bool, chafa_only: bool) {
362 if ascii_only {
363 let art = get_distro_logo_lines(distro);
365 for line in art {
366 println!("{}", line);
367 }
368 return;
369 }
370
371 let has_chafa = chafa_available();
372
373 if !chafa_only {
374 let supports_kitty = supports_kitty();
375 let supports_iterm2 = supports_iterm2();
376 let supports_sixel = supports_sixel();
377
378 #[cfg(feature = "graphics")]
380 if supports_kitty {
381 if let Some(bytes) = get_embedded_logo(distro) {
382 if !bytes.is_empty() {
383 print_graphical_logo(bytes);
384 return;
385 }
386 }
387 }
388
389 #[cfg(feature = "graphics")]
391 if supports_iterm2 {
392 if let Some(bytes) = get_embedded_logo(distro) {
393 if !bytes.is_empty() {
394 print_iterm2_logo(bytes);
395 return;
396 }
397 }
398 }
399
400 #[cfg(feature = "graphics")]
402 if supports_sixel {
403 if let Some(bytes) = get_embedded_logo(distro) {
404 if !bytes.is_empty() {
405 print_sixel_logo(bytes);
406 return;
407 }
408 }
409 }
410 }
411
412 if has_chafa {
414 if let Some(bytes) = get_embedded_logo(distro) {
415 if bytes.len() > 100 {
416 if let Ok(temp_path) = write_temp_logo(bytes) {
417 if print_with_chafa(&temp_path) {
418 let _ = std::fs::remove_file(&temp_path);
419 return;
420 }
421 let _ = std::fs::remove_file(&temp_path);
422 }
423 }
424 }
425 }
426
427 let art = get_distro_logo_lines(distro);
429 for line in art {
430 println!("{}", line);
431 }
432}
433
434#[cfg(feature = "graphics")]
436pub fn print_iterm2_logo(image_data: &[u8]) {
437 use base64::Engine;
438 let encoded = base64::engine::general_purpose::STANDARD.encode(image_data);
439 print!(
440 "\x1b]1337;File=inline=1;height=10;preserveAspectRatio=1:{}\x07",
441 encoded
442 );
443 println!(); }
445
446#[cfg(feature = "graphics")]
448pub fn print_iterm2_logo_from_path(path: &std::path::Path) {
449 if let Ok(bytes) = std::fs::read(path) {
450 print_iterm2_logo(&bytes);
451 } else {
452 println!("[Could not read logo for iTerm2 from {}]", path.display());
453 }
454}
455
456#[cfg(not(feature = "graphics"))]
458pub fn print_iterm2_logo(_image_data: &[u8]) {
459 println!("[iTerm2 logo support requires --features graphics]");
460}
461
462#[cfg(feature = "graphics")]
464pub fn print_graphical_logo(image_data: &[u8]) {
465 use base64::Engine;
466
467 let (width, height) = image::load_from_memory(image_data)
468 .map(|img| (img.width(), img.height()))
469 .unwrap_or((0, 0));
470
471 let encoded = base64::engine::general_purpose::STANDARD.encode(image_data);
472
473 if width > 0 && height > 0 {
474 println!(
475 "\x1b_Gf=100,s={},v={},c=26,r=10,a=T;{}\x1b\\",
476 width, height, encoded
477 );
478 } else {
479 println!("\x1b_Gf=100,a=T;{}", encoded);
480 }
481}
482
483#[cfg(feature = "graphics")]
485pub fn print_sixel_logo(image_data: &[u8]) {
486 if let Ok(img) = image::load_from_memory(image_data) {
487 let resized = img.resize(240, 200, image::imageops::FilterType::Triangle);
488 let rgba = resized.to_rgba8();
489 let (width, height) = rgba.dimensions();
490 print_sixel_rgba(rgba.as_raw(), width, height);
491 }
492}
493
494#[cfg(feature = "graphics")]
496pub fn print_sixel_rgba(rgba: &[u8], width: u32, height: u32) {
497 use icy_sixel::SixelImage;
498
499 match SixelImage::try_from_rgba(rgba.to_vec(), width as usize, height as usize) {
500 Ok(sixel_img) => match sixel_img.encode() {
501 Ok(sixel_str) => {
502 print!("{}", sixel_str);
503 }
504 Err(e) => eprintln!("[Sixel Encoding Error: {}]", e),
505 },
506 Err(e) => eprintln!("[Sixel Creation Error: {}]", e),
507 }
508}
509
510#[cfg(not(feature = "graphics"))]
512pub fn print_graphical_logo(_image_data: &[u8]) {
513 println!("[Graphical logo support requires --features graphics]");
514}
515
516#[cfg(not(feature = "graphics"))]
518pub fn print_sixel_logo(_image_data: &[u8]) {
519 println!("[Sixel logo support requires --features graphics]");
520}
521
522#[cfg(feature = "graphics")]
524pub fn print_graphical_logo_from_path(path: &std::path::Path) {
525 use image::ImageFormat;
526 match image::open(path) {
527 Ok(img) => {
528 let resized = img.resize(128, 128, image::imageops::FilterType::Lanczos3);
529 let mut png_data = Vec::new();
530 if resized
531 .write_to(&mut std::io::Cursor::new(&mut png_data), ImageFormat::Png)
532 .is_ok()
533 {
534 print_graphical_logo(&png_data);
535 } else {
536 println!("[Failed to encode logo as PNG]");
537 }
538 }
539 Err(_) => {
540 println!("[Could not load graphical logo from {}]", path.display());
541 }
542 }
543}
544
545#[cfg(feature = "graphics")]
547pub fn print_sixel_logo_from_path(path: &std::path::Path) {
548 match image::open(path) {
549 Ok(img) => {
550 let resized = img.resize(128, 128, image::imageops::FilterType::Lanczos3);
551 let rgba = resized.to_rgba8();
552 let (width, height) = rgba.dimensions();
553 print_sixel_rgba(rgba.as_raw(), width, height);
554 }
555 Err(_) => {
556 println!("[Could not load logo for Sixel from {}]", path.display());
557 }
558 }
559}
560
561#[cfg(test)]
562mod tests {
563 use super::*;
564
565 #[test]
566 fn test_get_ascii_logo_arch() {
567 let logo = get_ascii_logo(Some("arch"));
568 assert!(!logo.is_empty());
569 assert!(logo[0].contains("`"));
570 }
571
572 #[test]
573 fn test_get_ascii_logo_unknown() {
574 let logo = get_ascii_logo(Some("unknown_distro"));
575 assert!(!logo.is_empty());
576 assert!(logo
578 .iter()
579 .any(|line| line.contains("o${2}_${3}o") || line.contains("o_o")));
580 }
581
582 #[test]
583 fn test_get_ascii_logo_none() {
584 let logo = get_ascii_logo(None);
585 assert!(!logo.is_empty());
586 }
587
588 static ENV_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
589
590 struct EnvGuard {
591 _mutex_guard: std::sync::MutexGuard<'static, ()>,
592 old_vars: std::collections::HashMap<&'static str, Option<String>>,
593 }
594
595 impl EnvGuard {
596 fn new(vars_to_mock: &[&'static str]) -> Self {
597 let guard = ENV_LOCK.lock().unwrap();
598 let mut old_vars = std::collections::HashMap::new();
599 for var in vars_to_mock {
600 old_vars.insert(*var, std::env::var(var).ok());
601 }
602 EnvGuard {
603 _mutex_guard: guard,
604 old_vars,
605 }
606 }
607 }
608
609 impl Drop for EnvGuard {
610 fn drop(&mut self) {
611 for (var, value) in &self.old_vars {
612 if let Some(val) = value {
613 std::env::set_var(var, val);
614 } else {
615 std::env::remove_var(var);
616 }
617 }
618 }
619 }
620
621 #[test]
622 fn test_supports_kitty_heuristics() {
623 let _guard = EnvGuard::new(&["TERM", "TERMINAL_EMULATOR", "TERM_PROGRAM"]);
624
625 std::env::set_var("TERM", "xterm-kitty");
627 std::env::remove_var("TERMINAL_EMULATOR");
628 std::env::remove_var("TERM_PROGRAM");
629 assert!(supports_kitty());
630
631 std::env::remove_var("TERM");
633 std::env::set_var("TERMINAL_EMULATOR", "iterm-kitty");
634 assert!(supports_kitty());
635
636 std::env::set_var("TERMINAL_EMULATOR", "iTerm.app");
638 assert!(supports_kitty());
639
640 std::env::remove_var("TERMINAL_EMULATOR");
642 std::env::set_var("TERM_PROGRAM", "rio");
643 assert!(supports_kitty());
644
645 std::env::remove_var("TERM_PROGRAM");
647 assert!(!supports_kitty());
648 }
649
650 #[test]
651 fn test_supports_iterm2_heuristics() {
652 let _guard = EnvGuard::new(&["TERM_PROGRAM"]);
653
654 std::env::set_var("TERM_PROGRAM", "iTerm.app");
656 assert!(supports_iterm2());
657
658 std::env::set_var("TERM_PROGRAM", "WezTerm");
660 assert!(supports_iterm2());
661
662 std::env::set_var("TERM_PROGRAM", "rio");
664 assert!(supports_iterm2());
665
666 std::env::set_var("TERM_PROGRAM", "Apple_Terminal");
668 assert!(!supports_iterm2());
669
670 std::env::remove_var("TERM_PROGRAM");
672 assert!(!supports_iterm2());
673 }
674
675 #[test]
676 fn test_supports_sixel_heuristics() {
677 let _guard = EnvGuard::new(&["TERM", "TERM_PROGRAM", "WT_SESSION"]);
678
679 std::env::remove_var("TERM");
681 std::env::remove_var("TERM_PROGRAM");
682 std::env::remove_var("WT_SESSION");
683 assert!(!supports_sixel());
684
685 std::env::set_var("TERM", "xterm-sixel");
687 assert!(supports_sixel());
688
689 std::env::set_var("TERM", "foot");
691 assert!(supports_sixel());
692
693 std::env::set_var("TERM", "MLTerm");
695 assert!(supports_sixel());
696
697 std::env::remove_var("TERM");
699 std::env::set_var("TERM_PROGRAM", "WezTerm");
700 assert!(supports_sixel());
701
702 std::env::set_var("TERM_PROGRAM", "iTerm.app");
704 assert!(supports_sixel());
705
706 std::env::set_var("TERM_PROGRAM", "rio");
708 assert!(supports_sixel());
709
710 std::env::remove_var("TERM_PROGRAM");
712 std::env::set_var("WT_SESSION", "active");
713 assert!(supports_sixel());
714 }
715
716 #[test]
717 fn test_get_embedded_logo() {
718 let logo = get_embedded_logo(Some("arch"));
719 assert!(logo.is_some());
720 let logo = get_embedded_logo(Some("pop"));
721 assert!(logo.is_some());
722 let logo = get_embedded_logo(Some("manjaro"));
723 assert!(logo.is_some());
724 let logo = get_embedded_logo(Some("endeavouros"));
725 assert!(logo.is_some());
726 let logo = get_embedded_logo(Some("opensuse"));
727 assert!(logo.is_some());
728 let logo = get_embedded_logo(Some("opensuse-leap"));
729 assert!(logo.is_some());
730 let logo = get_embedded_logo(Some("opensuse-tumbleweed"));
731 assert!(logo.is_some());
732 let logo = get_embedded_logo(Some("mx"));
733 assert!(logo.is_some());
734 let logo = get_embedded_logo(Some("linuxmint"));
735 assert!(logo.is_some());
736 let logo = get_embedded_logo(Some("kali"));
737 assert!(logo.is_some());
738 let logo = get_embedded_logo(Some("zorin"));
739 assert!(logo.is_some());
740 let logo = get_embedded_logo(Some("garuda"));
741 assert!(logo.is_some());
742 let logo = get_embedded_logo(Some("macos"));
743 assert!(logo.is_some());
744 let logo = get_embedded_logo(Some("windows"));
745 assert!(logo.is_some());
746 let logo = get_embedded_logo(None);
747 assert!(logo.is_some());
748 }
749
750 #[test]
751 fn test_get_ascii_logo_new_distros() {
752 let pop = get_ascii_logo(Some("pop"));
753 assert!(!pop.is_empty());
754 assert!(pop.iter().any(|line| line.contains("767")));
755
756 let manjaro = get_ascii_logo(Some("manjaro"));
757 assert!(!manjaro.is_empty());
758 assert!(manjaro.iter().any(|line| line.contains("████████")));
759
760 let endeavouros = get_ascii_logo(Some("endeavouros"));
761 assert!(!endeavouros.is_empty());
762 assert!(endeavouros.iter().any(|line| line.contains("ssso")));
763
764 let opensuse = get_ascii_logo(Some("opensuse"));
765 assert!(!opensuse.is_empty());
766 assert!(opensuse.iter().any(|line| line.contains("O0000Ok")));
767
768 let macos = get_ascii_logo(Some("macos"));
769 assert!(!macos.is_empty());
770 assert!(macos
771 .iter()
772 .any(|line| line.contains("cKMMMMMMMMMMNWMMMMMMMMMM0")));
773
774 let windows = get_ascii_logo(Some("windows"));
775 assert!(!windows.is_empty());
776 assert!(windows
777 .iter()
778 .any(|line| line.contains("AEEEtttt::::ztF") || line.contains("tt:::tt333EE3")));
779
780 let mx = get_ascii_logo(Some("mx"));
781 assert!(!mx.is_empty());
782 assert!(mx
783 .iter()
784 .any(|line| line.contains("MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNMMMMMMMMM")));
785
786 let linuxmint = get_ascii_logo(Some("linuxmint"));
787 assert!(!linuxmint.is_empty());
788 assert!(linuxmint.iter().any(|line| line.contains("oOOOOOOOOOOo")));
789
790 let kali = get_ascii_logo(Some("kali"));
791 assert!(!kali.is_empty());
792 assert!(kali.iter().any(|line| line.contains(":ccc")));
793
794 let zorin = get_ascii_logo(Some("zorin"));
795 assert!(!zorin.is_empty());
796 assert!(zorin
797 .iter()
798 .any(|line| line.contains("osssssssssssssssssssso")));
799
800 let garuda = get_ascii_logo(Some("garuda"));
801 assert!(!garuda.is_empty());
802 assert!(garuda.iter().any(|line| line.contains("888:8898898")));
803 }
804}