<commit_before>{-# LANGUAGE FlexibleInstances
           , OverlappingInstances
           , RankNTypes
           , ScopedTypeVariables
           , TemplateHaskell
           , TypeSynonymInstances
 #-}
{-# OPTIONS_HADDOCK show-extensions #-}


{- |

Description : command-line option handling
Copyright   : (c) <NAME> 2014, 2015
License     : BSD
Maintainer  : <EMAIL>

A library for handling cmdline options & arguments, including checking for
argument count, parsing arguments & options, pre-evaluated IO on both (to
trap errors early), handling collections of options, and automatically
generating help texts.

 -}

module Console.Getopt
  ( -- I tried to use the '-- $name' syntax here, but got a 'parse error' on the
    -- next line of non-doc haskell (even using the example c'n'p from the
    -- manual); so I gave up

    -- * Synopsis

    {- | To use this module:

             (0) create a (lensed) record that will store the result
                 of parsing the options (and give it a default value, if you're
                 going to use getopts*)
             (0) create an options-parsing configuration (which is just a
                 list of individual parsers), and
             (0) call one of the getopts* family (or getOptions).

         Here is a simple example.

         Please note the distinction between /arguments/, which are the standard
         textual values given after the program name; and the /options/, which
         are optional tweaks given using '--foo' or '-F'; thus in @grep
         -r --include \\*.hs hlib GetOptions@, the @hlib@ and @GetOptions@ are
         considered arguments, while the @-r@ and the @--include \\*.hs@ are
         considered options.

         @
         {-# LANGUAGE ScopedTypeVariables, TemplateHaskell #-}
         import Control.Lens  ( (^.), makeLenses )
         import Data.Default  ( Default( def ) )
         import Data.List     ( intercalate )

         import Fluffy.Console.Getopt  ( ArgArity( ArgSome ), Option
                                       , getopts, mkOpt, setval )

         -- opts & options ----------------------

         data Opts = Opts { _str :: Maybe String }
         $( makeLenses ''Opts )

         instance Default Opts where def = Opts Nothing

         optCfg :: [Option Opts]
         optCfg = [ mkOpt "s"  [ "str"  ] (setval return str)
                          "summary" "option description" "String" ""
                  ]

         -- main --------------------------------

         main :: IO ()
         main = do
           (args :: [Int], opts) <- getopts optCfg (ArgSome 1 3) "integer"
                                            (return . read)
           let s = maybe "" (++ " ") (opts ^. str)
           putStrLn $ s ++ unwords (map show args)
         @

         Line by line; we start with:

         >    data Opts = Opts { _str :: Maybe String }

         this defines a record in which to store the results of parsing.  In
         this case, the single available option is stored as a string value; the
         @Maybe@ allows for the situation that the option wasn't invoked.

         >    $(makeLenses ''Opts )

         Each setval* function expects a Lens' argument to work with.  You can
         use this library without lenses - @Lens' s a@ is just a function - but
         the lens package makes it all much simpler.

         @
         type Lens' s a = 
           &#8704; (f :: * -> *) . Functor f => (a -> f a) -> s -> f s
         @

         A default instance of your Opts class is required so that
         getopts/getopts' has some values to start with.  Calls to
         getOptions/getopts_ don't need this.

         >    instance Default Opts where def = Opts Nothing

         Now configure your options parsing.  A configuration is just a list of
         individual options, each being built with mkOpt.  Note that the final
         four string arguments are only used by options constructed with helpme*;
         if you don't use that (as in this example), you don't need them.

         >    optCfg :: [Option Opts]
         >    optCfg = [ mkOpt "s"  [ "str"  ] (setval return str)
         >                     "summary" "option description" "String" ""
         >             ]

         Call getopts, parsing the configuration, a definition (@ArgArity@) of
         how many arguments you need, a text description of those arguments
         (again, for use with a helpme* option, but also when generating error
         messages), and a rule for parsing those arguments.  The type
         specification on @args@ is required because of the polymorphism of
         @read@.

         >    main :: IO ()
         >    main = do
         >      (args :: [Int], opts) <- getopts optCfg (ArgSome 1 3) "integer"
         >                                       (return . read)
         >      let s = maybe "" (++ " ") (opts ^. str)
         >      putStrLn $ s ++ unwords (map show args)

     -}

    -- * Notes

    {- | All option names are treated case-insensitively -}

    {- | This library eagerly evaluates argument an option parses when an entry
         point is called.  That is a deliberate strategy to ensure that once
         the program proper begins, all the options/arguments have been passed
         and are valid.  The rationale is that it is not good form to spend 30
         minutes crunching data only to then declare that "seven" is not a valid
         integer, or whatever.
     -}

    -- * Primary Entry Points
    getopts, getopts', getopts_, getOptions

    -- * Types
    -- OptParse isn't really needed to be exported, but exporting it means it
    -- gets documented
  , ArgArity(..), HelpOpts(..), Option, OptParse, ParseState, ParseState_

  -- * Option Constructors
  , helpme, helpme', mkOpt, mkOptsB

  -- * setval* Variants
  , setvalOW, setval, setvalc, setvalc', setvalm, setvalm_, setvals
  , setvals', setvalt, setvalf, setval', setvalAList, setvalAList'

  -- * useful extras
  , NFHandle( NFHandle ), progName, unhandle
  )
where

-- provide type sigs for generated functions in GetoptTH
-- test & document what happens when a ?Thing value is used with a default.
-- clean build from scratch
-- remove use of arity, argtype name, from getopts call generated by mkopts
--   since they're passed to mkopts itself
-- option invocation names should accept '-' not '_'.  Lensname should tr/-/_/.
--   starting with '-' or numbers should be illegal (numbers because you can't
--   have functions starting with numbers)
-- add tests for
--   * lensname beginning with _
--   * lensname defaulted from optname, with - replaced by _
--   * lensname defaulted from optname, with leading digit preceded by '_'
-- add tests to T/Getopt.hs / getopt-ex for setvalm{,'}; improve doc for
--   setvalm{,'}
-- add tests that check that an option with no default causes a throw at option-
--   parsing time if the user doesn't supply an option; test this for filero
--   when used without a default value
-- mandatory option; leading '!'; causes error if this option isn't invoked.
--   particularly required for, e.g., String, which has a natural default and so
--   wouldn't get the benefit of default-less checking.  Or should we use
--   encourage the use of a newtype for these?  One consideration is if one uses
--   say Float, which later gets given a natural default - action-at-a-distance.<commit_msg>provided type sigs for generated fns from mkopts<commit_after>{-# LANGUAGE FlexibleInstances
           , OverlappingInstances
           , RankNTypes
           , ScopedTypeVariables
           , TemplateHaskell
           , TypeSynonymInstances
 #-}
{-# OPTIONS_HADDOCK show-extensions #-}


{- |

Description : command-line option handling
Copyright   : (c) <NAME> 2014, 2015
License     : BSD
Maintainer  : <EMAIL>

A library for handling cmdline options & arguments, including checking for
argument count, parsing arguments & options, pre-evaluated IO on both (to
trap errors early), handling collections of options, and automatically
generating help texts.

 -}

module Console.Getopt
  ( -- I tried to use the '-- $name' syntax here, but got a 'parse error' on the
    -- next line of non-doc haskell (even using the example c'n'p from the
    -- manual); so I gave up

    -- * Synopsis

    {- | To use this module:

             (0) create a (lensed) record that will store the result
                 of parsing the options (and give it a default value, if you're
                 going to use getopts*)
             (0) create an options-parsing configuration (which is just a
                 list of individual parsers), and
             (0) call one of the getopts* family (or getOptions).

         Here is a simple example.

         Please note the distinction between /arguments/, which are the standard
         textual values given after the program name; and the /options/, which
         are optional tweaks given using '--foo' or '-F'; thus in @grep
         -r --include \\*.hs hlib GetOptions@, the @hlib@ and @GetOptions@ are
         considered arguments, while the @-r@ and the @--include \\*.hs@ are
         considered options.

         @
         {-# LANGUAGE ScopedTypeVariables, TemplateHaskell #-}
         import Control.Lens  ( (^.), makeLenses )
         import Data.Default  ( Default( def ) )
         import Data.List     ( intercalate )

         import Fluffy.Console.Getopt  ( ArgArity( ArgSome ), Option
                                       , getopts, mkOpt, setval )

         -- opts & options ----------------------

         data Opts = Opts { _str :: Maybe String }
         $( makeLenses ''Opts )

         instance Default Opts where def = Opts Nothing

         optCfg :: [Option Opts]
         optCfg = [ mkOpt "s"  [ "str"  ] (setval return str)
                          "summary" "option description" "String" ""
                  ]

         -- main --------------------------------

         main :: IO ()
         main = do
           (args :: [Int], opts) <- getopts optCfg (ArgSome 1 3) "integer"
                                            (return . read)
           let s = maybe "" (++ " ") (opts ^. str)
           putStrLn $ s ++ unwords (map show args)
         @

         Line by line; we start with:

         >    data Opts = Opts { _str :: Maybe String }

         this defines a record in which to store the results of parsing.  In
         this case, the single available option is stored as a string value; the
         @Maybe@ allows for the situation that the option wasn't invoked.

         >    $(makeLenses ''Opts )

         Each setval* function expects a Lens' argument to work with.  You can
         use this library without lenses - @Lens' s a@ is just a function - but
         the lens package makes it all much simpler.

         @
         type Lens' s a = 
           &#8704; (f :: * -> *) . Functor f => (a -> f a) -> s -> f s
         @

         A default instance of your Opts class is required so that
         getopts/getopts' has some values to start with.  Calls to
         getOptions/getopts_ don't need this.

         >    instance Default Opts where def = Opts Nothing

         Now configure your options parsing.  A configuration is just a list of
         individual options, each being built with mkOpt.  Note that the final
         four string arguments are only used by options constructed with helpme*;
         if you don't use that (as in this example), you don't need them.

         >    optCfg :: [Option Opts]
         >    optCfg = [ mkOpt "s"  [ "str"  ] (setval return str)
         >                     "summary" "option description" "String" ""
         >             ]

         Call getopts, parsing the configuration, a definition (@ArgArity@) of
         how many arguments you need, a text description of those arguments
         (again, for use with a helpme* option, but also when generating error
         messages), and a rule for parsing those arguments.  The type
         specification on @args@ is required because of the polymorphism of
         @read@.

         >    main :: IO ()
         >    main = do
         >      (args :: [Int], opts) <- getopts optCfg (ArgSome 1 3) "integer"
         >                                       (return . read)
         >      let s = maybe "" (++ " ") (opts ^. str)
         >      putStrLn $ s ++ unwords (map show args)

     -}

    -- * Notes

    {- | All option names are treated case-insensitively -}

    {- | This library eagerly evaluates argument an option parses when an entry
         point is called.  That is a deliberate strategy to ensure that once
         the program proper begins, all the options/arguments have been passed
         and are valid.  The rationale is that it is not good form to spend 30
         minutes crunching data only to then declare that "seven" is not a valid
         integer, or whatever.
     -}

    -- * Primary Entry Points
    getopts, getopts', getopts_, getOptions

    -- * Types
    -- OptParse isn't really needed to be exported, but exporting it means it
    -- gets documented
  , ArgArity(..), HelpOpts(..), Option, OptParse, ParseState, ParseState_

  -- * Option Constructors
  , helpme, helpme', mkOpt, mkOptsB

  -- * setval* Variants
  , setvalOW, setval, setvalc, setvalc', setvalm, setvalm_, setvals
  , setvals', setvalt, setvalf, setval', setvalAList, setvalAList'

  -- * useful extras
  , NFHandle( NFHandle ), progName, unhandle
  )
where

-- test & document what happens when a ?Thing value is used with a default.
-- clean build from scratch
-- remove use of arity, argtype name, from getopts call generated by mkopts
--   since they're passed to mkopts itself
-- option invocation names should accept '-' not '_'.  Lensname should tr/-/_/.
--   starting with '-' or numbers should be illegal (numbers because you can't
--   have functions starting with numbers)
-- add tests for
--   * lensname beginning with _
--   * lensname defaulted from optname, with - replaced by _
--   * lensname defaulted from optname, with leading digit preceded by '_'
-- add tests to T/Getopt.hs / getopt-ex for setvalm{,'}; improve doc for
--   setvalm{,'}
-- add tests that check that an option with no default causes a throw at option-
--   parsing time if the user doesn't supply an option; test this for filero
--   when used without a default value
-- mandatory option; leading '!'; causes error if this option isn't invoked.
--   particularly required for, e.g., String, which has a natural default and so
--   wouldn't get the benefit of default-less checking.  Or should we use
--   encourage the use of a newtype for these?  One consideration is if one uses
--   say Float, which later gets given a natural default - action-at-a-distance.
{'fraction_non_alphanumeric': 0.09176915799432356, 'fraction_numerical': 0.002838221381267739, 'mean_word_length': 1.9951426836672739, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1033154', 'n_tokens_mistral': 4048, 'n_tokens_neox': 3846, 'n_words': 1734}