Code Monkey home page Code Monkey logo

Comments (3)

muellan avatar muellan commented on June 29, 2024

You could achieve that by separating the definitions of the commands and options from the parsing control flow logic:

    auto opts = (
        option("-a"),
        option("-b"),
        option("-c")
    );
    auto cmds = ( 
          command("cmd1")
        | command("cmd2")
        | command("cmd3")
        | command("cmd4")
    );
    auto cli = ( (cmds, opts) | opts );  // <--

from clipp.

risa2000 avatar risa2000 commented on June 29, 2024

This would be probably good enough for me, but I cannot make it work. Here is a testing code to reproduce the behavior:

#include <iostream>
#include <string>
#include <clipp.h>

int main(int argc, char *argv[])
{
    using namespace clipp;

    //variables storing the parsing result; initialized with their default values
    enum class mode { cmd1, cmd2, cmd3 };
    mode selected = mode::cmd1;
    std::string input;
    int verb = 0;

    auto cli_cmds = (
        (command("cmd1").set(selected, mode::cmd1).doc("command 1") \
            | command("find").set(selected, mode::cmd2).doc("command 2") \
            | command("help").set(selected, mode::cmd3).doc("command 3")));
 
    auto cli_opts = (
        option("-i", "--input") & value("data", input) % "testing input",
        (option("-v", "--verb").set(verb, 1) & opt_value("level", verb)) % "verbosity"
        );

    auto cli = ((cli_cmds, cli_opts) | cli_opts);

    if (parse(argc, argv, cli)) {
        switch (selected) {
        case mode::cmd1:
        case mode::cmd2:
        case mode::cmd3:
            std::cout << "selected: " << static_cast<int>(selected) << '\n';
            std::cout << "input: " << input << '\n';
            std::cout << "verb: " << verb << '\n';
        }
    }
    else {
        std::cout << usage_lines(cli, "tester") << '\n';
    }
    return 0;
}

If I do not give any command on the CL, the parsing fails. Changing the processing to the original idea works however:

    if (parse(argc, argv, (cli_cmds, cli_opts))) {
        switch (selected) {
        case mode::cmd1:
        case mode::cmd2:
        case mode::cmd3:
            std::cout << "selected: " << static_cast<int>(selected) << '\n';
            std::cout << "input: " << input << '\n';
            std::cout << "verb: " << verb << '\n';
        }
    }
    else {
        if (parse(argc, argv, cli_opts)) {
            std::cout << "selected: " << static_cast<int>(mode::cmd1) << '\n';
            std::cout << "input: " << input << '\n';
            std::cout << "verb: " << verb << '\n';
        }
        std::cout << usage_lines(cli, "tester") << '\n';
    }
    return 0;

from clipp.

risa2000 avatar risa2000 commented on June 29, 2024

FWIW I accidentally figured out the situation when it works as you proposed. Here is a streamlined testcase:

int main(int argc, char *argv[])
{
    using namespace clipp;

    enum class mode { cmd1, cmd2 };
    mode selected = mode::cmd1;
    std::string name;
    std::string opt1;

    auto cli_cmds = (
        command("cmd1").set(selected, mode::cmd1).doc("command 1")
        | command("cmd2").set(selected, mode::cmd2).doc("command 2"));
 
    auto cli_args = value("name", name) % "pos. arg. name";
    auto cli_opts = (option("-o", "--option") & value("option", opt1)) % "option";
    //auto cli_nocmd = (cli_args, cli_opts);
    auto cli_nocmd = cli_opts;
    auto cli = ((cli_cmds, cli_nocmd) | cli_nocmd);

    if (parse(argc, argv, cli)) {
        switch (selected) {
        case mode::cmd1:
        case mode::cmd2:
            std::cout << "selected: " << static_cast<int>(selected) << '\n';
            std::cout << "option: " << opt1 << '\n';
            std::cout << "name: " << name << '\n';
        }
    }
    else {
        std::cout << "Usage:\n" << usage_lines(cli, "tester") << '\n';
    }
    return 0;
}

Basically the CLI definition has two parts: cli_cmds which contains commands, and cli_nocmd which is the rest. The rest can differ as will be explained below. Then I use:

auto cli = ((cli_cmds, cli_nocmd) | cli_nocmd);

to define the "composite" definition to also accept a command line without any command (i.e. using "default" command).

The code as presented above does not work. Running the executable without any arguments does not get parsed properly (as "no command & no option").

However if I add additional positional argument name into "no commands" definition (currently commented out) and run the code, it starts working as expected. I.e. running it with only the positional argument gets parsed correctly.

It seems that if there is no argument on the command line and no required argument in cli_nocmd definition the whole cli_nocmd part gets ignored and the parsing fails.

Can it be qualified as a bug?

from clipp.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.