{-# 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
        [[String]]
ebefore <- forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM ([String] -> String -> String -> IO [String]
f [] String
".") [String]
before
        forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[String]]
ebefore forall a. [a] -> [a] -> [a]
++ [String]
after
    where
        ([String]
before,[String]
after) = forall a. (a -> Bool) -> [a] -> ([a], [a])
break (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 forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [String]
seen = forall a. HasCallStack => String -> a
error forall a b. (a -> b) -> a -> b
$ [String] -> String
unlines forall a b. (a -> b) -> a -> b
$
                String
"System.Console.CmdArgs.Explicit.expandArgsAt, recursion in @ directives:" forall a. a -> [a] -> [a]
:
                forall a b. (a -> b) -> [a] -> [b]
map (String
"  "forall a. [a] -> [a] -> [a]
++) (forall a. [a] -> [a]
reverse forall a b. (a -> b) -> a -> b
$ String
xforall a. a -> [a] -> [a]
:[String]
seen)
            | forall (t :: * -> *) a. Foldable t => t a -> Int
length [String]
seen forall a. Ord a => a -> a -> Bool
> Int
15 = forall a. HasCallStack => String -> a
error forall a b. (a -> b) -> a -> b
$ [String] -> String
unlines forall a b. (a -> b) -> a -> b
$
                String
"System.Console.CmdArgs.Explicit.expandArgsAt, over 15 @ directives deep:" forall a. a -> [a] -> [a]
:
                forall a b. (a -> b) -> [a] -> [b]
map (String
"  "forall a. [a] -> [a] -> [a]
++) (forall a. [a] -> [a]
reverse [String]
seen)
            | Bool
otherwise = do
                String
src <- String -> IO String
readFile forall a b. (a -> b) -> a -> b
$ String
dir String -> String -> String
</> String
x
                forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM ([String] -> String -> String -> IO [String]
f (String
xforall a. a -> [a] -> [a]
:[String]
seen) (String -> String
takeDirectory String
x)) forall a b. (a -> b) -> a -> b
$ String -> [String]
lines String
src
        f [String]
_ String
_ String
x = forall (m :: * -> *) a. Monad m => a -> m a
return [String
x]