Skip to content

Commit

Permalink
Footer callback (#309)
Browse files Browse the repository at this point in the history
fix incorrect parenthesis

update some clang-tidy fixes mainly else after return but a few conversions from into to bool

add extra newline before footer

add an extra field to the extra Error

add a footer callback for help operations
  • Loading branch information
phlptp authored and henryiii committed Aug 18, 2019
1 parent 127f538 commit 06ab2d0
Show file tree
Hide file tree
Showing 12 changed files with 146 additions and 107 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,7 @@ There are several options that are supported on the main app and subcommands and
- `.positionals_at_end()`: 🆕 Specify that positional arguments occur as the last arguments and throw an error if an unexpected positional is encountered.
- `.prefix_command()`: Like `allow_extras`, but stop immediately on the first unrecognized item. It is ideal for allowing your app or subcommand to be a "prefix" to calling another app.
- `.footer(message)`: Set text to appear at the bottom of the help string.
- `.footer(std::string())`: 🚧 Set a callback to generate a string that will appear at the end of the help string.
- `.set_help_flag(name, message)`: Set the help flag name and message, returns a pointer to the created option.
- `.set_help_all_flag(name, message)`: Set the help all flag name and message, returns a pointer to the created option. Expands subcommands.
- `.failure_message(func)`: Set the failure message function. Two provided: `CLI::FailureMessage::help` and `CLI::FailureMessage::simple` (the default).
Expand Down
49 changes: 27 additions & 22 deletions include/CLI/App.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@ class App {
/// Footer to put after all options in the help output INHERITABLE
std::string footer_;

/// This is a function that generates a footer to put after all other options in help output
std::function<std::string()> footer_callback_;

/// A pointer to the help flag if there is one INHERITABLE
Option *help_ptr_{nullptr};

Expand Down Expand Up @@ -461,9 +464,8 @@ class App {
option->capture_default_str();

return option.get();

} else
throw OptionAlreadyAdded(myopt.get_name());
}
throw OptionAlreadyAdded(myopt.get_name());
}

/// Add option for non-vectors (duplicate copy needed without defaulted to avoid `iostream << value`)
Expand Down Expand Up @@ -950,6 +952,7 @@ class App {
remove_option(config_ptr_);
config_name_ = "";
config_required_ = false; // Not really needed, but complete
config_ptr_ = nullptr; // need to remove the config_ptr completely
}

// Only add config if option passed
Expand Down Expand Up @@ -1423,25 +1426,23 @@ class App {
/// Removes an option from the excludes list of this subcommand
bool remove_excludes(Option *opt) {
auto iterator = std::find(std::begin(exclude_options_), std::end(exclude_options_), opt);
if(iterator != std::end(exclude_options_)) {
exclude_options_.erase(iterator);
return true;
} else {
if(iterator == std::end(exclude_options_)) {
return false;
}
exclude_options_.erase(iterator);
return true;
}

/// Removes a subcommand from this excludes list of this subcommand
bool remove_excludes(App *app) {
auto iterator = std::find(std::begin(exclude_subcommands_), std::end(exclude_subcommands_), app);
if(iterator != std::end(exclude_subcommands_)) {
auto other_app = *iterator;
exclude_subcommands_.erase(iterator);
other_app->remove_excludes(this);
return true;
} else {
if(iterator == std::end(exclude_subcommands_)) {
return false;
}
auto other_app = *iterator;
exclude_subcommands_.erase(iterator);
other_app->remove_excludes(this);
return true;
}

///@}
Expand All @@ -1453,7 +1454,11 @@ class App {
footer_ = std::move(footer_string);
return this;
}

/// Set footer.
App *footer(std::function<std::string()> footer_function) {
footer_callback_ = std::move(footer_function);
return this;
}
/// Produce a string that could be read in as a config of the current values of the App. Set default_also to
/// include default arguments. Prefix will add a string to the beginning of each option.
std::string config_to_str(bool default_also = false, bool write_description = false) const {
Expand All @@ -1470,10 +1475,10 @@ class App {

// Delegate to subcommand if needed
auto selected_subcommands = get_subcommands();
if(!selected_subcommands.empty())
if(!selected_subcommands.empty()) {
return selected_subcommands.at(0)->help(prev, mode);
else
return formatter_->make_help(this, prev, mode);
}
return formatter_->make_help(this, prev, mode);
}

///@}
Expand Down Expand Up @@ -1592,8 +1597,8 @@ class App {
/// Get the group of this subcommand
const std::string &get_group() const { return group_; }

/// Get footer.
const std::string &get_footer() const { return footer_; }
/// Generate and return the footer.
std::string get_footer() const { return (footer_callback_) ? footer_callback_() + '\n' + footer_ : footer_; }

/// Get the required min subcommand value
size_t get_require_subcommand_min() const { return require_subcommand_min_; }
Expand Down Expand Up @@ -2090,7 +2095,7 @@ class App {
if(!(allow_extras_ || prefix_command_)) {
size_t num_left_over = remaining_size();
if(num_left_over > 0) {
throw ExtrasError(remaining(false));
throw ExtrasError(name_, remaining(false));
}
}

Expand All @@ -2107,7 +2112,7 @@ class App {
size_t num_left_over = remaining_size();
if(num_left_over > 0) {
args = remaining(false);
throw ExtrasError(args);
throw ExtrasError(name_, args);
}
}

Expand Down Expand Up @@ -2372,7 +2377,7 @@ class App {
}

if(positionals_at_end_) {
throw CLI::ExtrasError(args);
throw CLI::ExtrasError(name_, args);
}
/// If this is an option group don't deal with it
if(parent_ != nullptr && name_.empty()) {
Expand Down
3 changes: 2 additions & 1 deletion include/CLI/ConfigFwd.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ class Config {
/// This converter works with INI files
class ConfigINI : public Config {
public:
std::string to_config(const App *, bool default_also, bool write_description, std::string prefix) const override;
std::string
to_config(const App * /*app*/, bool default_also, bool write_description, std::string prefix) const override;

std::vector<ConfigItem> from_config(std::istream &input) const override {
std::string line;
Expand Down
30 changes: 18 additions & 12 deletions include/CLI/Error.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,32 +206,32 @@ class RequiredError : public ParseError {
CLI11_ERROR_DEF(ParseError, RequiredError)
explicit RequiredError(std::string name) : RequiredError(name + " is required", ExitCodes::RequiredError) {}
static RequiredError Subcommand(size_t min_subcom) {
if(min_subcom == 1)
if(min_subcom == 1) {
return RequiredError("A subcommand");
else
return RequiredError("Requires at least " + std::to_string(min_subcom) + " subcommands",
ExitCodes::RequiredError);
}
return RequiredError("Requires at least " + std::to_string(min_subcom) + " subcommands",
ExitCodes::RequiredError);
}
static RequiredError Option(size_t min_option, size_t max_option, size_t used, const std::string &option_list) {
if((min_option == 1) && (max_option == 1) && (used == 0))
return RequiredError("Exactly 1 option from [" + option_list + "]");
else if((min_option == 1) && (max_option == 1) && (used > 1))
if((min_option == 1) && (max_option == 1) && (used > 1))
return RequiredError("Exactly 1 option from [" + option_list + "] is required and " + std::to_string(used) +
" were given",
ExitCodes::RequiredError);
else if((min_option == 1) && (used == 0))
if((min_option == 1) && (used == 0))
return RequiredError("At least 1 option from [" + option_list + "]");
else if(used < min_option)
if(used < min_option)
return RequiredError("Requires at least " + std::to_string(min_option) + " options used and only " +
std::to_string(used) + "were given from [" + option_list + "]",
ExitCodes::RequiredError);
else if(max_option == 1)
if(max_option == 1)
return RequiredError("Requires at most 1 options be given from [" + option_list + "]",
ExitCodes::RequiredError);
else
return RequiredError("Requires at most " + std::to_string(max_option) + " options be used and " +
std::to_string(used) + "were given from [" + option_list + "]",
ExitCodes::RequiredError);

return RequiredError("Requires at most " + std::to_string(max_option) + " options be used and " +
std::to_string(used) + "were given from [" + option_list + "]",
ExitCodes::RequiredError);
}
};

Expand Down Expand Up @@ -279,6 +279,12 @@ class ExtrasError : public ParseError {
: "The following argument was not expected: ") +
detail::rjoin(args, " "),
ExitCodes::ExtrasError) {}
ExtrasError(const std::string &name, std::vector<std::string> args)
: ExtrasError(name,
(args.size() > 1 ? "The following arguments were not expected: "
: "The following argument was not expected: ") +
detail::rjoin(args, " "),
ExitCodes::ExtrasError) {}
};

/// Thrown when extra values are found in an INI file
Expand Down
18 changes: 9 additions & 9 deletions include/CLI/Formatter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ inline std::string Formatter::make_positionals(const App *app) const {

if(opts.empty())
return std::string();
else
return make_group(get_label("Positionals"), true, opts);

return make_group(get_label("Positionals"), true, opts);
}

inline std::string Formatter::make_groups(const App *app, AppFormatMode mode) const {
Expand Down Expand Up @@ -126,10 +126,10 @@ inline std::string Formatter::make_usage(const App *app, std::string name) const

inline std::string Formatter::make_footer(const App *app) const {
std::string footer = app->get_footer();
if(!footer.empty())
return footer + "\n";
else
return "";
if(footer.empty()) {
return std::string{};
}
return footer + "\n";
}

inline std::string Formatter::make_help(const App *app, std::string name, AppFormatMode mode) const {
Expand All @@ -151,7 +151,7 @@ inline std::string Formatter::make_help(const App *app, std::string name, AppFor
out << make_positionals(app);
out << make_groups(app, mode);
out << make_subcommands(app, mode);
out << make_footer(app);
out << '\n' << make_footer(app);

return out.str();
}
Expand Down Expand Up @@ -222,8 +222,8 @@ inline std::string Formatter::make_expanded(const App *sub) const {
inline std::string Formatter::make_option_name(const Option *opt, bool is_positional) const {
if(is_positional)
return opt->get_name(true, false);
else
return opt->get_name(false, true);

return opt->get_name(false, true);
}

inline std::string Formatter::make_option_opts(const Option *opt) const {
Expand Down
2 changes: 1 addition & 1 deletion include/CLI/FormatterFwd.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ class Formatter : public FormatterBase {
virtual std::string make_usage(const App *app, std::string name) const;

/// This puts everything together
std::string make_help(const App *, std::string, AppFormatMode) const override;
std::string make_help(const App * /*app*/, std::string, AppFormatMode) const override;

///@}
/// @name Options
Expand Down
Loading

0 comments on commit 06ab2d0

Please sign in to comment.