{-# LANGUAGE MultilineStrings #-} -- | Options parser using optparse-applicative for the debugger options in -- 'Development.Debug.Options' module Development.Debug.Options.Parser ( -- * Command line options parsing parseHdbOptions ) where import Options.Applicative hiding (command) import Data.Version import qualified Options.Applicative import qualified Paths_haskell_debugger as P import Colog.Core import Development.Debug.Options -------------------------------------------------------------------------------- -- Options parser -------------------------------------------------------------------------------- -- | Parser for 'HdbDAPServer' options serverParser :: Parser HdbOptions serverParser = HdbDAPServer <$> option auto ( long "port" <> short 'p' <> metavar "PORT" <> help "DAP server port" ) <*> verbosityParser Debug <*> internalInterpreterParser <*> disableIpeBacktracesParser -- | Parser for 'HdbCLI' options cliParser :: Parser HdbOptions cliParser = HdbCLI <$> strOption ( long "entry-point" <> short 'e' <> metavar "ENTRY_POINT" <> value "main" <> help "The name of the function that is called to start execution (default: main)" ) <*> argument str ( metavar "ENTRY_FILE" <> help "The relative path from the project root to the file with the entry point for execution" ) <*> many ( argument str ( metavar "ENTRY_ARGS..." <> help "The arguments passed to the entryPoint. If the entryPoint is main, these arguments are passed as environment arguments (as in getArgs) rather than direct function arguments." ) ) <*> option (words <$> str) ( long "extra-ghc-args" <> metavar "GHC_ARGS" <> value [] <> help "Additional flags to pass to the ghc invocation that loads the program for debugging" ) <*> option (Just <$> str) (long "cradle-file" <> metavar "HIE_PATH" <> value Nothing <> help "Path to .yaml file to use as cradle configuration. Location inferred from ENTRY_POINT otherwise." ) <*> verbosityParser Warning <*> internalInterpreterParser <*> disableIpeBacktracesParser <*> (optional $ strOption ( long "debuggee-stdin" <> metavar "FILE" <> help """ Provide a file to be used as stdin for the debuggee. If `hdb` is connected to a terminal, the debuggee input can be given interactively, interleaved with the debugger input. However, if the debuggee reads from stdin and `hdb` is invoked reading from a file or pipe (e.g. `hdb Main.hs < instructions`), then the debuggee output must be given separately using this flag (and `instructions` should only contain debugger commands). Otherwise, the debuggee and debugger will race to read from the file (regardless of buffering), which typically results in an error like `: hGetLine: end of file` This flag does not do anything when using --internal-interpreter """ )) -- | Parser for 'HdbProxy' options proxyParser :: Parser HdbOptions proxyParser = HdbProxy <$> option auto ( long "port" <> short 'p' <> metavar "PORT" <> help "proxy port to which the debugger connects" ) <*> verbosityParser Warning -- | Parser for @hdb external-interpreter @ or -- @hdb external-interpreter --port @ -- See Note [Custom external interpreter] extInterpParser :: Parser HdbOptions extInterpParser = HdbExternalInterpreterPort <$> option auto ( long "port" <> short 'p' <> metavar "PORT" <> help "port on which the external interpreter should connect to the debugger" ) <*> verbosityParser Error <|> HdbExternalInterpreter <$> argument auto ( metavar "WRITE_FD" <> help "external interpreter write file descriptor" ) <*> argument auto ( metavar "READ_FD" <> help "external interpreter read file descriptor" ) <*> verbosityParser Error -- | Combined parser for HdbOptions hdbOptionsParser :: Parser HdbOptions hdbOptionsParser = hsubparser ( Options.Applicative.command "server" ( info serverParser ( progDesc "Start the Haskell debugger in DAP server mode" ) ) <> Options.Applicative.command "cli" ( info cliParser ( progDesc "Debug a Haskell program in CLI mode" ) ) <> Options.Applicative.command "proxy" ( info proxyParser ( progDesc "Internal mode used by the DAP server to proxy stdin/stdout to the DAP client's terminal when using the internal interpreter" ) ) <> Options.Applicative.command "external-interpreter" ( info extInterpParser ( progDesc "Start the custom-for-debugger external interpreter" ) ) ) <|> cliParser -- Default to CLI mode if no subcommand -- | Parser for --version flag versioner :: Parser (a -> a) versioner = simpleVersioner $ "Haskell Debugger, version " ++ showVersion P.version -- | Parser for --verbosity 0 -- -- The default verbosity differs by mode (#86): -- - DAP server mode: DEBUG -- - CLI mode: WARNING verbosityParser :: Severity -> Parser Severity verbosityParser vdef = option verb ( long "verbosity" <> short 'v' <> metavar "VERBOSITY" <> value vdef <> help "Logger verbosity in [0..3] interval, where 0 is silent and 3 is debug" ) where verb = verbNum =<< auto verbNum n = case n :: Int of 0 -> pure Error 1 -> pure Warning 2 -> pure Info 3 -> pure Debug _ -> readerAbort (ErrorMsg "Verbosity must be a value in [0..3]") -- | Parser for --internal-interpreter -- -- Prefer running the debuggee on the debugger's internal interpreter rather -- than using an external interpreter by default. internalInterpreterParser :: Parser Bool internalInterpreterParser = switch ( long "internal-interpreter" <> help "Prefer running the debuggee on the debugger's internal interpreter rather than on a separate (external-interpreter) process" ) -- | Parser for --disable-ipe-backtraces -- -- Disable IPE backtrace information in the debugger. By default, IPE backtraces -- are enabled to provide better crash diagnostics when debugging Haskell programs. -- However, when using the internal interpreter, IPE backtraces appear in the -- debugger output but not with the external interpreter (since they run as -- separate processes). Use this flag only if you need consistent test output -- between internal and external interpreter modes, or when testing behavior that -- should not include IPE backtrace information. disableIpeBacktracesParser :: Parser Bool disableIpeBacktracesParser = switch ( long "disable-ipe-backtraces" <> help "Disable IPE backtrace info for consistent output between internal/external interpreter modes" ) -- | Main parser info hdbParserInfo :: ParserInfo HdbOptions hdbParserInfo = info (hdbOptionsParser <**> versioner <**> helper) ( fullDesc <> header "Haskell debugger supporting both CLI and DAP modes" ) -- | Parse command line arguments parseHdbOptions :: IO HdbOptions parseHdbOptions = customExecParser defaultPrefs{prefShowHelpOnError = True, prefShowHelpOnEmpty = True} hdbParserInfo