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 ++ "]"
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 <- enumerate]
optionsEnumDesc :: Show a => [(a, String)] -> [OptDescr (Either String a)]
optionsEnumDesc xs = [Option "" [lower $ show x] (NoArg $ Right x) d | (x,d) <- xs]