module Args (ArgSpec (..), handleArgs) where import Data.List (partition, stripPrefix) data ArgSpec a = ArgSpec { optName :: String, updateCfg :: a -> [String] -> a, info :: String } -- | Updates a config based on the given list of ArgSpecs and command line -- arguments. If --help is encountered within the arguments, we stop -- everything and just return a help message. handleArgs :: a -> [ArgSpec a] -> [String] -> Either String (a, [String]) handleArgs cfg specs args = if elem "--help" cfgargs then Left (printHelp specs) else Right (foldl (matchSpec specs) cfg (map (drop 2) cfgargs), rest) where (cfgargs, rest) = partition ((== "--") . take 2) args matchSpec :: [ArgSpec a] -> a -> String -> a matchSpec specs cfg arg = foldl updCfg cfg matchingSpecs where updCfg cfg' (spec, args) = updateCfg spec cfg' (commaBreak args) specArgs = map (\spec -> stripPrefix (optName spec) arg) specs matchingSpecs = map (\(s, Just a) -> (s, a)) $ filter isMatching (zip specs specArgs) isMatching (_, Nothing) = False isMatching _ = True -- | Like 'words', except it breaks on commas instead of spaces. commaBreak :: String -> [String] commaBreak [] = [] commaBreak s = case span (/= ',') s of (w, ws) -> w : commaBreak (drop 1 ws) printHelp :: [ArgSpec a] -> String printHelp = unlines . map helpString helpString :: ArgSpec a -> String helpString spec = "--" ++ hdr ++ "\n " ++ info spec ++ "\n" where hdr = case last $ optName spec of '=' -> optName spec ++ "" _ -> optName spec