1515namespace rsl {
1616struct cli ;
1717struct config ;
18- }
18+ } // namespace rsl
1919
2020namespace rsl ::_cli_impl {
2121
@@ -35,8 +35,12 @@ struct Spec {
3535 // but cannot be used in combination with variadic or optional arguments
3636 std::vector<Spec> subcommands;
3737
38+ bool allow_positional;
39+
40+ consteval explicit Parser (bool allow_positional = true ) : allow_positional(allow_positional) {}
41+
3842 consteval void parse (std::meta::info r) {
39- auto ctx = std::meta::access_context::current ();
43+ auto ctx = std::meta::access_context::current ();
4044 for (auto base : bases_of (r, ctx)) {
4145 parse_base (r, base);
4246 }
@@ -77,12 +81,30 @@ struct Spec {
7781 return false ;
7882 }
7983
80- if (!meta::has_annotation (r, ^^annotations::Positional)) {
81- return false ;
84+ if (meta::has_annotation (r, ^^annotations::Positional)) {
85+ if (!allow_positional) {
86+ compile_error (" Positional arguments are only supported at the config root." );
87+ }
88+ arguments.emplace_back (idx, r);
89+ return true ;
8290 }
8391
84- arguments.emplace_back (idx, r);
85- return true ;
92+ if (extract<bool >(substitute (^^std::derived_from, {type_of (r), ^^config}))) {
93+ auto name = identifier_of (r);
94+
95+ auto subparser = Parser (false );
96+ subparser.parse (type_of (r));
97+
98+ for (auto option : subparser.options ) {
99+ option.name = std::define_static_string (std::string (name) + ' :' + option.name );
100+ options.push_back (option);
101+ }
102+ for (auto command : subparser.commands ) {
103+ command.name = std::define_static_string (std::string (name) + ' :' + command.name );
104+ options.push_back (command);
105+ }
106+ }
107+ return false ;
86108 }
87109
88110 consteval bool parse_command (std::meta::info r) {
0 commit comments