My agentic slop goes here. Not intended for anyone else!
1(** OCaml implementation of the Kitty text sizing protocol *)
2
3(* Types *)
4
5type vertical = [ `Bottom | `Center | `Top ]
6type horizontal = [ `Left | `Center | `Right ]
7
8type t = {
9 scale : int option;
10 width : int option;
11 numerator : int option;
12 denominator : int option;
13 vertical : vertical option;
14 horizontal : horizontal option;
15}
16
17(* Validation helpers *)
18
19let validate_scale n =
20 if n < 1 || n > 7 then
21 invalid_arg (Printf.sprintf "scale must be in range 1-7, got %d" n)
22
23let validate_width n =
24 if n < 0 || n > 7 then
25 invalid_arg (Printf.sprintf "width must be in range 0-7, got %d" n)
26
27let validate_numerator n =
28 if n < 0 || n > 15 then
29 invalid_arg (Printf.sprintf "numerator must be in range 0-15, got %d" n)
30
31let validate_denominator n =
32 if n < 0 || n > 15 then
33 invalid_arg (Printf.sprintf "denominator must be in range 0-15, got %d" n)
34
35(* Constructor *)
36
37let v ?scale ?width ?fraction ?vertical ?horizontal () =
38 Option.iter validate_scale scale;
39 Option.iter validate_width width;
40 let numerator, denominator = match fraction with
41 | None -> None, None
42 | Some (num, den) ->
43 validate_numerator num;
44 validate_denominator den;
45 Some num, Some den
46 in
47 {
48 scale;
49 width;
50 numerator;
51 denominator;
52 vertical;
53 horizontal;
54 }
55
56let empty = v ()
57
58(* Conversion helpers *)
59
60let vertical_to_int = function
61 | `Bottom -> 0
62 | `Center -> 1
63 | `Top -> 2
64
65let horizontal_to_int = function
66 | `Left -> 0
67 | `Center -> 1
68 | `Right -> 2
69
70(* Escape sequence generation *)
71
72let metadata_to_string t =
73 let parts = [] in
74 let parts = match t.scale with
75 | Some s -> (Printf.sprintf "s=%d" s) :: parts
76 | None -> parts
77 in
78 let parts = match t.width with
79 | Some w -> (Printf.sprintf "w=%d" w) :: parts
80 | None -> parts
81 in
82 let parts = match t.numerator with
83 | Some n -> (Printf.sprintf "n=%d" n) :: parts
84 | None -> parts
85 in
86 let parts = match t.denominator with
87 | Some d -> (Printf.sprintf "d=%d" d) :: parts
88 | None -> parts
89 in
90 let parts = match t.vertical with
91 | Some v -> (Printf.sprintf "v=%d" (vertical_to_int v)) :: parts
92 | None -> parts
93 in
94 let parts = match t.horizontal with
95 | Some h -> (Printf.sprintf "h=%d" (horizontal_to_int h)) :: parts
96 | None -> parts
97 in
98 String.concat ":" (List.rev parts)
99
100let render t text =
101 (* Validate text length (max 4096 bytes of UTF-8) *)
102 let text_len = String.length text in
103 if text_len > 4096 then
104 invalid_arg (Printf.sprintf "text exceeds 4096 bytes (got %d)" text_len);
105
106 let metadata_str = metadata_to_string t in
107
108 (* OSC 66 ; metadata ; text BEL *)
109 (* Using \x1b for ESC and \x07 for BEL *)
110 if metadata_str = "" then
111 Printf.sprintf "\x1b]66;;%s\x07" text
112 else
113 Printf.sprintf "\x1b]66;%s;%s\x07" metadata_str text
114
115let render_to_channel oc t text =
116 output_string oc (render t text);
117 flush oc
118
119(* Fmt-style combinators *)
120
121let pp t ppf text =
122 Format.pp_print_string ppf (render t text)
123
124let styled t pp_inner ppf value =
125 (* We need to capture the inner formatter's output as a string first *)
126 let inner_str = Format.asprintf "%a" pp_inner value in
127 Format.pp_print_string ppf (render t inner_str)
128
129(* Convenience Fmt formatters *)
130
131let pp_double = pp (v ~scale:2 ())
132let pp_triple = pp (v ~scale:3 ())
133let pp_quadruple = pp (v ~scale:4 ())
134let pp_half = pp (v ~fraction:(1, 2) ())
135
136let pp_superscript = pp (v ~fraction:(1, 2) ~vertical:`Top ())
137let pp_subscript = pp (v ~fraction:(1, 2) ~vertical:`Bottom ())
138
139let pp_scaled n = pp (v ~scale:n ())
140
141let styled_double pp_inner = styled (v ~scale:2 ()) pp_inner
142let styled_triple pp_inner = styled (v ~scale:3 ()) pp_inner
143
144let styled_superscript pp_inner = styled (v ~fraction:(1, 2) ~vertical:`Top ()) pp_inner
145let styled_subscript pp_inner = styled (v ~fraction:(1, 2) ~vertical:`Bottom ()) pp_inner
146
147(* Convenience functions *)
148
149let double text = render (v ~scale:2 ()) text
150let triple text = render (v ~scale:3 ()) text
151let quadruple text = render (v ~scale:4 ()) text
152let half text = render (v ~fraction:(1, 2) ()) text
153let superscript text = render (v ~fraction:(1, 2) ~vertical:`Top ()) text
154let subscript text = render (v ~fraction:(1, 2) ~vertical:`Bottom ()) text
155let scaled n text = render (v ~scale:n ()) text