{-|
Description : Facade for the location handling of HSE

See also "Language.Haskell.Formatter.Source".
-}
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 b
difference a
natural
          = Int -> a
forall a. Enum a => Int -> a
toEnum (Int -> a) -> Int -> a
forall a b. (a -> b) -> a -> b
$ b -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral b
difference Int -> Int -> Int
forall a. Num a => a -> a -> a
+ a -> Int
forall a. Enum a => a -> Int
fromEnum a
natural

        minus :: Num b => a -> a -> b
        minus a
minuend = Int -> b
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> b) -> (a -> Int) -> a -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int -> Int -> Int) -> (a -> Int) -> a -> a -> Int
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
Function.on (-) a -> Int
forall a. Enum a => a -> Int
fromEnum a
minuend

class Portioned a where

        getPortion :: a -> SrcLoc.SrcSpan

newtype Line = Line Int
                 deriving (Line -> Line -> Bool
(Line -> Line -> Bool) -> (Line -> Line -> Bool) -> Eq Line
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Line -> Line -> Bool
$c/= :: Line -> Line -> Bool
== :: Line -> Line -> Bool
$c== :: Line -> Line -> Bool
Eq, Eq Line
Eq Line
-> (Line -> Line -> Ordering)
-> (Line -> Line -> Bool)
-> (Line -> Line -> Bool)
-> (Line -> Line -> Bool)
-> (Line -> Line -> Bool)
-> (Line -> Line -> Line)
-> (Line -> Line -> Line)
-> Ord Line
Line -> Line -> Bool
Line -> Line -> Ordering
Line -> Line -> Line
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Line -> Line -> Line
$cmin :: Line -> Line -> Line
max :: Line -> Line -> Line
$cmax :: Line -> Line -> Line
>= :: Line -> Line -> Bool
$c>= :: Line -> Line -> Bool
> :: Line -> Line -> Bool
$c> :: Line -> Line -> Bool
<= :: Line -> Line -> Bool
$c<= :: Line -> Line -> Bool
< :: Line -> Line -> Bool
$c< :: Line -> Line -> Bool
compare :: Line -> Line -> Ordering
$ccompare :: Line -> Line -> Ordering
$cp1Ord :: Eq Line
Ord, Int -> Line -> ShowS
[Line] -> ShowS
Line -> String
(Int -> Line -> ShowS)
-> (Line -> String) -> ([Line] -> ShowS) -> Show Line
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Line] -> ShowS
$cshowList :: [Line] -> ShowS
show :: Line -> String
$cshow :: Line -> String
showsPrec :: Int -> Line -> ShowS
$cshowsPrec :: Int -> Line -> ShowS
Show)

newtype Column = Column Int
                   deriving (Column -> Column -> Bool
(Column -> Column -> Bool)
-> (Column -> Column -> Bool) -> Eq Column
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Column -> Column -> Bool
$c/= :: Column -> Column -> Bool
== :: Column -> Column -> Bool
$c== :: Column -> Column -> Bool
Eq, Eq Column
Eq Column
-> (Column -> Column -> Ordering)
-> (Column -> Column -> Bool)
-> (Column -> Column -> Bool)
-> (Column -> Column -> Bool)
-> (Column -> Column -> Bool)
-> (Column -> Column -> Column)
-> (Column -> Column -> Column)
-> Ord Column
Column -> Column -> Bool
Column -> Column -> Ordering
Column -> Column -> Column
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Column -> Column -> Column
$cmin :: Column -> Column -> Column
max :: Column -> Column -> Column
$cmax :: Column -> Column -> Column
>= :: Column -> Column -> Bool
$c>= :: Column -> Column -> Bool
> :: Column -> Column -> Bool
$c> :: Column -> Column -> Bool
<= :: Column -> Column -> Bool
$c<= :: Column -> Column -> Bool
< :: Column -> Column -> Bool
$c< :: Column -> Column -> Bool
compare :: Column -> Column -> Ordering
$ccompare :: Column -> Column -> Ordering
$cp1Ord :: Eq Column
Ord, Int -> Column -> ShowS
[Column] -> ShowS
Column -> String
(Int -> Column -> ShowS)
-> (Column -> String) -> ([Column] -> ShowS) -> Show Column
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Column] -> ShowS
$cshowList :: [Column] -> ShowS
show :: Column -> String
$cshow :: Column -> String
showsPrec :: Int -> Column -> ShowS
$cshowsPrec :: Int -> Column -> ShowS
Show)

instance Enum Line where
        toEnum :: Int -> Line
toEnum = Int -> Line
Line
        fromEnum :: Line -> Int
fromEnum (Line Int
line) = Int
line

instance Enum Column where
        toEnum :: Int -> Column
toEnum = Int -> Column
Column
        fromEnum :: Column -> Int
fromEnum (Column Int
column) = Int
column

instance Natural Line where
        base :: Line
base = Int -> Line
Line Int
1

instance Natural Column where
        base :: Column
base = Int -> Column
Column Int
1

instance Portioned SrcLoc.SrcSpanInfo where
        getPortion :: SrcSpanInfo -> SrcSpan
getPortion = SrcSpanInfo -> SrcSpan
SrcLoc.srcInfoSpan

instance Portioned a => Portioned (Syntax.Module a) where
        getPortion :: Module a -> SrcSpan
getPortion = a -> SrcSpan
forall a. Portioned a => a -> SrcSpan
getPortion (a -> SrcSpan) -> (Module a -> a) -> Module a -> SrcSpan
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Module a -> a
forall (ast :: * -> *) l. Annotated ast => ast l -> l
Syntax.ann

instance Portioned Comments.Comment where
        getPortion :: Comment -> SrcSpan
getPortion (Comments.Comment Bool
_ SrcSpan
commentPortion String
_) = SrcSpan
commentPortion

streamName :: SrcLoc.SrcInfo a => a -> StreamName.StreamName
streamName :: a -> StreamName
streamName = String -> StreamName
StreamName.createStreamName (String -> StreamName) -> (a -> String) -> a -> StreamName
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> String
forall si. SrcInfo si => si -> String
SrcLoc.fileName

getLine :: SrcLoc.SrcLoc -> Line
getLine :: SrcLoc -> Line
getLine = Int -> Line
Line (Int -> Line) -> (SrcLoc -> Int) -> SrcLoc -> Line
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SrcLoc -> Int
SrcLoc.srcLine

getColumn :: SrcLoc.SrcLoc -> Column
getColumn :: SrcLoc -> Column
getColumn = Int -> Column
Column (Int -> Column) -> (SrcLoc -> Int) -> SrcLoc -> Column
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SrcLoc -> Int
SrcLoc.srcColumn

createPosition :: StreamName.StreamName -> Line -> Column -> SrcLoc.SrcLoc
createPosition :: StreamName -> Line -> Column -> SrcLoc
createPosition StreamName
stream (Line Int
line) (Column Int
column)
  = SrcLoc :: String -> Int -> Int -> SrcLoc
SrcLoc.SrcLoc{srcFilename :: String
SrcLoc.srcFilename = StreamName -> String
forall a. Show a => a -> String
show StreamName
stream, srcLine :: Int
SrcLoc.srcLine = Int
line,
                  srcColumn :: Int
SrcLoc.srcColumn = Int
column}

getEndPosition :: SrcLoc.SrcSpan -> SrcLoc.SrcLoc
getEndPosition :: SrcSpan -> SrcLoc
getEndPosition SrcSpan
portion = StreamName -> Line -> Column -> SrcLoc
createPosition StreamName
stream Line
line Column
column
  where stream :: StreamName
stream = SrcSpan -> StreamName
forall a. SrcInfo a => a -> StreamName
streamName SrcSpan
portion
        line :: Line
line = Int -> Line
Line (Int -> Line) -> Int -> Line
forall a b. (a -> b) -> a -> b
$ SrcSpan -> Int
SrcLoc.srcSpanEndLine SrcSpan
portion
        column :: Column
column = Int -> Column
Column (Int -> Column) -> Int -> Column
forall a b. (a -> b) -> a -> b
$ SrcSpan -> Int
SrcLoc.srcSpanEndColumn SrcSpan
portion

replaceNestedPortionLines ::
                          (Line -> Line) ->
                            SrcLoc.SrcSpanInfo -> SrcLoc.SrcSpanInfo
replaceNestedPortionLines :: (Line -> Line) -> SrcSpanInfo -> SrcSpanInfo
replaceNestedPortionLines Line -> Line
function SrcSpanInfo
nestedPortion
  = SrcSpanInfo
nestedPortion{srcInfoSpan :: SrcSpan
SrcLoc.srcInfoSpan = SrcSpan
parent',
                  srcInfoPoints :: [SrcSpan]
SrcLoc.srcInfoPoints = [SrcSpan]
children'}
  where parent' :: SrcSpan
parent' = SrcSpan -> SrcSpan
replace SrcSpan
parent
        replace :: SrcSpan -> SrcSpan
replace = (Line -> Line) -> SrcSpan -> SrcSpan
replacePortionLines Line -> Line
function
        parent :: SrcSpan
parent = SrcSpanInfo -> SrcSpan
SrcLoc.srcInfoSpan SrcSpanInfo
nestedPortion
        children' :: [SrcSpan]
children' = (SrcSpan -> SrcSpan) -> [SrcSpan] -> [SrcSpan]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap SrcSpan -> SrcSpan
replace [SrcSpan]
children
        children :: [SrcSpan]
children = SrcSpanInfo -> [SrcSpan]
SrcLoc.srcInfoPoints SrcSpanInfo
nestedPortion

replacePortionLines :: (Line -> Line) -> SrcLoc.SrcSpan -> SrcLoc.SrcSpan
replacePortionLines :: (Line -> Line) -> SrcSpan -> SrcSpan
replacePortionLines Line -> Line
function SrcSpan
portion
  = SrcSpan
portion{srcSpanStartLine :: Int
SrcLoc.srcSpanStartLine = Int
start, srcSpanEndLine :: Int
SrcLoc.srcSpanEndLine = Int
end}
  where Line Int
start = Line -> Line
function (Line -> Line) -> Line -> Line
forall a b. (a -> b) -> a -> b
$ SrcSpan -> Line
forall a. SrcInfo a => a -> Line
getStartLine SrcSpan
portion
        Line Int
end = Line -> Line
function (Line -> Line) -> Line -> Line
forall a b. (a -> b) -> a -> b
$ SrcSpan -> Line
getEndLine SrcSpan
portion

stringPortion :: SrcLoc.SrcLoc -> String -> SrcLoc.SrcSpan
stringPortion :: SrcLoc -> String -> SrcSpan
stringPortion SrcLoc
startPosition String
string = SrcLoc -> SrcLoc -> SrcSpan
SrcLoc.mkSrcSpan SrcLoc
startPosition SrcLoc
endPosition
  where endPosition :: SrcLoc
endPosition = StreamName -> Line -> Column -> SrcLoc
createPosition StreamName
stream Line
endLine Column
endColumn
        stream :: StreamName
stream = SrcLoc -> StreamName
forall a. SrcInfo a => a -> StreamName
streamName SrcLoc
startPosition
        endLine :: Line
endLine = Int -> Line -> Line
forall c b. (Natural c, Integral b) => b -> c -> c
lastIndex Int
lineCount Line
startLine
        lastIndex :: b -> c -> c
lastIndex b
difference = c -> c
forall a. Enum a => a -> a
pred (c -> c) -> (c -> c) -> c -> c
forall b c a. (b -> c) -> (a -> b) -> a -> c
. b -> c -> c
forall a b. (Natural a, Integral b) => b -> a -> a
plus b
difference
        lineCount :: Int
lineCount = [String] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [String]
stringLines
        stringLines :: [String]
stringLines = String -> [String]
Newline.splitSeparatedLines String
string
        startLine :: Line
startLine = SrcLoc -> Line
forall a. SrcInfo a => a -> Line
getStartLine SrcLoc
startPosition
        endColumn :: Column
endColumn = Int -> Column -> Column
forall c b. (Natural c, Integral b) => b -> c -> c
lastIndex Int
lastLineLength Column
lastLineStartColumn
        lastLineLength :: Int
lastLineLength = Int -> (String -> Int) -> Maybe String -> Int
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Int
0 String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (Maybe String -> Int) -> Maybe String -> Int
forall a b. (a -> b) -> a -> b
$ [String] -> Maybe String
forall a. [a] -> Maybe a
ListTool.maybeLast [String]
stringLines
        lastLineStartColumn :: Column
lastLineStartColumn = if Bool
hasSingleLine then Column
startColumn else Column
forall a. Natural a => a
base
        hasSingleLine :: Bool
hasSingleLine = Int
lineCount Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
1
        startColumn :: Column
startColumn = SrcLoc -> Column
forall a. SrcInfo a => a -> Column
getStartColumn SrcLoc
startPosition

getStartLine :: SrcLoc.SrcInfo a => a -> Line
getStartLine :: a -> Line
getStartLine = SrcLoc -> Line
getLine (SrcLoc -> Line) -> (a -> SrcLoc) -> a -> Line
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> SrcLoc
forall si. SrcInfo si => si -> SrcLoc
SrcLoc.getPointLoc

getStartColumn :: SrcLoc.SrcInfo a => a -> Column
getStartColumn :: a -> Column
getStartColumn = SrcLoc -> Column
getColumn (SrcLoc -> Column) -> (a -> SrcLoc) -> a -> Column
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> SrcLoc
forall si. SrcInfo si => si -> SrcLoc
SrcLoc.getPointLoc

getEndLine :: SrcLoc.SrcSpan -> Line
getEndLine :: SrcSpan -> Line
getEndLine = SrcLoc -> Line
getLine (SrcLoc -> Line) -> (SrcSpan -> SrcLoc) -> SrcSpan -> Line
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SrcSpan -> SrcLoc
getEndPosition

getEndColumn :: SrcLoc.SrcSpan -> Column
getEndColumn :: SrcSpan -> Column
getEndColumn = SrcLoc -> Column
getColumn (SrcLoc -> Column) -> (SrcSpan -> SrcLoc) -> SrcSpan -> Column
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SrcSpan -> SrcLoc
getEndPosition