module Darcs.Patch.Rebase.Item
( RebaseItem(..)
, simplifyPush, simplifyPushes
, countToEdit
) where
import Prelude ()
import Darcs.Prelude
import Darcs.Patch.Commute ( selfCommuter )
import Darcs.Patch.Conflict ( Conflict(..), CommuteNoConflicts(..) )
import Darcs.Patch.Effect ( Effect(..) )
import Darcs.Patch.FileHunk ( IsHunk(..) )
import Darcs.Patch.Format ( PatchListFormat(..) )
import Darcs.Patch.Named ( Named(..), commuterIdNamed )
import Darcs.Patch.Patchy ( Invert(..), Commute(..), Apply(..)
, ShowPatch(..), ReadPatch(..)
, PatchInspect(..)
)
import Darcs.Patch.Prim ( PrimPatchBase, PrimOf, FromPrim(..), FromPrim(..), canonizeFL )
import Darcs.Patch.Rebase.Fixup ( RebaseFixup(..) )
import Darcs.Patch.Rebase.Name
( RebaseName(..)
, commutePrimName, commuteNamePrim
, canonizeNamePair
)
import Darcs.Patch.Repair ( Check(..) )
import Darcs.Patch.Show ( ShowPatchBasic(..) )
import Darcs.Patch.ReadMonads ( ParserM, lexString )
import Darcs.Patch.Witnesses.Eq
import Darcs.Patch.Witnesses.Ordered
import Darcs.Patch.Witnesses.Sealed
import Darcs.Patch.Witnesses.Show
( Show1(..), Show2(..), showsPrec2
, ShowDict(ShowDictClass), appPrec
)
import Darcs.Patch.Witnesses.Unsafe ( unsafeCoerceP )
import qualified Darcs.Util.Diff as D ( DiffAlgorithm )
import Darcs.Util.Printer ( vcat, blueText, ($$), (<+>) )
import Control.Applicative ( (<|>) )
import qualified Data.ByteString as B ( ByteString )
import qualified Data.ByteString.Char8 as BC ( pack )
#include "impossible.h"
data RebaseItem p wX wY where
ToEdit :: Named p wX wY -> RebaseItem p wX wY
Fixup :: RebaseFixup p wX wY -> RebaseItem p wX wY
instance (Show2 p, Show2 (PrimOf p)) => Show (RebaseItem p wX wY) where
showsPrec d (ToEdit p) =
showParen (d > appPrec) $ showString "ToEdit " . showsPrec2 (appPrec + 1) p
showsPrec d (Fixup p) =
showParen (d > appPrec) $ showString "Fixup " . showsPrec2 (appPrec + 1) p
instance (Show2 p, Show2 (PrimOf p)) => Show1 (RebaseItem p wX) where
showDict1 = ShowDictClass
instance (Show2 p, Show2 (PrimOf p)) => Show2 (RebaseItem p) where
showDict2 = ShowDictClass
countToEdit :: FL (RebaseItem p) wX wY -> Int
countToEdit NilFL = 0
countToEdit (ToEdit _ :>: ps) = 1 + countToEdit ps
countToEdit (_ :>: ps) = countToEdit ps
simplifyPush :: (PrimPatchBase p, Commute p, FromPrim p, Effect p)
=> D.DiffAlgorithm -> RebaseFixup p wX wY -> FL (RebaseItem p) wY wZ -> Sealed (FL (RebaseItem p) wX)
simplifyPush _ _f NilFL = Sealed NilFL
simplifyPush da (PrimFixup f1) (Fixup (PrimFixup f2) :>: ps)
| IsEq <- isInverse = Sealed ps
| otherwise
= case commute (f1 :> f2) of
Nothing -> Sealed (mapFL_FL (Fixup . PrimFixup) (canonizeFL da (f1 :>: f2 :>: NilFL)) +>+ ps)
Just (f2' :> f1') -> mapSeal (Fixup (PrimFixup f2') :>:) (simplifyPush da (PrimFixup f1') ps)
where isInverse = invert f1 =\/= f2
simplifyPush da (PrimFixup f) (Fixup (NameFixup n) :>: ps)
= case commutePrimName (f :> n) of
n' :> f' -> mapSeal (Fixup (NameFixup n') :>:) (simplifyPush da (PrimFixup f') ps)
simplifyPush da (PrimFixup f) (ToEdit e :>: ps)
= case commuterIdNamed selfCommuter (fromPrim f :> e) of
Nothing -> Sealed (Fixup (PrimFixup f) :>: ToEdit e :>: ps)
Just (e' :> f') -> mapSeal (ToEdit e' :>:) (simplifyPushes da (mapFL_FL PrimFixup (effect f')) ps)
simplifyPush da (NameFixup n1) (Fixup (NameFixup n2) :>: ps)
| IsEq <- isInverse = Sealed ps
| otherwise
= case commute (n1 :> n2) of
Nothing -> Sealed (mapFL_FL (Fixup . NameFixup) (canonizeNamePair (n1 :> n2)) +>+ ps)
Just (n2' :> n1') -> mapSeal (Fixup (NameFixup n2') :>:) (simplifyPush da (NameFixup n1') ps)
where isInverse = invert n1 =\/= n2
simplifyPush da (NameFixup n) (Fixup (PrimFixup f) :>: ps) =
case commuteNamePrim (n :> f) of
f' :> n' -> mapSeal (Fixup (PrimFixup f') :>:) (simplifyPush da (NameFixup n') ps)
simplifyPush da (NameFixup (AddName an)) (p@(ToEdit (NamedP pn deps _)) :>: ps)
| an == pn = impossible
| an `elem` deps = Sealed (Fixup (NameFixup (AddName an)) :>: p :>: ps)
| otherwise = mapSeal (unsafeCoerceP p :>:) (simplifyPush da (NameFixup (AddName an)) ps)
simplifyPush da (NameFixup (DelName dn)) (p@(ToEdit (NamedP pn deps _)) :>: ps)
| dn == pn = Sealed (Fixup (NameFixup (DelName dn)) :>: p :>: ps)
| dn `elem` deps = impossible
| otherwise = mapSeal (unsafeCoerceP p :>:) (simplifyPush da (NameFixup (DelName dn)) ps)
simplifyPush da (NameFixup (Rename old new)) (p@(ToEdit (NamedP pn deps body)) :>: ps)
| old == pn = impossible
| new == pn = impossible
| old `elem` deps = impossible
| new `elem` deps =
let newdeps = map (\dep -> if new == dep then old else dep) deps
in mapSeal (ToEdit (NamedP pn newdeps (unsafeCoerceP body)) :>:) (simplifyPush da (NameFixup (Rename old new)) ps)
| otherwise = mapSeal (unsafeCoerceP p :>:) (simplifyPush da (NameFixup (Rename old new)) ps)
simplifyPushes :: (PrimPatchBase p, Commute p, FromPrim p, Effect p)
=> D.DiffAlgorithm -> FL (RebaseFixup p) wX wY -> FL (RebaseItem p) wY wZ -> Sealed (FL (RebaseItem p) wX)
simplifyPushes _ NilFL ps = Sealed ps
simplifyPushes da (f :>: fs) ps = unseal (simplifyPush da f) (simplifyPushes da fs ps)
instance (PrimPatchBase p, PatchListFormat p, ShowPatchBasic p) => ShowPatchBasic (RebaseItem p) where
showPatch (ToEdit p) = blueText "rebase-toedit" <+> blueText "(" $$ showPatch p $$ blueText ")"
showPatch (Fixup (PrimFixup p)) = blueText "rebase-fixup" <+> blueText "(" $$ showPatch p $$ blueText ")"
showPatch (Fixup (NameFixup p)) = blueText "rebase-name" <+> blueText "(" $$ showPatch p $$ blueText ")"
instance (PrimPatchBase p, PatchListFormat p, Apply p, CommuteNoConflicts p, Conflict p, IsHunk p, ShowPatch p)
=> ShowPatch (RebaseItem p) where
summary (ToEdit p) = summary p
summary (Fixup (PrimFixup p)) = summary p
summary (Fixup (NameFixup n)) = summary n
summaryFL ps = vcat (mapFL summary ps)
instance (PrimPatchBase p, PatchListFormat p, ReadPatch p) => ReadPatch (RebaseItem p) where
readPatch' = mapSeal ToEdit <$> readWith (BC.pack "rebase-toedit") <|>
mapSeal (Fixup . PrimFixup) <$> readWith (BC.pack "rebase-fixup" ) <|>
mapSeal (Fixup . NameFixup) <$> readWith (BC.pack "rebase-name" )
where readWith :: forall m q wX . (ParserM m, ReadPatch q) => B.ByteString -> m (Sealed (q wX))
readWith str = do lexString str
lexString (BC.pack "(")
res <- readPatch'
lexString (BC.pack ")")
return res
instance Check p => Check (RebaseItem p) where
isInconsistent (Fixup _) = Nothing
isInconsistent (ToEdit p) = isInconsistent p
instance (PrimPatchBase p, PatchInspect p) => PatchInspect (RebaseItem p) where
listTouchedFiles (ToEdit p) = listTouchedFiles p
listTouchedFiles (Fixup p) = listTouchedFiles p
hunkMatches f (ToEdit p) = hunkMatches f p
hunkMatches f (Fixup p) = hunkMatches f p