]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | ||
4 | #include "tools/rbd/OptionPrinter.h" | |
5 | #include "tools/rbd/IndentStream.h" | |
20effc67 | 6 | #include "include/ceph_assert.h" |
7c673cae FG |
7 | |
8 | namespace rbd { | |
9 | ||
10 | namespace po = boost::program_options; | |
11 | ||
12 | const std::string OptionPrinter::POSITIONAL_ARGUMENTS("Positional arguments"); | |
13 | const std::string OptionPrinter::OPTIONAL_ARGUMENTS("Optional arguments"); | |
14 | ||
15 | const size_t OptionPrinter::MAX_DESCRIPTION_OFFSET; | |
16 | ||
17 | OptionPrinter::OptionPrinter(const OptionsDescription &positional, | |
18 | const OptionsDescription &optional) | |
19 | : m_positional(positional), m_optional(optional) { | |
20 | } | |
21 | ||
22 | void OptionPrinter::print_short(std::ostream &os, size_t initial_offset) { | |
f67539c2 TL |
23 | size_t max_option_width = 0; |
24 | std::vector<std::string> optionals; | |
7c673cae | 25 | for (size_t i = 0; i < m_optional.options().size(); ++i) { |
f67539c2 TL |
26 | std::stringstream option; |
27 | ||
7c673cae FG |
28 | bool required = m_optional.options()[i]->semantic()->is_required(); |
29 | if (!required) { | |
f67539c2 | 30 | option << "["; |
7c673cae | 31 | } |
f67539c2 | 32 | option << "--" << m_optional.options()[i]->long_name(); |
7c673cae | 33 | if (m_optional.options()[i]->semantic()->max_tokens() != 0) { |
f67539c2 | 34 | option << " <" << m_optional.options()[i]->long_name() << ">"; |
7c673cae FG |
35 | } |
36 | if (!required) { | |
f67539c2 TL |
37 | option << "]"; |
38 | } | |
39 | max_option_width = std::max(max_option_width, option.str().size()); | |
40 | optionals.emplace_back(option.str()); | |
41 | } | |
42 | ||
43 | std::vector<std::string> positionals; | |
44 | for (size_t i = 0; i < m_positional.options().size(); ++i) { | |
45 | std::stringstream option; | |
46 | ||
20effc67 TL |
47 | // we overload po::value<std::string>()->default_value("") to signify |
48 | // an optional positional argument (purely for help printing purposes) | |
49 | boost::any v; | |
50 | bool required = !m_positional.options()[i]->semantic()->apply_default(v); | |
51 | if (!required) { | |
52 | auto ptr = boost::any_cast<std::string>(&v); | |
53 | ceph_assert(ptr && ptr->empty()); | |
54 | option << "["; | |
55 | } | |
f67539c2 TL |
56 | option << "<" << m_positional.options()[i]->long_name() << ">"; |
57 | if (m_positional.options()[i]->semantic()->max_tokens() > 1) { | |
58 | option << " [<" << m_positional.options()[i]->long_name() << "> ...]"; | |
7c673cae | 59 | } |
20effc67 TL |
60 | if (!required) { |
61 | option << "]"; | |
62 | } | |
f67539c2 TL |
63 | |
64 | max_option_width = std::max(max_option_width, option.str().size()); | |
65 | positionals.emplace_back(option.str()); | |
66 | ||
67 | if (m_positional.options()[i]->semantic()->max_tokens() > 1) { | |
68 | break; | |
69 | } | |
70 | } | |
71 | ||
72 | size_t indent = std::min(initial_offset, MAX_DESCRIPTION_OFFSET) + 1; | |
73 | if (indent + max_option_width + 2 > LINE_WIDTH) { | |
74 | // decrease the indent so that we don't wrap past the end of the line | |
75 | indent = LINE_WIDTH - max_option_width - 2; | |
76 | } | |
77 | ||
78 | IndentStream indent_stream(indent, initial_offset, LINE_WIDTH, os); | |
79 | indent_stream.set_delimiter("["); | |
80 | for (auto& option : optionals) { | |
81 | indent_stream << option << " "; | |
7c673cae | 82 | } |
11fdf7f2 | 83 | |
f67539c2 | 84 | if (optionals.size() > 0 || positionals.size() == 0) { |
11fdf7f2 TL |
85 | indent_stream << std::endl; |
86 | } | |
7c673cae | 87 | |
f67539c2 | 88 | if (positionals.size() > 0) { |
7c673cae | 89 | indent_stream.set_delimiter(" "); |
f67539c2 TL |
90 | for (auto& option : positionals) { |
91 | indent_stream << option << " "; | |
7c673cae FG |
92 | } |
93 | indent_stream << std::endl; | |
94 | } | |
95 | } | |
96 | ||
f67539c2 TL |
97 | void OptionPrinter::print_optional(const OptionsDescription &global_opts, |
98 | size_t &name_width, std::ostream &os) { | |
99 | std::string indent2(2, ' '); | |
100 | ||
101 | for (size_t i = 0; i < global_opts.options().size(); ++i) { | |
102 | std::string description = global_opts.options()[i]->description(); | |
103 | auto result = boost::find_first(description, "deprecated"); | |
104 | if (!result.empty()) { | |
105 | continue; | |
106 | } | |
107 | std::stringstream ss; | |
108 | ss << indent2 | |
109 | << global_opts.options()[i]->format_name() << " " | |
110 | << global_opts.options()[i]->format_parameter(); | |
111 | ||
112 | std::cout << ss.str(); | |
113 | IndentStream indent_stream(name_width, ss.str().size(), LINE_WIDTH, std::cout); | |
114 | indent_stream << global_opts.options()[i]->description() << std::endl; | |
115 | } | |
116 | ||
117 | } | |
118 | ||
7c673cae FG |
119 | void OptionPrinter::print_detailed(std::ostream &os) { |
120 | std::string indent_prefix(2, ' '); | |
121 | size_t name_width = compute_name_width(indent_prefix.size()); | |
122 | ||
123 | if (m_positional.options().size() > 0) { | |
124 | std::cout << POSITIONAL_ARGUMENTS << std::endl; | |
125 | for (size_t i = 0; i < m_positional.options().size(); ++i) { | |
126 | std::stringstream ss; | |
127 | ss << indent_prefix << "<" << m_positional.options()[i]->long_name() | |
128 | << ">"; | |
129 | ||
130 | std::cout << ss.str(); | |
131 | IndentStream indent_stream(name_width, ss.str().size(), LINE_WIDTH, os); | |
132 | indent_stream << m_positional.options()[i]->description() << std::endl; | |
133 | } | |
134 | std::cout << std::endl; | |
135 | } | |
136 | ||
137 | if (m_optional.options().size() > 0) { | |
138 | std::cout << OPTIONAL_ARGUMENTS << std::endl; | |
f67539c2 | 139 | print_optional(m_optional, name_width, os); |
7c673cae FG |
140 | std::cout << std::endl; |
141 | } | |
142 | } | |
143 | ||
144 | size_t OptionPrinter::compute_name_width(size_t indent) { | |
145 | size_t width = MIN_NAME_WIDTH; | |
146 | std::vector<OptionsDescription> descs = {m_positional, m_optional}; | |
147 | for (size_t desc_idx = 0; desc_idx < descs.size(); ++desc_idx) { | |
148 | const OptionsDescription &desc = descs[desc_idx]; | |
149 | for (size_t opt_idx = 0; opt_idx < desc.options().size(); ++opt_idx) { | |
150 | size_t name_width = desc.options()[opt_idx]->format_name().size() + | |
151 | desc.options()[opt_idx]->format_parameter().size() | |
152 | + 1; | |
153 | width = std::max(width, name_width); | |
154 | } | |
155 | } | |
156 | width += indent; | |
157 | width = std::min(width, MAX_DESCRIPTION_OFFSET) + 1; | |
158 | return width; | |
159 | } | |
160 | ||
161 | } // namespace rbd |