module Unison.Util.Range where

import Unison.Lexer.Pos (Pos (..))

-- | True if `_x` contains `_y`
contains :: Range -> Range -> Bool
_x :: Range
_x@(Range Pos
a Pos
b) contains :: Range -> Range -> Bool
`contains` _y :: Range
_y@(Range Pos
c Pos
d) = Pos
a Pos -> Pos -> Bool
forall a. Ord a => a -> a -> Bool
<= Pos
c Bool -> Bool -> Bool
&& Pos
d Pos -> Pos -> Bool
forall a. Ord a => a -> a -> Bool
<= Pos
b

overlaps :: Range -> Range -> Bool
overlaps :: Range -> Range -> Bool
overlaps (Range Pos
a Pos
b) (Range Pos
c Pos
d) = Pos
a Pos -> Pos -> Bool
forall a. Ord a => a -> a -> Bool
< Pos
d Bool -> Bool -> Bool
&& Pos
c Pos -> Pos -> Bool
forall a. Ord a => a -> a -> Bool
< Pos
b

inRange :: Pos -> Range -> Bool
inRange :: Pos -> Range -> Bool
inRange Pos
p (Range Pos
a Pos
b) = Pos
p Pos -> Pos -> Bool
forall a. Ord a => a -> a -> Bool
>= Pos
a Bool -> Bool -> Bool
&& Pos
p Pos -> Pos -> Bool
forall a. Ord a => a -> a -> Bool
< Pos
b

isMultiLine :: Range -> Bool
isMultiLine :: Range -> Bool
isMultiLine (Range (Pos Line
startLine Line
_) (Pos Line
endLine Line
_)) = Line
startLine Line -> Line -> Bool
forall a. Ord a => a -> a -> Bool
< Line
endLine

data Range = Range {Range -> Pos
start :: Pos, Range -> Pos
end :: Pos} deriving (Range -> Range -> Bool
(Range -> Range -> Bool) -> (Range -> Range -> Bool) -> Eq Range
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Range -> Range -> Bool
== :: Range -> Range -> Bool
$c/= :: Range -> Range -> Bool
/= :: Range -> Range -> Bool
Eq, Eq Range
Eq Range =>
(Range -> Range -> Ordering)
-> (Range -> Range -> Bool)
-> (Range -> Range -> Bool)
-> (Range -> Range -> Bool)
-> (Range -> Range -> Bool)
-> (Range -> Range -> Range)
-> (Range -> Range -> Range)
-> Ord Range
Range -> Range -> Bool
Range -> Range -> Ordering
Range -> Range -> Range
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
$ccompare :: Range -> Range -> Ordering
compare :: Range -> Range -> Ordering
$c< :: Range -> Range -> Bool
< :: Range -> Range -> Bool
$c<= :: Range -> Range -> Bool
<= :: Range -> Range -> Bool
$c> :: Range -> Range -> Bool
> :: Range -> Range -> Bool
$c>= :: Range -> Range -> Bool
>= :: Range -> Range -> Bool
$cmax :: Range -> Range -> Range
max :: Range -> Range -> Range
$cmin :: Range -> Range -> Range
min :: Range -> Range -> Range
Ord, Line -> Range -> ShowS
[Range] -> ShowS
Range -> String
(Line -> Range -> ShowS)
-> (Range -> String) -> ([Range] -> ShowS) -> Show Range
forall a.
(Line -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Line -> Range -> ShowS
showsPrec :: Line -> Range -> ShowS
$cshow :: Range -> String
show :: Range -> String
$cshowList :: [Range] -> ShowS
showList :: [Range] -> ShowS
Show)

startingLine :: Range -> Range
startingLine :: Range -> Range
startingLine r :: Range
r@(Range start :: Pos
start@(Pos Line
startLine Line
_) (Pos Line
stopLine Line
_)) =
  if Line
stopLine Line -> Line -> Bool
forall a. Eq a => a -> a -> Bool
== Line
startLine
    then Range
r
    else Pos -> Pos -> Range
Range Pos
start (Line -> Line -> Pos
Pos (Line
startLine Line -> Line -> Line
forall a. Num a => a -> a -> a
+ Line
1) Line
0)

instance Semigroup Range where
  (Range Pos
start Pos
end) <> :: Range -> Range -> Range
<> (Range Pos
start2 Pos
end2) =
    Pos -> Pos -> Range
Range (Pos -> Pos -> Pos
forall a. Ord a => a -> a -> a
min Pos
start Pos
start2) (Pos -> Pos -> Pos
forall a. Ord a => a -> a -> a
max Pos
end Pos
end2)