mirror of
https://github.com/chshersh/github-tui.git
synced 2024-10-26 11:00:19 +03:00
Refactor pretty-printing library to support styles
This commit is contained in:
parent
7802849271
commit
65e041b606
@ -23,7 +23,7 @@
|
||||
(cmdliner (>= "1.2.0"))
|
||||
(ezcurl (>= "0.2.4"))
|
||||
(minttea (>= "0.0.2"))
|
||||
uuseg.string
|
||||
uuseg
|
||||
)
|
||||
(tags
|
||||
(tui cli git github)))
|
||||
|
@ -15,7 +15,7 @@ depends: [
|
||||
"cmdliner" {>= "1.2.0"}
|
||||
"ezcurl" {>= "0.2.4"}
|
||||
"minttea" {>= "0.0.2"}
|
||||
"uuseg.string"
|
||||
"uuseg"
|
||||
"odoc" {with-doc}
|
||||
]
|
||||
build: [
|
||||
|
@ -1,11 +1,16 @@
|
||||
(* A simple pretty printing combinator library *)
|
||||
|
||||
type styles = ANSITerminal.style list
|
||||
|
||||
type doc =
|
||||
| Empty
|
||||
| Str of string
|
||||
| Str of styles * string
|
||||
| Vertical of doc * doc
|
||||
| Horizontal of doc * doc
|
||||
|
||||
let str string = Str ([], string)
|
||||
let fmt styles string = Str (styles, string)
|
||||
|
||||
let row = function
|
||||
| [] -> Empty
|
||||
| hd :: tl -> List.fold_left (fun l r -> Horizontal (l, r)) hd tl
|
||||
@ -14,25 +19,71 @@ let col = function
|
||||
| [] -> Empty
|
||||
| hd :: tl -> List.fold_left (fun l r -> Vertical (l, r)) hd tl
|
||||
|
||||
let zip_lines l r =
|
||||
let max_len_l = List.map String_extra.graphemes_len l |> List.fold_left max 0 in
|
||||
let padding = String.make max_len_l ' ' in
|
||||
type chunk =
|
||||
{
|
||||
styles: styles;
|
||||
string: string;
|
||||
}
|
||||
|
||||
let fmt_chunk {styles; string} =
|
||||
ANSITerminal.sprintf styles "%s" string
|
||||
|
||||
let mk_padding_chunk n =
|
||||
let padding = String.make n ' ' in
|
||||
{styles = []; string = padding}
|
||||
|
||||
type line =
|
||||
{
|
||||
chunks: chunk list
|
||||
}
|
||||
|
||||
let fmt_line line =
|
||||
line.chunks
|
||||
|> List.map fmt_chunk
|
||||
|> String.concat ""
|
||||
|
||||
let line_len line =
|
||||
List.fold_left
|
||||
(fun acc {string; _} -> acc + String_extra.graphemes_len string)
|
||||
0
|
||||
line.chunks
|
||||
|
||||
let zip_lines (l: line list) (r: line list) =
|
||||
let max_len_l = List.map line_len l |> List.fold_left max 0 in
|
||||
|
||||
let rec zip l r =
|
||||
match (l, r) with
|
||||
| (l, []) ->
|
||||
l
|
||||
|
||||
| ([], r) ->
|
||||
List.map (fun s -> padding ^ s) r
|
||||
(* Optimisation: Add extra chunk only if padding is needed *)
|
||||
if max_len_l > 0 then
|
||||
let padding_chunk = mk_padding_chunk max_len_l in
|
||||
List.map (fun line -> { chunks = padding_chunk :: line.chunks }) r
|
||||
else
|
||||
r
|
||||
|
||||
| (hd_l :: tl_l, hd_r :: tl_r) ->
|
||||
(String_extra.fill_right max_len_l hd_l ^ hd_r) :: zip tl_l tl_r
|
||||
let left_len = line_len hd_l in
|
||||
|
||||
(* Optimisation: Combine chunks when left is already max len *)
|
||||
if left_len >= max_len_l then
|
||||
let new_line = { chunks = hd_l.chunks @ hd_r.chunks } in
|
||||
new_line :: zip tl_l tl_r
|
||||
else
|
||||
let padding_chunk = mk_padding_chunk (max_len_l - left_len) in
|
||||
let new_line = { chunks = hd_l.chunks @ [padding_chunk] @ hd_r.chunks } in
|
||||
new_line :: zip tl_l tl_r
|
||||
in
|
||||
|
||||
zip l r
|
||||
|
||||
let rec render_to_lines = function
|
||||
| Empty ->
|
||||
[]
|
||||
| Str s ->
|
||||
[s]
|
||||
| Str (styles, string) ->
|
||||
[{ chunks = [{styles; string}] }]
|
||||
| Vertical (top, bottom) ->
|
||||
render_to_lines top @ render_to_lines bottom
|
||||
| Horizontal (left, right) ->
|
||||
@ -41,4 +92,5 @@ let rec render_to_lines = function
|
||||
let render doc =
|
||||
doc
|
||||
|> render_to_lines
|
||||
|> List.map fmt_line
|
||||
|> String_extra.unlines
|
@ -1,24 +1,21 @@
|
||||
let fmt (styles : ANSITerminal.style list) : string -> string =
|
||||
ANSITerminal.sprintf styles "%s"
|
||||
let style_repo =
|
||||
ANSITerminal.([Bold; blue])
|
||||
|
||||
let fmt_repo =
|
||||
fmt ANSITerminal.([Bold; blue])
|
||||
|
||||
let fmt_selected =
|
||||
fmt ANSITerminal.([Bold; green])
|
||||
let style_selected =
|
||||
ANSITerminal.([Bold; green])
|
||||
|
||||
let tabs_section cur_tab =
|
||||
let open Pretty in
|
||||
let p_tab tab txt =
|
||||
if cur_tab = tab
|
||||
then Str (fmt_selected txt)
|
||||
else Str txt
|
||||
then fmt style_selected txt
|
||||
else str txt
|
||||
in
|
||||
let sep = col
|
||||
[
|
||||
Str " ";
|
||||
Str " ";
|
||||
Str "─";
|
||||
str " ";
|
||||
str " ";
|
||||
str "─";
|
||||
]
|
||||
in
|
||||
render @@ row
|
||||
@ -61,7 +58,7 @@ let file_widget ~max_name_len ~selected files =
|
||||
|> (fun lines -> [top] @ lines @ [bot])
|
||||
|> List.mapi (fun i s ->
|
||||
if i = hi_pos - 1 || i = hi_pos || i = hi_pos + 1
|
||||
then fmt_selected s
|
||||
then ANSITerminal.sprintf style_selected "%s" s
|
||||
else s
|
||||
)
|
||||
|> String_extra.unlines
|
||||
@ -81,7 +78,7 @@ let tab_content_section (model: Model.t) =
|
||||
| Issues | PullRequests -> ""
|
||||
|
||||
let view (model: Model.t) =
|
||||
let repo = fmt_repo model.repo in
|
||||
let repo = ANSITerminal.sprintf style_repo "%s" model.repo in
|
||||
let tabs = tabs_section model.current_tab in
|
||||
let content = tab_content_section model in
|
||||
Format.sprintf
|
||||
|
Loading…
Reference in New Issue
Block a user