sr-extra-1.64: Extra/Pretty.hs
-- | A constructor we can wrap around values to avoid any built in
-- Pretty instance - for example, instance Pretty [a].
--
-- * display is now prettyShow
-- * display' is now prettyText
-- * ppDisplay is now ppShow
-- * ppDisplay' is now ppText
{-# LANGUAGE DeriveFunctor, FlexibleContexts, FlexibleInstances, OverloadedStrings, TypeSynonymInstances #-}
module Extra.Pretty
( PP(PP, unPP)
, prettyText
, ppPrint
, pprPair
, pprSet
, ppShow
, ppText
, pprint1, pprint1', render1
, pprintW
, friendlyNames
-- * Re-export
, prettyShow
, renderW
) where
import Data.Data (Data)
import Data.Generics (everywhere, mkT)
import Data.Set as Set (Set, toList)
import Data.Text (Text, unpack, pack)
import Distribution.Pretty (Pretty(pretty), prettyShow)
import Language.Haskell.TH
import Language.Haskell.TH.PprLib as TH (Doc, hcat, hsep, ptext, to_HPJ_Doc)
import Language.Haskell.TH.Syntax
import qualified Text.PrettyPrint as HPJ
import Text.PrettyPrint.HughesPJClass as HPJ (Doc, text, empty)
-- | This type is wrapped around values before we pretty print them so
-- we can write our own Pretty instances for common types without
-- polluting the name space of clients of this package with instances
-- they don't want.
newtype PP a = PP {unPP :: a} deriving (Functor)
instance Pretty (PP Text) where
pretty = text . unpack . unPP
instance Pretty (PP String) where
pretty = text . unPP
instance Pretty (PP a) => Pretty (PP (Maybe a)) where
pretty = maybe empty ppPrint . unPP
prettyText :: Pretty a => a -> Text
prettyText = pack . prettyShow
ppPrint :: Pretty (PP a) => a -> HPJ.Doc
ppPrint = pretty . PP
ppShow :: Pretty (PP a) => a -> String
ppShow = prettyShow . PP
ppText :: Pretty (PP a) => a -> Text
ppText = pack . prettyShow . PP
-- | Make a template haskell value more human reader friendly. The
-- result may or may not be compilable. That's ok, though, because
-- the input is usually uncompilable - it imports hidden modules, uses
-- infix operators in invalid positions, puts module qualifiers in
-- places where they are not allowed, and maybe other things.
friendlyNames :: Data a => a -> a
friendlyNames =
everywhere (mkT friendlyName)
where
friendlyName (Name x _) = Name x NameS -- Remove all module qualifiers
-- | Render a 'Doc' on a single line.
render1 :: TH.Doc -> String
render1 = HPJ.renderStyle (HPJ.style {HPJ.mode = HPJ.OneLineMode}) . to_HPJ_Doc
-- | Render a 'Doc' with the given width.
renderW :: Int -> TH.Doc -> String
renderW w = HPJ.renderStyle (HPJ.style {HPJ.lineLength = w}) . to_HPJ_Doc
-- | Pretty print the result of 'render1'.
pprint1' :: Ppr a => a -> [Char]
pprint1' = render1 . ppr
-- | 'pprint1'' with friendlyNames.
pprint1 :: (Ppr a, Data a) => a -> [Char]
pprint1 = pprint1' . friendlyNames
-- | Pretty print the result of 'renderW'.
pprintW' :: Ppr a => Int -> a -> [Char]
pprintW' w = renderW w . ppr
-- | 'pprintW'' with friendly names.
pprintW :: (Ppr a, Data a) => Int -> a -> [Char]
pprintW w = pprintW' w . friendlyNames
pprPair :: (Ppr a, Ppr b) => (a, b) -> TH.Doc
pprPair (a, b) = hcat [ptext "(", ppr a, ptext ", ", ppr b, ptext ")"]
pprSet :: Ppr a => Set a -> TH.Doc
pprSet s = hcat [ptext "[", hsep (fmap ppr (Set.toList s)), ptext "]"]