module Options.Harg.Config
  ( mkConfigParser,
    getConfig,
  )
where

import qualified Barbies as B
import Data.Functor.Compose (Compose (..))
import Data.Kind (Type)
import qualified Options.Applicative as Optparse
import Options.Harg.Cmdline (mkOptparseParser)
import Options.Harg.Sources (accumSourceResults)
import Options.Harg.Sources.Env (EnvSourceVal (..))
import Options.Harg.Sources.Types
import Options.Harg.Types

-- | Create a 'Optparse.Parser' for the configuration option parser, using
-- 'EnvSource' as the only source.
mkConfigParser ::
  forall f c.
  ( Applicative f,
    B.TraversableB c,
    B.ApplicativeB c
  ) =>
  HargCtx ->
  c (Compose Opt f) ->
  Optparse.Parser (c f)
mkConfigParser :: HargCtx -> c (Compose Opt f) -> Parser (c f)
mkConfigParser HargCtx {..} conf :: c (Compose Opt f)
conf =
  [c (Compose Maybe f)] -> c (Compose Opt f) -> Parser (c f)
forall (f :: * -> *) (a :: (* -> *) -> *).
(Applicative f, TraversableB a, ApplicativeB a) =>
[a (Compose Maybe f)] -> a (Compose Opt f) -> Parser (a f)
mkOptparseParser [c (Compose Maybe f)]
envC c (Compose Opt f)
conf
  where
    (_, envC :: [c (Compose Maybe f)]
envC) =
      [Either SourceRunError (c (Compose SourceRunResult f))]
-> ([SourceRunError], [c (Compose Maybe f)])
forall (a :: (* -> *) -> *) (f :: * -> *).
TraversableB a =>
[Either SourceRunError (a (Compose SourceRunResult f))]
-> ([SourceRunError], [a (Compose Maybe f)])
accumSourceResults ([Either SourceRunError (c (Compose SourceRunResult f))]
 -> ([SourceRunError], [c (Compose Maybe f)]))
-> [Either SourceRunError (c (Compose SourceRunResult f))]
-> ([SourceRunError], [c (Compose Maybe f)])
forall a b. (a -> b) -> a -> b
$
        EnvSourceVal
-> c (Compose Opt f)
-> [Either SourceRunError (c (Compose SourceRunResult f))]
forall s (a :: (* -> *) -> *) (f :: * -> *).
(RunSource s a, Applicative f) =>
s
-> a (Compose Opt f)
-> [Either SourceRunError (a (Compose SourceRunResult f))]
runSource (Environment -> EnvSourceVal
EnvSourceVal Environment
_hcEnv) c (Compose Opt f)
conf

-- | Run two option parsers in parallel and return the result of the
-- first one. This is used with the configuration parser being the first
-- argument, and the target option parser that has been converted to
-- the dummy parser using 'Options.Harg.Util.toDummyOpts' as the second
-- one.
getConfig ::
  HargCtx ->
  Optparse.Parser (c (f :: Type -> Type)) ->
  Optparse.Parser (a (g :: Type -> Type)) ->
  IO (c f)
getConfig :: HargCtx -> Parser (c f) -> Parser (a g) -> IO (c f)
getConfig HargCtx {..} confParser :: Parser (c f)
confParser optParser :: Parser (a g)
optParser = do
  let parser :: Parser (c f, a g)
parser =
        (,) (c f -> a g -> (c f, a g))
-> Parser (c f) -> Parser (a g -> (c f, a g))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser (c f)
confParser Parser (a g -> (c f, a g)) -> Parser (a g) -> Parser (c f, a g)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser (a g)
optParser
      parserInfo :: ParserInfo (c f, a g)
parserInfo =
        Parser (c f, a g) -> InfoMod (c f, a g) -> ParserInfo (c f, a g)
forall a. Parser a -> InfoMod a -> ParserInfo a
Optparse.info (Parser ((c f, a g) -> (c f, a g))
forall a. Parser (a -> a)
Optparse.helper Parser ((c f, a g) -> (c f, a g))
-> Parser (c f, a g) -> Parser (c f, a g)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser (c f, a g)
parser) InfoMod (c f, a g)
forall a. Monoid a => a
mempty
      res :: ParserResult (c f, a g)
res =
        ParserPrefs
-> ParserInfo (c f, a g) -> Args -> ParserResult (c f, a g)
forall a. ParserPrefs -> ParserInfo a -> Args -> ParserResult a
Optparse.execParserPure ParserPrefs
Optparse.defaultPrefs ParserInfo (c f, a g)
parserInfo Args
_hcArgs
  (c f, a g) -> c f
forall a b. (a, b) -> a
fst ((c f, a g) -> c f) -> IO (c f, a g) -> IO (c f)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParserResult (c f, a g) -> IO (c f, a g)
forall a. ParserResult a -> IO a
Optparse.handleParseResult ParserResult (c f, a g)
res