From ae1c3cae5bb5d1b78c890ee1253fdc6d447c8960 Mon Sep 17 00:00:00 2001 From: amirsojoodi Date: Sun, 3 Dec 2023 16:56:00 -0500 Subject: [PATCH 1/2] Format custom help message with configured column width --- include/cxxopts.hpp | 53 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/include/cxxopts.hpp b/include/cxxopts.hpp index a5c67f1..adedf00 100644 --- a/include/cxxopts.hpp +++ b/include/cxxopts.hpp @@ -2300,6 +2300,58 @@ format_description return result; } +String +format_custom_help +( + const std::string& custom_help, + std::size_t start, + std::size_t allowed +) +{ + String result; + std::size_t count = 0; + std::size_t word_size = 0; + + if(allowed <= start) + { + throw_or_mimic("Allowed column" + "width must be greater than start column width!"); + } + + for (std::size_t i = 0; i < custom_help.length(); i++) + { + char c = custom_help[i]; + + while (count < start) { + result.push_back(' '); + count++; + } + + // record the start of a word + word_size = (std::isspace(c)) ? 0 : word_size + 1; + + result.push_back(c); + + count = (c == '\n') ? 0 : count + 1; + + if (count >= allowed) + { + // if we are in the middle of a word, backtrack until word_size is 0 + + for (std::size_t c1 = 0; c1 < word_size; c1++) + { + result.pop_back(); + i--; + } + + result.push_back('\n'); + count = 0; + } + } + + return result; +} + } // namespace inline @@ -2886,6 +2938,7 @@ Options::help(const std::vector& help_groups, bool print_usage) con if (!m_custom_help.empty()) { result += " " + toLocalString(m_custom_help); + result = format_custom_help(result, OPTION_DESC_GAP, m_width); } if (!m_positional.empty() && !m_positional_help.empty()) { From 2f7f44936720539bfb236289185c0539b70e70d1 Mon Sep 17 00:00:00 2001 From: amirsojoodi Date: Mon, 29 Dec 2025 01:24:41 -0500 Subject: [PATCH 2/2] Add unit test for customized width for help --- test/options.cpp | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/test/options.cpp b/test/options.cpp index 6df4972..99f11e2 100644 --- a/test/options.cpp +++ b/test/options.cpp @@ -1191,3 +1191,39 @@ TEST_CASE("No Options help", "[options]") CHECK_NOTHROW(options.parse(argc, argv)); CHECK(options.help().find("test ...") != std::string::npos); } + +TEST_CASE("Format custom message with selected width", "[help]") +{ + cxxopts::Options options("Custom message width", + " - test custom message formatting width"); + + options.custom_help( + "A very very long description that should be wrapped according to the " + "specified width for help messages. This is to ensure that lines are not " + "very long and remain readable. Just to make sure we have enough text here " + "to trigger the wrapping functionality properly. Let's add a bit more text " + "to be certain!"); + + options.set_width(60); + const auto help = options.help(); + CHECK( + help.find( + "Custom message width A very very long description that \n should " + "be wrapped according to the specified width for \n help messages. " + "This is to ensure that lines are not very \n long and remain " + "readable. Just to make sure we have \n enough text here to trigger " + "the wrapping functionality \n properly. Let's add a bit more text " + "to be certain!") != std::string::npos); + + options.set_width(90); + const auto help90 = options.help(); + CHECK( + help90.find( + "Custom message width A very very long description that should be " + "wrapped according to \n the specified width for help messages. " + "This is to ensure that lines are not very long \n and remain " + "readable. Just to make sure we have enough text here to trigger the " + "wrapping \n functionality properly. Let's add a bit more text to " + "be certain!") != + std::string::npos); +} \ No newline at end of file