#include "gadts.h"
module Darcs.SelectChanges (selectChanges, WhichChanges(..), viewChanges, withSelectedPatchFromRepo,
filterOutConflicts, runSelection, selectionContextPrim,
selectionContext
) where
import System.IO
import Data.List ( intersperse )
import Data.Maybe ( catMaybes, isJust, fromJust )
import Data.Char ( toUpper )
import Control.Monad ( when, (>=>) )
import Control.Monad.Trans ( liftIO )
import Control.Monad.Reader ( ReaderT, Reader, asks, runReader, runReaderT )
import Control.Monad.State ( State(..), StateT, modify, gets, execStateT )
import System.Exit ( exitWith, ExitCode(ExitSuccess) )
import English ( Noun(..), englishNum )
import Darcs.Arguments ( showFriendly )
import Darcs.Hopefully ( PatchInfoAnd, hopefully, n2pia )
import Darcs.Repository ( Repository, readRepo, unrecordedChanges )
import Darcs.Patch ( RepoPatch, Patchy, Prim, summary,
invert, listTouchedFiles,
commuteFLorComplain, fromPrims, anonymous )
import Darcs.Patch.Set ( newset2RL )
import qualified Darcs.Patch ( thing, things )
import Darcs.Patch.Split ( Splitter(..) )
import Darcs.Witnesses.Ordered ( FL(..), RL(..), (:>)(..), (:||:)(..),
(+>+), lengthFL, concatRL, mapFL_FL,
spanFL, spanFL_M, reverseFL, (+<+), mapFL, filterFL )
import Darcs.Witnesses.WZipper( FZipper(..), left, right
, rightmost, lengthFZ, focus
, toEnd)
import Darcs.Patch.Choices ( PatchChoices, patchChoices,
patchChoicesTpsSub,
forceFirst, forceLast, makeUncertain, tag,
getChoices, refineChoices,
separateFirstFromMiddleLast,
patchSlot',
selectAllMiddles,
forceMatchingLast,
forceMatchingFirst, makeEverythingLater,
makeEverythingSooner,
TaggedPatch, tpPatch, Slot(..),
substitute
)
import Darcs.Patch.Permutations ( partitionConflictingFL, selfCommuter, commuterIdRL )
import qualified Darcs.Patch.TouchesFiles as TouchesFiles
import Darcs.PrintPatch ( printFriendly, printPatch, printPatchPager )
import Darcs.Match ( haveNonrangeMatch, matchAPatch, matchAPatchread )
import Darcs.Flags ( DarcsFlag( Summary, DontGrabDeps, Verbose, DontPromptForDependencies, SkipConflicts), isInteractive )
import Darcs.Witnesses.Sealed ( FlippedSeal(..), flipSeal, seal2, unseal2, Sealed(..), Sealed2(..) )
import Darcs.Utils ( askUser, promptChar, PromptConfig(..) )
import Darcs.Lock ( editText )
import Printer ( prefix, putDocLn )
data WhichChanges = Last | LastReversed | First | FirstReversed deriving (Eq, Show)
backward :: WhichChanges -> Bool
backward w = w == Last || w == FirstReversed
type MatchCriterion p = WhichChanges -> [DarcsFlag] -> Sealed2 p -> Bool
data PatchSelectionContext p = PSC { opts :: [DarcsFlag]
, splitter :: Maybe (Splitter p)
, files :: [FilePath]
, matchCriterion :: MatchCriterion p
, jobname :: String }
selectionContextPrim :: String -> [DarcsFlag] -> Maybe (Splitter Prim)
-> [FilePath] -> PatchSelectionContext Prim
selectionContextPrim jn o spl fs =
PSC { opts = o
, splitter = spl
, files = fs
, matchCriterion = triv
, jobname = jn }
selectionContext :: (RepoPatch p) => String -> [DarcsFlag] -> Maybe (Splitter (PatchInfoAnd p))
-> [FilePath] -> PatchSelectionContext (PatchInfoAnd p)
selectionContext jn o spl fs =
PSC { opts = o
, splitter = spl
, files = fs
, matchCriterion = iswanted
, jobname = jn }
data InteractiveSelectionContext p C(x y) = ISC { total :: Int
, current :: Int
, tps :: FZipper (TaggedPatch p) C(x y)
, choices :: PatchChoices p C(x y)
}
type PatchSelectionM p a = ReaderT (PatchSelectionContext p) a
type InteractiveSelectionM p C(x y) a =
StateT (InteractiveSelectionContext p C(x y))
(PatchSelectionM p IO) a
type PatchSelection p C(x y) =
PatchSelectionM p IO ((FL p :> FL p) C(x y))
triv :: MatchCriterion p
triv = \ _ _ _ -> True
iswanted :: Patchy p => MatchCriterion (PatchInfoAnd p)
iswanted whch opts' =
unseal2 (iw whch opts')
where
iw First o = matchAPatch o . hopefully
iw Last o = matchAPatch o . hopefully
iw LastReversed o = matchAPatch o . hopefully . invert
iw FirstReversed o = matchAPatch o . hopefully . invert
liftR :: Monad m => Reader r a -> ReaderT r m a
liftR = asks . runReader
runSelection :: (Patchy p) => PatchSelection p C(x y) -> PatchSelectionContext p
-> IO ((FL p :> FL p) C(x y))
runSelection = runReaderT
selectChanges :: forall p C(x y) . Patchy p =>
WhichChanges -> FL p C(x y)
-> PatchSelection p C(x y)
selectChanges First = sc1 First
selectChanges Last = sc1 Last
selectChanges FirstReversed = return . invert
>=> sc1 FirstReversed
>=> return . invertC
selectChanges LastReversed = return . invert
>=> sc1 LastReversed
>=> return . invertC
sc1 :: forall p C(x y) . Patchy p =>
WhichChanges -> FL p C(x y)
-> PatchSelection p C(x y)
sc1 whch =
((liftR . patchesToConsider whch)
>=> realSelectChanges whch
>=> return . selectedPatches whch
>=> (liftR . canonizeAfterSplitter))
invertC :: (Patchy p) => (FL p :> FL p) C(x y) -> (FL p :> FL p) C(y x)
invertC (a :> b) = (invert b) :> (invert a)
repr :: (Patchy p) => WhichChanges -> Sealed2 p -> Sealed2 p
repr First (Sealed2 p) = Sealed2 p
repr LastReversed (Sealed2 p) = Sealed2 (invert p)
repr Last (Sealed2 p) = Sealed2 p
repr FirstReversed (Sealed2 p) = Sealed2 (invert p)
viewChanges :: Patchy p => [DarcsFlag] -> [Sealed2 p] -> IO ()
viewChanges opts ps = textView opts Nothing 0 [] ps
data KeyPress = KeyPress { kp :: Char
, kpHelp :: String }
helpFor :: String -> [[KeyPress]] -> [[KeyPress]] -> String
helpFor jn basicKeypresses advancedKeyPresses =
unlines $ [ "How to use "++jn++":" ]
++ (concat $ intersperse [""] $ map (map help) keypresses)
++ [ ""
, "?: show this help"
, ""
, "<Space>: accept the current default (which is capitalized)"
]
where help i = kp i:(": "++kpHelp i)
keypresses = basicKeypresses ++ advancedKeyPresses
keysFor :: [[KeyPress]] -> [Char]
keysFor = concatMap (map kp)
withSelectedPatchFromRepo :: forall p C(r u t). RepoPatch p => String -> Repository p C(r u t) -> [DarcsFlag]
-> (FORALL(a) (FL (PatchInfoAnd p) :> PatchInfoAnd p) C(a r) -> IO ()) -> IO ()
withSelectedPatchFromRepo jn repository o job = do
p_s <- readRepo repository
sp <- wspfr jn (matchAPatchread o)
(newset2RL p_s) NilFL
case sp of
Just (FlippedSeal (skipped :> selected)) -> job (skipped :> selected)
Nothing -> do putStrLn $ "Cancelling "++jn++" since no patch was selected."
wspfr :: RepoPatch p => String -> (FORALL(a b) (PatchInfoAnd p) C(a b) -> Bool)
-> RL (PatchInfoAnd p) C(x y) -> FL (PatchInfoAnd p) C(y u)
-> IO (Maybe (FlippedSeal (FL (PatchInfoAnd p) :> (PatchInfoAnd p)) C(u)))
wspfr _ _ NilRL _ = return Nothing
wspfr jn matches (p:<:pps) skipped
| not $ matches p = wspfr jn matches pps (p:>:skipped)
| otherwise =
case commuteFLorComplain (p :> skipped) of
Left _ -> do putStrLn "\nSkipping depended-upon patch:"
printFriendly [] p
wspfr jn matches pps (p:>:skipped)
Right (skipped' :> p') -> do
printFriendly [] p
let repeat_this = wspfr jn matches (p:<:pps) skipped
basic_options =
[[ KeyPress 'y' (jn++" this patch")
, KeyPress 'n' ("don't "++jn++" it")
]]
advanced_options =
[[ KeyPress 'v' "view this patch in full"
, KeyPress 'p' "view this patch in full with pager"
, KeyPress 'x' "view a summary of this patch"
, KeyPress 'q' ("cancel "++jn)
]]
let prompt = "Shall I "++jn++" this patch?"
yorn <- promptChar $ PromptConfig { pPrompt = prompt
, pBasicCharacters = keysFor basic_options
, pAdvancedCharacters = keysFor advanced_options
, pDefault = Just 'n'
, pHelp = "?h" }
case yorn of
'y' -> return $ Just $ flipSeal $ skipped' :> p'
'n' -> wspfr jn matches pps (p:>:skipped)
'v' -> printPatch p >> repeat_this
'p' -> printPatchPager p >> repeat_this
'x' -> do putDocLn $ prefix " " $ summary p
repeat_this
'q' -> do putStrLn $ jn_cap++" cancelled."
exitWith $ ExitSuccess
_ -> do putStrLn $ helpFor jn basic_options advanced_options
repeat_this
where jn_cap = (toUpper $ head jn) : tail jn
canonizeAfterSplitter :: (FL p :> FL p) C(x y) -> Reader (PatchSelectionContext p) ((FL p :> FL p) C(x y))
canonizeAfterSplitter (x :> y) =
do spl' <- asks splitter
case spl' of
Nothing -> return (x:>y)
Just spl -> return $ canonizeSplit spl x :> canonizeSplit spl y
realSelectChanges :: forall p C(x y). Patchy p
=> WhichChanges
-> PatchChoices p C(x y)
-> PatchSelectionM p IO (PatchChoices p C(x y))
realSelectChanges whch autoChoices =
do
o <- asks opts
if not $ isInteractive o
then return $ promote autoChoices
else flip refineChoices autoChoices $ textSelect whch
where forward = not $ backward whch
promote = if forward
then makeEverythingSooner
else makeEverythingLater
deselectUnwanted :: forall p C(x y) . Patchy p => WhichChanges ->
PatchChoices p C(x y) ->
Reader (PatchSelectionContext p) (PatchChoices p C(x y))
deselectUnwanted whichch pc =
do
o <- asks opts
c <- (asks matchCriterion)
let iswanted_ = c whichch o . seal2 . tpPatch
select = if forward
then forceMatchingFirst iswanted_
else forceMatchingLast iswanted_
deselect = if forward
then forceMatchingLast (not . iswanted_)
else forceMatchingFirst (not . iswanted_)
if haveNonrangeMatch o
then if DontGrabDeps `elem` o
then return $ deselect pc
else do
return . demote $ select pc
else return pc
where
forward = not $ backward whichch
demote = if forward
then makeEverythingLater
else makeEverythingSooner
patchesToConsider :: Patchy p
=> WhichChanges
-> FL p C(x y)
-> Reader (PatchSelectionContext p) (PatchChoices p C(x y))
patchesToConsider whch ps =
do
fs <- asks files
o <- asks opts
let deselectNotTouching =
case whch of
First -> TouchesFiles.deselectNotTouching
Last -> TouchesFiles.selectNotTouching
FirstReversed -> TouchesFiles.selectNotTouching
LastReversed -> TouchesFiles.deselectNotTouching
everything = patchChoices ps
if null fs && not (haveNonrangeMatch o)
then return everything
else do notUnwanted <- deselectUnwanted whch everything
return $ deselectNotTouching fs notUnwanted
selectedPatches :: Patchy p => WhichChanges -> PatchChoices p C(y z)
-> (FL p :> FL p) C(y z)
selectedPatches Last pc =
case getChoices pc of
fc :> mc :> lc -> mapFL_FL tpPatch (fc +>+ mc) :> mapFL_FL tpPatch lc
selectedPatches First pc =
case separateFirstFromMiddleLast pc of
xs :> ys -> mapFL_FL tpPatch xs :> mapFL_FL tpPatch ys
selectedPatches LastReversed pc =
case separateFirstFromMiddleLast pc of
xs :> ys -> mapFL_FL tpPatch (xs) :> (mapFL_FL tpPatch (ys))
selectedPatches FirstReversed pc =
case getChoices pc of
fc :> mc :> lc -> (mapFL_FL tpPatch (fc +>+ mc)) :> (mapFL_FL tpPatch lc)
liftChoices :: forall p a C(x y) . Patchy p =>
State (PatchChoices p C(x y)) a
-> InteractiveSelectionM p C(x y) a
liftChoices act = do
ch <- gets choices
let (result, ch') = runState act ch
modify $ \isc -> isc {choices = ch}
return result
justDone :: Patchy p => Int -> InteractiveSelectionM p C(x y) ()
justDone n = modify $ \isc -> isc{ current = current isc + n}
textSelect :: forall p C(x y) . Patchy p => WhichChanges ->
FL (TaggedPatch p) C(x y) -> PatchChoices p C(x y)
-> PatchSelectionM p IO (PatchChoices p C(x y))
textSelect whch tps pcs = do
userSelection <- execStateT (skipMundane whch >>
showCur whch >>
textSelect' whch) $
ISC { total = lengthFL tps
, current = 0
, tps = FZipper NilRL tps
, choices = pcs }
return $ choices userSelection
textSelect' :: Patchy p => WhichChanges ->
InteractiveSelectionM p C(x y) ()
textSelect' whch = do
z <- gets tps
when (not $ rightmost z) $
do
textSelectOne whch
textSelect' whch
optionsBasic :: [Char] -> [Char] -> [KeyPress]
optionsBasic jn aThing =
[ KeyPress 'y' (jn++" this "++aThing)
, KeyPress 'n' ("don't "++jn++" it")
, KeyPress 'w' ("wait and decide later, defaulting to no") ]
optionsFile :: [Char] -> [KeyPress]
optionsFile jn =
[ KeyPress 's' ("don't "++jn++" the rest of the changes to this file")
, KeyPress 'f' (jn++" the rest of the changes to this file") ]
optionsView :: String -> String -> [KeyPress]
optionsView aThing someThings =
[ KeyPress 'v' ("view this "++aThing++" in full")
, KeyPress 'p' ("view this "++aThing++" in full with pager")
, KeyPress 'l' ("list all selected "++someThings) ]
optionsSummary :: String -> [KeyPress]
optionsSummary aThing =
[ KeyPress 'x' ("view a summary of this "++aThing) ]
optionsQuit :: String -> String -> [KeyPress]
optionsQuit jn someThings =
[ KeyPress 'd' (jn++" selected "++someThings++", skipping all the remaining "++someThings)
, KeyPress 'a' (jn++" all the remaining "++someThings)
, KeyPress 'q' ("cancel "++jn) ]
optionsNav :: String -> [KeyPress]
optionsNav aThing =
[ KeyPress 'j' ("skip to next "++ aThing)
, KeyPress 'k' ("back up to previous "++ aThing) ]
optionsSplit :: Maybe (Splitter a) -> String -> [KeyPress]
optionsSplit split aThing
| Just _ <- split
= [ KeyPress 'e' ("interactively edit this "++ aThing) ]
| otherwise = []
options :: forall p C(x y) . (Patchy p) => Bool ->
InteractiveSelectionM p C(x y) ([[KeyPress]],[[KeyPress]])
options single = do
split <- asks splitter
jn <- asks jobname
aThing <- thing
someThings <- things
o <- asks opts
return $
([optionsBasic jn aThing]
,[optionsSplit split aThing]
++ (if single then
[optionsFile jn ] else [])
++ [optionsView aThing someThings ++
if Summary `elem` o then []
else optionsSummary aThing]
++ [optionsQuit jn someThings]
++ [optionsNav aThing]
)
currentPatch :: forall p C(x y) . Patchy p =>
InteractiveSelectionM p C(x y)
(Maybe (Sealed2 (TaggedPatch p)))
currentPatch = do
(FZipper _ tps_todo) :: FZipper (TaggedPatch p) C(x y) <- gets tps
case tps_todo of
NilFL -> return Nothing
(tp:>:_) -> return $ Just (Sealed2 tp)
todo :: forall p C(x y) . Patchy p
=> InteractiveSelectionM p C(x y)
(FlippedSeal (FL (TaggedPatch p)) C(y))
todo = do
(FZipper _ tps_todo) <- gets tps
return (FlippedSeal tps_todo)
modChoices :: forall p C(x y) . Patchy p =>
(PatchChoices p C(x y) -> PatchChoices p C(x y))
-> InteractiveSelectionM p C(x y) ()
modChoices f = modify $ \isc -> isc{choices = f $ choices isc}
currentFile :: forall p C(x y) . Patchy p
=> InteractiveSelectionM p C(x y) (Maybe FilePath)
currentFile = do
c <- currentPatch
return $ case c of
Nothing -> Nothing
Just (Sealed2 tp) ->
case listTouchedFiles tp of
[f] -> Just f
_ -> Nothing
decide :: forall p C(x y t u) . Patchy p => WhichChanges -> Bool
-> TaggedPatch p C(t u)
-> InteractiveSelectionM p C(x y) ()
decide whch takeOrDrop tp =
if backward whch == takeOrDrop
then modChoices $ forceLast (tag tp)
else modChoices $ forceFirst (tag tp)
decideWholeFile :: forall p C(x y). Patchy p => WhichChanges ->
FilePath -> Bool -> InteractiveSelectionM p C(x y) ()
decideWholeFile whch file takeOrDrop =
do
FlippedSeal tps_todo <- todo
let patches_to_skip =
filterFL (\tp' -> listTouchedFiles tp' == [file]) tps_todo
mapM_ (unseal2 $ decide whch takeOrDrop) patches_to_skip
postponeNext :: forall p C(x y) . Patchy p => InteractiveSelectionM p C(x y) ()
postponeNext =
do
Just (Sealed2 tp) <- currentPatch
modChoices $ makeUncertain (tag tp)
skipOne :: forall p C(x y) . Patchy p => InteractiveSelectionM p C(x y) ()
skipOne = modify so
where so x = x{tps = right (tps x), current = current x +1}
backOne :: forall p C(x y) . Patchy p => InteractiveSelectionM p C(x y) ()
backOne = modify so
where so isc = isc{tps = left (tps isc), current = max (current isc1) 0}
splitCurrent :: forall p C(x y) . Patchy p => Splitter p
-> InteractiveSelectionM p C(x y) ()
splitCurrent s = do
FZipper tps_done (tp:>:tps_todo) <- gets tps
case (applySplitter s (tpPatch tp)) of
Nothing -> return ()
Just (text, parse) ->
do
newText <- liftIO $ editText "darcs-patch-edit" text
case parse newText of
Nothing -> return ()
Just ps -> do
tps_new <- liftIO . return . snd
$ patchChoicesTpsSub (Just (tag tp)) ps
modify $ \isc -> isc { total = ( total isc
+ lengthFL tps_new 1 )
, tps = (FZipper tps_done
(tps_new +>+ tps_todo))
, choices = (substitute
(seal2 (tp :||: tps_new))
(choices isc))
}
selected :: forall p C(x y). Patchy p => WhichChanges ->
InteractiveSelectionM p C(x y) [Sealed2 p]
selected whichch = do
c <- gets choices
(first_chs :> _ :> last_chs) <- return $ getChoices c
return $ if backward whichch
then
mapFL (repr whichch . Sealed2 . tpPatch) $ last_chs
else
mapFL (repr whichch . Sealed2 . tpPatch) $ first_chs
printSelected :: Patchy p => WhichChanges ->
InteractiveSelectionM p C(x y) ()
printSelected whichch = do
someThings <- things
o <- asks opts
s <- selected whichch
liftIO $ do
putStrLn $ "---- Already selected "++someThings++" ----"
mapM_ (putDocLn . unseal2 (showFriendly o)) s
putStrLn $ "---- end of already selected "++someThings++" ----"
printSummary :: forall p C(x y) . Patchy p => p C(x y) -> IO ()
printSummary =
putDocLn . prefix " " . summary
skipAll :: forall p C(x y) . Patchy p =>
InteractiveSelectionM p C(x y) ()
skipAll = do
modify $ \isc -> isc {tps = toEnd $ tps isc}
isSingleFile :: Patchy p => p C(x y) -> Bool
isSingleFile p = length (listTouchedFiles p) == 1
askConfirmation :: forall p C(x y) . Patchy p =>
InteractiveSelectionM p C(x y) ()
askConfirmation = do
jn <- asks jobname
liftIO $ if jn `elem` ["unpull", "unrecord", "obliterate"]
then do
yorn <- askUser $ "Really " ++ jn ++ " all undecided patches? "
case yorn of
('y':_) -> return ()
_ -> exitWith $ ExitSuccess
else return ()
thing :: Patchy p => InteractiveSelectionM p C(x y) String
thing = gets choices >>= return . Darcs.Patch.thing . helper
where
helper :: PatchChoices p C(a b) -> p C(a b)
helper = undefined
things :: Patchy p => InteractiveSelectionM p C(x y) String
things = gets choices >>= return . Darcs.Patch.things . helper
where
helper :: PatchChoices p C(a b) -> p C(a b)
helper = undefined
prompt :: Patchy p => InteractiveSelectionM p C(x y) String
prompt = do
jn <- asks jobname
aThing <- thing
n <- gets current
n_max <- gets total
return $ "Shall I "++jn++" this "++aThing++"? "
++ "(" ++ show (n+1) ++ "/" ++ show n_max ++ ") "
promptUser :: forall p C(x y) . Patchy p => Bool -> Char
-> InteractiveSelectionM p C(x y) Char
promptUser single def = do
thePrompt <- prompt
(basicOptions,advancedOptions) <- options single
liftIO $ promptChar $ PromptConfig { pPrompt = thePrompt
, pBasicCharacters = keysFor basicOptions
, pAdvancedCharacters = keysFor advancedOptions
, pDefault = Just def
, pHelp = "?h"
}
textSelectOne :: forall p C(x y). Patchy p => WhichChanges
-> InteractiveSelectionM p C(x y) ()
textSelectOne whichch = do
c <- currentPatch
case c of
Nothing -> return ()
Just (Sealed2 tp) ->
do
jn <- asks jobname
spl <- asks splitter
o <- asks opts
let singleFile = isSingleFile (tpPatch tp)
reprCur = repr whichch (Sealed2 (tpPatch tp))
(basicOptions,advancedOptions) <- options singleFile
theSlot <- liftChoices $ patchSlot' tp
let
the_default = getDefault (whichch == Last || whichch == FirstReversed) theSlot
jn_cap = (toUpper $ head jn) : tail jn
yorn <- promptUser singleFile the_default
let nextPatch = skipMundane whichch >> showCur whichch
case yorn of
'y' -> decide whichch True tp >> skipOne >> nextPatch
'n' -> decide whichch False tp >> skipOne >> nextPatch
'w' -> postponeNext >> skipOne >> nextPatch
'e' | (Just s) <- spl -> splitCurrent s >> showCur whichch
's' -> currentFile >>= maybe
(return ())
(\f -> decideWholeFile whichch f False) >> nextPatch
'f' -> currentFile >>= maybe
(return ())
(\f -> decideWholeFile whichch f True) >> nextPatch
'v' -> liftIO $ unseal2 printPatch reprCur
'p' -> liftIO $ unseal2 printPatchPager reprCur
'l' -> printSelected whichch >> showCur whichch
'x' -> liftIO $ unseal2 printSummary reprCur
'd' -> skipAll
'a' ->
do
askConfirmation
modChoices $ selectAllMiddles (whichch == Last || whichch == FirstReversed)
skipAll
'q' -> liftIO $
do putStrLn $ jn_cap++" cancelled."
exitWith $ ExitSuccess
'j' -> skipOne >> showCur whichch
'k' -> backOne >> showCur whichch
_ -> do liftIO . putStrLn $ helpFor jn basicOptions advancedOptions
showCur :: forall p C(x y) . Patchy p => WhichChanges
-> InteractiveSelectionM p C(x y) ()
showCur whichch = do
o <- asks opts
c <- currentPatch
case c of
Nothing -> return ()
Just (Sealed2 tp) -> do
let reprCur = repr whichch (Sealed2 (tpPatch tp))
liftIO . (unseal2 (printFriendly o)) $ reprCur
textView :: forall p C(x y u r s). Patchy p => [DarcsFlag] -> Maybe Int -> Int
-> [Sealed2 p] -> [Sealed2 p]
-> IO ()
textView _ _ _ _ [] = return ()
textView o n_max n
ps_done ps_todo@(p:ps_todo') = do
unseal2 (printFriendly o) p
repeat_this
where
prev_patch :: IO ()
prev_patch = case ps_done of
[] -> repeat_this
(p':ps_done') ->
textView o
n_max (n1) ps_done' (p':ps_todo)
next_patch :: IO ()
next_patch = case ps_todo' of
[] ->
textView o n_max
n ps_done []
_ -> textView o n_max
(n+1) (p:ps_done) ps_todo'
options_yn =
[ KeyPress 'y' "view this patch and go to the next"
, KeyPress 'n' "skip to the next patch" ]
optionsView =
[ KeyPress 'v' "view this patch in full"
, KeyPress 'p' "view this patch in full with pager" ]
optionsSummary =
[ KeyPress 'x' "view a summary of this patch" ]
optionsNav =
[ KeyPress 'q' "quit view changes"
, KeyPress 'k' "back up to previous patch"
, KeyPress 'j' "skip to next patch"
, KeyPress 'c' "count total patch number" ]
basicOptions = [ options_yn ]
advancedOptions =
[ optionsView ++
if Summary `elem` o then [] else optionsSummary ]
++ [ optionsNav ]
prompt = "Shall I view this patch? "
++ "(" ++ show (n+1) ++ "/" ++ maybe "?" show n_max ++ ")"
repeat_this :: IO ()
repeat_this = do
yorn <- promptChar (PromptConfig prompt (keysFor basicOptions) (keysFor advancedOptions) (Just 'n') "?h")
case yorn of
'y' -> unseal2 printPatch p >> next_patch
'n' -> next_patch
'v' -> unseal2 printPatch p >> repeat_this
'p' -> unseal2 printPatchPager p >> repeat_this
'x' -> do putDocLn $ prefix " " $ unseal2 summary p
repeat_this
'q' -> exitWith ExitSuccess
'k' -> prev_patch
'j' -> next_patch
'c' -> textView o
count_n_max n ps_done ps_todo
_ -> do putStrLn $ helpFor "view changes" basicOptions advancedOptions
repeat_this
count_n_max | isJust n_max = n_max
| otherwise = Just $ length ps_done + length ps_todo
skipMundane :: Patchy p => WhichChanges ->
InteractiveSelectionM p C(x y) ()
skipMundane whichch = do
(FZipper tps_done tps_todo) <- gets tps
o <- asks opts
crit <- asks matchCriterion
jn <- asks jobname
(skipped :> unskipped) <- liftChoices $ spanFL_M
(patchSlot' >=> return . decided)
tps_todo
let numSkipped = lengthFL skipped
when (numSkipped > 0) . liftIO $ show_skipped o jn numSkipped skipped
let boringThenInteresting =
if DontPromptForDependencies `elem` o
then spanFL (not.(crit whichch o) . seal2 . tpPatch) $
unskipped
else NilFL :> unskipped
case boringThenInteresting of
boring :> interesting ->
do
justDone $ lengthFL boring + numSkipped
modify $ \isc -> isc {tps = (FZipper (reverseFL boring +<+ reverseFL skipped +<+ tps_done) interesting)}
where
show_skipped o jn n ps = do putStrLn $ _nevermind_ jn ++ _these_ n ++ "."
when (Verbose `elem` o) $
showskippedpatch ps
_nevermind_ jn = "Will not ask whether to " ++ jn ++ " "
_these_ n = show n ++ " already decided " ++ _elem_ n ""
_elem_ n = englishNum n (Noun "patch")
showskippedpatch :: Patchy p => FL (TaggedPatch p) C(y t) -> IO ()
showskippedpatch =
sequence_ . mapFL (printSummary . tpPatch)
decided :: Slot -> Bool
decided InMiddle = False
decided _ = True
getDefault :: Bool -> Slot -> Char
getDefault _ InMiddle = 'w'
getDefault True InFirst = 'n'
getDefault True InLast = 'y'
getDefault False InFirst = 'y'
getDefault False InLast = 'n'
filterOutConflicts :: RepoPatch p
=> [DarcsFlag]
-> RL (PatchInfoAnd p) C(x t)
-> Repository p C(r u t)
-> FL (PatchInfoAnd p) C(x z)
-> IO (Bool, Sealed (FL (PatchInfoAnd p) C(x)))
filterOutConflicts o us repository them
| SkipConflicts `elem` o
= do let commuter = commuterIdRL selfCommuter
unrec <- fmap n2pia . (anonymous . fromPrims) =<< unrecordedChanges [] repository []
them' :> rest <- return $ partitionConflictingFL commuter them (unrec :<: us)
return (check rest, Sealed them')
| otherwise
= return (False, Sealed them)
where check :: FL p C(a b) -> Bool
check NilFL = False
check _ = True