-- | Printer combinators related to indent.
module HIndent.Pretty.Combinators.Indent
  ( indentedBlock
  , indentedWithSpace
  , (|=>)
  , indentedWithFixedLevel
  , prefixed
  , getIndentSpaces
  ) where

import Control.Monad.State
import Data.Int
import HIndent.Config
import HIndent.Pretty.Combinators.String
import HIndent.Printer

-- | This function runs the given printer with an additional indent. The
-- indent has 'configIndentSpaces' spaces.
indentedBlock :: Printer a -> Printer a
indentedBlock :: forall a. Printer a -> Printer a
indentedBlock Printer a
p = do
  Int64
indentSpaces <- Printer Int64
getIndentSpaces
  Int64 -> Printer a -> Printer a
forall a. Int64 -> Printer a -> Printer a
indentedWithSpace Int64
indentSpaces Printer a
p

-- | This function runs the given printer with an additional indent. The
-- indent has the specified number of spaces.
indentedWithSpace :: Int64 -> Printer a -> Printer a
indentedWithSpace :: forall a. Int64 -> Printer a -> Printer a
indentedWithSpace Int64
i Printer a
p = do
  Int64
level <- (PrintState -> Int64) -> Printer Int64
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets PrintState -> Int64
psIndentLevel
  Int64 -> Printer a -> Printer a
forall a. Int64 -> Printer a -> Printer a
indentedWithFixedLevel (Int64
level Int64 -> Int64 -> Int64
forall a. Num a => a -> a -> a
+ Int64
i) Printer a
p

-- | This function runs the first printer, fixes the indent, and then runs
-- the second one.
--
-- For example,
--
-- > string "foo " |=> lined [string "bar", "baz"]
--
-- will print texts as below.
-- foo bar
--     baz
(|=>) :: Printer () -> Printer a -> Printer a
Printer ()
hd |=> :: forall a. Printer () -> Printer a -> Printer a
|=> Printer a
p = do
  Printer ()
hd
  Int64
col <- (PrintState -> Int64) -> Printer Int64
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets PrintState -> Int64
psColumn
  Int64 -> Printer a -> Printer a
forall a. Int64 -> Printer a -> Printer a
indentedWithFixedLevel Int64
col Printer a
p

infixl 1 |=>
-- | This function runs the given printer with the passed indent level.
indentedWithFixedLevel :: Int64 -> Printer a -> Printer a
indentedWithFixedLevel :: forall a. Int64 -> Printer a -> Printer a
indentedWithFixedLevel Int64
i Printer a
p = do
  Int64
l <- (PrintState -> Int64) -> Printer Int64
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets PrintState -> Int64
psIndentLevel
  (PrintState -> PrintState) -> Printer ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (\PrintState
s -> PrintState
s {psIndentLevel = i})
  a
m <- Printer a
p
  (PrintState -> PrintState) -> Printer ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (\PrintState
s -> PrintState
s {psIndentLevel = l})
  a -> Printer a
forall a. a -> Printer a
forall (m :: * -> *) a. Monad m => a -> m a
return a
m

-- | Prints the text passed as the first argument before the current
-- position and then the second argument.
prefixed :: String -> Printer () -> Printer ()
prefixed :: String -> Printer () -> Printer ()
prefixed String
s Printer ()
p = do
  Int64 -> Printer () -> Printer ()
forall a. Int64 -> Printer a -> Printer a
indentedWithSpace (-(Int -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Int64) -> Int -> Int64
forall a b. (a -> b) -> a -> b
$ String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
s)) (Printer () -> Printer ()) -> Printer () -> Printer ()
forall a b. (a -> b) -> a -> b
$ HasCallStack => String -> Printer ()
String -> Printer ()
string String
s
  Printer ()
p

-- | This function returns the current indent level.
getIndentSpaces :: Printer Int64
getIndentSpaces :: Printer Int64
getIndentSpaces = (PrintState -> Int64) -> Printer Int64
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets (Config -> Int64
configIndentSpaces (Config -> Int64) -> (PrintState -> Config) -> PrintState -> Int64
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PrintState -> Config
psConfig)