From 5a03ee58384ce18b6b3de5a2256e18f5ef103633 Mon Sep 17 00:00:00 2001 From: Philip Top Date: Wed, 23 Oct 2024 05:14:29 -0700 Subject: [PATCH] Allow non standard option names like `-option` (#1078) This has been bounced around for a couple years now #474 and a few others have expressed desire to work with non-standard option names. We have been somewhat resistant to that but I think it can be done now. This PR adds a modifier `allow_non_standard_option_names()` It is purposely long, it is purposely off by default. But what it does is allow option names with a single `-` to act like a short option name. With this modifier enabled no single letter short option names are allowed to start with the same letter as a non-standard names. For example `-s` and `-single` would not be allowed. --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Henry Schreiner --- CPPLINT.cfg | 2 ++ README.md | 10 ++++-- azure-pipelines.yml | 2 +- examples/custom_parse.cpp | 1 + examples/formatter.cpp | 1 + examples/inter_argument_order.cpp | 1 + include/CLI/App.hpp | 12 +++++++ include/CLI/Option.hpp | 8 +++-- include/CLI/Split.hpp | 2 +- include/CLI/Timer.hpp | 1 + include/CLI/impl/App_inl.hpp | 47 ++++++++++++++++++++++-- include/CLI/impl/Split_inl.hpp | 28 ++++++++++----- tests/AppTest.cpp | 51 ++++++++++++++++++++++++++ tests/BoostOptionTypeTest.cpp | 60 +++++++++++++++---------------- tests/ComplexTypeTest.cpp | 1 + tests/ConfigFileTest.cpp | 5 +++ tests/CreationTest.cpp | 2 ++ tests/FormatterTest.cpp | 2 ++ tests/FuzzFailTest.cpp | 2 ++ tests/HelpTest.cpp | 18 ++++++++++ tests/HelpersTest.cpp | 1 + tests/NewParseTest.cpp | 2 ++ tests/OptionGroupTest.cpp | 4 +++ tests/OptionTypeTest.cpp | 3 ++ tests/OptionalTest.cpp | 2 ++ tests/SetTest.cpp | 4 +++ tests/SimpleTest.cpp | 2 ++ tests/StringParseTest.cpp | 1 + tests/SubcommandTest.cpp | 4 +++ tests/TimerTest.cpp | 1 + tests/TransformTest.cpp | 7 +++- tests/TrueFalseTest.cpp | 1 + tests/mesonTest/main.cpp | 1 + 33 files changed, 241 insertions(+), 48 deletions(-) diff --git a/CPPLINT.cfg b/CPPLINT.cfg index e1d27d9f..614531fd 100644 --- a/CPPLINT.cfg +++ b/CPPLINT.cfg @@ -3,6 +3,7 @@ linelength=120 # As in .clang-format # Unused filters filter=-build/c++11 # Reports e.g. chrono and thread, which overlap with Chromium's API. Not applicable to general C++ projects. +filter=-build/c++17 # google only restrictions not relevant filter=-build/include_order # Requires unusual include order that encourages creating not self-contained headers filter=-build/include_subdir # Prevents including files in current directory for whatever reason filter=-readability/nolint # Conflicts with clang-tidy @@ -13,3 +14,4 @@ filter=-runtime/string # Requires not using static const strings which makes th filter=-whitespace/blank_line # Unnecessarily strict with blank lines that otherwise help with readability filter=-whitespace/indent # Requires strange 3-space indent of private/protected/public markers filter=-whitespace/parens,-whitespace/braces # Conflict with clang-format +filter=-whitespace/newline # handled by clang-format diff --git a/README.md b/README.md index c3ae26fb..cad71a02 100644 --- a/README.md +++ b/README.md @@ -158,8 +158,6 @@ installation fuss. There are some other possible "features" that are intentionally not supported by this library: -- Non-standard variations on syntax, like `-long` options. This is non-standard - and should be avoided, so that is enforced by this library. - Completion of partial options, such as Python's `argparse` supplies for incomplete arguments. It's better not to guess. Most third party command line parsers for python actually reimplement command line parsing rather than using @@ -904,6 +902,14 @@ option_groups. These are: the form of `/s /long /file:file_name.ext` This option does not change how options are specified in the `add_option` calls or the ability to process options in the form of `-s --long --file=file_name.ext`. +- `.allow_non_standard_option_names()`:🚧 Allow specification of single `-` long + form option names. This is not recommended but is available to enable + reworking of existing interfaces. If this modifier is enabled on an app or + subcommand, options or flags can be specified like normal but instead of + throwing an exception, long form single dash option names will be allowed. It + is not allowed to have a single character short option starting with the same + character as a single dash long form name; for example, `-s` and `-single` are + not allowed in the same application. - `.fallthrough()`: Allow extra unmatched options and positionals to "fall through" and be matched on a parent option. Subcommands by default are allowed to "fall through" as in they will first attempt to match on the current diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 98bdc336..be02ec63 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -22,7 +22,7 @@ jobs: - job: CppLint pool: vmImage: "ubuntu-latest" - container: sharaku/cpplint:latest + container: helics/buildenv:cpplint steps: - bash: cpplint --counting=detailed --recursive examples include/CLI tests displayName: Checking against google style guide diff --git a/examples/custom_parse.cpp b/examples/custom_parse.cpp index 2f9c2a08..f78d2558 100644 --- a/examples/custom_parse.cpp +++ b/examples/custom_parse.cpp @@ -9,6 +9,7 @@ #include #include #include +#include // example file to demonstrate a custom lexical cast function diff --git a/examples/formatter.cpp b/examples/formatter.cpp index b9afb1f9..98818a0c 100644 --- a/examples/formatter.cpp +++ b/examples/formatter.cpp @@ -7,6 +7,7 @@ #include #include #include +#include class MyFormatter : public CLI::Formatter { public: diff --git a/examples/inter_argument_order.cpp b/examples/inter_argument_order.cpp index d0a8ba55..98f38750 100644 --- a/examples/inter_argument_order.cpp +++ b/examples/inter_argument_order.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include diff --git a/include/CLI/App.hpp b/include/CLI/App.hpp index dd8b3722..f822b4f8 100644 --- a/include/CLI/App.hpp +++ b/include/CLI/App.hpp @@ -260,6 +260,9 @@ class App { /// This is potentially useful as a modifier subcommand bool silent_{false}; + /// indicator that the subcommand should allow non-standard option arguments, such as -single_dash_flag + bool allow_non_standard_options_{false}; + /// Counts the number of times this command/subcommand was parsed std::uint32_t parsed_{0U}; @@ -392,6 +395,12 @@ class App { return this; } + /// allow non standard option names + App *allow_non_standard_option_names(bool allowed = true) { + allow_non_standard_options_ = allowed; + return this; + } + /// Set the subcommand to be disabled by default, so on clear(), at the start of each parse it is disabled App *disabled_by_default(bool disable = true) { if(disable) { @@ -1146,6 +1155,9 @@ class App { /// Get the status of silence CLI11_NODISCARD bool get_silent() const { return silent_; } + /// Get the status of silence + CLI11_NODISCARD bool get_allow_non_standard_option_names() const { return allow_non_standard_options_; } + /// Get the status of disabled CLI11_NODISCARD bool get_immediate_callback() const { return immediate_callback_; } diff --git a/include/CLI/Option.hpp b/include/CLI/Option.hpp index 24acc82d..316260f2 100644 --- a/include/CLI/Option.hpp +++ b/include/CLI/Option.hpp @@ -341,9 +341,13 @@ class Option : public OptionBase