packages feed

hsenv-0.3: src/Util/Args/GetOpt.hs

{-# LANGUAGE MultiParamTypeClasses
  , FunctionalDependencies
  , TypeSynonymInstances
  , FlexibleInstances
  , Arrows
  #-}
module Util.Args.GetOpt ( GetOpt(..)
                        , Switch(..)
                        , DynOpt(..)
                        , StaticOpt(..)
                        ) where

import Util.Args.ArgArrow (ArgArrow, askArgs, addKnownArg)
import Util.Args.ArgDescr (DefaultValue(..), ArgDescr(..))
import Util.Args.RawArgs (Args(..))
import Data.Maybe (fromMaybe)
import Control.Arrow (returnA)

-- getOpt method takes a cli option description and returns at runtime value for that option.
-- it also statically records information about such option (and uses it to generate usage)
class GetOpt a b | a -> b where
    getOpt :: a -> ArgArrow () b

-- description of a cli switch, getOpt-ing it will return True if it's present
-- in cli args and False otherwise
data Switch =
    Switch { switchName  :: String     -- switch long name (e.g. 'verbose' for '--verbose')
           , switchHelp  :: String     -- human readable switch description (used for usage msg)
           , switchShort :: Maybe Char -- optional short version of this switch
                                      -- (e.g. 'v' for '-v')
           }

instance GetOpt Switch Bool where
    getOpt descr = proc () -> do
      addKnownArg [SwitchDescr (switchName descr)
                               (switchHelp descr)
                               (switchShort descr)] -< ()
      args <- askArgs -< ()
      let longSwitchStatus = switchName descr `elem` switches args
          switchStatus = case switchShort descr of
                           Nothing -> longSwitchStatus
                           Just c  -> longSwitchStatus || c `elem` shortSwitches args
      returnA -< switchStatus

-- description of a key,value cli argument, that if not present,
-- defaults to a value returned by some dynamic process
-- getOpt-ing it will return Just its value if it's present in cli args,
-- otherwise Nothing
data DynOpt =
    DynOpt { dynOptName        :: String -- key name (e.g. 'foo' for '--foo=bar')
           , dynOptTemplate    :: String -- help template for value
                                        -- (e.g. 'PATH' for --binary=PATH)
           , dynOptDescription :: String -- human readable description of a process
                                        -- that will provide default value
                                        -- (e.g. 'current directory')
           , dynOptHelp        :: String -- human readable switch description
                                        -- (used for usage msg)
           }

instance GetOpt DynOpt (Maybe String) where
    getOpt descr = proc () -> do
      addKnownArg [ValArg (dynOptName descr)
                          (dynOptTemplate descr)
                          (DynValue $ dynOptDescription descr)
                          (dynOptHelp descr)] -< ()
      args <- askArgs -< ()
      returnA -< lookup (dynOptName descr) $ valArgs args

-- description of a key,value cli argument, that if not present,
-- defaults to an explicit value
-- getOpt-ing it will return String with its value if it's present in cli args,
-- otherwise default value is returned
data StaticOpt =
    StaticOpt { staticOptName     :: String -- key name (e.g. 'foo' for '--foo=bar')
              , staticOptTemplate :: String -- help template for value
                                           -- (e.g. 'PATH' for --binary=PATH)
              , staticOptDefault  :: String -- default value for this argument
              , staticOptHelp     :: String -- human readable switch description
                                           -- (used for usage msg)
              }

instance GetOpt StaticOpt String where
    getOpt descr = proc () -> do
      addKnownArg [ValArg (staticOptName descr)
                          (staticOptTemplate descr)
                          (DynValue $ staticOptDefault descr)
                          (staticOptHelp descr)] -< ()
      args <- askArgs -< ()
      returnA -< fromMaybe (staticOptDefault descr)
                          $ lookup (staticOptName descr)
                          $ valArgs args