rbd: ensure the help printer doesn't print past the end of the line

When long command names and long optional names are combined,
it's possible for the help text to be printed beyond the 80
character limit.

Signed-off-by: Jason Dillaman <dillaman@redhat.com>
This commit is contained in:
Jason Dillaman 2020-10-21 15:15:09 -04:00
parent 9edc30366b
commit 51478deab2
2 changed files with 45 additions and 20 deletions

View File

@ -727,7 +727,7 @@
rbd help feature disable
usage: rbd feature disable [--pool <pool>] [--namespace <namespace>]
[--image <image>]
<image-spec> <features> [<features> ...]
<image-spec> <features> [<features> ...]
Disable the specified image feature.
@ -748,7 +748,7 @@
[--journal-splay-width <journal-splay-width>]
[--journal-object-size <journal-object-size>]
[--journal-pool <journal-pool>]
<image-spec> <features> [<features> ...]
<image-spec> <features> [<features> ...]
Enable the specified image feature.

View File

@ -19,38 +19,63 @@ OptionPrinter::OptionPrinter(const OptionsDescription &positional,
}
void OptionPrinter::print_short(std::ostream &os, size_t initial_offset) {
size_t name_width = std::min(initial_offset, MAX_DESCRIPTION_OFFSET) + 1;
IndentStream indent_stream(name_width, initial_offset, LINE_WIDTH, os);
indent_stream.set_delimiter("[");
size_t max_option_width = 0;
std::vector<std::string> optionals;
for (size_t i = 0; i < m_optional.options().size(); ++i) {
std::stringstream option;
bool required = m_optional.options()[i]->semantic()->is_required();
if (!required) {
indent_stream << "[";
option << "[";
}
indent_stream << "--" << m_optional.options()[i]->long_name();
option << "--" << m_optional.options()[i]->long_name();
if (m_optional.options()[i]->semantic()->max_tokens() != 0) {
indent_stream << " <" << m_optional.options()[i]->long_name() << ">";
option << " <" << m_optional.options()[i]->long_name() << ">";
}
if (!required) {
indent_stream << "]";
option << "]";
}
indent_stream << " ";
max_option_width = std::max(max_option_width, option.str().size());
optionals.emplace_back(option.str());
}
if (m_optional.options().size() > 0 || m_positional.options().size() == 0) {
std::vector<std::string> positionals;
for (size_t i = 0; i < m_positional.options().size(); ++i) {
std::stringstream option;
option << "<" << m_positional.options()[i]->long_name() << ">";
if (m_positional.options()[i]->semantic()->max_tokens() > 1) {
option << " [<" << m_positional.options()[i]->long_name() << "> ...]";
}
max_option_width = std::max(max_option_width, option.str().size());
positionals.emplace_back(option.str());
if (m_positional.options()[i]->semantic()->max_tokens() > 1) {
break;
}
}
size_t indent = std::min(initial_offset, MAX_DESCRIPTION_OFFSET) + 1;
if (indent + max_option_width + 2 > LINE_WIDTH) {
// decrease the indent so that we don't wrap past the end of the line
indent = LINE_WIDTH - max_option_width - 2;
}
IndentStream indent_stream(indent, initial_offset, LINE_WIDTH, os);
indent_stream.set_delimiter("[");
for (auto& option : optionals) {
indent_stream << option << " ";
}
if (optionals.size() > 0 || positionals.size() == 0) {
indent_stream << std::endl;
}
if (m_positional.options().size() > 0) {
if (positionals.size() > 0) {
indent_stream.set_delimiter(" ");
for (size_t i = 0; i < m_positional.options().size(); ++i) {
indent_stream << "<" << m_positional.options()[i]->long_name() << "> ";
if (m_positional.options()[i]->semantic()->max_tokens() > 1) {
indent_stream << "[<" << m_positional.options()[i]->long_name()
<< "> ...]";
break;
}
for (auto& option : positionals) {
indent_stream << option << " ";
}
indent_stream << std::endl;
}