module General.GetOpt( OptDescr(..), ArgDescr(..), getOpt, fmapFmapOptDescr, showOptDescr, mergeOptDescr, removeOverlap, optionsEnum, optionsEnumDesc ) where import qualified System.Console.GetOpt as O import System.Console.GetOpt hiding (getOpt) import qualified Data.HashSet as Set import Data.Maybe import Data.Either import Data.List.Extra getOpt :: [OptDescr (Either String a)] -> [String] -> ([a], [String], [String]) getOpt opts args = (flagGood, files, flagBad ++ errs) where (flags, files, errs) = O.getOpt O.Permute opts args (flagBad, flagGood) = partitionEithers flags fmapFmapOptDescr :: (a -> b) -> OptDescr (Either String a) -> OptDescr (Either String b) fmapFmapOptDescr f = fmap (fmap f) showOptDescr :: [OptDescr a] -> [String] showOptDescr xs = concat [ if nargs <= 26 then [" " ++ args ++ replicate (28 - nargs) ' ' ++ desc] else [" " ++ args, replicate 30 ' ' ++ desc] | Option s l arg desc <- xs , let args = intercalate ", " $ map (short arg) s ++ map (long arg) l , let nargs = length args] where short NoArg{} x = "-" ++ [x] short (ReqArg _ b) x = "-" ++ [x] ++ " " ++ b short (OptArg _ b) x = "-" ++ [x] ++ "[" ++ b ++ "]" long NoArg{} x = "--" ++ x long (ReqArg _ b) x = "--" ++ x ++ "=" ++ b long (OptArg _ b) x = "--" ++ x ++ "[=" ++ b ++ "]" -- | Remove flags from the first field that are present in the second removeOverlap :: [OptDescr b] -> [OptDescr a] -> [OptDescr a] removeOverlap bad = mapMaybe f where short = Set.fromList $ concat [x | Option x _ _ _ <- bad] long = Set.fromList $ concat [x | Option _ x _ _ <- bad] f (Option a b c d) | null a2 && null b2 = Nothing | otherwise = Just $ Option a2 b2 c d where a2 = filter (not . flip Set.member short) a b2 = filter (not . flip Set.member long) b mergeOptDescr :: [OptDescr (Either String a)] -> [OptDescr (Either String b)] -> [OptDescr (Either String (Either a b))] mergeOptDescr xs ys = map (fmapFmapOptDescr Left) xs ++ map (fmapFmapOptDescr Right) ys optionsEnum :: (Enum a, Bounded a, Show a) => [OptDescr (Either String a)] optionsEnum = optionsEnumDesc [(x, "Flag " ++ lower (show x) ++ ".") | x <- [minBound..maxBound]] optionsEnumDesc :: Show a => [(a, String)] -> [OptDescr (Either String a)] optionsEnumDesc xs = [Option "" [lower $ show x] (NoArg $ Right x) d | (x,d) <- xs]