mirror of
https://github.com/github/semantic.git
synced 2024-12-18 12:21:57 +03:00
Merge remote-tracking branch 'origin/master' into git-diff
This commit is contained in:
commit
724910bf7a
@ -19,6 +19,7 @@ import qualified Data.Text.Lazy.IO as TextIO
|
|||||||
import qualified PatchOutput
|
import qualified PatchOutput
|
||||||
import Interpreter
|
import Interpreter
|
||||||
import qualified Parsers as P
|
import qualified Parsers as P
|
||||||
|
import Rainbow
|
||||||
|
|
||||||
-- | The available types of diff rendering.
|
-- | The available types of diff rendering.
|
||||||
data Format = Unified | Split | Patch
|
data Format = Unified | Split | Patch
|
||||||
@ -51,9 +52,10 @@ readAndTranscodeFile path = do
|
|||||||
|
|
||||||
printDiff :: DiffArguments -> (Source Char, Source Char) -> (Term T.Text Info, Term T.Text Info) -> IO ()
|
printDiff :: DiffArguments -> (Source Char, Source Char) -> (Term T.Text Info, Term T.Text Info) -> IO ()
|
||||||
printDiff arguments (aSource, bSource) (aTerm, bTerm) = case format arguments of
|
printDiff arguments (aSource, bSource) (aTerm, bTerm) = case format arguments of
|
||||||
Unified -> do
|
Unified -> put $ unified diff (aSource, bSource)
|
||||||
rendered <- unified diff (aSource, bSource)
|
where put chunks = do
|
||||||
B1.putStr rendered
|
renderer <- byteStringMakerFromEnvironment
|
||||||
|
B1.putStr $ mconcat $ chunksToByteStrings renderer chunks
|
||||||
Split -> do
|
Split -> do
|
||||||
rendered <- split diff (aSource, bSource)
|
rendered <- split diff (aSource, bSource)
|
||||||
case output arguments of
|
case output arguments of
|
||||||
|
@ -22,6 +22,6 @@ lineByLineParser input = return . root . Indexed $ case foldl' annotateLeaves ([
|
|||||||
leaf charIndex line = Info (Range charIndex $ charIndex + T.length line) mempty :< Leaf line
|
leaf charIndex line = Info (Range charIndex $ charIndex + T.length line) mempty :< Leaf line
|
||||||
annotateLeaves (accum, charIndex) line =
|
annotateLeaves (accum, charIndex) line =
|
||||||
(accum ++ [ leaf charIndex (toText line) ]
|
(accum ++ [ leaf charIndex (toText line) ]
|
||||||
, charIndex + length line + 1)
|
, charIndex + length line)
|
||||||
toText = T.pack . Source.toString
|
toText = T.pack . Source.toString
|
||||||
|
|
||||||
|
@ -67,6 +67,7 @@ executable semantic-diff-exe
|
|||||||
, filepath
|
, filepath
|
||||||
, free
|
, free
|
||||||
, optparse-applicative
|
, optparse-applicative
|
||||||
|
, rainbow
|
||||||
, semantic-diff
|
, semantic-diff
|
||||||
, text >= 1.2.1.3
|
, text >= 1.2.1.3
|
||||||
, text-icu
|
, text-icu
|
||||||
@ -106,6 +107,7 @@ executable semantic-diff
|
|||||||
, text-icu
|
, text-icu
|
||||||
, gitlib
|
, gitlib
|
||||||
, gitlib-libgit2
|
, gitlib-libgit2
|
||||||
|
, rainbow
|
||||||
, tagged
|
, tagged
|
||||||
, mtl
|
, mtl
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
|
@ -21,13 +21,15 @@ import Data.Maybe
|
|||||||
-- | Returns whether two terms are comparable
|
-- | Returns whether two terms are comparable
|
||||||
type Comparable a annotation = Term a annotation -> Term a annotation -> Bool
|
type Comparable a annotation = Term a annotation -> Term a annotation -> Bool
|
||||||
|
|
||||||
-- | Diff two terms.
|
-- | Diff two terms, given the default Categorizable.comparable function.
|
||||||
diffTerms :: (Eq a, Eq annotation, Categorizable annotation) => Term a annotation -> Term a annotation -> Diff a annotation
|
diffTerms :: (Eq a, Eq annotation, Categorizable annotation) => Term a annotation -> Term a annotation -> Diff a annotation
|
||||||
diffTerms = interpret comparable
|
diffTerms = interpret comparable
|
||||||
|
|
||||||
|
-- | Diff two terms, given a function that determines whether two terms can be compared.
|
||||||
interpret :: (Eq a, Eq annotation) => Comparable a annotation -> Term a annotation -> Term a annotation -> Diff a annotation
|
interpret :: (Eq a, Eq annotation) => Comparable a annotation -> Term a annotation -> Term a annotation -> Diff a annotation
|
||||||
interpret comparable a b = fromMaybe (Pure $ Replace a b) $ constructAndRun comparable a b
|
interpret comparable a b = fromMaybe (Pure $ Replace a b) $ constructAndRun comparable a b
|
||||||
|
|
||||||
|
-- | A hylomorphism. Given an `a`, unfold and then refold into a `b`.
|
||||||
hylo :: Functor f => (t -> f b -> b) -> (a -> (t, f a)) -> a -> b
|
hylo :: Functor f => (t -> f b -> b) -> (a -> (t, f a)) -> a -> b
|
||||||
hylo down up a = down annotation $ hylo down up <$> syntax where
|
hylo down up a = down annotation $ hylo down up <$> syntax where
|
||||||
(annotation, syntax) = up a
|
(annotation, syntax) = up a
|
||||||
|
@ -10,13 +10,18 @@ import Data.List (uncons)
|
|||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
import Data.Ord (comparing)
|
import Data.Ord (comparing)
|
||||||
|
|
||||||
|
-- | A function that maybe creates a diff from two terms.
|
||||||
type Compare a annotation = Term a annotation -> Term a annotation -> Maybe (Diff a annotation)
|
type Compare a annotation = Term a annotation -> Term a annotation -> Maybe (Diff a annotation)
|
||||||
|
|
||||||
|
-- | A function that computes the cost of a diff.
|
||||||
type Cost a annotation = Diff a annotation -> Integer
|
type Cost a annotation = Diff a annotation -> Integer
|
||||||
|
|
||||||
|
-- | Find the shortest edit script (diff) between two terms given a function to compute the cost.
|
||||||
ses :: Compare a annotation -> Cost a annotation -> [Term a annotation] -> [Term a annotation] -> [Diff a annotation]
|
ses :: Compare a annotation -> Cost a annotation -> [Term a annotation] -> [Term a annotation] -> [Diff a annotation]
|
||||||
ses diffTerms cost as bs = fst <$> evalState diffState Map.empty where
|
ses diffTerms cost as bs = fst <$> evalState diffState Map.empty where
|
||||||
diffState = diffAt diffTerms cost (0, 0) as bs
|
diffState = diffAt diffTerms cost (0, 0) as bs
|
||||||
|
|
||||||
|
-- | Find the shortest edit script between two terms at a given vertex in the edit graph.
|
||||||
diffAt :: Compare a annotation -> Cost a annotation -> (Integer, Integer) -> [Term a annotation] -> [Term a annotation] -> State (Map.Map (Integer, Integer) [(Diff a annotation, Integer)]) [(Diff a annotation, Integer)]
|
diffAt :: Compare a annotation -> Cost a annotation -> (Integer, Integer) -> [Term a annotation] -> [Term a annotation] -> State (Map.Map (Integer, Integer) [(Diff a annotation, Integer)]) [(Diff a annotation, Integer)]
|
||||||
diffAt _ _ _ [] [] = return []
|
diffAt _ _ _ [] [] = return []
|
||||||
diffAt _ cost _ [] bs = return $ foldr toInsertions [] bs where
|
diffAt _ cost _ [] bs = return $ foldr toInsertions [] bs where
|
||||||
@ -46,5 +51,6 @@ diffAt diffTerms cost (i, j) (a : as) (b : bs) = do
|
|||||||
best = minimumBy (comparing costOf)
|
best = minimumBy (comparing costOf)
|
||||||
recur = diffAt diffTerms cost
|
recur = diffAt diffTerms cost
|
||||||
|
|
||||||
|
-- | Prepend a diff to the list with the cumulative cost.
|
||||||
consWithCost :: Cost a annotation -> Diff a annotation -> [(Diff a annotation, Integer)] -> [(Diff a annotation, Integer)]
|
consWithCost :: Cost a annotation -> Diff a annotation -> [(Diff a annotation, Integer)] -> [(Diff a annotation, Integer)]
|
||||||
consWithCost cost diff rest = (diff, cost diff + maybe 0 snd (fst <$> uncons rest)) : rest
|
consWithCost cost diff rest = (diff, cost diff + maybe 0 snd (fst <$> uncons rest)) : rest
|
||||||
|
@ -14,36 +14,45 @@ import Data.List hiding (foldl)
|
|||||||
import qualified Data.OrderedMap as Map
|
import qualified Data.OrderedMap as Map
|
||||||
import Rainbow
|
import Rainbow
|
||||||
|
|
||||||
unified :: Renderer a (IO ByteString)
|
-- | Render a diff with the unified format.
|
||||||
unified diff (before, after) = do
|
unified :: Renderer a [Chunk String]
|
||||||
renderer <- byteStringMakerFromEnvironment
|
unified diff (before, after) = fst $ iter g mapped
|
||||||
return . mconcat . chunksToByteStrings renderer . fst $ iter g mapped where
|
where
|
||||||
mapped = fmap (unifiedPatch &&& range) diff
|
mapped = fmap (unifiedPatch &&& range) diff
|
||||||
|
toChunk = chunk . toList
|
||||||
g (Annotated (_, info) syntax) = annotationAndSyntaxToChunks after info syntax
|
g (Annotated (_, info) syntax) = annotationAndSyntaxToChunks after info syntax
|
||||||
annotationAndSyntaxToChunks source (Info range _) (Leaf _) = (pure . chunk . toList $ slice range source, Just range)
|
-- | Render an annotation and syntax into a list of chunks.
|
||||||
|
annotationAndSyntaxToChunks source (Info range _) (Leaf _) = ([ toChunk $ slice range source ], Just range)
|
||||||
annotationAndSyntaxToChunks source (Info range _) (Indexed i) = (unifiedRange range i source, Just range)
|
annotationAndSyntaxToChunks source (Info range _) (Indexed i) = (unifiedRange range i source, Just range)
|
||||||
annotationAndSyntaxToChunks source (Info range _) (Fixed f) = (unifiedRange range f source, Just range)
|
annotationAndSyntaxToChunks source (Info range _) (Fixed f) = (unifiedRange range f source, Just range)
|
||||||
annotationAndSyntaxToChunks source (Info range _) (Keyed k) = (unifiedRange range (sort $ snd <$> Map.toList k) source, Just range)
|
annotationAndSyntaxToChunks source (Info range _) (Keyed k) = (unifiedRange range (snd <$> Map.toList k) source, Just range)
|
||||||
|
|
||||||
|
-- | Render a Patch into a list of chunks.
|
||||||
unifiedPatch :: Patch (Term a Info) -> [Chunk String]
|
unifiedPatch :: Patch (Term a Info) -> [Chunk String]
|
||||||
unifiedPatch patch = (fore red . bold <$> beforeChunk) <> (fore green . bold <$> afterChunk) where
|
unifiedPatch patch = (fore red . bold <$> beforeChunks) <> (fore green . bold <$> afterChunks)
|
||||||
beforeChunk = maybe [] (change "-" . unifiedTerm before) $ Patch.before patch
|
where
|
||||||
afterChunk = maybe [] (change "+" . unifiedTerm after) $ Patch.after patch
|
beforeChunks = maybe [] (change "-" . unifiedTerm before) $ Patch.before patch
|
||||||
|
afterChunks = maybe [] (change "+" . unifiedTerm after) $ Patch.after patch
|
||||||
|
|
||||||
|
-- | Render the contents of a Term as a series of chunks.
|
||||||
unifiedTerm :: Source Char -> Term a Info -> [Chunk String]
|
unifiedTerm :: Source Char -> Term a Info -> [Chunk String]
|
||||||
|
|
||||||
unifiedTerm source term = fst $ cata (annotationAndSyntaxToChunks source) term
|
unifiedTerm source term = fst $ cata (annotationAndSyntaxToChunks source) term
|
||||||
|
|
||||||
|
-- | Given a range and a list of pairs of chunks and a range, render the
|
||||||
|
-- | entire range from the source as a single list of chunks.
|
||||||
unifiedRange :: Range -> [([Chunk String], Maybe Range)] -> Source Char -> [Chunk String]
|
unifiedRange :: Range -> [([Chunk String], Maybe Range)] -> Source Char -> [Chunk String]
|
||||||
unifiedRange range children source = out <> (pure . chunk . toList $ slice Range { start = previous, end = end range } source) where
|
unifiedRange range children source = out <> [ toChunk $ slice Range { start = previous, end = end range } source ]
|
||||||
(out, previous) = foldl' accumulateContext ([], start range) children
|
where
|
||||||
accumulateContext (out, previous) (child, Just range) = (mconcat [ out, pure . chunk . toList $ slice Range { start = previous, end = start range } source, child ], end range)
|
(out, previous) = foldl' accumulateContext ([], start range) children
|
||||||
accumulateContext (out, previous) (child, _) = (out <> child, previous)
|
accumulateContext (out, previous) (child, Just range) = (out <> [ toChunk $ slice Range { start = previous, end = start range } source ] <> child, end range)
|
||||||
|
accumulateContext (out, previous) (child, _) = (out <> child, previous)
|
||||||
|
|
||||||
|
-- | Return the range of the after side of the patch, or Nothing if it's not a replacement.
|
||||||
range :: Patch (Term a Info) -> Maybe Range
|
range :: Patch (Term a Info) -> Maybe Range
|
||||||
range patch = range . extract <$> after patch where
|
range patch = range . extract <$> after patch where
|
||||||
extract (annotation :< _) = annotation
|
extract (annotation :< _) = annotation
|
||||||
range (Info range _) = range
|
range (Info range _) = range
|
||||||
|
|
||||||
|
-- | Add chunks to the beginning and end of the list with curly braces and the given string.
|
||||||
change :: String -> [Chunk String] -> [Chunk String]
|
change :: String -> [Chunk String] -> [Chunk String]
|
||||||
change bound content = [ chunk "{", chunk bound ] ++ content ++ [ chunk bound, chunk "}" ]
|
change bound content = [ chunk "{", chunk bound ] ++ content ++ [ chunk bound, chunk "}" ]
|
||||||
|
Loading…
Reference in New Issue
Block a user