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!["\x1b[32m", "\x1b[33m", "\x1b[31m", "\x1b[35m", "\x1b[34m"],
179 Some("windows") => vec!["\x1b[36m"],
180 _ => vec!["\x1b[30m", "\x1b[37m", "\x1b[33m"], }
182}
183
184pub fn get_distro_logo_lines(distro: Option<&str>) -> Vec<String> {
186 let raw_lines = get_ascii_logo(distro);
187 let colors = get_distro_colors(distro);
188 let default_color = colors.first().copied().unwrap_or("\x1b[0m");
189
190 raw_lines
191 .into_iter()
192 .map(|line| {
193 let mut formatted = line;
194 for i in 1..=9 {
195 let color_val = colors.get(i - 1).copied().unwrap_or("\x1b[0m");
196 let placeholder = format!("${{{}}}", i);
197 formatted = formatted.replace(&placeholder, color_val);
198 let placeholder_short = format!("${}", i);
199 formatted = formatted.replace(&placeholder_short, color_val);
200 }
201 if !formatted.is_empty() {
202 format!("{}{}\x1b[0m", default_color, formatted)
203 } else {
204 formatted
205 }
206 })
207 .collect()
208}
209
210pub fn supports_kitty() -> bool {
212 std::env::var("TERM")
213 .map(|t| t == "xterm-kitty")
214 .unwrap_or(false)
215 || std::env::var("TERMINAL_EMULATOR")
216 .map(|t| t == "iterm-kitty" || t == "iTerm.app")
217 .unwrap_or(false)
218 || std::env::var("TERM_PROGRAM")
219 .map(|t| t == "rio")
220 .unwrap_or(false)
221}
222
223pub fn supports_iterm2() -> bool {
225 if let Ok(prog) = std::env::var("TERM_PROGRAM") {
226 if prog == "iTerm.app" || prog == "WezTerm" || prog == "rio" {
227 return true;
228 }
229 }
230 false
231}
232
233pub fn supports_sixel() -> bool {
235 if let Ok(term) = std::env::var("TERM") {
236 let term = term.to_lowercase();
237 if term.contains("sixel") || term.contains("foot") || term.contains("mlterm") {
238 return true;
239 }
240 }
241
242 if let Ok(prog) = std::env::var("TERM_PROGRAM") {
243 if prog == "WezTerm" || prog == "iTerm.app" || prog == "rio" {
244 return true;
245 }
246 }
247
248 if std::env::var("WT_SESSION").is_ok() {
249 return true;
250 }
251
252 false
253}
254
255pub fn chafa_available() -> bool {
257 std::process::Command::new("chafa")
258 .arg("--version")
259 .output()
260 .map(|o| o.status.success())
261 .unwrap_or(false)
262}
263
264fn write_temp_logo(bytes: &[u8]) -> std::io::Result<std::path::PathBuf> {
266 let temp_path = std::env::temp_dir().join(format!("retch_logo_{}.png", std::process::id()));
267 std::fs::write(&temp_path, bytes)?;
268 Ok(temp_path)
269}
270
271pub fn print_with_chafa(path: &std::path::Path) -> bool {
276 let output = std::process::Command::new("chafa")
277 .arg("--format")
278 .arg("symbols")
279 .arg("--size")
280 .arg("40x20")
281 .arg(path)
282 .output();
283
284 match output {
285 Ok(out) if out.status.success() => {
286 print!("{}", String::from_utf8_lossy(&out.stdout));
287 true
288 }
289 Ok(out) => {
290 eprintln!("warning: chafa failed with status: {}", out.status);
291 false
292 }
293 Err(e) => {
294 eprintln!("warning: failed to execute chafa: {}", e);
295 false
296 }
297 }
298}
299
300pub fn get_chafa_logo_lines(path: &std::path::Path) -> Option<Vec<String>> {
302 let output = std::process::Command::new("chafa")
303 .arg("--format")
304 .arg("symbols")
305 .arg("--size")
306 .arg("40x20")
307 .arg(path)
308 .output()
309 .ok()?;
310 if output.status.success() {
311 let content = String::from_utf8_lossy(&output.stdout);
312 Some(content.lines().map(|s| s.to_string()).collect())
313 } else {
314 None
315 }
316}
317
318pub fn print_distro_logo(distro: Option<&str>) {
323 print_distro_logo_with_ascii(distro, false, false);
324}
325
326pub fn print_distro_logo_with_ascii(distro: Option<&str>, ascii_only: bool, chafa_only: bool) {
334 if ascii_only {
335 let art = get_distro_logo_lines(distro);
337 for line in art {
338 println!("{}", line);
339 }
340 return;
341 }
342
343 let has_chafa = chafa_available();
344
345 if !chafa_only {
346 let supports_kitty = supports_kitty();
347 let supports_iterm2 = supports_iterm2();
348 let supports_sixel = supports_sixel();
349
350 #[cfg(feature = "graphics")]
352 if supports_kitty {
353 if let Some(bytes) = get_embedded_logo(distro) {
354 if !bytes.is_empty() {
355 print_graphical_logo(bytes);
356 return;
357 }
358 }
359 }
360
361 #[cfg(feature = "graphics")]
363 if supports_iterm2 {
364 if let Some(bytes) = get_embedded_logo(distro) {
365 if !bytes.is_empty() {
366 print_iterm2_logo(bytes);
367 return;
368 }
369 }
370 }
371
372 #[cfg(feature = "graphics")]
374 if supports_sixel {
375 if let Some(bytes) = get_embedded_logo(distro) {
376 if !bytes.is_empty() {
377 print_sixel_logo(bytes);
378 return;
379 }
380 }
381 }
382 }
383
384 if has_chafa {
386 if let Some(bytes) = get_embedded_logo(distro) {
387 if bytes.len() > 100 {
388 if let Ok(temp_path) = write_temp_logo(bytes) {
389 if print_with_chafa(&temp_path) {
390 let _ = std::fs::remove_file(&temp_path);
391 return;
392 }
393 let _ = std::fs::remove_file(&temp_path);
394 }
395 }
396 }
397 }
398
399 let art = get_distro_logo_lines(distro);
401 for line in art {
402 println!("{}", line);
403 }
404}
405
406#[cfg(feature = "graphics")]
408pub fn print_iterm2_logo(image_data: &[u8]) {
409 use base64::Engine;
410 let encoded = base64::engine::general_purpose::STANDARD.encode(image_data);
411 print!(
412 "\x1b]1337;File=inline=1;preserveAspectRatio=1:{}\x07",
413 encoded
414 );
415 println!(); }
417
418#[cfg(feature = "graphics")]
420pub fn print_iterm2_logo_from_path(path: &std::path::Path) {
421 if let Ok(bytes) = std::fs::read(path) {
422 print_iterm2_logo(&bytes);
423 } else {
424 println!("[Could not read logo for iTerm2 from {}]", path.display());
425 }
426}
427
428#[cfg(not(feature = "graphics"))]
430pub fn print_iterm2_logo(_image_data: &[u8]) {
431 println!("[iTerm2 logo support requires --features graphics]");
432}
433
434#[cfg(feature = "graphics")]
436pub fn print_graphical_logo(image_data: &[u8]) {
437 use base64::Engine;
438
439 let (width, height) = image::load_from_memory(image_data)
440 .map(|img| (img.width(), img.height()))
441 .unwrap_or((0, 0));
442
443 let encoded = base64::engine::general_purpose::STANDARD.encode(image_data);
444
445 if width > 0 && height > 0 {
446 println!("\x1b_Gf=100,s={},v={},a=T;{}\x1b\\", width, height, encoded);
447 } else {
448 println!("\x1b_Gf=100,a=T;{}", encoded);
449 }
450}
451
452#[cfg(feature = "graphics")]
454pub fn print_sixel_logo(image_data: &[u8]) {
455 if let Ok(img) = image::load_from_memory(image_data) {
456 let rgba = img.to_rgba8();
457 let (width, height) = rgba.dimensions();
458 print_sixel_rgba(rgba.as_raw(), width, height);
459 }
460}
461
462#[cfg(feature = "graphics")]
464pub fn print_sixel_rgba(rgba: &[u8], width: u32, height: u32) {
465 use icy_sixel::SixelImage;
466
467 match SixelImage::try_from_rgba(rgba.to_vec(), width as usize, height as usize) {
468 Ok(sixel_img) => match sixel_img.encode() {
469 Ok(sixel_str) => {
470 print!("{}", sixel_str);
471 }
472 Err(e) => eprintln!("[Sixel Encoding Error: {}]", e),
473 },
474 Err(e) => eprintln!("[Sixel Creation Error: {}]", e),
475 }
476}
477
478#[cfg(not(feature = "graphics"))]
480pub fn print_graphical_logo(_image_data: &[u8]) {
481 println!("[Graphical logo support requires --features graphics]");
482}
483
484#[cfg(not(feature = "graphics"))]
486pub fn print_sixel_logo(_image_data: &[u8]) {
487 println!("[Sixel logo support requires --features graphics]");
488}
489
490#[cfg(feature = "graphics")]
492pub fn print_graphical_logo_from_path(path: &std::path::Path) {
493 use image::ImageFormat;
494 match image::open(path) {
495 Ok(img) => {
496 let resized = img.resize(128, 128, image::imageops::FilterType::Lanczos3);
497 let mut png_data = Vec::new();
498 if resized
499 .write_to(&mut std::io::Cursor::new(&mut png_data), ImageFormat::Png)
500 .is_ok()
501 {
502 print_graphical_logo(&png_data);
503 } else {
504 println!("[Failed to encode logo as PNG]");
505 }
506 }
507 Err(_) => {
508 println!("[Could not load graphical logo from {}]", path.display());
509 }
510 }
511}
512
513#[cfg(feature = "graphics")]
515pub fn print_sixel_logo_from_path(path: &std::path::Path) {
516 match image::open(path) {
517 Ok(img) => {
518 let resized = img.resize(128, 128, image::imageops::FilterType::Lanczos3);
519 let rgba = resized.to_rgba8();
520 let (width, height) = rgba.dimensions();
521 print_sixel_rgba(rgba.as_raw(), width, height);
522 }
523 Err(_) => {
524 println!("[Could not load logo for Sixel from {}]", path.display());
525 }
526 }
527}
528
529#[cfg(test)]
530mod tests {
531 use super::*;
532
533 #[test]
534 fn test_get_ascii_logo_arch() {
535 let logo = get_ascii_logo(Some("arch"));
536 assert!(!logo.is_empty());
537 assert!(logo[0].contains("`"));
538 }
539
540 #[test]
541 fn test_get_ascii_logo_unknown() {
542 let logo = get_ascii_logo(Some("unknown_distro"));
543 assert!(!logo.is_empty());
544 assert!(logo
546 .iter()
547 .any(|line| line.contains("o${2}_${3}o") || line.contains("o_o")));
548 }
549
550 #[test]
551 fn test_get_ascii_logo_none() {
552 let logo = get_ascii_logo(None);
553 assert!(!logo.is_empty());
554 }
555
556 static ENV_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
557
558 struct EnvGuard {
559 _mutex_guard: std::sync::MutexGuard<'static, ()>,
560 old_vars: std::collections::HashMap<&'static str, Option<String>>,
561 }
562
563 impl EnvGuard {
564 fn new(vars_to_mock: &[&'static str]) -> Self {
565 let guard = ENV_LOCK.lock().unwrap();
566 let mut old_vars = std::collections::HashMap::new();
567 for var in vars_to_mock {
568 old_vars.insert(*var, std::env::var(var).ok());
569 }
570 EnvGuard {
571 _mutex_guard: guard,
572 old_vars,
573 }
574 }
575 }
576
577 impl Drop for EnvGuard {
578 fn drop(&mut self) {
579 for (var, value) in &self.old_vars {
580 if let Some(val) = value {
581 std::env::set_var(var, val);
582 } else {
583 std::env::remove_var(var);
584 }
585 }
586 }
587 }
588
589 #[test]
590 fn test_supports_kitty_heuristics() {
591 let _guard = EnvGuard::new(&["TERM", "TERMINAL_EMULATOR", "TERM_PROGRAM"]);
592
593 std::env::set_var("TERM", "xterm-kitty");
595 std::env::remove_var("TERMINAL_EMULATOR");
596 std::env::remove_var("TERM_PROGRAM");
597 assert!(supports_kitty());
598
599 std::env::remove_var("TERM");
601 std::env::set_var("TERMINAL_EMULATOR", "iterm-kitty");
602 assert!(supports_kitty());
603
604 std::env::set_var("TERMINAL_EMULATOR", "iTerm.app");
606 assert!(supports_kitty());
607
608 std::env::remove_var("TERMINAL_EMULATOR");
610 std::env::set_var("TERM_PROGRAM", "rio");
611 assert!(supports_kitty());
612
613 std::env::remove_var("TERM_PROGRAM");
615 assert!(!supports_kitty());
616 }
617
618 #[test]
619 fn test_supports_iterm2_heuristics() {
620 let _guard = EnvGuard::new(&["TERM_PROGRAM"]);
621
622 std::env::set_var("TERM_PROGRAM", "iTerm.app");
624 assert!(supports_iterm2());
625
626 std::env::set_var("TERM_PROGRAM", "WezTerm");
628 assert!(supports_iterm2());
629
630 std::env::set_var("TERM_PROGRAM", "rio");
632 assert!(supports_iterm2());
633
634 std::env::set_var("TERM_PROGRAM", "Apple_Terminal");
636 assert!(!supports_iterm2());
637
638 std::env::remove_var("TERM_PROGRAM");
640 assert!(!supports_iterm2());
641 }
642
643 #[test]
644 fn test_supports_sixel_heuristics() {
645 let _guard = EnvGuard::new(&["TERM", "TERM_PROGRAM", "WT_SESSION"]);
646
647 std::env::remove_var("TERM");
649 std::env::remove_var("TERM_PROGRAM");
650 std::env::remove_var("WT_SESSION");
651 assert!(!supports_sixel());
652
653 std::env::set_var("TERM", "xterm-sixel");
655 assert!(supports_sixel());
656
657 std::env::set_var("TERM", "foot");
659 assert!(supports_sixel());
660
661 std::env::set_var("TERM", "MLTerm");
663 assert!(supports_sixel());
664
665 std::env::remove_var("TERM");
667 std::env::set_var("TERM_PROGRAM", "WezTerm");
668 assert!(supports_sixel());
669
670 std::env::set_var("TERM_PROGRAM", "iTerm.app");
672 assert!(supports_sixel());
673
674 std::env::set_var("TERM_PROGRAM", "rio");
676 assert!(supports_sixel());
677
678 std::env::remove_var("TERM_PROGRAM");
680 std::env::set_var("WT_SESSION", "active");
681 assert!(supports_sixel());
682 }
683
684 #[test]
685 fn test_get_embedded_logo() {
686 let logo = get_embedded_logo(Some("arch"));
687 assert!(logo.is_some());
688 let logo = get_embedded_logo(Some("pop"));
689 assert!(logo.is_some());
690 let logo = get_embedded_logo(Some("manjaro"));
691 assert!(logo.is_some());
692 let logo = get_embedded_logo(Some("endeavouros"));
693 assert!(logo.is_some());
694 let logo = get_embedded_logo(Some("opensuse"));
695 assert!(logo.is_some());
696 let logo = get_embedded_logo(Some("opensuse-leap"));
697 assert!(logo.is_some());
698 let logo = get_embedded_logo(Some("opensuse-tumbleweed"));
699 assert!(logo.is_some());
700 let logo = get_embedded_logo(Some("mx"));
701 assert!(logo.is_some());
702 let logo = get_embedded_logo(Some("linuxmint"));
703 assert!(logo.is_some());
704 let logo = get_embedded_logo(Some("kali"));
705 assert!(logo.is_some());
706 let logo = get_embedded_logo(Some("zorin"));
707 assert!(logo.is_some());
708 let logo = get_embedded_logo(Some("garuda"));
709 assert!(logo.is_some());
710 let logo = get_embedded_logo(Some("macos"));
711 assert!(logo.is_some());
712 let logo = get_embedded_logo(Some("windows"));
713 assert!(logo.is_some());
714 let logo = get_embedded_logo(None);
715 assert!(logo.is_some());
716 }
717
718 #[test]
719 fn test_get_ascii_logo_new_distros() {
720 let pop = get_ascii_logo(Some("pop"));
721 assert!(!pop.is_empty());
722 assert!(pop.iter().any(|line| line.contains("767")));
723
724 let manjaro = get_ascii_logo(Some("manjaro"));
725 assert!(!manjaro.is_empty());
726 assert!(manjaro.iter().any(|line| line.contains("████████")));
727
728 let endeavouros = get_ascii_logo(Some("endeavouros"));
729 assert!(!endeavouros.is_empty());
730 assert!(endeavouros.iter().any(|line| line.contains("ssso")));
731
732 let opensuse = get_ascii_logo(Some("opensuse"));
733 assert!(!opensuse.is_empty());
734 assert!(opensuse.iter().any(|line| line.contains("O0000Ok")));
735
736 let macos = get_ascii_logo(Some("macos"));
737 assert!(!macos.is_empty());
738 assert!(macos
739 .iter()
740 .any(|line| line.contains("cKMMMMMMMMMMNWMMMMMMMMMM0")));
741
742 let windows = get_ascii_logo(Some("windows"));
743 assert!(!windows.is_empty());
744 assert!(windows
745 .iter()
746 .any(|line| line.contains("AEEEtttt::::ztF") || line.contains("tt:::tt333EE3")));
747
748 let mx = get_ascii_logo(Some("mx"));
749 assert!(!mx.is_empty());
750 assert!(mx
751 .iter()
752 .any(|line| line.contains("MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNMMMMMMMMM")));
753
754 let linuxmint = get_ascii_logo(Some("linuxmint"));
755 assert!(!linuxmint.is_empty());
756 assert!(linuxmint.iter().any(|line| line.contains("oOOOOOOOOOOo")));
757
758 let kali = get_ascii_logo(Some("kali"));
759 assert!(!kali.is_empty());
760 assert!(kali.iter().any(|line| line.contains(":ccc")));
761
762 let zorin = get_ascii_logo(Some("zorin"));
763 assert!(!zorin.is_empty());
764 assert!(zorin
765 .iter()
766 .any(|line| line.contains("osssssssssssssssssssso")));
767
768 let garuda = get_ascii_logo(Some("garuda"));
769 assert!(!garuda.is_empty());
770 assert!(garuda.iter().any(|line| line.contains("888:8898898")));
771 }
772}