{-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE AllowAmbiguousTypes #-} module Prologue.Text.Show.Styled where import Prelude hiding (Monoid) import qualified Data.Text.IO as Text import qualified Text.Show.Pretty as Formatted import qualified Text.PrettyPrint as Formatted import Control.Monad.IO.Class (MonadIO, liftIO) import Data.Text (Text) import Data.Convert import Data.Monoids (Monoid, intercalate) import Data.String (IsString) -- TODO -- We should replace Text with some TextBuilder + Cache, which will -- automatically replace Text.Builders with new one after Text chunks -- concatenation. ------------------- -- === Class === -- ------------------- -- === Definition === -- type family StyledShowOutput style class StyledShow style a where styledShow :: style -> a -> StyledShowOutput style class StyledShow1 style a where styledShow1 :: ∀ t1. style -> a t1 -> StyledShowOutput style class StyledShow2 style a where styledShow2 :: ∀ t1 t2. style -> a t1 t2 -> StyledShowOutput style -- === Redirect instances === -- instance {-# OVERLAPPABLE #-} StyledShow1 style a => StyledShow style (a t) where styledShow = styledShow1 ; {-# INLINE styledShow #-} instance {-# OVERLAPPABLE #-} StyledShow2 style a => StyledShow1 style (a t) where styledShow1 = styledShow2 ; {-# INLINE styledShow1 #-} -------------------------------- -- === Monadic StyledShow === -- -------------------------------- -- === Definition === -- class StyledShowM style a m where styledShowM :: style -> a -> m (StyledShowOutput style) class StyledShowM1 style a m where styledShowM1 :: ∀ t1. style -> a t1 -> m (StyledShowOutput style) class StyledShowM2 style a m where styledShowM2 :: ∀ t1 t2. style -> a t1 t2 -> m (StyledShowOutput style) -- === Redirect instances === -- instance {-# OVERLAPPABLE #-} StyledShowM1 style a m => StyledShowM style (a t) m where styledShowM = styledShowM1 ; {-# INLINE styledShowM #-} instance {-# OVERLAPPABLE #-} StyledShowM2 style a m => StyledShowM1 style (a t) m where styledShowM1 = styledShowM2 ; {-# INLINE styledShowM1 #-} ----------------------- -- === Formatted === -- ----------------------- -- TODO -- We should change the whole printing API to use Text instead format__ :: Text -> Text format__ txt = convert . show $ case Formatted.parseValue s of Just v -> Formatted.valToDoc v Nothing -> Formatted.text s where s = convert txt {-# INLINE format__ #-} putLnFmtd :: MonadIO m => Text -> m () putLnFmtd = liftIO . Text.putStrLn . format__ ----------------------------- -- === StructShowStyle === -- ----------------------------- -- === Definition === -- data StructShowStyle = StructShowStyle deriving (Show) type instance StyledShowOutput StructShowStyle = Text type StructShow = StyledShow StructShowStyle type StructShow1 = StyledShow1 StructShowStyle type StructShow2 = StyledShow2 StructShowStyle type StructShowM = StyledShowM StructShowStyle type StructShowM1 = StyledShowM1 StructShowStyle type StructShowM2 = StyledShowM2 StructShowStyle -- TODO -- We should rename all 'structShowX' functions to just 'showX' and replace all -- usages of 'show' with it, because using Strings is not good here. structShow :: StructShow a => a -> Text structShow1 :: StructShow1 a => a t1 -> Text structShow2 :: StructShow2 a => a t1 t2 -> Text structShow = styledShow StructShowStyle ; {-# INLINE structShow #-} structShow1 = styledShow1 StructShowStyle ; {-# INLINE structShow1 #-} structShow2 = styledShow2 StructShowStyle ; {-# INLINE structShow2 #-} showM :: StructShowM a m => a -> m Text showM1 :: StructShowM1 a m => a t1 -> m Text showM2 :: StructShowM2 a m => a t1 t2 -> m Text showM = styledShowM StructShowStyle ; {-# INLINE showM #-} showM1 = styledShowM1 StructShowStyle ; {-# INLINE showM1 #-} showM2 = styledShowM2 StructShowStyle ; {-# INLINE showM2 #-} -- === Instances === -- instance ( out ~ StyledShowOutput style , Monad m , Monoid out , IsString out , StyledShowM style a m ) => StyledShowM style [a] m where styledShowM style a = lstfmt <$> mapM (styledShowM style) a where lstfmt = braced . intercalate "," braced = \a -> "[" <> a <> "]" ----------------------------- -- === PrettyShowStyle === -- ----------------------------- -- === Definition === -- data PrettyShowStyle = PrettyShowStyle deriving (Show) type instance StyledShowOutput PrettyShowStyle = Text type PrettyShow = StyledShow PrettyShowStyle type PrettyShow1 = StyledShow1 PrettyShowStyle type PrettyShow2 = StyledShow2 PrettyShowStyle type PrettyShowM = StyledShowM PrettyShowStyle type PrettyShowM1 = StyledShowM1 PrettyShowStyle type PrettyShowM2 = StyledShowM2 PrettyShowStyle prettyShow :: PrettyShow a => a -> Text prettyShow1 :: PrettyShow1 a => a t1 -> Text prettyShow2 :: PrettyShow2 a => a t1 t2 -> Text prettyShow = styledShow PrettyShowStyle ; {-# INLINE prettyShow #-} prettyShow1 = styledShow1 PrettyShowStyle ; {-# INLINE prettyShow1 #-} prettyShow2 = styledShow2 PrettyShowStyle ; {-# INLINE prettyShow2 #-} prettyShowM :: PrettyShow a => a -> Text prettyShowM1 :: PrettyShow1 a => a t1 -> Text prettyShowM2 :: PrettyShow2 a => a t1 t2 -> Text prettyShowM = styledShow PrettyShowStyle ; {-# INLINE prettyShowM #-} prettyShowM1 = styledShow1 PrettyShowStyle ; {-# INLINE prettyShowM1 #-} prettyShowM2 = styledShow2 PrettyShowStyle ; {-# INLINE prettyShowM2 #-}