1
1
{-# LANGUAGE ScopedTypeVariables #-}
2
2
3
+ -- | This module provides some utility functions to help with aligning pretty
4
+ -- printed values by column.
3
5
module Codec.CBOR.Cuddle.Pretty.Columnar (
4
6
CellAlign (.. ),
5
7
Row (.. ),
@@ -27,33 +29,46 @@ data Cell ann = Cell
27
29
, cellAlign :: CellAlign
28
30
}
29
31
32
+ -- | Creates a cell by pretty printing the input value and then left-aligning
33
+ -- the resulting `Doc` within the table.
30
34
cellL :: Pretty a => a -> Cell ann
31
35
cellL = (`Cell ` LeftAlign ) . pretty
32
36
37
+ -- | Creates a cell by pretty printing the input value and then right-aligning
38
+ -- the resulting `Doc` within the table.
33
39
cellR :: Pretty a => a -> Cell ann
34
40
cellR = (`Cell ` RightAlign ) . pretty
35
41
42
+ -- | A cell that takes up a cell but has no content.
36
43
emptyCell :: Cell ann
37
44
emptyCell = Cell mempty LeftAlign
38
45
46
+ -- | Checks whether the cell contains a `Doc` with a rendered width of zero.
39
47
isEmptyCell :: Cell ann -> Bool
40
48
isEmptyCell (Cell d _) = renderedLen d == 0
41
49
50
+ -- | A row within the table.
42
51
newtype Row ann = Row { rowCells :: [Cell ann ]}
43
52
53
+ -- | Adds a cell at the beginning of the row.
44
54
prependCell :: Cell ann -> Row ann -> Row ann
45
55
prependCell c (Row cs) = Row $ c : cs
46
56
57
+ -- | A row with a single left-aligned document
47
58
singletonRow :: Doc ann -> Row ann
48
59
singletonRow x = Row [Cell x LeftAlign ]
49
60
61
+ -- | `Columnar` is a two-dimensional table of `Doc`s. When rendered, the cells
62
+ -- within each row will be aligned with the cells of every other row in the
63
+ -- same column.
50
64
newtype Columnar ann = Columnar { colRows :: [Row ann ]}
51
65
52
66
prettyRow :: [Int ] -> [Cell ann ] -> Doc ann
53
67
prettyRow = prettyRow'
54
68
where
55
69
prettyRow' [] (Cell c _ : cs) = c <> prettyRow' [] cs
56
70
prettyRow' _ [] = mempty
71
+ prettyRow' _ [Cell c LeftAlign ] = c -- Do not add white space to the last cell
57
72
prettyRow' (0 : ws) (_ : cs) = prettyRow' ws cs -- Skip empty columns
58
73
prettyRow' (w : ws) (Cell c alignment : cs) =
59
74
let
@@ -63,12 +78,23 @@ prettyRow = prettyRow'
63
78
in
64
79
align' w c <> prettyRow' ws cs
65
80
81
+ -- | Pretty print the `Columnar` as a table.
66
82
prettyColumnar :: forall ann . Columnar ann -> Doc ann
67
83
prettyColumnar (Columnar rows) = vcat $ prettyRow columnWidths . rowCells <$> rows
68
84
where
69
85
columnWidths =
70
86
foldr (zipWith max . fmap (renderedLen . cellDoc) . rowCells) (repeat 0 ) rows
71
87
88
+ -- | Pretty prints the `Columnar` so that the rows are separated by by the
89
+ -- separator `Doc` provided as the third argument and then everything is
90
+ -- enclosed within the left and right brackets provided as the first and second
91
+ -- argument accordingly. The brackets will be aligned with the separators in the
92
+ -- first column, e.g.
93
+ -- ```
94
+ -- [ foo
95
+ -- , bar
96
+ -- ]
97
+ -- ```
72
98
columnarListing :: Doc ann -> Doc ann -> Doc ann -> Columnar ann -> Doc ann
73
99
columnarListing lEnc rEnc _ (Columnar [] ) = lEnc <> rEnc
74
100
columnarListing lEnc rEnc s (Columnar (row : rows)) =
@@ -80,10 +106,22 @@ columnarListing lEnc rEnc s (Columnar (row : rows)) =
80
106
<> line'
81
107
<> rEnc
82
108
109
+ -- | Pretty prints the `Columnar` so that every line after the first has a
110
+ -- separator prepended to it. This can be useful when you want to align the rows,
111
+ -- but the separator would cause all the other rows after the first to be shifted
112
+ -- right by one. The way you use this is you reduce the indentation on the
113
+ -- following lines by the width of the separator.
114
+ -- ```
115
+ -- foo = x
116
+ -- , y
117
+ -- , z
118
+ -- ```
83
119
columnarSepBy :: Doc ann -> Columnar ann -> Doc ann
84
120
columnarSepBy _ (Columnar [] ) = mempty
85
- columnarSepBy s (Columnar ( x : xs)) =
86
- prettyColumnar ( Columnar [x]) <> line' <> prettyColumnar (Columnar $ prependRow <$> xs)
121
+ columnarSepBy s (Columnar rows @ ( Row x : xs)) =
122
+ prettyRow columnWidths x <> line' <> prettyColumnar (Columnar $ prependRow <$> xs)
87
123
where
88
124
prependRow (Row (Cell c al : cs)) = Row $ Cell (s <+> c) al : cs
89
125
prependRow (Row [] ) = Row []
126
+ columnWidths =
127
+ foldr (zipWith max . fmap (renderedLen . cellDoc) . rowCells) (repeat 0 ) rows
0 commit comments