1 module Hcompta.LCC.Write.Table where
4 import Data.Char (Char)
5 import Data.Eq (Eq(..))
6 import Data.Foldable (any, foldr)
7 import Data.Functor ((<$>))
8 import Data.Maybe (Maybe(..), fromMaybe)
9 import Data.Ord (Ord(..))
10 import Data.Semigroup (Semigroup(..))
11 import Data.Text (Text)
12 import Data.Tuple (curry)
13 import Prelude (($), (.), Int, Integral(..), Num(..), fromIntegral, id, zipWith)
14 import Text.Show (Show)
15 import qualified Data.List as L
16 import qualified Data.Text as T
17 import qualified Data.Text.Lazy as TL
19 import Hcompta.LCC.Write.Compta
20 import qualified Language.Symantic.Document as D
22 -- * Type 'TablePlain'
23 type TablePlain d = [ColumnPlain d]
25 instance (D.Doc_Text d, D.Doc_Color d) => Writeable d (TablePlain d) where
27 let cols = refreshWidthCol <$> cols' in
28 let rows = L.transpose $ columnPlain_rows <$> cols in
29 let has_title = any (not . T.null . columnPlain_title) cols in
30 let titles :: d = D.catH $ L.intersperse (d_sep '|') $ d_title <$> cols in
32 (if has_title then (:) titles else id) $
35 L.intersperse (D.space <> d_sep '|') $
37 zipWith (curry $ alignCellPlain Nothing) cols row
39 (case cols of { [] -> D.empty; _ -> D.eol })
41 refreshWidthCol col@ColumnPlain{columnPlain_width=w} =
43 then col{columnPlain_width = widthCol col}
46 widthCol :: ColumnPlain d -> Int
49 , columnPlain_rows } =
50 max (T.length columnPlain_title) $
51 foldr (max . cellPlain_width) 0 columnPlain_rows
52 d_title :: ColumnPlain d -> d
53 d_title col@ColumnPlain{columnPlain_title} = do
54 let pad len = D.blacker $ D.text $ T.pack $ L.replicate len '_'
55 alignCellPlain (Just pad) (col, CellPlain
56 { cellPlain_width = T.length columnPlain_title
57 , cellPlain_content = d_under <> d_underline columnPlain_title <> d_under
58 , cellPlain_align = Just AlignPlainC
60 d_sep = D.blacker . D.charH
63 D.catH $ (<$> T.unpack t) $ \case
71 (ColumnPlain d, CellPlain d) -> d
72 alignCellPlain may_padding
73 ( ColumnPlain{columnPlain_align, columnPlain_width}
74 , CellPlain{cellPlain_width, cellPlain_content, cellPlain_align} ) =
75 let pad = columnPlain_width - cellPlain_width in
76 case columnPlain_align `fromMaybe` cellPlain_align of
77 AlignPlainL -> cellPlain_content <> padding pad
78 AlignPlainC -> padding half <> cellPlain_content <> padding (pad - half)
79 where half = fromInteger $ quot (toInteger pad) 2
80 AlignPlainR -> padding pad <> cellPlain_content
81 where padding = D.spaces `fromMaybe` may_padding
82 alignCellPlain _filling
83 ( ColumnPlain{columnPlain_width}
84 , CellPlain_Line{cellPlain_pad} ) =
85 D.blacker $ D.ltextH $
86 TL.replicate (fromIntegral columnPlain_width) $
87 TL.singleton cellPlain_pad
89 -- ** Class 'TablePlainOf'
90 class TablePlainOf a d where
91 tablePlainOf :: a -> TablePlain d
93 -- * Type 'ColumnPlain'
96 { columnPlain_title :: Text
97 , columnPlain_align :: AlignPlain
98 , columnPlain_width :: Int
99 , columnPlain_rows :: [CellPlain d]
100 } deriving (Eq, Show)
102 columnPlain :: Text -> AlignPlain -> [CellPlain d] -> ColumnPlain d
105 { columnPlain_title = t
106 , columnPlain_align = a
107 , columnPlain_width = 0
108 , columnPlain_rows = r
111 -- ** Type 'AlignPlain'
118 -- ** Class 'columnPlainOf'
119 class ColumnPlainOf a d where
120 columnPlainOf :: a -> ColumnPlain d
122 -- * Type 'CellPlain'
124 = CellPlain { cellPlain_align :: Maybe AlignPlain
125 , cellPlain_width :: Int
126 , cellPlain_content :: d
128 | CellPlain_Line { cellPlain_pad :: Char
129 , cellPlain_width :: Int
133 -- ** Class 'CellPlainOf'
134 class CellPlainOf a d where
135 cellPlainOf :: a -> CellPlain d
136 default cellPlainOf ::
140 cellPlainOf = cellPlain
142 instance D.Doc_Text d => CellPlainOf () d where
143 cellPlainOf () = CellPlain
144 { cellPlain_width = 0
145 , cellPlain_align = Nothing
146 , cellPlain_content = D.empty
155 { cellPlain_width = D.width $ D.dim $ write a
156 , cellPlain_align = Nothing
157 , cellPlain_content = write a
166 instance ToDoc ColumnPlain CellPlain where
167 toDoc = alignCellPlain Nothing
170 class CellOf context x where
171 cellOf :: context -> x -> CellPlain
173 instance CellOf context x => CellOf context (Maybe x) where
174 cellOf ctx = maybe cellPlain (cellOf ctx)
176 -- ** Class 'Cell_of_forall_param'
178 -- | A class useful when using a context of kind '*' is not wanted
179 -- for example in a class instance constraint
180 -- to keep the instance decidable (i.e. avoid UndecidableInstances).
181 class Cell_of_forall_param f x where
182 cellPlain_of_forall_param :: forall m. f m -> x -> CellPlain
183 -- instance Cell_of_forall_param f x => CellOf (f m) x where
184 -- cellOf = cellPlain_of_forall_param
185 instance Cell_of_forall_param context x => Cell_of_forall_param context (Maybe x) where
186 cellPlain_of_forall_param ctx = maybe cellPlain (cellPlain_of_forall_param ctx)