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

Add CLI apps, and a flags library #15

Merged
merged 8 commits into from
Jul 11, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
fix issues w the parser
  • Loading branch information
mcy committed Jul 11, 2024
commit 8db1aa27fa8224824dbcc195c1e960855344b3ea
19 changes: 19 additions & 0 deletions best/cli/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,25 @@ cc_test(
deps = [
":cli",
":parser",
":toy_flags",
"//best/test",
]
)

cc_library(
name = "toy_flags",
hdrs = ["toy_flags.h"],
deps = [
":cli",
],
visibility = ["//visibility:private"],
)

cc_binary(
name = "toy",
srcs = ["toy.cc"],
deps = [
":app",
":toy_flags",
]
)
5 changes: 3 additions & 2 deletions best/cli/cli.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,9 @@ class cli final {
struct alias final {
/// Same restrictions as the `name` field on the corresponding tag.
best::str name;
/// The visibility for this alias.
visibility vis = Public;
/// The visibility for this alias. If not specified, uses the visibility
/// of the tag it is attached to.
best::option<visibility> vis;
};

/// # `cli::flag`
Expand Down
129 changes: 2 additions & 127 deletions best/cli/cli_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,136 +22,11 @@
#include "best/cli/cli.h"

#include "best/cli/parser.h"
#include "best/cli/toy_flags.h"
#include "best/test/test.h"

namespace best::flag_parser_test {

struct Subcommand {
int sub_flag;
best::str arg;

friend constexpr auto BestReflect(auto& m, Subcommand*) {
using ::best::cli;
return m.infer()->*m.field(best::vals<&Subcommand::sub_flag>,
cli::flag{
.letter = 's',
.arg = "INT",
.help = "a subcommand argument",
});
}

bool operator==(const Subcommand&) const = default;
};

struct Subgroup {
int eks = 0, why = 0, zed = 0;

friend constexpr auto BestReflect(auto& m, Subgroup*) {
using ::best::cli;
return m.infer()
->*m.field(best::vals<&Subgroup::eks>, cli::flag{
.letter = 'x',
.arg = "INT",
.help = "a group integer",
})
->*m.field(best::vals<&Subgroup::why>, cli::flag{
.letter = 'y',
.arg = "INT",
.help = "another group integer",
})
->*m.field(best::vals<&Subgroup::zed>, cli::flag{
.letter = 'z',
.arg = "INT",
.help = "a third group integer",
});
}

bool operator==(const Subgroup&) const = default;
};

struct MyFlags {
int foo = 0;
best::vec<int> bar;
best::option<int> baz;
best::str name, addr;

bool flag1 = false;
bool flag2 = false;
bool flag3 = false;
bool flag4 = false;

Subcommand sub;
Subcommand sub2;

Subgroup group;
Subgroup flattened;

best::str arg;
best::vec<best::str> args;

friend constexpr auto BestReflect(auto& m, MyFlags*) {
using ::best::cli;
return m.infer()
->*m.field(best::vals<&MyFlags::foo>, cli::flag{
.letter = 'f',
.arg = "INT",
.count = cli::Required,
.help = "a required integer",
})
->*m.field(best::vals<&MyFlags::bar>, cli::flag{
.arg = "INT",
.help = "repeated integer",
})
->*m.field(best::vals<&MyFlags::baz>, cli::flag{
.help = "an optional integer",
})

->*m.field(best::vals<&MyFlags::name>, cli::flag{
.vis = cli::Hidden,
.help = "your name",
}, cli::alias{"my-name"})
->*m.field(best::vals<&MyFlags::addr>, cli::flag{
.vis = cli::Hidden,
.help = "your address",
}, cli::alias{"my-address"})

->*m.field(best::vals<&MyFlags::flag1>, cli::flag{
.letter = 'a',
.help = "this is a flag\nnewline",
})
->*m.field(best::vals<&MyFlags::flag2>, cli::flag{
.letter = 'b',
.help = "this is a flag\nnewline",
})
->*m.field(best::vals<&MyFlags::flag3>, cli::flag{
.letter = 'c',
.help = "this is a flag\nnewline",
}, cli::alias{"flag3-alias"},
cli::alias{"flag3-alias2", cli::Hidden})
->*m.field(best::vals<&MyFlags::flag4>, cli::flag{
.letter = 'd',
.help = "this is a flag\nnewline",
})

->*m.field(best::vals<&MyFlags::sub>, cli::subcommand{
.help = "a subcommand",
.about = "longer help for the subcommand\nwith multiple lines",
})
->*m.field(best::vals<&MyFlags::sub2>, cli::subcommand{
.help = "identical in all ways to `sub`\nexceptt for this help",
.about = "longer help for the subcommand\nwith multiple lines",
}, cli::alias{"sub3"})

->*m.field(best::vals<&MyFlags::group>, cli::group{
.name = "subgroup",
.letter = 'X',
.help = "extra options behind the -X flag",
})
->*m.field(best::vals<&MyFlags::flattened>, cli::group{}, cli::alias{"sub3"});
}

bool operator==(const MyFlags&) const = default;
};
using ::best::cli_toy::MyFlags;

best::test Flags = [](auto& t) {
best::parse_flags<MyFlags>("test", {"--help"}).err()->print_and_exit();
Expand Down
Loading