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

Whether subcommands are supported ? #90

Open
velasco300 opened this issue Feb 19, 2023 · 3 comments
Open

Whether subcommands are supported ? #90

velasco300 opened this issue Feb 19, 2023 · 3 comments

Comments

@velasco300
Copy link

No description provided.

@Hejsil
Copy link
Owner

Hejsil commented Feb 19, 2023

This is not a feature this library has yet and I've not had much motivation to implement this feature myself. It is not really a feature I need this library to have for my projects, so I've had little motivation to come up with a good API and implement it.

Here are some examples of how people have implemented subcommands and then used zig-clap to parse the args for each command:

@james-callahan
Copy link

james-callahan commented Jul 5, 2023

I'm trying to implement subcommands with different parsers, but it appears that you can only use parseParamsComptime once due to it hardcoding Param(Help) in the return type.

    const Subcommand = enum { client, server };
    const parsers = comptime .{
        .int = clap.parsers.int,
        .SUBCOMMAND = clap.parsers.enumeration(Subcommand),
    };
    
    const params = comptime clap.parseParamsComptime(
        \\-h, --help    Display this help and exit
        \\--version     Prints version information
        \\<SUBCOMMAND>  Either "client" or "server"
        \\
    );
    const client_params = comptime clap.parseParamsComptime(
        \\--cid <int>   The remote endpoint CID
        \\--port <int>  The remote endpoint port
        \\
    );
    const server_params = comptime clap.parseParamsComptime(
        \\--port <int>  The local port to listen on
        \\
    );
    
    var diag = clap.Diagnostic{};
    var res = clap.parse(clap.Help, &params, parsers, .{
        .diagnostic = &diag,
    }) catch |err| {
        diag.report(std.io.getStdErr().writer(), err) catch {};
        show_usage(clap.Help, &params) catch {};
        return;
    };
    defer res.deinit();
    
    if (res.positionals.len != 1) {
        std.io.getStdErr().writer().print("Missing subcommand\n", .{}) catch {};
        show_usage(clap.Help, &params) catch {};
        return;
    }
    
    if (res.args.help) {
        const stdout = std.io.getStdOut();
        try clap.help(stdout.writer(), clap.Help, &params, .{});
        try stdout.writer().print("\nclient subcommand options:\n", .{});
        try clap.help(stdout.writer(), clap.Help, &client_params, .{});
        try stdout.writer().print("\nserver subcommand options:\n", .{});
        try clap.help(stdout.writer(), clap.Help, &server_params, .{});
        return;
    }
    
    if (res.args.version) {
        const stdout = std.io.getStdOut();
        try stdout.writer().print("v0.0.0", .{});
        return;
    }
    
    switch (res.positionals[0]) {
        .client => {
            var client_res = clap.parse(clap.Help, &client_params, parsers, .{
                .diagnostic = &diag,
            }) catch |err| {
                diag.report(std.io.getStdErr().writer(), err) catch {};
                show_usage(&client_params) catch {};
                return;
            };
            defer client_res.deinit();
        },
        .server => {
            unreachable;
        },
    }

Could you add a parseParamsComptime variant where I can pass in an Id?

@Hejsil
Copy link
Owner

Hejsil commented Jul 5, 2023

I've tried your code and it does compile fine (after changing .int = clap.parsers.int, to .int = clap.parsers.int(u8, 10),).

The problem now is when you do:

$ zig-out/bin/exe client
Invalid argument 'client'

What happens here, is that clap.parse with params succeeds and the program end up in the .client switch case. Then clap.parse on client_params fails because it does not expect a positional argument, and clap.parse looks at all arguments given to the program. I recommend having a look at the links above for examples of how people have done sub commands.

Another resource is the PR #93. There is an example for how you can use clap to find the first positional and parse args[0..first_pos + 1] with one parser and args[first_pos + 1..] with another.

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

3 participants