1
1
mirror of https://github.com/github/semantic.git synced 2024-12-27 17:05:33 +03:00
This commit is contained in:
Rob Rix 2017-11-21 15:56:34 -05:00
parent 4aa083332c
commit 4b07ad44ac

View File

@ -19,9 +19,11 @@ import Data.Record
import Data.Semigroup ((<>)) import Data.Semigroup ((<>))
import qualified Data.Source as Source import qualified Data.Source as Source
import Data.SplitDiff import Data.SplitDiff
import qualified Data.Syntax as Syntax
import Data.Term import Data.Term
import qualified Data.Text as Text import qualified Data.Text as Text
import Data.These import Data.These
import Data.Union
import Test.Hspec (Spec, describe, it, parallel) import Test.Hspec (Spec, describe, it, parallel)
import Test.Hspec.Expectations.Pretty import Test.Hspec.Expectations.Pretty
import Test.Hspec.LeanCheck import Test.Hspec.LeanCheck
@ -63,13 +65,13 @@ spec = parallel $ do
describe "alignDiff" $ do describe "alignDiff" $ do
it "aligns identical branches on a single line" $ it "aligns identical branches on a single line" $
let sources = both (Source.fromText "[ foo ]") (Source.fromText "[ foo ]") in let sources = both (Source.fromText "[ foo ]") (Source.fromText "[ foo ]") in
align sources ((info 0 7, info 0 7) `merge` [ (info 2 5, info 2 5) `merge` Leaf "foo" ]) `shouldBe` prettyDiff sources align sources ((info 0 7, info 0 7) `merge` [ (info 2 5, info 2 5) `merge` inj (Syntax.Identifier "foo") ]) `shouldBe` prettyDiff sources
[ Join (These (wrap $ info 0 7 `In` [ wrap $ info 2 5 `In` [] ]) [ Join (These (wrap $ info 0 7 `In` [ wrap $ info 2 5 `In` [] ])
(wrap $ info 0 7 `In` [ wrap $ info 2 5 `In` [] ])) ] (wrap $ info 0 7 `In` [ wrap $ info 2 5 `In` [] ])) ]
it "aligns identical branches spanning multiple lines" $ it "aligns identical branches spanning multiple lines" $
let sources = both (Source.fromText "[\nfoo\n]") (Source.fromText "[\nfoo\n]") in let sources = both (Source.fromText "[\nfoo\n]") (Source.fromText "[\nfoo\n]") in
align sources ((info 0 7, info 0 7) `merge` [ (info 2 5, info 2 5) `merge` Leaf "foo" ]) `shouldBe` prettyDiff sources align sources ((info 0 7, info 0 7) `merge` [ (info 2 5, info 2 5) `merge` inj (Syntax.Identifier "foo") ]) `shouldBe` prettyDiff sources
[ Join (These (wrap $ info 0 2 `In` []) [ Join (These (wrap $ info 0 2 `In` [])
(wrap $ info 0 2 `In` [])) (wrap $ info 0 2 `In` []))
, Join (These (wrap $ info 2 6 `In` [ wrap $ info 2 5 `In` [] ]) , Join (These (wrap $ info 2 6 `In` [ wrap $ info 2 5 `In` [] ])
@ -80,7 +82,7 @@ spec = parallel $ do
it "aligns reformatted branches" $ it "aligns reformatted branches" $
let sources = both (Source.fromText "[ foo ]") (Source.fromText "[\nfoo\n]") in let sources = both (Source.fromText "[ foo ]") (Source.fromText "[\nfoo\n]") in
align sources ((info 0 7, info 0 7) `merge` [ (info 2 5, info 2 5) `merge` Leaf "foo" ]) `shouldBe` prettyDiff sources align sources ((info 0 7, info 0 7) `merge` [ (info 2 5, info 2 5) `merge` inj (Syntax.Identifier "foo") ]) `shouldBe` prettyDiff sources
[ Join (That (wrap $ info 0 2 `In` [])) [ Join (That (wrap $ info 0 2 `In` []))
, Join (These (wrap $ info 0 7 `In` [ wrap $ info 2 5 `In` [] ]) , Join (These (wrap $ info 0 7 `In` [ wrap $ info 2 5 `In` [] ])
(wrap $ info 2 6 `In` [ wrap $ info 2 5 `In` [] ])) (wrap $ info 2 6 `In` [ wrap $ info 2 5 `In` [] ]))
@ -89,7 +91,7 @@ spec = parallel $ do
it "aligns nodes following reformatted branches" $ it "aligns nodes following reformatted branches" $
let sources = both (Source.fromText "[ foo ]\nbar\n") (Source.fromText "[\nfoo\n]\nbar\n") in let sources = both (Source.fromText "[ foo ]\nbar\n") (Source.fromText "[\nfoo\n]\nbar\n") in
align sources ((info 0 12, info 0 12) `merge` [ (info 0 7, info 0 7) `merge` [ (info 2 5, info 2 5) `merge` Leaf "foo" ], (info 8 11, info 8 11) `merge` Leaf "bar" ]) `shouldBe` prettyDiff sources align sources ((info 0 12, info 0 12) `merge` [ (info 0 7, info 0 7) `merge` [ (info 2 5, info 2 5) `merge` inj (Syntax.Identifier "foo") ], (info 8 11, info 8 11) `merge` inj (Syntax.Identifier "bar") ]) `shouldBe` prettyDiff sources
[ Join (That (wrap $ info 0 2 `In` [ wrap $ info 0 2 `In` [] ])) [ Join (That (wrap $ info 0 2 `In` [ wrap $ info 0 2 `In` [] ]))
, Join (These (wrap $ info 0 8 `In` [ wrap $ info 0 7 `In` [ wrap $ info 2 5 `In` [] ] ]) , Join (These (wrap $ info 0 8 `In` [ wrap $ info 0 7 `In` [ wrap $ info 2 5 `In` [] ] ])
(wrap $ info 2 6 `In` [ wrap $ info 2 6 `In` [ wrap $ info 2 5 `In` [] ] ])) (wrap $ info 2 6 `In` [ wrap $ info 2 6 `In` [ wrap $ info 2 5 `In` [] ] ]))
@ -102,12 +104,12 @@ spec = parallel $ do
it "aligns identical branches with multiple children on the same line" $ it "aligns identical branches with multiple children on the same line" $
let sources = pure (Source.fromText "[ foo, bar ]") in let sources = pure (Source.fromText "[ foo, bar ]") in
align sources ((info 0 12, info 0 12) `merge` [ (info 2 5, info 2 5) `merge` Leaf "foo", (info 7 10, info 7 10) `merge` Leaf "bar" ]) `shouldBe` prettyDiff sources align sources ((info 0 12, info 0 12) `merge` [ (info 2 5, info 2 5) `merge` inj (Syntax.Identifier "foo"), (info 7 10, info 7 10) `merge` inj (Syntax.Identifier "bar") ]) `shouldBe` prettyDiff sources
[ Join (runBothWith These (pure (wrap $ info 0 12 `In` [ wrap $ info 2 5 `In` [], wrap $ info 7 10 `In` [] ])) ) ] [ Join (runBothWith These (pure (wrap $ info 0 12 `In` [ wrap $ info 2 5 `In` [], wrap $ info 7 10 `In` [] ])) ) ]
it "aligns insertions" $ it "aligns insertions" $
let sources = both (Source.fromText "a") (Source.fromText "a\nb") in let sources = both (Source.fromText "a") (Source.fromText "a\nb") in
align sources ((info 0 1, info 0 3) `merge` [ (info 0 1, info 0 1) `merge` Leaf "a", inserting (Term (info 2 3 `In` Leaf "b")) ]) `shouldBe` prettyDiff sources align sources ((info 0 1, info 0 3) `merge` [ (info 0 1, info 0 1) `merge` inj (Syntax.Identifier "a"), inserting (termIn (info 2 3) inj (Syntax.Identifier "b")) ]) `shouldBe` prettyDiff sources
[ Join (These (wrap $ info 0 1 `In` [ wrap $ info 0 1 `In` [] ]) [ Join (These (wrap $ info 0 1 `In` [ wrap $ info 0 1 `In` [] ])
(wrap $ info 0 2 `In` [ wrap $ info 0 1 `In` [] ])) (wrap $ info 0 2 `In` [ wrap $ info 0 1 `In` [] ]))
, Join (That (wrap $ info 2 3 `In` [ pure (SplitInsert (Term (info 2 3 `In` []))) ])) , Join (That (wrap $ info 2 3 `In` [ pure (SplitInsert (Term (info 2 3 `In` []))) ]))
@ -115,19 +117,19 @@ spec = parallel $ do
it "aligns total insertions" $ it "aligns total insertions" $
let sources = both (Source.fromText "") (Source.fromText "a") in let sources = both (Source.fromText "") (Source.fromText "a") in
align sources (inserting (Term (info 0 1 `In` Leaf "a"))) `shouldBe` prettyDiff sources align sources (inserting (Term (info 0 1 `In` Syntax.Identifier "a"))) `shouldBe` prettyDiff sources
[ Join (That (pure (SplitInsert (Term (info 0 1 `In` []))))) ] [ Join (That (pure (SplitInsert (Term (info 0 1 `In` []))))) ]
it "aligns insertions into empty branches" $ it "aligns insertions into empty branches" $
let sources = both (Source.fromText "[ ]") (Source.fromText "[a]") in let sources = both (Source.fromText "[ ]") (Source.fromText "[a]") in
align sources ((info 0 3, info 0 3) `merge` [ inserting (Term (info 1 2 `In` Leaf "a")) ]) `shouldBe` prettyDiff sources align sources ((info 0 3, info 0 3) `merge` [ inserting (termIn (info 1 2) (inj (Syntax.Identifier "a"))) ]) `shouldBe` prettyDiff sources
[ Join (That (wrap $ info 0 3 `In` [ pure (SplitInsert (Term (info 1 2 `In` []))) ])) [ Join (That (wrap $ info 0 3 `In` [ pure (SplitInsert (Term (info 1 2 `In` []))) ]))
, Join (This (wrap $ info 0 3 `In` [])) , Join (This (wrap $ info 0 3 `In` []))
] ]
it "aligns symmetrically following insertions" $ it "aligns symmetrically following insertions" $
let sources = both (Source.fromText "a\nc") (Source.fromText "a\nb\nc") in let sources = both (Source.fromText "a\nc") (Source.fromText "a\nb\nc") in
align sources ((info 0 3, info 0 5) `merge` [ (info 0 1, info 0 1) `merge` Leaf "a", inserting (Term (info 2 3 `In` Leaf "b")), (info 2 3, info 4 5) `merge` Leaf "c" ]) align sources ((info 0 3, info 0 5) `merge` [ (info 0 1, info 0 1) `merge` Syntax.Identifier "a", inserting (Term (info 2 3 `In` Syntax.Identifier "b")), (info 2 3, info 4 5) `merge` Syntax.Identifier "c" ])
`shouldBe` prettyDiff sources `shouldBe` prettyDiff sources
[ Join (These (wrap $ info 0 2 `In` [ wrap $ info 0 1 `In` [] ]) [ Join (These (wrap $ info 0 2 `In` [ wrap $ info 0 1 `In` [] ])
(wrap $ info 0 2 `In` [ wrap $ info 0 1 `In` [] ])) (wrap $ info 0 2 `In` [ wrap $ info 0 1 `In` [] ]))
@ -138,13 +140,13 @@ spec = parallel $ do
it "symmetrical nodes force the alignment of asymmetrical nodes on both sides" $ it "symmetrical nodes force the alignment of asymmetrical nodes on both sides" $
let sources = both (Source.fromText "[ a, b ]") (Source.fromText "[ b, c ]") in let sources = both (Source.fromText "[ a, b ]") (Source.fromText "[ b, c ]") in
align sources ((info 0 8, info 0 8) `merge` [ deleting (Term (info 2 3 `In` Leaf "a")), (info 5 6, info 2 3) `merge` Leaf "b", inserting (Term (info 5 6 `In` Leaf "c")) ]) `shouldBe` prettyDiff sources align sources ((info 0 8, info 0 8) `merge` [ deleting (termIn (info 2 3) (inj (Syntax.Identifier "a"))), (info 5 6, info 2 3) `merge` inj (Syntax.Identifier "b"), inserting (Term (info 5 6 `In` Syntax.Identifier "c")) ]) `shouldBe` prettyDiff sources
[ Join (These (wrap $ info 0 8 `In` [ pure (SplitDelete (Term (info 2 3 `In` []))), wrap $ info 5 6 `In` [] ]) [ Join (These (wrap $ info 0 8 `In` [ pure (SplitDelete (termIn (info 2 3) (inj []))), wrap $ info 5 6 `In` [] ])
(wrap $ info 0 8 `In` [ wrap $ info 2 3 `In` [], pure (SplitInsert (Term (info 5 6 `In` []))) ])) ] (wrap $ info 0 8 `In` [ wrap $ info 2 3 `In` [], pure (SplitInsert (Term (info 5 6 `In` []))) ])) ]
it "when one of two symmetrical nodes must be split, splits the latter" $ it "when one of two symmetrical nodes must be split, splits the latter" $
let sources = both (Source.fromText "[ a, b ]") (Source.fromText "[ a\n, b\n]") in let sources = both (Source.fromText "[ a, b ]") (Source.fromText "[ a\n, b\n]") in
align sources ((info 0 8, info 0 9) `merge` [ (info 2 3, info 2 3) `merge` Leaf "a", (info 5 6, info 6 7) `merge` Leaf "b" ]) `shouldBe` prettyDiff sources align sources ((info 0 8, info 0 9) `merge` [ (info 2 3, info 2 3) `merge` inj (Syntax.Identifier "a"), (info 5 6, info 6 7) `merge` inj (Syntax.Identifier "b") ]) `shouldBe` prettyDiff sources
[ Join (These (wrap $ info 0 8 `In` [ wrap $ info 2 3 `In` [], wrap $ info 5 6 `In` [] ]) [ Join (These (wrap $ info 0 8 `In` [ wrap $ info 2 3 `In` [], wrap $ info 5 6 `In` [] ])
(wrap $ info 0 4 `In` [ wrap $ info 2 3 `In` [] ])) (wrap $ info 0 4 `In` [ wrap $ info 2 3 `In` [] ]))
, Join (That (wrap $ info 4 8 `In` [ wrap $ info 6 7 `In` [] ])) , Join (That (wrap $ info 4 8 `In` [ wrap $ info 6 7 `In` [] ]))
@ -153,14 +155,14 @@ spec = parallel $ do
it "aligns deletions before insertions" $ it "aligns deletions before insertions" $
let sources = both (Source.fromText "[ a ]") (Source.fromText "[ b ]") in let sources = both (Source.fromText "[ a ]") (Source.fromText "[ b ]") in
align sources ((info 0 5, info 0 5) `merge` [ deleting (Term (info 2 3 `In` Leaf "a")), inserting (Term (info 2 3 `In` Leaf "b")) ]) `shouldBe` prettyDiff sources align sources ((info 0 5, info 0 5) `merge` [ deleting (termIn (info 2 3) (inj (Syntax.Identifier "a"))), inserting (termIn (info 2 3) (inj (Syntax.Identifier "b"))) ]) `shouldBe` prettyDiff sources
[ Join (This (wrap $ info 0 5 `In` [ pure (SplitDelete (Term (info 2 3 `In` []))) ])) [ Join (This (wrap $ info 0 5 `In` [ pure (SplitDelete (Term (info 2 3 `In` []))) ]))
, Join (That (wrap $ info 0 5 `In` [ pure (SplitInsert (Term (info 2 3 `In` []))) ])) , Join (That (wrap $ info 0 5 `In` [ pure (SplitInsert (Term (info 2 3 `In` []))) ]))
] ]
it "aligns context-only lines symmetrically" $ it "aligns context-only lines symmetrically" $
let sources = both (Source.fromText "[\n a\n,\n b\n]") (Source.fromText "[\n a, b\n\n\n]") in let sources = both (Source.fromText "[\n a\n,\n b\n]") (Source.fromText "[\n a, b\n\n\n]") in
align sources ((info 0 13, info 0 12) `merge` [ (info 4 5, info 4 5) `merge` Leaf "a", (info 10 11, info 7 8) `merge` Leaf "b" ]) `shouldBe` prettyDiff sources align sources ((info 0 13, info 0 12) `merge` [ (info 4 5, info 4 5) `merge` inj (Syntax.Identifier "a"), (info 10 11, info 7 8) `merge` inj (Syntax.Identifier "b") ]) `shouldBe` prettyDiff sources
[ Join (These (wrap $ info 0 2 `In` []) [ Join (These (wrap $ info 0 2 `In` [])
(wrap $ info 0 2 `In` [])) (wrap $ info 0 2 `In` []))
, Join (These (wrap $ info 2 6 `In` [ wrap $ info 4 5 `In` [] ]) , Join (These (wrap $ info 2 6 `In` [ wrap $ info 4 5 `In` [] ])
@ -175,7 +177,7 @@ spec = parallel $ do
it "aligns asymmetrical nodes preceding their symmetrical siblings conservatively" $ it "aligns asymmetrical nodes preceding their symmetrical siblings conservatively" $
let sources = both (Source.fromText "[ b, c ]") (Source.fromText "[ a\n, c\n]") in let sources = both (Source.fromText "[ b, c ]") (Source.fromText "[ a\n, c\n]") in
align sources ((info 0 8, info 0 9) `merge` [ inserting (Term (info 2 3 `In` Leaf "a")), deleting (Term (info 2 3 `In` Leaf "b")), (info 5 6, info 6 7) `merge` Leaf "c" ]) `shouldBe` prettyDiff sources align sources ((info 0 8, info 0 9) `merge` [ inserting (Term (info 2 3 `In` Syntax.Identifier "a")), deleting (Term (info 2 3 `In` Syntax.Identifier "b")), (info 5 6, info 6 7) `merge` Syntax.Identifier "c" ]) `shouldBe` prettyDiff sources
[ Join (That (wrap $ info 0 4 `In` [ pure (SplitInsert (Term (info 2 3 `In` []))) ])) [ Join (That (wrap $ info 0 4 `In` [ pure (SplitInsert (Term (info 2 3 `In` []))) ]))
, Join (These (wrap $ info 0 8 `In` [ pure (SplitDelete (Term (info 2 3 `In` []))), wrap $ info 5 6 `In` [] ]) , Join (These (wrap $ info 0 8 `In` [ pure (SplitDelete (Term (info 2 3 `In` []))), wrap $ info 5 6 `In` [] ])
(wrap $ info 4 8 `In` [ wrap $ info 6 7 `In` [] ])) (wrap $ info 4 8 `In` [ wrap $ info 6 7 `In` [] ]))
@ -184,7 +186,7 @@ spec = parallel $ do
it "aligns symmetrical reformatted nodes" $ it "aligns symmetrical reformatted nodes" $
let sources = both (Source.fromText "a [ b ]\nc") (Source.fromText "a [\nb\n]\nc") in let sources = both (Source.fromText "a [ b ]\nc") (Source.fromText "a [\nb\n]\nc") in
align sources ((info 0 9, info 0 9) `merge` [ (info 0 1, info 0 1) `merge` Leaf "a", (info 2 7, info 2 7) `merge` [ (info 4 5, info 4 5) `merge` Leaf "b" ], (info 8 9, info 8 9) `merge` Leaf "c" ]) `shouldBe` prettyDiff sources align sources ((info 0 9, info 0 9) `merge` [ (info 0 1, info 0 1) `merge` Syntax.Identifier "a", (info 2 7, info 2 7) `merge` [ (info 4 5, info 4 5) `merge` Syntax.Identifier "b" ], (info 8 9, info 8 9) `merge` Syntax.Identifier "c" ]) `shouldBe` prettyDiff sources
[ Join (These (wrap $ info 0 8 `In` [ wrap $ info 0 1 `In` [], wrap $ info 2 7 `In` [ wrap $ info 4 5 `In` [] ] ]) [ Join (These (wrap $ info 0 8 `In` [ wrap $ info 0 1 `In` [], wrap $ info 2 7 `In` [ wrap $ info 4 5 `In` [] ] ])
(wrap $ info 0 4 `In` [ wrap $ info 0 1 `In` [], wrap $ info 2 4 `In` [] ])) (wrap $ info 0 4 `In` [ wrap $ info 0 1 `In` [], wrap $ info 2 4 `In` [] ]))
, Join (That (wrap $ info 4 6 `In` [ wrap $ info 4 6 `In` [ wrap $ info 4 5 `In` [] ] ])) , Join (That (wrap $ info 4 6 `In` [ wrap $ info 4 6 `In` [ wrap $ info 4 5 `In` [] ] ]))
@ -257,7 +259,7 @@ instance Listable BranchElement where
counts :: [Join These (Int, a)] -> Both Int counts :: [Join These (Int, a)] -> Both Int
counts numbered = fromMaybe 0 . getLast . mconcat . fmap Last <$> Join (unalign (runJoin . fmap fst <$> numbered)) counts numbered = fromMaybe 0 . getLast . mconcat . fmap Last <$> Join (unalign (runJoin . fmap fst <$> numbered))
align :: Both Source.Source -> Diff Syntax (Record '[Range]) (Record '[Range]) -> PrettyDiff (SplitDiff [] (Record '[Range])) align :: Both Source.Source -> Diff ListableSyntax (Record '[Range]) (Record '[Range]) -> PrettyDiff (SplitDiff [] (Record '[Range]))
align sources = PrettyDiff sources . fmap (fmap (getRange &&& id)) . alignDiff sources align sources = PrettyDiff sources . fmap (fmap (getRange &&& id)) . alignDiff sources
info :: Int -> Int -> Record '[Range] info :: Int -> Int -> Record '[Range]