2015-12-18 17:48:04 +03:00
|
|
|
module PatchOutput (
|
|
|
|
patch,
|
|
|
|
hunks
|
|
|
|
) where
|
2015-12-18 01:22:09 +03:00
|
|
|
|
2015-12-18 01:22:53 +03:00
|
|
|
import Diff
|
2015-12-25 02:11:19 +03:00
|
|
|
import Line
|
2015-12-30 20:35:27 +03:00
|
|
|
import Range
|
2015-12-25 01:41:45 +03:00
|
|
|
import Row
|
2015-12-25 00:37:14 +03:00
|
|
|
import Source hiding ((++))
|
2015-12-25 01:41:45 +03:00
|
|
|
import Split
|
2015-12-25 02:11:19 +03:00
|
|
|
import Control.Comonad.Cofree
|
|
|
|
import Control.Monad.Free
|
2015-12-18 01:22:53 +03:00
|
|
|
|
2015-12-28 18:02:50 +03:00
|
|
|
patch :: Eq a => Diff a Info -> Source Char -> Source Char -> String
|
2015-12-30 23:23:52 +03:00
|
|
|
patch diff sourceA sourceB = mconcat $ showHunk (sourceA, sourceB) <$> hunks diff (sourceA, sourceB)
|
2015-12-18 16:00:01 +03:00
|
|
|
|
2015-12-30 23:21:26 +03:00
|
|
|
data Hunk a = Hunk { offsetA :: Int, offsetB :: Int, changes :: [Change a], trailingContext :: [Row a] }
|
2015-12-25 02:11:38 +03:00
|
|
|
deriving (Eq, Show)
|
2015-12-18 16:25:37 +03:00
|
|
|
|
2015-12-25 02:28:31 +03:00
|
|
|
data Change a = Change { context :: [Row a], contents :: [Row a] }
|
|
|
|
deriving (Eq, Show)
|
|
|
|
|
2015-12-30 23:23:52 +03:00
|
|
|
showHunk :: Eq a => (Source Char, Source Char) -> Hunk (SplitDiff a Info) -> String
|
2015-12-30 23:29:17 +03:00
|
|
|
showHunk sources hunk = header hunk ++ concat (showChange sources <$> changes hunk) ++ concat (showLine ' ' (snd sources) . unRight <$> trailingContext hunk)
|
2015-12-25 02:50:39 +03:00
|
|
|
|
2015-12-30 23:23:52 +03:00
|
|
|
showChange :: Eq a => (Source Char, Source Char) -> Change (SplitDiff a Info) -> String
|
2015-12-30 23:27:04 +03:00
|
|
|
showChange sources change = concat (showLine ' ' (snd sources) . unRight <$> context change) ++ concat (showRow sources <$> contents change)
|
|
|
|
|
|
|
|
showRow :: Eq leaf => (Source Char, Source Char) -> Row (SplitDiff leaf Info) -> String
|
|
|
|
showRow sources (Row lineA lineB) = if lineA == lineB
|
|
|
|
then showLine ' ' (snd sources) lineB
|
|
|
|
else showLine '-' (fst sources) lineA ++ showLine '+' (snd sources) lineB
|
2015-12-30 23:27:00 +03:00
|
|
|
|
|
|
|
showLine :: Char -> Source Char -> Line (SplitDiff leaf Info) -> String
|
|
|
|
showLine _ _ EmptyLine = ""
|
|
|
|
showLine prefix source line = prefix : (toString . (`slice` source) . unionRanges $ getRange <$> unLine line)
|
2015-12-30 23:26:49 +03:00
|
|
|
|
|
|
|
getRange :: SplitDiff leaf Info -> Range
|
|
|
|
getRange (Free (Annotated (Info range _) _)) = range
|
|
|
|
getRange (Pure (Info range _ :< _)) = range
|
2015-12-25 02:11:19 +03:00
|
|
|
|
2015-12-25 01:41:45 +03:00
|
|
|
header :: Hunk a -> String
|
2015-12-30 20:31:38 +03:00
|
|
|
header hunk = "@@ -" ++ show (offsetA hunk) ++ "," ++ show (0 :: Int) ++ " +" ++ show (offsetB hunk) ++ "," ++ show (0 :: Int) ++ " @@\n"
|
2015-12-18 16:07:43 +03:00
|
|
|
|
2015-12-30 23:23:52 +03:00
|
|
|
hunks :: Diff a Info -> (Source Char, Source Char) -> [Hunk (SplitDiff a Info)]
|
|
|
|
hunks diff sources = hunksInRows . fst $ splitDiffByLines diff (0, 0) sources
|
2015-12-25 01:42:08 +03:00
|
|
|
|
2015-12-25 02:23:04 +03:00
|
|
|
hunksInRows :: [Row (SplitDiff a Info)] -> [Hunk (SplitDiff a Info)]
|
2015-12-25 01:42:22 +03:00
|
|
|
hunksInRows rows = case nextHunk rows of
|
|
|
|
Nothing -> []
|
|
|
|
Just (hunk, rest) -> hunk : hunksInRows rest
|
|
|
|
|
2015-12-25 02:23:04 +03:00
|
|
|
nextHunk :: [Row (SplitDiff a Info)] -> Maybe (Hunk (SplitDiff a Info), [Row (SplitDiff a Info)])
|
2015-12-25 02:52:33 +03:00
|
|
|
nextHunk rows = case nextChange rows of
|
|
|
|
Nothing -> Nothing
|
2015-12-30 23:21:26 +03:00
|
|
|
Just (change, rest) -> Just (Hunk 0 0 [ change ] (take 3 rest), drop 3 rest)
|
2015-12-25 01:42:08 +03:00
|
|
|
|
2015-12-25 02:28:37 +03:00
|
|
|
nextChange :: [Row (SplitDiff a Info)] -> Maybe (Change (SplitDiff a Info), [Row (SplitDiff a Info)])
|
|
|
|
nextChange rows = case changes of
|
|
|
|
[] -> Nothing
|
|
|
|
_ -> Just (Change (takeLast 3 leadingRows) changes, afterChanges)
|
|
|
|
where (leadingRows, afterLeadingContext) = Prelude.break rowHasChanges rows
|
|
|
|
(changes, afterChanges) = span rowHasChanges afterLeadingContext
|
|
|
|
|
2015-12-25 02:14:19 +03:00
|
|
|
rowHasChanges :: Row (SplitDiff a Info) -> Bool
|
|
|
|
rowHasChanges (Row left right) = lineHasChanges left || lineHasChanges right
|
|
|
|
|
|
|
|
lineHasChanges :: Line (SplitDiff a Info) -> Bool
|
|
|
|
lineHasChanges = or . fmap diffHasChanges
|
|
|
|
|
|
|
|
diffHasChanges :: SplitDiff a Info -> Bool
|
|
|
|
diffHasChanges = or . fmap (const True)
|
2015-12-25 01:54:26 +03:00
|
|
|
|
|
|
|
takeLast :: Int -> [a] -> [a]
|
|
|
|
takeLast n = fst . foldr accum ([], 0)
|
|
|
|
where accum each (rest, i) = if i < n
|
|
|
|
then (each : rest, i + 1)
|
|
|
|
else (rest, i)
|