My agentic slop goes here. Not intended for anyone else!
at main 11 kB view raw
1(** Kitty Terminal Graphics Protocol 2 3 This library implements the Kitty terminal graphics protocol, allowing 4 OCaml programs to display images in terminals that support the protocol 5 (Kitty, WezTerm, Konsole, Ghostty, etc.). 6 7 The protocol uses APC (Application Programming Command) escape sequences 8 to transmit and display pixel graphics. Images can be transmitted as raw 9 RGB/RGBA data or PNG, and displayed at specific positions with various 10 placement options. 11 12 {2 Basic Usage} 13 14 {[ 15 (* Display a PNG image *) 16 let png_data = read_file "image.png" in 17 let cmd = Kgp.Command.transmit_and_display ~format:`Png () in 18 let buf = Buffer.create 1024 in 19 Kgp.Command.write buf cmd ~data:png_data; 20 print_string (Buffer.contents buf) 21 ]} 22 23 {2 Protocol Reference} 24 25 See {{:https://sw.kovidgoyal.net/kitty/graphics-protocol/} Kitty Graphics Protocol} 26 for the full specification. *) 27 28(** {1 Polymorphic Variant Types} *) 29 30type format = [ `Rgba32 | `Rgb24 | `Png ] 31(** Image data formats. [`Rgba32] is 32-bit RGBA (4 bytes per pixel), 32 [`Rgb24] is 24-bit RGB (3 bytes per pixel), [`Png] is PNG encoded data. *) 33 34type transmission = [ `Direct | `File | `Tempfile ] 35(** Transmission methods. [`Direct] sends data inline, [`File] reads from a path, 36 [`Tempfile] reads from a temp file that the terminal deletes after reading. *) 37 38type compression = [ `None | `Zlib ] 39(** Compression options. [`None] for raw data, [`Zlib] for RFC 1950 compression. *) 40 41type quiet = [ `Noisy | `Errors_only | `Silent ] 42(** Response suppression. [`Noisy] sends all responses (default), 43 [`Errors_only] suppresses OK responses, [`Silent] suppresses all. *) 44 45type cursor = [ `Move | `Static ] 46(** Cursor movement after displaying. [`Move] advances cursor (default), 47 [`Static] keeps cursor in place. *) 48 49type composition = [ `Alpha_blend | `Overwrite ] 50(** Composition modes. [`Alpha_blend] for full blending (default), 51 [`Overwrite] for simple pixel replacement. *) 52 53type delete = 54 [ `All_visible 55 | `All_visible_and_free 56 | `By_id of int * int option 57 | `By_id_and_free of int * int option 58 | `By_number of int * int option 59 | `By_number_and_free of int * int option 60 | `At_cursor 61 | `At_cursor_and_free 62 | `At_cell of int * int 63 | `At_cell_and_free of int * int 64 | `At_cell_z of int * int * int 65 | `At_cell_z_and_free of int * int * int 66 | `By_column of int 67 | `By_column_and_free of int 68 | `By_row of int 69 | `By_row_and_free of int 70 | `By_z_index of int 71 | `By_z_index_and_free of int 72 | `By_id_range of int * int 73 | `By_id_range_and_free of int * int 74 | `Frames 75 | `Frames_and_free ] 76(** Delete target specification. Each variant has two forms: one that only 77 removes placements (e.g., [`All_visible]) and one that also frees the 78 image data (e.g., [`All_visible_and_free]). Tuple variants contain 79 (image_id, optional_placement_id) or (x, y) coordinates. *) 80 81type animation_state = [ `Stop | `Loading | `Run ] 82(** Animation playback state. [`Stop] halts animation, [`Loading] runs but 83 waits for new frames at end, [`Run] runs normally and loops. *) 84 85(** {1 Type Modules} *) 86 87module Format : sig 88 type t = format 89 90 val to_int : t -> int 91 (** Convert to protocol integer value (32, 24, or 100). *) 92end 93 94module Transmission : sig 95 type t = transmission 96 97 val to_char : t -> char 98 (** Convert to protocol character ('d', 'f', or 't'). *) 99end 100 101module Compression : sig 102 type t = compression 103 104 val to_char : t -> char option 105 (** Convert to protocol character ([None] or [Some 'z']). *) 106end 107 108module Quiet : sig 109 type t = quiet 110 111 val to_int : t -> int 112 (** Convert to protocol integer (0, 1, or 2). *) 113end 114 115module Cursor : sig 116 type t = cursor 117 118 val to_int : t -> int 119 (** Convert to protocol integer (0 or 1). *) 120end 121 122module Composition : sig 123 type t = composition 124 125 val to_int : t -> int 126 (** Convert to protocol integer (0 or 1). *) 127end 128 129module Delete : sig 130 type t = delete 131end 132 133(** {1 Placement Options} *) 134 135module Placement : sig 136 type t = Kgp_placement.t 137 (** Placement configuration. *) 138 139 val make : 140 ?source_x:int -> 141 ?source_y:int -> 142 ?source_width:int -> 143 ?source_height:int -> 144 ?cell_x_offset:int -> 145 ?cell_y_offset:int -> 146 ?columns:int -> 147 ?rows:int -> 148 ?z_index:int -> 149 ?placement_id:int -> 150 ?cursor:cursor -> 151 ?unicode_placeholder:bool -> 152 unit -> 153 t 154 (** Create a placement configuration. 155 156 @param source_x Left edge of source rectangle in pixels (default 0) 157 @param source_y Top edge of source rectangle in pixels (default 0) 158 @param source_width Width of source rectangle (default: full width) 159 @param source_height Height of source rectangle (default: full height) 160 @param cell_x_offset X offset within the first cell in pixels 161 @param cell_y_offset Y offset within the first cell in pixels 162 @param columns Number of columns to display over (scales image) 163 @param rows Number of rows to display over (scales image) 164 @param z_index Stacking order (negative = under text) 165 @param placement_id Unique ID for this placement 166 @param cursor Cursor movement policy after display 167 @param unicode_placeholder Create virtual placement for Unicode mode *) 168 169 val empty : t 170 (** Empty placement with all defaults. *) 171end 172 173(** {1 Animation} *) 174 175module Frame : sig 176 type t = Kgp_frame.t 177 (** Animation frame configuration. *) 178 179 val make : 180 ?x:int -> 181 ?y:int -> 182 ?base_frame:int -> 183 ?edit_frame:int -> 184 ?gap_ms:int -> 185 ?composition:composition -> 186 ?background_color:int32 -> 187 unit -> 188 t 189 (** Create a frame specification. 190 191 @param x Left edge where frame data is placed (pixels) 192 @param y Top edge where frame data is placed (pixels) 193 @param base_frame 1-based frame number to use as background canvas 194 @param edit_frame 1-based frame number to edit (0 = new frame) 195 @param gap_ms Delay before next frame in milliseconds 196 @param composition How to blend pixels onto the canvas 197 @param background_color 32-bit RGBA background when no base frame *) 198 199 val empty : t 200 (** Empty frame spec with defaults. *) 201end 202 203module Animation : sig 204 type state = animation_state 205 206 type t = Kgp_animation.t 207 (** Animation control operations. *) 208 209 val set_state : ?loops:int -> state -> t 210 (** Set animation state. 211 @param loops Number of loops: 0 = ignored, 1 = infinite, n = n-1 loops *) 212 213 val set_gap : frame:int -> gap_ms:int -> t 214 (** Set the gap (delay) for a specific frame. 215 @param frame 1-based frame number 216 @param gap_ms Delay in milliseconds (negative = gapless) *) 217 218 val set_current_frame : int -> t 219 (** Make a specific frame (1-based) the current displayed frame. *) 220end 221 222module Compose : sig 223 type t = Kgp_compose.t 224 (** Composition operation. *) 225 226 val make : 227 source_frame:int -> 228 dest_frame:int -> 229 ?width:int -> 230 ?height:int -> 231 ?source_x:int -> 232 ?source_y:int -> 233 ?dest_x:int -> 234 ?dest_y:int -> 235 ?composition:composition -> 236 unit -> 237 t 238 (** Compose a rectangle from one frame onto another. *) 239end 240 241(** {1 Commands} *) 242 243module Command : sig 244 type t = Kgp_command.t 245 (** A graphics protocol command. *) 246 247 (** {2 Image Transmission} *) 248 249 val transmit : 250 ?image_id:int -> 251 ?image_number:int -> 252 ?format:format -> 253 ?transmission:transmission -> 254 ?compression:compression -> 255 ?width:int -> 256 ?height:int -> 257 ?size:int -> 258 ?offset:int -> 259 ?quiet:quiet -> 260 unit -> 261 t 262 (** Transmit image data without displaying. *) 263 264 val transmit_and_display : 265 ?image_id:int -> 266 ?image_number:int -> 267 ?format:format -> 268 ?transmission:transmission -> 269 ?compression:compression -> 270 ?width:int -> 271 ?height:int -> 272 ?size:int -> 273 ?offset:int -> 274 ?quiet:quiet -> 275 ?placement:Placement.t -> 276 unit -> 277 t 278 (** Transmit image data and display it immediately. *) 279 280 val query : 281 ?format:format -> 282 ?transmission:transmission -> 283 ?width:int -> 284 ?height:int -> 285 ?quiet:quiet -> 286 unit -> 287 t 288 (** Query terminal support without storing the image. *) 289 290 (** {2 Display} *) 291 292 val display : 293 ?image_id:int -> 294 ?image_number:int -> 295 ?placement:Placement.t -> 296 ?quiet:quiet -> 297 unit -> 298 t 299 (** Display a previously transmitted image. *) 300 301 (** {2 Deletion} *) 302 303 val delete : ?quiet:quiet -> delete -> t 304 (** Delete images or placements. *) 305 306 (** {2 Animation} *) 307 308 val frame : 309 ?image_id:int -> 310 ?image_number:int -> 311 ?format:format -> 312 ?transmission:transmission -> 313 ?compression:compression -> 314 ?width:int -> 315 ?height:int -> 316 ?quiet:quiet -> 317 frame:Frame.t -> 318 unit -> 319 t 320 (** Transmit animation frame data. *) 321 322 val animate : ?image_id:int -> ?image_number:int -> ?quiet:quiet -> Animation.t -> t 323 (** Control animation playback. *) 324 325 val compose : ?image_id:int -> ?image_number:int -> ?quiet:quiet -> Compose.t -> t 326 (** Compose animation frames. *) 327 328 (** {2 Output} *) 329 330 val write : Buffer.t -> t -> data:string -> unit 331 (** Write the command to a buffer. *) 332 333 val to_string : t -> data:string -> string 334 (** Convert command to a string. *) 335end 336 337(** {1 Response Parsing} *) 338 339module Response : sig 340 type t = Kgp_response.t 341 (** A parsed terminal response. *) 342 343 val parse : string -> t option 344 (** Parse a response from terminal output. *) 345 346 val is_ok : t -> bool 347 (** Check if the response indicates success. *) 348 349 val message : t -> string 350 (** Get the response message. *) 351 352 val error_code : t -> string option 353 (** Extract the error code if this is an error response. *) 354 355 val image_id : t -> int option 356 (** Get the image ID from the response. *) 357 358 val image_number : t -> int option 359 (** Get the image number from the response. *) 360 361 val placement_id : t -> int option 362 (** Get the placement ID from the response. *) 363end 364 365(** {1 Unicode Placeholders} *) 366 367module Unicode_placeholder : sig 368 val placeholder_char : Uchar.t 369 (** The Unicode placeholder character U+10EEEE. *) 370 371 val write : 372 Buffer.t -> 373 image_id:int -> 374 ?placement_id:int -> 375 rows:int -> 376 cols:int -> 377 unit -> 378 unit 379 (** Write placeholder characters to a buffer. *) 380 381 val row_diacritic : int -> Uchar.t 382 (** Get the combining diacritic for a row number (0-based). *) 383 384 val column_diacritic : int -> Uchar.t 385 (** Get the combining diacritic for a column number (0-based). *) 386 387 val id_high_byte_diacritic : int -> Uchar.t 388 (** Get the diacritic for the high byte of a 32-bit image ID. *) 389end 390 391(** {1 Terminal Detection} *) 392 393module Detect : sig 394 val make_query : unit -> string 395 (** Generate a query command to test graphics support. *) 396 397 val supports_graphics : Response.t option -> da1_received:bool -> bool 398 (** Determine if graphics are supported based on query results. *) 399end