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

combining parsers with overlapping flags #85

Open
aavogt opened this issue May 29, 2014 · 5 comments
Open

combining parsers with overlapping flags #85

aavogt opened this issue May 29, 2014 · 5 comments

Comments

@aavogt
Copy link

aavogt commented May 29, 2014

Could optparse-applicative provide more help when combining parsers that have the same flag names. For example:

mapOptName  :: (OptName -> OptName) -> Parser a -> Parser a
mapOptName f (OptP x) = OptP (mapOption x)
  where
    mapOption :: Option a -> Option a
    mapOption (Option r p) = Option (mapReader r) p

    mapReader :: OptReader a -> OptReader a
    mapReader (OptReader n x y) = OptReader (map f n) x y
    mapReader (FlagReader n a) = FlagReader (map f n) a
    mapReader x = x
mapOptName f (MultP x y) = MultP (mapOptName f x) (mapOptName f y)
mapOptName f (AltP x y) = AltP (mapOptName f x) (mapOptName f y)
mapOptName f (BindP x y) = BindP (mapOptName f x) (mapOptName f . y)
mapOptName f x = x

addPrefix p (OptShort c) = OptLong (p ++ "-" ++ [c])
addPrefix p (OptLong c) = OptLong (p ++ "-" ++ c)

Lets me write something like:

step :: Parser Step
step = ...

steps :: Parser (Step, Step)
steps = (,) <$> mapOptName (addPrefix "step1") step
   <*> mapOptName (addPrefix "step2") step

steps accepts arguments like --step1-x --step2-x if step accepts -x. Ideally the prefix could be left out when there is no conflict, but I think BindP gets in the way of defining a renameOptNames :: ([OptName] -> [OptName]) -> Parser a -> Parser a that sees all OptName at once.

uu-options supports +blah -blah delimiters. See section 5.2 of their techreport

@pcapriotti
Copy link
Owner

I'm not sure what feature you are requesting here. Can you elaborate? See also #77.

@aavogt
Copy link
Author

aavogt commented Aug 18, 2014

I want something(s) better than the mapOptName pasted above. Maybe these examples help:

import Options.Applicative; import Options.Applicative.Internal; import Options.Applicative.Types
import Data.Monoid

mapOptName  :: (OptName -> OptName) -> Parser a -> Parser a
addPrefix :: String -> OptName -> OptName
-- both are defined above

step1 = (,) <$> switch (long "step1specific") <*> switch (short 'x')
step2 = (,) <$> switch (long "step2specific") <*> switch (short 'x')


steps = (,) <$> mapOptName (addPrefix "step1") step1
    <*> mapOptName (addPrefix "step2") step2


run str = execParserPure (prefs mempty) (info steps mempty) str
{- ^

>>> run ["--step1-step1specific","--step2-step2specific","--step1-x","--step2-x"]
Success ((True,True),(True,True))

The above code works. I would like if it were possible to
make the following examples work without needing to make
substantial changes to the parsers.

>>> run ["--step1specific","--step2specific","--step2-x"]
Success ((True,False),(True,True))

>>> run ["-x"]
Success ((False,True),(False,True))

>>> run ["+step1","-x","-step1","--step2specific"]
Success ((False,True),(True,False))

-}

@pcapriotti
Copy link
Owner

I see. This is a sensible request, as the current semantics of sequencing of parsers with overlapping option names is a bit unsatisfactory (the second option cannot be parsed until the first one is).

I think the proper way to handle this is to add a namespace field to OptName, and then take it into account when parsing. Then we could make "+foo" and "-foo" set and unset the current namespace respectively.

I'm not sure I'll be able to implement this right away, but patches are (as always) welcome :)

@yaitskov
Copy link

Hi,

I am also worried about current behavior.
I have short name flag in a subcommand parser with same name as on level above.
The flag from a subcommand parser is not available.
Validation for top level flag is triggered and it terminates my program.
I would like to see at least warning when short name flag is used and help produced by the library could remove short name for subcommand if it is already used and enforce user to use long version.

@HuwCampbell
Copy link
Collaborator

So I'm going to guess you're in subparser inline mode. If you move the flag to after the definitions of the commands it should work for you, as the inlined parser will be searched first.

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

No branches or pull requests

4 participants