Kitty Graphics Protocol in OCaml
terminal graphics ocaml
1(* Terminal Environment Detection *) 2 3type graphics_mode = [ `Auto | `Enabled | `Disabled | `Tmux ] 4 5let is_kitty () = 6 Option.is_some (Sys.getenv_opt "KITTY_WINDOW_ID") || 7 (match Sys.getenv_opt "TERM" with 8 | Some term -> String.lowercase_ascii term = "xterm-kitty" 9 | None -> false) || 10 (match Sys.getenv_opt "TERM_PROGRAM" with 11 | Some prog -> String.lowercase_ascii prog = "kitty" 12 | None -> false) 13 14let is_wezterm () = 15 Option.is_some (Sys.getenv_opt "WEZTERM_PANE") || 16 (match Sys.getenv_opt "TERM_PROGRAM" with 17 | Some prog -> String.lowercase_ascii prog = "wezterm" 18 | None -> false) 19 20let is_ghostty () = 21 Option.is_some (Sys.getenv_opt "GHOSTTY_RESOURCES_DIR") || 22 (match Sys.getenv_opt "TERM_PROGRAM" with 23 | Some prog -> String.lowercase_ascii prog = "ghostty" 24 | None -> false) 25 26let is_graphics_terminal () = 27 is_kitty () || is_wezterm () || is_ghostty () 28 29let is_tmux () = Kgp_tmux.is_active () 30 31let is_interactive () = 32 Unix.isatty Unix.stdout 33 34let is_pager () = 35 (* Not interactive = likely piped to pager *) 36 not (is_interactive ()) || 37 (* PAGER set and not in a known graphics terminal *) 38 (Option.is_some (Sys.getenv_opt "PAGER") && not (is_graphics_terminal ())) 39 40let resolve_mode = function 41 | `Disabled -> `Placeholder 42 | `Enabled -> `Graphics 43 | `Tmux -> `Tmux 44 | `Auto -> 45 if is_pager () || not (is_interactive ()) then 46 `Placeholder 47 else if is_tmux () then 48 (* Inside tmux - use passthrough if underlying terminal supports graphics *) 49 if is_graphics_terminal () then `Tmux 50 else `Placeholder 51 else if is_graphics_terminal () then 52 `Graphics 53 else 54 `Placeholder 55 56let supports_graphics mode = 57 match resolve_mode mode with 58 | `Graphics | `Tmux -> true 59 | `Placeholder -> false