packages feed

optparse-applicative 0.16.1.0 → 0.17.0.0

raw patch · 17 files changed

+222/−65 lines, 17 files

Files

CHANGELOG.md view
@@ -1,3 +1,16 @@+## Version 0.17.0.0 (1 Feb 2022)++- Make tabulation width configurable in usage texts.++- Separate program name and description in ParserHelp type.++- Add `helperWith` function, which can be easily used to+  localize the help flag.++- Improve usage texts when command names are long.++- Improve Documentation.+ ## Version 0.16.1.0 (21 Nov 2020)  - Guard `process` dependency behind an on by default flag.
README.md view
@@ -527,22 +527,6 @@ global options that apply to all of them. Typical examples are version control systems like `git`, or build tools like `cabal`. -A command can be created using the `subparser` builder (or `hsubparser`,-which is identical but for an additional `--help` option on each-command), and commands can be added with the `command` modifier.-For example--```haskell-subparser-  ( command "add" (info addOptions ( progDesc "Add a file to the repository" ))- <> command "commit" (info commitOptions ( progDesc "Record changes to the repository" ))-  )-```--Each command takes a full `ParserInfo` structure, which will be-used to extract a description for this command when generating a-help text.- Note that all the parsers appearing in a command need to have the same type.  For this reason, it is often best to use a sum type which has the same structure as the command itself. For example,@@ -559,6 +543,22 @@   ... ``` +A command can then be created using the `subparser` builder (or+`hsubparser`, which is identical but for an additional `--help` option+on each command), and commands can be added with the `command`+modifier. For example,++```haskell+subparser+  ( command "add" (info addCommand ( progDesc "Add a file to the repository" ))+ <> command "commit" (info commitCommand ( progDesc "Record changes to the repository" ))+  )+```++Each command takes a full `ParserInfo` structure, which will be+used to extract a description for this command when generating a+help text.+ Alternatively, you can directly return an `IO` action from a parser, and execute it using `join` from `Control.Monad`. @@ -702,6 +702,11 @@  ``` +**Note**. If an option name is a prefix of another option, then it+will never be matched when disambiguation is on. See+[#419](https://github.com/pcapriotti/optparse-applicative/issues/419)+for more details.+ ### Customising the help screen  optparse-applicative has a number of combinators to help customise@@ -1020,6 +1025,6 @@  [monoid]: http://hackage.haskell.org/package/base/docs/Data-Monoid.html  [semigroup]: http://hackage.haskell.org/package/base/docs/Data-Semigroup.html  [parsec]: http://hackage.haskell.org/package/parsec- [status]: http://travis-ci.org/pcapriotti/optparse-applicative?branch=master- [status-png]: https://api.travis-ci.org/pcapriotti/optparse-applicative.svg?branch=master+ [status]: https://github.com/pcapriotti/optparse-applicative/actions/workflows/haskell-ci.yml+ [status-png]: https://github.com/pcapriotti/optparse-applicative/workflows/Haskell-CI/badge.svg  [ansi-wl-pprint]: http://hackage.haskell.org/package/ansi-wl-pprint
optparse-applicative.cabal view
@@ -1,5 +1,5 @@ name:                optparse-applicative-version:             0.16.1.0+version:             0.17.0.0 synopsis:            Utilities and combinators for parsing command line options description:     optparse-applicative is a haskell library for parsing options@@ -36,6 +36,7 @@                      tests/helponemptysub.err.txt                      tests/long_equals.err.txt                      tests/formatting.err.txt+                     tests/formatting-long-subcommand.err.txt                      tests/nested.err.txt                      tests/optional.err.txt                      tests/nested_optional.err.txt@@ -54,7 +55,9 @@   GHC==8.2.2,   GHC==8.4.4,   GHC==8.6.5,-  GHC==8.8.1+  GHC==8.8.4,+  GHC==8.10.4,+  GHC==9.0.1  source-repository head   type:     git@@ -95,15 +98,15 @@                      , Options.Applicative.Internal    build-depends:       base                            == 4.*-                     , transformers                    >= 0.2 && < 0.6-                     , transformers-compat             >= 0.3 && < 0.7+                     , transformers                    >= 0.2 && < 0.7+                     , transformers-compat             >= 0.3 && < 0.8                      , ansi-wl-pprint                  >= 0.6.8 && < 0.7    if flag(process)     build-depends:     process                         >= 1.0 && < 1.7    if !impl(ghc >= 8)-    build-depends:     semigroups                      >= 0.10 && < 0.20+    build-depends:     semigroups                      >= 0.10 && < 0.21                      , fail                            == 4.9.*  test-suite tests@@ -122,6 +125,7 @@                      , Examples.Commands                      , Examples.Formatting                      , Examples.Hello+                     , Examples.LongSub    build-depends:       base                      , optparse-applicative
src/Options/Applicative/Builder.hs view
@@ -1,5 +1,4 @@ {-# LANGUAGE CPP #-}- module Options.Applicative.Builder (   -- * Parser builders   --@@ -89,6 +88,7 @@   columns,   helpLongEquals,   helpShowGlobals,+  helpIndent,   prefs,   defaultPrefs, @@ -219,7 +219,7 @@ -- -- /NOTE/: This builder is more flexible than its name and example -- allude. One of the motivating examples for its addition was to--- used `const` to completely replace the usage text of an option.+-- use `const` to completely replace the usage text of an option. style :: ( Doc -> Doc ) -> Mod f a style x = optionMod $ \p ->   p { propDescMod = Just x }@@ -273,6 +273,11 @@  -- | Builder for a command parser. The 'command' modifier can be used to -- specify individual commands.+--+-- By default, sub-parsers allow backtracking to their parent's options when+-- they are completed. To allow full mixing of parent and sub-parser options,+-- turn on 'subparserInline'; otherwise, to disable backtracking completely,+-- use 'noBacktrack'. subparser :: Mod CommandFields a -> Parser a subparser m = mkParser d g rdr   where@@ -385,7 +390,7 @@ instance Semigroup (InfoMod a) where   m1 <> m2 = InfoMod $ applyInfoMod m2 . applyInfoMod m1 --- | Show a full description in the help text of this parser.+-- | Show a full description in the help text of this parser (default). fullDesc :: InfoMod a fullDesc = InfoMod $ \i -> i { infoFullDesc = True } @@ -517,11 +522,16 @@ helpLongEquals :: PrefsMod helpLongEquals = PrefsMod $ \p -> p { prefHelpLongEquals = True } --- | Show global help information in subparser usage+-- | Show global help information in subparser usage. helpShowGlobals :: PrefsMod-helpShowGlobals = PrefsMod $ \p -> p { prefHelpShowGlobal = True}+helpShowGlobals = PrefsMod $ \p -> p { prefHelpShowGlobal = True } +-- | Set fill width in help text presentation.+helpIndent :: Int -> PrefsMod+helpIndent w = PrefsMod $ \p -> p { prefTabulateFill = w } ++ -- | Create a `ParserPrefs` given a modifier prefs :: PrefsMod -> ParserPrefs prefs m = applyPrefsMod m base@@ -534,7 +544,8 @@       , prefBacktrack = Backtrack       , prefColumns = 80       , prefHelpLongEquals = False-      , prefHelpShowGlobal = False }+      , prefHelpShowGlobal = False+      , prefTabulateFill = 24 }  -- Convenience shortcuts 
src/Options/Applicative/Extra.hs view
@@ -4,6 +4,7 @@   --   -- | This module contains high-level functions to run parsers.   helper,+  helperWith,   hsubparser,   execParser,   customExecParser,@@ -47,16 +48,32 @@  helper :: Parser (a -> a) helper =+  helperWith (mconcat [+    long "help",+    short 'h',+    help "Show this help text"+  ])++-- | Like helper, but with a minimal set of modifiers that can be extended+-- as desired.+--+-- > opts :: ParserInfo Sample+-- > opts = info (sample <**> helperWith (mconcat [+-- >          long "help",+-- >          short 'h',+-- >          help "Show this help text",+-- >          hidden+-- >        ])) mempty+helperWith :: Mod OptionFields (a -> a) -> Parser (a -> a)+helperWith modifiers =   option helpReader $     mconcat-      [ long "help",-        short 'h',-        help "Show this help text",-        value id,+      [ value id,         metavar "",         noGlobal,         noArgError (ShowHelpText Nothing),-        hidden+        hidden,+        modifiers       ]   where     helpReader = do@@ -197,9 +214,10 @@       InfoMsg _         -> mempty       _-        -> usageHelp $ vcatChunks-          [ pure . parserUsage pprefs (infoParser i) . unwords $ progn : names-          , fmap (indent 2) . infoProgDesc $ i ]+        -> mconcat [+            usageHelp (pure . parserUsage pprefs (infoParser i) . unwords $ progn : names)+          , descriptionHelp (infoProgDesc i)+          ]      error_help = errorHelp $ case msg of       ShowHelpText {}
src/Options/Applicative/Help/Chunk.hs view
@@ -128,12 +128,9 @@ paragraph = foldr (chunked (</>) . stringChunk) mempty           . words -tabulate' :: Int -> [(Doc, Doc)] -> Chunk Doc-tabulate' _ [] = mempty-tabulate' size table = pure $ vcat+-- | Display pairs of strings in a table.+tabulate :: Int -> [(Doc, Doc)] -> Chunk Doc+tabulate _ [] = mempty+tabulate size table = pure $ vcat   [ indent 2 (fillBreak size key <+> value)   | (key, value) <- table ]---- | Display pairs of strings in a table.-tabulate :: [(Doc, Doc)] -> Chunk Doc-tabulate = tabulate' 24
src/Options/Applicative/Help/Core.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} module Options.Applicative.Help.Core (   cmdDesc,   briefDesc,@@ -9,6 +10,7 @@   headerHelp,   suggestionsHelp,   usageHelp,+  descriptionHelp,   bodyHelp,   footerHelp,   globalsHelp,@@ -23,8 +25,12 @@ import Data.List (sort, intersperse, groupBy) import Data.Foldable (any, foldl') import Data.Maybe (maybeToList, catMaybes, fromMaybe)+#if !MIN_VERSION_base(4,8,0) import Data.Monoid (mempty)+#endif+#if !MIN_VERSION_base(4,11,0) import Data.Semigroup (Semigroup (..))+#endif import Prelude hiding (any)  import Options.Applicative.Common@@ -83,14 +89,14 @@    in (modified, wrapping)  -- | Generate descriptions for commands.-cmdDesc :: Parser a -> [(Maybe String, Chunk Doc)]-cmdDesc = mapParser desc+cmdDesc :: ParserPrefs -> Parser a -> [(Maybe String, Chunk Doc)]+cmdDesc pprefs = mapParser desc   where     desc _ opt =       case optMain opt of         CmdReader gn cmds p ->           (,) gn $-            tabulate+            tabulate (prefTabulateFill pprefs)               [ (string cmd, align (extractChunk d))                 | cmd <- reverse cmds,                   d <- maybeToList . fmap infoProgDesc $ p cmd@@ -188,7 +194,7 @@  -- | Common generator for full descriptions and globals optionsDesc :: Bool -> ParserPrefs -> Parser a -> Chunk Doc-optionsDesc global pprefs = tabulate . catMaybes . mapParser doc+optionsDesc global pprefs = tabulate (prefTabulateFill pprefs) . catMaybes . mapParser doc   where     doc info opt = do       guard . not . isEmpty $ n@@ -220,6 +226,9 @@ usageHelp :: Chunk Doc -> ParserHelp usageHelp chunk = mempty { helpUsage = chunk } +descriptionHelp :: Chunk Doc -> ParserHelp+descriptionHelp chunk = mempty { helpDescription = chunk }+ bodyHelp :: Chunk Doc -> ParserHelp bodyHelp chunk = mempty { helpBody = chunk } @@ -234,7 +243,7 @@       : (group_title <$> cs)   where     def = "Available commands:"-    cs = groupBy ((==) `on` fst) $ cmdDesc p+    cs = groupBy ((==) `on` fst) $ cmdDesc pprefs p      group_title a@((n, _) : _) =       with_title (fromMaybe def n) $@@ -256,11 +265,12 @@ -- | Generate option summary. parserUsage :: ParserPrefs -> Parser a -> String -> Doc parserUsage pprefs p progn =-  hsep-    [ string "Usage:",-      string progn,-      align (extractChunk (briefDesc pprefs p))-    ]+  group $+    hsep+      [ string "Usage:",+        string progn,+        hangAtIfOver 9 35 (extractChunk (briefDesc pprefs p))+      ]  -- | Peek at the structure of the rendered tree within. --
src/Options/Applicative/Help/Pretty.hs view
@@ -1,12 +1,16 @@+{-# LANGUAGE CPP #-} module Options.Applicative.Help.Pretty   ( module Text.PrettyPrint.ANSI.Leijen   , (.$.)   , groupOrNestLine   , altSep+  , hangAtIfOver   ) where  import           Control.Applicative+#if !MIN_VERSION_base(4,11,0) import           Data.Semigroup ((<>))+#endif  import           Text.PrettyPrint.ANSI.Leijen hiding ((<$>), (<>), columns) import           Text.PrettyPrint.ANSI.Leijen.Internal (Doc (..), flatten)@@ -21,12 +25,24 @@ -- | Apply the function if we're not at the --   start of our nesting level. ifNotAtRoot :: (Doc -> Doc) -> Doc -> Doc-ifNotAtRoot f doc =+ifNotAtRoot =+  ifElseAtRoot id++-- | Apply the function if we're not at the+--   start of our nesting level.+ifAtRoot :: (Doc -> Doc) -> Doc -> Doc+ifAtRoot =+  flip ifElseAtRoot id++-- | Apply the function if we're not at the+--   start of our nesting level.+ifElseAtRoot :: (Doc -> Doc) -> (Doc -> Doc) -> Doc -> Doc+ifElseAtRoot f g doc =   Nesting $ \i ->     Column $ \j ->       if i == j-        then doc-        else f doc+        then f doc+        else g doc   -- | Render flattened text on this line, or start@@ -54,3 +70,23 @@ altSep :: Doc -> Doc -> Doc altSep x y =   group (x <+> char '|' <> line) <//> y+++-- | Printer hacks to get nice indentation for long commands+--   and subcommands.+--+--   If we're starting this section over the desired width+--   (usually 1/3 of the ribbon), then we will make a line+--   break, indent all of the usage, and go.+--+--   The ifAtRoot is an interesting clause. If this whole+--   operation is put under a `group` then the linebreak+--   will disappear; then item d will therefore not be at+--   the starting column, and it won't be indented more.+hangAtIfOver :: Int -> Int -> Doc -> Doc+hangAtIfOver i j d =+  Column $ \k ->+    if k <= j then+      align d+    else+      linebreak <> ifAtRoot (indent i) d
src/Options/Applicative/Help/Types.hs view
@@ -14,26 +14,30 @@   , helpSuggestions :: Chunk Doc   , helpHeader :: Chunk Doc   , helpUsage :: Chunk Doc+  , helpDescription :: Chunk Doc   , helpBody :: Chunk Doc   , helpGlobals :: Chunk Doc-  , helpFooter :: Chunk Doc }+  , helpFooter :: Chunk Doc+  }  instance Show ParserHelp where   showsPrec _ h = showString (renderHelp 80 h)  instance Monoid ParserHelp where-  mempty = ParserHelp mempty mempty mempty mempty mempty mempty mempty+  mempty = ParserHelp mempty mempty mempty mempty mempty mempty mempty mempty   mappend = (<>)  instance Semigroup ParserHelp where-  (ParserHelp e1 s1 h1 u1 b1 g1 f1) <> (ParserHelp e2 s2 h2 u2 b2 g2 f2)+  (ParserHelp e1 s1 h1 u1 d1 b1 g1 f1) <> (ParserHelp e2 s2 h2 u2 d2 b2 g2 f2)     = ParserHelp (mappend e1 e2) (mappend s1 s2)                  (mappend h1 h2) (mappend u1 u2)-                 (mappend b1 b2) (mappend g1 g2)-                 (mappend f1 f2)+                 (mappend d1 d2) (mappend b1 b2)+                 (mappend g1 g2) (mappend f1 f2)  helpText :: ParserHelp -> Doc-helpText (ParserHelp e s h u b g f) = extractChunk . vsepChunks $ [e, s, h, u, b, g, f]+helpText (ParserHelp e s h u d b g f) =+  extractChunk $+    vsepChunks [e, s, h, u, fmap (indent 2) d, b, g, f]  -- | Convert a help text to 'String'. renderHelp :: Int -> ParserHelp -> String
src/Options/Applicative/NonEmpty.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE CPP, Rank2Types, ExistentialQuantification #-} module Options.Applicative.NonEmpty (   some1 ) where
src/Options/Applicative/Types.hs view
@@ -125,7 +125,8 @@                                   -- single space (default: False)   , prefHelpShowGlobal :: Bool    -- ^ when displaying subparsers' usage help,                                   -- show parent options under a "global options"-                                  -- section (default: True)+                                  -- section (default: False)+  , prefTabulateFill ::Int       -- ^ Indentation width for tables   } deriving (Eq, Show)  data OptName = OptShort !Char
+ tests/Examples/LongSub.hs view
@@ -0,0 +1,34 @@+{-# LANGUAGE CPP #-}+module Examples.LongSub where++import Data.Monoid+import Options.Applicative++#if __GLASGOW_HASKELL__ <= 702+(<>) :: Monoid a => a -> a -> a+(<>) = mappend+#endif++data Sample+  = Hello [String]+  | Goodbye+  deriving (Eq, Show)++hello :: Parser Sample+hello =+  Hello+    <$> many (argument str (metavar "TARGET..."))+    <*  switch (long "first-flag")+    <*  switch (long "second-flag")+    <*  switch (long "third-flag")+    <*  switch (long "fourth-flag")++sample :: Parser Sample+sample = hsubparser+       ( command "hello-very-long-sub"+         (info hello+               (progDesc "Print greeting"))+       )++opts :: ParserInfo Sample+opts = info (sample <**> helper) idm
tests/cabal.err.txt view
@@ -1,4 +1,5 @@ Usage: cabal configure [--enable-tests] [-f|--flags FLAGS]+   Prepare to build the package  Available options:
+ tests/formatting-long-subcommand.err.txt view
@@ -0,0 +1,9 @@+Usage: formatting-long-subcommand hello-very-long-sub +         [TARGET...] [--first-flag] +         [--second-flag] [--third-flag] +         [--fourth-flag]++  Print greeting++Available options:+  -h,--help                Show this help text
tests/formatting.err.txt view
@@ -1,4 +1,5 @@ Usage: formatting [-t|--test FOO_BAR_BAZ_LONG_METAVARIABLE]+   This is a very long program description. This   text should be automatically wrapped to fit the   size of the terminal
tests/hello.err.txt view
@@ -1,6 +1,7 @@ hello - a test for optparse-applicative  Usage: hello --hello TARGET [-q|--quiet] [--repeat INT]+   Print a greeting for TARGET  Available options:
tests/test.hs view
@@ -9,6 +9,7 @@ import qualified Examples.Cabal as Cabal import qualified Examples.Alternatives as Alternatives import qualified Examples.Formatting as Formatting+import qualified Examples.LongSub as LongSub  import           Control.Applicative import           Control.Monad@@ -890,6 +891,18 @@     pre = run i ["--help"]     post = run i ["--help", "not-a-command"]   in grabHelpMessage pre === grabHelpMessage post+++prop_long_command_line_flow :: Property+prop_long_command_line_flow = once $+  let p = LongSub.sample <**> helper+      i = info p+        ( progDesc (concat+            [ "This is a very long program description. "+            , "This text should be automatically wrapped "+            , "to fit the size of the terminal" ]) )+  in checkHelpTextWith ExitSuccess (prefs (columns 50)) "formatting-long-subcommand" i ["hello-very-long-sub", "--help"]+  ---