Skip to content

Commit a6f81c3

Browse files
committed
[FEATURE] Copy some metadata to subparsers
1 parent fc235df commit a6f81c3

4 files changed

Lines changed: 90 additions & 0 deletions

File tree

doc/howto/subcommand_parser/index.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,16 @@ max$ ./mygit push -h
4848
then the sub-parser will be named `mygit-push` and will be instantiated with all arguments
4949
followed by the keyword `push` which in this case triggers printing the help page (`-h`).
5050

51+
Additionally, the following metadata will be copied from the top-level parser to the sub-parser:
52+
* sharg::parser::info::version
53+
* sharg::parser::info::author
54+
* sharg::parser::info::email
55+
* sharg::parser::info::date
56+
* sharg::parser::info::url
57+
* sharg::parser::info::short_copyright
58+
* sharg::parser::info::long_copyright
59+
* sharg::parser::info::citation
60+
5161
That's it. Here is a full example of a subcommand parser you can try and adjust to your needs:
5262

5363
\include doc/howto/subcommand_parser/subcommand_parse.cpp

include/sharg/auxiliary.hpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,20 @@ class vector_of_string : public std::vector<std::string>
7777
* The meta information is assembled in a struct to provide a central access
7878
* point that can be easily extended.
7979
*
80+
* ### Subparser
81+
*
82+
* When \link subcommand_parse using a subparser \endlink, the subcommand will be appended to the
83+
* subparser's #app_name.
84+
* Additionally, the following metadata will be copied from the top-level parser to the sub-parser:
85+
* * #version
86+
* * #author
87+
* * #email
88+
* * #date
89+
* * #url
90+
* * #short_copyright
91+
* * #long_copyright
92+
* * #citation
93+
*
8094
* \remark For a complete overview, take a look at \ref parser
8195
*
8296
* \stableapi{Since version 1.0.}

include/sharg/parser.hpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -838,11 +838,24 @@ class parser
838838
if (subcommands.empty())
839839
return false;
840840

841+
auto copy_metadata_to_subparser = [this](parser & sub_parser)
842+
{
843+
sub_parser.info.version = info.version;
844+
sub_parser.info.author = info.author;
845+
sub_parser.info.email = info.email;
846+
sub_parser.info.date = info.date;
847+
sub_parser.info.url = info.url;
848+
sub_parser.info.short_copyright = info.short_copyright;
849+
sub_parser.info.long_copyright = info.long_copyright;
850+
sub_parser.info.citation = info.citation;
851+
};
852+
841853
if (std::ranges::find(subcommands, arg) != subcommands.end())
842854
{
843855
sub_parser = std::make_unique<parser>(info.app_name + "-" + arg.data(),
844856
std::vector<std::string>{it, arguments.end()},
845857
update_notifications::off);
858+
copy_metadata_to_subparser(get_sub_parser());
846859

847860
// Add the original calls to the front, e.g. ["raptor"],
848861
// s.t. ["raptor", "build"] will be the list after constructing the subparser

test/unit/parser/subcommand_test.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,3 +271,56 @@ TEST_F(subcommand_test, recursive_subcommands)
271271

272272
EXPECT_EQ(get_parse_cout_on_exit(sub_sub_parser), expected_sub_sub_full_help);
273273
}
274+
275+
TEST_F(subcommand_test, copy_meta_data)
276+
{
277+
sharg::parser_meta_data info{.version = "1.0.0",
278+
.author = "SeqAn-Team",
279+
.email = "mail@example.org",
280+
.date = "1970-01-01",
281+
.url = "example.org",
282+
.short_copyright = "BSD 3-Clause",
283+
.long_copyright = "BSD 3-Clause Text",
284+
.citation = "Cite me!"};
285+
286+
auto parser = get_subcommand_parser({"index", "--help"}, {"index"});
287+
info.app_name = parser.info.app_name;
288+
parser.info = info;
289+
EXPECT_EQ(parser.info.app_name, "test_parser");
290+
ASSERT_EQ(parser.info, info); // Sanity check for test setup
291+
EXPECT_NO_THROW(parser.parse());
292+
293+
auto & sub_parser = parser.get_sub_parser();
294+
EXPECT_EQ(sub_parser.info.app_name, "test_parser-index");
295+
info.app_name = sub_parser.info.app_name;
296+
EXPECT_EQ(sub_parser.info, info);
297+
298+
std::string expected_sub_full_help = "test_parser-index\n"
299+
"=================\n"
300+
"\n"
301+
"OPTIONS\n"
302+
"\n"
303+
+ basic_options_str
304+
+ "\n"
305+
"VERSION\n"
306+
" Last update: 1970-01-01\n"
307+
" test_parser-index version: 1.0.0\n"
308+
" Sharg version: "
309+
+ sharg::sharg_version_cstring
310+
+ "\n"
311+
"\n"
312+
"URL\n"
313+
" example.org\n"
314+
"\n"
315+
"LEGAL\n"
316+
" test_parser-index Copyright: BSD 3-Clause\n"
317+
" Author: SeqAn-Team\n"
318+
" Contact: mail@example.org\n"
319+
" SeqAn Copyright: 2006-2025 Knut Reinert, FU-Berlin; released under the\n"
320+
" 3-clause BSDL.\n"
321+
" In your academic works please cite:\n"
322+
" [1] Cite me!\n"
323+
" For full copyright and/or warranty information see --copyright.\n";
324+
325+
EXPECT_EQ(get_parse_cout_on_exit(sub_parser), expected_sub_full_help);
326+
}

0 commit comments

Comments
 (0)