Move chunks API into a separate module

This commit is contained in:
Dmitrii Kovanikov 2024-06-23 15:28:33 +01:00
parent f6610ea77b
commit 8140646945
10 changed files with 47 additions and 43 deletions

View File

@ -25,6 +25,7 @@
(minttea (>= "0.0.2"))
shape-the-term
(terminal_size (>= "0.2.0"))
unix
)
(tags
(tui cli git github)))

View File

@ -17,6 +17,7 @@ depends: [
"minttea" {>= "0.0.2"}
"shape-the-term"
"terminal_size" {>= "0.2.0"}
"unix"
"odoc" {with-doc}
]
build: [

14
lib/pretty/chunk.ml Normal file
View File

@ -0,0 +1,14 @@
type styles = ANSITerminal.style list
type t = {
styles : styles;
string : string;
}
let fmt { styles; string } = ANSITerminal.sprintf styles "%s" string
let replicate width s =
if width <= 0 then { styles = []; string = "" }
else
let filling = Extra.String.repeat_txt width s in
{ styles = []; string = filling }

14
lib/pretty/chunk.mli Normal file
View File

@ -0,0 +1,14 @@
(** Formatting of a string. *)
type styles = ANSITerminal.style list
(** A part of a line with the formatting added to it. *)
type t = {
styles : styles;
string : string;
}
(** Convert a chunk to string, applying formatting *)
val fmt : t -> string
(** [replicate_chunk n s] creates a chunk without formatting of [n] repeated strings [s]. *)
val replicate : int -> string -> t

View File

@ -1,20 +1,5 @@
type styles = ANSITerminal.style list
type chunk = {
styles : styles;
string : string;
}
let fmt_chunk { styles; string } = ANSITerminal.sprintf styles "%s" string
let replicate_chunk width s =
if width <= 0 then { styles = []; string = "" }
else
let filling = Extra.String.repeat_txt width s in
{ styles = []; string = filling }
type t = {
chunks : chunk list;
chunks : Chunk.t list;
length : int;
}
@ -23,7 +8,7 @@ let length line = line.length
let of_chunks chunks =
let length =
List.fold_left
(fun acc { string; _ } -> acc + Extra.String.width string)
(fun acc { Chunk.string; _ } -> acc + Extra.String.width string)
0 chunks
in
{ chunks; length }
@ -38,4 +23,4 @@ let append line1 line2 =
let length = line1.length + line2.length in
{ chunks; length }
let fmt line = line.chunks |> List.map fmt_chunk |> String.concat ""
let fmt line = line.chunks |> List.map Chunk.fmt |> String.concat ""

View File

@ -1,29 +1,17 @@
(** Formatting of a string. *)
type styles = ANSITerminal.style list
(** A part of a line with the formatting added to it. *)
type chunk = {
styles : styles;
string : string;
}
(** [replicate_chunk n s] creates a [chunk] without formatting of [n] repeated strings [s]. *)
val replicate_chunk : int -> string -> chunk
(** A type defining a single line of text with different parts ("chunks") having
potentially different formatting. *)
type t
(** Returns the length of a string as in the number of graphemes (before
(** Returns the length of a line as in the number of graphemes (before
formatting applied). *)
val length : t -> int
(** Smart constructor for a line from a list of chunks to calculate the final
[length] automatically as well. *)
val of_chunks : chunk list -> t
val of_chunks : Chunk.t list -> t
(** Add a chunk to the beginning of a line. *)
val prepend_chunk : chunk -> t -> t
val prepend_chunk : Chunk.t -> t -> t
(** Append two lines into a single line. *)
val append : t -> t -> t

View File

@ -1,5 +1,5 @@
type doc =
| Str of Line.styles * string
| Str of Chunk.styles * string
| Horizontal_fill of string
| Vertical of doc list
| Horizontal of doc list
@ -19,7 +19,7 @@ let zip_lines (l : Line.t list) (r : Line.t list) =
| [], r ->
(* Optimisation: Add extra chunk only if padding is needed *)
if max_len_l > 0 then
let padding_chunk = Line.replicate_chunk max_len_l " " in
let padding_chunk = Chunk.replicate max_len_l " " in
List.map (Line.prepend_chunk padding_chunk) r
else r
| hd_l :: tl_l, hd_r :: tl_r ->
@ -30,7 +30,7 @@ let zip_lines (l : Line.t list) (r : Line.t list) =
let new_line = Line.append hd_l hd_r in
new_line :: zip tl_l tl_r
else
let padding_chunk = Line.replicate_chunk (max_len_l - left_len) " " in
let padding_chunk = Chunk.replicate (max_len_l - left_len) " " in
let new_line =
Line.append hd_l
(Line.append (Line.of_chunks [ padding_chunk ]) hd_r)
@ -47,7 +47,7 @@ type prerender =
let rec render_to_lines ~width = function
| Str (styles, string) -> [ Line.of_chunks [ { styles; string } ] ]
| Horizontal_fill filler ->
[ Line.of_chunks [ Line.replicate_chunk width filler ] ]
[ Line.of_chunks [ Chunk.replicate width filler ] ]
| Vertical rows -> List.concat_map (render_to_lines ~width) rows
| Horizontal cols -> horizontal_to_lines ~width cols
@ -85,9 +85,7 @@ and horizontal_to_lines ~width cols =
( 0,
rendered
@ [
[
Line.(of_chunks [ replicate_chunk remaining_width filler ]);
];
[ Line.of_chunks [ Chunk.replicate remaining_width filler ] ];
] ))
(fill_width, []) prerendered
in
@ -95,7 +93,7 @@ and horizontal_to_lines ~width cols =
(* Step [combine]. Combine the final columns of lines. *)
match rendered with
| [] -> []
(* TODO: This is potentially really slow; optimise *)
(* TODO: This has quadratic time complexity; optimise *)
| hd :: tl -> List.fold_left zip_lines hd tl
let render ~width doc =

View File

@ -5,7 +5,7 @@ type doc
val str : string -> doc
(** Create a single chunk of string with formatting. *)
val fmt : Line.styles -> string -> doc
val fmt : Chunk.styles -> string -> doc
(** Put all documents in a list horizontally, automatically adding required padding. *)
val horizontal : doc list -> doc

View File

@ -1,2 +1,3 @@
(library
(name shell))
(name shell)
(libraries unix))

2
lib/shell/shell.mli Normal file
View File

@ -0,0 +1,2 @@
(** Run the given CLI command as external process and collect its stdout to the resulting string. *)
val proc_stdout : string -> string