1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Issue.Render
( IssueTitle (..),
IssueDescription (..),
IssueTags (..),
IssueComments (..),
IssueOpenedOn (..),
IssueOpenedBy (..),
)
where
import Data.List (intersperse)
import Data.List.NonEmpty qualified as N
import Data.Map qualified as M
import Data.Text qualified as T
import Data.Time.Clock (UTCTime (utctDay))
import Issue (Issue (..))
import Issue.Provenance (Author (..), Commit (..), Provenance (..))
import Render ((<<<))
import Render qualified as P
-- TODO Easily separate renderables by newlines
--
-- For convenience, the (<<<) combinator adds spaces between renderable entities, **if** those renderables are non-empty.
--
-- We should similarly allow for a combinator that similarly adds empty lines between renderable entities.
--
-- @topic rendering
instance P.Render (P.Detailed Issue) where
render (P.Detailed issue) =
IssueTitle issue
<<< P.hardline @P.AnsiStyle
<<< IssueDescription issue
<<< P.hardline @P.AnsiStyle
<<< IssueTags issue
<<< P.hardline @P.AnsiStyle
<<< IssueComments issue
instance P.Render Issue where
render = P.render . P.Detailed
newtype IssueTitle = IssueTitle {unIssueTitle :: Issue}
instance P.Render IssueTitle where
render (IssueTitle issue)
| issue.closed = P.styled [P.colorDull P.Red] $ P.render issue.title
| otherwise = P.styled [(P.color P.Green)] $ P.render issue.title
newtype IssueDescription = IssueDescription {unIssueDescription :: Issue}
instance P.Render IssueDescription where
render (IssueDescription issue) =
maybe P.emptyDoc (P.render . N.toList) $
issue.description
instance P.Render (P.Linked Issue) where
render (P.Linked issue)
| issue.closed =
P.styled [P.underlined, P.colorDull P.Red] $
("(closed)" :: T.Text) <<< P.render issue.id
| otherwise =
P.styled [P.underlined, (P.color P.Green)] $
P.render issue.id
instance P.Render (P.Summarized Issue) where
render (P.Summarized issue) =
P.nest 4 $
IssueTitle issue
<<< IssueTags issue
<<< IssueOpenedOn issue
<<< IssueOpenedBy issue
newtype IssueTags = IssueTags {unIssueTags :: Issue}
instance P.Render IssueTags where
render (IssueTags issue) = P.render issue.tags
newtype IssueComments = IssueComments {unIssueComments :: Issue}
instance P.Render IssueComments where
render (IssueComments issue) =
maybe P.emptyDoc (P.vsep . map P.render . N.toList) $
issue.comments
newtype IssueOpenedBy = IssueOpenedBy {unIssueOpenedBy :: Issue}
instance P.Render IssueOpenedBy where
render (IssueOpenedBy issue) =
("by" :: T.Text) <<< issue.provenance.first.author.name
newtype IssueOpenedOn = IssueOpenedOn {unIssueOpenedOn :: Issue}
instance P.Render IssueOpenedOn where
render (IssueOpenedOn issue) =
("on" :: T.Text) <<< utctDay issue.provenance.first.date
instance P.Render (T.Text, M.Map T.Text [Issue]) where
render (tagKey, groupedIssues) =
(P.vsep . intersperse ("" :: P.Doc ann)) $
concatMap
( \(name, issues) ->
( P.styled [P.underlined] $
("@" <> tagKey)
<<< name
<<< P.parens @P.AnsiStyle (P.pretty (length issues))
)
: map
(P.indent 4)
( map (P.render . IssueTitle) issues
)
)
(M.toList groupedIssues)
|