Skip to main content

mcraw_tui/
terminal.rs

1use std::sync::OnceLock;
2
3#[derive(Debug, Clone, Copy, PartialEq)]
4pub enum TerminalProtocol {
5    Sixel,
6    Kitty,
7    TextFallback,
8}
9
10static PROTOCOL: OnceLock<TerminalProtocol> = OnceLock::new();
11
12pub fn init(p: TerminalProtocol) {
13    _ = PROTOCOL.set(p);
14}
15
16pub fn protocol() -> TerminalProtocol {
17    *PROTOCOL.get().unwrap_or(&TerminalProtocol::TextFallback)
18}
19
20pub fn protocol_name(p: TerminalProtocol) -> &'static str {
21    match p {
22        TerminalProtocol::Sixel => "sixel",
23        TerminalProtocol::Kitty => "kitty",
24        TerminalProtocol::TextFallback => "text-fallback",
25    }
26}
27
28/// Detect the terminal image protocol from environment variables.
29/// Kitty protocol is checked first (modern terminals support it).
30/// Falls back to sixel for known sixel terminals, then TextFallback.
31pub fn detect() -> TerminalProtocol {
32    let term = std::env::var("TERM").unwrap_or_default();
33
34    // Kitty protocol — supported by Kitty, Ghostty, VS Code, Konsole, etc.
35    // True 24-bit RGB, no palette limits.
36    if std::env::var("KITTY_WINDOW_ID").is_ok() || std::env::var("KITTY_PID").is_ok() {
37        return TerminalProtocol::Kitty;
38    }
39    if std::env::var("TERM_PROGRAM").as_deref().ok() == Some("Ghostty")
40        || std::env::var("TERM_PROGRAM").as_deref().ok() == Some("vscode")
41    {
42        return TerminalProtocol::Kitty;
43    }
44    if term == "xterm-kitty" {
45        return TerminalProtocol::Kitty;
46    }
47
48    // WezTerm — native Kitty protocol support on all platforms including
49    // Windows (APC passes through ConPTY, unlike sixel's DCS which is
50    // blocked). WEZTERM_EXECUTABLE is set by WezTerm in every child process.
51    if std::env::var("WEZTERM_EXECUTABLE").is_ok() {
52        return TerminalProtocol::Kitty;
53    }
54
55    // Sixel — foot, contour, and any terminal with "sixel" in TERM
56    if term.contains("sixel") || term == "foot" || term == "contour" {
57        return TerminalProtocol::Sixel;
58    }
59
60    // Unknown terminal — the encoder will fall back to sixel anyway
61    // (harmless on non-sixel terminals)
62    TerminalProtocol::TextFallback
63}