blob: eeff8205cba906931632082c2438409021df2bd4 (
plain)
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
|
module Table where
import Data.Char
import Data.List
import Data.Maybe (isJust, fromMaybe)
import qualified DList
type Row = [String]
type ColWidth = Int
type WrappedString = [String]
-- | Wrap a string to lines of at most the given length on whitespace
-- if possible.
wrapAt :: Int -> String -> WrappedString
wrapAt width = wrapLine
where
wrapLine :: String -> WrappedString
wrapLine s =
go width mempty (take width s : wrapLine (drop width s)) s
go :: Int -- ^ remaining width
-> DList.DList Char -- ^ accumulator
-> WrappedString -- ^ last good wrapping
-> String -- ^ remaining string
-> WrappedString
go 0 _ back _ = back
go n accum _ (c:rest)
| breakable c = go (n-1) accum'
(DList.toList accum' : wrapLine rest) rest
where accum' = accum `DList.snoc` c
go n accum back (c:rest) = go (n-1) (accum `DList.snoc` c) back rest
go _ accum _ [] = [DList.toList accum]
breakable = isSpace
transpose' :: [[a]] -> [[Maybe a]]
transpose' = goRow
where
peel :: [a] -> (Maybe a, [a])
peel (x:xs) = (Just x, xs)
peel [] = (Nothing, [])
goRow xs =
case unzip $ map peel xs of
(xs', ys)
| any isJust xs' -> xs' : goRow ys
| otherwise -> []
table :: [ColWidth] -> Row -> [Row] -> String
table widths hdr rows = unlines $
[rule '-'] ++
[formatRow hdr] ++
[rule '='] ++
intersperse (rule '-') (map formatRow rows) ++
[rule '-']
where
formatRow :: Row -> String
formatRow cols =
intercalate "\n"
$ map (rawRow . map (fromMaybe ""))
$ transpose'
$ zipWith wrapAt (map (subtract 4) widths) cols
rawRow :: Row -> String
rawRow cols = "| " ++ intercalate " | " (zipWith padTo widths cols) ++ " |"
padTo width content = take width $ content ++ repeat ' '
rule :: Char -> String
rule lineChar =
['+',lineChar]
++intercalate [lineChar,'+',lineChar]
(map (\n -> replicate n lineChar) widths)
++[lineChar,'+']
|