-----------------------------------------------------------------------------
-- |
-- Module      :  XMobar.Environment
-- Copyright   :  (c) William Song
-- License     :  BSD-style (see LICENSE)
--
-- Maintainer  :  Will Song <incertia@incertia.net>
-- Stability   :  stable
-- Portability :  portable
--
-- A function to expand environment variables in strings
--
-----------------------------------------------------------------------------
module Xmobar.System.Environment(expandEnv) where

import qualified Data.Maybe as M
import qualified System.Environment as E

expandEnv :: String -> IO String
expandEnv :: [Char] -> IO [Char]
expandEnv [Char]
"" = [Char] -> IO [Char]
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return [Char]
""
expandEnv (Char
c:[Char]
s) = case Char
c of
  Char
'$'       -> do
    envVar <- [Char] -> Maybe [Char] -> [Char]
forall a. a -> Maybe a -> a
M.fromMaybe [Char]
"" (Maybe [Char] -> [Char]) -> IO (Maybe [Char]) -> IO [Char]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Char] -> IO (Maybe [Char])
E.lookupEnv [Char]
e
    remainder <- expandEnv s'
    return $ envVar ++ remainder
    where ([Char]
e, [Char]
s') = [Char] -> ([Char], [Char])
getVar [Char]
s
          getVar :: [Char] -> ([Char], [Char])
getVar [Char]
"" = ([Char]
"", [Char]
"")
          getVar (Char
'{':[Char]
s'') = ([Char] -> [Char] -> [Char]
forall {t :: * -> *} {a}. (Foldable t, Eq a) => t a -> [a] -> [a]
takeUntil [Char]
"}" [Char]
s'', Int -> [Char] -> [Char]
forall a. Int -> [a] -> [a]
drop Int
1 ([Char] -> [Char]) -> ([Char] -> [Char]) -> [Char] -> [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> [Char] -> [Char]
forall {t :: * -> *} {a}. (Foldable t, Eq a) => t a -> [a] -> [a]
dropUntil [Char]
"}" ([Char] -> [Char]) -> [Char] -> [Char]
forall a b. (a -> b) -> a -> b
$ [Char]
s'')
          getVar [Char]
s'' = ([Char] -> [Char] -> [Char]
forall {t :: * -> *} {a}. (Foldable t, Eq a) => t a -> [a] -> [a]
takeUntil [Char]
filterstr [Char]
s'', [Char] -> [Char] -> [Char]
forall {t :: * -> *} {a}. (Foldable t, Eq a) => t a -> [a] -> [a]
dropUntil [Char]
filterstr [Char]
s'')
          filterstr :: [Char]
filterstr = [Char]
",./? \t;:\"'~`!@#$%^&*()<>-+=\\|"
          takeUntil :: t a -> [a] -> [a]
takeUntil t a
f = (a -> Bool) -> [a] -> [a]
forall a. (a -> Bool) -> [a] -> [a]
takeWhile (Bool -> Bool
not (Bool -> Bool) -> (a -> Bool) -> a -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> t a -> Bool) -> t a -> a -> Bool
forall a b c. (a -> b -> c) -> b -> a -> c
flip a -> t a -> Bool
forall a. Eq a => a -> t a -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem t a
f)
          dropUntil :: t a -> [a] -> [a]
dropUntil t a
f = (a -> Bool) -> [a] -> [a]
forall a. (a -> Bool) -> [a] -> [a]
dropWhile (Bool -> Bool
not (Bool -> Bool) -> (a -> Bool) -> a -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> t a -> Bool) -> t a -> a -> Bool
forall a b c. (a -> b -> c) -> b -> a -> c
flip a -> t a -> Bool
forall a. Eq a => a -> t a -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem t a
f)

  Char
'\\' -> case [Char]
s [Char] -> [Char] -> Bool
forall a. Eq a => a -> a -> Bool
== [Char]
"" of
    Bool
True  -> [Char] -> IO [Char]
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return [Char]
"\\"
    Bool
False -> do
      remainder <- [Char] -> IO [Char]
expandEnv ([Char] -> IO [Char]) -> [Char] -> IO [Char]
forall a b. (a -> b) -> a -> b
$ Int -> [Char] -> [Char]
forall a. Int -> [a] -> [a]
drop Int
1 [Char]
s
      return $ escString s ++ remainder
      where escString :: [Char] -> [Char]
escString (Char
cc:[Char]
_) =
              case Char
cc of
                Char
't' -> [Char]
"\t"
                Char
'n' -> [Char]
"\n"
                Char
'$' -> [Char]
"$"
                Char
_   -> [Char
cc]
            escString [] = [Char]
""

  Char
_    -> do
    remainder <- [Char] -> IO [Char]
expandEnv [Char]
s
    return $ c : remainder