module GetOpt.Declarative.Interpret ( ParseResult(..) , parseCommandLineOptions , parse , interpretOptions ) where import Prelude () import Test.Hspec.Core.Compat import Data.Maybe import System.Console.GetOpt (OptDescr, ArgOrder(..), getOpt) import qualified System.Console.GetOpt as GetOpt import GetOpt.Declarative.Types import GetOpt.Declarative.Util (mkUsageInfo, mapOptDescr) data InvalidArgument = InvalidArgument String String data ParseResult config = Help String | Failure String | Success config parseCommandLineOptions :: [(String, [Option config])] -> String -> [String] -> config -> ParseResult config parseCommandLineOptions :: forall config. [(String, [Option config])] -> String -> [String] -> config -> ParseResult config parseCommandLineOptions [(String, [Option config])] opts String prog [String] args config config = case forall config. [OptDescr (Maybe (config -> Either InvalidArgument config))] -> config -> [String] -> Maybe (Either String config) parseWithHelp (forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b] concatMap forall a b. (a, b) -> b snd [(String, [OptDescr (Maybe (config -> Either InvalidArgument config))])] options) config config [String] args of Maybe (Either String config) Nothing -> forall config. String -> ParseResult config Help String usage Just (Right config c) -> forall config. config -> ParseResult config Success config c Just (Left String err) -> forall config. String -> ParseResult config Failure forall a b. (a -> b) -> a -> b $ String prog forall a. [a] -> [a] -> [a] ++ String ": " forall a. [a] -> [a] -> [a] ++ String err forall a. [a] -> [a] -> [a] ++ String "\nTry `" forall a. [a] -> [a] -> [a] ++ String prog forall a. [a] -> [a] -> [a] ++ String " --help' for more information.\n" where options :: [(String, [OptDescr (Maybe (config -> Either InvalidArgument config))])] options = forall a a1. [(a, [OptDescr a1])] -> [(a, [OptDescr (Maybe a1)])] addHelpFlag forall a b. (a -> b) -> a -> b $ forall a b. (a -> b) -> [a] -> [b] map (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b fmap forall config. [Option config] -> [OptDescr (config -> Either InvalidArgument config)] interpretOptions) [(String, [Option config])] opts documentedOptions :: [(String, [OptDescr (Maybe (config -> Either InvalidArgument config))])] documentedOptions = forall a a1. [(a, [OptDescr a1])] -> [(a, [OptDescr (Maybe a1)])] addHelpFlag forall a b. (a -> b) -> a -> b $ forall a b. (a -> b) -> [a] -> [b] map (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b fmap forall a b. (a -> b) -> a -> b $ forall config. [Option config] -> [OptDescr (config -> Either InvalidArgument config)] interpretOptions forall b c a. (b -> c) -> (a -> b) -> a -> c . forall a. (a -> Bool) -> [a] -> [a] filter forall config. Option config -> Bool optionDocumented) [(String, [Option config])] opts usage :: String usage :: String usage = String "Usage: " forall a. [a] -> [a] -> [a] ++ String prog forall a. [a] -> [a] -> [a] ++ String " [OPTION]...\n\n" forall a. [a] -> [a] -> [a] ++ (forall a. [a] -> [[a]] -> [a] intercalate String "\n" forall a b. (a -> b) -> a -> b $ forall a b. (a -> b) -> [a] -> [b] map (forall a b c. (a -> b -> c) -> (a, b) -> c uncurry forall a. String -> [OptDescr a] -> String mkUsageInfo) [(String, [OptDescr (Maybe (config -> Either InvalidArgument config))])] documentedOptions) addHelpFlag :: [(a, [OptDescr a1])] -> [(a, [OptDescr (Maybe a1)])] addHelpFlag :: forall a a1. [(a, [OptDescr a1])] -> [(a, [OptDescr (Maybe a1)])] addHelpFlag [(a, [OptDescr a1])] opts = case [(a, [OptDescr a1])] opts of (a section, [OptDescr a1] xs) : [(a, [OptDescr a1])] ys -> (a section, forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a GetOpt.Option [] [String "help"] (forall a. a -> ArgDescr a GetOpt.NoArg forall {a}. Maybe a help) String "display this help and exit" forall a. a -> [a] -> [a] : forall a. [OptDescr a] -> [OptDescr (Maybe a)] noHelp [OptDescr a1] xs) forall a. a -> [a] -> [a] : forall a b. (a -> b) -> [a] -> [b] map (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b fmap forall a. [OptDescr a] -> [OptDescr (Maybe a)] noHelp) [(a, [OptDescr a1])] ys [] -> [] where help :: Maybe a help = forall {a}. Maybe a Nothing noHelp :: [OptDescr a] -> [OptDescr (Maybe a)] noHelp :: forall a. [OptDescr a] -> [OptDescr (Maybe a)] noHelp = forall a b. (a -> b) -> [a] -> [b] map (forall a b. (a -> b) -> OptDescr a -> OptDescr b mapOptDescr forall a. a -> Maybe a Just) parseWithHelp :: [OptDescr (Maybe (config -> Either InvalidArgument config))] -> config -> [String] -> Maybe (Either String config) parseWithHelp :: forall config. [OptDescr (Maybe (config -> Either InvalidArgument config))] -> config -> [String] -> Maybe (Either String config) parseWithHelp [OptDescr (Maybe (config -> Either InvalidArgument config))] options config config [String] args = case forall a. ArgOrder a -> [OptDescr a] -> [String] -> ([a], [String], [String]) getOpt forall a. ArgOrder a Permute [OptDescr (Maybe (config -> Either InvalidArgument config))] options [String] args of ([Maybe (config -> Either InvalidArgument config)] opts, [], []) | () _ : [()] _ <- [() | Maybe (config -> Either InvalidArgument config) Nothing <- [Maybe (config -> Either InvalidArgument config)] opts] -> forall {a}. Maybe a Nothing ([Maybe (config -> Either InvalidArgument config)] opts, [String] xs, [String] ys) -> forall a. a -> Maybe a Just forall a b. (a -> b) -> a -> b $ forall config. config -> ([config -> Either InvalidArgument config], [String], [String]) -> Either String config interpretResult config config (forall a. [Maybe a] -> [a] catMaybes [Maybe (config -> Either InvalidArgument config)] opts, [String] xs, [String] ys) parse :: [OptDescr (config -> Either InvalidArgument config)] -> config -> [String] -> Either String config parse :: forall config. [OptDescr (config -> Either InvalidArgument config)] -> config -> [String] -> Either String config parse [OptDescr (config -> Either InvalidArgument config)] options config config = forall config. config -> ([config -> Either InvalidArgument config], [String], [String]) -> Either String config interpretResult config config forall b c a. (b -> c) -> (a -> b) -> a -> c . forall a. ArgOrder a -> [OptDescr a] -> [String] -> ([a], [String], [String]) getOpt forall a. ArgOrder a Permute [OptDescr (config -> Either InvalidArgument config)] options interpretResult :: config -> ([config -> Either InvalidArgument config], [String], [String]) -> Either String config interpretResult :: forall config. config -> ([config -> Either InvalidArgument config], [String], [String]) -> Either String config interpretResult config config = forall a. ([a], [String], [String]) -> Either String [a] interpretGetOptResult forall (m :: * -> *) a b c. Monad m => (a -> m b) -> (b -> m c) -> a -> m c >=> forall config. config -> [config -> Either InvalidArgument config] -> Either String config foldResult config config foldResult :: config -> [config -> Either InvalidArgument config] -> Either String config foldResult :: forall config. config -> [config -> Either InvalidArgument config] -> Either String config foldResult config config [config -> Either InvalidArgument config] opts = forall a c b. (a -> c) -> (b -> c) -> Either a b -> c either (forall a b. a -> Either a b Left forall b c a. (b -> c) -> (a -> b) -> a -> c . InvalidArgument -> String renderInvalidArgument) forall (m :: * -> *) a. Monad m => a -> m a return forall a b. (a -> b) -> a -> b $ forall (t :: * -> *) (m :: * -> *) b a. (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m b foldlM (forall a b c. (a -> b -> c) -> b -> a -> c flip forall a. a -> a id) config config [config -> Either InvalidArgument config] opts renderInvalidArgument :: InvalidArgument -> String renderInvalidArgument :: InvalidArgument -> String renderInvalidArgument (InvalidArgument String name String value) = String "invalid argument `" forall a. [a] -> [a] -> [a] ++ String value forall a. [a] -> [a] -> [a] ++ String "' for `--" forall a. [a] -> [a] -> [a] ++ String name forall a. [a] -> [a] -> [a] ++ String "'" interpretGetOptResult :: ([a], [String], [String]) -> Either String [a] interpretGetOptResult :: forall a. ([a], [String], [String]) -> Either String [a] interpretGetOptResult ([a], [String], [String]) result = case ([a], [String], [String]) result of ([a] opts, [], []) -> forall a b. b -> Either a b Right [a] opts ([a] _, [String] _, String err:[String] _) -> forall a b. a -> Either a b Left (forall a. [a] -> [a] init String err) ([a] _, String arg:[String] _, [String] _) -> forall a b. a -> Either a b Left (String "unexpected argument `" forall a. [a] -> [a] -> [a] ++ String arg forall a. [a] -> [a] -> [a] ++ String "'") interpretOptions :: [Option config] -> [OptDescr (config -> Either InvalidArgument config)] interpretOptions :: forall config. [Option config] -> [OptDescr (config -> Either InvalidArgument config)] interpretOptions = forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b] concatMap forall config. Option config -> [OptDescr (config -> Either InvalidArgument config)] interpretOption interpretOption :: Option config -> [OptDescr (config -> Either InvalidArgument config)] interpretOption :: forall config. Option config -> [OptDescr (config -> Either InvalidArgument config)] interpretOption (Option String name Maybe Char shortcut OptionSetter config argDesc String help Bool _) = case OptionSetter config argDesc of NoArg config -> config setter -> [forall {a}. ArgDescr a -> OptDescr a option forall a b. (a -> b) -> a -> b $ forall a. a -> ArgDescr a GetOpt.NoArg (forall a b. b -> Either a b Right forall b c a. (b -> c) -> (a -> b) -> a -> c . config -> config setter)] Flag Bool -> config -> config setter -> [ forall {a}. ArgDescr a -> OptDescr a option (forall {a}. Bool -> ArgDescr (config -> Either a config) arg Bool True) , forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a GetOpt.Option [] [String "no-" forall a. [a] -> [a] -> [a] ++ String name] (forall {a}. Bool -> ArgDescr (config -> Either a config) arg Bool False) (String "do not " forall a. [a] -> [a] -> [a] ++ String help) ] where arg :: Bool -> ArgDescr (config -> Either a config) arg Bool v = forall a. a -> ArgDescr a GetOpt.NoArg (forall a b. b -> Either a b Right forall b c a. (b -> c) -> (a -> b) -> a -> c . Bool -> config -> config setter Bool v) OptArg String argName Maybe String -> config -> Maybe config setter -> [forall {a}. ArgDescr a -> OptDescr a option forall a b. (a -> b) -> a -> b $ forall a. (Maybe String -> a) -> String -> ArgDescr a GetOpt.OptArg Maybe String -> config -> Either InvalidArgument config arg String argName] where arg :: Maybe String -> config -> Either InvalidArgument config arg Maybe String mInput config c = case Maybe String -> config -> Maybe config setter Maybe String mInput config c of Just config c_ -> forall a b. b -> Either a b Right config c_ Maybe config Nothing -> case Maybe String mInput of Just String input -> forall {b}. String -> Either InvalidArgument b invalid String input Maybe String Nothing -> forall a b. b -> Either a b Right config c Arg String argName String -> config -> Maybe config setter -> [forall {a}. ArgDescr a -> OptDescr a option (forall a. (String -> a) -> String -> ArgDescr a GetOpt.ReqArg String -> config -> Either InvalidArgument config arg String argName)] where arg :: String -> config -> Either InvalidArgument config arg String input = forall b a. b -> (a -> b) -> Maybe a -> b maybe (forall {b}. String -> Either InvalidArgument b invalid String input) forall a b. b -> Either a b Right forall b c a. (b -> c) -> (a -> b) -> a -> c . String -> config -> Maybe config setter String input where invalid :: String -> Either InvalidArgument b invalid = forall a b. a -> Either a b Left forall b c a. (b -> c) -> (a -> b) -> a -> c . String -> String -> InvalidArgument InvalidArgument String name option :: ArgDescr a -> OptDescr a option ArgDescr a arg = forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a GetOpt.Option (forall a. Maybe a -> [a] maybeToList Maybe Char shortcut) [String name] ArgDescr a arg String help