Skip to content

Commit 9ed8ec8

Browse files
committed
Fix (<>) for PatchMapWithPatchingMove
There were situations in which it would generate fixups that it would then refuse to apply
1 parent 07c115a commit 9ed8ec8

File tree

1 file changed

+54
-22
lines changed

1 file changed

+54
-22
lines changed

src/Data/Patch/MapWithPatchingMove.hs

+54-22
Original file line numberDiff line numberDiff line change
@@ -382,46 +382,78 @@ instance ( Ord k
382382
, DecidablyEmpty p
383383
, Patch p
384384
) => Semigroup (PatchMapWithPatchingMove k p) where
385-
PatchMapWithPatchingMove ma <> PatchMapWithPatchingMove mb = PatchMapWithPatchingMove m
385+
PatchMapWithPatchingMove mNew <> PatchMapWithPatchingMove mOld = PatchMapWithPatchingMove m
386386
where
387-
connections = Map.toList $ Map.intersectionWithKey (\_ a b -> (_nodeInfo_to a, _nodeInfo_from b)) ma mb
388-
h :: (k, (Maybe k, From k p)) -> [(k, Fixup k p)]
389-
h (_, (mToAfter, editBefore)) = case (mToAfter, editBefore) of
387+
connections = Map.elems $ Map.intersectionWithKey (\_ new old -> (_nodeInfo_to new, _nodeInfo_from old)) mNew mOld
388+
h :: (Maybe k, From k p) -> [(k, Fixup k p)]
389+
h = \case
390390
(Just toAfter, From_Move fromBefore p)
391391
| fromBefore == toAfter && isEmpty p
392-
-> [(toAfter, Fixup_Delete)]
392+
-> [ (toAfter, Fixup_Delete)
393+
]
393394
| otherwise
394-
-> [ (toAfter, Fixup_Update (This editBefore))
395-
, (fromBefore, Fixup_Update (That mToAfter))
395+
-> [ (toAfter, Fixup_Update (This (From_Move fromBefore p)))
396+
, (fromBefore, Fixup_Update (That (Just toAfter)))
396397
]
397-
(Nothing, From_Move fromBefore _) -> [(fromBefore, Fixup_Update (That mToAfter))] -- The item is destroyed in the second patch, so indicate that it is destroyed in the source map
398-
(Just toAfter, _) -> [(toAfter, Fixup_Update (This editBefore))]
398+
(Nothing, From_Move fromBefore _) -> [(fromBefore, Fixup_Update (That Nothing))] -- The item is destroyed in the second patch, so indicate that it is destroyed in the source map
399+
(Just toAfter, editBefore) -> [(toAfter, Fixup_Update (This editBefore))]
399400
(Nothing, _) -> []
400-
mergeFixups _ Fixup_Delete Fixup_Delete = Fixup_Delete
401-
mergeFixups _ (Fixup_Update a) (Fixup_Update b)
401+
mergeFixups Fixup_Delete Fixup_Delete = Fixup_Delete
402+
mergeFixups (Fixup_Update a) (Fixup_Update b)
402403
| This x <- a, That y <- b
403404
= Fixup_Update $ These x y
404405
| That y <- a, This x <- b
405406
= Fixup_Update $ These x y
406-
mergeFixups _ _ _ = error "PatchMapWithPatchingMove: incompatible fixups"
407-
fixups = Map.fromListWithKey mergeFixups $ concatMap h connections
408-
combineNodeInfos _ nia nib = NodeInfo
409-
{ _nodeInfo_from = _nodeInfo_from nia
410-
, _nodeInfo_to = _nodeInfo_to nib
407+
mergeFixups _ _ = error "PatchMapWithPatchingMove: incompatible fixups"
408+
fixups = Map.fromListWithKey (\_ -> mergeFixups) $ concatMap h connections
409+
combineNodeInfos niNew niOld = NodeInfo
410+
{ _nodeInfo_from = _nodeInfo_from niNew
411+
, _nodeInfo_to = _nodeInfo_to niOld
411412
}
412-
applyFixup _ ni = \case
413+
applyFixup ni = \case
413414
Fixup_Delete -> Nothing
414415
Fixup_Update u -> Just $ NodeInfo
415416
{ _nodeInfo_from = case _nodeInfo_from ni of
416-
f@(From_Move _ p') -> case getHere u of -- The `from` fixup comes from the "old" patch
417-
Nothing -> f -- If there's no `from` fixup, just use the "new" `from`
417+
-- The new patch has a Move, so it could be affected by the
418+
-- corresponding From in the old patch. If that From exists, then
419+
-- it is in the fixup here.
420+
f@(From_Move _ p') -> case getHere u of
421+
-- If there's no `From` fixup, just use the "new" `From`
422+
Nothing -> f
423+
-- If there's a `From` fixup which is an Insert, we can just apply
424+
-- our patch to that and turn ourselves into an insert.
418425
Just (From_Insert v) -> From_Insert $ applyAlways p' v
426+
-- If there's a `From` fixup which is a Delete, then we can throw
427+
-- our patch away because there's nothing to apply it to and
428+
-- become a Delete ourselves.
419429
Just From_Delete -> From_Delete
430+
-- If there's a `From` fixup which is a Move, we need to apply
431+
-- both the old patch and the new patch (in that order) to the
432+
-- value, so we append the patches here.
420433
Just (From_Move oldKey p) -> From_Move oldKey $ p' <> p
421-
_ -> error "PatchMapWithPatchingMove: fixup for non-move From"
422-
, _nodeInfo_to = fromMaybe (_nodeInfo_to ni) $ getThere u
434+
-- If the new patch has an Insert, it doesn't care what the fixup
435+
-- value is, because it will overwrite it anyway.
436+
f@(From_Insert _) -> f
437+
-- If the new patch has an Delete, it doesn't care what the fixup
438+
-- value is, because it will overwrite it anyway.
439+
f@From_Delete -> f
440+
, _nodeInfo_to = case _nodeInfo_to ni of
441+
-- The old patch deletes this data, so we must delete it as well.
442+
-- According to the code above, any time we have this situation we
443+
-- should also have `getThere u == Nothing` because a fixup
444+
-- shouldn't be generated.
445+
Nothing -> Nothing
446+
-- The old patch sends the value to oldToAfter
447+
Just oldToAfter -> case getThere u of
448+
-- If there is no fixup, that should mean that the new patch
449+
-- doesn't do anything with the value in oldToAfter, so we still
450+
-- send it to oldToAfter
451+
Nothing -> Just oldToAfter
452+
-- If there is a fixup, it should tell us where the new patch
453+
-- sends the value at key oldToAfter. We send our value there.
454+
Just mNewToAfter -> mNewToAfter
423455
}
424-
m = Map.differenceWithKey applyFixup (Map.unionWithKey combineNodeInfos ma mb) fixups
456+
m = Map.differenceWithKey (\_ -> applyFixup) (Map.unionWith combineNodeInfos mNew mOld) fixups
425457
getHere :: These a b -> Maybe a
426458
getHere = \case
427459
This a -> Just a

0 commit comments

Comments
 (0)