packages feed

calligraphy-0.1.2: src/Calligraphy/Util/Printer.hs

{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}

module Calligraphy.Util.Printer where

import Control.Monad.RWS
import Control.Monad.State
import Data.Foldable
import Data.Text (Text)
import qualified Data.Text.Lazy as TL
import Data.Text.Lazy.Builder (Builder)
import qualified Data.Text.Lazy.Builder as TB

newtype Printer a = Printer {unPrinter :: RWS Int () Builder a}
  deriving newtype (Functor, Applicative, Monad)
  deriving (Semigroup, Monoid) via (Ap Printer a)

type Prints a = a -> Printer ()

runPrinter :: Printer () -> Text
runPrinter (Printer p) = TL.toStrict . TB.toLazyText . fst $ execRWS p 0 mempty

class Monad m => MonadPrint m where
  line :: Builder -> m ()
  indent :: m a -> m a

instance MonadPrint Printer where
  {-# INLINE indent #-}
  indent (Printer p) = Printer $ local (+ 4) p

  {-# INLINE line #-}
  line t = Printer $ do
    n <- ask
    modify $
      flip mappend $ fold (replicate n (TB.singleton ' ')) <> t <> TB.singleton '\n'

instance MonadPrint m => MonadPrint (StateT s m) where
  line = lift . line
  indent (StateT m) = StateT $ indent . m

{-# INLINE brack #-}
brack :: MonadPrint m => String -> String -> m a -> m a
brack pre post inner = strLn pre *> indent inner <* strLn post

{-# INLINE strLn #-}
strLn :: MonadPrint m => String -> m ()
strLn = line . TB.fromString

{-# INLINE textLn #-}
textLn :: MonadPrint m => Text -> m ()
textLn = line . TB.fromText

{-# INLINE showLn #-}
showLn :: (MonadPrint m, Show a) => a -> m ()
showLn = strLn . show