{-# LANGUAGE ViewPatterns #-}
{-# OPTIONS_GHC -fno-warn-unused-imports #-}
module Darcs.Patch.Split
( Splitter(..)
, rawSplitter
, noSplitter
, primSplitter
, reversePrimSplitter
) where
import Darcs.Prelude
import Data.List ( intersperse )
import Darcs.Patch.Witnesses.Ordered
import Darcs.Patch.Witnesses.Sealed
import Darcs.Patch.FileHunk ( FileHunk(..), IsHunk(..) )
import Darcs.Patch.Read ( ReadPatch(..) )
import Darcs.Patch.Show ( showPatch, ShowPatch(..) )
import Darcs.Patch.Invert( Invert(..), invertFL )
import Darcs.Patch.Prim ( PrimPatch, canonize, canonizeFL, primFromHunk )
import Darcs.Util.Parser ( parse )
import Darcs.Patch.Read ()
import Darcs.Patch.Show ( ShowPatchFor(ForDisplay) )
import Darcs.Patch.Viewing ()
import Darcs.Util.Printer ( renderPS )
import qualified Darcs.Util.Diff as D ( DiffAlgorithm )
import qualified Data.ByteString as B
import qualified Data.ByteString.Char8 as BC
data Splitter p = Splitter
{ applySplitter :: forall wX wY. p wX wY
-> Maybe (B.ByteString, B.ByteString -> Maybe (FL p wX wY))
, canonizeSplit :: forall wX wY. FL p wX wY -> FL p wX wY
}
withEditedHead :: Invert p => p wX wY -> p wX wZ -> FL p wX wY
withEditedHead p res = res :>: invert res :>: p :>: NilFL
rawSplitter :: (ShowPatch p, ReadPatch p, Invert p) => Splitter p
rawSplitter = Splitter
{ applySplitter = \p ->
Just (renderPS . showPatch ForDisplay $ p
,\str -> case parse readPatch' str of
Right (Sealed res, _) -> Just (withEditedHead p res)
Left _ -> Nothing)
, canonizeSplit = id
}
noSplitter :: Splitter p
noSplitter = Splitter { applySplitter = const Nothing, canonizeSplit = id }
doPrimSplit :: PrimPatch prim => D.DiffAlgorithm -> prim wX wY
-> Maybe (B.ByteString, B.ByteString -> Maybe (FL prim wX wY))
doPrimSplit da = doPrimSplit_ da True explanation
where
explanation =
map BC.pack
[ "Interactive hunk edit:"
, " - Edit the section marked 'AFTER'"
, " - Arbitrary editing is supported"
, " - This will only affect the patch, not your working tree"
, " - Hints:"
, " - To split added text, delete the part you want to postpone"
, " - To split removed text, copy back the part you want to retain"
, ""
]
doPrimSplit_ :: (PrimPatch prim, IsHunk p)
=> D.DiffAlgorithm
-> Bool
-> [B.ByteString]
-> p wX wY
-> Maybe (B.ByteString, B.ByteString -> Maybe (FL prim wX wY))
doPrimSplit_ da edit_before_part helptext (isHunk -> Just (FileHunk fn n before after))
= Just (B.concat $ intersperse (BC.pack "\n") $ concat
[ helptext
, [mkSep " BEFORE (reference) =========================="]
, before
, [mkSep "=== AFTER (edit) ============================="]
, after
, [mkSep "=== (edit above) ============================="]
],
\bs -> do let ls = BC.split '\n' bs
(_, ls2) <- breakSep ls
(before', ls3) <- breakSep ls2
(after', _) <- breakSep ls3
return $
if edit_before_part
then hunk before before' +>+ hunk before' after' +>+ hunk after' after
else hunk before after' +>+ hunk after' after)
where sep = BC.pack "=========================="
hunk :: PrimPatch prim => [B.ByteString] -> [B.ByteString] -> FL prim wA wB
hunk b a = canonize da (primFromHunk (FileHunk fn n b a))
mkSep s = BC.append sep (BC.pack s)
breakSep xs = case break (sep `BC.isPrefixOf`) xs of
(_, []) -> Nothing
(ys, _:zs) -> Just (ys, zs)
doPrimSplit_ _ _ _ _ = Nothing
primSplitter :: PrimPatch p => D.DiffAlgorithm -> Splitter p
primSplitter da = Splitter { applySplitter = doPrimSplit da
, canonizeSplit = canonizeFL da }
doReversePrimSplit :: PrimPatch prim => D.DiffAlgorithm -> prim wX wY
-> Maybe (B.ByteString, B.ByteString -> Maybe (FL prim wX wY))
doReversePrimSplit da prim = do
(text, parser) <- doPrimSplit_ da False reverseExplanation (invert prim)
let parser' p = do
patch <- parser p
return . reverseRL $ invertFL patch
return (text, parser')
where
reverseExplanation =
map BC.pack
[ "Interactive hunk edit:"
, " - Edit the section marked 'AFTER' (representing the state to which you'll revert)"
, " - Arbitrary editing is supported"
, " - Your working tree will be returned to the 'AFTER' state"
, " - Do not touch the 'BEFORE' section"
, " - Hints:"
, " - To revert only a part of a text addition, delete the part you want to get rid of"
, " - To revert only a part of a removal, copy back the part you want to retain"
, ""
]
reversePrimSplitter :: PrimPatch prim => D.DiffAlgorithm -> Splitter prim
reversePrimSplitter da = Splitter { applySplitter = doReversePrimSplit da
, canonizeSplit = canonizeFL da }