Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

easy --no-switch complement to --switch #148

Open
joeyh opened this issue Aug 20, 2015 · 6 comments
Open

easy --no-switch complement to --switch #148

joeyh opened this issue Aug 20, 2015 · 6 comments

Comments

@joeyh
Copy link

joeyh commented Aug 20, 2015

A fairly common idiom in option parsing libraries is for --no-switch to be available as a way to disable an earlier --switch on the command line.

This is useful eg, when you have a shell alias foo = foo --switch, so foo --no-switch can be used to override . Another use case is to help future-proof a program; if it later changes so --switch is enabled by default, then users of both the old and the new version can use --no-switch to get the old behavior.

This is a bit clumsy to do with optparse-applicative, unless I'm missing an easy way to do it. Here's an implementation that makes it easy. I'd be happy if this or something like it were added to your library.

-- | A switch that can be enabled using --foo and disabled using --no-foo.
--
-- The option modifier is applied to only the option that is *not* enabled
-- by default. For example:
--
-- > invertableSwitch "recursive" True (help "do not recurse into directories")
-- 
-- This example makes --recursive enabled by default, so 
-- the help is shown only for --no-recursive.
invertableSwitch 
    :: String -- ^ long option
    -> Bool -- ^ is switch enabled by default?
    -> Mod FlagFields Bool -- ^ option modifier
    -> Parser Bool
invertableSwitch longopt defv optmod = invertableSwitch' longopt defv
    (if defv then mempty else optmod)
    (if defv then optmod else mempty)

-- | Allows providing option modifiers for both --foo and --no-foo.
invertableSwitch'
    :: String -- ^ long option (eg "foo")
    -> Bool -- ^ is switch enabled by default?
    -> Mod FlagFields Bool -- ^ option modifier for --foo
    -> Mod FlagFields Bool -- ^ option modifier for --no-foo
    -> Parser Bool
invertableSwitch' longopt defv enmod dismod = collapse <$> many
    ( flag' True (enmod <> long longopt)
    <|> flag' False (dismod <> long nolongopt)
    )
  where
    nolongopt = "no-" ++ longopt
    collapse [] = defv
    collapse l = last l
@borsboom
Copy link

Here's the version of this from stack, which I think is pretty similar: https://github.com/commercialhaskell/stack/blob/0fa72bd825228d65f8e2c2b024d3fff0d7d792e7/src/Options/Applicative/Builder/Extra.hs#L36. Ours also accepts hidden --disable-* and --enable-* versions

@HuwCampbell
Copy link
Collaborator

In you example of foo = bar --switch, then foo --no-switch; this is monadic parsing as the order then becomes important.
I would suggest using something like the example given instead.

@joeyh
Copy link
Author

joeyh commented Aug 26, 2015

Huw Campbell wrote:

In you example of foo = bar --switch, then foo --no-switch; this is monadic
parsing as the order then becomes important.

Order can be important in applicative parsing, no monads necessary.

In my implementation sent to this bug, it's handled by getting a list of
parses of values for the switch, and using only the last value.

see shy jo

@HuwCampbell
Copy link
Collaborator

Oh ok, you're using many (optparse provides its own version of many which uses bind instead of apply, it's the one bit using bind in there and I don't want to add any more).
I'll have a think about it, it looks like there's a few people who have written something along these lines before.

@NorfairKing
Copy link

+1 Would love this feature.

@hasufell
Copy link

Ping. Has there been any decision whether such a feature would be accepted?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants