-----------------------------------------------------------------------------
-- |
-- 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 Control.Applicative  ((<$>))
import Data.Maybe (fromMaybe)
import System.Environment   (lookupEnv)

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

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

  _    -> do
    String
remainder <- String -> IO String
expandEnv String
s
    String -> IO String
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> IO String) -> String -> IO String
forall a b. (a -> b) -> a -> b
$ Char
c Char -> String -> String
forall a. a -> [a] -> [a]
: String
remainder