]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
rbd: ensure the help printer doesn't print past the end of the line
authorJason Dillaman <dillaman@redhat.com>
Wed, 21 Oct 2020 19:15:09 +0000 (15:15 -0400)
committerIlya Dryomov <idryomov@gmail.com>
Sun, 13 Feb 2022 17:05:59 +0000 (18:05 +0100)
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>
(cherry picked from commit 51478deab22178d01db7fa8632ba72071b4dfc38)

src/test/cli/rbd/help.t
src/tools/rbd/OptionPrinter.cc

index e6f1ee869d1528d3f963f0fa5619f3423dfa5f99..5d0738b24754644e334c5b67bd192b865e1e755a 100644 (file)
   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.
   
                             [--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.
   
index 14affb0b3bb85192e9f3d0ac8bbaebb55ee02b24..40969b3c3bdd427eb79dae0cfdf8990ef1f2d3fd 100644 (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;
   }