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: v16.1.0~702^2~5 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=51478deab22178d01db7fa8632ba72071b4dfc38;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 --- diff --git a/src/test/cli/rbd/help.t b/src/test/cli/rbd/help.t index aeb1620a36ed..7eeb4ab6e4bc 100644 --- a/src/test/cli/rbd/help.t +++ b/src/test/cli/rbd/help.t @@ -727,7 +727,7 @@ rbd help feature disable usage: rbd feature disable [--pool ] [--namespace ] [--image ] - [ ...] + [ ...] Disable the specified image feature. @@ -748,7 +748,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 a1874a769dcf..5a5bf9504989 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; }