{-# LANGUAGE RankNTypes #-}
module Text.Layout.Table.Primitives.ColumnModifier where
import Control.Arrow ((&&&))
import Data.List
import Data.Semigroup (Max(..))
import Text.Layout.Table.Cell
import Text.Layout.Table.Primitives.AlignInfo
import Text.Layout.Table.Spec.AlignSpec
import Text.Layout.Table.Spec.ColSpec
import Text.Layout.Table.Spec.CutMark
import Text.Layout.Table.Spec.LenSpec
import Text.Layout.Table.Spec.OccSpec
import Text.Layout.Table.Spec.Position
import Text.Layout.Table.Spec.Util
import Text.Layout.Table.StringBuilder
data ColModInfo
= FillAligned OccSpec AlignInfo
| FillTo Int
| FitTo Int (Maybe (OccSpec, AlignInfo))
showCMI :: ColModInfo -> String
showCMI :: ColModInfo -> String
showCMI ColModInfo
cmi = case ColModInfo
cmi of
FillAligned OccSpec
_ AlignInfo
ai -> String
"FillAligned .. " String -> String -> String
forall a. [a] -> [a] -> [a]
++ AlignInfo -> String
showAI AlignInfo
ai
FillTo Int
i -> String
"FillTo " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
i
FitTo Int
i Maybe (OccSpec, AlignInfo)
_ -> String
"FitTo " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
i String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
".."
widthCMI :: ColModInfo -> Int
widthCMI :: ColModInfo -> Int
widthCMI ColModInfo
cmi = case ColModInfo
cmi of
FillAligned OccSpec
_ AlignInfo
ai -> AlignInfo -> Int
widthAI AlignInfo
ai
FillTo Int
maxLen -> Int
maxLen
FitTo Int
lim Maybe (OccSpec, AlignInfo)
_ -> Int
lim
unalignedCMI :: ColModInfo -> ColModInfo
unalignedCMI :: ColModInfo -> ColModInfo
unalignedCMI ColModInfo
cmi = case ColModInfo
cmi of
FillAligned OccSpec
_ AlignInfo
ai -> Int -> ColModInfo
FillTo (Int -> ColModInfo) -> Int -> ColModInfo
forall a b. (a -> b) -> a -> b
$ AlignInfo -> Int
widthAI AlignInfo
ai
FitTo Int
i Maybe (OccSpec, AlignInfo)
_ -> Int -> Maybe (OccSpec, AlignInfo) -> ColModInfo
FitTo Int
i Maybe (OccSpec, AlignInfo)
forall a. Maybe a
Nothing
ColModInfo
_ -> ColModInfo
cmi
ensureWidthCMI :: Int -> Position H -> ColModInfo -> ColModInfo
ensureWidthCMI :: Int -> Position H -> ColModInfo -> ColModInfo
ensureWidthCMI Int
w Position H
pos ColModInfo
cmi = case ColModInfo
cmi of
FillAligned OccSpec
oS ai :: AlignInfo
ai@(AlignInfo Int
lw Maybe Int
optRW)
->
let neededW :: Int
neededW = Int
w Int -> Int -> Int
forall a. Num a => a -> a -> a
- AlignInfo -> Int
widthAI AlignInfo
ai
in if Int
neededW Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0
then ColModInfo
cmi
else OccSpec -> AlignInfo -> ColModInfo
FillAligned OccSpec
oS (AlignInfo -> ColModInfo) -> AlignInfo -> ColModInfo
forall a b. (a -> b) -> a -> b
$ case Position H
pos of
Position H
Start -> case Maybe Int
optRW of
Just Int
rw -> Int -> Maybe Int -> AlignInfo
AlignInfo Int
lw (Maybe Int -> AlignInfo) -> Maybe Int -> AlignInfo
forall a b. (a -> b) -> a -> b
$ Int -> Maybe Int
forall a. a -> Maybe a
Just (Int
rw Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
neededW)
Maybe Int
Nothing -> Int -> Maybe Int -> AlignInfo
AlignInfo (Int
lw Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
neededW) Maybe Int
optRW
Position H
End -> Int -> Maybe Int -> AlignInfo
AlignInfo (Int
lw Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
neededW) Maybe Int
optRW
Position H
Center -> case Maybe Int
optRW of
Just Int
_ -> let (Int
q, Int
r) = Int
w Int -> Int -> (Int, Int)
forall a. Integral a => a -> a -> (a, a)
`divMod` Int
2
in Int -> Maybe Int -> AlignInfo
AlignInfo Int
q (Maybe Int -> AlignInfo) -> Maybe Int -> AlignInfo
forall a b. (a -> b) -> a -> b
$ Int -> Maybe Int
forall a. a -> Maybe a
Just (Int
q Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
r)
Maybe Int
Nothing -> Int -> Maybe Int -> AlignInfo
AlignInfo (Int
lw Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
neededW) Maybe Int
optRW
FillTo Int
maxLen -> Int -> ColModInfo
FillTo (Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
maxLen Int
w)
ColModInfo
_ -> ColModInfo
cmi
ensureWidthOfCMI :: Cell a => a -> Position H -> ColModInfo -> ColModInfo
ensureWidthOfCMI :: forall a. Cell a => a -> Position H -> ColModInfo -> ColModInfo
ensureWidthOfCMI = Int -> Position H -> ColModInfo -> ColModInfo
ensureWidthCMI (Int -> Position H -> ColModInfo -> ColModInfo)
-> (a -> Int) -> a -> Position H -> ColModInfo -> ColModInfo
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Int
forall a. Cell a => a -> Int
visibleLength
fitTitlesCMI :: Cell a => [a] -> [Position H] -> [ColModInfo] -> [ColModInfo]
fitTitlesCMI :: forall a.
Cell a =>
[a] -> [Position H] -> [ColModInfo] -> [ColModInfo]
fitTitlesCMI = (a -> Position H -> ColModInfo -> ColModInfo)
-> [a] -> [Position H] -> [ColModInfo] -> [ColModInfo]
forall a b c d. (a -> b -> c -> d) -> [a] -> [b] -> [c] -> [d]
zipWith3 a -> Position H -> ColModInfo -> ColModInfo
forall a. Cell a => a -> Position H -> ColModInfo -> ColModInfo
ensureWidthOfCMI
columnModifier
:: (Cell a, StringBuilder b)
=> Position H
-> CutMark
-> ColModInfo
-> (a -> b)
columnModifier :: forall a b.
(Cell a, StringBuilder b) =>
Position H -> CutMark -> ColModInfo -> a -> b
columnModifier Position H
pos CutMark
cms ColModInfo
colModInfo = CutMark -> CellMod a -> b
forall c s. (Cell c, StringBuilder s) => CutMark -> CellMod c -> s
buildCellMod CutMark
cms (CellMod a -> b) -> (a -> CellMod a) -> a -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. case ColModInfo
colModInfo of
FillAligned OccSpec
oS AlignInfo
ai -> OccSpec -> AlignInfo -> a -> CellMod a
forall a. Cell a => OccSpec -> AlignInfo -> a -> CellMod a
align OccSpec
oS AlignInfo
ai
FillTo Int
maxLen -> Position H -> Int -> a -> CellMod a
forall a o. Cell a => Position o -> Int -> a -> CellMod a
pad Position H
pos Int
maxLen
FitTo Int
lim Maybe (OccSpec, AlignInfo)
mT ->
(a -> CellMod a)
-> ((OccSpec, AlignInfo) -> a -> CellMod a)
-> Maybe (OccSpec, AlignInfo)
-> a
-> CellMod a
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (Position H -> CutMark -> Int -> a -> CellMod a
forall a o.
Cell a =>
Position o -> CutMark -> Int -> a -> CellMod a
trimOrPad Position H
pos CutMark
cms Int
lim) ((OccSpec -> AlignInfo -> a -> CellMod a)
-> (OccSpec, AlignInfo) -> a -> CellMod a
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry ((OccSpec -> AlignInfo -> a -> CellMod a)
-> (OccSpec, AlignInfo) -> a -> CellMod a)
-> (OccSpec -> AlignInfo -> a -> CellMod a)
-> (OccSpec, AlignInfo)
-> a
-> CellMod a
forall a b. (a -> b) -> a -> b
$ Position H
-> CutMark -> Int -> OccSpec -> AlignInfo -> a -> CellMod a
forall a o.
Cell a =>
Position o
-> CutMark -> Int -> OccSpec -> AlignInfo -> a -> CellMod a
alignFixed Position H
pos CutMark
cms Int
lim) Maybe (OccSpec, AlignInfo)
mT
deriveAlignInfo :: Cell a => OccSpec -> a -> AlignInfo
deriveAlignInfo :: forall a. Cell a => OccSpec -> a -> AlignInfo
deriveAlignInfo OccSpec
occSpec = (Char -> Bool) -> a -> AlignInfo
forall a. Cell a => (Char -> Bool) -> a -> AlignInfo
measureAlignment (OccSpec -> Char -> Bool
predicate OccSpec
occSpec)
unpackColSpecs :: [ColSpec] -> [(LenSpec, AlignSpec)]
unpackColSpecs :: [ColSpec] -> [(LenSpec, AlignSpec)]
unpackColSpecs = (ColSpec -> (LenSpec, AlignSpec))
-> [ColSpec] -> [(LenSpec, AlignSpec)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((ColSpec -> (LenSpec, AlignSpec))
-> [ColSpec] -> [(LenSpec, AlignSpec)])
-> (ColSpec -> (LenSpec, AlignSpec))
-> [ColSpec]
-> [(LenSpec, AlignSpec)]
forall a b. (a -> b) -> a -> b
$ ColSpec -> LenSpec
lenSpec (ColSpec -> LenSpec)
-> (ColSpec -> AlignSpec) -> ColSpec -> (LenSpec, AlignSpec)
forall (a :: * -> * -> *) b c c'.
Arrow a =>
a b c -> a b c' -> a b (c, c')
&&& ColSpec -> AlignSpec
alignSpec
deriveColModInfosFromGridLA :: Cell a => [(LenSpec, AlignSpec)] -> [Row a] -> [ColModInfo]
deriveColModInfosFromGridLA :: forall a.
Cell a =>
[(LenSpec, AlignSpec)] -> [Row a] -> [ColModInfo]
deriveColModInfosFromGridLA [(LenSpec, AlignSpec)]
specs = [(LenSpec, AlignSpec)] -> [[a]] -> [ColModInfo]
forall (col :: * -> *) a.
(Foldable col, Cell a) =>
[(LenSpec, AlignSpec)] -> [col a] -> [ColModInfo]
deriveColModInfosFromColumnsLA [(LenSpec, AlignSpec)]
specs ([[a]] -> [ColModInfo])
-> ([[a]] -> [[a]]) -> [[a]] -> [ColModInfo]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [[a]] -> [[a]]
forall a. [[a]] -> [[a]]
transpose
deriveColModInfosFromGrid :: Cell a => [ColSpec] -> [Row a] -> [ColModInfo]
deriveColModInfosFromGrid :: forall a. Cell a => [ColSpec] -> [Row a] -> [ColModInfo]
deriveColModInfosFromGrid = [(LenSpec, AlignSpec)] -> [Row a] -> [ColModInfo]
forall a.
Cell a =>
[(LenSpec, AlignSpec)] -> [Row a] -> [ColModInfo]
deriveColModInfosFromGridLA ([(LenSpec, AlignSpec)] -> [Row a] -> [ColModInfo])
-> ([ColSpec] -> [(LenSpec, AlignSpec)])
-> [ColSpec]
-> [Row a]
-> [ColModInfo]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ColSpec] -> [(LenSpec, AlignSpec)]
unpackColSpecs
deriveColModInfoFromColumnLA :: (Foldable col, Cell a) => (LenSpec, AlignSpec) -> col a -> ColModInfo
deriveColModInfoFromColumnLA :: forall (col :: * -> *) a.
(Foldable col, Cell a) =>
(LenSpec, AlignSpec) -> col a -> ColModInfo
deriveColModInfoFromColumnLA (LenSpec
lenS, AlignSpec
alignS) = case AlignSpec
alignS of
AlignSpec
NoAlign -> let expandFun :: Int -> ColModInfo
expandFun = Int -> ColModInfo
FillTo
fixedFun :: Int -> b -> ColModInfo
fixedFun Int
i = ColModInfo -> b -> ColModInfo
forall a b. a -> b -> a
const (ColModInfo -> b -> ColModInfo) -> ColModInfo -> b -> ColModInfo
forall a b. (a -> b) -> a -> b
$ Int -> Maybe (OccSpec, AlignInfo) -> ColModInfo
FitTo Int
i Maybe (OccSpec, AlignInfo)
forall a. Maybe a
Nothing
measureMaximumWidth :: col a -> Int
measureMaximumWidth = Max Int -> Int
forall a. Max a -> a
getMax (Max Int -> Int) -> (col a -> Max Int) -> col a -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> Max Int) -> col a -> Max Int
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap (Int -> Max Int
forall a. a -> Max a
Max (Int -> Max Int) -> (a -> Int) -> a -> Max Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Int
forall a. Cell a => a -> Int
visibleLength)
lengthFun :: a -> a
lengthFun = a -> a
forall a. a -> a
id
in (Int -> ColModInfo)
-> (Int -> Int -> ColModInfo)
-> (col a -> Int)
-> (Int -> Int)
-> col a
-> ColModInfo
forall a w (col :: * -> *).
(Cell a, Foldable col) =>
(w -> ColModInfo)
-> (Int -> w -> ColModInfo)
-> (col a -> w)
-> (w -> Int)
-> col a
-> ColModInfo
go Int -> ColModInfo
expandFun Int -> Int -> ColModInfo
forall {b}. Int -> b -> ColModInfo
fixedFun col a -> Int
measureMaximumWidth Int -> Int
forall a. a -> a
lengthFun
AlignOcc OccSpec
oS -> let expandFun :: AlignInfo -> ColModInfo
expandFun = OccSpec -> AlignInfo -> ColModInfo
FillAligned OccSpec
oS
fixedFun :: Int -> AlignInfo -> ColModInfo
fixedFun Int
i = Int -> Maybe (OccSpec, AlignInfo) -> ColModInfo
FitTo Int
i (Maybe (OccSpec, AlignInfo) -> ColModInfo)
-> (AlignInfo -> Maybe (OccSpec, AlignInfo))
-> AlignInfo
-> ColModInfo
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (OccSpec, AlignInfo) -> Maybe (OccSpec, AlignInfo)
forall a. a -> Maybe a
Just ((OccSpec, AlignInfo) -> Maybe (OccSpec, AlignInfo))
-> (AlignInfo -> (OccSpec, AlignInfo))
-> AlignInfo
-> Maybe (OccSpec, AlignInfo)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (,) OccSpec
oS
measureMaximumWidth :: col a -> AlignInfo
measureMaximumWidth = (a -> AlignInfo) -> col a -> AlignInfo
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap ((a -> AlignInfo) -> col a -> AlignInfo)
-> (a -> AlignInfo) -> col a -> AlignInfo
forall a b. (a -> b) -> a -> b
$ OccSpec -> a -> AlignInfo
forall a. Cell a => OccSpec -> a -> AlignInfo
deriveAlignInfo OccSpec
oS
lengthFun :: AlignInfo -> Int
lengthFun = AlignInfo -> Int
widthAI
in (AlignInfo -> ColModInfo)
-> (Int -> AlignInfo -> ColModInfo)
-> (col a -> AlignInfo)
-> (AlignInfo -> Int)
-> col a
-> ColModInfo
forall a w (col :: * -> *).
(Cell a, Foldable col) =>
(w -> ColModInfo)
-> (Int -> w -> ColModInfo)
-> (col a -> w)
-> (w -> Int)
-> col a
-> ColModInfo
go AlignInfo -> ColModInfo
expandFun Int -> AlignInfo -> ColModInfo
fixedFun col a -> AlignInfo
measureMaximumWidth AlignInfo -> Int
lengthFun
where
go :: forall a w col. (Cell a, Foldable col)
=> (w -> ColModInfo)
-> (Int -> w -> ColModInfo)
-> (col a -> w)
-> (w -> Int)
-> col a
-> ColModInfo
go :: forall a w (col :: * -> *).
(Cell a, Foldable col) =>
(w -> ColModInfo)
-> (Int -> w -> ColModInfo)
-> (col a -> w)
-> (w -> Int)
-> col a
-> ColModInfo
go w -> ColModInfo
expandFun Int -> w -> ColModInfo
fixedFun col a -> w
measureMaximumWidth w -> Int
lengthFun =
let expandBetween' :: Int -> Int -> w -> ColModInfo
expandBetween' Int
i Int
j w
widthInfo | w -> Int
lengthFun w
widthInfo Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
j = Int -> w -> ColModInfo
fixedFun Int
j w
widthInfo
| w -> Int
lengthFun w
widthInfo Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
i = Int -> w -> ColModInfo
fixedFun Int
i w
widthInfo
| Bool
otherwise = w -> ColModInfo
expandFun w
widthInfo
expandUntil' :: (Bool -> Bool) -> Int -> w -> ColModInfo
expandUntil' Bool -> Bool
f Int
i w
widthInfo = if Bool -> Bool
f (w -> Int
lengthFun w
widthInfo Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
i)
then w -> ColModInfo
expandFun w
widthInfo
else Int -> w -> ColModInfo
fixedFun Int
i w
widthInfo
interpretLenSpec :: w -> ColModInfo
interpretLenSpec = case LenSpec
lenS of
LenSpec
Expand -> w -> ColModInfo
expandFun
Fixed Int
i -> Int -> w -> ColModInfo
fixedFun Int
i
ExpandUntil Int
i -> (Bool -> Bool) -> Int -> w -> ColModInfo
expandUntil' Bool -> Bool
forall a. a -> a
id Int
i
FixedUntil Int
i -> (Bool -> Bool) -> Int -> w -> ColModInfo
expandUntil' Bool -> Bool
not Int
i
ExpandBetween Int
i Int
j -> Int -> Int -> w -> ColModInfo
expandBetween' Int
i Int
j
in w -> ColModInfo
interpretLenSpec (w -> ColModInfo) -> (col a -> w) -> col a -> ColModInfo
forall b c a. (b -> c) -> (a -> b) -> a -> c
. col a -> w
measureMaximumWidth
deriveColModInfosFromColumnsLA :: (Foldable col, Cell a) => [(LenSpec, AlignSpec)] -> [col a] -> [ColModInfo]
deriveColModInfosFromColumnsLA :: forall (col :: * -> *) a.
(Foldable col, Cell a) =>
[(LenSpec, AlignSpec)] -> [col a] -> [ColModInfo]
deriveColModInfosFromColumnsLA [(LenSpec, AlignSpec)]
specs = ((col a -> ColModInfo) -> col a -> ColModInfo)
-> [col a -> ColModInfo] -> [col a] -> [ColModInfo]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith (col a -> ColModInfo) -> col a -> ColModInfo
forall a b. (a -> b) -> a -> b
($) (((LenSpec, AlignSpec) -> col a -> ColModInfo)
-> [(LenSpec, AlignSpec)] -> [col a -> ColModInfo]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (LenSpec, AlignSpec) -> col a -> ColModInfo
forall (col :: * -> *) a.
(Foldable col, Cell a) =>
(LenSpec, AlignSpec) -> col a -> ColModInfo
deriveColModInfoFromColumnLA [(LenSpec, AlignSpec)]
specs)
deriveColModInfosFromColumns :: (Foldable col, Cell a) => [ColSpec] -> [col a] -> [ColModInfo]
deriveColModInfosFromColumns :: forall (col :: * -> *) a.
(Foldable col, Cell a) =>
[ColSpec] -> [col a] -> [ColModInfo]
deriveColModInfosFromColumns = [(LenSpec, AlignSpec)] -> [col a] -> [ColModInfo]
forall (col :: * -> *) a.
(Foldable col, Cell a) =>
[(LenSpec, AlignSpec)] -> [col a] -> [ColModInfo]
deriveColModInfosFromColumnsLA ([(LenSpec, AlignSpec)] -> [col a] -> [ColModInfo])
-> ([ColSpec] -> [(LenSpec, AlignSpec)])
-> [ColSpec]
-> [col a]
-> [ColModInfo]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ColSpec] -> [(LenSpec, AlignSpec)]
unpackColSpecs
deriveColumnModifiers
:: (Cell a, StringBuilder b)
=> [ColSpec]
-> [Row a]
-> [a -> b]
deriveColumnModifiers :: forall a b.
(Cell a, StringBuilder b) =>
[ColSpec] -> [Row a] -> [a -> b]
deriveColumnModifiers [ColSpec]
specs [Row a]
tab =
((Position H, CutMark) -> ColModInfo -> a -> b)
-> [(Position H, CutMark)] -> [ColModInfo] -> [a -> b]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith ((Position H -> CutMark -> ColModInfo -> a -> b)
-> (Position H, CutMark) -> ColModInfo -> a -> b
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry Position H -> CutMark -> ColModInfo -> a -> b
forall a b.
(Cell a, StringBuilder b) =>
Position H -> CutMark -> ColModInfo -> a -> b
columnModifier) ((ColSpec -> (Position H, CutMark))
-> [ColSpec] -> [(Position H, CutMark)]
forall a b. (a -> b) -> [a] -> [b]
map (ColSpec -> Position H
position (ColSpec -> Position H)
-> (ColSpec -> CutMark) -> ColSpec -> (Position H, CutMark)
forall (a :: * -> * -> *) b c c'.
Arrow a =>
a b c -> a b c' -> a b (c, c')
&&& ColSpec -> CutMark
cutMark) [ColSpec]
specs) [ColModInfo]
cmis
where
cmis :: [ColModInfo]
cmis = [ColSpec] -> [Row a] -> [ColModInfo]
forall a. Cell a => [ColSpec] -> [Row a] -> [ColModInfo]
deriveColModInfosFromGrid [ColSpec]
specs [Row a]
tab