{-# LANGUAGE NoImplicitPrelude #-}

{-|
Module      : Stack.Options.ExecParser
License     : BSD-3-Clause

Functions to parse command line arguments for Stack's @exec@, @ghc@, @run@,
@runghc@ and @runhaskell@ commands.
-}

module Stack.Options.ExecParser
  ( execOptsParser
  , execOptsExtraParser
  ) where

import           Options.Applicative
                   ( Parser, completer, help, idm, long, metavar, strArgument
                   , strOption
                   )
import           Options.Applicative.Builder.Extra ( boolFlags, dirCompleter )
import           Options.Applicative.Args ( argsOption )
import           Stack.Exec
                   ( ExecOpts (..), ExecOptsExtra (..), SpecialExecCmd (..) )
import           Stack.Options.Completion ( projectExeCompleter )
import           Stack.Prelude
import           Stack.Types.EnvSettings ( EnvSettings (..) )

-- | Parse command line arguments for Stack's @exec@, @ghc@, @run@,
-- @runghc@ and @runhaskell@ commands.
execOptsParser :: Maybe SpecialExecCmd -> Parser ExecOpts
execOptsParser mcmd = ExecOpts
  <$> maybe eoCmdParser pure mcmd
  <*> eoArgsParser
  <*> execOptsExtraParser
 where
  eoCmdParser = ExecCmd
    <$> strArgument
          (  metavar "COMMAND"
          <> completer projectExeCompleter
          )
  eoArgsParser = many (strArgument (metavar txt))
   where
    txt = case mcmd of
      Nothing -> normalTxt
      Just ExecCmd{} -> normalTxt
      Just ExecRun -> "-- ARGUMENT(S) (e.g. stack run -- file.txt)"
      Just ExecGhc -> "-- ARGUMENT(S) (e.g. stack ghc -- X.hs -o x)"
      Just ExecRunGhc -> "-- ARGUMENT(S) (e.g. stack runghc -- X.hs)"
    normalTxt = "-- ARGUMENT(S) (e.g. stack exec ghc-pkg -- describe base)"

-- | Parser for extra options to exec command
execOptsExtraParser :: Parser ExecOptsExtra
execOptsExtraParser = ExecOptsExtra
  <$> eoEnvSettingsParser
  <*> eoPackagesParser
  <*> eoRtsOptionsParser
  <*> eoCwdParser
 where
  eoEnvSettingsParser :: Parser EnvSettings
  eoEnvSettingsParser = EnvSettings True
    <$> boolFlags True
          "ghc-package-path"
          "setting the GHC_PACKAGE_PATH variable for the subprocess."
          idm
    <*> boolFlags True
          "stack-exe"
          "setting the STACK_EXE environment variable to the path for the \
          \stack executable."
          idm
    <*> pure False
    <*> pure True

  eoPackagesParser :: Parser [String]
  eoPackagesParser = many (strOption
    (  long "package"
    <> metavar "PACKAGE(S)"
    <> help "Add package(s) as a list of names or identifiers separated by \
            \spaces (can be specified multiple times)."
    ))

  eoRtsOptionsParser :: Parser [String]
  eoRtsOptionsParser = concat <$> many (argsOption
    ( long "rts-options"
    <> help "Explicit RTS options to pass to application (can be specified \
            \multiple times)."
    <> metavar "RTSFLAG"
    ))

  eoCwdParser :: Parser (Maybe FilePath)
  eoCwdParser = optional (strOption
    (  long "cwd"
    <> help "Sets the working directory before executing."
    <> metavar "DIR"
    <> completer dirCompleter
    ))
