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

80 lines
3.2 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
import Range
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 :: 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-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
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-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 01:41:45 +03:00
header :: Hunk a -> String
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 02:23:04 +03:00
hunksInRows :: [Row (SplitDiff a Info)] -> [Hunk (SplitDiff a Info)]
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)])
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)
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
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)
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)