module HIndent.Combinators
(
write
, newline
, space
, comma
, int
, string
, maybeCtx
, inter
, spaced
, lined
, prefixedLined
, commas
, parens
, brackets
, braces
, indented
, column
, depend
, swing
, getIndentSpaces
, getColumnLimit
, nullBinds
, sandbox
, pretty'
)
where
import HIndent.Types
import Control.Monad.State hiding (state)
import Data.Int
import Data.List
import Data.Monoid
import qualified Data.Text as T
import qualified Data.Text.Lazy as LT
import Data.Text.Lazy.Builder (Builder)
import qualified Data.Text.Lazy.Builder as T
import Data.Text.Lazy.Builder.Int
import qualified Language.Haskell.Exts.Pretty as P
import Language.Haskell.Exts.Syntax
import Prelude hiding (exp)
indented :: Int64 -> Printer a -> Printer a
indented i p =
do level <- gets psIndentLevel
modify (\s -> s {psIndentLevel = level + i})
m <- p
modify (\s -> s {psIndentLevel = level})
return m
spaced :: [Printer ()] -> Printer ()
spaced = inter space
commas :: [Printer ()] -> Printer ()
commas = inter comma
inter :: Printer () -> [Printer ()] -> Printer ()
inter sep ps =
foldr (\(i,p) next ->
depend (do p
if i <
length ps
then sep
else return ())
next)
(return ())
(zip [1 ..] ps)
lined :: [Printer ()] -> Printer ()
lined ps = sequence_ (intersperse newline ps)
prefixedLined :: Char -> [Printer ()] -> Printer ()
prefixedLined pref ps' =
case ps' of
[] -> return ()
(p:ps) ->
do p
indented (1)
(mapM_ (\p' ->
do newline
depend (string [pref]) p')
ps)
column :: Int64 -> Printer a -> Printer a
column i p =
do level <- gets psIndentLevel
modify (\s -> s {psIndentLevel = i})
m <- p
modify (\s -> s {psIndentLevel = level})
return m
newline :: Printer ()
newline =
do write "\n"
modify (\s -> s {psNewline = True})
depend :: Printer () -> Printer b -> Printer b
depend maker dependent =
do state <- get
maker
st <- get
col <- gets psColumn
if state /= st
then column col dependent
else dependent
parens :: Printer a -> Printer a
parens p =
depend (write "(")
(do v <- p
write ")"
return v)
braces :: Printer a -> Printer a
braces p =
depend (write "{")
(do v <- p
write "}"
return v)
brackets :: Printer a -> Printer a
brackets p =
depend (write "[")
(do v <- p
write "]"
return v)
space :: Printer ()
space = write " "
comma :: Printer ()
comma = write ","
int :: Integral n => n -> Printer ()
int = write . decimal
write :: Builder -> Printer ()
write x =
do state <- get
let out =
if psNewline state
then T.fromText (T.replicate (fromIntegral (psIndentLevel state)) " ") <>
x
else x
out' = T.toLazyText out
modify (\s ->
s {psOutput = psOutput state <> out
,psNewline = False
,psLine = psLine state + additionalLines
,psColumn =
if additionalLines > 0
then LT.length (LT.concat (take 1 (reverse srclines)))
else psColumn state + LT.length out'})
where x' = T.toLazyText x
srclines = LT.lines x'
additionalLines =
LT.length (LT.filter (== '\n') x')
pretty' :: P.Pretty a => a -> Printer ()
pretty' = write . T.fromText . T.pack . P.prettyPrint
string :: String -> Printer ()
string = write . T.fromText . T.pack
getIndentSpaces :: Printer Int64
getIndentSpaces = gets (configIndentSpaces . psConfig)
getColumnLimit :: Printer Int64
getColumnLimit = gets (configMaxColumns . psConfig)
sandbox :: MonadState s m => m a -> m s
sandbox p =
do orig <- get
_ <- p
new <- get
put orig
return new
nullBinds :: Binds -> Bool
nullBinds (BDecls x) = null x
nullBinds (IPBinds x) = null x
maybeCtx :: Pretty a => [a] -> Printer ()
maybeCtx ctx =
unless (null ctx)
(do write "("
commas (map pretty ctx)
write ") => ")
swing :: Printer () -> Printer b -> Printer b
swing a b =
do orig <- gets psIndentLevel
a
newline
indentSpaces <- getIndentSpaces
column (orig + indentSpaces) b