1
1
mirror of https://github.com/github/semantic.git synced 2024-12-29 18:06:14 +03:00
semantic/src/PatchOutput.hs

57 lines
2.0 KiB
Haskell
Raw Normal View History

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
import Line
2015-12-25 01:41:45 +03:00
import Row
import Source hiding ((++))
2015-12-25 01:41:45 +03:00
import Split
import Control.Comonad.Cofree
import Control.Monad.Free
2015-12-18 01:22:53 +03:00
patch :: Diff a Info -> Source Char -> Source Char -> String
2015-12-25 02:11:32 +03:00
patch diff sourceA sourceB = mconcat $ showHunk sourceA sourceB <$> hunks diff sourceA sourceB
2015-12-25 01:41:45 +03:00
data Hunk a = Hunk { offsetA :: Int, offsetB :: Int, getRows :: [Row (SplitDiff a Info)] }
2015-12-25 02:11:38 +03:00
deriving (Eq, Show)
2015-12-18 16:25:37 +03:00
showHunk sourceA sourceB hunk = header hunk ++ concat (showRow <$> getRows hunk)
where showRow (Row lineA lineB) = showLine sourceA lineA ++ showLine sourceB lineB
showLine _ EmptyLine = ""
showLine source line = toString . (`slice` source) . mconcat $ getRange <$> unLine line
getRange (Free (Annotated (Info range _) _)) = range
getRange (Pure (Info range _ :< _)) = range
2015-12-25 01:41:45 +03:00
header :: Hunk a -> String
header hunk = "@@ -" ++ show (offsetA hunk) ++ "," ++ show 0 ++ " +" ++ show (offsetB hunk) ++ "," ++ show 0 ++ " @@\n"
2015-12-18 16:07:43 +03:00
2015-12-25 01:41:45 +03:00
hunks :: Diff a Info -> Source Char -> Source Char -> [Hunk a]
2015-12-25 01:42:38 +03:00
hunks diff sourceA sourceB = hunksInRows rows
where (rows, _) = splitDiffByLines diff (0, 0) (sourceA, sourceB)
hunksInRows :: [Row (SplitDiff a Info)] -> [Hunk a]
hunksInRows rows = case nextHunk rows of
Nothing -> []
Just (hunk, rest) -> hunk : hunksInRows rest
nextHunk :: [Row (SplitDiff a Info)] -> Maybe (Hunk a, [Row (SplitDiff a Info)])
nextHunk rows = case hunkRows of
[] -> Nothing
hunkRows' -> Just (Hunk 0 0 hunkRows', afterChanges)
where hunkRows = takeLast 3 leadingRows ++ changes
(leadingRows, afterLeadingContext) = Prelude.break rowHasChanges rows
(changes, afterChanges) = span rowHasChanges afterLeadingContext
rowHasChanges (Row left right) = lineHasChanges left || lineHasChanges right
lineHasChanges = or . fmap diffHasChanges
diffHasChanges = or . fmap (const True)
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)