1
1
mirror of https://github.com/github/semantic.git synced 2024-12-29 01:42:43 +03:00
semantic/src/PatchOutput.hs

104 lines
4.5 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
2015-12-31 01:42:18 +03:00
import Source hiding ((++), break)
2015-12-25 01:41:45 +03:00
import Split
2015-12-30 23:56:12 +03:00
import Control.Arrow
import Control.Comonad.Cofree
import Control.Monad.Free
2015-12-30 23:56:12 +03:00
import Data.Monoid
2015-12-18 01:22:53 +03:00
2015-12-30 23:38:53 +03:00
patch :: 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-31 00:24:33 +03:00
data Hunk a = Hunk { offset :: (Sum Int, Sum 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-31 00:25:18 +03:00
hunkLength :: Hunk a -> (Sum Int, Sum Int)
hunkLength hunk = mconcat $ (changeLength <$> changes hunk) <> (rowLength <$> trailingContext hunk)
changeLength :: Change a -> (Sum Int, Sum Int)
changeLength change = mconcat $ (rowLength <$> context change) <> (rowLength <$> contents change)
2015-12-30 23:56:12 +03:00
2015-12-30 23:56:03 +03:00
rowLength :: Row a -> (Sum Int, Sum Int)
rowLength (Row a b) = (lineLength a, lineLength b)
2015-12-30 23:55:55 +03:00
lineLength :: Line a -> Sum Int
lineLength EmptyLine = 0
lineLength _ = 1
2015-12-30 23:38:53 +03:00
showHunk :: (Source Char, Source Char) -> Hunk (SplitDiff a Info) -> String
2015-12-30 23:38:11 +03:00
showHunk sources hunk = header hunk ++ concat (showChange sources <$> changes hunk) ++ concat (showRow sources <$> trailingContext hunk)
2015-12-30 23:38:53 +03:00
showChange :: (Source Char, Source Char) -> Change (SplitDiff a Info) -> String
2015-12-30 23:38:11 +03:00
showChange sources change = concat (showRow sources <$> context change) ++ concat (showRow sources <$> contents change)
2015-12-30 23:27:04 +03:00
2015-12-30 23:38:53 +03:00
showRow :: (Source Char, Source Char) -> Row (SplitDiff leaf Info) -> String
showRow sources (Row lineA lineB) = if stringA == stringB
2015-12-31 00:03:38 +03:00
then maybe "" (' ' :) stringB
else maybe "" ('-' :) stringA ++ maybe "" ('+' :) stringB
2015-12-30 23:37:04 +03:00
where stringA = showLine (fst sources) lineA
stringB = showLine (snd sources) lineB
2015-12-30 23:27:00 +03:00
2015-12-31 00:03:38 +03:00
showLine :: Source Char -> Line (SplitDiff leaf Info) -> Maybe String
showLine _ EmptyLine = Nothing
showLine source line = Just . toString . (`slice` source) . unionRanges $ getRange <$> unLine line
2015-12-30 23:32:51 +03:00
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
2015-12-31 00:05:42 +03:00
header hunk = "@@ -" ++ show offsetA ++ "," ++ show lengthA ++ " +" ++ show offsetB ++ "," ++ show lengthB ++ " @@\n"
2015-12-31 00:25:18 +03:00
where (lengthA, lengthB) = getSum *** getSum $ hunkLength hunk
2015-12-31 00:24:33 +03:00
(offsetA, offsetB) = getSum *** getSum $ offset hunk
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)]
2015-12-31 00:39:23 +03:00
hunks diff sources = hunksInRows (1, 1) . fst $ splitDiffByLines diff (0, 0) sources
hunksInRows :: (Sum Int, Sum Int) -> [Row (SplitDiff a Info)] -> [Hunk (SplitDiff a Info)]
hunksInRows start rows = case nextHunk start rows of
Nothing -> []
Just (hunk, rest) -> hunk : hunksInRows (offset hunk <> hunkLength hunk) rest
nextHunk :: (Sum Int, Sum Int) -> [Row (SplitDiff a Info)] -> Maybe (Hunk (SplitDiff a Info), [Row (SplitDiff a Info)])
nextHunk start rows = case nextChange start rows of
Nothing -> Nothing
Just (offset, change, rest) -> let (changes, rest') = contiguousChanges rest in Just (Hunk offset (change : changes) $ take 3 rest', drop 3 rest')
2015-12-31 02:06:47 +03:00
where contiguousChanges rows = case break rowHasChanges (take 7 rows) of
(_, []) -> ([], rows)
(context, changes) -> case changeIncludingContext context changes of
2015-12-31 01:54:27 +03:00
Nothing -> ([], rows)
Just (change, rest) -> let (changes, rest') = contiguousChanges rest in (change : changes, rest')
nextChange :: (Sum Int, Sum Int) -> [Row (SplitDiff a Info)] -> Maybe ((Sum Int, Sum Int), Change (SplitDiff a Info), [Row (SplitDiff a Info)])
nextChange start rows = case changeIncludingContext leadingContext changes of
Nothing -> Nothing
Just (change, afterChanges) -> Just (start <> mconcat (rowLength <$> skippedContext), change, afterChanges)
where (leadingRows, changes) = break rowHasChanges rows
2015-12-31 00:33:45 +03:00
(skippedContext, leadingContext) = splitAt (max (length leadingRows - 3) 0) leadingRows
changeIncludingContext :: [Row (SplitDiff a Info)] -> [Row (SplitDiff a Info)] -> Maybe (Change (SplitDiff a Info), [Row (SplitDiff a Info)])
changeIncludingContext leadingContext rows = case changes of
[] -> Nothing
_ -> Just (Change leadingContext changes, afterChanges)
where (changes, afterChanges) = span rowHasChanges rows
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)