diff --git a/include/boost/program_options/options_description.hpp b/include/boost/program_options/options_description.hpp index da92f5f..81336a6 100644 --- a/include/boost/program_options/options_description.hpp +++ b/include/boost/program_options/options_description.hpp @@ -158,12 +158,18 @@ namespace program_options { static const unsigned m_default_line_length; /** Creates the instance. */ - options_description(unsigned line_length = m_default_line_length); + options_description(unsigned line_length = m_default_line_length, + unsigned description_length = m_default_line_length / 2); /** Creates the instance. The 'caption' parameter gives the name of this 'options_description' instance. Primarily useful for output. + The 'description_length' specifies the number of columns that + should be reserved for the description text; if the option text + encroaches into this, then the description will start on the next + line. */ options_description(const std::string& caption, - unsigned line_length = m_default_line_length); + unsigned line_length = m_default_line_length, + unsigned description_length = m_default_line_length / 2); /** Adds new variable description. Throws duplicate_variable_error if either short or long name matches that of already present one. */ @@ -213,6 +219,8 @@ namespace program_options { std::string m_caption; const unsigned m_line_length; + const unsigned m_description_length; + // Data organization is chosen because: // - there could be two names for one option // - option_add_proxy needs to know the last added option diff --git a/src/options_description.cpp b/src/options_description.cpp index 6beb293..557b41f 100644 --- a/src/options_description.cpp +++ b/src/options_description.cpp @@ -205,15 +205,26 @@ namespace boost { namespace program_options { const unsigned options_description::m_default_line_length = 80; - options_description::options_description(unsigned line_length) + options_description::options_description(unsigned line_length, + unsigned description_length) : m_line_length(line_length) - {} - - options_description::options_description(const string& caption, - unsigned line_length) - : m_caption(caption), m_line_length(line_length) - {} + , m_description_length(description_length) + { + // we require a space between the option and description parts, so add 1. + assert(m_description_length < m_line_length - 1); + } + options_description::options_description(const std::string& caption, + unsigned line_length, + unsigned description_length) + : m_caption(caption) + , m_line_length(line_length) + , m_description_length(description_length) + { + // we require a space between the option and description parts, so add 1. + assert(m_description_length < m_line_length - 1); + } + void options_description::add(shared_ptr desc) { @@ -543,7 +554,7 @@ namespace boost { namespace program_options { } /* this is the column were description should start, if first column is longer, we go to a new line */ - unsigned start_of_description_column = m_line_length / 2; + const unsigned start_of_description_column = m_line_length - m_description_length; width = (min)(width, start_of_description_column-1); diff --git a/test/options_description_test.cpp b/test/options_description_test.cpp index e7fdeb0..11d9cd5 100644 --- a/test/options_description_test.cpp +++ b/test/options_description_test.cpp @@ -111,6 +111,54 @@ void test_formatting() ); } +void test_formatting_description_length() +{ + { + options_description desc("", + options_description::m_default_line_length, + options_description::m_default_line_length / 2U); + desc.add_options() + ("an-option-that-sets-the-max", new untyped_value(), // > 40 available for desc + "this description sits on the same line, but wrapping should still work correctly") + ("a-long-option-that-would-leave-very-little-space-for-description", new untyped_value(), + "the description of the long opt, but placed on the next line\n" + " \talso ensure that the tabulation works correctly when a" + " description size has been set"); + + stringstream ss; + ss << desc; + BOOST_CHECK_EQUAL(ss.str(), + " --an-option-that-sets-the-max arg this description sits on the same line,\n" + " but wrapping should still work \n" + " correctly\n" + " --a-long-option-that-would-leave-very-little-space-for-description arg\n" + " the description of the long opt, but \n" + " placed on the next line\n" + " also ensure that the tabulation \n" + " works correctly when a description \n" + " size has been set\n"); + } + { + // the default behaviour reserves 23 (+1 space) characters for the + // option column; this shows that the min_description_length does not + // breach that. + options_description desc("", + options_description::m_default_line_length, + options_description::m_default_line_length - 10U); // leaves < 23 (default option space) + desc.add_options() + ("an-option-that-encroaches-description", new untyped_value(), + "this description should always be placed on the next line, and wrapping should continue as normal"); + + stringstream ss; + ss << desc; + BOOST_CHECK_EQUAL(ss.str(), + " --an-option-that-encroaches-description arg\n" + //123456789_123456789_ + " this description should always be placed on the next line, and \n" + " wrapping should continue as normal\n"); + } +} + void test_long_default_value() { options_description desc; @@ -175,6 +223,7 @@ int main(int, char* []) test_type(); test_approximation(); test_formatting(); + test_formatting_description_length(); test_long_default_value(); test_word_wrapping(); test_default_values();