    {-# LANGUAGE RecordWildCards #-}
    module System.Console.CmdArgs.Explicit.ExpandArgsAt(expandArgsAt) where

    import System.FilePath

    -- | Expand @\@@ directives in a list of arguments, usually obtained from 'getArgs'.
    --   As an example, given the file @test.txt@ with the lines @hello@ and @world@:
    --
    -- > expandArgsAt ["@test.txt","!"] == ["hello","world","!"]
    --
    --   Any @\@@ directives in the files will be recursively expanded (raising an error
    --   if there is infinite recursion).
    --
    --   To supress @\@@ expansion, pass any @\@@ arguments after @--@.
    expandArgsAt :: [String] -> IO [String]
    expandArgsAt :: [String] -> IO [String]
    expandArgsAt [String]
    args = do
            ebefore <- (String -> IO [String]) -> [String] -> IO [[String]]
    forall (t :: * -> *) (m :: * -> *) a b.
    (Traversable t, Monad m) =>
    (a -> m b) -> t a -> m (t b)
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
    mapM ([String] -> String -> String -> IO [String]
    f [] String
    ".") [String]
    before
            return $ concat ebefore ++ after
        where
            ([String]
    before,[String]
    after) = (String -> Bool) -> [String] -> ([String], [String])
    forall a. (a -> Bool) -> [a] -> ([a], [a])
    break (String -> String -> Bool
    forall a. Eq a => a -> a -> Bool
    == String
    "--") [String]
    args

            f :: [String] -> String -> String -> IO [String]
    f [String]
    seen String
    dir (Char
    '@':String
    x)
                | String
    x String -> [String] -> Bool
    forall a. Eq a => a -> [a] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem` [String]
    seen = String -> IO [String]
    forall a. HasCallStack => String -> a
    error (String -> IO [String]) -> String -> IO [String]
    forall a b. (a -> b) -> a -> b
    $ [String] -> String
    unlines ([String] -> String) -> [String] -> String
    forall a b. (a -> b) -> a -> b
    $
                    String
    "System.Console.CmdArgs.Explicit.expandArgsAt, recursion in @ directives:" String -> [String] -> [String]
    forall a. a -> [a] -> [a]
    :
                    (String -> String) -> [String] -> [String]
    forall a b. (a -> b) -> [a] -> [b]
    map (String
    "  "String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++) ([String] -> [String]
    forall a. [a] -> [a]
    reverse ([String] -> [String]) -> [String] -> [String]
    forall a b. (a -> b) -> a -> b
    $ String
    xString -> [String] -> [String]
    forall a. a -> [a] -> [a]
    :[String]
    seen)
                | [String] -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length [String]
    seen Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    > Int
    15 = String -> IO [String]
    forall a. HasCallStack => String -> a
    error (String -> IO [String]) -> String -> IO [String]
    forall a b. (a -> b) -> a -> b
    $ [String] -> String
    unlines ([String] -> String) -> [String] -> String
    forall a b. (a -> b) -> a -> b
    $
                    String
    "System.Console.CmdArgs.Explicit.expandArgsAt, over 15 @ directives deep:" String -> [String] -> [String]
    forall a. a -> [a] -> [a]
    :
                    (String -> String) -> [String] -> [String]
    forall a b. (a -> b) -> [a] -> [b]
    map (String
    "  "String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++) ([String] -> [String]
    forall a. [a] -> [a]
    reverse [String]
    seen)
                | Bool
    otherwise = do
                    src <- String -> IO String
    readFile (String -> IO String) -> String -> IO String
    forall a b. (a -> b) -> a -> b
    $ String
    dir String -> String -> String
    </> String
    x
                    fmap concat $ mapM (f (x:seen) (takeDirectory x)) $ lines src
            f [String]
    _ String
    _ String
    x = [String] -> IO [String]
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return [String
    x]