diff options
author | lightqwant <lightqwant@yandex-team.com> | 2022-09-01 20:05:05 +0300 |
---|---|---|
committer | lightqwant <lightqwant@yandex-team.com> | 2022-09-01 20:05:05 +0300 |
commit | 7cfd122cb661b485fb0fb4139573a0beac97ae48 (patch) | |
tree | 5f205aaa2d0cdbc28370858218ff766fff8646a5 | |
parent | c1f7f3324e630e845df52ba0d4ac0a7e0e7f0f9d (diff) | |
download | ydb-7cfd122cb661b485fb0fb4139573a0beac97ae48.tar.gz |
[getopt] Add typo check for long options
-rw-r--r-- | library/cpp/getopt/small/last_getopt_opts.h | 9 | ||||
-rw-r--r-- | library/cpp/getopt/small/last_getopt_parse_result.cpp | 20 | ||||
-rw-r--r-- | library/cpp/getopt/ut/last_getopt_ut.cpp | 25 |
3 files changed, 54 insertions, 0 deletions
diff --git a/library/cpp/getopt/small/last_getopt_opts.h b/library/cpp/getopt/small/last_getopt_opts.h index 825b99c871..718dbfcb89 100644 --- a/library/cpp/getopt/small/last_getopt_opts.h +++ b/library/cpp/getopt/small/last_getopt_opts.h @@ -54,6 +54,7 @@ namespace NLastGetopt { bool AllowUnknownLongOptions_ = false; ui32 Wrap_ = 80; + bool CheckUserTypos_ = false; private: ui32 FreeArgsMin_; // minimal number of free args @@ -341,6 +342,14 @@ namespace NLastGetopt { } /** + * Set check user typos or not + * @param check bool flag for chosing + */ + void SetCheckUserTypos(bool check = true) { + CheckUserTypos_ = check; + } + + /** * Creates new [option description (TOpt)] for svn-revision printing, * adds appropriate handler for it. * If "svnversion" option already exist, will add given short name to it. diff --git a/library/cpp/getopt/small/last_getopt_parse_result.cpp b/library/cpp/getopt/small/last_getopt_parse_result.cpp index f4b5607a90..60effba41b 100644 --- a/library/cpp/getopt/small/last_getopt_parse_result.cpp +++ b/library/cpp/getopt/small/last_getopt_parse_result.cpp @@ -119,6 +119,20 @@ namespace NLastGetopt { return Parser_->Argc_ - GetFreeArgsPos(); } + void FindUserTypos(const TString& arg, const TOpts* options) { + if (arg.size() < 4 || !arg.StartsWith("-")) { + return; + } + + for (auto opt: options->Opts_) { + for (auto name: opt->GetLongNames()) { + if ("-" + name == arg) { + throw TUsageException() << "did you mean `-" << arg << "` (with two dashes)?"; + } + } + } + } + void TOptsParseResult::Init(const TOpts* options, int argc, const char** argv) { try { Parser_.Reset(new TOptsParser(options, argc, argv)); @@ -136,6 +150,12 @@ namespace NLastGetopt { options->ArgBindings_[i](freeArgs[i]); } + + if (options->CheckUserTypos_) { + for (auto arg: TVector<TString>(argv, std::next(argv, argc))) { + FindUserTypos(arg, options); + } + } } catch (...) { HandleError(); } diff --git a/library/cpp/getopt/ut/last_getopt_ut.cpp b/library/cpp/getopt/ut/last_getopt_ut.cpp index 6606000ca6..c2ee4f0c40 100644 --- a/library/cpp/getopt/ut/last_getopt_ut.cpp +++ b/library/cpp/getopt/ut/last_getopt_ut.cpp @@ -825,4 +825,29 @@ Y_UNIT_TEST_SUITE(TLastGetoptTests) { UNIT_ASSERT_VALUES_EQUAL(25, number); UNIT_ASSERT_VALUES_EQUAL(2, r.GetFreeArgCount()); } + + Y_UNIT_TEST(TestCheckUserTypos) { + { + TOptsNoDefault opts; + opts.SetCheckUserTypos(); + opts.AddLongOption("from"); + opts.AddLongOption("to"); + + UNIT_ASSERT_EXCEPTION( + TOptsParseResultTestWrapper(&opts, V({"copy", "-from", "/home", "--to=/etc"})), + TUsageException); + UNIT_ASSERT_NO_EXCEPTION( + TOptsParseResultTestWrapper(&opts, V({"copy", "--from", "from", "--to=/etc"}))); + } + + { + TOptsNoDefault opts; + opts.SetCheckUserTypos(); + opts.AddLongOption('f', "file", ""); + opts.AddLongOption('r', "read", ""); + opts.AddLongOption("fr"); + UNIT_ASSERT_NO_EXCEPTION( + TOptsParseResultTestWrapper(&opts, V({"copy", "-fr"}))); + } + } } |