module Language.Haskell.Formatter.Location
(SrcLoc.SrcLoc, SrcLoc.SrcSpan, SrcLoc.SrcSpanInfo, base, plus, minus,
Portioned(..), Line, Column, streamName, getLine, getColumn,
createPosition, SrcLoc.getPointLoc, getEndPosition,
replaceNestedPortionLines, stringPortion, getStartLine, getStartColumn,
getEndLine, getEndColumn)
where
import qualified Data.Function as Function
import qualified Language.Haskell.Exts.Comments as Comments
import qualified Language.Haskell.Exts.SrcLoc as SrcLoc
import qualified Language.Haskell.Exts.Syntax as Syntax
import qualified Language.Haskell.Formatter.Internal.Newline as Newline
import qualified Language.Haskell.Formatter.Toolkit.ListTool as ListTool
import qualified Language.Haskell.Formatter.Toolkit.StreamName as StreamName
import Prelude hiding (getLine)
class Enum a => Natural a where
base :: a
plus :: Integral b => b -> a -> a
plus difference natural
= toEnum $ fromIntegral difference + fromEnum natural
minus :: Num b => a -> a -> b
minus minuend = fromIntegral . Function.on (-) fromEnum minuend
class Portioned a where
getPortion :: a -> SrcLoc.SrcSpan
newtype Line = Line Int
deriving (Eq, Ord, Show)
newtype Column = Column Int
deriving (Eq, Ord, Show)
instance Enum Line where
toEnum = Line
fromEnum (Line line) = line
instance Enum Column where
toEnum = Column
fromEnum (Column column) = column
instance Natural Line where
base = Line 1
instance Natural Column where
base = Column 1
instance Portioned SrcLoc.SrcSpanInfo where
getPortion = SrcLoc.srcInfoSpan
instance Portioned a => Portioned (Syntax.Module a) where
getPortion = getPortion . Syntax.ann
instance Portioned Comments.Comment where
getPortion (Comments.Comment _ commentPortion _) = commentPortion
streamName :: SrcLoc.SrcInfo a => a -> StreamName.StreamName
streamName = StreamName.createStreamName . SrcLoc.fileName
getLine :: SrcLoc.SrcLoc -> Line
getLine = Line . SrcLoc.srcLine
getColumn :: SrcLoc.SrcLoc -> Column
getColumn = Column . SrcLoc.srcColumn
createPosition :: StreamName.StreamName -> Line -> Column -> SrcLoc.SrcLoc
createPosition stream (Line line) (Column column)
= SrcLoc.SrcLoc{SrcLoc.srcFilename = show stream, SrcLoc.srcLine = line,
SrcLoc.srcColumn = column}
getEndPosition :: SrcLoc.SrcSpan -> SrcLoc.SrcLoc
getEndPosition portion = createPosition stream line column
where stream = streamName portion
line = Line $ SrcLoc.srcSpanEndLine portion
column = Column $ SrcLoc.srcSpanEndColumn portion
replaceNestedPortionLines ::
(Line -> Line) ->
SrcLoc.SrcSpanInfo -> SrcLoc.SrcSpanInfo
replaceNestedPortionLines function nestedPortion
= nestedPortion{SrcLoc.srcInfoSpan = parent',
SrcLoc.srcInfoPoints = children'}
where parent' = replace parent
replace = replacePortionLines function
parent = SrcLoc.srcInfoSpan nestedPortion
children' = fmap replace children
children = SrcLoc.srcInfoPoints nestedPortion
replacePortionLines :: (Line -> Line) -> SrcLoc.SrcSpan -> SrcLoc.SrcSpan
replacePortionLines function portion
= portion{SrcLoc.srcSpanStartLine = start, SrcLoc.srcSpanEndLine = end}
where Line start = function $ getStartLine portion
Line end = function $ getEndLine portion
stringPortion :: SrcLoc.SrcLoc -> String -> SrcLoc.SrcSpan
stringPortion startPosition string = SrcLoc.mkSrcSpan startPosition endPosition
where endPosition = createPosition stream endLine endColumn
stream = streamName startPosition
endLine = lastIndex lineCount startLine
lastIndex difference = pred . plus difference
lineCount = length stringLines
stringLines = Newline.splitSeparatedLines string
startLine = getStartLine startPosition
endColumn = lastIndex lastLineLength lastLineStartColumn
lastLineLength = maybe 0 length $ ListTool.maybeLast stringLines
lastLineStartColumn = if hasSingleLine then startColumn else base
hasSingleLine = lineCount == 1
startColumn = getStartColumn startPosition
getStartLine :: SrcLoc.SrcInfo a => a -> Line
getStartLine = getLine . SrcLoc.getPointLoc
getStartColumn :: SrcLoc.SrcInfo a => a -> Column
getStartColumn = getColumn . SrcLoc.getPointLoc
getEndLine :: SrcLoc.SrcSpan -> Line
getEndLine = getLine . getEndPosition
getEndColumn :: SrcLoc.SrcSpan -> Column
getEndColumn = getColumn . getEndPosition