Commit 822f3d67007edfcad7aac4e1f3e463bf255c7a3c
Committed by
GitHub
1 parent
a86f7fbd
fix: add an alias section to the help for subcommands (#545)
Showing
4 changed files
with
69 additions
and
4 deletions
include/CLI/App.hpp
| ... | ... | @@ -1834,7 +1834,21 @@ class App { |
| 1834 | 1834 | } |
| 1835 | 1835 | |
| 1836 | 1836 | /// Get a display name for an app |
| 1837 | - std::string get_display_name() const { return (!name_.empty()) ? name_ : "[Option Group: " + get_group() + "]"; } | |
| 1837 | + std::string get_display_name(bool with_aliases = false) const { | |
| 1838 | + if(name_.empty()) { | |
| 1839 | + return std::string("[Option Group: ") + get_group() + "]"; | |
| 1840 | + } | |
| 1841 | + if(aliases_.empty() || !with_aliases || aliases_.empty()) { | |
| 1842 | + return name_; | |
| 1843 | + } | |
| 1844 | + std::string dispname = name_; | |
| 1845 | + for(const auto &lalias : aliases_) { | |
| 1846 | + dispname.push_back(','); | |
| 1847 | + dispname.push_back(' '); | |
| 1848 | + dispname.append(lalias); | |
| 1849 | + } | |
| 1850 | + return dispname; | |
| 1851 | + } | |
| 1838 | 1852 | |
| 1839 | 1853 | /// Check the name, case insensitive and underscore insensitive if set |
| 1840 | 1854 | bool check_name(std::string name_to_check) const { | ... | ... |
include/CLI/Formatter.hpp
| ... | ... | @@ -205,15 +205,18 @@ inline std::string Formatter::make_subcommands(const App *app, AppFormatMode mod |
| 205 | 205 | |
| 206 | 206 | inline std::string Formatter::make_subcommand(const App *sub) const { |
| 207 | 207 | std::stringstream out; |
| 208 | - detail::format_help(out, sub->get_name(), sub->get_description(), column_width_); | |
| 208 | + detail::format_help(out, sub->get_display_name(true), sub->get_description(), column_width_); | |
| 209 | 209 | return out.str(); |
| 210 | 210 | } |
| 211 | 211 | |
| 212 | 212 | inline std::string Formatter::make_expanded(const App *sub) const { |
| 213 | 213 | std::stringstream out; |
| 214 | - out << sub->get_display_name() << "\n"; | |
| 214 | + out << sub->get_display_name(true) << "\n"; | |
| 215 | 215 | |
| 216 | 216 | out << make_description(sub); |
| 217 | + if(sub->get_name().empty() && !sub->get_aliases().empty()) { | |
| 218 | + detail::format_aliases(out, sub->get_aliases(), column_width_ + 2); | |
| 219 | + } | |
| 217 | 220 | out << make_positionals(sub); |
| 218 | 221 | out << make_groups(sub, AppFormatMode::Sub); |
| 219 | 222 | out << make_subcommands(sub, AppFormatMode::Sub); | ... | ... |
include/CLI/StringTools.hpp
| ... | ... | @@ -159,7 +159,7 @@ inline std::string trim_copy(const std::string &str, const std::string &filter) |
| 159 | 159 | return trim(s, filter); |
| 160 | 160 | } |
| 161 | 161 | /// Print a two part "help" string |
| 162 | -inline std::ostream &format_help(std::ostream &out, std::string name, std::string description, std::size_t wid) { | |
| 162 | +inline std::ostream &format_help(std::ostream &out, std::string name, const std::string &description, std::size_t wid) { | |
| 163 | 163 | name = " " + name; |
| 164 | 164 | out << std::setw(static_cast<int>(wid)) << std::left << name; |
| 165 | 165 | if(!description.empty()) { |
| ... | ... | @@ -176,6 +176,24 @@ inline std::ostream &format_help(std::ostream &out, std::string name, std::strin |
| 176 | 176 | return out; |
| 177 | 177 | } |
| 178 | 178 | |
| 179 | +/// Print subcommand aliases | |
| 180 | +inline std::ostream &format_aliases(std::ostream &out, const std::vector<std::string> &aliases, std::size_t wid) { | |
| 181 | + if(!aliases.empty()) { | |
| 182 | + out << std::setw(static_cast<int>(wid)) << " aliases: "; | |
| 183 | + bool front = true; | |
| 184 | + for(const auto &alias : aliases) { | |
| 185 | + if(!front) { | |
| 186 | + out << ", "; | |
| 187 | + } else { | |
| 188 | + front = false; | |
| 189 | + } | |
| 190 | + out << alias; | |
| 191 | + } | |
| 192 | + out << "\n"; | |
| 193 | + } | |
| 194 | + return out; | |
| 195 | +} | |
| 196 | + | |
| 179 | 197 | /// Verify the first character of an option |
| 180 | 198 | template <typename T> bool valid_first_char(T c) { |
| 181 | 199 | return std::isalnum(c, std::locale()) || c == '_' || c == '?' || c == '@'; | ... | ... |
tests/HelpTest.cpp
| ... | ... | @@ -467,6 +467,36 @@ TEST(THelp, Subcom) { |
| 467 | 467 | EXPECT_THAT(help, HasSubstr("Usage: ./myprogram sub2")); |
| 468 | 468 | } |
| 469 | 469 | |
| 470 | +TEST(THelp, Subcom_alias) { | |
| 471 | + CLI::App app{"My prog"}; | |
| 472 | + | |
| 473 | + auto sub1 = app.add_subcommand("sub1", "Subcommand1 description test"); | |
| 474 | + sub1->alias("sub_alias1"); | |
| 475 | + sub1->alias("sub_alias2"); | |
| 476 | + | |
| 477 | + app.add_subcommand("sub2", "Subcommand2 description test"); | |
| 478 | + | |
| 479 | + std::string help = app.help(); | |
| 480 | + EXPECT_THAT(help, HasSubstr("Usage: [OPTIONS] [SUBCOMMAND]")); | |
| 481 | + EXPECT_THAT(help, HasSubstr("sub_alias1")); | |
| 482 | + EXPECT_THAT(help, HasSubstr("sub_alias2")); | |
| 483 | +} | |
| 484 | + | |
| 485 | +TEST(THelp, Subcom_alias_group) { | |
| 486 | + CLI::App app{"My prog"}; | |
| 487 | + | |
| 488 | + auto sub1 = app.add_subcommand("", "Subcommand1 description test"); | |
| 489 | + sub1->alias("sub_alias1"); | |
| 490 | + sub1->alias("sub_alias2"); | |
| 491 | + | |
| 492 | + app.add_subcommand("sub2", "Subcommand2 description test"); | |
| 493 | + | |
| 494 | + std::string help = app.help(); | |
| 495 | + EXPECT_THAT(help, HasSubstr("Usage: [OPTIONS] [SUBCOMMAND]")); | |
| 496 | + EXPECT_THAT(help, HasSubstr("sub_alias1")); | |
| 497 | + EXPECT_THAT(help, HasSubstr("sub_alias2")); | |
| 498 | +} | |
| 499 | + | |
| 470 | 500 | TEST(THelp, MasterName) { |
| 471 | 501 | CLI::App app{"My prog", "MyRealName"}; |
| 472 | 502 | ... | ... |