My agentic slop goes here. Not intended for anyone else!
1(* Kitty Graphics Protocol - Response *)
2
3type t = {
4 message : string;
5 image_id : int option;
6 image_number : int option;
7 placement_id : int option;
8}
9
10let is_ok t = t.message = "OK"
11let message t = t.message
12
13let error_code t =
14 if is_ok t then None
15 else
16 String.index_opt t.message ':'
17 |> Option.fold ~none:(Some t.message) ~some:(fun i ->
18 Some (String.sub t.message 0 i))
19
20let image_id t = t.image_id
21let image_number t = t.image_number
22let placement_id t = t.placement_id
23
24let parse s =
25 let ( let* ) = Option.bind in
26 let esc = '\027' in
27 let len = String.length s in
28 let* () =
29 if len >= 5 && s.[0] = esc && s.[1] = '_' && s.[2] = 'G' then Some ()
30 else None
31 in
32 let* semi_pos = String.index_from_opt s 3 ';' in
33 let rec find_end pos =
34 if pos + 1 < len && s.[pos] = esc && s.[pos + 1] = '\\' then Some pos
35 else if pos + 1 < len then find_end (pos + 1)
36 else None
37 in
38 let* end_pos = find_end (semi_pos + 1) in
39 let keys_str = String.sub s 3 (semi_pos - 3) in
40 let message = String.sub s (semi_pos + 1) (end_pos - semi_pos - 1) in
41 let parse_kv part =
42 if String.length part >= 3 && part.[1] = '=' then
43 Some (part.[0], String.sub part 2 (String.length part - 2))
44 else None
45 in
46 let keys = String.split_on_char ',' keys_str |> List.filter_map parse_kv in
47 let find_int key =
48 List.assoc_opt key keys |> Fun.flip Option.bind int_of_string_opt
49 in
50 Some
51 {
52 message;
53 image_id = find_int 'i';
54 image_number = find_int 'I';
55 placement_id = find_int 'p';
56 }