{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE RankNTypes #-}

-- | Printer types.
module HIndent.Printer
  ( Printer(..)
  , PrintState(..)
  , runPrinterStyle
  ) where

import Control.Applicative
import Control.Monad
import Control.Monad.State.Strict
import Data.ByteString.Builder
import Data.Int (Int64)
import HIndent.Config

-- | A pretty printing monad.
newtype Printer a = Printer
  { forall a. Printer a -> StateT PrintState Maybe a
runPrinter :: StateT PrintState Maybe a
  } deriving ( Functor Printer
Functor Printer =>
(forall a. a -> Printer a)
-> (forall a b. Printer (a -> b) -> Printer a -> Printer b)
-> (forall a b c.
    (a -> b -> c) -> Printer a -> Printer b -> Printer c)
-> (forall a b. Printer a -> Printer b -> Printer b)
-> (forall a b. Printer a -> Printer b -> Printer a)
-> Applicative Printer
forall a. a -> Printer a
forall a b. Printer a -> Printer b -> Printer a
forall a b. Printer a -> Printer b -> Printer b
forall a b. Printer (a -> b) -> Printer a -> Printer b
forall a b c. (a -> b -> c) -> Printer a -> Printer b -> Printer c
forall (f :: * -> *).
Functor f =>
(forall a. a -> f a)
-> (forall a b. f (a -> b) -> f a -> f b)
-> (forall a b c. (a -> b -> c) -> f a -> f b -> f c)
-> (forall a b. f a -> f b -> f b)
-> (forall a b. f a -> f b -> f a)
-> Applicative f
$cpure :: forall a. a -> Printer a
pure :: forall a. a -> Printer a
$c<*> :: forall a b. Printer (a -> b) -> Printer a -> Printer b
<*> :: forall a b. Printer (a -> b) -> Printer a -> Printer b
$cliftA2 :: forall a b c. (a -> b -> c) -> Printer a -> Printer b -> Printer c
liftA2 :: forall a b c. (a -> b -> c) -> Printer a -> Printer b -> Printer c
$c*> :: forall a b. Printer a -> Printer b -> Printer b
*> :: forall a b. Printer a -> Printer b -> Printer b
$c<* :: forall a b. Printer a -> Printer b -> Printer a
<* :: forall a b. Printer a -> Printer b -> Printer a
Applicative
             , Applicative Printer
Applicative Printer =>
(forall a b. Printer a -> (a -> Printer b) -> Printer b)
-> (forall a b. Printer a -> Printer b -> Printer b)
-> (forall a. a -> Printer a)
-> Monad Printer
forall a. a -> Printer a
forall a b. Printer a -> Printer b -> Printer b
forall a b. Printer a -> (a -> Printer b) -> Printer b
forall (m :: * -> *).
Applicative m =>
(forall a b. m a -> (a -> m b) -> m b)
-> (forall a b. m a -> m b -> m b)
-> (forall a. a -> m a)
-> Monad m
$c>>= :: forall a b. Printer a -> (a -> Printer b) -> Printer b
>>= :: forall a b. Printer a -> (a -> Printer b) -> Printer b
$c>> :: forall a b. Printer a -> Printer b -> Printer b
>> :: forall a b. Printer a -> Printer b -> Printer b
$creturn :: forall a. a -> Printer a
return :: forall a. a -> Printer a
Monad
             , (forall a b. (a -> b) -> Printer a -> Printer b)
-> (forall a b. a -> Printer b -> Printer a) -> Functor Printer
forall a b. a -> Printer b -> Printer a
forall a b. (a -> b) -> Printer a -> Printer b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
$cfmap :: forall a b. (a -> b) -> Printer a -> Printer b
fmap :: forall a b. (a -> b) -> Printer a -> Printer b
$c<$ :: forall a b. a -> Printer b -> Printer a
<$ :: forall a b. a -> Printer b -> Printer a
Functor
             , MonadState PrintState
             , Monad Printer
Alternative Printer
(Alternative Printer, Monad Printer) =>
(forall a. Printer a)
-> (forall a. Printer a -> Printer a -> Printer a)
-> MonadPlus Printer
forall a. Printer a
forall a. Printer a -> Printer a -> Printer a
forall (m :: * -> *).
(Alternative m, Monad m) =>
(forall a. m a) -> (forall a. m a -> m a -> m a) -> MonadPlus m
$cmzero :: forall a. Printer a
mzero :: forall a. Printer a
$cmplus :: forall a. Printer a -> Printer a -> Printer a
mplus :: forall a. Printer a -> Printer a -> Printer a
MonadPlus
             , Applicative Printer
Applicative Printer =>
(forall a. Printer a)
-> (forall a. Printer a -> Printer a -> Printer a)
-> (forall a. Printer a -> Printer [a])
-> (forall a. Printer a -> Printer [a])
-> Alternative Printer
forall a. Printer a
forall a. Printer a -> Printer [a]
forall a. Printer a -> Printer a -> Printer a
forall (f :: * -> *).
Applicative f =>
(forall a. f a)
-> (forall a. f a -> f a -> f a)
-> (forall a. f a -> f [a])
-> (forall a. f a -> f [a])
-> Alternative f
$cempty :: forall a. Printer a
empty :: forall a. Printer a
$c<|> :: forall a. Printer a -> Printer a -> Printer a
<|> :: forall a. Printer a -> Printer a -> Printer a
$csome :: forall a. Printer a -> Printer [a]
some :: forall a. Printer a -> Printer [a]
$cmany :: forall a. Printer a -> Printer [a]
many :: forall a. Printer a -> Printer [a]
Alternative
             )

-- | The state of the pretty printer.
data PrintState = PrintState
  { PrintState -> Int64
psIndentLevel :: !Int64
    -- ^ Current indentation level, i.e. every time there's a
    -- new-line, output this many spaces.
  , PrintState -> Builder
psOutput :: !Builder
    -- ^ The current output bytestring builder.
  , PrintState -> Bool
psNewline :: !Bool
    -- ^ Just outputted a newline?
  , PrintState -> Int64
psColumn :: !Int64
    -- ^ Current column.
  , PrintState -> Int64
psLine :: !Int64
    -- ^ Current line number.
  , PrintState -> Config
psConfig :: !Config
    -- ^ Configuration of max colums and indentation style.
  , PrintState -> Bool
psFitOnOneLine :: !Bool
    -- ^ Bail out if we need to print beyond the current line or
    -- the maximum column.
  , PrintState -> Bool
psEolComment :: !Bool
  }

-- | Pretty print the given printable thing.
runPrinterStyle :: Config -> Printer () -> Builder
runPrinterStyle :: Config -> Printer () -> Builder
runPrinterStyle Config
config Printer ()
m =
  Builder -> (PrintState -> Builder) -> Maybe PrintState -> Builder
forall b a. b -> (a -> b) -> Maybe a -> b
maybe ([Char] -> Builder
forall a. HasCallStack => [Char] -> a
error [Char]
"Printer failed with mzero call.") PrintState -> Builder
psOutput
    (Maybe PrintState -> Builder) -> Maybe PrintState -> Builder
forall a b. (a -> b) -> a -> b
$ StateT PrintState Maybe () -> PrintState -> Maybe PrintState
forall (m :: * -> *) s a. Monad m => StateT s m a -> s -> m s
execStateT (Printer () -> StateT PrintState Maybe ()
forall a. Printer a -> StateT PrintState Maybe a
runPrinter Printer ()
m) PrintState
initState
  where
    initState :: PrintState
initState =
      PrintState
        { psIndentLevel :: Int64
psIndentLevel = Int64
0
        , psOutput :: Builder
psOutput = Builder
forall a. Monoid a => a
mempty
        , psNewline :: Bool
psNewline = Bool
False
        , psColumn :: Int64
psColumn = Int64
0
        , psLine :: Int64
psLine = Int64
1
        , psConfig :: Config
psConfig = Config
config
        , psFitOnOneLine :: Bool
psFitOnOneLine = Bool
False
        , psEolComment :: Bool
psEolComment = Bool
False
        }