{-# LANGUAGE NoImplicitPrelude #-} module Data.Aviation.Casa.AbbreviationsAndAcronyms.Render.Spacing( Spacing , HasSpacing(..) , nameHeader , meaningHeader , sourceHeader , scoreHeader , standardSpacing , mkSpacing , (<->) , exactWidthSpacing ) where import Control.Category((.), id) import Control.Lens(Lens', set, (^.)) import Data.Aviation.Casa.AbbreviationsAndAcronyms.Acronym(HasAcronym(name, meaning, source)) import Data.Aviation.Casa.AbbreviationsAndAcronyms.Render.Score(HasShowScore(showScore)) import Data.Eq(Eq) import Data.Foldable(length, foldMap) import Data.Function(($)) import Data.Functor(fmap) import Data.Int(Int) import Data.Monoid(Monoid(mappend, mempty)) import Data.Ord(Ord, max, min) import Data.Semigroup(Semigroup((<>))) import Data.String(String) import Prelude(Show) data Spacing = Spacing Int -- separator Int -- name Int -- meaning Int -- source Int -- score deriving (Eq, Ord, Show) mkSpacing :: Int -> Int -> Int -> Int -> Int -> Spacing mkSpacing sep n m s r = let b = max 1 in Spacing (b sep) (b n) (b m) (b s) (b r) instance Semigroup Spacing where Spacing a1 b1 c1 d1 e1 <> Spacing a2 b2 c2 d2 e2 = Spacing (a1 `max` a2) (b1 `max` b2) (c1 `max` c2) (d1 `max` d2) (e1 `max` e2) instance Monoid Spacing where mappend = (<>) mempty = mkSpacing 1 1 1 1 1 class HasSpacing a where spacing :: Lens' a Spacing separatorSpacing :: Lens' a Int {-# INLINE separatorSpacing #-} separatorSpacing = spacing . separatorSpacing nameSpacing :: Lens' a Int {-# INLINE nameSpacing #-} nameSpacing = spacing . nameSpacing meaningSpacing :: Lens' a Int {-# INLINE meaningSpacing #-} meaningSpacing = spacing . meaningSpacing sourceSpacing :: Lens' a Int {-# INLINE sourceSpacing #-} sourceSpacing = spacing . sourceSpacing scoreSpacing :: Lens' a Int {-# INLINE scoreSpacing #-} scoreSpacing = spacing . scoreSpacing instance HasSpacing Spacing where spacing = id separatorSpacing f (Spacing a b c d e) = fmap (\x -> mkSpacing x b c d e) (f a) nameSpacing f (Spacing a b c d e) = fmap (\x -> mkSpacing a x c d e) (f b) meaningSpacing f (Spacing a b c d e) = fmap (\x -> mkSpacing a b x d e) (f c) sourceSpacing f (Spacing a b c d e) = fmap (\x -> mkSpacing a b c x e) (f d) scoreSpacing f (Spacing a b c d e) = fmap (\x -> mkSpacing a b c d x) (f e) nameHeader :: String nameHeader = "NAME" meaningHeader :: String meaningHeader = "MEANING" sourceHeader :: String sourceHeader = "SOURCE" scoreHeader :: String scoreHeader = "SCORE" standardSpacing :: Spacing standardSpacing = Spacing 1 (length nameHeader) (length meaningHeader) (length sourceHeader) (length scoreHeader) exactWidthSpacing :: (HasShowScore a, HasAcronym a) => [a] -> Spacing exactWidthSpacing x = standardSpacing <> foldMap ( \a -> set nameSpacing (length (a ^. name)) . set meaningSpacing (length (a ^. meaning)) . set sourceSpacing (length (a ^. source)) . set scoreSpacing (length (a ^. showScore)) $ mempty ) x (<->) :: Spacing -> Spacing -> Spacing Spacing a1 b1 c1 d1 e1 <-> Spacing a2 b2 c2 d2 e2 = Spacing (a1 `min` a2) (b1 `min` b2) (c1 `min` c2) (d1 `min` d2) (e1 `min` e2)