Duplicate option displays wrong error message...
I have a parser accepting --request option, and when user accidentally uses it twice, the error message says:
Invalid option `--request'
It should probably report:
Duplicated option is not allowed `--request'
Otherwise user things that the option name is wrong.
I don't think the current behaviour is wrong per se, the option really is invalid at that stage in the parse – maybe sub-optimal.
I did write something to test for this; but it couldn't distinguish between an option which has been used and an option which is not accessible due to an alternative being used. So the message could be something more like "the option --request can no longer be accessed".
Haven't merged it or put it anywhere yet though.
I also hit this problem and think there should be a better error message if a valid option is supplied too often.
Here is a popular instance:
$ cabal-plan --ascii info --ascii
Invalid option `--ascii'
$ cabal-plan --help
Usage: cabal-plan [--version] [--show-builtin | --hide-builtin]
[--show-global | --hide-global] [--show-setup | --hide-setup]
[--show-exes | --hide-exes] [--color always|never|auto]
[--ascii | --unicode | --ascii-auto] [COMMAND]
So the option is not "invalid".
Here is a reproducer:
import Options.Applicative
main :: IO ()
main = print =<< do
execParser $ (`info` header "Try options -o 1 -o 2") $ helper <*> optionO
optionO :: Parser (Maybe String)
optionO =
optional $ strOption $ mconcat
[ short 'o'
, metavar "STRING"
, help "Output STRING."
]
$ ./Main -o 1 -o 2
Invalid option `-o'
Commenting here for others facing a similar issue: I've opted to create two parsers, the first of which is the legitimate one, and the second of which throws an error instantly if invoked.
By chaining them with const, if the flag is ever specified a second time, the second parser is invoked and errors out with a custom message.
myOption :: Parser String
myOption = const <$> actualParser <*> errorIfTwiceParser
where
nameMod = long "my-option"
actualParser = option str nameMod
errorIfTwiceParser = option (readerError errMsg) (nameMod <> hidden <> value (error "optionOnce: should not happen!"))
It's a bit of a hack, but it works and conveniently avoids mucking around with any optparse internals.