{- | Module : Text.Tabl.Ascii Description : ASCII-art table rendering engine Copyright : (c) Daniel Lovasko, 2016 License : BSD3 Maintainer : Daniel Lovasko Stability : stable Portability : portable Implementation of the ASCII-art environment for table rendering. -} {-# LANGUAGE OverloadedStrings #-} module Text.Tabl.Ascii ( ascii ) where import Safe import qualified Data.Text as T import Text.Tabl.Alignment import Text.Tabl.Util -- | Compute the greatest cell width of each column. columnWidths :: [[T.Text]] -- ^ table cell data -> [Int] -- ^ column widths columnWidths cells = foldr combine zeros cells where zeros = replicate (length $ head cells) 0 combine = zipWith (\txt len -> max len (T.length txt)) -- | Convert decoration presence to actual decorator text. verticalDecorators :: [Bool] -- ^ presence -> [T.Text] -- ^ decorators verticalDecorators pres = [left $ head pres] ++ map mid (drop 1 $ init pres) ++ [right $ last pres] where left = bool "| " "" mid = bool " | " " " right = bool " |" "" -- | Create the decorative horizontal line. horizontalLine :: [T.Text] -- ^ first row -> [T.Text] -- ^ vertical decoration -> T.Text -- ^ horizontal line horizontalLine frow vdecor = zipcat isects dashes where dashes = map (\cell -> T.replicate (T.length cell) "-") frow isects = map (T.map conv) vdecor conv c = lookupJustDef '?' c [(' ', '-'), ('|', '+')] -- | Apply both vertical and horizontal decorations to the table. applyDecoration :: [Bool] -- ^ horizontal decoration -> [Bool] -- ^ vertical decoration -> [[T.Text]] -- ^ table cell data -> [T.Text] -- ^ decorated rows applyDecoration hpres vpres cells = intersperseOn rows hpres hline where vdecor = verticalDecorators vpres hline = horizontalLine (head cells) vdecor rows = map (zipcat vdecor) cells -- | Align a cell content based on specified width and style. alignCell :: Alignment -- ^ alignment style -> Int -- ^ width -> T.Text -- ^ text -> T.Text -- ^ aligned text alignCell AlignLeft = flip T.justifyLeft ' ' alignCell AlignRight = flip T.justifyRight ' ' alignCell AlignCentre = flip T.center ' ' -- | Align each cell of the table based on the width and alignment of -- the column it is in. alignCells :: [[T.Text]] -- ^ table cell data -> [Int] -- ^ column widths -> [Alignment] -- ^ column alignments -> [[T.Text]] -- ^ aligned table cell data alignCells cells widths aligns = map (zipWith3 alignCell aligns widths) cells -- | Create a table layout using elements of ASCII art, thus making the table -- suitable for the command line environment. ascii :: [Bool] -- ^ horizontal decoration -> [Bool] -- ^ vertical decoration -> [Alignment] -- ^ column alignments -> [[T.Text]] -- ^ table cell data -> T.Text -- ^ table ascii hpres vpres aligns cells = T.intercalate "\n" decorated where decorated = applyDecoration hpres vpres aligned aligned = alignCells escaped (columnWidths escaped) aligns escaped = map (map (T.replace "\n" "\\n" . T.replace "\t" "\\t")) cells