disco-0.1.6: src/Disco/Pretty/DSL.hs
{-# OPTIONS_GHC -fno-warn-orphans #-}
-- |
-- Module : Disco.Pretty.DSL
-- Copyright : disco team and contributors
-- Maintainer : byorgey@gmail.com
--
-- SPDX-License-Identifier: BSD-3-Clause
--
-- Adapter DSL on top of Text.PrettyPrint for Applicative pretty-printing.
module Disco.Pretty.DSL where
import Control.Applicative hiding (empty)
import Data.String (IsString (..))
import Disco.Pretty.Prec
import Polysemy
import Polysemy.Reader
import Prettyprinter (Doc)
import qualified Prettyprinter as PP
import Prettyprinter.Internal (Doc (Empty)) -- XXX comment me
import Prettyprinter.Render.String (renderString)
import Prelude hiding ((<>))
instance IsString (Sem r (Doc ann)) where
fromString = text
------------------------------------------------------------
-- Adapter DSL
--
-- Each combinator here mirrors one from Text.PrettyPrint, but
-- operates over a generic functor/monad.
vcat :: Applicative f => [f (Doc ann)] -> f (Doc ann)
vcat ds = PP.vcat <$> sequenceA ds
hcat :: Applicative f => [f (Doc ann)] -> f (Doc ann)
hcat ds = PP.hcat <$> sequenceA ds
hsep :: Applicative f => [f (Doc ann)] -> f (Doc ann)
hsep ds = PP.hsep <$> sequenceA ds
parens :: Functor f => f (Doc ann) -> f (Doc ann)
parens = fmap PP.parens
brackets :: Functor f => f (Doc ann) -> f (Doc ann)
brackets = fmap PP.brackets
braces :: Functor f => f (Doc ann) -> f (Doc ann)
braces = fmap PP.braces
bag :: Applicative f => f (Doc ann) -> f (Doc ann)
bag p = text "⟅" <> p <> text "⟆"
quotes :: Functor f => f (Doc ann) -> f (Doc ann)
quotes = fmap PP.squotes
doubleQuotes :: Functor f => f (Doc ann) -> f (Doc ann)
doubleQuotes = fmap PP.dquotes
text :: Applicative m => String -> m (Doc ann)
text = pure . fromString
integer :: Applicative m => Integer -> m (Doc ann)
integer = pure . PP.pretty
nest :: Functor f => Int -> f (Doc ann) -> f (Doc ann)
nest n d = PP.nest n <$> d
indent :: Functor f => Int -> f (Doc ann) -> f (Doc ann)
indent n d = PP.indent n <$> d
hang :: Applicative f => f (Doc ann) -> Int -> f (Doc ann) -> f (Doc ann)
hang d1 n d2 = d1 <+> nest n d2
empty :: Applicative m => m (Doc ann)
empty = pure PP.emptyDoc
(<+>) :: Applicative f => f (Doc ann) -> f (Doc ann) -> f (Doc ann)
(<+>) = liftA2 (PP.<+>)
(<>) :: Applicative f => f (Doc ann) -> f (Doc ann) -> f (Doc ann)
(<>) = liftA2 (PP.<>)
($+$) :: Applicative f => f (Doc ann) -> f (Doc ann) -> f (Doc ann)
d1 $+$ d2 = f <$> d1 <*> d2
where
f x1 Empty = x1
f x1 x2 = PP.vcat [x1, x2]
punctuate :: Applicative f => f (Doc ann) -> [f (Doc ann)] -> f [f (Doc ann)]
punctuate p ds = map pure <$> (PP.punctuate <$> p <*> sequenceA ds)
intercalate :: Monad f => f (Doc ann) -> [f (Doc ann)] -> f (Doc ann)
intercalate p ds = do
ds' <- punctuate p ds
hsep ds'
bulletList :: Applicative f => f (Doc ann) -> [f (Doc ann)] -> f (Doc ann)
bulletList bullet = vcat . map (hang bullet 2)
------------------------------------------------------------
-- Running a pretty-printer
renderDoc :: Sem (Reader PA ': r) (Doc ann) -> Sem r String
renderDoc = fmap renderDoc' . runReader initPA
renderDoc' :: Doc ann -> String
renderDoc' = renderString . PP.layoutPretty PP.defaultLayoutOptions