From 1a46d66f62a768c58333f25439c92b03d417a6a7 Mon Sep 17 00:00:00 2001 From: kamchatka-volcano Date: Fri, 3 Jan 2025 01:58:55 +0500 Subject: [PATCH] -fixed usage info width calculation, by taking commands width into account; -set version to 2.7.0; --- CMakeLists.txt | 2 +- include/cmdlime/detail/gnuformat.h | 9 +++++++++ include/cmdlime/detail/posixformat.h | 9 +++++++++ include/cmdlime/detail/simpleformat.h | 9 +++++++++ include/cmdlime/detail/usageinfocreator.h | 10 ++++++---- include/cmdlime/detail/x11format.h | 9 +++++++++ tests/test_gnu_format.cpp | 18 ++++++++++++++++++ 7 files changed, 61 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 60caeab..b1fa5ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.18) -project(cmdlime VERSION 2.6.0 DESCRIPTION "C++17 command line parsing library") +project(cmdlime VERSION 2.7.0 DESCRIPTION "C++17 command line parsing library") include(external/seal_lake) option(CMDLIME_USE_NAMEOF "Enable automatic registration of struct field names using the nameof library" OFF) diff --git a/include/cmdlime/detail/gnuformat.h b/include/cmdlime/detail/gnuformat.h index 5edfdeb..d5ab179 100644 --- a/include/cmdlime/detail/gnuformat.h +++ b/include/cmdlime/detail/gnuformat.h @@ -350,6 +350,15 @@ class GNUOutputFormatter { stream << "<" << argList.info().name() << "> (" << argList.info().valueName() << ")"; return stream.str(); } + + static std::string commandDescriptionName(const ICommand& command, int indent = 0) + { + auto stream = std::stringstream{}; + if (indent) + stream << std::setw(indent) << " "; + stream << command.info().name() << " [options]"; + return stream.str(); + } }; template<> diff --git a/include/cmdlime/detail/posixformat.h b/include/cmdlime/detail/posixformat.h index 61155bb..8b1337d 100644 --- a/include/cmdlime/detail/posixformat.h +++ b/include/cmdlime/detail/posixformat.h @@ -247,6 +247,15 @@ class PosixOutputFormatter { stream << "<" << argList.info().name() << "> (" << argList.info().valueName() << ")"; return stream.str(); } + + static std::string commandDescriptionName(const ICommand& command, int indent = 0) + { + auto stream = std::stringstream{}; + if (indent) + stream << std::setw(indent) << " "; + stream << command.info().name() << " [options]"; + return stream.str(); + } }; template<> diff --git a/include/cmdlime/detail/simpleformat.h b/include/cmdlime/detail/simpleformat.h index 9576c7b..fdf73a0 100644 --- a/include/cmdlime/detail/simpleformat.h +++ b/include/cmdlime/detail/simpleformat.h @@ -200,6 +200,15 @@ class DefaultOutputFormatter { stream << "<" << argList.info().name() << "> (" << argList.info().valueName() << ")"; return stream.str(); } + + static std::string commandDescriptionName(const ICommand& command, int indent = 0) + { + auto stream = std::stringstream{}; + if (indent) + stream << std::setw(indent) << " "; + stream << command.info().name() << " [options]"; + return stream.str(); + } }; template<> diff --git a/include/cmdlime/detail/usageinfocreator.h b/include/cmdlime/detail/usageinfocreator.h index 70cc11b..a84daf6 100644 --- a/include/cmdlime/detail/usageinfocreator.h +++ b/include/cmdlime/detail/usageinfocreator.h @@ -193,9 +193,9 @@ class UsageInfoCreator { std::string paramsInfo() { - auto result = std::string{"Parameters:\n"}; if (params_.empty()) - return result; + return {}; + auto result = std::string{"Parameters:\n"}; for (const IParam& param : params_) { const auto name = OutputFormatter::paramDescriptionName(param, outputSettings_.nameIndentation) + "\n"; result += makeConfigFieldInfo(name, getDescription(param)); @@ -205,9 +205,9 @@ class UsageInfoCreator { std::string paramListsInfo() { - auto result = std::string{}; if (paramLists_.empty()) - return result; + return {}; + auto result = std::string{}; for (const IParamList& paramList : paramLists_) { const auto name = OutputFormatter::paramListDescriptionName(paramList, outputSettings_.nameIndentation) + "\n"; @@ -364,6 +364,8 @@ class UsageInfoCreator { updateLength(OutputFormatter::flagDescriptionName(*flag, outputSettings_.nameIndentation)); for (auto& arg : options_.args()) updateLength(OutputFormatter::argDescriptionName(*arg, outputSettings_.nameIndentation)); + for (auto& command : options_.commands()) + updateLength(OutputFormatter::commandDescriptionName(*command, outputSettings_.nameIndentation)); if (options_.argList()) updateLength(OutputFormatter::argListDescriptionName(*options_.argList(), outputSettings_.nameIndentation)); return length; diff --git a/include/cmdlime/detail/x11format.h b/include/cmdlime/detail/x11format.h index e5985b2..a2532cb 100644 --- a/include/cmdlime/detail/x11format.h +++ b/include/cmdlime/detail/x11format.h @@ -222,6 +222,15 @@ class X11OutputFormatter { stream << "<" << argList.info().name() << "> (" << argList.info().valueName() << ")"; return stream.str(); } + + static std::string commandDescriptionName(const ICommand& command, int indent = 0) + { + auto stream = std::stringstream{}; + if (indent) + stream << std::setw(indent) << " "; + stream << command.info().name() << " [options]"; + return stream.str(); + } }; template<> diff --git a/tests/test_gnu_format.cpp b/tests/test_gnu_format.cpp index 39ec044..d302963 100644 --- a/tests/test_gnu_format.cpp +++ b/tests/test_gnu_format.cpp @@ -44,6 +44,11 @@ struct FullConfig : public Config { CMDLIME_SUBCOMMAND(subcommand, SubcommandConfig); }; +struct CommandsConfig : public Config { + CMDLIME_COMMAND(cmd, SubcommandConfig); + CMDLIME_SUBCOMMAND(subcommand, SubcommandConfig); +}; + #ifdef CMDLIME_NAMEOF_AVAILABLE struct FullConfigWithoutMacro : public Config { std::string requiredParam = param<&T::requiredParam>(); @@ -1387,6 +1392,19 @@ TEST(GNUConfig, DetailedUsageInfo) EXPECT_EQ(reader.usageInfoDetailed(), expectedDetailedInfo); } +TEST(GNUConfig, DetailedUsageInfoCommandsOnly) +{ + auto reader = cmdlime::CommandLineReader{}; + reader.setProgramName("testproc"); + auto expectedDetailedInfo = + std::string{"Usage: testproc [commands] \n" + "Commands:\n" + " cmd [options] \n" + " subcommand [options] \n"}; + EXPECT_EQ(reader.usageInfoDetailed(), expectedDetailedInfo); +} + + TEST(GNUConfig, DetailedUsageInfoWithoutMacro) { auto reader = cmdlime::CommandLineReader{};