From 204aef6ffecb92bc22b3ea4f0a7a9f9653896928 Mon Sep 17 00:00:00 2001 From: Vishal Chiluveri <36564980+ironmanvim@users.noreply.github.com> Date: Sat, 16 Mar 2024 19:29:43 +0530 Subject: [PATCH] feat(spices): add border style (#41) * feat(spices): add border * feat: add demo.gif and demo.tape in border example * add get_border util to get border instead of using module * add make constructor function * add module Border signature in spices.mli * add border example in examples/README.md --- examples/README.md | 6 ++ examples/border/demo.gif | Bin 0 -> 58364 bytes examples/border/demo.tape | 17 +++ examples/border/dune | 3 + examples/border/main.ml | 32 ++++++ spices/border.ml | 219 ++++++++++++++++++++++++++++++++++++++ spices/dune | 2 +- spices/spices.ml | 12 +++ spices/spices.mli | 31 ++++++ 9 files changed, 321 insertions(+), 1 deletion(-) create mode 100644 examples/border/demo.gif create mode 100644 examples/border/demo.tape create mode 100644 examples/border/dune create mode 100644 examples/border/main.ml create mode 100644 spices/border.ml diff --git a/examples/README.md b/examples/README.md index 93c3c61..307e420 100644 --- a/examples/README.md +++ b/examples/README.md @@ -59,3 +59,9 @@ + +## Border + + + + diff --git a/examples/border/demo.gif b/examples/border/demo.gif new file mode 100644 index 0000000000000000000000000000000000000000..046d7323fcde9ddee88649c089fe5c1fc441d2e9 GIT binary patch literal 58364 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
m`H6mQ!UH>6vg(@snSc3oLLZP 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 literal 0 HcmV?d00001 diff --git a/examples/border/demo.tape b/examples/border/demo.tape new file mode 100644 index 0000000..6057224 --- /dev/null +++ b/examples/border/demo.tape @@ -0,0 +1,17 @@ +Output demo.gif + +Require echo + +Set Shell "bash" +Set Framerate 24 +Set FontSize 32 +Set Width 1200 +Set Height 600 + +Type "dune exec --no-print-directory ./main.exe" +Enter +Sleep 1s +Type "hello world" +Sleep 1s +Type "q" +Sleep 1s diff --git a/examples/border/dune b/examples/border/dune new file mode 100644 index 0000000..c3afbe4 --- /dev/null +++ b/examples/border/dune @@ -0,0 +1,3 @@ +(executable + (name main) + (libraries minttea spices)) diff --git a/examples/border/main.ml b/examples/border/main.ml new file mode 100644 index 0000000..e27a344 --- /dev/null +++ b/examples/border/main.ml @@ -0,0 +1,32 @@ +open Minttea + +let red_with_border fmt = + Spices.( + default |> border Border.thick |> padding_left 5 |> padding_right 5 + |> fg (color "#FF0000") + |> build) + fmt + +let overlay_border fmt = Spices.(default |> border Border.double |> build) fmt + +type s = { text : string } + +let init _ = Command.Noop +let initial_model = { text = "" } + +let update event model = + match event with + | Event.KeyDown (Key "q" | Escape) -> (model, Command.Quit) + | Event.KeyDown (Key k) -> + let model = { text = model.text ^ k } in + (model, Command.Noop) + | Event.KeyDown Space -> + let model = { text = model.text ^ " " } in + (model, Command.Noop) + | Event.KeyDown Enter -> + let model = { text = model.text ^ "\n" } in + (model, Command.Noop) + | _ -> (model, Command.Noop) + +let view model = overlay_border "%s" (red_with_border "%s" model.text) +let () = Minttea.app ~init ~update ~view () |> Minttea.start ~initial_model diff --git a/spices/border.ml b/spices/border.ml new file mode 100644 index 0000000..bd011ca --- /dev/null +++ b/spices/border.ml @@ -0,0 +1,219 @@ +let remove_color_sequences s = + let regex = Str.regexp "\027\\[[0-9;]*m" in + Str.global_replace regex "" s + +let rec create_string n s = + if n = 0 then "" + else + let str = create_string (n - 1) s in + str ^ s + +let utf8_len str = + Uuseg_string.fold_utf_8 `Grapheme_cluster (fun x _ -> x + 1) 0 str + +let get_width text = + List.fold_left + (fun acc line -> + let len = utf8_len (remove_color_sequences line) in + if acc < len then len else acc) + 0 + (Str.split (Str.regexp "\r?\n") text) + +let get_height text = List.length (Str.split (Str.regexp "\r?\n") text) + +type t = { + top : string option; + left : string option; + bottom : string option; + right : string option; + top_left : string option; + top_right : string option; + bottom_left : string option; + bottom_right : string option; + middle_left : string option; + middle_right : string option; + middle : string option; + middle_top : string option; + middle_bottom : string option; +} + +let make ?top ?left ?bottom ?right ?top_left ?top_right ?bottom_left + ?bottom_right ?middle_left ?middle_right ?middle ?middle_top ?middle_bottom + () = + { + top; + left; + bottom; + right; + top_left; + top_right; + bottom_left; + bottom_right; + middle_left; + middle_right; + middle; + middle_top; + middle_bottom; + } + +let build_border (border : t) text = + let top = Option.value border.top ~default:"" in + let left = Option.value border.left ~default:"" in + let bottom = Option.value border.bottom ~default:"" in + let right = Option.value border.right ~default:"" in + let top_left = Option.value border.top_left ~default:"" in + let top_right = Option.value border.top_right ~default:"" in + let bottom_left = Option.value border.bottom_left ~default:"" in + let bottom_right = Option.value border.bottom_right ~default:"" in + + let width = get_width text in + let top_border = top_left ^ create_string width top ^ top_right in + let bottom_border = bottom_left ^ create_string width bottom ^ bottom_right in + let l = Str.split (Str.regexp "\r?\n") text in + let l = + List.map + (fun x -> + let x_w = get_width x in + let extra_right_spacing = create_string (width - x_w) " " in + let res = left ^ x ^ extra_right_spacing ^ right in + res) + l + in + let text = String.concat "\n" l in + Format.sprintf "%s\n%s\n%s" top_border text bottom_border + +let normal = + { + top = Some "─"; + bottom = Some "─"; + left = Some "│"; + right = Some "│"; + top_left = Some "┌"; + top_right = Some "┐"; + bottom_left = Some "└"; + bottom_right = Some "┘"; + middle_left = Some "├"; + middle_right = Some "┤"; + middle = Some "┼"; + middle_top = Some "┬"; + middle_bottom = Some "┴"; + } + +let rounded = + { + top = Some "─"; + bottom = Some "─"; + left = Some "│"; + right = Some "│"; + top_left = Some "╭"; + top_right = Some "╮"; + bottom_left = Some "╰"; + bottom_right = Some "╯"; + middle_left = Some "├"; + middle_right = Some "┤"; + middle = Some "┼"; + middle_top = Some "┬"; + middle_bottom = Some "┴"; + } + +let block = + { + top = Some "█"; + bottom = Some "█"; + left = Some "█"; + right = Some "█"; + top_left = Some "█"; + top_right = Some "█"; + bottom_left = Some "█"; + bottom_right = Some "█"; + middle_left = None; + middle_right = None; + middle = None; + middle_top = None; + middle_bottom = None; + } + +let outer_half_block = + { + top = Some "▀"; + bottom = Some "▄"; + left = Some "▌"; + right = Some "▐"; + top_left = Some "▛"; + top_right = Some "▜"; + bottom_left = Some "▙"; + bottom_right = Some "▟"; + middle_left = None; + middle_right = None; + middle = None; + middle_top = None; + middle_bottom = None; + } + +let inner_half_block = + { + top = Some "▄"; + bottom = Some "▀"; + left = Some "▐"; + right = Some "▌"; + top_left = Some "▗"; + top_right = Some "▖"; + bottom_left = Some "▝"; + bottom_right = Some "▘"; + middle_left = None; + middle_right = None; + middle = None; + middle_top = None; + middle_bottom = None; + } + +let thick = + { + top = Some "━"; + bottom = Some "━"; + left = Some "┃"; + right = Some "┃"; + top_left = Some "┏"; + top_right = Some "┓"; + bottom_left = Some "┗"; + bottom_right = Some "┛"; + middle_left = Some "┣"; + middle_right = Some "┫"; + middle = Some "╋"; + middle_top = Some "┳"; + middle_bottom = Some "┻"; + } + +let double = + { + top = Some "═"; + bottom = Some "═"; + left = Some "║"; + right = Some "║"; + top_left = Some "╔"; + top_right = Some "╗"; + bottom_left = Some "╚"; + bottom_right = Some "╝"; + middle_left = Some "╠"; + middle_right = Some "╣"; + middle = Some "╬"; + middle_top = Some "╦"; + middle_bottom = Some "╩"; + } + +let hidden = + { + top = Some " "; + bottom = Some " "; + left = Some " "; + right = Some " "; + top_left = Some " "; + top_right = Some " "; + bottom_left = Some " "; + bottom_right = Some " "; + middle_left = Some " "; + middle_right = Some " "; + middle = Some " "; + middle_top = Some " "; + middle_bottom = Some " "; + } diff --git a/spices/dune b/spices/dune index aca7a4f..1e59937 100644 --- a/spices/dune +++ b/spices/dune @@ -1,4 +1,4 @@ (library (public_name spices) (name spices) - (libraries tty colors)) + (libraries tty colors str uuseg)) diff --git a/spices/spices.ml b/spices/spices.ml index 39e78d2..7f42f35 100644 --- a/spices/spices.ml +++ b/spices/spices.ml @@ -13,6 +13,8 @@ let color ?(profile = Tty.Profile.default) raw = let gradient = Gradient.make +module Border = Border + type style = { background : color option; blink : bool; @@ -35,6 +37,7 @@ type style = { strikethrough : bool; underline : bool; width : int option; + border : Border.t option; } let default = @@ -60,6 +63,7 @@ let default = strikethrough = false; underline = false; width = None; + border = None; } let bg x t = { t with background = Some x } @@ -83,6 +87,7 @@ let reverse x t = { t with reverse = x } let strikethrough x t = { t with strikethrough = x } let underline x t = { t with underline = x } let width x t = { t with width = x } +let border x t = { t with border = Some x } let do_render t str = (* Pre-process padding *) @@ -133,6 +138,13 @@ let do_render t str = Buffer.contents buf in + (* handle border *) + let str = + match t.border with + | Some border -> Border.build_border border str + | None -> str + in + (* handle margin *) let str = ref str in if t.margin_left > 0 then str := String.make t.margin_left ' ' ^ !str; diff --git a/spices/spices.mli b/spices/spices.mli index 0844b1f..50aa598 100644 --- a/spices/spices.mli +++ b/spices/spices.mli @@ -7,6 +7,36 @@ type color = Tty.Color.t = private val color : ?profile:Tty.Profile.t -> string -> color val gradient : start:color -> finish:color -> steps:int -> color array +module Border : sig + type t + + val make : + ?top:string -> + ?left:string -> + ?bottom:string -> + ?right:string -> + ?top_left:string -> + ?top_right:string -> + ?bottom_left:string -> + ?bottom_right:string -> + ?middle_left:string -> + ?middle_right:string -> + ?middle:string -> + ?middle_top:string -> + ?middle_bottom:string -> + unit -> + t + + val normal : t + val rounded : t + val block : t + val outer_half_block : t + val inner_half_block : t + val thick : t + val double : t + val hidden : t +end + type style val default : style @@ -31,6 +61,7 @@ val reverse : bool -> style -> style val strikethrough : bool -> style -> style val underline : bool -> style -> style val width : int option -> style -> style +val border : Border.t -> style -> style type 'a style_fun = ('a, Format.formatter, unit, unit, unit, string) format6 -> 'a