nuviz_cli/terminal/
capability.rs1use std::env;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub enum ColorDepth {
6 TrueColor,
7 Colors256,
8 Colors16,
9}
10
11#[derive(Debug, Clone)]
13pub struct TerminalCapabilities {
14 pub supports_kitty_graphics: bool,
15 pub supports_iterm2: bool,
16 pub supports_sixel: bool,
17 pub color_depth: ColorDepth,
18 #[allow(dead_code)]
19 pub unicode_support: bool,
20 #[allow(dead_code)]
21 pub terminal_name: Option<String>,
22}
23
24pub fn detect_capabilities() -> TerminalCapabilities {
28 let term_program = env::var("TERM_PROGRAM").ok();
29 let term = env::var("TERM").ok();
30 let colorterm = env::var("COLORTERM").ok();
31 let lang = env::var("LANG").ok();
32
33 let term_program_lower = term_program.as_deref().unwrap_or("").to_lowercase();
34
35 let supports_kitty = term_program_lower == "kitty"
37 || term_program_lower == "wezterm"
38 || term_program_lower == "ghostty"
39 || env::var("KITTY_WINDOW_ID").is_ok();
40
41 let supports_iterm2 = term_program_lower.contains("iterm")
43 || term_program_lower == "wezterm"
44 || env::var("ITERM_SESSION_ID").is_ok();
45
46 let supports_sixel = term
48 .as_deref()
49 .map(|t| t.contains("xterm") || t.contains("foot") || t.contains("mlterm"))
50 .unwrap_or(false)
51 || term_program_lower == "wezterm";
52
53 let color_depth = if colorterm.as_deref() == Some("truecolor")
55 || colorterm.as_deref() == Some("24bit")
56 || supports_kitty
57 {
58 ColorDepth::TrueColor
59 } else if term.as_deref().is_some_and(|t| t.contains("256color")) {
60 ColorDepth::Colors256
61 } else {
62 ColorDepth::Colors16
63 };
64
65 let unicode_support = lang
67 .as_deref()
68 .map(|l| l.contains("UTF-8") || l.contains("utf-8") || l.contains("UTF8"))
69 .unwrap_or(false)
70 || supports_kitty;
71
72 TerminalCapabilities {
73 supports_kitty_graphics: supports_kitty,
74 supports_iterm2,
75 supports_sixel,
76 color_depth,
77 unicode_support,
78 terminal_name: term_program,
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85
86 #[test]
87 fn test_detect_returns_valid_struct() {
88 let caps = detect_capabilities();
89 let _ = caps.color_depth;
91 let _ = caps.supports_kitty_graphics;
92 let _ = caps.supports_sixel;
93 let _ = caps.supports_iterm2;
94 let _ = caps.unicode_support;
95 }
96
97 #[test]
98 fn test_color_depth_variants() {
99 assert_ne!(ColorDepth::TrueColor, ColorDepth::Colors256);
101 assert_ne!(ColorDepth::Colors256, ColorDepth::Colors16);
102 }
103}