this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

.

+643
+1
tgp/.gitignore
··· 1 + _build
+116
tgp/README.md
··· 1 + # Textsize 2 + 3 + A clean, standalone OCaml library implementing the [Kitty text sizing protocol](https://sw.kovidgoyal.net/kitty/text-sizing-protocol/). 4 + 5 + ## Overview 6 + 7 + 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. 8 + 9 + ## Features 10 + 11 + - ✨ Clean, type-safe API with validation 12 + - 📦 Zero dependencies (besides OCaml standard library) 13 + - 🎯 Full protocol support (scale, width, fractional sizing, alignment) 14 + - 🚀 Convenient helper functions for common use cases 15 + - 📝 Comprehensive documentation 16 + 17 + ## Installation 18 + 19 + ```bash 20 + # Via opam (once published) 21 + opam install textsize 22 + 23 + # Or add to your dune-project dependencies 24 + (depends 25 + (textsize (>= 0.1.0))) 26 + ``` 27 + 28 + ## Quick Start 29 + 30 + ```ocaml 31 + (* Simple convenience functions *) 32 + print_string (Textsize.double "Hello, World!");; 33 + print_string (Textsize.triple "Big Text");; 34 + print_string (Textsize.half "Small text");; 35 + 36 + (* Superscripts and subscripts *) 37 + print_string "E=mc"; 38 + print_string (Textsize.superscript "2");; 39 + 40 + print_string "H"; 41 + print_string (Textsize.subscript "2"); 42 + print_string "O";; 43 + 44 + (* Custom sizing with metadata *) 45 + let custom = 46 + Textsize.empty 47 + |> Textsize.with_scale (Textsize.make_scale 4) 48 + |> Textsize.with_width (Textsize.make_width 6) 49 + in 50 + print_string (Textsize.render custom "Custom sized");; 51 + ``` 52 + 53 + ## API Overview 54 + 55 + ### Core Types 56 + 57 + - `scale` - Text scale factor (1-7) 58 + - `width` - Width in cells (0-7) 59 + - `numerator`/`denominator` - Fractional scaling (0-15) 60 + - `vertical_align` - Vertical alignment (Bottom, Center, Top) 61 + - `horizontal_align` - Horizontal alignment (Left, Center, Right) 62 + - `metadata` - Combined sizing metadata 63 + 64 + ### Convenience Functions 65 + 66 + - `double`, `triple`, `quadruple` - Quick size multipliers 67 + - `half` - Half-sized text 68 + - `superscript`, `subscript` - Typographic positioning 69 + - `scaled n` - Arbitrary scale factor 70 + 71 + ### Metadata Builders 72 + 73 + - `empty` - Start with empty metadata 74 + - `with_scale` - Set scale factor 75 + - `with_width` - Set width 76 + - `with_fraction` - Set fractional scaling 77 + - `with_vertical_align` - Set vertical alignment 78 + - `with_horizontal_align` - Set horizontal alignment 79 + 80 + ### Rendering 81 + 82 + - `render metadata text` - Generate escape sequence 83 + - `render_to_channel oc metadata text` - Write to channel 84 + 85 + ## Building from Source 86 + 87 + ```bash 88 + cd textsize 89 + dune build 90 + dune exec example/demo.exe # Run example 91 + ``` 92 + 93 + ## Terminal Compatibility 94 + 95 + This library generates escape sequences for the Kitty text sizing protocol. It requires a terminal emulator that supports this protocol: 96 + 97 + - ✅ [Kitty](https://sw.kovidgoyal.net/kitty/) (v0.40.0+) 98 + - ✅ [Ghostty](https://ghostty.org/) (with protocol support) 99 + 100 + Other terminals will typically ignore these sequences gracefully. 101 + 102 + ## Protocol Reference 103 + 104 + The library implements OSC 66 sequences as specified in the [Kitty text sizing protocol documentation](https://sw.kovidgoyal.net/kitty/text-sizing-protocol/). 105 + 106 + Format: `ESC ] 66 ; metadata ; text BEL` 107 + 108 + Where metadata is colon-separated key=value pairs. 109 + 110 + ## License 111 + 112 + MIT 113 + 114 + ## Contributing 115 + 116 + Contributions welcome! Please feel free to submit issues or pull requests.
+18
tgp/dune-project
··· 1 + (lang dune 3.0) 2 + (name textsize) 3 + (version 0.1.0) 4 + 5 + (generate_opam_files true) 6 + 7 + (source (github username/textsize)) 8 + (license MIT) 9 + (authors "Anonymous") 10 + (maintainers "Anonymous") 11 + 12 + (package 13 + (name textsize) 14 + (synopsis "OCaml implementation of the Kitty text sizing protocol") 15 + (description "A clean, standalone library for generating escape sequences to render text in different sizes using the Kitty terminal's text sizing protocol.") 16 + (depends 17 + (ocaml (>= 4.14)) 18 + dune))
+56
tgp/example/demo.ml
··· 1 + (* Example demonstrating the textsize library *) 2 + 3 + let () = 4 + print_endline "=== Kitty Text Sizing Protocol Demo ===\n"; 5 + 6 + (* Simple convenience functions *) 7 + print_string (Textsize.double "Double sized text"); 8 + print_endline "\n"; 9 + 10 + print_string (Textsize.triple "Triple sized text"); 11 + print_endline "\n\n"; 12 + 13 + print_string (Textsize.quadruple "Quadruple sized text"); 14 + print_endline "\n\n\n"; 15 + 16 + (* Scaled text *) 17 + print_string (Textsize.scaled 5 "Scale 5 text"); 18 + print_endline "\n\n\n\n"; 19 + 20 + (* Fractional scaling *) 21 + print_string (Textsize.half "Half sized text"); 22 + print_newline (); 23 + 24 + (* Superscripts and subscripts *) 25 + print_string "E=mc"; 26 + print_string (Textsize.superscript "2"); 27 + print_newline (); 28 + 29 + print_string "H"; 30 + print_string (Textsize.subscript "2"); 31 + print_string "O"; 32 + print_newline (); 33 + 34 + (* Custom metadata *) 35 + print_newline (); 36 + let custom = 37 + Textsize.empty 38 + |> Textsize.with_scale (Textsize.make_scale 3) 39 + |> Textsize.with_width (Textsize.make_width 5) 40 + in 41 + print_string (Textsize.render custom "Custom sized text"); 42 + print_endline "\n\n"; 43 + 44 + (* Fractional with alignment *) 45 + let aligned = 46 + Textsize.empty 47 + |> Textsize.with_fraction 48 + (Textsize.make_numerator 1) 49 + (Textsize.make_denominator 3) 50 + |> Textsize.with_vertical_align Textsize.Center 51 + |> Textsize.with_horizontal_align Textsize.Center 52 + in 53 + print_string (Textsize.render aligned "Centered 1/3 size text"); 54 + print_newline (); 55 + 56 + print_endline "\n=== Demo Complete ===";
+3
tgp/example/dune
··· 1 + (executable 2 + (name demo) 3 + (libraries textsize))
+3
tgp/src/dune
··· 1 + (library 2 + (name textsize) 3 + (public_name textsize))
+167
tgp/src/textsize.ml
··· 1 + (** OCaml implementation of the Kitty text sizing protocol *) 2 + 3 + (* Types *) 4 + 5 + type scale = int 6 + type width = int 7 + type numerator = int 8 + type denominator = int 9 + 10 + type vertical_align = 11 + | Bottom 12 + | Center 13 + | Top 14 + 15 + type horizontal_align = 16 + | Left 17 + | Center 18 + | Right 19 + 20 + type metadata = { 21 + scale : scale option; 22 + width : width option; 23 + numerator : numerator option; 24 + denominator : denominator option; 25 + vertical : vertical_align option; 26 + horizontal : horizontal_align option; 27 + } 28 + 29 + (* Constructors with validation *) 30 + 31 + let make_scale n = 32 + if n < 1 || n > 7 then 33 + invalid_arg (Printf.sprintf "scale must be in range 1-7, got %d" n) 34 + else 35 + n 36 + 37 + let make_width n = 38 + if n < 0 || n > 7 then 39 + invalid_arg (Printf.sprintf "width must be in range 0-7, got %d" n) 40 + else 41 + n 42 + 43 + let make_numerator n = 44 + if n < 0 || n > 15 then 45 + invalid_arg (Printf.sprintf "numerator must be in range 0-15, got %d" n) 46 + else 47 + n 48 + 49 + let make_denominator n = 50 + if n < 0 || n > 15 then 51 + invalid_arg (Printf.sprintf "denominator must be in range 0-15, got %d" n) 52 + else 53 + n 54 + 55 + (* Metadata creation *) 56 + 57 + let empty = { 58 + scale = None; 59 + width = None; 60 + numerator = None; 61 + denominator = None; 62 + vertical = None; 63 + horizontal = None; 64 + } 65 + 66 + let with_scale s metadata = { metadata with scale = Some s } 67 + let with_width w metadata = { metadata with width = Some w } 68 + 69 + let with_fraction num den metadata = 70 + { metadata with numerator = Some num; denominator = Some den } 71 + 72 + let with_vertical_align v metadata = { metadata with vertical = Some v } 73 + let with_horizontal_align h metadata = { metadata with horizontal = Some h } 74 + 75 + (* Conversion helpers *) 76 + 77 + let vertical_align_to_int = function 78 + | Bottom -> 0 79 + | Center -> 1 80 + | Top -> 2 81 + 82 + let horizontal_align_to_int = function 83 + | Left -> 0 84 + | Center -> 1 85 + | Right -> 2 86 + 87 + (* Escape sequence generation *) 88 + 89 + let metadata_to_string metadata = 90 + let parts = [] in 91 + let parts = match metadata.scale with 92 + | Some s -> (Printf.sprintf "s=%d" s) :: parts 93 + | None -> parts 94 + in 95 + let parts = match metadata.width with 96 + | Some w -> (Printf.sprintf "w=%d" w) :: parts 97 + | None -> parts 98 + in 99 + let parts = match metadata.numerator with 100 + | Some n -> (Printf.sprintf "n=%d" n) :: parts 101 + | None -> parts 102 + in 103 + let parts = match metadata.denominator with 104 + | Some d -> (Printf.sprintf "d=%d" d) :: parts 105 + | None -> parts 106 + in 107 + let parts = match metadata.vertical with 108 + | Some v -> (Printf.sprintf "v=%d" (vertical_align_to_int v)) :: parts 109 + | None -> parts 110 + in 111 + let parts = match metadata.horizontal with 112 + | Some h -> (Printf.sprintf "h=%d" (horizontal_align_to_int h)) :: parts 113 + | None -> parts 114 + in 115 + String.concat ":" (List.rev parts) 116 + 117 + let render metadata text = 118 + (* Validate text length (max 4096 bytes of UTF-8) *) 119 + let text_len = String.length text in 120 + if text_len > 4096 then 121 + invalid_arg (Printf.sprintf "text exceeds 4096 bytes (got %d)" text_len); 122 + 123 + let metadata_str = metadata_to_string metadata in 124 + 125 + (* OSC 66 ; metadata ; text BEL *) 126 + (* Using \x1b for ESC and \x07 for BEL *) 127 + if metadata_str = "" then 128 + Printf.sprintf "\x1b]66;;%s\x07" text 129 + else 130 + Printf.sprintf "\x1b]66;%s;%s\x07" metadata_str text 131 + 132 + let render_to_channel oc metadata text = 133 + output_string oc (render metadata text); 134 + flush oc 135 + 136 + (* Convenience functions *) 137 + 138 + let double text = 139 + render (with_scale (make_scale 2) empty) text 140 + 141 + let triple text = 142 + render (with_scale (make_scale 3) empty) text 143 + 144 + let quadruple text = 145 + render (with_scale (make_scale 4) empty) text 146 + 147 + let half text = 148 + render 149 + (with_fraction (make_numerator 1) (make_denominator 2) empty) 150 + text 151 + 152 + let superscript text = 153 + render 154 + (empty 155 + |> with_fraction (make_numerator 1) (make_denominator 2) 156 + |> with_vertical_align Top) 157 + text 158 + 159 + let subscript text = 160 + render 161 + (empty 162 + |> with_fraction (make_numerator 1) (make_denominator 2) 163 + |> with_vertical_align Bottom) 164 + text 165 + 166 + let scaled n text = 167 + render (with_scale (make_scale n) empty) text
+141
tgp/src/textsize.mli
··· 1 + (** OCaml implementation of the Kitty text sizing protocol. 2 + 3 + This library provides a clean API for generating escape sequences to render 4 + text in different sizes within terminals that support the Kitty text sizing 5 + protocol (introduced in kitty v0.40.0). 6 + 7 + The protocol allows rendering text at multiple sizes both larger and smaller 8 + than the base text, enabling typographic features like headlines, superscripts, 9 + and subscripts. 10 + *) 11 + 12 + (** {1 Types} *) 13 + 14 + (** Scale factor for text rendering (1-7). 15 + 16 + Controls the overall size of the text block. A scale of [s] will render text 17 + in a block of [s * w] by [s] cells (where [w] is the width parameter). *) 18 + type scale = private int 19 + 20 + (** Width in cells for text rendering (0-7). 21 + 22 + When set to 0, width is auto-calculated based on text length. *) 23 + type width = private int 24 + 25 + (** Fractional scaling numerator (0-15). 26 + 27 + Used together with denominator for precise fractional scaling. *) 28 + type numerator = private int 29 + 30 + (** Fractional scaling denominator (0-15). 31 + 32 + Used together with numerator for precise fractional scaling. *) 33 + type denominator = private int 34 + 35 + (** Vertical alignment for fractionally scaled text. 36 + - [Bottom]: Align to bottom (0) 37 + - [Center]: Align to center (1) 38 + - [Top]: Align to top (2) *) 39 + type vertical_align = 40 + | Bottom 41 + | Center 42 + | Top 43 + 44 + (** Horizontal alignment for fractionally scaled text. 45 + - [Left]: Align to left (0) 46 + - [Center]: Align to center (1) 47 + - [Right]: Align to right (2) *) 48 + type horizontal_align = 49 + | Left 50 + | Center 51 + | Right 52 + 53 + (** Metadata for text sizing. *) 54 + type metadata = { 55 + scale : scale option; 56 + width : width option; 57 + numerator : numerator option; 58 + denominator : denominator option; 59 + vertical : vertical_align option; 60 + horizontal : horizontal_align option; 61 + } 62 + 63 + (** {1 Constructors} *) 64 + 65 + (** [make_scale n] creates a scale value. 66 + @raise Invalid_argument if [n] is not in range 1-7. *) 67 + val make_scale : int -> scale 68 + 69 + (** [make_width n] creates a width value. 70 + @raise Invalid_argument if [n] is not in range 0-7. *) 71 + val make_width : int -> width 72 + 73 + (** [make_numerator n] creates a numerator value. 74 + @raise Invalid_argument if [n] is not in range 0-15. *) 75 + val make_numerator : int -> numerator 76 + 77 + (** [make_denominator n] creates a denominator value. 78 + @raise Invalid_argument if [n] is not in range 0-15. *) 79 + val make_denominator : int -> denominator 80 + 81 + (** {1 Metadata Creation} *) 82 + 83 + (** Empty metadata (all fields set to [None]). *) 84 + val empty : metadata 85 + 86 + (** [with_scale s metadata] sets the scale. *) 87 + val with_scale : scale -> metadata -> metadata 88 + 89 + (** [with_width w metadata] sets the width. *) 90 + val with_width : width -> metadata -> metadata 91 + 92 + (** [with_fraction num den metadata] sets fractional scaling. *) 93 + val with_fraction : numerator -> denominator -> metadata -> metadata 94 + 95 + (** [with_vertical_align v metadata] sets vertical alignment. *) 96 + val with_vertical_align : vertical_align -> metadata -> metadata 97 + 98 + (** [with_horizontal_align h metadata] sets horizontal alignment. *) 99 + val with_horizontal_align : horizontal_align -> metadata -> metadata 100 + 101 + (** {1 Escape Sequence Generation} *) 102 + 103 + (** [render metadata text] generates the complete escape sequence for sized text. 104 + 105 + @param metadata The sizing metadata 106 + @param text The text to render (max 4096 bytes of UTF-8) 107 + @return The escape sequence string 108 + @raise Invalid_argument if text exceeds 4096 bytes *) 109 + val render : metadata -> string -> string 110 + 111 + (** [render_to_channel oc metadata text] writes the escape sequence to a channel. 112 + 113 + @param oc Output channel 114 + @param metadata The sizing metadata 115 + @param text The text to render (max 4096 bytes of UTF-8) 116 + @raise Invalid_argument if text exceeds 4096 bytes *) 117 + val render_to_channel : out_channel -> metadata -> string -> unit 118 + 119 + (** {1 Convenience Functions} *) 120 + 121 + (** [double text] renders text at double size (scale=2). *) 122 + val double : string -> string 123 + 124 + (** [triple text] renders text at triple size (scale=3). *) 125 + val triple : string -> string 126 + 127 + (** [quadruple text] renders text at quadruple size (scale=4). *) 128 + val quadruple : string -> string 129 + 130 + (** [half text] renders text at half size (n=1, d=2). *) 131 + val half : string -> string 132 + 133 + (** [superscript text] renders text as superscript (n=1, d=2, v=Top). *) 134 + val superscript : string -> string 135 + 136 + (** [subscript text] renders text as subscript (n=1, d=2, v=Bottom). *) 137 + val subscript : string -> string 138 + 139 + (** [scaled n text] renders text at scale [n] (1-7). 140 + @raise Invalid_argument if [n] is not in range 1-7. *) 141 + val scaled : int -> string -> string
+3
tgp/test/dune
··· 1 + (test 2 + (name test_textsize) 3 + (libraries textsize))
+104
tgp/test/test_textsize.ml
··· 1 + (* Basic tests for the textsize library *) 2 + 3 + let test name f = 4 + try 5 + f (); 6 + Printf.printf "✓ %s\n" name 7 + with e -> 8 + Printf.printf "✗ %s: %s\n" name (Printexc.to_string e); 9 + exit 1 10 + 11 + let () = 12 + print_endline "Running textsize tests...\n"; 13 + 14 + (* Test scale validation *) 15 + test "scale validation - valid range" (fun () -> 16 + let _ = Textsize.make_scale 1 in 17 + let _ = Textsize.make_scale 7 in 18 + () 19 + ); 20 + 21 + test "scale validation - rejects invalid" (fun () -> 22 + try 23 + let _ = Textsize.make_scale 0 in 24 + failwith "Should have raised Invalid_argument" 25 + with Invalid_argument _ -> () 26 + ); 27 + 28 + (* Test width validation *) 29 + test "width validation - valid range" (fun () -> 30 + let _ = Textsize.make_width 0 in 31 + let _ = Textsize.make_width 7 in 32 + () 33 + ); 34 + 35 + (* Test escape sequence generation *) 36 + test "double escape sequence" (fun () -> 37 + let result = Textsize.double "test" in 38 + assert (String.length result > 0); 39 + assert (result = "\x1b]66;s=2;test\x07") 40 + ); 41 + 42 + test "triple escape sequence" (fun () -> 43 + let result = Textsize.triple "hello" in 44 + assert (result = "\x1b]66;s=3;hello\x07") 45 + ); 46 + 47 + test "half escape sequence" (fun () -> 48 + let result = Textsize.half "tiny" in 49 + assert (result = "\x1b]66;n=1:d=2;tiny\x07") 50 + ); 51 + 52 + test "superscript escape sequence" (fun () -> 53 + let result = Textsize.superscript "2" in 54 + assert (result = "\x1b]66;n=1:d=2:v=2;2\x07") 55 + ); 56 + 57 + test "subscript escape sequence" (fun () -> 58 + let result = Textsize.subscript "2" in 59 + assert (result = "\x1b]66;n=1:d=2:v=0;2\x07") 60 + ); 61 + 62 + (* Test custom metadata *) 63 + test "custom metadata - scale and width" (fun () -> 64 + let metadata = 65 + Textsize.empty 66 + |> Textsize.with_scale (Textsize.make_scale 3) 67 + |> Textsize.with_width (Textsize.make_width 5) 68 + in 69 + let result = Textsize.render metadata "custom" in 70 + assert (result = "\x1b]66;s=3:w=5;custom\x07") 71 + ); 72 + 73 + test "custom metadata - fractional" (fun () -> 74 + let metadata = 75 + Textsize.empty 76 + |> Textsize.with_fraction 77 + (Textsize.make_numerator 2) 78 + (Textsize.make_denominator 3) 79 + in 80 + let result = Textsize.render metadata "frac" in 81 + assert (result = "\x1b]66;n=2:d=3;frac\x07") 82 + ); 83 + 84 + test "empty metadata" (fun () -> 85 + let result = Textsize.render Textsize.empty "plain" in 86 + assert (result = "\x1b]66;;plain\x07") 87 + ); 88 + 89 + (* Test text length validation *) 90 + test "text length validation - accepts valid" (fun () -> 91 + let text = String.make 4096 'a' in 92 + let _ = Textsize.double text in 93 + () 94 + ); 95 + 96 + test "text length validation - rejects oversized" (fun () -> 97 + let text = String.make 4097 'a' in 98 + try 99 + let _ = Textsize.double text in 100 + failwith "Should have raised Invalid_argument" 101 + with Invalid_argument _ -> () 102 + ); 103 + 104 + print_endline "\n✓ All tests passed!"
+31
tgp/textsize.opam
··· 1 + # This file is generated by dune, edit dune-project instead 2 + opam-version: "2.0" 3 + version: "0.1.0" 4 + synopsis: "OCaml implementation of the Kitty text sizing protocol" 5 + description: 6 + "A clean, standalone library for generating escape sequences to render text in different sizes using the Kitty terminal's text sizing protocol." 7 + maintainer: ["Anonymous"] 8 + authors: ["Anonymous"] 9 + license: "MIT" 10 + homepage: "https://github.com/username/textsize" 11 + bug-reports: "https://github.com/username/textsize/issues" 12 + depends: [ 13 + "ocaml" {>= "4.14"} 14 + "dune" {>= "3.0"} 15 + "odoc" {with-doc} 16 + ] 17 + build: [ 18 + ["dune" "subst"] {dev} 19 + [ 20 + "dune" 21 + "build" 22 + "-p" 23 + name 24 + "-j" 25 + jobs 26 + "@install" 27 + "@runtest" {with-test} 28 + "@doc" {with-doc} 29 + ] 30 + ] 31 + dev-repo: "git+https://github.com/username/textsize.git"