summaryrefslogtreecommitdiff
path: root/absl/flags/internal/usage.cc
diff options
context:
space:
mode:
Diffstat (limited to 'absl/flags/internal/usage.cc')
-rw-r--r--absl/flags/internal/usage.cc273
1 files changed, 200 insertions, 73 deletions
diff --git a/absl/flags/internal/usage.cc b/absl/flags/internal/usage.cc
index 0805df31..a588c7f7 100644
--- a/absl/flags/internal/usage.cc
+++ b/absl/flags/internal/usage.cc
@@ -37,26 +37,26 @@
#include "absl/strings/str_split.h"
#include "absl/strings/string_view.h"
-ABSL_FLAG(bool, help, false,
- "show help on important flags for this binary [tip: all flags can "
- "have two dashes]");
-ABSL_FLAG(bool, helpfull, false, "show help on all flags");
-ABSL_FLAG(bool, helpshort, false,
- "show help on only the main module for this program");
-ABSL_FLAG(bool, helppackage, false,
- "show help on all modules in the main package");
-ABSL_FLAG(bool, version, false, "show version and build info and exit");
-ABSL_FLAG(bool, only_check_args, false, "exit after checking all flags");
-ABSL_FLAG(std::string, helpon, "",
- "show help on the modules named by this flag value");
-ABSL_FLAG(std::string, helpmatch, "",
- "show help on modules whose name contains the specified substr");
+// Dummy global variables to prevent anyone else defining these.
+bool FLAGS_help = false;
+bool FLAGS_helpfull = false;
+bool FLAGS_helpshort = false;
+bool FLAGS_helppackage = false;
+bool FLAGS_version = false;
+bool FLAGS_only_check_args = false;
+bool FLAGS_helpon = false;
+bool FLAGS_helpmatch = false;
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace flags_internal {
namespace {
+using PerFlagFilter = std::function<bool(const absl::CommandLineFlag&)>;
+
+// Maximum length size in a human readable format.
+constexpr size_t kHrfMaxLineLength = 80;
+
// This class is used to emit an XML element with `tag` and `text`.
// It adds opening and closing tags and escapes special characters in the text.
// For example:
@@ -109,9 +109,12 @@ class FlagHelpPrettyPrinter {
public:
// Pretty printer holds on to the std::ostream& reference to direct an output
// to that stream.
- FlagHelpPrettyPrinter(int max_line_len, std::ostream& out)
+ FlagHelpPrettyPrinter(size_t max_line_len, size_t min_line_len,
+ size_t wrapped_line_indent, std::ostream& out)
: out_(out),
max_line_len_(max_line_len),
+ min_line_len_(min_line_len),
+ wrapped_line_indent_(wrapped_line_indent),
line_len_(0),
first_line_(true) {}
@@ -145,7 +148,8 @@ class FlagHelpPrettyPrinter {
}
// Write the token, ending the string first if necessary/possible.
- if (!new_line && (line_len_ + token.size() >= max_line_len_)) {
+ if (!new_line &&
+ (line_len_ + static_cast<int>(token.size()) >= max_line_len_)) {
EndLine();
new_line = true;
}
@@ -164,13 +168,12 @@ class FlagHelpPrettyPrinter {
void StartLine() {
if (first_line_) {
- out_ << " ";
- line_len_ = 4;
+ line_len_ = min_line_len_;
first_line_ = false;
} else {
- out_ << " ";
- line_len_ = 6;
+ line_len_ = min_line_len_ + wrapped_line_indent_;
}
+ out_ << std::string(line_len_, ' ');
}
void EndLine() {
out_ << '\n';
@@ -179,13 +182,15 @@ class FlagHelpPrettyPrinter {
private:
std::ostream& out_;
- const int max_line_len_;
- int line_len_;
+ const size_t max_line_len_;
+ const size_t min_line_len_;
+ const size_t wrapped_line_indent_;
+ size_t line_len_;
bool first_line_;
};
void FlagHelpHumanReadable(const CommandLineFlag& flag, std::ostream& out) {
- FlagHelpPrettyPrinter printer(80, out); // Max line length is 80.
+ FlagHelpPrettyPrinter printer(kHrfMaxLineLength, 4, 2, out);
// Flag name.
printer.Write(absl::StrCat("--", flag.Name()));
@@ -221,7 +226,7 @@ void FlagHelpHumanReadable(const CommandLineFlag& flag, std::ostream& out) {
// If a flag's help message has been stripped (e.g. by adding '#define
// STRIP_FLAG_HELP 1' then this flag will not be displayed by '--help'
// and its variants.
-void FlagsHelpImpl(std::ostream& out, flags_internal::FlagKindFilter filter_cb,
+void FlagsHelpImpl(std::ostream& out, PerFlagFilter filter_cb,
HelpFormat format, absl::string_view program_usage_message) {
if (format == HelpFormat::kHumanReadable) {
out << flags_internal::ShortProgramInvocationName() << ": "
@@ -256,10 +261,10 @@ void FlagsHelpImpl(std::ostream& out, flags_internal::FlagKindFilter filter_cb,
// If the flag has been stripped, pretend that it doesn't exist.
if (flag.Help() == flags_internal::kStrippedFlagHelp) return;
- std::string flag_filename = flag.Filename();
-
// Make sure flag satisfies the filter
- if (!filter_cb || !filter_cb(flag_filename)) return;
+ if (!filter_cb(flag)) return;
+
+ std::string flag_filename = flag.Filename();
matching_flags[std::string(flags_internal::Package(flag_filename))]
[flag_filename]
@@ -289,15 +294,34 @@ void FlagsHelpImpl(std::ostream& out, flags_internal::FlagKindFilter filter_cb,
}
if (format == HelpFormat::kHumanReadable) {
+ FlagHelpPrettyPrinter printer(kHrfMaxLineLength, 0, 0, out);
+
if (filter_cb && matching_flags.empty()) {
- out << " No modules matched: use -helpfull\n";
+ printer.Write("No flags matched.\n", true);
}
+ printer.EndLine();
+ printer.Write(
+ "Try --helpfull to get a list of all flags or --help=substring "
+ "shows help for flags which include specified substring in either "
+ "in the name, or description or path.\n",
+ true);
} else {
// The end of the document.
out << "</AllFlags>\n";
}
}
+void FlagsHelpImpl(std::ostream& out,
+ flags_internal::FlagKindFilter filename_filter_cb,
+ HelpFormat format, absl::string_view program_usage_message) {
+ FlagsHelpImpl(
+ out,
+ [&](const absl::CommandLineFlag& flag) {
+ return filename_filter_cb && filename_filter_cb(flag.Filename());
+ },
+ format, program_usage_message);
+}
+
} // namespace
// --------------------------------------------------------------------
@@ -309,7 +333,7 @@ void FlagHelp(std::ostream& out, const CommandLineFlag& flag,
}
// --------------------------------------------------------------------
-// Produces the help messages for all flags matching the filter.
+// Produces the help messages for all flags matching the filename filter.
// If filter is empty produces help messages for all flags.
void FlagsHelp(std::ostream& out, absl::string_view filter, HelpFormat format,
absl::string_view program_usage_message) {
@@ -324,66 +348,169 @@ void FlagsHelp(std::ostream& out, absl::string_view filter, HelpFormat format,
// If so, handles them appropriately.
int HandleUsageFlags(std::ostream& out,
absl::string_view program_usage_message) {
- if (absl::GetFlag(FLAGS_helpshort)) {
- flags_internal::FlagsHelpImpl(
- out, flags_internal::GetUsageConfig().contains_helpshort_flags,
- HelpFormat::kHumanReadable, program_usage_message);
- return 1;
- }
+ switch (GetFlagsHelpMode()) {
+ case HelpMode::kNone:
+ break;
+ case HelpMode::kImportant:
+ flags_internal::FlagsHelpImpl(
+ out, flags_internal::GetUsageConfig().contains_help_flags,
+ GetFlagsHelpFormat(), program_usage_message);
+ return 1;
+
+ case HelpMode::kShort:
+ flags_internal::FlagsHelpImpl(
+ out, flags_internal::GetUsageConfig().contains_helpshort_flags,
+ GetFlagsHelpFormat(), program_usage_message);
+ return 1;
+
+ case HelpMode::kFull:
+ flags_internal::FlagsHelp(out, "", GetFlagsHelpFormat(),
+ program_usage_message);
+ return 1;
+
+ case HelpMode::kPackage:
+ flags_internal::FlagsHelpImpl(
+ out, flags_internal::GetUsageConfig().contains_helppackage_flags,
+ GetFlagsHelpFormat(), program_usage_message);
+
+ return 1;
+
+ case HelpMode::kMatch: {
+ std::string substr = GetFlagsHelpMatchSubstr();
+ if (substr.empty()) {
+ // show all options
+ flags_internal::FlagsHelp(out, substr, GetFlagsHelpFormat(),
+ program_usage_message);
+ } else {
+ auto filter_cb = [&substr](const absl::CommandLineFlag& flag) {
+ if (absl::StrContains(flag.Name(), substr)) return true;
+ if (absl::StrContains(flag.Filename(), substr)) return true;
+ if (absl::StrContains(flag.Help(), substr)) return true;
+
+ return false;
+ };
+ flags_internal::FlagsHelpImpl(
+ out, filter_cb, HelpFormat::kHumanReadable, program_usage_message);
+ }
- if (absl::GetFlag(FLAGS_helpfull)) {
- // show all options
- flags_internal::FlagsHelp(out, "", HelpFormat::kHumanReadable,
- program_usage_message);
- return 1;
+ return 1;
+ }
+ case HelpMode::kVersion:
+ if (flags_internal::GetUsageConfig().version_string)
+ out << flags_internal::GetUsageConfig().version_string();
+ // Unlike help, we may be asking for version in a script, so return 0
+ return 0;
+
+ case HelpMode::kOnlyCheckArgs:
+ return 0;
}
- if (!absl::GetFlag(FLAGS_helpon).empty()) {
- flags_internal::FlagsHelp(
- out, absl::StrCat("/", absl::GetFlag(FLAGS_helpon), "."),
- HelpFormat::kHumanReadable, program_usage_message);
- return 1;
- }
+ return -1;
+}
- if (!absl::GetFlag(FLAGS_helpmatch).empty()) {
- flags_internal::FlagsHelp(out, absl::GetFlag(FLAGS_helpmatch),
- HelpFormat::kHumanReadable,
- program_usage_message);
- return 1;
- }
+// --------------------------------------------------------------------
+// Globals representing usage reporting flags
- if (absl::GetFlag(FLAGS_help)) {
- flags_internal::FlagsHelpImpl(
- out, flags_internal::GetUsageConfig().contains_help_flags,
- HelpFormat::kHumanReadable, program_usage_message);
+namespace {
- out << "\nTry --helpfull to get a list of all flags.\n";
+ABSL_CONST_INIT absl::Mutex help_attributes_guard(absl::kConstInit);
+ABSL_CONST_INIT std::string* match_substr
+ ABSL_GUARDED_BY(help_attributes_guard) = nullptr;
+ABSL_CONST_INIT HelpMode help_mode ABSL_GUARDED_BY(help_attributes_guard) =
+ HelpMode::kNone;
+ABSL_CONST_INIT HelpFormat help_format ABSL_GUARDED_BY(help_attributes_guard) =
+ HelpFormat::kHumanReadable;
- return 1;
- }
+} // namespace
- if (absl::GetFlag(FLAGS_helppackage)) {
- flags_internal::FlagsHelpImpl(
- out, flags_internal::GetUsageConfig().contains_helppackage_flags,
- HelpFormat::kHumanReadable, program_usage_message);
+std::string GetFlagsHelpMatchSubstr() {
+ absl::MutexLock l(&help_attributes_guard);
+ if (match_substr == nullptr) return "";
+ return *match_substr;
+}
- out << "\nTry --helpfull to get a list of all flags.\n";
+void SetFlagsHelpMatchSubstr(absl::string_view substr) {
+ absl::MutexLock l(&help_attributes_guard);
+ if (match_substr == nullptr) match_substr = new std::string;
+ match_substr->assign(substr.data(), substr.size());
+}
- return 1;
+HelpMode GetFlagsHelpMode() {
+ absl::MutexLock l(&help_attributes_guard);
+ return help_mode;
+}
+
+void SetFlagsHelpMode(HelpMode mode) {
+ absl::MutexLock l(&help_attributes_guard);
+ help_mode = mode;
+}
+
+HelpFormat GetFlagsHelpFormat() {
+ absl::MutexLock l(&help_attributes_guard);
+ return help_format;
+}
+
+void SetFlagsHelpFormat(HelpFormat format) {
+ absl::MutexLock l(&help_attributes_guard);
+ help_format = format;
+}
+
+// Deduces usage flags from the input argument in a form --name=value or
+// --name. argument is already split into name and value before we call this
+// function.
+bool DeduceUsageFlags(absl::string_view name, absl::string_view value) {
+ if (absl::ConsumePrefix(&name, "help")) {
+ if (name == "") {
+ if (value.empty()) {
+ SetFlagsHelpMode(HelpMode::kImportant);
+ } else {
+ SetFlagsHelpMode(HelpMode::kMatch);
+ SetFlagsHelpMatchSubstr(value);
+ }
+ return true;
+ }
+
+ if (name == "match") {
+ SetFlagsHelpMode(HelpMode::kMatch);
+ SetFlagsHelpMatchSubstr(value);
+ return true;
+ }
+
+ if (name == "on") {
+ SetFlagsHelpMode(HelpMode::kMatch);
+ SetFlagsHelpMatchSubstr(absl::StrCat("/", value, "."));
+ return true;
+ }
+
+ if (name == "full") {
+ SetFlagsHelpMode(HelpMode::kFull);
+ return true;
+ }
+
+ if (name == "short") {
+ SetFlagsHelpMode(HelpMode::kShort);
+ return true;
+ }
+
+ if (name == "package") {
+ SetFlagsHelpMode(HelpMode::kPackage);
+ return true;
+ }
+
+ return false;
}
- if (absl::GetFlag(FLAGS_version)) {
- if (flags_internal::GetUsageConfig().version_string)
- out << flags_internal::GetUsageConfig().version_string();
- // Unlike help, we may be asking for version in a script, so return 0
- return 0;
+ if (name == "version") {
+ SetFlagsHelpMode(HelpMode::kVersion);
+ return true;
}
- if (absl::GetFlag(FLAGS_only_check_args)) {
- return 0;
+ if (name == "only_check_args") {
+ SetFlagsHelpMode(HelpMode::kOnlyCheckArgs);
+ return true;
}
- return -1;
+ return false;
}
} // namespace flags_internal