this repo has no description
0
fork

Configure Feed

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

more

+201 -206
+31 -13
tgp/example/demo.ml
··· 33 33 34 34 (* Custom metadata *) 35 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 36 + let custom = Textsize.v ~scale:3 ~width:5 () in 41 37 print_string (Textsize.render custom "Custom sized text"); 42 38 print_endline "\n\n"; 43 39 44 40 (* 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 41 + let aligned = Textsize.v ~fraction:(1, 3) ~vertical:`Center ~horizontal:`Center () in 53 42 print_string (Textsize.render aligned "Centered 1/3 size text"); 54 43 print_newline (); 44 + 45 + (* Fmt-style combinators *) 46 + print_endline "\n=== Fmt-style Examples ===\n"; 47 + 48 + (* Basic pp formatter *) 49 + Fmt.pr "This is %a text\n" Textsize.pp_double "double-sized"; 50 + Fmt.pr "This is %a text\n" Textsize.pp_triple "triple-sized"; 51 + 52 + (* Superscripts and subscripts with Fmt *) 53 + Fmt.pr "E=mc%a\n" Textsize.pp_superscript "2"; 54 + Fmt.pr "H%aO\n" Textsize.pp_subscript "2"; 55 + 56 + (* Styled combinators wrapping other formatters *) 57 + Fmt.pr "The answer is %a\n" (Textsize.styled_double Fmt.int) 42; 58 + Fmt.pr "Pi is approximately %a\n" (Textsize.styled_triple Fmt.float) 3.14159; 59 + 60 + (* Complex formatting with Fmt *) 61 + Fmt.pr "Temperature: %a°C (that's %a°F)\n" 62 + (Textsize.styled_superscript Fmt.int) 25 63 + (Textsize.styled_subscript Fmt.int) 77; 64 + 65 + (* Custom metadata with Fmt *) 66 + let custom_meta = Textsize.v ~scale:4 () in 67 + Fmt.pr "\n%a\n" (Textsize.pp custom_meta) "Custom Fmt-styled text"; 68 + 69 + (* Composing with other Fmt combinators *) 70 + Fmt.pr "\nList items: %a\n" 71 + (Fmt.list ~sep:(Fmt.any ", ") (Textsize.styled_double Fmt.string)) 72 + ["apple"; "banana"; "cherry"]; 55 73 56 74 print_endline "\n=== Demo Complete ===";
+1 -1
tgp/example/dune
··· 1 1 (executable 2 2 (name demo) 3 - (libraries textsize)) 3 + (libraries textsize fmt))
+2 -1
tgp/src/dune
··· 1 1 (library 2 2 (name textsize) 3 - (public_name textsize)) 3 + (public_name textsize) 4 + (libraries fmt))
+85 -97
tgp/src/textsize.ml
··· 2 2 3 3 (* Types *) 4 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 5 + type vertical = [ `Bottom | `Center | `Top ] 6 + type horizontal = [ `Left | `Center | `Right ] 14 7 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; 8 + type 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; 27 15 } 28 16 29 - (* Constructors with validation *) 17 + (* Validation helpers *) 30 18 31 - let make_scale n = 19 + let validate_scale n = 32 20 if n < 1 || n > 7 then 33 21 invalid_arg (Printf.sprintf "scale must be in range 1-7, got %d" n) 34 - else 35 - n 36 22 37 - let make_width n = 23 + let validate_width n = 38 24 if n < 0 || n > 7 then 39 25 invalid_arg (Printf.sprintf "width must be in range 0-7, got %d" n) 40 - else 41 - n 42 26 43 - let make_numerator n = 27 + let validate_numerator n = 44 28 if n < 0 || n > 15 then 45 29 invalid_arg (Printf.sprintf "numerator must be in range 0-15, got %d" n) 46 - else 47 - n 48 30 49 - let make_denominator n = 31 + let validate_denominator n = 50 32 if n < 0 || n > 15 then 51 33 invalid_arg (Printf.sprintf "denominator must be in range 0-15, got %d" n) 52 - else 53 - n 54 34 55 - (* Metadata creation *) 35 + (* Constructor *) 56 36 57 - let empty = { 58 - scale = None; 59 - width = None; 60 - numerator = None; 61 - denominator = None; 62 - vertical = None; 63 - horizontal = None; 64 - } 37 + let 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 + } 65 55 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 } 56 + let empty = v () 74 57 75 58 (* Conversion helpers *) 76 59 77 - let vertical_align_to_int = function 78 - | Bottom -> 0 79 - | Center -> 1 80 - | Top -> 2 60 + let vertical_to_int = function 61 + | `Bottom -> 0 62 + | `Center -> 1 63 + | `Top -> 2 81 64 82 - let horizontal_align_to_int = function 83 - | Left -> 0 84 - | Center -> 1 85 - | Right -> 2 65 + let horizontal_to_int = function 66 + | `Left -> 0 67 + | `Center -> 1 68 + | `Right -> 2 86 69 87 70 (* Escape sequence generation *) 88 71 89 - let metadata_to_string metadata = 72 + let metadata_to_string t = 90 73 let parts = [] in 91 - let parts = match metadata.scale with 74 + let parts = match t.scale with 92 75 | Some s -> (Printf.sprintf "s=%d" s) :: parts 93 76 | None -> parts 94 77 in 95 - let parts = match metadata.width with 78 + let parts = match t.width with 96 79 | Some w -> (Printf.sprintf "w=%d" w) :: parts 97 80 | None -> parts 98 81 in 99 - let parts = match metadata.numerator with 82 + let parts = match t.numerator with 100 83 | Some n -> (Printf.sprintf "n=%d" n) :: parts 101 84 | None -> parts 102 85 in 103 - let parts = match metadata.denominator with 86 + let parts = match t.denominator with 104 87 | Some d -> (Printf.sprintf "d=%d" d) :: parts 105 88 | None -> parts 106 89 in 107 - let parts = match metadata.vertical with 108 - | Some v -> (Printf.sprintf "v=%d" (vertical_align_to_int v)) :: parts 90 + let parts = match t.vertical with 91 + | Some v -> (Printf.sprintf "v=%d" (vertical_to_int v)) :: parts 109 92 | None -> parts 110 93 in 111 - let parts = match metadata.horizontal with 112 - | Some h -> (Printf.sprintf "h=%d" (horizontal_align_to_int h)) :: parts 94 + let parts = match t.horizontal with 95 + | Some h -> (Printf.sprintf "h=%d" (horizontal_to_int h)) :: parts 113 96 | None -> parts 114 97 in 115 98 String.concat ":" (List.rev parts) 116 99 117 - let render metadata text = 100 + let render t text = 118 101 (* Validate text length (max 4096 bytes of UTF-8) *) 119 102 let text_len = String.length text in 120 103 if text_len > 4096 then 121 104 invalid_arg (Printf.sprintf "text exceeds 4096 bytes (got %d)" text_len); 122 105 123 - let metadata_str = metadata_to_string metadata in 106 + let metadata_str = metadata_to_string t in 124 107 125 108 (* OSC 66 ; metadata ; text BEL *) 126 109 (* Using \x1b for ESC and \x07 for BEL *) ··· 129 112 else 130 113 Printf.sprintf "\x1b]66;%s;%s\x07" metadata_str text 131 114 132 - let render_to_channel oc metadata text = 133 - output_string oc (render metadata text); 115 + let render_to_channel oc t text = 116 + output_string oc (render t text); 134 117 flush oc 135 118 136 - (* Convenience functions *) 119 + (* Fmt-style combinators *) 120 + 121 + let pp t ppf text = 122 + Format.pp_print_string ppf (render t text) 123 + 124 + let 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 *) 137 130 138 - let double text = 139 - render (with_scale (make_scale 2) empty) text 131 + let pp_double = pp (v ~scale:2 ()) 132 + let pp_triple = pp (v ~scale:3 ()) 133 + let pp_quadruple = pp (v ~scale:4 ()) 134 + let pp_half = pp (v ~fraction:(1, 2) ()) 140 135 141 - let triple text = 142 - render (with_scale (make_scale 3) empty) text 136 + let pp_superscript = pp (v ~fraction:(1, 2) ~vertical:`Top ()) 137 + let pp_subscript = pp (v ~fraction:(1, 2) ~vertical:`Bottom ()) 143 138 144 - let quadruple text = 145 - render (with_scale (make_scale 4) empty) text 139 + let pp_scaled n = pp (v ~scale:n ()) 146 140 147 - let half text = 148 - render 149 - (with_fraction (make_numerator 1) (make_denominator 2) empty) 150 - text 141 + let styled_double pp_inner = styled (v ~scale:2 ()) pp_inner 142 + let styled_triple pp_inner = styled (v ~scale:3 ()) pp_inner 151 143 152 - let superscript text = 153 - render 154 - (empty 155 - |> with_fraction (make_numerator 1) (make_denominator 2) 156 - |> with_vertical_align Top) 157 - text 144 + let styled_superscript pp_inner = styled (v ~fraction:(1, 2) ~vertical:`Top ()) pp_inner 145 + let styled_subscript pp_inner = styled (v ~fraction:(1, 2) ~vertical:`Bottom ()) pp_inner 158 146 159 - let subscript text = 160 - render 161 - (empty 162 - |> with_fraction (make_numerator 1) (make_denominator 2) 163 - |> with_vertical_align Bottom) 164 - text 147 + (* Convenience functions *) 165 148 166 - let scaled n text = 167 - render (with_scale (make_scale n) empty) text 149 + let double text = render (v ~scale:2 ()) text 150 + let triple text = render (v ~scale:3 ()) text 151 + let quadruple text = render (v ~scale:4 ()) text 152 + let half text = render (v ~fraction:(1, 2) ()) text 153 + let superscript text = render (v ~fraction:(1, 2) ~vertical:`Top ()) text 154 + let subscript text = render (v ~fraction:(1, 2) ~vertical:`Bottom ()) text 155 + let scaled n text = render (v ~scale:n ()) text
+74 -77
tgp/src/textsize.mli
··· 11 11 12 12 (** {1 Types} *) 13 13 14 - (** Scale factor for text rendering (1-7). 14 + (** Vertical alignment for fractionally scaled text. *) 15 + type vertical = [ `Bottom | `Center | `Top ] 15 16 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 17 + (** Horizontal alignment for fractionally scaled text. *) 18 + type horizontal = [ `Left | `Center | `Right ] 19 19 20 - (** Width in cells for text rendering (0-7). 20 + (** Abstract metadata for text sizing. *) 21 + type t 21 22 22 - When set to 0, width is auto-calculated based on text length. *) 23 - type width = private int 23 + (** {1 Constructor} *) 24 24 25 - (** Fractional scaling numerator (0-15). 25 + (** [v ?scale ?width ?fraction ?vertical ?horizontal ()] creates text sizing metadata. 26 26 27 - Used together with denominator for precise fractional scaling. *) 28 - type numerator = private int 27 + @param scale Scale factor (1-7) 28 + @param width Width in cells (0-7) 29 + @param fraction Fractional scaling as (numerator, denominator) where both are 0-15 30 + @param vertical Vertical alignment 31 + @param horizontal Horizontal alignment 32 + @raise Invalid_argument if any parameter is out of range *) 33 + val v : 34 + ?scale:int -> 35 + ?width:int -> 36 + ?fraction:(int * int) -> 37 + ?vertical:vertical -> 38 + ?horizontal:horizontal -> 39 + unit -> t 29 40 30 - (** Fractional scaling denominator (0-15). 41 + (** Empty metadata (all fields set to [None]). Equivalent to [v ()]. *) 42 + val empty : t 31 43 32 - Used together with numerator for precise fractional scaling. *) 33 - type denominator = private int 44 + (** {1 Escape Sequence Generation} *) 34 45 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 46 + (** [render t text] generates the complete escape sequence for sized text. 43 47 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 48 + @param t The sizing metadata 49 + @param text The text to render (max 4096 bytes of UTF-8) 50 + @return The escape sequence string 51 + @raise Invalid_argument if text exceeds 4096 bytes *) 52 + val render : t -> string -> string 52 53 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 - } 54 + (** [render_to_channel oc t text] writes the escape sequence to a channel. 62 55 63 - (** {1 Constructors} *) 56 + @param oc Output channel 57 + @param t The sizing metadata 58 + @param text The text to render (max 4096 bytes of UTF-8) 59 + @raise Invalid_argument if text exceeds 4096 bytes *) 60 + val render_to_channel : out_channel -> t -> string -> unit 64 61 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 62 + (** {1 Fmt-style Combinators} *) 68 63 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 64 + (** [pp t] creates a Fmt formatter that wraps text with sizing metadata. 72 65 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 66 + Example: 67 + {[ 68 + Fmt.pr "This is %a" (Textsize.pp (Textsize.with_scale 2 Textsize.empty)) "big" 69 + ]} 70 + *) 71 + val pp : t -> string Fmt.t 76 72 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 73 + (** [styled t pp_inner] wraps any formatter with sizing metadata. 80 74 81 - (** {1 Metadata Creation} *) 75 + Example: 76 + {[ 77 + Fmt.pr "Value: %a" (Textsize.styled (Textsize.with_scale 3 Textsize.empty) Fmt.int) 42 78 + ]} 79 + *) 80 + val styled : t -> 'a Fmt.t -> 'a Fmt.t 82 81 83 - (** Empty metadata (all fields set to [None]). *) 84 - val empty : metadata 82 + (** Fmt formatter for double-sized text. *) 83 + val pp_double : string Fmt.t 85 84 86 - (** [with_scale s metadata] sets the scale. *) 87 - val with_scale : scale -> metadata -> metadata 85 + (** Fmt formatter for triple-sized text. *) 86 + val pp_triple : string Fmt.t 88 87 89 - (** [with_width w metadata] sets the width. *) 90 - val with_width : width -> metadata -> metadata 88 + (** Fmt formatter for quadruple-sized text. *) 89 + val pp_quadruple : string Fmt.t 91 90 92 - (** [with_fraction num den metadata] sets fractional scaling. *) 93 - val with_fraction : numerator -> denominator -> metadata -> metadata 91 + (** Fmt formatter for half-sized text. *) 92 + val pp_half : string Fmt.t 94 93 95 - (** [with_vertical_align v metadata] sets vertical alignment. *) 96 - val with_vertical_align : vertical_align -> metadata -> metadata 94 + (** Fmt formatter for superscript text. *) 95 + val pp_superscript : string Fmt.t 97 96 98 - (** [with_horizontal_align h metadata] sets horizontal alignment. *) 99 - val with_horizontal_align : horizontal_align -> metadata -> metadata 97 + (** Fmt formatter for subscript text. *) 98 + val pp_subscript : string Fmt.t 100 99 101 - (** {1 Escape Sequence Generation} *) 100 + (** [pp_scaled n] creates a Fmt formatter for text at scale [n]. 101 + @raise Invalid_argument if [n] is not in range 1-7. *) 102 + val pp_scaled : int -> string Fmt.t 102 103 103 - (** [render metadata text] generates the complete escape sequence for sized text. 104 + (** [styled_double pp_inner] wraps any formatter with double sizing. *) 105 + val styled_double : 'a Fmt.t -> 'a Fmt.t 104 106 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 107 + (** [styled_triple pp_inner] wraps any formatter with triple sizing. *) 108 + val styled_triple : 'a Fmt.t -> 'a Fmt.t 110 109 111 - (** [render_to_channel oc metadata text] writes the escape sequence to a channel. 110 + (** [styled_superscript pp_inner] wraps any formatter with superscript styling. *) 111 + val styled_superscript : 'a Fmt.t -> 'a Fmt.t 112 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 113 + (** [styled_subscript pp_inner] wraps any formatter with subscript styling. *) 114 + val styled_subscript : 'a Fmt.t -> 'a Fmt.t 118 115 119 116 (** {1 Convenience Functions} *) 120 117
+8 -17
tgp/test/test_textsize.ml
··· 13 13 14 14 (* Test scale validation *) 15 15 test "scale validation - valid range" (fun () -> 16 - let _ = Textsize.make_scale 1 in 17 - let _ = Textsize.make_scale 7 in 16 + let _ = Textsize.v ~scale:1 () in 17 + let _ = Textsize.v ~scale:7 () in 18 18 () 19 19 ); 20 20 21 21 test "scale validation - rejects invalid" (fun () -> 22 22 try 23 - let _ = Textsize.make_scale 0 in 23 + let _ = Textsize.v ~scale:0 () in 24 24 failwith "Should have raised Invalid_argument" 25 25 with Invalid_argument _ -> () 26 26 ); 27 27 28 28 (* Test width validation *) 29 29 test "width validation - valid range" (fun () -> 30 - let _ = Textsize.make_width 0 in 31 - let _ = Textsize.make_width 7 in 30 + let _ = Textsize.v ~width:0 () in 31 + let _ = Textsize.v ~width:7 () in 32 32 () 33 33 ); 34 34 ··· 61 61 62 62 (* Test custom metadata *) 63 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 64 + let metadata = Textsize.v ~scale:3 ~width:5 () in 69 65 let result = Textsize.render metadata "custom" in 70 66 assert (result = "\x1b]66;s=3:w=5;custom\x07") 71 67 ); 72 68 73 69 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 70 + let metadata = Textsize.v ~fraction:(2, 3) () in 80 71 let result = Textsize.render metadata "frac" in 81 72 assert (result = "\x1b]66;n=2:d=3;frac\x07") 82 73 ); 83 74 84 75 test "empty metadata" (fun () -> 85 - let result = Textsize.render Textsize.empty "plain" in 76 + let result = Textsize.render (Textsize.v ()) "plain" in 86 77 assert (result = "\x1b]66;;plain\x07") 87 78 ); 88 79