-----------------------------------------------------------------------------
-- |
-- Module      :  Data.Algorithm.DiffOutput
-- Copyright   :  (c) Sterling Clover 2008-2011, Kevin Charter 2011
-- License     :  BSD 3 Clause
-- Maintainer  :  s.clover@gmail.com
-- Stability   :  experimental
-- Portability :  portable
-- Author      :  Stephan Wehr (wehr@factisresearch.com) and JP Moresmau (jp@moresmau.fr)
--
-- Generates a string output that is similar to diff normal mode.
-----------------------------------------------------------------------------
module Data.Algorithm.DiffOutput where
import Data.Algorithm.Diff
import Text.PrettyPrint hiding ((<>))
import Data.Char
import Data.List

-- | Converts 'Diff's to 'DiffOperation's. 'First' and 'Second'
-- ocurrances are converted to 'Addition' and 'Deletion', respectively, while
-- consecutive ocurrances of them are replaced by a 'Change'.
{-@ diffToLineRanges :: [LineDiff] -> [DiffOperation ValidLineRange] @-}
diffToLineRanges :: [Diff [String]] -> [DiffOperation LineRange]
diffToLineRanges :: [Diff [String]] -> [DiffOperation LineRange]
diffToLineRanges = LineNo -> LineNo -> [Diff [String]] -> [DiffOperation LineRange]
toLineRange LineNo
1 LineNo
1
   where
          -- | In @toLineRange x y ds@, @x@ is the index of the current string in the
          -- left input of the diff @ds@, and @y@ is the index of the corresponding
          -- string in the right input of the diff @ds@.
          {-@ toLineRange :: Nat1
                          -> Nat1
                          -> diffs : [LineDiff]
                          -> [DiffOperation ValidLineRange] / [len diffs, 0] @-}
          toLineRange :: Int -> Int -> [Diff [String]] -> [DiffOperation LineRange]
          toLineRange :: LineNo -> LineNo -> [Diff [String]] -> [DiffOperation LineRange]
toLineRange LineNo
_ LineNo
_ []=[]
          -- If the lines are the same, we just move forward.
          toLineRange LineNo
leftLine LineNo
rightLine (Both [String]
ls [String]
_:[Diff [String]]
rs)=
                let lins :: LineNo
lins=[String] -> LineNo
forall a. [a] -> LineNo
forall (t :: * -> *) a. Foldable t => t a -> LineNo
length [String]
ls
                in  LineNo -> LineNo -> [Diff [String]] -> [DiffOperation LineRange]
toLineRange (LineNo
leftLineLineNo -> LineNo -> LineNo
forall a. Num a => a -> a -> a
+LineNo
lins) (LineNo
rightLineLineNo -> LineNo -> LineNo
forall a. Num a => a -> a -> a
+LineNo
lins) [Diff [String]]
rs
          -- A 'Change' is introduced when an addition is followed by a deletion, or vice versa.
          toLineRange LineNo
leftLine LineNo
rightLine (Second [String]
lsS : First [String]
lsF : [Diff [String]]
rs) =
                LineNo
-> LineNo
-> [String]
-> [String]
-> [Diff [String]]
-> [DiffOperation LineRange]
toChange LineNo
leftLine LineNo
rightLine [String]
lsF [String]
lsS [Diff [String]]
rs
          toLineRange LineNo
leftLine LineNo
rightLine (First [String]
lsF : Second [String]
lsS : [Diff [String]]
rs) =
                LineNo
-> LineNo
-> [String]
-> [String]
-> [Diff [String]]
-> [DiffOperation LineRange]
toChange LineNo
leftLine LineNo
rightLine [String]
lsF [String]
lsS [Diff [String]]
rs
          -- Introduce 'Addition's.
          toLineRange LineNo
leftLine LineNo
rightLine (Second [String]
lsS : [Diff [String]]
rs) =
                let diff :: DiffOperation LineRange
diff = LineRange -> LineNo -> DiffOperation LineRange
forall a. a -> LineNo -> DiffOperation a
Addition (LineNo -> [String] -> LineRange
mkLineRange LineNo
rightLine [String]
lsS) (LineNo
leftLineLineNo -> LineNo -> LineNo
forall a. Num a => a -> a -> a
-LineNo
1)
                in  DiffOperation LineRange
diff DiffOperation LineRange
-> [DiffOperation LineRange] -> [DiffOperation LineRange]
forall a. a -> [a] -> [a]
: LineNo -> LineNo -> [Diff [String]] -> [DiffOperation LineRange]
toLineRange LineNo
leftLine (LineNo
rightLine LineNo -> LineNo -> LineNo
forall a. Num a => a -> a -> a
+ [String] -> LineNo
forall a. [a] -> LineNo
forall (t :: * -> *) a. Foldable t => t a -> LineNo
length [String]
lsS) [Diff [String]]
rs
          -- Introduce 'Deletion's.
          toLineRange LineNo
leftLine LineNo
rightLine (First [String]
lsF : [Diff [String]]
rs)=
                let diff :: DiffOperation LineRange
diff = LineRange -> LineNo -> DiffOperation LineRange
forall a. a -> LineNo -> DiffOperation a
Deletion (LineNo -> [String] -> LineRange
mkLineRange LineNo
leftLine [String]
lsF) (LineNo
rightLineLineNo -> LineNo -> LineNo
forall a. Num a => a -> a -> a
-LineNo
1)
                in  DiffOperation LineRange
diff DiffOperation LineRange
-> [DiffOperation LineRange] -> [DiffOperation LineRange]
forall a. a -> [a] -> [a]
: LineNo -> LineNo -> [Diff [String]] -> [DiffOperation LineRange]
toLineRange (LineNo
leftLine LineNo -> LineNo -> LineNo
forall a. Num a => a -> a -> a
+ [String] -> LineNo
forall a. [a] -> LineNo
forall (t :: * -> *) a. Foldable t => t a -> LineNo
length [String]
lsF) LineNo
rightLine [Diff [String]]
rs
          -- | Build 'Change's from adjacent additions and deletions.
          {-@ toChange :: Nat1
                       -> Nat1
                       -> NonEmpty String
                       -> NonEmpty String
                       -> diffs : [LineDiff]
                       -> [DiffOperation ValidLineRange]
                       / [len diffs, 1] @-}
          toChange :: Int -- ^ Current left line number.
                   -> Int -- ^ Current right line number.
                   -> [String] -- ^ Lines from the 'First' list (corresponding to deletions).
                   -> [String] -- ^ Lines from the 'Second' list (corresponding to additions).
                   -> [Diff [String]] -- ^ Remaining 'Diff's.
                   -> [DiffOperation LineRange]
          toChange :: LineNo
-> LineNo
-> [String]
-> [String]
-> [Diff [String]]
-> [DiffOperation LineRange]
toChange LineNo
leftLine LineNo
rightLine [String]
lsF [String]
lsS [Diff [String]]
rs=
                LineRange -> LineRange -> DiffOperation LineRange
forall a. a -> a -> DiffOperation a
Change (LineNo -> [String] -> LineRange
mkLineRange LineNo
leftLine [String]
lsF) (LineNo -> [String] -> LineRange
mkLineRange LineNo
rightLine [String]
lsS)
                    DiffOperation LineRange
-> [DiffOperation LineRange] -> [DiffOperation LineRange]
forall a. a -> [a] -> [a]
: LineNo -> LineNo -> [Diff [String]] -> [DiffOperation LineRange]
toLineRange (LineNo
leftLine LineNo -> LineNo -> LineNo
forall a. Num a => a -> a -> a
+ [String] -> LineNo
forall a. [a] -> LineNo
forall (t :: * -> *) a. Foldable t => t a -> LineNo
length [String]
lsF) (LineNo
rightLine LineNo -> LineNo -> LineNo
forall a. Num a => a -> a -> a
+ [String] -> LineNo
forall a. [a] -> LineNo
forall (t :: * -> *) a. Foldable t => t a -> LineNo
length [String]
lsS) [Diff [String]]
rs

{-@ ppDiff :: [LineDiff] -> String @-}
-- | Pretty print the differences. The output is similar to the output of the @diff@ utility.
--
-- > > putStr (ppDiff (getGroupedDiff ["a","b","c","d","e"] ["a","c","d","f"]))
-- > 2d1
-- > < b
-- > 5c4
-- > < e
-- > ---
-- > > f
ppDiff :: [Diff [String]] -> String
ppDiff :: [Diff [String]] -> String
ppDiff [Diff [String]]
gdiff =
   let  diffLineRanges :: [DiffOperation LineRange]
diffLineRanges = [Diff [String]] -> [DiffOperation LineRange]
diffToLineRanges [Diff [String]]
gdiff
   in
        Doc -> String
render ([DiffOperation LineRange] -> Doc
prettyDiffs [DiffOperation LineRange]
diffLineRanges) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"\n"


-- | Pretty print of diff operations.
prettyDiffs :: [DiffOperation LineRange] -> Doc
prettyDiffs :: [DiffOperation LineRange] -> Doc
prettyDiffs [] = Doc
empty
prettyDiffs (DiffOperation LineRange
d : [DiffOperation LineRange]
rest) = DiffOperation LineRange -> Doc
prettyDiff DiffOperation LineRange
d Doc -> Doc -> Doc
$$ [DiffOperation LineRange] -> Doc
prettyDiffs [DiffOperation LineRange]
rest
    where
      prettyDiff :: DiffOperation LineRange -> Doc
prettyDiff (Deletion LineRange
inLeft LineNo
lineNoRight) =
          (LineNo, LineNo) -> Doc
prettyRange (LineRange -> (LineNo, LineNo)
lrNumbers LineRange
inLeft) Doc -> Doc -> Doc
forall a. Semigroup a => a -> a -> a
<> Char -> Doc
char Char
'd' Doc -> Doc -> Doc
forall a. Semigroup a => a -> a -> a
<> LineNo -> Doc
int LineNo
lineNoRight Doc -> Doc -> Doc
$$
          Char -> [String] -> Doc
prettyLines Char
'<' (LineRange -> [String]
lrContents LineRange
inLeft)
      prettyDiff (Addition LineRange
inRight LineNo
lineNoLeft) =
          LineNo -> Doc
int LineNo
lineNoLeft Doc -> Doc -> Doc
forall a. Semigroup a => a -> a -> a
<> Char -> Doc
char Char
'a' Doc -> Doc -> Doc
forall a. Semigroup a => a -> a -> a
<> (LineNo, LineNo) -> Doc
prettyRange (LineRange -> (LineNo, LineNo)
lrNumbers LineRange
inRight) Doc -> Doc -> Doc
$$
          Char -> [String] -> Doc
prettyLines Char
'>' (LineRange -> [String]
lrContents LineRange
inRight)
      prettyDiff (Change LineRange
inLeft LineRange
inRight) =
          (LineNo, LineNo) -> Doc
prettyRange (LineRange -> (LineNo, LineNo)
lrNumbers LineRange
inLeft) Doc -> Doc -> Doc
forall a. Semigroup a => a -> a -> a
<> Char -> Doc
char Char
'c' Doc -> Doc -> Doc
forall a. Semigroup a => a -> a -> a
<> (LineNo, LineNo) -> Doc
prettyRange (LineRange -> (LineNo, LineNo)
lrNumbers LineRange
inRight) Doc -> Doc -> Doc
$$
          Char -> [String] -> Doc
prettyLines Char
'<' (LineRange -> [String]
lrContents LineRange
inLeft) Doc -> Doc -> Doc
$$
          String -> Doc
text String
"---" Doc -> Doc -> Doc
$$
          Char -> [String] -> Doc
prettyLines Char
'>' (LineRange -> [String]
lrContents LineRange
inRight)
      prettyRange :: (LineNo, LineNo) -> Doc
prettyRange (LineNo
start, LineNo
end) =
          if LineNo
start LineNo -> LineNo -> Bool
forall a. Eq a => a -> a -> Bool
== LineNo
end then LineNo -> Doc
int LineNo
start else LineNo -> Doc
int LineNo
start Doc -> Doc -> Doc
forall a. Semigroup a => a -> a -> a
<> Doc
comma Doc -> Doc -> Doc
forall a. Semigroup a => a -> a -> a
<> LineNo -> Doc
int LineNo
end
      prettyLines :: Char -> [String] -> Doc
prettyLines Char
start [String]
lins =
          [Doc] -> Doc
vcat ((String -> Doc) -> [String] -> [Doc]
forall a b. (a -> b) -> [a] -> [b]
map (\String
l -> Char -> Doc
char Char
start Doc -> Doc -> Doc
<+> String -> Doc
text String
l) [String]
lins)

-- | Parse pretty printed 'Diff's as 'DiffOperation's.
parsePrettyDiffs :: String -> [DiffOperation LineRange]
parsePrettyDiffs :: String -> [DiffOperation LineRange]
parsePrettyDiffs = [DiffOperation LineRange] -> [DiffOperation LineRange]
forall a. [a] -> [a]
reverse ([DiffOperation LineRange] -> [DiffOperation LineRange])
-> (String -> [DiffOperation LineRange])
-> String
-> [DiffOperation LineRange]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [DiffOperation LineRange] -> [String] -> [DiffOperation LineRange]
doParse [] ([String] -> [DiffOperation LineRange])
-> (String -> [String]) -> String -> [DiffOperation LineRange]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
lines
  where
    -- | Parsing entry point that iteratively accumulates 'DiffOperation's
    -- until the input is exhausted.
    {-@ doParse :: [DiffOperation LineRange] -> diffs : [String] -> [DiffOperation LineRange] / [len diffs] @-}
    doParse :: [DiffOperation LineRange] -> [String] -> [DiffOperation LineRange]
    -- NOTE: Incorrectly formatted lines are ignored.
    doParse :: [DiffOperation LineRange] -> [String] -> [DiffOperation LineRange]
doParse [DiffOperation LineRange]
acc [] = [DiffOperation LineRange]
acc
    doParse [DiffOperation LineRange]
acc [String]
s =
        let (Maybe (DiffOperation LineRange)
mnd,[String]
r) = [String] -> (Maybe (DiffOperation LineRange), [String])
parseDiff [String]
s
        in case Maybe (DiffOperation LineRange)
mnd of
            Just DiffOperation LineRange
nd -> [DiffOperation LineRange] -> [String] -> [DiffOperation LineRange]
doParse (DiffOperation LineRange
ndDiffOperation LineRange
-> [DiffOperation LineRange] -> [DiffOperation LineRange]
forall a. a -> [a] -> [a]
:[DiffOperation LineRange]
acc) [String]
r
            Maybe (DiffOperation LineRange)
_          -> [DiffOperation LineRange] -> [String] -> [DiffOperation LineRange]
doParse [DiffOperation LineRange]
acc [String]
r

    parseDiff :: [String] -> (Maybe (DiffOperation LineRange), [String])
    parseDiff :: [String] -> (Maybe (DiffOperation LineRange), [String])
parseDiff [] = (Maybe (DiffOperation LineRange)
forall a. Maybe a
Nothing,[])
    parseDiff (String
h:[String]
rs) = let
        ((LineNo, LineNo)
r1,String
hrs1) = String -> ((LineNo, LineNo), String)
parseRange String
h
        in case String
hrs1 of
                -- In each case, we pass the left line range,
                -- the remaining string after the type character,
                -- which must contain the right line range,
                -- and the remaining lines to parse.
                (Char
'd':String
hrs2) -> (LineNo, LineNo)
-> String
-> [String]
-> (Maybe (DiffOperation LineRange), [String])
parseDel (LineNo, LineNo)
r1 String
hrs2 [String]
rs
                (Char
'a':String
hrs2) -> (LineNo, LineNo)
-> String
-> [String]
-> (Maybe (DiffOperation LineRange), [String])
parseAdd (LineNo, LineNo)
r1 String
hrs2 [String]
rs
                (Char
'c':String
hrs2) -> (LineNo, LineNo)
-> String
-> [String]
-> (Maybe (DiffOperation LineRange), [String])
parseChange (LineNo, LineNo)
r1 String
hrs2 [String]
rs
                String
_ -> (Maybe (DiffOperation LineRange)
forall a. Maybe a
Nothing,[String]
rs)

    parseDel :: (LineNo, LineNo) -> String -> [String] -> (Maybe (DiffOperation LineRange), [String])
    parseDel :: (LineNo, LineNo)
-> String
-> [String]
-> (Maybe (DiffOperation LineRange), [String])
parseDel (LineNo, LineNo)
r1 String
hrs2 [String]
rs = let
        -- NOTE: the wildcard should correspond to the end of line,
        -- but is ignored for simplicity.
        ((LineNo, LineNo)
r2,String
_) = String -> ((LineNo, LineNo), String)
parseRange String
hrs2
        ([String]
ls,[String]
rs2) = (String -> Bool) -> [String] -> ([String], [String])
forall a. (a -> Bool) -> [a] -> ([a], [a])
span (String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
isPrefixOf String
"<") [String]
rs
        in (DiffOperation LineRange -> Maybe (DiffOperation LineRange)
forall a. a -> Maybe a
Just (DiffOperation LineRange -> Maybe (DiffOperation LineRange))
-> DiffOperation LineRange -> Maybe (DiffOperation LineRange)
forall a b. (a -> b) -> a -> b
$ LineRange -> LineNo -> DiffOperation LineRange
forall a. a -> LineNo -> DiffOperation a
Deletion ((LineNo, LineNo) -> [String] -> LineRange
LineRange (LineNo, LineNo)
r1 ((String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (LineNo -> String -> String
forall a. LineNo -> [a] -> [a]
drop LineNo
2) [String]
ls)) ((LineNo, LineNo) -> LineNo
forall a b. (a, b) -> a
fst (LineNo, LineNo)
r2), [String]
rs2)

    parseAdd :: (LineNo, LineNo) -> String -> [String] -> (Maybe (DiffOperation LineRange), [String])
    parseAdd :: (LineNo, LineNo)
-> String
-> [String]
-> (Maybe (DiffOperation LineRange), [String])
parseAdd (LineNo, LineNo)
r1 String
hrs2 [String]
rs = let
        -- NOTE: the wildcard should correspond to the end of line,
        -- but is ignored for simplicity.
        ((LineNo, LineNo)
r2,String
_) = String -> ((LineNo, LineNo), String)
parseRange String
hrs2
        ([String]
ls,[String]
rs2) = (String -> Bool) -> [String] -> ([String], [String])
forall a. (a -> Bool) -> [a] -> ([a], [a])
span (String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
isPrefixOf String
">") [String]
rs
        in (DiffOperation LineRange -> Maybe (DiffOperation LineRange)
forall a. a -> Maybe a
Just (DiffOperation LineRange -> Maybe (DiffOperation LineRange))
-> DiffOperation LineRange -> Maybe (DiffOperation LineRange)
forall a b. (a -> b) -> a -> b
$ LineRange -> LineNo -> DiffOperation LineRange
forall a. a -> LineNo -> DiffOperation a
Addition ((LineNo, LineNo) -> [String] -> LineRange
LineRange (LineNo, LineNo)
r2 ((String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (LineNo -> String -> String
forall a. LineNo -> [a] -> [a]
drop LineNo
2) [String]
ls)) ((LineNo, LineNo) -> LineNo
forall a b. (a, b) -> a
fst (LineNo, LineNo)
r1), [String]
rs2)

    parseChange :: (LineNo, LineNo) -> String -> [String] -> (Maybe (DiffOperation LineRange), [String])
    parseChange :: (LineNo, LineNo)
-> String
-> [String]
-> (Maybe (DiffOperation LineRange), [String])
parseChange (LineNo, LineNo)
r1 String
hrs2 [String]
rs = let
        -- NOTE: the wildcard should correspond to the end of line,
        -- but is ignored for simplicity.
        ((LineNo, LineNo)
r2,String
_) = String -> ((LineNo, LineNo), String)
parseRange String
hrs2
        ([String]
ls1,[String]
rs2) = (String -> Bool) -> [String] -> ([String], [String])
forall a. (a -> Bool) -> [a] -> ([a], [a])
span (String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
isPrefixOf String
"<") [String]
rs
        in case [String]
rs2 of
            -- The left and right diff of a 'Change' are separated by a "---" line.
            (String
"---":[String]
rs3) -> let
                ([String]
ls2,[String]
rs4) = (String -> Bool) -> [String] -> ([String], [String])
forall a. (a -> Bool) -> [a] -> ([a], [a])
span (String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
isPrefixOf String
">") [String]
rs3
                in (DiffOperation LineRange -> Maybe (DiffOperation LineRange)
forall a. a -> Maybe a
Just (DiffOperation LineRange -> Maybe (DiffOperation LineRange))
-> DiffOperation LineRange -> Maybe (DiffOperation LineRange)
forall a b. (a -> b) -> a -> b
$ LineRange -> LineRange -> DiffOperation LineRange
forall a. a -> a -> DiffOperation a
Change ((LineNo, LineNo) -> [String] -> LineRange
LineRange (LineNo, LineNo)
r1 ((String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (LineNo -> String -> String
forall a. LineNo -> [a] -> [a]
drop LineNo
2) [String]
ls1)) ((LineNo, LineNo) -> [String] -> LineRange
LineRange (LineNo, LineNo)
r2 ((String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (LineNo -> String -> String
forall a. LineNo -> [a] -> [a]
drop LineNo
2) [String]
ls2)), [String]
rs4)
            [String]
_ -> (Maybe (DiffOperation LineRange)
forall a. Maybe a
Nothing,[String]
rs2)

    parseRange :: String -> ((LineNo, LineNo),String)
    parseRange :: String -> ((LineNo, LineNo), String)
parseRange String
l = let
        (String
fstLine,String
rs) = (Char -> Bool) -> String -> (String, String)
forall a. (a -> Bool) -> [a] -> ([a], [a])
span Char -> Bool
isDigit String
l
        (String
sndLine,String
rs3) = case String
rs of
                                    -- The comma is used to separate
                                    -- the start and end line numbers in a range,
                                    -- but is omitted if they are the same.
                                    -- i.e. the range is a single line.
                                    (Char
',':String
rs2) -> (Char -> Bool) -> String -> (String, String)
forall a. (a -> Bool) -> [a] -> ([a], [a])
span Char -> Bool
isDigit String
rs2
                                    String
_ -> (String
fstLine,String
rs)
        in ((String -> LineNo
forall a. Read a => String -> a
read String
fstLine,String -> LineNo
forall a. Read a => String -> a
read String
sndLine),String
rs3)

-- | Line number alias. Always non-negative.
type LineNo = Int

-- | Line Range: start, end and contents.
--
-- The following invariants hold:
--
-- > snd lrNumbers >= fst lrNumbers
-- > snd lrNumbers - fst lrNumbers + 1 == length lrContents
--
-- which imply @lrContents@ cannot be empty.
{-@
data LineRange = LineRange { lrNumbers :: (LineNo, LineNo)
                           , lrContents :: [String]
                           }
@-}
data LineRange = LineRange { LineRange -> (LineNo, LineNo)
lrNumbers :: (LineNo, LineNo)
                           , LineRange -> [String]
lrContents :: [String]
                           }
            deriving (LineNo -> LineRange -> String -> String
[LineRange] -> String -> String
LineRange -> String
(LineNo -> LineRange -> String -> String)
-> (LineRange -> String)
-> ([LineRange] -> String -> String)
-> Show LineRange
forall a.
(LineNo -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
$cshowsPrec :: LineNo -> LineRange -> String -> String
showsPrec :: LineNo -> LineRange -> String -> String
$cshow :: LineRange -> String
show :: LineRange -> String
$cshowList :: [LineRange] -> String -> String
showList :: [LineRange] -> String -> String
Show, ReadPrec [LineRange]
ReadPrec LineRange
LineNo -> ReadS LineRange
ReadS [LineRange]
(LineNo -> ReadS LineRange)
-> ReadS [LineRange]
-> ReadPrec LineRange
-> ReadPrec [LineRange]
-> Read LineRange
forall a.
(LineNo -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
$creadsPrec :: LineNo -> ReadS LineRange
readsPrec :: LineNo -> ReadS LineRange
$creadList :: ReadS [LineRange]
readList :: ReadS [LineRange]
$creadPrec :: ReadPrec LineRange
readPrec :: ReadPrec LineRange
$creadListPrec :: ReadPrec [LineRange]
readListPrec :: ReadPrec [LineRange]
Read, LineRange -> LineRange -> Bool
(LineRange -> LineRange -> Bool)
-> (LineRange -> LineRange -> Bool) -> Eq LineRange
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: LineRange -> LineRange -> Bool
== :: LineRange -> LineRange -> Bool
$c/= :: LineRange -> LineRange -> Bool
/= :: LineRange -> LineRange -> Bool
Eq, Eq LineRange
Eq LineRange =>
(LineRange -> LineRange -> Ordering)
-> (LineRange -> LineRange -> Bool)
-> (LineRange -> LineRange -> Bool)
-> (LineRange -> LineRange -> Bool)
-> (LineRange -> LineRange -> Bool)
-> (LineRange -> LineRange -> LineRange)
-> (LineRange -> LineRange -> LineRange)
-> Ord LineRange
LineRange -> LineRange -> Bool
LineRange -> LineRange -> Ordering
LineRange -> LineRange -> LineRange
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 :: LineRange -> LineRange -> Ordering
compare :: LineRange -> LineRange -> Ordering
$c< :: LineRange -> LineRange -> Bool
< :: LineRange -> LineRange -> Bool
$c<= :: LineRange -> LineRange -> Bool
<= :: LineRange -> LineRange -> Bool
$c> :: LineRange -> LineRange -> Bool
> :: LineRange -> LineRange -> Bool
$c>= :: LineRange -> LineRange -> Bool
>= :: LineRange -> LineRange -> Bool
$cmax :: LineRange -> LineRange -> LineRange
max :: LineRange -> LineRange -> LineRange
$cmin :: LineRange -> LineRange -> LineRange
min :: LineRange -> LineRange -> LineRange
Ord)

{-@ predicate validRange Start End ContentLenght = Start >= 0 && End >= 0 && Start <= End && ContentLenght = End - Start + 1 @-}

{-@ type ValidLineRange = {r : LineRange | validRange (fst (lrNumbers r)) (snd (lrNumbers r)) (len (lrContents r))} @-}

-- | Smart constructor for 'LineRange' that computes the end line from the
-- start line and the content length, guaranteeing that its content length and
-- range match.
{-@ mkLineRange :: Nat -> {contents : [String] | len contents >= 1} -> ValidLineRange @-}
mkLineRange :: Int -> [String] -> LineRange
mkLineRange :: LineNo -> [String] -> LineRange
mkLineRange LineNo
start [String]
contents = (LineNo, LineNo) -> [String] -> LineRange
LineRange (LineNo
start, LineNo
start LineNo -> LineNo -> LineNo
forall a. Num a => a -> a -> a
+ [String] -> LineNo
forall a. [a] -> LineNo
forall (t :: * -> *) a. Foldable t => t a -> LineNo
length [String]
contents LineNo -> LineNo -> LineNo
forall a. Num a => a -> a -> a
- LineNo
1) [String]
contents

-- | Diff operation representing changes to apply.
data DiffOperation a
  = Deletion a LineNo  -- ^ Element deleted on the left input, line number
                       -- preceding the deleted lines in the right input.
  | Addition a LineNo  -- ^ Element added from the right input, line number
                       -- preceding the added lines in the left input.
  | Change a a         -- ^ Element changed from the left input to the right input.
  deriving (LineNo -> DiffOperation a -> String -> String
[DiffOperation a] -> String -> String
DiffOperation a -> String
(LineNo -> DiffOperation a -> String -> String)
-> (DiffOperation a -> String)
-> ([DiffOperation a] -> String -> String)
-> Show (DiffOperation a)
forall a. Show a => LineNo -> DiffOperation a -> String -> String
forall a. Show a => [DiffOperation a] -> String -> String
forall a. Show a => DiffOperation a -> String
forall a.
(LineNo -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
$cshowsPrec :: forall a. Show a => LineNo -> DiffOperation a -> String -> String
showsPrec :: LineNo -> DiffOperation a -> String -> String
$cshow :: forall a. Show a => DiffOperation a -> String
show :: DiffOperation a -> String
$cshowList :: forall a. Show a => [DiffOperation a] -> String -> String
showList :: [DiffOperation a] -> String -> String
Show,ReadPrec [DiffOperation a]
ReadPrec (DiffOperation a)
LineNo -> ReadS (DiffOperation a)
ReadS [DiffOperation a]
(LineNo -> ReadS (DiffOperation a))
-> ReadS [DiffOperation a]
-> ReadPrec (DiffOperation a)
-> ReadPrec [DiffOperation a]
-> Read (DiffOperation a)
forall a. Read a => ReadPrec [DiffOperation a]
forall a. Read a => ReadPrec (DiffOperation a)
forall a. Read a => LineNo -> ReadS (DiffOperation a)
forall a. Read a => ReadS [DiffOperation a]
forall a.
(LineNo -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
$creadsPrec :: forall a. Read a => LineNo -> ReadS (DiffOperation a)
readsPrec :: LineNo -> ReadS (DiffOperation a)
$creadList :: forall a. Read a => ReadS [DiffOperation a]
readList :: ReadS [DiffOperation a]
$creadPrec :: forall a. Read a => ReadPrec (DiffOperation a)
readPrec :: ReadPrec (DiffOperation a)
$creadListPrec :: forall a. Read a => ReadPrec [DiffOperation a]
readListPrec :: ReadPrec [DiffOperation a]
Read,DiffOperation a -> DiffOperation a -> Bool
(DiffOperation a -> DiffOperation a -> Bool)
-> (DiffOperation a -> DiffOperation a -> Bool)
-> Eq (DiffOperation a)
forall a. Eq a => DiffOperation a -> DiffOperation a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: forall a. Eq a => DiffOperation a -> DiffOperation a -> Bool
== :: DiffOperation a -> DiffOperation a -> Bool
$c/= :: forall a. Eq a => DiffOperation a -> DiffOperation a -> Bool
/= :: DiffOperation a -> DiffOperation a -> Bool
Eq,Eq (DiffOperation a)
Eq (DiffOperation a) =>
(DiffOperation a -> DiffOperation a -> Ordering)
-> (DiffOperation a -> DiffOperation a -> Bool)
-> (DiffOperation a -> DiffOperation a -> Bool)
-> (DiffOperation a -> DiffOperation a -> Bool)
-> (DiffOperation a -> DiffOperation a -> Bool)
-> (DiffOperation a -> DiffOperation a -> DiffOperation a)
-> (DiffOperation a -> DiffOperation a -> DiffOperation a)
-> Ord (DiffOperation a)
DiffOperation a -> DiffOperation a -> Bool
DiffOperation a -> DiffOperation a -> Ordering
DiffOperation a -> DiffOperation a -> DiffOperation a
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
forall a. Ord a => Eq (DiffOperation a)
forall a. Ord a => DiffOperation a -> DiffOperation a -> Bool
forall a. Ord a => DiffOperation a -> DiffOperation a -> Ordering
forall a.
Ord a =>
DiffOperation a -> DiffOperation a -> DiffOperation a
$ccompare :: forall a. Ord a => DiffOperation a -> DiffOperation a -> Ordering
compare :: DiffOperation a -> DiffOperation a -> Ordering
$c< :: forall a. Ord a => DiffOperation a -> DiffOperation a -> Bool
< :: DiffOperation a -> DiffOperation a -> Bool
$c<= :: forall a. Ord a => DiffOperation a -> DiffOperation a -> Bool
<= :: DiffOperation a -> DiffOperation a -> Bool
$c> :: forall a. Ord a => DiffOperation a -> DiffOperation a -> Bool
> :: DiffOperation a -> DiffOperation a -> Bool
$c>= :: forall a. Ord a => DiffOperation a -> DiffOperation a -> Bool
>= :: DiffOperation a -> DiffOperation a -> Bool
$cmax :: forall a.
Ord a =>
DiffOperation a -> DiffOperation a -> DiffOperation a
max :: DiffOperation a -> DiffOperation a -> DiffOperation a
$cmin :: forall a.
Ord a =>
DiffOperation a -> DiffOperation a -> DiffOperation a
min :: DiffOperation a -> DiffOperation a -> DiffOperation a
Ord)