generic-pretty-0.1.0: src/Text/PrettyPrint/Generic.hs
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedLists #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
-- | Pretty printing for Generic data types
module Text.PrettyPrint.Generic (
-- * Type classes
Pretty(..),
GPretty(..),
-- * Utility functions
pretty, prettyShow, prettyPrint, hPrettyPrint,
pretty', prettyShow', prettyPrint', hPrettyPrint',
) where
import GHC.Exts (IsList (..))
import GHC.Generics
import System.IO
import Text.PrettyPrint.ANSI.Leijen hiding (Pretty (..))
import Control.Applicative (Const, WrappedArrow,
WrappedMonad, ZipList)
import qualified Data.ByteString.Char8 as S
import qualified Data.ByteString.Lazy.Char8 as L
import Data.Complex
import Data.Functor.Identity (Identity)
import Data.Int
import qualified Data.IntMap as IntMap
import qualified Data.IntSet as IntSet
import qualified Data.Map as Map
import Data.Monoid (All, Alt, Any, First, Last,
Product, Sum)
import Data.Ratio
import qualified Data.Sequence as Seq
import qualified Data.Set as Set
import qualified Data.Text as T
import qualified Data.Text.Encoding as T
import qualified Data.Text.Lazy as TL
import qualified Data.Vector as V
import qualified Data.Vector.Primitive as VP
import qualified Data.Vector.Storable as VS
import qualified Data.Vector.Unboxed as VU
import Data.Word
-- Color scheme
constructorS, numericS, stringS, operatorS, selectorS :: Doc -> Doc
constructorS = underline . bold . dullgreen
numericS = magenta
stringS = dullyellow
operatorS = dullred
selectorS = blue
-- Generic function
-- | Type class for generic representations
class GPretty f where
-- | Pretty print a `Generic` value
gprettyPrec :: Int -> f a -> [Doc]
instance GPretty V1 where
gprettyPrec _ _ = error "this never happen"
instance GPretty U1 where
gprettyPrec _ U1 = []
instance Pretty c => GPretty (Rec0 c) where
gprettyPrec p (K1 c) = [prettyPrec p c]
instance GPretty f => GPretty (D1 d f) where
gprettyPrec p (M1 a) = gprettyPrec p a
instance (GPretty f, Constructor c) => GPretty (C1 c f) where
gprettyPrec p c@(M1 a)
| conIsRecord c =
[ con <+> encloseSep (lbrace <> space) (space <> rbrace) (comma <> space) es ]
| null es = [ con ]
| p == 0 = [ con <+> align (sep es) ]
| otherwise = [ parens $ con <+> align (sep es) ]
where
con = constructorS $ text (conName c)
es = gprettyPrec (p + 1) a
instance {-# OVERLAPPABLE #-} (GPretty f, Selector s) => GPretty (S1 s f) where
gprettyPrec _ s@(M1 a) =
[ selectorS (text (selName s)) <+> operatorS (text "=") <+> sep (gprettyPrec 0 a) ]
instance {-# OVERLAPPING #-} GPretty f => GPretty (S1 NoSelector f) where
gprettyPrec p (M1 a) = gprettyPrec p a
instance (GPretty f, GPretty g) => GPretty (f :+: g) where
gprettyPrec p (L1 a) = gprettyPrec p a
gprettyPrec p (R1 a) = gprettyPrec p a
instance (GPretty f, GPretty g) => GPretty (f :*: g) where
gprettyPrec p (a :*: b) = gprettyPrec p a ++ gprettyPrec p b
-- Wrapper function
-- | Type class for pretty printing
class Pretty a where
-- | Pretty print a value to `Doc`
prettyPrec :: Int -> a -> Doc
default prettyPrec :: (Generic a, GPretty (Rep a)) => Int -> a -> Doc
prettyPrec p = sep . gprettyPrec p . from
-- Utility functions
-- | Pretty print a value with decoration
pretty :: Pretty a => a -> Doc
pretty = prettyPrec 0
-- | Pretty print a value to `String`
prettyShow :: Pretty a => a -> String
prettyShow = show . pretty
-- | Pretty print a value to `stdout`
prettyPrint :: Pretty a => a -> IO ()
prettyPrint = hPrettyPrint stdout
-- | Pretty print a value
hPrettyPrint :: Pretty a => Handle -> a -> IO ()
hPrettyPrint h = hPutDoc h . (<> hardline) . pretty
-- | Pretty print a value without decoration
pretty' :: Pretty a => a -> Doc
pretty' = plain . pretty
-- | Plain version for `prettyShow`
prettyShow' :: Pretty a => a -> String
prettyShow' = show . pretty'
-- | Plain version for `prettyPrint`
prettyPrint' :: Pretty a => a -> IO ()
prettyPrint' = hPrettyPrint' stdout
-- | Plain version for `hPrettyPrint`
hPrettyPrint' :: Pretty a => Handle -> a -> IO ()
hPrettyPrint' h = hPutDoc h . (<> hardline) . pretty'
-- instances
instance Pretty () where prettyPrec _ = text . show
instance Pretty Char where prettyPrec _ = stringS . text . show
instance Pretty Int where prettyPrec _ = numericS . text . show
instance Pretty Integer where prettyPrec _ = numericS . text . show
instance Pretty Float where prettyPrec _ = numericS . text . show
instance Pretty Double where prettyPrec _ = numericS . text . show
instance Pretty Bool where prettyPrec _ = numericS . text . show
instance Pretty Word where prettyPrec _ = numericS . text . show
instance Pretty Word8 where prettyPrec _ = numericS . text . show
instance Pretty Word16 where prettyPrec _ = numericS . text . show
instance Pretty Word32 where prettyPrec _ = numericS . text . show
instance Pretty Word64 where prettyPrec _ = numericS . text . show
instance Pretty Int8 where prettyPrec _ = numericS . text . show
instance Pretty Int16 where prettyPrec _ = numericS . text . show
instance Pretty Int32 where prettyPrec _ = numericS . text . show
instance Pretty Int64 where prettyPrec _ = numericS . text . show
instance (Integral a, Pretty a) => Pretty (Ratio a) where
prettyPrec _ r =
pretty (numerator r) <+> operatorS (char '%') <+> pretty (denominator r)
instance (Pretty a) => Pretty (Complex a) where
prettyPrec _ (r :+ i) =
pretty r <+> operatorS (text ":+") <+> pretty i
instance {-# OVERLAPPABLE #-} Pretty a => Pretty [a] where
prettyPrec _ = encloseSep (lbracket <> space) (space <> rbracket) (comma <> space) . map pretty
instance {-# OVERLAPPING #-} Pretty String where
prettyPrec _ = stringS . dquotes . text . prettyString where
prettyString cs = foldr ((.) . prettyChar) id cs ""
prettyChar c
| fromEnum c < 0x80 = showChar c
| otherwise = (c:)
instance (Pretty a, Pretty b) => Pretty (a, b) where
prettyPrec _ (a, b) = parens $ pretty a <> comma <+> pretty b
instance (Pretty a, Pretty b, Pretty c) => Pretty (a, b, c) where
prettyPrec _ (a, b, c) = parens $ pretty a <> comma <+> pretty b <> comma <+> pretty c
instance (Pretty a, Pretty b, Pretty c, Pretty d) => Pretty (a, b, c, d) where
prettyPrec _ (a, b, c, d) = parens $ pretty a <> comma <+> pretty b <> comma <+> pretty c <> comma <+> pretty d
instance (Pretty a, Pretty b, Pretty c, Pretty d, Pretty e) => Pretty (a, b, c, d, e) where
prettyPrec _ (a, b, c, d, e) = parens $ pretty a <> comma <+> pretty b <> comma <+> pretty c <> comma <+> pretty d <> comma <+> pretty e
instance (Pretty a, Pretty b, Pretty c, Pretty d, Pretty e, Pretty f) => Pretty (a, b, c, d, e, f) where
prettyPrec _ (a, b, c, d, e, f) = parens $ pretty a <> comma <+> pretty b <> comma <+> pretty c <> comma <+> pretty d <> comma <+> pretty e <> comma <+> pretty f
instance (Pretty a, Pretty b, Pretty c, Pretty d, Pretty e, Pretty f, Pretty g) => Pretty (a, b, c, d, e, f, g) where
prettyPrec _ (a, b, c, d, e, f, g) = parens $ pretty a <> comma <+> pretty b <> comma <+> pretty c <> comma <+> pretty d <> comma <+> pretty e <> comma <+> pretty f <> comma <+> pretty g
instance Pretty a => Pretty (Maybe a)
instance (Pretty a, Pretty b) => Pretty (Either a b)
instance Pretty Ordering
instance Pretty Any
instance Pretty All
instance Pretty a => Pretty (First a)
instance Pretty a => Pretty (Last a)
instance Pretty a => Pretty (Sum a)
instance Pretty a => Pretty (Product a)
instance Pretty (f a) => Pretty (Alt f a)
instance Pretty a => Pretty (Identity a)
instance Pretty a => Pretty (Const a b)
instance Pretty a => Pretty (ZipList a)
instance Pretty (m a) => Pretty (WrappedMonad m a)
instance Pretty (a b c) => Pretty (WrappedArrow a b c)
-- bytestrings, texts
instance Pretty S.ByteString where
prettyPrec _ bs = case T.decodeUtf8' bs of
Left err -> pretty $ show err
Right t -> pretty t
instance Pretty T.Text where
prettyPrec _ = pretty . T.unpack
instance Pretty L.ByteString where
prettyPrec _ = pretty . L.toStrict
instance Pretty TL.Text where
prettyPrec _ = pretty . TL.toStrict
-- containers
instance (Pretty a, Ord a) => Pretty (Set.Set a) where
prettyPrec _ = encloseSep (lbracket <> space) (space <> rbracket) (comma <> space) . map pretty . toList
instance Pretty IntSet.IntSet where
prettyPrec _ = pretty . Set.fromList . toList
instance (Pretty a, Pretty b, Ord a) => Pretty (Map.Map a b) where
prettyPrec _ = encloseSep (lbrace <> space) (space <> rbrace) (comma <> space) . map f . toList where
f (key, val) = pretty key <> colon <+> pretty val
instance Pretty b => Pretty (IntMap.IntMap b) where
prettyPrec _ = pretty . Map.fromList . toList
instance Pretty a => Pretty (Seq.Seq a) where
prettyPrec _ = pretty . toList
-- vectors
instance Pretty a => Pretty (V.Vector a) where
prettyPrec _ = pretty . toList
instance (Pretty a, VP.Prim a) => Pretty (VP.Vector a) where
prettyPrec _ = pretty . toList
instance (Pretty a, VS.Storable a) => Pretty (VS.Vector a) where
prettyPrec _ = pretty . toList
instance (Pretty a, VU.Unbox a) => Pretty (VU.Vector a) where
prettyPrec _ = pretty . toList