{-# LANGUAGE CPP #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Floskell.Types
( OutputRestriction(..)
, TypeLayout(..)
, Penalty(..)
, TabStop(..)
, Printer(..)
, execPrinter
, runPrinter
, PrintState(..)
, psLine
, psColumn
, psNewline
, initialPrintState
, Config(..)
, SrcSpan(..)
, CommentType(..)
, Comment(..)
, NodeInfo(..)
, noNodeInfo
, nodeSpan
, Location(..)
) where
import Control.Applicative
import Control.Monad
import Control.Monad.Search
( MonadSearch, Search, runSearchBest )
import Control.Monad.State.Strict
( MonadState(..), StateT, execStateT, runStateT )
import qualified Data.Map.Strict as Map
import Data.Semigroup as Sem
import Floskell.Buffer ( Buffer )
import qualified Floskell.Buffer as Buffer
import Floskell.Config ( Config(..), Location(..) )
import Language.Haskell.Exts.SrcLoc ( SrcSpan(..), mkSrcSpan, noLoc )
import Language.Haskell.Exts.Syntax ( Annotated(..) )
data OutputRestriction = Anything | NoOverflow | NoOverflowOrLinebreak
deriving ( Eq, Ord, Show )
data TypeLayout = TypeFree | TypeFlex | TypeVertical
deriving ( Eq, Ord, Show )
newtype Penalty = Penalty Int
deriving ( Eq, Ord, Num, Show )
newtype TabStop = TabStop String
deriving ( Eq, Ord, Show )
instance Sem.Semigroup Penalty where
(<>) = (+)
instance Monoid Penalty where
mempty = 0
#if !(MIN_VERSION_base(4,11,0))
mappend = (<>)
#endif
newtype Printer a =
Printer { unPrinter :: StateT PrintState (Search Penalty) a }
deriving ( Applicative, Monad, Functor, MonadState PrintState
, MonadSearch Penalty, MonadPlus, Alternative )
execPrinter :: Printer a -> PrintState -> Maybe (Penalty, PrintState)
execPrinter m s = runSearchBest $ execStateT (unPrinter m) s
runPrinter :: Printer a -> PrintState -> Maybe (Penalty, (a, PrintState))
runPrinter m s = runSearchBest $ runStateT (unPrinter m) s
data PrintState =
PrintState { psBuffer :: !Buffer
, psIndentLevel :: !Int
, psOnside :: !Int
, psTabStops :: !(Map.Map TabStop Int)
, psConfig :: !Config
, psEolComment :: !Bool
, psOutputRestriction :: !OutputRestriction
, psTypeLayout :: !TypeLayout
}
psLine :: PrintState -> Int
psLine = Buffer.line . psBuffer
psColumn :: PrintState -> Int
psColumn = Buffer.column . psBuffer
psNewline :: PrintState -> Bool
psNewline = (== 0) . Buffer.column . psBuffer
initialPrintState :: Config -> PrintState
initialPrintState config =
PrintState Buffer.empty 0 0 Map.empty config False Anything TypeFree
data CommentType = InlineComment | LineComment | PreprocessorDirective
deriving ( Show )
data Comment = Comment { commentType :: !CommentType
, commentSpan :: !SrcSpan
, commentText :: !String
}
deriving ( Show )
data NodeInfo =
NodeInfo { nodeInfoSpan :: !SrcSpan
, nodeInfoLeadingComments :: ![Comment]
, nodeInfoTrailingComments :: ![Comment]
}
deriving ( Show )
noNodeInfo :: NodeInfo
noNodeInfo = NodeInfo (mkSrcSpan noLoc noLoc) [] []
nodeSpan :: Annotated ast => ast NodeInfo -> SrcSpan
nodeSpan = nodeInfoSpan . ann