mirror of
https://github.com/ilyakooo0/optparse-applicative.git
synced 2025-01-08 14:12:15 +03:00
Change how subparsers are executed:
Previously seachparser would return a Maybe a, which would then be wrapped in a NilP . Just and swapped into the parser. This means that subparsers needed to execute completely before returning, and gives a somewhat unsatifactory notion of backtracking, where one could supply commands to the top level, but only after fully completing the subparser. If instead of returning a Maybe a, we return a Maybe (Parse a) then for flags, args, and options we can bahave the same and just wrap a little earlier, but for subcommands we can do something a bit different and replace the subparser with the contents of the selected command. This means that we're essentially inlining the selected subparser, and all parent options are still 'in scope' of the current parse. Given that we can still enter the context (but not exit it), not much changes with this, but backtracking is now quite different and can not be turned off.
This commit is contained in:
parent
b04118b039
commit
9108ccd1f6
@ -51,7 +51,7 @@ module Options.Applicative.Common (
|
||||
) where
|
||||
|
||||
import Control.Applicative
|
||||
import Control.Monad (guard, mzero, msum, when, liftM)
|
||||
import Control.Monad (guard, mzero, msum, when)
|
||||
import Control.Monad.Trans.Class (lift)
|
||||
import Control.Monad.Trans.State (StateT(..), get, put, runStateT)
|
||||
import Data.List (isPrefixOf)
|
||||
@ -79,22 +79,6 @@ isOptionPrefix _ _ = False
|
||||
liftOpt :: Option a -> Parser a
|
||||
liftOpt = OptP
|
||||
|
||||
argMatches :: MonadP m => OptReader a -> String
|
||||
-> Maybe (StateT Args m a)
|
||||
argMatches opt arg = case opt of
|
||||
ArgReader rdr -> Just . lift $
|
||||
runReadM (crReader rdr) arg
|
||||
CmdReader _ _ f ->
|
||||
flip fmap (f arg) $ \subp -> StateT $ \args -> do
|
||||
prefs <- getPrefs
|
||||
let runSubparser
|
||||
| prefBacktrack prefs = \i a ->
|
||||
runParser (infoPolicy i) CmdStart (infoParser i) a
|
||||
| otherwise = \i a
|
||||
-> (,) <$> runParserInfo i a <*> pure []
|
||||
enterContext arg subp *> runSubparser subp args <* exitContext
|
||||
_ -> Nothing
|
||||
|
||||
optMatches :: MonadP m => Bool -> OptReader a -> OptWord -> Maybe (StateT Args m a)
|
||||
optMatches disambiguate opt (OptWord arg1 val) = case opt of
|
||||
OptReader names rdr no_arg_err -> do
|
||||
@ -150,10 +134,10 @@ parseWord ('-' : w) = case w of
|
||||
parseWord _ = Nothing
|
||||
|
||||
searchParser :: Monad m
|
||||
=> (forall r . Option r -> NondetT m r)
|
||||
=> (forall r . Option r -> NondetT m (Parser r))
|
||||
-> Parser a -> NondetT m (Parser a)
|
||||
searchParser _ (NilP _) = mzero
|
||||
searchParser f (OptP opt) = liftM pure (f opt)
|
||||
searchParser f (OptP opt) = f opt
|
||||
searchParser f (MultP p1 p2) = foldr1 (<!>)
|
||||
[ do p1' <- searchParser f p1
|
||||
return (p1' <*> p2)
|
||||
@ -175,16 +159,23 @@ searchOpt pprefs w = searchParser $ \opt -> do
|
||||
let disambiguate = prefDisambiguate pprefs
|
||||
&& optVisibility opt > Internal
|
||||
case optMatches disambiguate (optMain opt) w of
|
||||
Just matcher -> lift matcher
|
||||
Just matcher -> lift $ fmap pure matcher
|
||||
Nothing -> mzero
|
||||
|
||||
searchArg :: MonadP m => String -> Parser a
|
||||
-> NondetT (StateT Args m) (Parser a)
|
||||
searchArg arg = searchParser $ \opt -> do
|
||||
when (isArg (optMain opt)) cut
|
||||
case argMatches (optMain opt) arg of
|
||||
Just matcher -> lift matcher
|
||||
Nothing -> mzero
|
||||
case optMain opt of
|
||||
CmdReader _ _ f ->
|
||||
case f arg of
|
||||
Just subp -> do
|
||||
lift . lift $ enterContext arg subp
|
||||
return $ infoParser subp
|
||||
Nothing -> mzero
|
||||
ArgReader rdr ->
|
||||
fmap pure . lift . lift $ runReadM (crReader rdr) arg
|
||||
_ -> mzero
|
||||
|
||||
stepParser :: MonadP m => ParserPrefs -> ArgPolicy -> String
|
||||
-> Parser a -> NondetT (StateT Args m) (Parser a)
|
||||
|
Loading…
Reference in New Issue
Block a user