From: Jason Dillaman Date: Wed, 21 Oct 2020 19:15:09 +0000 (-0400) Subject: rbd: ensure the help printer doesn't print past the end of the line X-Git-Tag: v15.2.17~121^2~1 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=6a80eb5cf7f76e2adabe2d41ab3237c4003791d0;p=ceph.git 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 (cherry picked from commit 51478deab22178d01db7fa8632ba72071b4dfc38) --- diff --git a/src/test/cli/rbd/help.t b/src/test/cli/rbd/help.t index e6f1ee869d1..5d0738b2475 100644 --- a/src/test/cli/rbd/help.t +++ b/src/test/cli/rbd/help.t @@ -732,7 +732,7 @@ rbd help feature disable usage: rbd feature disable [--pool ] [--namespace ] [--image ] - [ ...] + [ ...] Disable the specified image feature. @@ -753,7 +753,7 @@ [--journal-splay-width ] [--journal-object-size ] [--journal-pool ] - [ ...] + [ ...] Enable the specified image feature. diff --git a/src/tools/rbd/OptionPrinter.cc b/src/tools/rbd/OptionPrinter.cc index 14affb0b3bb..40969b3c3bd 100644 --- a/src/tools/rbd/OptionPrinter.cc +++ b/src/tools/rbd/OptionPrinter.cc @@ -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 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 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; }