Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2024-09-28 07:02:17

0001 // Copyright (c) 2017-2020, University of Cincinnati, developed by Henry Schreiner
0002 // under NSF AWARD 1414736 and by the respective contributors.
0003 // All rights reserved.
0004 //
0005 // SPDX-License-Identifier: BSD-3-Clause
0006 
0007 #pragma once
0008 
0009 // [CLI11:public_includes:set]
0010 #include <algorithm>
0011 #include <string>
0012 #include <vector>
0013 // [CLI11:public_includes:end]
0014 
0015 #include "App.hpp"
0016 #include "FormatterFwd.hpp"
0017 
0018 namespace CLI {
0019 // [CLI11:formatter_hpp:verbatim]
0020 
0021 inline std::string
0022 Formatter::make_group(std::string group, bool is_positional, std::vector<const Option *> opts) const {
0023     std::stringstream out;
0024 
0025     out << "\n" << group << ":\n";
0026     for(const Option *opt : opts) {
0027         out << make_option(opt, is_positional);
0028     }
0029 
0030     return out.str();
0031 }
0032 
0033 inline std::string Formatter::make_positionals(const App *app) const {
0034     std::vector<const Option *> opts =
0035         app->get_options([](const Option *opt) { return !opt->get_group().empty() && opt->get_positional(); });
0036 
0037     if(opts.empty())
0038         return std::string();
0039 
0040     return make_group(get_label("Positionals"), true, opts);
0041 }
0042 
0043 inline std::string Formatter::make_groups(const App *app, AppFormatMode mode) const {
0044     std::stringstream out;
0045     std::vector<std::string> groups = app->get_groups();
0046 
0047     // Options
0048     for(const std::string &group : groups) {
0049         std::vector<const Option *> opts = app->get_options([app, mode, &group](const Option *opt) {
0050             return opt->get_group() == group                     // Must be in the right group
0051                    && opt->nonpositional()                       // Must not be a positional
0052                    && (mode != AppFormatMode::Sub                // If mode is Sub, then
0053                        || (app->get_help_ptr() != opt            // Ignore help pointer
0054                            && app->get_help_all_ptr() != opt));  // Ignore help all pointer
0055         });
0056         if(!group.empty() && !opts.empty()) {
0057             out << make_group(group, false, opts);
0058 
0059             if(group != groups.back())
0060                 out << "\n";
0061         }
0062     }
0063 
0064     return out.str();
0065 }
0066 
0067 inline std::string Formatter::make_description(const App *app) const {
0068     std::string desc = app->get_description();
0069     auto min_options = app->get_require_option_min();
0070     auto max_options = app->get_require_option_max();
0071     if(app->get_required()) {
0072         desc += " REQUIRED ";
0073     }
0074     if((max_options == min_options) && (min_options > 0)) {
0075         if(min_options == 1) {
0076             desc += " \n[Exactly 1 of the following options is required]";
0077         } else {
0078             desc += " \n[Exactly " + std::to_string(min_options) + "options from the following list are required]";
0079         }
0080     } else if(max_options > 0) {
0081         if(min_options > 0) {
0082             desc += " \n[Between " + std::to_string(min_options) + " and " + std::to_string(max_options) +
0083                     " of the follow options are required]";
0084         } else {
0085             desc += " \n[At most " + std::to_string(max_options) + " of the following options are allowed]";
0086         }
0087     } else if(min_options > 0) {
0088         desc += " \n[At least " + std::to_string(min_options) + " of the following options are required]";
0089     }
0090     return (!desc.empty()) ? desc + "\n" : std::string{};
0091 }
0092 
0093 inline std::string Formatter::make_usage(const App *app, std::string name) const {
0094     std::stringstream out;
0095 
0096     out << get_label("Usage") << ":" << (name.empty() ? "" : " ") << name;
0097 
0098     std::vector<std::string> groups = app->get_groups();
0099 
0100     // Print an Options badge if any options exist
0101     std::vector<const Option *> non_pos_options =
0102         app->get_options([](const Option *opt) { return opt->nonpositional(); });
0103     if(!non_pos_options.empty())
0104         out << " [" << get_label("OPTIONS") << "]";
0105 
0106     // Positionals need to be listed here
0107     std::vector<const Option *> positionals = app->get_options([](const Option *opt) { return opt->get_positional(); });
0108 
0109     // Print out positionals if any are left
0110     if(!positionals.empty()) {
0111         // Convert to help names
0112         std::vector<std::string> positional_names(positionals.size());
0113         std::transform(positionals.begin(), positionals.end(), positional_names.begin(), [this](const Option *opt) {
0114             return make_option_usage(opt);
0115         });
0116 
0117         out << " " << detail::join(positional_names, " ");
0118     }
0119 
0120     // Add a marker if subcommands are expected or optional
0121     if(!app->get_subcommands(
0122                [](const CLI::App *subc) { return ((!subc->get_disabled()) && (!subc->get_name().empty())); })
0123             .empty()) {
0124         out << " " << (app->get_require_subcommand_min() == 0 ? "[" : "")
0125             << get_label(app->get_require_subcommand_max() < 2 || app->get_require_subcommand_min() > 1 ? "SUBCOMMAND"
0126                                                                                                         : "SUBCOMMANDS")
0127             << (app->get_require_subcommand_min() == 0 ? "]" : "");
0128     }
0129 
0130     out << std::endl;
0131 
0132     return out.str();
0133 }
0134 
0135 inline std::string Formatter::make_footer(const App *app) const {
0136     std::string footer = app->get_footer();
0137     if(footer.empty()) {
0138         return std::string{};
0139     }
0140     return footer + "\n";
0141 }
0142 
0143 inline std::string Formatter::make_help(const App *app, std::string name, AppFormatMode mode) const {
0144 
0145     // This immediately forwards to the make_expanded method. This is done this way so that subcommands can
0146     // have overridden formatters
0147     if(mode == AppFormatMode::Sub)
0148         return make_expanded(app);
0149 
0150     std::stringstream out;
0151     if((app->get_name().empty()) && (app->get_parent() != nullptr)) {
0152         if(app->get_group() != "Subcommands") {
0153             out << app->get_group() << ':';
0154         }
0155     }
0156 
0157     out << make_description(app);
0158     out << make_usage(app, name);
0159     out << make_positionals(app);
0160     out << make_groups(app, mode);
0161     out << make_subcommands(app, mode);
0162     out << '\n' << make_footer(app);
0163 
0164     return out.str();
0165 }
0166 
0167 inline std::string Formatter::make_subcommands(const App *app, AppFormatMode mode) const {
0168     std::stringstream out;
0169 
0170     std::vector<const App *> subcommands = app->get_subcommands({});
0171 
0172     // Make a list in definition order of the groups seen
0173     std::vector<std::string> subcmd_groups_seen;
0174     for(const App *com : subcommands) {
0175         if(com->get_name().empty()) {
0176             if(!com->get_group().empty()) {
0177                 out << make_expanded(com);
0178             }
0179             continue;
0180         }
0181         std::string group_key = com->get_group();
0182         if(!group_key.empty() &&
0183            std::find_if(subcmd_groups_seen.begin(), subcmd_groups_seen.end(), [&group_key](std::string a) {
0184                return detail::to_lower(a) == detail::to_lower(group_key);
0185            }) == subcmd_groups_seen.end())
0186             subcmd_groups_seen.push_back(group_key);
0187     }
0188 
0189     // For each group, filter out and print subcommands
0190     for(const std::string &group : subcmd_groups_seen) {
0191         out << "\n" << group << ":\n";
0192         std::vector<const App *> subcommands_group = app->get_subcommands(
0193             [&group](const App *sub_app) { return detail::to_lower(sub_app->get_group()) == detail::to_lower(group); });
0194         for(const App *new_com : subcommands_group) {
0195             if(new_com->get_name().empty())
0196                 continue;
0197             if(mode != AppFormatMode::All) {
0198                 out << make_subcommand(new_com);
0199             } else {
0200                 out << new_com->help(new_com->get_name(), AppFormatMode::Sub);
0201                 out << "\n";
0202             }
0203         }
0204     }
0205 
0206     return out.str();
0207 }
0208 
0209 inline std::string Formatter::make_subcommand(const App *sub) const {
0210     std::stringstream out;
0211     detail::format_help(out, sub->get_display_name(true), sub->get_description(), column_width_);
0212     return out.str();
0213 }
0214 
0215 inline std::string Formatter::make_expanded(const App *sub) const {
0216     std::stringstream out;
0217     out << sub->get_display_name(true) << "\n";
0218 
0219     out << make_description(sub);
0220     if(sub->get_name().empty() && !sub->get_aliases().empty()) {
0221         detail::format_aliases(out, sub->get_aliases(), column_width_ + 2);
0222     }
0223     out << make_positionals(sub);
0224     out << make_groups(sub, AppFormatMode::Sub);
0225     out << make_subcommands(sub, AppFormatMode::Sub);
0226 
0227     // Drop blank spaces
0228     std::string tmp = detail::find_and_replace(out.str(), "\n\n", "\n");
0229     tmp = tmp.substr(0, tmp.size() - 1);  // Remove the final '\n'
0230 
0231     // Indent all but the first line (the name)
0232     return detail::find_and_replace(tmp, "\n", "\n  ") + "\n";
0233 }
0234 
0235 inline std::string Formatter::make_option_name(const Option *opt, bool is_positional) const {
0236     if(is_positional)
0237         return opt->get_name(true, false);
0238 
0239     return opt->get_name(false, true);
0240 }
0241 
0242 inline std::string Formatter::make_option_opts(const Option *opt) const {
0243     std::stringstream out;
0244 
0245     if(!opt->get_option_text().empty()) {
0246         out << " " << opt->get_option_text();
0247     } else {
0248         if(opt->get_type_size() != 0) {
0249             if(!opt->get_type_name().empty())
0250                 out << " " << get_label(opt->get_type_name());
0251             if(!opt->get_default_str().empty())
0252                 out << "=" << opt->get_default_str();
0253             if(opt->get_expected_max() == detail::expected_max_vector_size)
0254                 out << " ...";
0255             else if(opt->get_expected_min() > 1)
0256                 out << " x " << opt->get_expected();
0257 
0258             if(opt->get_required())
0259                 out << " " << get_label("REQUIRED");
0260         }
0261         if(!opt->get_envname().empty())
0262             out << " (" << get_label("Env") << ":" << opt->get_envname() << ")";
0263         if(!opt->get_needs().empty()) {
0264             out << " " << get_label("Needs") << ":";
0265             for(const Option *op : opt->get_needs())
0266                 out << " " << op->get_name();
0267         }
0268         if(!opt->get_excludes().empty()) {
0269             out << " " << get_label("Excludes") << ":";
0270             for(const Option *op : opt->get_excludes())
0271                 out << " " << op->get_name();
0272         }
0273     }
0274     return out.str();
0275 }
0276 
0277 inline std::string Formatter::make_option_desc(const Option *opt) const { return opt->get_description(); }
0278 
0279 inline std::string Formatter::make_option_usage(const Option *opt) const {
0280     // Note that these are positionals usages
0281     std::stringstream out;
0282     out << make_option_name(opt, true);
0283     if(opt->get_expected_max() >= detail::expected_max_vector_size)
0284         out << "...";
0285     else if(opt->get_expected_max() > 1)
0286         out << "(" << opt->get_expected() << "x)";
0287 
0288     return opt->get_required() ? out.str() : "[" + out.str() + "]";
0289 }
0290 
0291 // [CLI11:formatter_hpp:end]
0292 }  // namespace CLI