{-# LANGUAGE OverloadedStrings #-} module DataFrame.Display.Terminal.PrettyPrint where import qualified Data.Text as T import Data.List (transpose) type Filler = Int -> T.Text -> T.Text data ColDesc t = ColDesc { forall t. ColDesc t -> Filler colTitleFill :: Filler , forall t. ColDesc t -> Text colTitle :: T.Text , forall t. ColDesc t -> Filler colValueFill :: Filler } fillLeft :: Char -> Int -> T.Text -> T.Text fillLeft :: Char -> Filler fillLeft Char c Int n Text s = Text s Text -> Text -> Text `T.append` Filler T.replicate (Int n Int -> Int -> Int forall a. Num a => a -> a -> a - Text -> Int T.length Text s) (Char -> Text T.singleton Char c) fillRight :: Char -> Int -> T.Text -> T.Text fillRight :: Char -> Filler fillRight Char c Int n Text s = Filler T.replicate (Int n Int -> Int -> Int forall a. Num a => a -> a -> a - Text -> Int T.length Text s) (Char -> Text T.singleton Char c) Text -> Text -> Text `T.append` Text s fillCenter :: Char -> Int -> T.Text -> T.Text fillCenter :: Char -> Filler fillCenter Char c Int n Text s = Filler T.replicate Int l (Char -> Text T.singleton Char c) Text -> Text -> Text `T.append` Text s Text -> Text -> Text `T.append` Filler T.replicate Int r (Char -> Text T.singleton Char c) where x :: Int x = Int n Int -> Int -> Int forall a. Num a => a -> a -> a - Text -> Int T.length Text s l :: Int l = Int x Int -> Int -> Int forall a. Integral a => a -> a -> a `div` Int 2 r :: Int r = Int x Int -> Int -> Int forall a. Num a => a -> a -> a - Int l left :: Int -> T.Text -> T.Text left :: Filler left = Char -> Filler fillLeft Char ' ' right :: Int -> T.Text -> T.Text right :: Filler right = Char -> Filler fillRight Char ' ' center :: Int -> T.Text -> T.Text center :: Filler center = Char -> Filler fillCenter Char ' ' showTable :: Bool -> [T.Text] -> [T.Text] -> [[T.Text]] -> T.Text showTable :: Bool -> [Text] -> [Text] -> [[Text]] -> Text showTable Bool properMarkdown [Text] header [Text] types [[Text]] rows = let consolidatedHeader :: [Text] consolidatedHeader = if Bool properMarkdown then (Text -> Text -> Text) -> [Text] -> [Text] -> [Text] forall a b c. (a -> b -> c) -> [a] -> [b] -> [c] zipWith (\Text h Text t -> Text h Text -> Text -> Text forall a. Semigroup a => a -> a -> a <> Text "<br>" Text -> Text -> Text forall a. Semigroup a => a -> a -> a <> Text t) [Text] header [Text] types else [Text] header cs :: [ColDesc t] cs = (Text -> ColDesc t) -> [Text] -> [ColDesc t] forall a b. (a -> b) -> [a] -> [b] map (\Text h -> Filler -> Text -> Filler -> ColDesc t forall t. Filler -> Text -> Filler -> ColDesc t ColDesc Filler center Text h Filler left) [Text] consolidatedHeader widths :: [Int] widths = [ [Int] -> Int forall a. Ord a => [a] -> a forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a maximum ([Int] -> Int) -> [Int] -> Int forall a b. (a -> b) -> a -> b $ (Text -> Int) -> [Text] -> [Int] forall a b. (a -> b) -> [a] -> [b] map Text -> Int T.length [Text] col | [Text] col <- [[Text]] -> [[Text]] forall a. [[a]] -> [[a]] transpose ([[Text]] -> [[Text]]) -> [[Text]] -> [[Text]] forall a b. (a -> b) -> a -> b $ [Text] consolidatedHeader [Text] -> [[Text]] -> [[Text]] forall a. a -> [a] -> [a] : [Text] types [Text] -> [[Text]] -> [[Text]] forall a. a -> [a] -> [a] : [[Text]] rows ] border :: Text border = Text -> [Text] -> Text T.intercalate Text "---" [Filler T.replicate Int width (Char -> Text T.singleton Char '-') | Int width <- [Int] widths] separator :: Text separator = Text -> [Text] -> Text T.intercalate Text "-|-" [Filler T.replicate Int width (Char -> Text T.singleton Char '-') | Int width <- [Int] widths] fillCols :: (ColDesc t -> Int -> t -> Text) -> [t] -> Text fillCols ColDesc t -> Int -> t -> Text fill [t] cols = Text -> [Text] -> Text T.intercalate Text " | " [ColDesc t -> Int -> t -> Text fill ColDesc t c Int width t col | (ColDesc t c, Int width, t col) <- [ColDesc t] -> [Int] -> [t] -> [(ColDesc t, Int, t)] forall a b c. [a] -> [b] -> [c] -> [(a, b, c)] zip3 [ColDesc t] forall {t}. [ColDesc t] cs [Int] widths [t] cols] lines :: [Text] lines = if Bool properMarkdown then [Text] -> Text T.concat [Text "| ", (ColDesc Any -> Filler) -> [Text] -> Text forall {t} {t}. (ColDesc t -> Int -> t -> Text) -> [t] -> Text fillCols ColDesc Any -> Filler forall t. ColDesc t -> Filler colTitleFill [Text] consolidatedHeader, Text " |"] Text -> [Text] -> [Text] forall a. a -> [a] -> [a] : [Text] -> Text T.concat [Text "| ", Text separator, Text " |"] Text -> [Text] -> [Text] forall a. a -> [a] -> [a] : ([Text] -> Text) -> [[Text]] -> [Text] forall a b. (a -> b) -> [a] -> [b] map ((\Text t -> [Text] -> Text T.concat [Text "| ", Text t, Text " |"]) (Text -> Text) -> ([Text] -> Text) -> [Text] -> Text forall b c a. (b -> c) -> (a -> b) -> a -> c . (ColDesc Any -> Filler) -> [Text] -> Text forall {t} {t}. (ColDesc t -> Int -> t -> Text) -> [t] -> Text fillCols ColDesc Any -> Filler forall t. ColDesc t -> Filler colValueFill) [[Text]] rows else Text border Text -> [Text] -> [Text] forall a. a -> [a] -> [a] : (ColDesc Any -> Filler) -> [Text] -> Text forall {t} {t}. (ColDesc t -> Int -> t -> Text) -> [t] -> Text fillCols ColDesc Any -> Filler forall t. ColDesc t -> Filler colTitleFill [Text] consolidatedHeader Text -> [Text] -> [Text] forall a. a -> [a] -> [a] : Text separator Text -> [Text] -> [Text] forall a. a -> [a] -> [a] : (ColDesc Any -> Filler) -> [Text] -> Text forall {t} {t}. (ColDesc t -> Int -> t -> Text) -> [t] -> Text fillCols ColDesc Any -> Filler forall t. ColDesc t -> Filler colTitleFill [Text] types Text -> [Text] -> [Text] forall a. a -> [a] -> [a] : Text separator Text -> [Text] -> [Text] forall a. a -> [a] -> [a] : ([Text] -> Text) -> [[Text]] -> [Text] forall a b. (a -> b) -> [a] -> [b] map ((ColDesc Any -> Filler) -> [Text] -> Text forall {t} {t}. (ColDesc t -> Int -> t -> Text) -> [t] -> Text fillCols ColDesc Any -> Filler forall t. ColDesc t -> Filler colValueFill) [[Text]] rows in [Text] -> Text T.unlines [Text] lines