bfgroup / Lyra

A simple to use, composable, command line parser for C++ 11 and beyond
https://bfgroup.github.io/Lyra/
Boost Software License 1.0
471 stars 56 forks source link

Several options with multiple arguments #51

Closed OliverSchmitz closed 2 years ago

OliverSchmitz commented 3 years ago

Hello, after first successful experiments with Lyra I'm now stuck with something. I try to apply multiple arguments to several options, like this:

#include <lyra/lyra.hpp>

int main(int argc, const char** argv)
{
  bool showHelp = false;
  std::string opA = "OFF";
  std::string opB = "OFF";
  std::vector<std::string> argsA;
  std::vector<std::string> argsB;

  auto cli = lyra::cli();
  cli.add_argument(lyra::help(showHelp));

  cli.add_argument(lyra::opt(opA, "ON|OFF")["--optionA"]
    | lyra::arg(argsA, "args"));
  cli.add_argument(lyra::opt(opB, "ON|OFF")["--optionB"]
    | lyra::arg(argsB, "args"));

  auto result = cli.parse({ argc, argv });
  if (!result) {
    std::cerr << "ERROR:" << cli << "\n";
    return EXIT_FAILURE;
  }
  std::cout << "\nopA: " << opA << " opB: " << opB<< '\n';
  if(!argsA.empty()){
    for(auto a: argsA){
      std::cout << "argsA: " << a << "\n";
    }
  }
  if(!argsB.empty()){
    for(auto a: argsB){
      std::cout << "argsB: " << a << "\n";
    }
  }

  std::cout << " \n";
  std::cout << cli << " \n";
  return EXIT_SUCCESS;
}

when executing with ./testargs --optionA=ON a1 a2 a3 --optionB=ON b1 b2 I'd expect to get a1, a2, a3 in argsA and b1,b2 in argsB. However, all end up in argsA, and --optionB seems not to be recognised. The usage info from the help looks ok imo. The output for info:

 ./testargs --optionA=ON a1 a2 a3 --optionB=ON b1 b2 

opA: ON opB: OFF
argsA: a1
argsA: a2
argsA: a3
argsA: --optionB=ON
argsA: b1
argsA: b2

USAGE:
  testargs [-?|-h|--help] [--optionA <ON|OFF>] [[<args>...]] [--optionB <ON|OFF>] [[<args>...]]

Display usage information.

OPTIONS, ARGUMENTS:
  -?, -h, --help          
  --optionA <ON|OFF>      
  [<args>...]             
  --optionB <ON|OFF>      
  [<args>...]             

Am I doing something entirely wrong, or is there another way to obtain the arguments per option? Thanks in advance!

grafikrobot commented 2 years ago

The reason for this is that the way you specified the arguments:

  cli.add_argument(lyra::opt(opA, "ON|OFF")["--optionA"]
    | lyra::arg(argsA, "args"));
  cli.add_argument(lyra::opt(opB, "ON|OFF")["--optionB"]
    | lyra::arg(argsB, "args"));

Is equivalent to:

  cli.add_argument(lyra::opt(opA, "ON|OFF")["--optionA"]);
  cli.add_argument(lyra::arg(argsA, "args"));
  cli.add_argument(lyra::opt(opB, "ON|OFF")["--optionB"]);
  cli.add_argument(lyra::arg(argsB, "args"));

I think what you want is to use a group for each option+args. Something like this:

  cli.add_argument(lyra::group().sequential()
    | lyra::opt(opA, "ON|OFF")["--optionA"]
    | lyra::arg(argsA, "args"));
  cli.add_argument(lyra::group().sequential()
    | lyra::opt(opB, "ON|OFF")["--optionB"]
    | lyra::arg(argsB, "args"));