{-# OPTIONS_GHC -Wunused-imports #-} -- | Expand environment variables in strings module Agda.Utils.Environment ( EnvVars , expandEnvironmentVariables , expandEnvVarTelescope ) where import Data.Char import Data.Maybe import System.Environment import System.Directory ( getHomeDirectory ) expandEnvironmentVariables :: String -> IO String expandEnvironmentVariables s = do env <- getEnvironment home <- getHomeDirectory return $ expandVars home env s expandVars :: String -- ^ Home directory. -> EnvVars -- ^ Environment variable substitution map. -> String -- ^ Input. -> String -- ^ Output with variables and @~@ (home) substituted. expandVars home env s = concatMap repl $ tokens s where repl Home = home ++ "/" repl (Var x) = fromMaybe "" $ lookup x env repl (Str s) = s -- | List of environment variable bindings. type EnvVars = [(String, String)] -- | Expand a telescope of environment variables -- (each value may refer to variables earlier in the list). expandEnvVarTelescope :: String -> EnvVars -> EnvVars expandEnvVarTelescope home = reverse . foldl -- foldl reverses, so re-reverse afterwards (\ acc (var, val) -> (var, expandVars home acc val) : acc) [] -- | Tokenization for environment variable substitution. data Token = Home -- ^ @~@. | Var String -- ^ @$VARIABLE@ or @${VARIABLE}$. | Str String -- ^ Ordinary characters. deriving (Eq, Show) -- | Tokenize a string. -- The @~@ is recognized as @$HOME@ only at the beginning of the string. tokens :: String -> [Token] tokens = \case '~' : '/' : s -> Home : tokens' s '\\' : '~' : s -> cons '~' $ tokens' s s -> tokens' s where tokens' :: String -> [Token] tokens' = \case '$' : '$' : s -> cons '$' $ tokens' s '$' : s@(c : _) | c == '_' || isAlpha c -> Var x : tokens' s' where (x, s') = span (\ c -> c == '_' || isAlphaNum c) s '$' : '{' : s -> case break (== '}') s of (x, '}' : s) -> Var x : tokens' s _ -> [Str $ "${" ++ s] -- abort on unterminated '{' c : s -> cons c $ tokens' s "" -> [] cons :: Char -> [Token] -> [Token] cons c (Str s : ts) = Str (c : s) : ts cons c ts = Str [c] : ts