packages feed

disco-0.1.0.0: src/Disco/Pretty/DSL.hs

-----------------------------------------------------------------------------
-- |
-- 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.
--
-----------------------------------------------------------------------------

{-# OPTIONS_GHC -fno-warn-orphans #-}

module Disco.Pretty.DSL where

import           Control.Applicative hiding (empty)
import           Data.String         (IsString (..))
import           Prelude             hiding ((<>))

import           Polysemy
import           Polysemy.Reader

import           Text.PrettyPrint    (Doc)
import qualified Text.PrettyPrint    as PP

import           Disco.Pretty.Prec

instance IsString (Sem r Doc) 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] -> f Doc
vcat ds  = PP.vcat <$> sequenceA ds

hcat :: Applicative f => [f Doc] -> f Doc
hcat ds  = PP.hcat <$> sequenceA ds

hsep :: Applicative f => [f Doc] -> f Doc
hsep ds  = PP.hsep <$> sequenceA ds

parens :: Functor f => f Doc -> f Doc
parens   = fmap PP.parens

brackets :: Functor f => f Doc -> f Doc
brackets = fmap PP.brackets

braces :: Functor f => f Doc -> f Doc
braces = fmap PP.braces

bag :: Applicative f => f Doc -> f Doc
bag p = text "⟅" <> p <> text "⟆"

quotes :: Functor f => f Doc -> f Doc
quotes = fmap PP.quotes

doubleQuotes :: Functor f => f Doc -> f Doc
doubleQuotes = fmap PP.doubleQuotes

text :: Applicative m => String -> m Doc
text     = pure . PP.text

integer :: Applicative m => Integer -> m Doc
integer  = pure . PP.integer

nest :: Functor f => Int -> f Doc -> f Doc
nest n d = PP.nest n <$> d

hang :: Applicative f => f Doc -> Int -> f Doc -> f Doc
hang d1 n d2 = PP.hang <$> d1 <*> pure n <*> d2

empty :: Applicative m => m Doc
empty    = pure PP.empty

(<+>) :: Applicative f => f Doc -> f Doc -> f Doc
(<+>) = liftA2 (PP.<+>)

(<>) :: Applicative f => f Doc -> f Doc -> f Doc
(<>)  = liftA2 (PP.<>)

($+$) :: Applicative f => f Doc -> f Doc -> f Doc
($+$) = liftA2 (PP.$+$)

punctuate :: Applicative f => f Doc -> [f Doc] -> f [f Doc]
punctuate p ds = map pure <$> (PP.punctuate <$> p <*> sequenceA ds)

intercalate :: Monad f => f Doc -> [f Doc] -> f Doc
intercalate p ds = do
  ds' <- punctuate p ds
  hsep ds'

bulletList :: Applicative f => f Doc -> [f Doc] -> f Doc
bulletList bullet = vcat . map (hang bullet 2)

------------------------------------------------------------
-- Running a pretty-printer

renderDoc :: Sem (Reader PA ': r) Doc -> Sem r String
renderDoc = fmap PP.render . runReader initPA

renderDoc' :: Doc -> String
renderDoc' = PP.render