packages feed

table-layout-1.0.0.2: src/Text/Layout/Table/Spec/RowGroup.hs

{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveFoldable #-}
module Text.Layout.Table.Spec.RowGroup where

import Text.Layout.Table.Spec.Util

import Data.List (transpose)
import Data.Functor (void)

-- | Groups rows together which should not be visually seperated from each other.
data RowGroup a
    = SingletonRowGroup (Row a)
    | MultiRowGroup [Row a]
    | NullableRowGroup [Row (Maybe a)]

-- | Group the given rows together.
rowsG :: [Row a] -> RowGroup a
rowsG = MultiRowGroup

-- | Make a group of a single row.
rowG :: Row a -> RowGroup a
rowG = SingletonRowGroup

-- | Provide a 'RowGroup' where single cells may be missing.
nullableRowsG :: [Row (Maybe a)] -> RowGroup a
nullableRowsG = NullableRowGroup

-- | Extracts the shape of the 'RowGroup' from the first row.
rowGroupShape :: RowGroup a -> [()]
rowGroupShape rg = case rg of
    SingletonRowGroup r  -> void r
    MultiRowGroup rs     -> firstSubListShape rs
    NullableRowGroup ors -> firstSubListShape ors
  where
    firstSubListShape l = case l of
        r : _ -> void r
        []    -> []

data ColumnSegment a
    = SingleValueSegment a
    | ColumnSegment (Col a)
    | NullableColumnSegment (Col (Maybe a))
    deriving (Functor, Foldable, Eq, Show)

newtype SegmentedColumn a = SegmentedColumn [ColumnSegment a] deriving (Functor, Foldable, Eq, Show)

-- | Break down several 'RowGroups', which conceptually form a column by
-- themselves, into a list of columns.
transposeRowGroups :: Col (RowGroup a) -> [SegmentedColumn a]
transposeRowGroups = fmap SegmentedColumn . transpose . map transposeRowGroup
  where
    transposeRowGroup :: RowGroup a -> [ColumnSegment a]
    transposeRowGroup rg = case rg of
        SingletonRowGroup row -> SingleValueSegment <$> row
        MultiRowGroup rows    -> ColumnSegment <$> transpose rows
        NullableRowGroup rows -> NullableColumnSegment <$> transpose rows

-- | Map each column with the corresponding function and replace empty inputs
-- with the given value.
mapRowGroupColumns :: [(b, a -> b)] -> RowGroup a -> [[b]]
mapRowGroupColumns mappers rg = case rg of
    SingletonRowGroup row  -> pure $ zipWith snd mappers row
    MultiRowGroup rows     -> mapGrid snd rows
    NullableRowGroup orows -> mapGrid (uncurry maybe) orows
  where
    mapGrid applyMapper = map $ zipWith applyMapper mappers