Kitty Graphics Protocol in OCaml
terminal graphics ocaml
at main 1.8 kB view raw
1(*--------------------------------------------------------------------------- 2 Copyright (c) 2025 Anil Madhavapeddy. All rights reserved. 3 SPDX-License-Identifier: ISC 4 ---------------------------------------------------------------------------*) 5 6(* Kitty Graphics Protocol Response - Implementation *) 7 8type t = { 9 message : string; 10 image_id : int option; 11 image_number : int option; 12 placement_id : int option; 13} 14 15let is_ok t = t.message = "OK" 16let message t = t.message 17 18let error_code t = 19 if is_ok t then None 20 else 21 String.index_opt t.message ':' 22 |> Option.fold ~none:(Some t.message) ~some:(fun i -> 23 Some (String.sub t.message 0 i)) 24 25let image_id t = t.image_id 26let image_number t = t.image_number 27let placement_id t = t.placement_id 28 29let parse s = 30 let ( let* ) = Option.bind in 31 let esc = '\027' in 32 let len = String.length s in 33 let* () = 34 if len >= 5 && s.[0] = esc && s.[1] = '_' && s.[2] = 'G' then Some () 35 else None 36 in 37 let* semi_pos = String.index_from_opt s 3 ';' in 38 let rec find_end pos = 39 if pos + 1 < len && s.[pos] = esc && s.[pos + 1] = '\\' then Some pos 40 else if pos + 1 < len then find_end (pos + 1) 41 else None 42 in 43 let* end_pos = find_end (semi_pos + 1) in 44 let keys_str = String.sub s 3 (semi_pos - 3) in 45 let message = String.sub s (semi_pos + 1) (end_pos - semi_pos - 1) in 46 let parse_kv part = 47 if String.length part >= 3 && part.[1] = '=' then 48 Some (part.[0], String.sub part 2 (String.length part - 2)) 49 else None 50 in 51 let keys = String.split_on_char ',' keys_str |> List.filter_map parse_kv in 52 let find_int key = 53 List.assoc_opt key keys |> Fun.flip Option.bind int_of_string_opt 54 in 55 Some 56 { 57 message; 58 image_id = find_int 'i'; 59 image_number = find_int 'I'; 60 placement_id = find_int 'p'; 61 }