vtcode_tui/core_tui/session/
terminal_capabilities.rs1use std::env;
8
9pub fn supports_unicode_box_drawing() -> bool {
15 if env::var("VTCODE_NO_UNICODE").is_ok() {
17 return false;
18 }
19
20 if let Ok(term) = env::var("TERM") {
22 let term_lower = term.to_lowercase();
23
24 if term_lower.contains("unicode")
26 || term_lower.contains("utf")
27 || term_lower.contains("xterm-256color")
28 || term_lower.contains("screen-256color")
29 || term_lower.contains("tmux-256color")
30 || term_lower.contains("alacritty")
31 || term_lower.contains("wezterm")
32 || term_lower.contains("kitty")
33 || term_lower.contains("iterm")
34 || term_lower.contains("hyper")
35 {
36 return true;
37 }
38
39 if term_lower.contains("dumb")
41 || term_lower.contains("basic")
42 || term_lower == "xterm"
43 || term_lower == "screen"
44 {
45 return false;
46 }
47 }
48
49 if let Ok(lang) = env::var("LANG")
51 && (lang.to_lowercase().contains("utf-8") || lang.to_lowercase().contains("utf8"))
52 {
53 return true;
54 }
55
56 for var in &["LC_ALL", "LC_CTYPE"] {
58 if let Ok(locale) = env::var(var)
59 && (locale.to_lowercase().contains("utf-8") || locale.to_lowercase().contains("utf8"))
60 {
61 return true;
62 }
63 }
64
65 false
67}
68
69pub fn get_border_type() -> ratatui::widgets::BorderType {
74 if supports_unicode_box_drawing() {
75 ratatui::widgets::BorderType::Rounded
76 } else {
77 ratatui::widgets::BorderType::Plain
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84 #[inline]
85 fn set_var(key: &str, value: &str) {
86 unsafe { env::set_var(key, value) };
87 }
88 #[inline]
89 fn remove_var(key: &str) {
90 unsafe { env::remove_var(key) };
91 }
92
93 #[test]
94 fn test_supports_unicode_box_drawing() {
95 let original_term = env::var("TERM").ok();
99 let original_lang = env::var("LANG").ok();
100 let original_lc_all = env::var("LC_ALL").ok();
101 let original_no_unicode = env::var("VTCODE_NO_UNICODE").ok();
102
103 set_var("VTCODE_NO_UNICODE", "1");
105 assert!(!supports_unicode_box_drawing());
106 remove_var("VTCODE_NO_UNICODE");
107
108 set_var("TERM", "xterm-256color");
110 assert!(supports_unicode_box_drawing());
111
112 set_var("LANG", "en_US.UTF-8");
114 assert!(supports_unicode_box_drawing());
115
116 set_var("TERM", "dumb");
118 assert!(!supports_unicode_box_drawing());
119
120 remove_var("TERM");
122 remove_var("LANG");
123 remove_var("LC_ALL");
124 assert!(!supports_unicode_box_drawing());
125
126 match original_term {
128 Some(val) => set_var("TERM", &val),
129 None => remove_var("TERM"),
130 }
131 match original_lang {
132 Some(val) => set_var("LANG", &val),
133 None => remove_var("LANG"),
134 }
135 match original_lc_all {
136 Some(val) => set_var("LC_ALL", &val),
137 None => remove_var("LC_ALL"),
138 }
139 match original_no_unicode {
140 Some(val) => set_var("VTCODE_NO_UNICODE", &val),
141 None => remove_var("VTCODE_NO_UNICODE"),
142 }
143 }
144
145 #[test]
146 fn test_get_border_type() {
147 let original_term = env::var("TERM").ok();
149
150 set_var("TERM", "xterm-256color");
152 let border_type = get_border_type();
153 assert!(matches!(border_type, ratatui::widgets::BorderType::Rounded));
154
155 set_var("TERM", "dumb");
157 let border_type = get_border_type();
158 assert!(matches!(border_type, ratatui::widgets::BorderType::Plain));
159
160 match original_term {
162 Some(val) => set_var("TERM", &val),
163 None => remove_var("TERM"),
164 }
165 }
166}