Commit 822f3d67007edfcad7aac4e1f3e463bf255c7a3c

Authored by Philip Top
Committed by GitHub
1 parent a86f7fbd

fix: add an alias section to the help for subcommands (#545)

include/CLI/App.hpp
@@ -1834,7 +1834,21 @@ class App { @@ -1834,7 +1834,21 @@ class App {
1834 } 1834 }
1835 1835
1836 /// Get a display name for an app 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 /// Check the name, case insensitive and underscore insensitive if set 1853 /// Check the name, case insensitive and underscore insensitive if set
1840 bool check_name(std::string name_to_check) const { 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,15 +205,18 @@ inline std::string Formatter::make_subcommands(const App *app, AppFormatMode mod
205 205
206 inline std::string Formatter::make_subcommand(const App *sub) const { 206 inline std::string Formatter::make_subcommand(const App *sub) const {
207 std::stringstream out; 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 return out.str(); 209 return out.str();
210 } 210 }
211 211
212 inline std::string Formatter::make_expanded(const App *sub) const { 212 inline std::string Formatter::make_expanded(const App *sub) const {
213 std::stringstream out; 213 std::stringstream out;
214 - out << sub->get_display_name() << "\n"; 214 + out << sub->get_display_name(true) << "\n";
215 215
216 out << make_description(sub); 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 out << make_positionals(sub); 220 out << make_positionals(sub);
218 out << make_groups(sub, AppFormatMode::Sub); 221 out << make_groups(sub, AppFormatMode::Sub);
219 out << make_subcommands(sub, AppFormatMode::Sub); 222 out << make_subcommands(sub, AppFormatMode::Sub);
include/CLI/StringTools.hpp
@@ -159,7 +159,7 @@ inline std::string trim_copy(const std::string &amp;str, const std::string &amp;filter) @@ -159,7 +159,7 @@ inline std::string trim_copy(const std::string &amp;str, const std::string &amp;filter)
159 return trim(s, filter); 159 return trim(s, filter);
160 } 160 }
161 /// Print a two part "help" string 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 name = " " + name; 163 name = " " + name;
164 out << std::setw(static_cast<int>(wid)) << std::left << name; 164 out << std::setw(static_cast<int>(wid)) << std::left << name;
165 if(!description.empty()) { 165 if(!description.empty()) {
@@ -176,6 +176,24 @@ inline std::ostream &amp;format_help(std::ostream &amp;out, std::string name, std::strin @@ -176,6 +176,24 @@ inline std::ostream &amp;format_help(std::ostream &amp;out, std::string name, std::strin
176 return out; 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 /// Verify the first character of an option 197 /// Verify the first character of an option
180 template <typename T> bool valid_first_char(T c) { 198 template <typename T> bool valid_first_char(T c) {
181 return std::isalnum(c, std::locale()) || c == '_' || c == '?' || c == '@'; 199 return std::isalnum(c, std::locale()) || c == '_' || c == '?' || c == '@';
tests/HelpTest.cpp
@@ -467,6 +467,36 @@ TEST(THelp, Subcom) { @@ -467,6 +467,36 @@ TEST(THelp, Subcom) {
467 EXPECT_THAT(help, HasSubstr("Usage: ./myprogram sub2")); 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 TEST(THelp, MasterName) { 500 TEST(THelp, MasterName) {
471 CLI::App app{"My prog", "MyRealName"}; 501 CLI::App app{"My prog", "MyRealName"};
472 502