-- | 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 p = do
  indentSpaces <- getIndentSpaces
  indentedWithSpace indentSpaces 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 i p = do
  level <- gets psIndentLevel
  indentedWithFixedLevel (level + i) 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
hd |=> p = do
  hd
  col <- gets psColumn
  indentedWithFixedLevel col p

infixl 1 |=>

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

-- | Prints the text passed as the first argument before the current
-- position and then the second argument.
prefixed :: String -> Printer () -> Printer ()
prefixed s p = do
  indentedWithSpace (-(fromIntegral $ length s)) $ string s
  p

-- | This function returns the current indent level.
getIndentSpaces :: Printer Int64
getIndentSpaces = gets (configIndentSpaces . psConfig)
