1
0
mirror of https://github.com/CLIUtils/CLI11.git synced 2025-04-29 12:13:52 +00:00

Adding access to current formatter, using shared pointer to link all formatters

This commit is contained in:
Henry Fredrick Schreiner 2018-05-07 14:04:13 +02:00 committed by Henry Schreiner
parent aac957507d
commit 0d9a33d4ca
5 changed files with 123 additions and 20 deletions

View File

@ -2,6 +2,7 @@
class MyFormatter : public CLI::Formatter {
public:
using Formatter::Formatter;
std::string make_option_opts(const CLI::Option *) const override { return " OPTION"; }
};
@ -9,8 +10,8 @@ int main(int argc, char **argv) {
CLI::App app;
app.set_help_all_flag("--help-all", "Show all help");
MyFormatter fmt;
fmt.column_width(15);
auto fmt = std::make_shared<MyFormatter>();
fmt->column_width(15);
app.formatter(fmt);
app.add_flag("--flag", "This is a flag");

View File

@ -106,8 +106,8 @@ class App {
/// A pointer to the help all flag if there is one INHERITABLE
Option *help_all_ptr_{nullptr};
/// This is the formatter for help printing. Default provided. INHERITABLE
std::function<std::string(const App *, std::string, AppFormatMode)> formatter_{Formatter()};
/// This is the formatter for help printing. Default provided. INHERITABLE (same pointer)
std::shared_ptr<FormatterBase> formatter_{new Formatter()};
/// The error message printing function INHERITABLE
std::function<std::string(const App *, const Error &e)> failure_message_ = FailureMessage::simple;
@ -262,11 +262,17 @@ class App {
}
/// Set the help formatter
App *formatter(std::function<std::string(const App *, std::string, AppFormatMode)> fmt) {
App *formatter(std::shared_ptr<FormatterBase> fmt) {
formatter_ = fmt;
return this;
}
/// Set the help formatter
App *formatter(std::function<std::string(const App *, std::string, AppFormatMode)> fmt) {
formatter_ = std::make_shared<FormatterLambda>(fmt);
return this;
}
/// Check to see if this subcommand was parsed, true only if received on command line.
bool parsed() const { return parsed_; }
@ -1071,13 +1077,16 @@ class App {
if(!selected_subcommands.empty())
return selected_subcommands.at(0)->help(prev);
else
return formatter_(this, prev, mode);
return formatter_->make_help(this, prev, mode);
}
///@}
/// @name Getters
///@{
/// Access the formatter
std::shared_ptr<FormatterBase> get_formatter() const { return formatter_; }
/// Get the app or subcommand description
std::string get_description() const { return description_; }

View File

@ -113,7 +113,7 @@ inline std::string Formatter::make_footer(const App *app) const {
return "";
}
inline std::string Formatter::operator()(const App *app, std::string name, AppFormatMode mode) const {
inline std::string Formatter::make_help(const App *app, std::string name, AppFormatMode mode) const {
// This immediatly forwards to the make_expanded method. This is done this way so that subcommands can
// have overridden formatters

View File

@ -21,10 +21,15 @@ class App;
enum class AppFormatMode {
Normal, //< The normal, detailed help
All, //< A fully expanded help
Sub, //< Used when printed as part of expanded subcommand
Sub, //< Used when printed as part of expanded subcommand
};
class Formatter {
/// This is the minimum requirements to run a formatter.
///
/// A user can subclass this is if they do not care at all
/// about the structure in CLI::Formatter.
class FormatterBase {
protected:
/// @name Options
///@{
@ -40,9 +45,14 @@ class Formatter {
///@{
public:
Formatter() = default;
Formatter(const Formatter &) = default;
Formatter(Formatter &&) = default;
FormatterBase() = default;
FormatterBase(const FormatterBase &) = default;
FormatterBase(FormatterBase &&) = default;
virtual ~FormatterBase() = default;
/// This is the key method that puts together help
virtual std::string make_help(const App *, std::string, AppFormatMode) const = 0;
///@}
/// @name Setters
///@{
@ -68,6 +78,30 @@ class Formatter {
/// Get the current column width
size_t get_column_width() const { return column_width_; }
///@}
};
/// This is a specialty override for lambda functions
class FormatterLambda final : public FormatterBase {
using funct_t = std::function<std::string(const App *, std::string, AppFormatMode)>;
funct_t lambda_;
public:
explicit FormatterLambda(funct_t funct) : lambda_(funct) {}
/// This will simply call the lambda function
std::string make_help(const App *app, std::string name, AppFormatMode mode) const override {
return lambda_(app, name, mode);
}
};
class Formatter : public FormatterBase {
public:
Formatter() = default;
Formatter(const Formatter &) = default;
Formatter(Formatter &&) = default;
/// @name Overridables
///@{
@ -102,7 +136,7 @@ class Formatter {
virtual std::string make_usage(const App *app, std::string name) const;
/// This puts everything together
virtual std::string operator()(const App *, std::string, AppFormatMode) const;
std::string make_help(const App *, std::string, AppFormatMode) const override;
///@}
/// @name Options

View File

@ -11,9 +11,28 @@
using ::testing::HasSubstr;
using ::testing::Not;
class SimpleFormatter : public CLI::FormatterBase {
public:
SimpleFormatter() : FormatterBase() {}
std::string make_help(const CLI::App *, std::string, CLI::AppFormatMode) const override {
return "This is really simple";
}
};
TEST(Formatter, Nothing) {
CLI::App app{"My prog"};
app.formatter(std::make_shared<SimpleFormatter>());
std::string help = app.help();
EXPECT_EQ(help, "This is really simple");
}
TEST(Formatter, NothingLambda) {
CLI::App app{"My prog"};
app.formatter(
[](const CLI::App *, std::string, CLI::AppFormatMode) { return std::string("This is really simple"); });
@ -25,9 +44,9 @@ TEST(Formatter, Nothing) {
TEST(Formatter, OptCustomize) {
CLI::App app{"My prog"};
CLI::Formatter optfmt;
optfmt.column_width(25);
optfmt.label("REQUIRED", "(MUST HAVE)");
auto optfmt = std::make_shared<CLI::Formatter>();
optfmt->column_width(25);
optfmt->label("REQUIRED", "(MUST HAVE)");
app.formatter(optfmt);
int v;
@ -44,13 +63,33 @@ TEST(Formatter, OptCustomize) {
" --opt INT (MUST HAVE) Something\n");
}
TEST(Formatter, AptCustomize) {
TEST(Formatter, OptCustomizeSimple) {
CLI::App app{"My prog"};
app.get_formatter()->column_width(25);
app.get_formatter()->label("REQUIRED", "(MUST HAVE)");
int v;
app.add_option("--opt", v, "Something")->required();
std::string help = app.help();
EXPECT_THAT(help, HasSubstr("(MUST HAVE)"));
EXPECT_EQ(help,
"My prog\n"
"Usage: [OPTIONS]\n\n"
"Options:\n"
" -h,--help Print this help message and exit\n"
" --opt INT (MUST HAVE) Something\n");
}
TEST(Formatter, AppCustomize) {
CLI::App app{"My prog"};
app.add_subcommand("subcom1", "This");
CLI::Formatter appfmt;
appfmt.column_width(20);
appfmt.label("Usage", "Run");
auto appfmt = std::make_shared<CLI::Formatter>();
appfmt->column_width(20);
appfmt->label("Usage", "Run");
app.formatter(appfmt);
app.add_subcommand("subcom2", "This");
@ -66,6 +105,26 @@ TEST(Formatter, AptCustomize) {
" subcom2 This\n");
}
TEST(Formatter, AppCustomizeSimple) {
CLI::App app{"My prog"};
app.add_subcommand("subcom1", "This");
app.get_formatter()->column_width(20);
app.get_formatter()->label("Usage", "Run");
app.add_subcommand("subcom2", "This");
std::string help = app.help();
EXPECT_EQ(help,
"My prog\n"
"Run: [OPTIONS] [SUBCOMMAND]\n\n"
"Options:\n"
" -h,--help Print this help message and exit\n\n"
"Subcommands:\n"
" subcom1 This\n"
" subcom2 This\n");
}
TEST(Formatter, AllSub) {
CLI::App app{"My prog"};
CLI::App *sub = app.add_subcommand("subcom", "This");