multiarg 0.8.0.0 → 0.10.0.0
raw patch · 5 files changed
+255/−58 lines, 5 filesdep ~containersPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: containers
API changes (from Hackage documentation)
+ System.Console.MultiArg.SimpleParser: instance Functor ArgWrap
+ System.Console.MultiArg.SimpleParser: mHelp :: Mode result -> String -> String
+ System.Console.MultiArg.SimpleParser: modesWithHelp :: (String -> String) -> [OptSpec a] -> ([a] -> Either ([String] -> result) [Mode result]) -> IO result
+ System.Console.MultiArg.SimpleParser: simpleWithHelp :: (String -> String) -> Intersperse -> [OptSpec a] -> (String -> a) -> IO [a]
- System.Console.MultiArg.SimpleParser: Mode :: String -> Intersperse -> [OptSpec b] -> (String -> b) -> ([b] -> result) -> Mode result
+ System.Console.MultiArg.SimpleParser: Mode :: String -> Intersperse -> [OptSpec b] -> (String -> b) -> ([b] -> result) -> (String -> String) -> Mode result
- System.Console.MultiArg.SimpleParser: modes :: [OptSpec a] -> ([a] -> Exceptional String b) -> (b -> Either (String -> c) [Mode result]) -> [String] -> Exceptional Error (b, Either [c] result)
+ System.Console.MultiArg.SimpleParser: modes :: [OptSpec a] -> ([a] -> Either ([String] -> result) [Mode result]) -> [String] -> Exceptional Error result
Files
- NEWS +12/−0
- System/Console/MultiArg/Combinator.hs +3/−1
- System/Console/MultiArg/Prim.hs +2/−0
- System/Console/MultiArg/SimpleParser.hs +236/−55
- multiarg.cabal +2/−2
NEWS view
@@ -64,3 +64,15 @@ System.Console.MultiArg. So fixing that is just a matter of changing imports in client code. Other breakage will be limited to error handling code.++Release 0.10.0.0, March 7, 2013+Changes since release 0.8.0.0:++* Added the simpleWithHelp and modesWithHelp pre-built parsers to+ the SimpleParser module++* Added the mHelp field to the Mode record to allow for the+ modesWithHelp pre-built parser++* Changed the modes function in the SimpleParser module. The new+ function has a simpler type. It will however break old code.
System/Console/MultiArg/Combinator.hs view
@@ -315,7 +315,9 @@ (_, a):[] -> return a _ -> Nothing --- | Formats error messages for nice display.+-- | Formats error messages for nice display. Returns a multi-line+-- string (there is no need to append a newline to the end of the+-- string returned). formatError :: String -- ^ Pass the name of your program here. Displayed at the beginning
System/Console/MultiArg/Prim.hs view
@@ -128,6 +128,8 @@ data Description = Unknown | General String | Expected String deriving (Eq, Show, Ord) +-- | Error messages. To format error messages for nice display, see+-- 'System.Console.MultiArg.Combinator.formatError'. data Error = Error InputDesc [Description] deriving (Eq, Show, Ord)
System/Console/MultiArg/SimpleParser.hs view
@@ -1,23 +1,33 @@ {-# LANGUAGE ExistentialQuantification #-}--- | A simple command line parser that can parse options that take an--- optional argument, one or two arguments, or a variable number of--- arguments. For sample code that uses this parser, see+-- | Some pre-built command line parsers. One is a simple command line+-- parser that can parse options that take an optional argument, one+-- or two arguments, or a variable number of arguments. For sample+-- code that uses this parser, see -- "System.Console.MultiArg.SampleParser".+--+-- Another parser is provided for multi-mode programs that are similar+-- to @git@ or @darcs@. module System.Console.MultiArg.SimpleParser ( -- * Interspersion control Intersperse (Intersperse, StopOptions) -- * The parser , simple+ , simpleWithHelp -- * Parsing multi-mode command lines , Mode(..) , modes+ , modesWithHelp ) where -import qualified System.Console.MultiArg.Prim as P+import Data.Either (partitionEithers) import qualified System.Console.MultiArg.Combinator as C+import qualified System.Console.MultiArg.GetArgs as GetArgs+import qualified System.Console.MultiArg.Prim as P import qualified Control.Monad.Exception.Synchronous as Ex+import System.Exit (exitFailure, exitSuccess)+import qualified System.IO as IO import Control.Applicative ( many, (<|>), optional, (<$), (<*>), (<*), (<$>)) import Data.List (find)@@ -99,6 +109,90 @@ parser = po <|> ps <|> pa in catMaybes <$> P.manyTill parser P.end +--+-- simpleWithHelp+--++-- | Wraps the OptSpec passed into to simpleWithHelp. +data ArgWrap a+ = HelpArg+ | OtherArg a++data ArgWrapResult a+ = NeedsHelp String+ | NoHelp a++instance Functor ArgWrap where+ fmap _ HelpArg = HelpArg+ fmap f (OtherArg a) = OtherArg $ f a++partitionHelp :: [ArgWrap a] -> (DoHelp, [a])+partitionHelp xs = (not . null . fst $ r, snd r)+ where+ toEither h = case h of+ HelpArg -> Left ()+ OtherArg a -> Right a+ r = partitionEithers . map toEither $ xs++-- | Shows help and exits successfully if that was requested;+-- otherwise, returns the parsed command line options.+extractOpts :: String -> (String -> String) -> [ArgWrap a] -> IO [a]+extractOpts pn hlp opts =+ let (doHelp, os) = partitionHelp opts+ in if doHelp+ then putStr (hlp pn) >> exitSuccess+ else return os+++-- | Parses a simple command line (that is, one without modes) in the+-- IO monad. Gets the arguments for you using 'getArgs'. In addition+-- to the arguments you provide for 'simple', you also provide online+-- help. This function adds @-h@ and @--help@ options and shows help+-- if the user entered one of these options anywhere on the command+-- line. If help is shown, the program exits successfully. In+-- addition, it will print a message to standard error if parsing the+-- command line fails and then exit unsuccessfully.+simpleWithHelp+ :: (String -> String)+ -- ^ Help message. Printed as is, so it can be one line or have many+ -- lines. It should however have a final end-of-line character. The+ -- function is applied to the name of the program (which is+ -- retrieved at runtime.)++ -> Intersperse+ -- ^ What to do after encountering the first positional argument++ -> [C.OptSpec a]+ -- ^ All possible options. Do not add a @-h@ or @--help@ option;+ -- these are added for you.++ -> (String -> a)+ -- ^ How to handle positional arguments. This function is applied to+ -- the appropriate string every time the parser encounters a+ -- positional argument.++ -> IO [a]+ -- ^ If help is requested, the program will print it and exit+ -- successfully. If there was an error parsing the command line, the+ -- program will print an error message and exit+ -- unsuccessfully. Otherwise, the parsed arguments are returned.+simpleWithHelp h i os p = do+ let os' = addHelpOpt os+ as <- GetArgs.getArgs+ pn <- GetArgs.getProgName+ let exResult = simple i os' (fmap OtherArg p) as+ rs <- case exResult of+ Ex.Exception e -> do+ IO.hPutStr IO.stderr (C.formatError pn e)+ exitFailure+ Ex.Success g -> return g+ extractOpts pn h rs+++--+-- Mode parsing+--+ -- | Provides information on each mode that you wish to parse. data Mode result = forall b. Mode { mName :: String@@ -117,78 +211,165 @@ , mProcess :: [b] -> result -- ^ Processes the options after they have been parsed.++ , mHelp :: String -> String+ -- ^ Help string for this mode. This is used only in+ -- 'modesWithHelp'; 'modes' ignores this. This is displayed on+ -- screen exactly as is, so be sure to include the necessary+ -- trailing newline. The function is applied to the name of the+ -- program (which is retrieved at runtime.) } instance Functor Mode where- fmap f (Mode nm i os pa p) =- Mode nm i os pa (f . p)+ fmap f (Mode nm i os pa p h) =+ Mode nm i os pa (f . p) h -processModeArgs :: Mode result -> P.Parser result-processModeArgs (Mode _ i os pa p) = do+type DoHelp = Bool++modesWithHelpPure+ :: String+ -- ^ Program name+ -> (String -> String)+ -- ^ Global help+ -> [C.OptSpec a]+ -> ([a] -> Either ([String] -> result) [Mode result])+ -> [String]+ -> Ex.Exceptional P.Error (ArgWrapResult (ArgWrapResult result))+modesWithHelpPure pn getHlp globals lsToEi ss = P.parse ss $ do+ let globals' = addHelpOpt globals+ gs <- P.manyTill (C.parseOption globals') endOrNonOpt+ let (needsHelp, gblOs) = partitionHelp gs+ if needsHelp then return (NeedsHelp (getHlp pn)) else NoHelp <$>+ case lsToEi gblOs of+ Left parsePosArgs ->+ (NoHelp . parsePosArgs) <$> many P.nextWord <* P.end+ Right mds -> do+ let modeWords = Set.fromList . map mName $ mds+ (_, w) <- P.matchApproxWord modeWords+ let cmd = fromJust . find (\c -> mName c == w) $ mds+ processModeWithHelp pn cmd++modesNoHelp+ :: [C.OptSpec a]+ -> ([a] -> Either ([String] -> result) [Mode result])+ -> [String]+ -> Ex.Exceptional P.Error result+modesNoHelp globals lsToEi ss = P.parse ss $ do+ gs <- P.manyTill (C.parseOption globals) endOrNonOpt+ case lsToEi gs of+ Left parsePosArgs ->+ parsePosArgs <$> many P.nextWord <* P.end+ Right mds -> do+ let modeWords = Set.fromList . map mName $ mds+ (_, w) <- P.matchApproxWord modeWords+ let cmd = fromJust . find (\c -> mName c == w) $ mds+ processModeNoHelp cmd++processModeWithHelp+ :: String+ -- ^ Program name+ -> Mode result+ -> P.Parser (ArgWrapResult result)+processModeWithHelp pn (Mode _ i os pa p h) = do let prsr = case i of Intersperse -> parseIntersperse StopOptions -> parseStopOpts+ os' = addHelpOpt os+ rs <- prsr (C.parseOption os') (fmap OtherArg pa) <* P.end+ let (needsHelp, parsedOpts) = partitionHelp rs+ return $ if needsHelp then NeedsHelp (h pn) else NoHelp $ p parsedOpts+++processModeNoHelp+ :: Mode result+ -> P.Parser result+processModeNoHelp (Mode _ i os pa p _) = do+ let prsr = case i of+ Intersperse -> parseIntersperse+ StopOptions -> parseStopOpts rs <- prsr (C.parseOption os) pa <* P.end return $ p rs ++addHelpOpt :: [C.OptSpec a] -> [C.OptSpec (ArgWrap a)]+addHelpOpt os =+ let helpOpt = C.OptSpec ["help"] "h" (C.NoArg HelpArg)+ origOpts = fmap (fmap OtherArg) os+ in helpOpt : origOpts+ -- | Parses a command line that may feature options followed by a -- mode followed by more options and then followed by positional -- arguments. modes :: [C.OptSpec a]- -- ^ Global options. These come after the program name but before- -- the mode name.-- -> ([a] -> Ex.Exceptional String b)- -- ^ This function is applied to all the global options after- -- they are parsed. To indicate a failure, return an Exception- -- String; otherwise, return a successful value. This allows you- -- to process the global options before the mode is parsed. (If- -- you don't need to do any preprocessing, pass @return@ here.)- -- If you indicate a failure here, parsing of the command line- -- will stop and this error message will be returned.+ -- ^ Global options. These come after the program name but before+ -- the mode name. - -> (b -> Either (String -> c) [Mode result])- -- ^ This function determines whether modes will be parsed and,- -- if so, which ones. The function is applied to the result of- -- the pre-processing of the global options, so which modes are- -- parsed and the behavior of those modes can vary depending on- -- the global options. Return a Left to indicate that you do not- -- want to parse modes at all. For instance, if the user passed a- -- @--help@ option, you may not want to look for a mode after- -- that. Otherwise, to parse modes, return a Right with a list of- -- the modes.+ -> ([a] -> Either ([String] -> result) [Mode result])+ -- ^ This function will be applied to the result of parsing the+ -- global options. The function must return a @Left@ if you do not+ -- want to parse any modes at all. This can be useful if one of the+ -- global options was something like @--help@ or @--version@ and so+ -- you do not need to see any mode. The function returned in the+ -- @Left@ will be applied to a list of all remaining command-line+ -- arguments after the global options. -> [String]- -- ^ The command line to parse (presumably from 'getArgs')+ -- ^ The command line to parse (presumably from 'getArgs') - -> Ex.Exceptional P.Error (b, Either [c] result)- -- ^ Returns an Exception if an error was encountered when- -- parsing the command line (including if the global options- -- procesor returned an Exception.) Otherwise, returns a- -- pair. The first element of the pair is the result of the- -- global options processor. The second element of the pair is an- -- Either. It is Left if no modes were parsed, with a list of the- -- positional arguments. It is a Right if modes were parsed, with- -- the result of parsing the arguments to the mode.+ -> Ex.Exceptional P.Error result+ -- ^ Returns an Exception if an error was encountered when parsing+ -- any part of the command line (either the global options or the+ -- mode.) Otherwise, returns the result.+modes = modesNoHelp -modes globals lsToB getCmds ss = P.parse ss $ do- gs <- P.manyTill (C.parseOption globals) endOrNonOpt- b <- case lsToB gs of- Ex.Exception e -> fail e- Ex.Success g -> return g- let cmds = getCmds b- case cmds of- Left fPa -> do- posArgs <- (fmap (fmap fPa) $ many P.nextWord) <* P.end- return (b, Left posArgs)- Right cds -> do- let cmdWords = Set.fromList . map mName $ cds- (_, w) <- P.matchApproxWord cmdWords- let cmd = fromJust . find (\c -> mName c == w) $ cds- r <- processModeArgs cmd- return (b, Right r)+-- | Like 'modes', but runs in the IO monad. Gets the command line+-- arguments for you. This function adds the options @-h@ and+-- @--help@, both in the global options and in the options for each+-- mode. If @-h@ or @--help@ is entered in the global options, the+-- global help is shown and the program exits successfully; similarly,+-- if help is requested for a particular mode, that mode's help is+-- shown and the program exits successfully.+--+-- If an error occurs in the processing of the command line, an error+-- message is printed and the program exits with a failure.+modesWithHelp+ :: (String -> String)+ -- ^ Global help. This is a function that, when applied to the name+ -- of the program (which is retrieved at runtime), returns a help+ -- string. This is output exactly as is, so include any necessary+ -- trailing newlines.++ -> [C.OptSpec a]+ -- ^ Global options. These come after the program name but before+ -- the mode name. Do not add options for @-h@ or @--help@; these are+ -- added automatically.++ -> ([a] -> Either ([String] -> result) [Mode result])+ -- ^ This function will be applied to the result of parsing the+ -- global options. The function must return a @Left@ if you do not+ -- want to parse any modes at all. This can be useful if one of the+ -- global options was something like @--version@ and so+ -- you do not need to see any mode. The function returned in the+ -- @Left@ will be applied to a list of all remaining command-line+ -- arguments after the global options.++ -> IO result++modesWithHelp hlp glbls lsToEi = do+ as <- GetArgs.getArgs+ pn <- GetArgs.getProgName+ case modesWithHelpPure pn hlp glbls lsToEi as of+ Ex.Exception e -> do+ IO.hPutStr IO.stderr $ C.formatError pn e+ exitFailure+ Ex.Success g -> case g of+ NeedsHelp h -> putStr h >> exitSuccess+ NoHelp g2 -> case g2 of+ NeedsHelp h -> putStr h >> exitSuccess+ NoHelp g3 -> return g3+ -- | Looks at the next word. Succeeds if it is a non-option, or if we -- are at the end of input. Fails otherwise.
multiarg.cabal view
@@ -1,5 +1,5 @@ Name: multiarg-Version: 0.8.0.0+Version: 0.10.0.0 Cabal-version: >=1.8 Build-Type: Simple License: BSD3@@ -39,7 +39,7 @@ Library Build-depends: explicit-exception ==0.1.*,- containers ==0.4.*+ containers ==0.5.* -- See documentation in System.Console.MultiArg.GetArgs for details