-- | Functions for working with command line arguments and options. module System.Build.Args( quote, (~~), (~:), (~?), param, many, manys, (~~~>), (~~>), (-~>), (^^^), space, searchPath, tryEnvs ) where import Control.Monad import Data.Maybe import Data.List import qualified Data.Map as M import System.Environment import System.FilePath -- | Surrounds the given string in double-quotes. quote :: String -> String quote s = '"' : s ++ "\"" -- | An empty list if the boolean is @False@ otherwise the given string value with @'-'@ prepended. (~~) :: String -> Bool -> String g ~~ k = if k then '-' : g else [] -- | If the given list of file paths is empty, then returns the empty list. Otherwise prepend @'-'@ to the string followed by @' '@ then the search path separator intercalated in the list of file paths. -- -- > Posix -- > "123" ~?? ["abc", "def"] == "-123 \"abc\":\"def\"" -- > "123" ~?? ["abc", "def", "ghi"] == "-123 \"abc\":\"def\":\"ghi\"" (~:) :: String -> [FilePath] -> String _ ~: [] = [] s ~: z = '-' : s ++ ' ' : [searchPathSeparator] >===< z -- | If the given value is @Nothing@ return the empty list, otherwise run the given function. (~?) :: (k -> [a]) -> Maybe k -> [a] (~?) = maybe [] -- | If the given value is @Nothing@ return the empty list, otherwise prepend @'-'@ to the given string followed by the given character followed by surrounding the result of running the given function in double-quotes. -- -- > param "abc" 'x' id (Just "tuv") == "-abcx\"tuv\"" -- > param "abc" 'x' id Nothing == "" param :: String -> Char -> (k -> String) -> Maybe k -> String param k c s = (~?) (\z -> '-' : k ++ c : quote (s z)) -- | A parameter with many values interspersed by @' '@. -- -- > many "abc" ["tuv", "wxy"] == "-abc \"tuv\" -abc \"wxy\"" many :: String -> [String] -> String many k v = intercalate " " $ map (k ~~~>) v -- | A parameter with many values interspersed by @' '@. -- -- > manys id "abc" ["tuv", "wxy"] == "-abc \"tuv\" -abc \"wxy\"" manys :: (a -> String) -> String -> [a] -> String manys f k = many k . map f -- | Prepends @'-'@ followed by the first value then @' '@ then the second value surrounded by double-quotes. -- -- > "abc" ~~~> "def" == "-abc \"def\"" (~~~>) :: String -> String -> String (~~~>) = (. Just) . (~~>) -- | If the given value is @Nothing@ return the empty list, otherwise prepend @'-'@ followed by the first value then @' '@ followed by surrounding the result of running the given function in double-quotes. -- -- > "abc" ~~> Just "def" == "-abc \"def\"" -- > "abc" ~~> Nothing == "" (~~>) :: (Show k) => String -> Maybe k -> String (~~>) k = param k ' ' show -- | If the given value is @Nothing@ return the empty list, otherwise prepend @'-'@ followed by the first value then @':'@ followed by surrounding the result of @show@ in double-quotes. -- -- > "abc" ~~> Just "def" == "-abc:\"def\"" -- > "abc" ~~> Nothing == "" (-~>) :: (Show k) => String -> Maybe k -> String (-~>) k = param k ':' show -- | Removes all empty lists from the first argument the intercalates the second argument. -- -- > ["abc", "", "def"] ^^^ "x" == "abcxdef" (^^^) :: [[a]] -> [a] -> [a] g ^^^ t = Data.List.intercalate t (filter (not . null) g) -- | Surrounds each given value in double-quotes then intercalates @' '@. -- -- > space ["abc", "def"] == "\"abc\" \"def\"" space :: [String] -> String space = (>===<) " " -- | Surrounds each given value in double-quotes then intercalates @[searchPathSeparator]@. -- -- > searchPath ["abc", "def"] == "\"abc\":\"def\"" searchPath :: [String] -> String searchPath = (>===<) [searchPathSeparator] -- | Look up the given environment variables. The first one found that exists has its associated function called to produce a value. tryEnvs :: [(String, String -> a)] -> IO (Maybe a) tryEnvs es = do e <- getEnvironment let k [] = Nothing k ((a, b):t) = fmap b (a `M.lookup` M.fromList e) `mplus` k t return (k es) -- not exported (>===<) :: String -> [String] -> String s >===< k = intercalate s (fmap quote k)