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