mirror of
https://github.com/sametersoylu/argument-parser.git
synced 2026-04-13 03:41:18 +00:00
feat: improve the readability of the generated help text. add type hints for the generation of the help text when description is not given for the variable. use sfinae for the check so that it compiles if not given.
This commit is contained in:
@@ -20,7 +20,7 @@ namespace argument_parser::conventions {
|
|||||||
virtual std::string name() const = 0;
|
virtual std::string name() const = 0;
|
||||||
virtual std::string short_prec() const = 0;
|
virtual std::string short_prec() const = 0;
|
||||||
virtual std::string long_prec() const = 0;
|
virtual std::string long_prec() const = 0;
|
||||||
virtual std::string make_help_text(std::string const &short_arg, std::string const &long_arg,
|
virtual std::pair<std::string, std::string> make_help_text(std::string const &short_arg, std::string const &long_arg,
|
||||||
bool requires_value) const = 0;
|
bool requires_value) const = 0;
|
||||||
virtual std::vector<convention_features> get_features() const = 0;
|
virtual std::vector<convention_features> get_features() const = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ namespace argument_parser::conventions::implementations {
|
|||||||
std::string name() const override;
|
std::string name() const override;
|
||||||
std::string short_prec() const override;
|
std::string short_prec() const override;
|
||||||
std::string long_prec() const override;
|
std::string long_prec() const override;
|
||||||
std::string make_help_text(std::string const &short_arg, std::string const &long_arg,
|
std::pair<std::string, std::string> make_help_text(std::string const &short_arg, std::string const &long_arg,
|
||||||
bool requires_value) const override;
|
bool requires_value) const override;
|
||||||
std::vector<convention_features> get_features() const override;
|
std::vector<convention_features> get_features() const override;
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ namespace argument_parser::conventions::implementations {
|
|||||||
std::string name() const override;
|
std::string name() const override;
|
||||||
std::string short_prec() const override;
|
std::string short_prec() const override;
|
||||||
std::string long_prec() const override;
|
std::string long_prec() const override;
|
||||||
std::string make_help_text(std::string const &short_arg, std::string const &long_arg,
|
std::pair<std::string, std::string> make_help_text(std::string const &short_arg, std::string const &long_arg,
|
||||||
bool requires_value) const override;
|
bool requires_value) const override;
|
||||||
std::vector<convention_features> get_features() const override;
|
std::vector<convention_features> get_features() const override;
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ namespace argument_parser::conventions::implementations {
|
|||||||
std::string name() const override;
|
std::string name() const override;
|
||||||
std::string short_prec() const override;
|
std::string short_prec() const override;
|
||||||
std::string long_prec() const override;
|
std::string long_prec() const override;
|
||||||
std::string make_help_text(std::string const &short_arg, std::string const &long_arg,
|
std::pair<std::string, std::string> make_help_text(std::string const &short_arg, std::string const &long_arg,
|
||||||
bool requires_value) const override;
|
bool requires_value) const override;
|
||||||
std::vector<convention_features> get_features() const override;
|
std::vector<convention_features> get_features() const override;
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ namespace argument_parser::conventions::implementations {
|
|||||||
std::string name() const override;
|
std::string name() const override;
|
||||||
std::string short_prec() const override;
|
std::string short_prec() const override;
|
||||||
std::string long_prec() const override;
|
std::string long_prec() const override;
|
||||||
std::string make_help_text(std::string const &short_arg, std::string const &long_arg,
|
std::pair<std::string, std::string> make_help_text(std::string const &short_arg, std::string const &long_arg,
|
||||||
bool requires_value) const override;
|
bool requires_value) const override;
|
||||||
std::vector<convention_features> get_features() const override;
|
std::vector<convention_features> get_features() const override;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include "traits.hpp"
|
||||||
#include <argument_parser.hpp>
|
#include <argument_parser.hpp>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
@@ -103,6 +104,30 @@ namespace argument_parser::v2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
template <typename T> struct has_format_hint {
|
||||||
|
private:
|
||||||
|
typedef char YesType[1];
|
||||||
|
typedef char NoType[2];
|
||||||
|
|
||||||
|
template <typename C> static YesType &test(decltype(&C::format_hint));
|
||||||
|
template <typename> static NoType &test(...);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static constexpr bool value = sizeof(test<T>(0)) == sizeof(YesType);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T> struct has_purpose_hint {
|
||||||
|
private:
|
||||||
|
typedef char YesType[1];
|
||||||
|
typedef char NoType[2];
|
||||||
|
|
||||||
|
template <typename C> static YesType &test(decltype(&C::purpose_hint));
|
||||||
|
template <typename> static NoType &test(...);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static constexpr bool value = sizeof(test<T>(0)) == sizeof(YesType);
|
||||||
|
};
|
||||||
|
|
||||||
template <bool IsTyped, typename ActionType, typename T, typename ArgsMap>
|
template <bool IsTyped, typename ActionType, typename T, typename ArgsMap>
|
||||||
void add_argument_impl(ArgsMap const &argument_pairs) {
|
void add_argument_impl(ArgsMap const &argument_pairs) {
|
||||||
std::unordered_map<extended_add_argument_flags, bool> found_params{
|
std::unordered_map<extended_add_argument_flags, bool> found_params{
|
||||||
@@ -132,19 +157,6 @@ namespace argument_parser::v2 {
|
|||||||
}
|
}
|
||||||
if (argument_pairs.find(add_argument_flags::HelpText) != argument_pairs.end()) {
|
if (argument_pairs.find(add_argument_flags::HelpText) != argument_pairs.end()) {
|
||||||
help_text = get_or_throw<std::string>(argument_pairs.at(add_argument_flags::HelpText), "help");
|
help_text = get_or_throw<std::string>(argument_pairs.at(add_argument_flags::HelpText), "help");
|
||||||
} else {
|
|
||||||
help_text = "";
|
|
||||||
if (short_arg != "-") {
|
|
||||||
help_text += short_arg;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (long_arg != "-") {
|
|
||||||
if (!help_text.empty()) {
|
|
||||||
help_text += ", ";
|
|
||||||
}
|
|
||||||
|
|
||||||
help_text += long_arg;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argument_pairs.find(add_argument_flags::Required) != argument_pairs.end() &&
|
if (argument_pairs.find(add_argument_flags::Required) != argument_pairs.end() &&
|
||||||
@@ -161,10 +173,34 @@ namespace argument_parser::v2 {
|
|||||||
if constexpr (IsTyped) {
|
if constexpr (IsTyped) {
|
||||||
switch (suggested_add) {
|
switch (suggested_add) {
|
||||||
case candidate_type::typed_action:
|
case candidate_type::typed_action:
|
||||||
|
if (help_text.empty()) {
|
||||||
|
if constexpr (has_format_hint<parsing_traits::parser_trait<T>>::value &&
|
||||||
|
has_purpose_hint<parsing_traits::parser_trait<T>>::value) {
|
||||||
|
auto format_hint = parsing_traits::parser_trait<T>::format_hint;
|
||||||
|
auto purpose_hint = parsing_traits::parser_trait<T>::purpose_hint;
|
||||||
|
help_text = "Triggers action with " + std::string(purpose_hint) + " (" +
|
||||||
|
std::string(format_hint) + ")";
|
||||||
|
} else {
|
||||||
|
help_text = "Triggers action with value.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
base::add_argument(short_arg, long_arg, help_text, *static_cast<ActionType *>(&(*action)),
|
base::add_argument(short_arg, long_arg, help_text, *static_cast<ActionType *>(&(*action)),
|
||||||
required);
|
required);
|
||||||
break;
|
break;
|
||||||
case candidate_type::store_other:
|
case candidate_type::store_other:
|
||||||
|
if (help_text.empty()) {
|
||||||
|
if constexpr (has_format_hint<parsing_traits::parser_trait<T>>::value &&
|
||||||
|
has_purpose_hint<parsing_traits::parser_trait<T>>::value) {
|
||||||
|
auto format_hint = parsing_traits::parser_trait<T>::format_hint;
|
||||||
|
auto purpose_hint = parsing_traits::parser_trait<T>::purpose_hint;
|
||||||
|
help_text =
|
||||||
|
"Accepts " + std::string(purpose_hint) + " in " + std::string(format_hint) + " format.";
|
||||||
|
} else {
|
||||||
|
help_text = "Accepts value.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
base::add_argument<T>(short_arg, long_arg, help_text, required);
|
base::add_argument<T>(short_arg, long_arg, help_text, required);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -173,10 +209,21 @@ namespace argument_parser::v2 {
|
|||||||
} else {
|
} else {
|
||||||
switch (suggested_add) {
|
switch (suggested_add) {
|
||||||
case candidate_type::non_typed_action:
|
case candidate_type::non_typed_action:
|
||||||
|
if (help_text.empty()) {
|
||||||
|
help_text = "Triggers action with no value.";
|
||||||
|
}
|
||||||
|
|
||||||
base::add_argument(short_arg, long_arg, help_text, *static_cast<ActionType *>(&(*action)),
|
base::add_argument(short_arg, long_arg, help_text, *static_cast<ActionType *>(&(*action)),
|
||||||
required);
|
required);
|
||||||
break;
|
break;
|
||||||
case candidate_type::store_boolean:
|
case candidate_type::store_boolean:
|
||||||
|
if (help_text.empty()) {
|
||||||
|
auto boolPurpose = parsing_traits::parser_trait<bool>::purpose_hint;
|
||||||
|
auto boolFormat = parsing_traits::parser_trait<bool>::format_hint;
|
||||||
|
help_text =
|
||||||
|
"Accepts " + std::string(boolPurpose) + " in " + std::string(boolFormat) + " format.";
|
||||||
|
}
|
||||||
|
|
||||||
base::add_argument(short_arg, long_arg, help_text, required);
|
base::add_argument(short_arg, long_arg, help_text, required);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -5,29 +5,43 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace argument_parser::parsing_traits {
|
namespace argument_parser::parsing_traits {
|
||||||
|
using hint_type = const char *;
|
||||||
|
|
||||||
template <typename T_> struct parser_trait {
|
template <typename T_> struct parser_trait {
|
||||||
using type = T_;
|
using type = T_;
|
||||||
static T_ parse(const std::string &input);
|
static T_ parse(const std::string &input);
|
||||||
|
static constexpr hint_type format_hint = "value";
|
||||||
|
static constexpr hint_type purpose_hint = "value";
|
||||||
};
|
};
|
||||||
|
|
||||||
template <> struct parser_trait<std::string> {
|
template <> struct parser_trait<std::string> {
|
||||||
static std::string parse(const std::string &input);
|
static std::string parse(const std::string &input);
|
||||||
|
static constexpr hint_type format_hint = "string";
|
||||||
|
static constexpr hint_type purpose_hint = "string value";
|
||||||
};
|
};
|
||||||
|
|
||||||
template <> struct parser_trait<bool> {
|
template <> struct parser_trait<bool> {
|
||||||
static bool parse(const std::string &input);
|
static bool parse(const std::string &input);
|
||||||
|
static constexpr hint_type format_hint = "true/false";
|
||||||
|
static constexpr hint_type purpose_hint = "boolean value";
|
||||||
};
|
};
|
||||||
|
|
||||||
template <> struct parser_trait<int> {
|
template <> struct parser_trait<int> {
|
||||||
static int parse(const std::string &input);
|
static int parse(const std::string &input);
|
||||||
|
static constexpr hint_type format_hint = "123";
|
||||||
|
static constexpr hint_type purpose_hint = "integer value";
|
||||||
};
|
};
|
||||||
|
|
||||||
template <> struct parser_trait<float> {
|
template <> struct parser_trait<float> {
|
||||||
static float parse(const std::string &input);
|
static float parse(const std::string &input);
|
||||||
|
static constexpr hint_type format_hint = "3.14";
|
||||||
|
static constexpr hint_type purpose_hint = "flaoting point number";
|
||||||
};
|
};
|
||||||
|
|
||||||
template <> struct parser_trait<double> {
|
template <> struct parser_trait<double> {
|
||||||
static double parse(const std::string &input);
|
static double parse(const std::string &input);
|
||||||
|
static constexpr hint_type format_hint = "3.14";
|
||||||
|
static constexpr hint_type purpose_hint = "double precision floating point number";
|
||||||
};
|
};
|
||||||
} // namespace argument_parser::parsing_traits
|
} // namespace argument_parser::parsing_traits
|
||||||
|
|
||||||
|
|||||||
19
src/main.cpp
19
src/main.cpp
@@ -1,3 +1,4 @@
|
|||||||
|
#include "headers/parser/parsing_traits/traits.hpp"
|
||||||
#include <string>
|
#include <string>
|
||||||
#define ALLOW_DASH_FOR_WINDOWS 0
|
#define ALLOW_DASH_FOR_WINDOWS 0
|
||||||
|
|
||||||
@@ -22,12 +23,16 @@ template <> struct argument_parser::parsing_traits::parser_trait<Point> {
|
|||||||
int y = std::stoi(input.substr(comma_pos + 1));
|
int y = std::stoi(input.substr(comma_pos + 1));
|
||||||
return {x, y};
|
return {x, y};
|
||||||
}
|
}
|
||||||
|
static constexpr argument_parser::parsing_traits::hint_type format_hint = "x,y";
|
||||||
|
static constexpr argument_parser::parsing_traits::hint_type purpose_hint = "point coordinates";
|
||||||
};
|
};
|
||||||
|
|
||||||
template <> struct argument_parser::parsing_traits::parser_trait<std::regex> {
|
template <> struct argument_parser::parsing_traits::parser_trait<std::regex> {
|
||||||
static std::regex parse(const std::string &input) {
|
static std::regex parse(const std::string &input) {
|
||||||
return std::regex(input);
|
return std::regex(input);
|
||||||
}
|
}
|
||||||
|
static constexpr argument_parser::parsing_traits::hint_type format_hint = "regex";
|
||||||
|
static constexpr argument_parser::parsing_traits::hint_type purpose_hint = "regular expression";
|
||||||
};
|
};
|
||||||
|
|
||||||
template <> struct argument_parser::parsing_traits::parser_trait<std::vector<int>> {
|
template <> struct argument_parser::parsing_traits::parser_trait<std::vector<int>> {
|
||||||
@@ -40,6 +45,8 @@ template <> struct argument_parser::parsing_traits::parser_trait<std::vector<int
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
static constexpr argument_parser::parsing_traits::hint_type format_hint = "int,int,int";
|
||||||
|
static constexpr argument_parser::parsing_traits::hint_type purpose_hint = "list of integers";
|
||||||
};
|
};
|
||||||
|
|
||||||
template <> struct argument_parser::parsing_traits::parser_trait<std::vector<std::string>> {
|
template <> struct argument_parser::parsing_traits::parser_trait<std::vector<std::string>> {
|
||||||
@@ -52,13 +59,16 @@ template <> struct argument_parser::parsing_traits::parser_trait<std::vector<std
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
static constexpr argument_parser::parsing_traits::hint_type format_hint = "string,string,string";
|
||||||
|
static constexpr argument_parser::parsing_traits::hint_type purpose_hint = "list of strings";
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::initializer_list<argument_parser::conventions::convention const *const> conventions = {
|
const std::initializer_list<argument_parser::conventions::convention const *const> conventions = {
|
||||||
&argument_parser::conventions::gnu_argument_convention,
|
&argument_parser::conventions::gnu_argument_convention,
|
||||||
&argument_parser::conventions::gnu_equal_argument_convention,
|
&argument_parser::conventions::gnu_equal_argument_convention,
|
||||||
&argument_parser::conventions::windows_argument_convention,
|
// &argument_parser::conventions::windows_argument_convention,
|
||||||
&argument_parser::conventions::windows_equal_argument_convention};
|
// &argument_parser::conventions::windows_equal_argument_convention
|
||||||
|
};
|
||||||
|
|
||||||
const auto echo = argument_parser::helpers::make_parametered_action<std::string>(
|
const auto echo = argument_parser::helpers::make_parametered_action<std::string>(
|
||||||
[](std::string const &text) { std::cout << text << std::endl; });
|
[](std::string const &text) { std::cout << text << std::endl; });
|
||||||
@@ -131,8 +141,7 @@ int v2Examples() {
|
|||||||
parser.add_argument<std::string>(
|
parser.add_argument<std::string>(
|
||||||
{{ShortArgument, "e"}, {LongArgument, "echo"}, {Action, echo}, {HelpText, "echoes given variable"}});
|
{{ShortArgument, "e"}, {LongArgument, "echo"}, {Action, echo}, {HelpText, "echoes given variable"}});
|
||||||
|
|
||||||
parser.add_argument<Point>(
|
parser.add_argument<Point>({{ShortArgument, "ep"}, {LongArgument, "echo-point"}, {Action, echo_point}});
|
||||||
{{ShortArgument, "ep"}, {LongArgument, "echo-point"}, {Action, echo_point}, {HelpText, "echoes given point"}});
|
|
||||||
|
|
||||||
parser.add_argument<std::string>({
|
parser.add_argument<std::string>({
|
||||||
// stores string for f/file flag
|
// stores string for f/file flag
|
||||||
@@ -159,6 +168,8 @@ int v2Examples() {
|
|||||||
{Required, true} // makes this flag required
|
{Required, true} // makes this flag required
|
||||||
});
|
});
|
||||||
|
|
||||||
|
parser.add_argument({{ShortArgument, "v"}, {LongArgument, "verbose"}});
|
||||||
|
|
||||||
parser.on_complete(::run_grep);
|
parser.on_complete(::run_grep);
|
||||||
parser.on_complete(::run_store_point);
|
parser.on_complete(::run_store_point);
|
||||||
|
|
||||||
|
|||||||
@@ -40,25 +40,26 @@ namespace argument_parser::conventions::implementations {
|
|||||||
return {}; // no fallback allowed
|
return {}; // no fallback allowed
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string gnu_argument_convention::make_help_text(std::string const &short_arg, std::string const &long_arg,
|
std::pair<std::string, std::string> gnu_argument_convention::make_help_text(std::string const &short_arg,
|
||||||
bool requires_value) const {
|
std::string const &long_arg,
|
||||||
std::string res = "";
|
bool requires_value) const {
|
||||||
|
std::string s_part = "";
|
||||||
if (short_arg != "-" && short_arg != "") {
|
if (short_arg != "-" && short_arg != "") {
|
||||||
res += short_prec() + short_arg;
|
s_part += short_prec() + short_arg;
|
||||||
if (requires_value) {
|
if (requires_value) {
|
||||||
res += " <value>";
|
s_part += " <value>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string l_part = "";
|
||||||
if (long_arg != "-" && long_arg != "") {
|
if (long_arg != "-" && long_arg != "") {
|
||||||
if (!res.empty()) {
|
l_part += long_prec() + long_arg;
|
||||||
res += ", ";
|
|
||||||
}
|
|
||||||
res += long_prec() + long_arg;
|
|
||||||
if (requires_value) {
|
if (requires_value) {
|
||||||
res += " <value>";
|
l_part += " <value>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res;
|
|
||||||
|
return {s_part, l_part};
|
||||||
}
|
}
|
||||||
} // namespace argument_parser::conventions::implementations
|
} // namespace argument_parser::conventions::implementations
|
||||||
|
|
||||||
@@ -97,26 +98,26 @@ namespace argument_parser::conventions::implementations {
|
|||||||
return "--";
|
return "--";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string gnu_equal_argument_convention::make_help_text(std::string const &short_arg, std::string const &long_arg,
|
std::pair<std::string, std::string> gnu_equal_argument_convention::make_help_text(std::string const &short_arg,
|
||||||
bool requires_value) const {
|
std::string const &long_arg,
|
||||||
std::string res = "";
|
bool requires_value) const {
|
||||||
|
std::string s_part = "";
|
||||||
if (short_arg != "-" && short_arg != "") {
|
if (short_arg != "-" && short_arg != "") {
|
||||||
res += short_prec() + short_arg;
|
s_part += short_prec() + short_arg;
|
||||||
if (requires_value) {
|
if (requires_value) {
|
||||||
res += "=<value>";
|
s_part += "=<value>";
|
||||||
}
|
|
||||||
}
|
|
||||||
if (long_arg != "-" && long_arg != "") {
|
|
||||||
if (!res.empty()) {
|
|
||||||
res += ", ";
|
|
||||||
}
|
|
||||||
res += long_prec() + long_arg;
|
|
||||||
if (requires_value) {
|
|
||||||
res += "=<value>";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
std::string l_part = "";
|
||||||
|
if (long_arg != "-" && long_arg != "") {
|
||||||
|
l_part += long_prec() + long_arg;
|
||||||
|
if (requires_value) {
|
||||||
|
l_part += "=<value>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {s_part, l_part};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<convention_features> gnu_equal_argument_convention::get_features() const {
|
std::vector<convention_features> gnu_equal_argument_convention::get_features() const {
|
||||||
|
|||||||
@@ -50,27 +50,25 @@ namespace argument_parser::conventions::implementations {
|
|||||||
return "/";
|
return "/";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string windows_argument_convention::make_help_text(std::string const &short_arg, std::string const &long_arg,
|
std::pair<std::string, std::string> windows_argument_convention::make_help_text(std::string const &short_arg, std::string const &long_arg,
|
||||||
bool requires_value) const {
|
bool requires_value) const {
|
||||||
std::string res = "";
|
std::string s_part = "";
|
||||||
if (short_arg != "-" && short_arg != "") {
|
if (short_arg != "-" && short_arg != "") {
|
||||||
res += short_prec() + short_arg;
|
s_part += short_prec() + short_arg;
|
||||||
if (requires_value) {
|
if (requires_value) {
|
||||||
res += " <value>";
|
s_part += " <value>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string l_part = "";
|
||||||
if (long_arg != "-" && long_arg != "") {
|
if (long_arg != "-" && long_arg != "") {
|
||||||
if (!res.empty()) {
|
l_part += long_prec() + long_arg;
|
||||||
res += ", ";
|
|
||||||
}
|
|
||||||
res += long_prec() + long_arg;
|
|
||||||
if (requires_value) {
|
if (requires_value) {
|
||||||
res += " <value>";
|
l_part += " <value>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return {s_part, l_part};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<convention_features> windows_argument_convention::get_features() const {
|
std::vector<convention_features> windows_argument_convention::get_features() const {
|
||||||
@@ -130,30 +128,25 @@ namespace argument_parser::conventions::implementations {
|
|||||||
return "/";
|
return "/";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string windows_kv_argument_convention::make_help_text(std::string const &short_arg,
|
std::pair<std::string, std::string> windows_kv_argument_convention::make_help_text(std::string const &short_arg,
|
||||||
std::string const &long_arg, bool requires_value) const {
|
std::string const &long_arg, bool requires_value) const {
|
||||||
std::string res = "";
|
std::string s_part = "";
|
||||||
if (short_arg != "-" && short_arg != "") {
|
if (short_arg != "-" && short_arg != "") {
|
||||||
res += short_prec() + short_arg;
|
s_part += short_prec() + short_arg;
|
||||||
if (requires_value) {
|
if (requires_value) {
|
||||||
res += "=<value>";
|
s_part += "=<value>, " + short_prec() + short_arg + ":<value>";
|
||||||
res += ", " + short_prec() + short_arg;
|
|
||||||
res += ":<value>";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string l_part = "";
|
||||||
if (long_arg != "-" && long_arg != "") {
|
if (long_arg != "-" && long_arg != "") {
|
||||||
if (!res.empty()) {
|
l_part += long_prec() + long_arg;
|
||||||
res += ", ";
|
|
||||||
}
|
|
||||||
res += long_prec() + long_arg;
|
|
||||||
if (requires_value) {
|
if (requires_value) {
|
||||||
res += "=<value>"
|
l_part += "=<value>, " + long_prec() + long_arg + ":<value>";
|
||||||
", " +
|
|
||||||
long_prec() + long_arg + ":<value>";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res;
|
|
||||||
|
return {s_part, l_part};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<convention_features> windows_kv_argument_convention::get_features() const {
|
std::vector<convention_features> windows_kv_argument_convention::get_features() const {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "argument_parser.hpp"
|
#include "argument_parser.hpp"
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <iomanip>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
@@ -86,23 +87,56 @@ namespace argument_parser {
|
|||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "Usage: " << program_name << " [OPTIONS]...\n";
|
ss << "Usage: " << program_name << " [OPTIONS]...\n";
|
||||||
|
|
||||||
|
size_t max_short_len = 0;
|
||||||
|
size_t max_long_len = 0;
|
||||||
|
|
||||||
|
struct arg_help_info_t {
|
||||||
|
std::vector<std::pair<std::string, std::string>> convention_parts;
|
||||||
|
std::string desc;
|
||||||
|
};
|
||||||
|
std::vector<arg_help_info_t> help_lines;
|
||||||
|
|
||||||
for (auto const &[id, arg] : argument_map) {
|
for (auto const &[id, arg] : argument_map) {
|
||||||
auto short_arg =
|
auto short_arg =
|
||||||
reverse_short_arguments.find(id) != reverse_short_arguments.end() ? reverse_short_arguments.at(id) : "";
|
reverse_short_arguments.find(id) != reverse_short_arguments.end() ? reverse_short_arguments.at(id) : "";
|
||||||
auto long_arg =
|
auto long_arg =
|
||||||
reverse_long_arguments.find(id) != reverse_long_arguments.end() ? reverse_long_arguments.at(id) : "";
|
reverse_long_arguments.find(id) != reverse_long_arguments.end() ? reverse_long_arguments.at(id) : "";
|
||||||
|
|
||||||
ss << "\t";
|
std::vector<std::pair<std::string, std::string>> parts;
|
||||||
std::unordered_set<std::string> hasOnce;
|
std::unordered_set<std::string> hasOnce;
|
||||||
for (auto const &convention : convention_types) {
|
for (auto const &convention : convention_types) {
|
||||||
auto generatedHelpText = convention->make_help_text(short_arg, long_arg, arg.expects_parameter());
|
auto generatedParts = convention->make_help_text(short_arg, long_arg, arg.expects_parameter());
|
||||||
if (hasOnce.find(generatedHelpText) == hasOnce.end()) {
|
std::string combined = generatedParts.first + "|" + generatedParts.second;
|
||||||
ss << generatedHelpText << "\t";
|
if (hasOnce.find(combined) == hasOnce.end()) {
|
||||||
hasOnce.insert(generatedHelpText);
|
parts.push_back(generatedParts);
|
||||||
|
hasOnce.insert(combined);
|
||||||
|
|
||||||
|
if (generatedParts.first.length() > max_short_len) {
|
||||||
|
max_short_len = generatedParts.first.length();
|
||||||
|
}
|
||||||
|
if (generatedParts.second.length() > max_long_len) {
|
||||||
|
max_long_len = generatedParts.second.length();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
parts.push_back({"", ""}); // trigger empty space in the help text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ss << arg.help_text << "\n";
|
help_lines.push_back({parts, arg.help_text});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto const &line : help_lines) {
|
||||||
|
ss << "\t";
|
||||||
|
for (size_t i = 0; i < line.convention_parts.size(); ++i) {
|
||||||
|
auto const &parts = line.convention_parts[i];
|
||||||
|
if (i > 0) {
|
||||||
|
ss << " ";
|
||||||
|
}
|
||||||
|
ss << std::left << std::setw(static_cast<int>(max_short_len)) << parts.first << " "
|
||||||
|
<< std::setw(static_cast<int>(max_long_len)) << parts.second;
|
||||||
|
}
|
||||||
|
ss << "\t" << line.desc << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,7 +347,18 @@ namespace argument_parser {
|
|||||||
for (auto const &[s, l, p] : required_args) {
|
for (auto const &[s, l, p] : required_args) {
|
||||||
std::cerr << "\t" << get_one_name(s, l) << ": must be provided as one of [";
|
std::cerr << "\t" << get_one_name(s, l) << ": must be provided as one of [";
|
||||||
for (auto it = convention_types.begin(); it != convention_types.end(); ++it) {
|
for (auto it = convention_types.begin(); it != convention_types.end(); ++it) {
|
||||||
std::cerr << (*it)->make_help_text(s, l, p);
|
auto generatedParts = (*it)->make_help_text(s, l, p);
|
||||||
|
std::string help_str = generatedParts.first;
|
||||||
|
if (!generatedParts.first.empty() && !generatedParts.second.empty()) {
|
||||||
|
help_str += " ";
|
||||||
|
}
|
||||||
|
help_str += generatedParts.second;
|
||||||
|
|
||||||
|
size_t last_not_space = help_str.find_last_not_of(" \t");
|
||||||
|
if (last_not_space != std::string::npos) {
|
||||||
|
help_str.erase(last_not_space + 1);
|
||||||
|
}
|
||||||
|
std::cerr << help_str;
|
||||||
if (it + 1 != convention_types.end()) {
|
if (it + 1 != convention_types.end()) {
|
||||||
std::cerr << ", ";
|
std::cerr << ", ";
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user