Skip to content

Commit 17b76cf

Browse files
committed
Render issues only once on fetch
1 parent e026271 commit 17b76cf

File tree

10 files changed

+115
-63
lines changed

10 files changed

+115
-63
lines changed

lib/pretty/line.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ let append line1 line2 =
2626
let fmt line = line.chunks |> List.map Chunk.fmt |> String.concat ""
2727

2828
let zip_lines l r =
29-
let max_len_l = List.map length l |> List.fold_left max 0 in
29+
let max_len_l = Extra.List.max_on length l in
3030

3131
let rec zip l r =
3232
match (l, r) with

lib/tui/model/dune

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@
33
(libraries
44
;; Internal dependencies
55
fs
6-
gh))
6+
gh
7+
render))

lib/tui/model/issue.ml

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
type t = {
2-
all_issues : Gh.Issue.t list Lazy.t;
2+
all_issues : Gh.Issue.t Render.t list Lazy.t;
33
filter : filter;
4-
issues : Gh.Issue.t list Lazy.t;
4+
issues : Gh.Issue.t Render.t list Lazy.t;
55
offset : int;
6-
error : Gh.Client.error option;
6+
error : Gh.Client.error option Lazy.t;
77
}
88

99
and filter =
@@ -18,7 +18,9 @@ let filter_issues ~filter issues =
1818
match filter with
1919
| All -> issues
2020
| State state ->
21-
issues |> List.filter (fun (issue : Gh.Issue.t) -> issue.state = state)
21+
issues
22+
|> List.filter (fun (issue : Gh.Issue.t Render.t) ->
23+
issue.item.state = state)
2224

2325
let lazy_filter_issues ~filter issues =
2426
lazy (issues |> Lazy.force |> filter_issues ~filter)
@@ -31,11 +33,16 @@ let apply_filter filter t =
3133
{ t with filter; issues; offset }
3234

3335
let make ~owner ~repo =
34-
let all_issues, error =
35-
match Gh.Issue.issues ~owner ~repo with
36-
| Ok issues -> (lazy issues, None)
37-
| Error err -> (lazy [], Some err)
36+
let issues_and_errors =
37+
lazy
38+
(match Gh.Issue.issues ~owner ~repo with
39+
| Ok issues ->
40+
let rendered = Render.issues issues in
41+
(rendered, None)
42+
| Error err -> ([], Some err))
3843
in
44+
let all_issues = lazy (issues_and_errors |> Lazy.force |> fst) in
45+
let error = lazy (issues_and_errors |> Lazy.force |> snd) in
3946
let filter = filter_open in
4047
let issues = lazy_filter_issues ~filter all_issues in
4148
let offset = 0 in

lib/tui/model/issue.mli

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77
- [issues]: Filtered issues from [all_issues] using [filter]
88
- [offset]: Offset for currently selected issue from [issues] *)
99
type t = {
10-
all_issues : Gh.Issue.t list Lazy.t;
10+
all_issues : Gh.Issue.t Render.t list Lazy.t;
1111
filter : filter;
12-
issues : Gh.Issue.t list Lazy.t;
12+
issues : Gh.Issue.t Render.t list Lazy.t;
1313
offset : int;
14-
error : Gh.Client.error option;
14+
error : Gh.Client.error option Lazy.t;
1515
}
1616

1717
and filter =

lib/tui/render/dune

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
(library
2+
(name render)
3+
(libraries
4+
;; Internal dependencies
5+
extra
6+
gh
7+
pretty))

lib/tui/render/render.ml

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
module Layout = Pretty.Layout
2+
3+
type 'a t = {
4+
item : 'a;
5+
layout : Pretty.Layout.t;
6+
}
7+
8+
let issue_char = "\u{f41b}"
9+
10+
let fmt_issue_state (state : Gh.Issue.state) =
11+
match state with
12+
| Open -> Layout.(fmt Style.issue_open issue_char)
13+
| Closed -> Layout.(fmt Style.issue_closed issue_char)
14+
15+
let fmt_title (issue : Gh.Issue.t) =
16+
let open Layout in
17+
horizontal
18+
[
19+
fmt_issue_state issue.state;
20+
str " ";
21+
fmt Style.secondary (Printf.sprintf "#%d " issue.number);
22+
str issue.title;
23+
str " by ";
24+
fmt Style.bold (Printf.sprintf "@%s" issue.author);
25+
]
26+
27+
let apply_background_color ~color text =
28+
let module Color = Pretty.Color in
29+
let color = Color.of_hex color in
30+
let foreground_suggestion = Color.foreground color in
31+
let color_code = Pretty.Color.to_escape_seq color in
32+
let text = Printf.sprintf "\027[48;%sm %s \027[0m" color_code text in
33+
(text, foreground_suggestion)
34+
35+
let fmt_labels labels =
36+
let open Layout in
37+
let fmt_label (label : Gh.Issue.label) =
38+
let label, foreground =
39+
apply_background_color ~color:label.color label.name
40+
in
41+
let label = label ^ " " in
42+
match foreground with
43+
| `Light -> fmt Style.fg_white label
44+
| `Dark -> fmt Style.fg_black label
45+
in
46+
labels |> List.map fmt_label |> fun labels -> horizontal (str " " :: labels)
47+
48+
let fmt_issue (issue : Gh.Issue.t) =
49+
Layout.vertical [ fmt_title issue; fmt_labels issue.labels ]
50+
51+
let issues issue_list =
52+
let layouts = List.map fmt_issue issue_list in
53+
let max_issue_width = Extra.List.max_on Layout.width layouts in
54+
ListLabels.map2 issue_list layouts ~f:(fun issue layout ->
55+
let width = Layout.width layout in
56+
let padding_len = max_issue_width - width in
57+
let layout =
58+
if padding_len <= 0 then layout
59+
else
60+
let padding = Layout.str (Extra.String.repeat_txt padding_len " ") in
61+
Layout.(horizontal [ layout; vertical [ padding; padding ] ])
62+
in
63+
{ item = issue; layout })

lib/tui/render/render.mli

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
(** This module describes functions to render domain types.
2+
3+
It surves several purposes:
4+
5+
+ Separate rendering from domain and fetching logic
6+
+ Prerender elements that don't change on the TUI start *)
7+
8+
(** Stores the item and the rendering of this item. *)
9+
type 'a t = {
10+
item : 'a;
11+
layout : Pretty.Layout.t;
12+
}
13+
14+
(** [issue_items issues] renders issues*)
15+
val issues : Gh.Issue.t list -> Gh.Issue.t t list

lib/tui/widget/generic.ml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ let item_padding = 4
2525

2626
let vlist_border ~selected items =
2727
let max_item_width = Extra.List.max_on Layout.width items in
28-
let pad = Extra.String.fill_right max_item_width in
2928
let max_width = max_item_width + item_padding in
3029

3130
(* Frame *)
@@ -42,9 +41,7 @@ let vlist_border ~selected items =
4241
Doc.(
4342
horizontal [ fmt Style.selected ""; str line; fmt Style.selected "" ])
4443
in
45-
let to_lines_item item =
46-
item |> Layout.to_lines |> List.map pad |> of_lines
47-
in
44+
let to_lines_item item = item |> Layout.to_lines |> of_lines in
4845

4946
let render_item { is_selected; item_type } =
5047
match item_type with

lib/tui/widget/generic.mli

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
(** This module contains generic widgets. *)
22

3-
(** Created a vertical list of items inside border like this one:
3+
(** Creates a vertical list of items inside border like this one:
44
55
{v
66
╭────────╮
@@ -16,6 +16,8 @@
1616
1717
Additionally, highlights the border of the selected item.
1818
19+
Also adds a scrollbar if items don't fit on the screen.
20+
1921
This function takes values of type {!Pretty.Layout.t}, so it could
2022
efficiently calculate the size of element per line. *)
2123
val vlist_border : selected:int -> Pretty.Layout.t list -> Pretty.Doc.t

lib/tui/widget/issue.ml

Lines changed: 5 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -37,55 +37,15 @@ let fmt_filters current_filter =
3737
let pad = Doc.str " " in
3838
Doc.horizontal [ filter_open; pad; filter_closed; pad; filter_all ]
3939

40-
let issue_char = "\u{f41b}"
41-
42-
let fmt_issue_state (state : Gh.Issue.state) =
43-
match state with
44-
| Open -> Layout.(fmt Style.issue_open issue_char)
45-
| Closed -> Layout.(fmt Style.issue_closed issue_char)
46-
47-
let fmt_title (issue : Gh.Issue.t) =
48-
let open Layout in
49-
horizontal
50-
[
51-
fmt_issue_state issue.state;
52-
str " ";
53-
fmt Style.secondary (Printf.sprintf "#%d " issue.number);
54-
str issue.title;
55-
str " by ";
56-
fmt Style.bold (Printf.sprintf "@%s" issue.author);
57-
]
58-
59-
let apply_background_color ~color text =
60-
let module Color = Pretty.Color in
61-
let color = Color.of_hex color in
62-
let foreground_suggestion = Color.foreground color in
63-
let color_code = Pretty.Color.to_escape_seq color in
64-
let text = Printf.sprintf "\027[48;%sm %s \027[0m" color_code text in
65-
(text, foreground_suggestion)
66-
67-
let fmt_labels labels =
68-
let open Layout in
69-
let fmt_label (label : Gh.Issue.label) =
70-
let label, foreground =
71-
apply_background_color ~color:label.color label.name
72-
in
73-
let label = label ^ " " in
74-
match foreground with
75-
| `Light -> fmt Style.fg_white label
76-
| `Dark -> fmt Style.fg_black label
77-
in
78-
labels |> List.map fmt_label |> fun labels -> horizontal (str " " :: labels)
79-
80-
let fmt_issue (issue : Gh.Issue.t) =
81-
Layout.vertical [ fmt_title issue; fmt_labels issue.labels ]
82-
8340
let fmt_issues ~selected issues =
84-
issues |> Lazy.force |> List.map fmt_issue |> Generic.vlist_border ~selected
41+
issues
42+
|> Lazy.force
43+
|> List.map (fun (rendered : _ Render.t) -> rendered.layout)
44+
|> Generic.vlist_border ~selected
8545

8646
let section (issues_tab : Model.Issue.t) =
8747
let docs =
88-
match issues_tab.error with
48+
match issues_tab.error |> Lazy.force with
8949
| None ->
9050
[
9151
fmt_filters issues_tab.filter;

0 commit comments

Comments
 (0)