My agentic slop goes here. Not intended for anyone else!

.

+1
tgp/.gitignore
···
+
_build
+116
tgp/README.md
···
+
# Textsize
+
+
A clean, standalone OCaml library implementing the [Kitty text sizing protocol](https://sw.kovidgoyal.net/kitty/text-sizing-protocol/).
+
+
## Overview
+
+
The Kitty text sizing protocol (introduced in kitty v0.40.0) allows terminals to render text in different sizes, enabling typographic features like headlines, superscripts, and subscripts.
+
+
## Features
+
+
- โœจ Clean, type-safe API with validation
+
- ๐Ÿ“ฆ Zero dependencies (besides OCaml standard library)
+
- ๐ŸŽฏ Full protocol support (scale, width, fractional sizing, alignment)
+
- ๐Ÿš€ Convenient helper functions for common use cases
+
- ๐Ÿ“ Comprehensive documentation
+
+
## Installation
+
+
```bash
+
# Via opam (once published)
+
opam install textsize
+
+
# Or add to your dune-project dependencies
+
(depends
+
(textsize (>= 0.1.0)))
+
```
+
+
## Quick Start
+
+
```ocaml
+
(* Simple convenience functions *)
+
print_string (Textsize.double "Hello, World!");;
+
print_string (Textsize.triple "Big Text");;
+
print_string (Textsize.half "Small text");;
+
+
(* Superscripts and subscripts *)
+
print_string "E=mc";
+
print_string (Textsize.superscript "2");;
+
+
print_string "H";
+
print_string (Textsize.subscript "2");
+
print_string "O";;
+
+
(* Custom sizing with metadata *)
+
let custom =
+
Textsize.empty
+
|> Textsize.with_scale (Textsize.make_scale 4)
+
|> Textsize.with_width (Textsize.make_width 6)
+
in
+
print_string (Textsize.render custom "Custom sized");;
+
```
+
+
## API Overview
+
+
### Core Types
+
+
- `scale` - Text scale factor (1-7)
+
- `width` - Width in cells (0-7)
+
- `numerator`/`denominator` - Fractional scaling (0-15)
+
- `vertical_align` - Vertical alignment (Bottom, Center, Top)
+
- `horizontal_align` - Horizontal alignment (Left, Center, Right)
+
- `metadata` - Combined sizing metadata
+
+
### Convenience Functions
+
+
- `double`, `triple`, `quadruple` - Quick size multipliers
+
- `half` - Half-sized text
+
- `superscript`, `subscript` - Typographic positioning
+
- `scaled n` - Arbitrary scale factor
+
+
### Metadata Builders
+
+
- `empty` - Start with empty metadata
+
- `with_scale` - Set scale factor
+
- `with_width` - Set width
+
- `with_fraction` - Set fractional scaling
+
- `with_vertical_align` - Set vertical alignment
+
- `with_horizontal_align` - Set horizontal alignment
+
+
### Rendering
+
+
- `render metadata text` - Generate escape sequence
+
- `render_to_channel oc metadata text` - Write to channel
+
+
## Building from Source
+
+
```bash
+
cd textsize
+
dune build
+
dune exec example/demo.exe # Run example
+
```
+
+
## Terminal Compatibility
+
+
This library generates escape sequences for the Kitty text sizing protocol. It requires a terminal emulator that supports this protocol:
+
+
- โœ… [Kitty](https://sw.kovidgoyal.net/kitty/) (v0.40.0+)
+
- โœ… [Ghostty](https://ghostty.org/) (with protocol support)
+
+
Other terminals will typically ignore these sequences gracefully.
+
+
## Protocol Reference
+
+
The library implements OSC 66 sequences as specified in the [Kitty text sizing protocol documentation](https://sw.kovidgoyal.net/kitty/text-sizing-protocol/).
+
+
Format: `ESC ] 66 ; metadata ; text BEL`
+
+
Where metadata is colon-separated key=value pairs.
+
+
## License
+
+
MIT
+
+
## Contributing
+
+
Contributions welcome! Please feel free to submit issues or pull requests.
+18
tgp/dune-project
···
+
(lang dune 3.0)
+
(name textsize)
+
(version 0.1.0)
+
+
(generate_opam_files true)
+
+
(source (github username/textsize))
+
(license MIT)
+
(authors "Anonymous")
+
(maintainers "Anonymous")
+
+
(package
+
(name textsize)
+
(synopsis "OCaml implementation of the Kitty text sizing protocol")
+
(description "A clean, standalone library for generating escape sequences to render text in different sizes using the Kitty terminal's text sizing protocol.")
+
(depends
+
(ocaml (>= 4.14))
+
dune))
+56
tgp/example/demo.ml
···
+
(* Example demonstrating the textsize library *)
+
+
let () =
+
print_endline "=== Kitty Text Sizing Protocol Demo ===\n";
+
+
(* Simple convenience functions *)
+
print_string (Textsize.double "Double sized text");
+
print_endline "\n";
+
+
print_string (Textsize.triple "Triple sized text");
+
print_endline "\n\n";
+
+
print_string (Textsize.quadruple "Quadruple sized text");
+
print_endline "\n\n\n";
+
+
(* Scaled text *)
+
print_string (Textsize.scaled 5 "Scale 5 text");
+
print_endline "\n\n\n\n";
+
+
(* Fractional scaling *)
+
print_string (Textsize.half "Half sized text");
+
print_newline ();
+
+
(* Superscripts and subscripts *)
+
print_string "E=mc";
+
print_string (Textsize.superscript "2");
+
print_newline ();
+
+
print_string "H";
+
print_string (Textsize.subscript "2");
+
print_string "O";
+
print_newline ();
+
+
(* Custom metadata *)
+
print_newline ();
+
let custom =
+
Textsize.empty
+
|> Textsize.with_scale (Textsize.make_scale 3)
+
|> Textsize.with_width (Textsize.make_width 5)
+
in
+
print_string (Textsize.render custom "Custom sized text");
+
print_endline "\n\n";
+
+
(* Fractional with alignment *)
+
let aligned =
+
Textsize.empty
+
|> Textsize.with_fraction
+
(Textsize.make_numerator 1)
+
(Textsize.make_denominator 3)
+
|> Textsize.with_vertical_align Textsize.Center
+
|> Textsize.with_horizontal_align Textsize.Center
+
in
+
print_string (Textsize.render aligned "Centered 1/3 size text");
+
print_newline ();
+
+
print_endline "\n=== Demo Complete ===";
+3
tgp/example/dune
···
+
(executable
+
(name demo)
+
(libraries textsize))
+3
tgp/src/dune
···
+
(library
+
(name textsize)
+
(public_name textsize))
+167
tgp/src/textsize.ml
···
+
(** OCaml implementation of the Kitty text sizing protocol *)
+
+
(* Types *)
+
+
type scale = int
+
type width = int
+
type numerator = int
+
type denominator = int
+
+
type vertical_align =
+
| Bottom
+
| Center
+
| Top
+
+
type horizontal_align =
+
| Left
+
| Center
+
| Right
+
+
type metadata = {
+
scale : scale option;
+
width : width option;
+
numerator : numerator option;
+
denominator : denominator option;
+
vertical : vertical_align option;
+
horizontal : horizontal_align option;
+
}
+
+
(* Constructors with validation *)
+
+
let make_scale n =
+
if n < 1 || n > 7 then
+
invalid_arg (Printf.sprintf "scale must be in range 1-7, got %d" n)
+
else
+
n
+
+
let make_width n =
+
if n < 0 || n > 7 then
+
invalid_arg (Printf.sprintf "width must be in range 0-7, got %d" n)
+
else
+
n
+
+
let make_numerator n =
+
if n < 0 || n > 15 then
+
invalid_arg (Printf.sprintf "numerator must be in range 0-15, got %d" n)
+
else
+
n
+
+
let make_denominator n =
+
if n < 0 || n > 15 then
+
invalid_arg (Printf.sprintf "denominator must be in range 0-15, got %d" n)
+
else
+
n
+
+
(* Metadata creation *)
+
+
let empty = {
+
scale = None;
+
width = None;
+
numerator = None;
+
denominator = None;
+
vertical = None;
+
horizontal = None;
+
}
+
+
let with_scale s metadata = { metadata with scale = Some s }
+
let with_width w metadata = { metadata with width = Some w }
+
+
let with_fraction num den metadata =
+
{ metadata with numerator = Some num; denominator = Some den }
+
+
let with_vertical_align v metadata = { metadata with vertical = Some v }
+
let with_horizontal_align h metadata = { metadata with horizontal = Some h }
+
+
(* Conversion helpers *)
+
+
let vertical_align_to_int = function
+
| Bottom -> 0
+
| Center -> 1
+
| Top -> 2
+
+
let horizontal_align_to_int = function
+
| Left -> 0
+
| Center -> 1
+
| Right -> 2
+
+
(* Escape sequence generation *)
+
+
let metadata_to_string metadata =
+
let parts = [] in
+
let parts = match metadata.scale with
+
| Some s -> (Printf.sprintf "s=%d" s) :: parts
+
| None -> parts
+
in
+
let parts = match metadata.width with
+
| Some w -> (Printf.sprintf "w=%d" w) :: parts
+
| None -> parts
+
in
+
let parts = match metadata.numerator with
+
| Some n -> (Printf.sprintf "n=%d" n) :: parts
+
| None -> parts
+
in
+
let parts = match metadata.denominator with
+
| Some d -> (Printf.sprintf "d=%d" d) :: parts
+
| None -> parts
+
in
+
let parts = match metadata.vertical with
+
| Some v -> (Printf.sprintf "v=%d" (vertical_align_to_int v)) :: parts
+
| None -> parts
+
in
+
let parts = match metadata.horizontal with
+
| Some h -> (Printf.sprintf "h=%d" (horizontal_align_to_int h)) :: parts
+
| None -> parts
+
in
+
String.concat ":" (List.rev parts)
+
+
let render metadata text =
+
(* Validate text length (max 4096 bytes of UTF-8) *)
+
let text_len = String.length text in
+
if text_len > 4096 then
+
invalid_arg (Printf.sprintf "text exceeds 4096 bytes (got %d)" text_len);
+
+
let metadata_str = metadata_to_string metadata in
+
+
(* OSC 66 ; metadata ; text BEL *)
+
(* Using \x1b for ESC and \x07 for BEL *)
+
if metadata_str = "" then
+
Printf.sprintf "\x1b]66;;%s\x07" text
+
else
+
Printf.sprintf "\x1b]66;%s;%s\x07" metadata_str text
+
+
let render_to_channel oc metadata text =
+
output_string oc (render metadata text);
+
flush oc
+
+
(* Convenience functions *)
+
+
let double text =
+
render (with_scale (make_scale 2) empty) text
+
+
let triple text =
+
render (with_scale (make_scale 3) empty) text
+
+
let quadruple text =
+
render (with_scale (make_scale 4) empty) text
+
+
let half text =
+
render
+
(with_fraction (make_numerator 1) (make_denominator 2) empty)
+
text
+
+
let superscript text =
+
render
+
(empty
+
|> with_fraction (make_numerator 1) (make_denominator 2)
+
|> with_vertical_align Top)
+
text
+
+
let subscript text =
+
render
+
(empty
+
|> with_fraction (make_numerator 1) (make_denominator 2)
+
|> with_vertical_align Bottom)
+
text
+
+
let scaled n text =
+
render (with_scale (make_scale n) empty) text
+141
tgp/src/textsize.mli
···
+
(** OCaml implementation of the Kitty text sizing protocol.
+
+
This library provides a clean API for generating escape sequences to render
+
text in different sizes within terminals that support the Kitty text sizing
+
protocol (introduced in kitty v0.40.0).
+
+
The protocol allows rendering text at multiple sizes both larger and smaller
+
than the base text, enabling typographic features like headlines, superscripts,
+
and subscripts.
+
*)
+
+
(** {1 Types} *)
+
+
(** Scale factor for text rendering (1-7).
+
+
Controls the overall size of the text block. A scale of [s] will render text
+
in a block of [s * w] by [s] cells (where [w] is the width parameter). *)
+
type scale = private int
+
+
(** Width in cells for text rendering (0-7).
+
+
When set to 0, width is auto-calculated based on text length. *)
+
type width = private int
+
+
(** Fractional scaling numerator (0-15).
+
+
Used together with denominator for precise fractional scaling. *)
+
type numerator = private int
+
+
(** Fractional scaling denominator (0-15).
+
+
Used together with numerator for precise fractional scaling. *)
+
type denominator = private int
+
+
(** Vertical alignment for fractionally scaled text.
+
- [Bottom]: Align to bottom (0)
+
- [Center]: Align to center (1)
+
- [Top]: Align to top (2) *)
+
type vertical_align =
+
| Bottom
+
| Center
+
| Top
+
+
(** Horizontal alignment for fractionally scaled text.
+
- [Left]: Align to left (0)
+
- [Center]: Align to center (1)
+
- [Right]: Align to right (2) *)
+
type horizontal_align =
+
| Left
+
| Center
+
| Right
+
+
(** Metadata for text sizing. *)
+
type metadata = {
+
scale : scale option;
+
width : width option;
+
numerator : numerator option;
+
denominator : denominator option;
+
vertical : vertical_align option;
+
horizontal : horizontal_align option;
+
}
+
+
(** {1 Constructors} *)
+
+
(** [make_scale n] creates a scale value.
+
@raise Invalid_argument if [n] is not in range 1-7. *)
+
val make_scale : int -> scale
+
+
(** [make_width n] creates a width value.
+
@raise Invalid_argument if [n] is not in range 0-7. *)
+
val make_width : int -> width
+
+
(** [make_numerator n] creates a numerator value.
+
@raise Invalid_argument if [n] is not in range 0-15. *)
+
val make_numerator : int -> numerator
+
+
(** [make_denominator n] creates a denominator value.
+
@raise Invalid_argument if [n] is not in range 0-15. *)
+
val make_denominator : int -> denominator
+
+
(** {1 Metadata Creation} *)
+
+
(** Empty metadata (all fields set to [None]). *)
+
val empty : metadata
+
+
(** [with_scale s metadata] sets the scale. *)
+
val with_scale : scale -> metadata -> metadata
+
+
(** [with_width w metadata] sets the width. *)
+
val with_width : width -> metadata -> metadata
+
+
(** [with_fraction num den metadata] sets fractional scaling. *)
+
val with_fraction : numerator -> denominator -> metadata -> metadata
+
+
(** [with_vertical_align v metadata] sets vertical alignment. *)
+
val with_vertical_align : vertical_align -> metadata -> metadata
+
+
(** [with_horizontal_align h metadata] sets horizontal alignment. *)
+
val with_horizontal_align : horizontal_align -> metadata -> metadata
+
+
(** {1 Escape Sequence Generation} *)
+
+
(** [render metadata text] generates the complete escape sequence for sized text.
+
+
@param metadata The sizing metadata
+
@param text The text to render (max 4096 bytes of UTF-8)
+
@return The escape sequence string
+
@raise Invalid_argument if text exceeds 4096 bytes *)
+
val render : metadata -> string -> string
+
+
(** [render_to_channel oc metadata text] writes the escape sequence to a channel.
+
+
@param oc Output channel
+
@param metadata The sizing metadata
+
@param text The text to render (max 4096 bytes of UTF-8)
+
@raise Invalid_argument if text exceeds 4096 bytes *)
+
val render_to_channel : out_channel -> metadata -> string -> unit
+
+
(** {1 Convenience Functions} *)
+
+
(** [double text] renders text at double size (scale=2). *)
+
val double : string -> string
+
+
(** [triple text] renders text at triple size (scale=3). *)
+
val triple : string -> string
+
+
(** [quadruple text] renders text at quadruple size (scale=4). *)
+
val quadruple : string -> string
+
+
(** [half text] renders text at half size (n=1, d=2). *)
+
val half : string -> string
+
+
(** [superscript text] renders text as superscript (n=1, d=2, v=Top). *)
+
val superscript : string -> string
+
+
(** [subscript text] renders text as subscript (n=1, d=2, v=Bottom). *)
+
val subscript : string -> string
+
+
(** [scaled n text] renders text at scale [n] (1-7).
+
@raise Invalid_argument if [n] is not in range 1-7. *)
+
val scaled : int -> string -> string
+3
tgp/test/dune
···
+
(test
+
(name test_textsize)
+
(libraries textsize))
+104
tgp/test/test_textsize.ml
···
+
(* Basic tests for the textsize library *)
+
+
let test name f =
+
try
+
f ();
+
Printf.printf "โœ“ %s\n" name
+
with e ->
+
Printf.printf "โœ— %s: %s\n" name (Printexc.to_string e);
+
exit 1
+
+
let () =
+
print_endline "Running textsize tests...\n";
+
+
(* Test scale validation *)
+
test "scale validation - valid range" (fun () ->
+
let _ = Textsize.make_scale 1 in
+
let _ = Textsize.make_scale 7 in
+
()
+
);
+
+
test "scale validation - rejects invalid" (fun () ->
+
try
+
let _ = Textsize.make_scale 0 in
+
failwith "Should have raised Invalid_argument"
+
with Invalid_argument _ -> ()
+
);
+
+
(* Test width validation *)
+
test "width validation - valid range" (fun () ->
+
let _ = Textsize.make_width 0 in
+
let _ = Textsize.make_width 7 in
+
()
+
);
+
+
(* Test escape sequence generation *)
+
test "double escape sequence" (fun () ->
+
let result = Textsize.double "test" in
+
assert (String.length result > 0);
+
assert (result = "\x1b]66;s=2;test\x07")
+
);
+
+
test "triple escape sequence" (fun () ->
+
let result = Textsize.triple "hello" in
+
assert (result = "\x1b]66;s=3;hello\x07")
+
);
+
+
test "half escape sequence" (fun () ->
+
let result = Textsize.half "tiny" in
+
assert (result = "\x1b]66;n=1:d=2;tiny\x07")
+
);
+
+
test "superscript escape sequence" (fun () ->
+
let result = Textsize.superscript "2" in
+
assert (result = "\x1b]66;n=1:d=2:v=2;2\x07")
+
);
+
+
test "subscript escape sequence" (fun () ->
+
let result = Textsize.subscript "2" in
+
assert (result = "\x1b]66;n=1:d=2:v=0;2\x07")
+
);
+
+
(* Test custom metadata *)
+
test "custom metadata - scale and width" (fun () ->
+
let metadata =
+
Textsize.empty
+
|> Textsize.with_scale (Textsize.make_scale 3)
+
|> Textsize.with_width (Textsize.make_width 5)
+
in
+
let result = Textsize.render metadata "custom" in
+
assert (result = "\x1b]66;s=3:w=5;custom\x07")
+
);
+
+
test "custom metadata - fractional" (fun () ->
+
let metadata =
+
Textsize.empty
+
|> Textsize.with_fraction
+
(Textsize.make_numerator 2)
+
(Textsize.make_denominator 3)
+
in
+
let result = Textsize.render metadata "frac" in
+
assert (result = "\x1b]66;n=2:d=3;frac\x07")
+
);
+
+
test "empty metadata" (fun () ->
+
let result = Textsize.render Textsize.empty "plain" in
+
assert (result = "\x1b]66;;plain\x07")
+
);
+
+
(* Test text length validation *)
+
test "text length validation - accepts valid" (fun () ->
+
let text = String.make 4096 'a' in
+
let _ = Textsize.double text in
+
()
+
);
+
+
test "text length validation - rejects oversized" (fun () ->
+
let text = String.make 4097 'a' in
+
try
+
let _ = Textsize.double text in
+
failwith "Should have raised Invalid_argument"
+
with Invalid_argument _ -> ()
+
);
+
+
print_endline "\nโœ“ All tests passed!"
+31
tgp/textsize.opam
···
+
# This file is generated by dune, edit dune-project instead
+
opam-version: "2.0"
+
version: "0.1.0"
+
synopsis: "OCaml implementation of the Kitty text sizing protocol"
+
description:
+
"A clean, standalone library for generating escape sequences to render text in different sizes using the Kitty terminal's text sizing protocol."
+
maintainer: ["Anonymous"]
+
authors: ["Anonymous"]
+
license: "MIT"
+
homepage: "https://github.com/username/textsize"
+
bug-reports: "https://github.com/username/textsize/issues"
+
depends: [
+
"ocaml" {>= "4.14"}
+
"dune" {>= "3.0"}
+
"odoc" {with-doc}
+
]
+
build: [
+
["dune" "subst"] {dev}
+
[
+
"dune"
+
"build"
+
"-p"
+
name
+
"-j"
+
jobs
+
"@install"
+
"@runtest" {with-test}
+
"@doc" {with-doc}
+
]
+
]
+
dev-repo: "git+https://github.com/username/textsize.git"