swift-argument-parser icon indicating copy to clipboard operation
swift-argument-parser copied to clipboard

Support option in children and parent with the same name

Open Frizlab opened this issue 5 years ago • 2 comments

My use case is an example from git. Potentially linked discussion: https://forums.swift.org/t/supporting-subcommands-with-same-option-name-as-reused-parent-command

Let’s consider git commit specifically which has the -C option to specify a commit from which to reuse the log message and other. git by itself also has a -C option, to change the repository path.

Thus, we can legally call git with:

git   -C my_path   commit   -C my_commit

If I’m not mistaken, this setup is currently impossible to describe using ArgumentParser.

Ideally, I think this:

struct GlobalOptions : ParsableArguments {
   @Option(name: .customShort("C"))
   var path: String
}

struct Git : ParsableCommand {
   static var configuration = CommandConfiguration(
      abstract: "…",
      subcommands: [
         GitCommit.self
      ]
   )

   @OptionGroup()
   var globalOptions: GlobalOptions
}

struct GitCommit : ParsableCommand {
   static var configuration = CommandConfiguration(abstract: "…")

   @OptionGroup()
   var globalOptions: GlobalOptions

   @Option(name: .customShort("C"))
   var commitFrom: String

   func run() throws {
      print(globalOptions.path)
      print(commitFrom)
   }
}

When called like this:

git -C path commit -C commit

Should print:

path
commit

Currently it says there is a missing -C argument.

Frizlab avatar May 28 '20 14:05 Frizlab

@natecook1000

Would you happen to have an update on this issue 👀 Ran into this today but when trying to create a command like swift run which allows forwarding arguments to an executable.

For example: Creating a command like: mycli run --path /path/to/bin foo --path /path/to/elsewhere. In this case, the run command has a path option to run an executable at some given path, and the executable foo also has a --path as part of its possible arguments. In this case only the first --path is read and the --path to foo is dropped. Looking for the same behavior as swift run essentially.

I'd be happy to help contribute this if needed!

Edit:

I see now that https://github.com/apple/swift-argument-parser/pull/304 might fix this!

luispadron avatar May 09 '21 19:05 luispadron

Actually think #304 is just for option arrays.

Here is an example where this support is missing:

struct RunCommand: ParsableCommand {
    @Option()
    var path: String?

    @Argument(parsing: .unconditionalRemaining)
    var arguments: [String] = []

    func run() throws {
        print(path)
        print(arguments)
    }
}

Running: mycli run run --path firstPath Arg1 Arg2 Arg3 --path secondPath results in:

secondPath
Arg1 Arg2 Arg3

But I would expect:

firstPath
[Arg1, Arg2, Arg3, --path, secondPath]

@natecook1000 Would this be an enhancement or a bug given parsing: .unconditionalRemaining?

luispadron avatar May 24 '21 01:05 luispadron