Query.XtermXterm-compatible terminal query functions.
Set terminal to raw mode for direct input/output.
Configures the terminal for raw mode where input is not line-buffered and special characters are not processed. This is necessary for reading terminal query responses.
Warning: This modifies terminal settings. Always restore original settings using Unix.tcsetattr or use the query function which handles this automatically.
Query terminal using xterm control codes.
Sends an xterm OSC (Operating System Command) query to the terminal and reads the response. The terminal must support xterm control sequences.
Common control codes:
(* Query foreground color *)
match Spectrum_tools.Query.Xterm.query Unix.stdin "10" with
| Ok response ->
Printf.printf "Foreground color response: %s\n" response
(* Example: "rgb:ffff/ffff/ffff" for white *)
| Error msg ->
Printf.printf "Query failed: %s\n" msg (* Query background color *)
match Spectrum_tools.Query.Xterm.query Unix.stdin "11" with
| Ok response -> Printf.printf "Background: %s\n" response
| Error msg -> Printf.eprintf "Error: %s\n" msg (* Query both colors in sequence *)
let query_colors () =
match Spectrum_tools.Query.Xterm.query Unix.stdin "10" with
| Ok fg_response ->
Printf.printf "FG: %s\n" fg_response;
(match Spectrum_tools.Query.Xterm.query Unix.stdin "11" with
| Ok bg_response -> Printf.printf "BG: %s\n" bg_response
| Error e -> Printf.eprintf "BG error: %s\n" e)
| Error e -> Printf.eprintf "FG error: %s\n" eConvert hexadecimal string to 8-bit integer (0-255) with scaling.
Translates a hexadecimal string of any width to an 8-bit int. The value is scaled according to the number of hex characters, where each character represents 4 bits.
(* Single hex digit scales to 8-bit *)
let result = Spectrum_tools.Query.Xterm.hex_to_8bit "C" in
Printf.printf "C -> %d\n" result
(* Output: C -> 204 *) (* Two hex digits *)
let result = Spectrum_tools.Query.Xterm.hex_to_8bit "C3" in
Printf.printf "C3 -> %d\n" result
(* Output: C3 -> 195 *) (* Four hex digits (16-bit terminal response) *)
let result = Spectrum_tools.Query.Xterm.hex_to_8bit "CCCC" in
Printf.printf "CCCC -> %d\n" result
(* Output: CCCC -> 204 *) (* Parse all components from terminal response *)
let parse_rgb_components r g b =
let r8 = Spectrum_tools.Query.Xterm.hex_to_8bit r in
let g8 = Spectrum_tools.Query.Xterm.hex_to_8bit g in
let b8 = Spectrum_tools.Query.Xterm.hex_to_8bit b in
Printf.printf "RGB(%d, %d, %d)\n" r8 g8 b8
in
parse_rgb_components "FFFF" "8080" "4040"
(* Output: RGB(255, 128, 64) *)Parse xterm RGB color string.
Parses terminal query responses in xterm's 48-bit RGB format: "rgb:RRRR/GGGG/BBBB" where each component is 1-4 hex digits.
(* Parse a typical terminal response *)
match Spectrum_tools.Query.Xterm.parse_colour "rgb:c3c3/b0b0/9090" with
| Ok color ->
let rgba = Spectrum_tools.Convert.Color.to_rgba color in
Printf.printf "Parsed: RGB(%d, %d, %d)\n" rgba.r rgba.g rgba.b
(* Output: Parsed: RGB(195, 176, 144) *)
| Error msg ->
Printf.printf "Parse error: %s\n" msg (* Parse white *)
match Spectrum_tools.Query.Xterm.parse_colour "rgb:ffff/ffff/ffff" with
| Ok color ->
let rgba = Spectrum_tools.Convert.Color.to_rgba color in
Printf.printf "White: RGB(%d, %d, %d)\n" rgba.r rgba.g rgba.b
(* Output: White: RGB(255, 255, 255) *)
| Error _ -> () (* Handle parse errors *)
let test_strings = [
"rgb:ffff/ffff/ffff"; (* valid *)
"rgb:ff/ff/ff"; (* valid, shorter format *)
"not a color"; (* invalid *)
] in
List.iter (fun s ->
match Spectrum_tools.Query.Xterm.parse_colour s with
| Ok _ -> Printf.printf "%s: valid\n" s
| Error msg -> Printf.printf "%s: %s\n" s msg
) test_strings (* Extract from terminal response *)
let response = "\027]10;rgb:d0d0/d0d0/d0d0\007" in
(* Extract just the RGB part *)
let rgb_part = "rgb:d0d0/d0d0/d0d0" in
match Spectrum_tools.Query.Xterm.parse_colour rgb_part with
| Ok color -> Printf.printf "Foreground color parsed\n"
| Error e -> Printf.eprintf "Error: %s\n" eval get_colours : Unix.file_descr -> terminal_coloursGet current terminal foreground and background colors.
Queries the terminal for both foreground (OSC 10) and background (OSC 11) colors and parses the responses.
(* Query terminal colors *)
let colours = Spectrum_tools.Query.Xterm.get_colours Unix.stdin in
let () =
match colours.fg with
| Ok fg_color ->
let rgba = Spectrum_tools.Convert.Color.to_rgba fg_color in
Printf.printf "Foreground: RGB(%d, %d, %d)\n" rgba.r rgba.g rgba.b
| Error msg ->
Printf.printf "Failed to detect foreground: %s\n" msg
in
let () =
match colours.bg with
| Ok bg_color ->
let rgba = Spectrum_tools.Convert.Color.to_rgba bg_color in
Printf.printf "Background: RGB(%d, %d, %d)\n" rgba.r rgba.g rgba.b
| Error msg ->
Printf.printf "Failed to detect background: %s\n" msg
in
() (* Check if terminal has dark or light background *)
let colours = Spectrum_tools.Query.Xterm.get_colours Unix.stdin in
match colours.bg with
| Ok bg_color ->
let rgba' = Spectrum_tools.Convert.Color.to_rgba' bg_color in
let brightness = (rgba'.r +. rgba'.g +. rgba'.b) /. 3. in
if brightness < 0.5 then
Printf.printf "Dark background detected\n"
else
Printf.printf "Light background detected\n"
| Error _ ->
Printf.printf "Could not determine background\n" (* Calculate contrast ratio *)
let colours = Spectrum_tools.Query.Xterm.get_colours Unix.stdin in
match colours.fg, colours.bg with
| Ok fg, Ok bg ->
let fg_rgba = Spectrum_tools.Convert.Color.to_rgba' fg in
let bg_rgba = Spectrum_tools.Convert.Color.to_rgba' bg in
let fg_luma = 0.299 *. fg_rgba.r +. 0.587 *. fg_rgba.g +. 0.114 *. fg_rgba.b in
let bg_luma = 0.299 *. bg_rgba.r +. 0.587 *. bg_rgba.g +. 0.114 *. bg_rgba.b in
let contrast = abs_float (fg_luma -. bg_luma) in
Printf.printf "Contrast: %.2f\n" contrast
| _ ->
Printf.printf "Could not calculate contrast\n"