last_getopt_opt.h 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895
  1. #pragma once
  2. #include "completer.h"
  3. #include "last_getopt_handlers.h"
  4. #include <util/string/split.h>
  5. #include <util/generic/hash_set.h>
  6. #include <util/generic/ptr.h>
  7. #include <util/generic/string.h>
  8. #include <util/generic/maybe.h>
  9. #include <util/generic/vector.h>
  10. #include <util/string/cast.h>
  11. #include <util/string/join.h>
  12. #include <optional>
  13. #include <stdarg.h>
  14. namespace NLastGetopt {
  15. enum EHasArg {
  16. NO_ARGUMENT,
  17. REQUIRED_ARGUMENT,
  18. OPTIONAL_ARGUMENT,
  19. DEFAULT_HAS_ARG = REQUIRED_ARGUMENT
  20. };
  21. /**
  22. * NLastGetopt::TOpt is a storage of data about exactly one program option.
  23. * The data is: parse politics and help information.
  24. *
  25. * The help information consists of following:
  26. * hidden or visible in help information
  27. * help string
  28. * argument name
  29. *
  30. * Parse politics is determined by following parameters:
  31. * argument parse politics: no/optional/required/
  32. * option existence: required or optional
  33. * handlers. See detailed documentation: <TODO:link>
  34. * default value: if the option has argument, but the option is ommited,
  35. * then the <default value> is used as the value of the argument
  36. * optional value: if the option has optional-argument, the option is present in parsed string,
  37. * but the argument is omitted, then <optional value is used>
  38. * in case of "not given <optional value>, omited optional argument" the <default value> is used
  39. * user value: allows to store arbitary pointer for handlers
  40. */
  41. class TOpt {
  42. public:
  43. typedef TVector<char> TShortNames;
  44. typedef TVector<TString> TLongNames;
  45. protected:
  46. TShortNames Chars_;
  47. TLongNames LongNames_;
  48. private:
  49. typedef TMaybe<TString> TdOptVal;
  50. typedef TVector<TSimpleSharedPtr<IOptHandler>> TOptHandlers;
  51. public:
  52. bool Hidden_ = false; // is visible in help
  53. TString ArgTitle_; // the name of argument in help output
  54. TString Help_; // the help string
  55. TString CompletionHelp_; // the help string that's used in completion script, a shorter version of Help_
  56. TString CompletionArgHelp_; // the description of argument in completion script
  57. EHasArg HasArg_ = DEFAULT_HAS_ARG; // the argument parsing politics
  58. bool Required_ = false; // option existence politics
  59. bool EqParseOnly_ = false; // allows option not to read argument
  60. bool AllowMultipleCompletion_ = false; // let the completer know that this option can occur more than once
  61. bool DisableCompletionForOptions_ = false;
  62. bool DisableCompletionForFreeArgs_ = false;
  63. TShortNames DisableCompletionForChar_;
  64. TLongNames DisableCompletionForLongName_;
  65. TVector<size_t> DisableCompletionForFreeArg_;
  66. NComp::ICompleterPtr Completer_;
  67. private:
  68. //Handlers information
  69. const void* UserValue_ = nullptr;
  70. TdOptVal OptionalValue_;
  71. TdOptVal DefaultValue_;
  72. TOptHandlers Handlers_;
  73. THashSet<TString> Choices_;
  74. public:
  75. /**
  76. * Checks if given char can be a short name
  77. * @param c char to check
  78. */
  79. static bool IsAllowedShortName(unsigned char c);
  80. /**
  81. * Checks if given string can be a long name
  82. * @param name string to check
  83. * @param c if given, the first bad charecter will be saved in c
  84. */
  85. static bool IsAllowedLongName(const TString& name, unsigned char* c = nullptr);
  86. /**
  87. * @return one of the expected representations of the option.
  88. * If the option has short names, will return "-<char>"
  89. * Otherwise will return "--<long name>"
  90. */
  91. TString ToShortString() const;
  92. /**
  93. * check if given string is one of the long names
  94. *
  95. * @param name string to check
  96. */
  97. bool NameIs(const TString& name) const;
  98. /**
  99. * check if given char is one of the short names
  100. *
  101. * @param c char to check
  102. */
  103. bool CharIs(char c) const;
  104. /**
  105. * If string has long names - will return one of them
  106. * Otherwise will throw
  107. */
  108. TString GetName() const;
  109. /**
  110. * adds short alias for the option
  111. *
  112. * @param c new short name
  113. *
  114. * @return self
  115. */
  116. TOpt& AddShortName(unsigned char c);
  117. /**
  118. * return all short names of the option
  119. */
  120. const TShortNames& GetShortNames() const {
  121. return Chars_;
  122. }
  123. /**
  124. * adds long alias for the option
  125. *
  126. * @param name new long name
  127. *
  128. * @return self
  129. */
  130. TOpt& AddLongName(const TString& name);
  131. /**
  132. * return all long names of the option
  133. */
  134. const TLongNames& GetLongNames() const {
  135. return LongNames_;
  136. }
  137. /**
  138. * @return one of short names of the opt. If there is no short names exception is raised.
  139. */
  140. char GetChar() const;
  141. /**
  142. * @return one of short names of the opt. If there is no short names '\0' returned.
  143. */
  144. char GetCharOr0() const;
  145. /**
  146. * @returns argument parsing politics
  147. */
  148. const EHasArg& GetHasArg() const {
  149. return HasArg_;
  150. }
  151. /**
  152. * sets argument parsing politics
  153. *
  154. * Note: its better use one of RequiredArgument/NoArgument/OptionalArgument methods
  155. *
  156. * @param hasArg new argument parsing mode
  157. * @return self
  158. */
  159. TOpt& HasArg(EHasArg hasArg) {
  160. HasArg_ = hasArg;
  161. return *this;
  162. }
  163. /**
  164. * @returns argument title
  165. */
  166. TString GetArgTitle() const {
  167. return ArgTitle_;
  168. }
  169. /**
  170. * sets argument parsing politics into REQUIRED_ARGUMENT
  171. *
  172. * @param title the new name of argument in help output
  173. * @return self
  174. */
  175. TOpt& RequiredArgument(const TString& title = "") {
  176. ArgTitle_ = title;
  177. return HasArg(REQUIRED_ARGUMENT);
  178. }
  179. /**
  180. * sets argument parsing politics into NO_ARGUMENT
  181. *
  182. * @return self
  183. */
  184. TOpt& NoArgument() {
  185. return HasArg(NO_ARGUMENT);
  186. }
  187. /**
  188. * sets argument parsing politics into OPTIONAL_ARGUMENT
  189. * for details see NLastGetopt::TOpt
  190. *
  191. * @param title the new name of argument in help output
  192. * @return self
  193. */
  194. TOpt& OptionalArgument(const TString& title = "") {
  195. ArgTitle_ = title;
  196. return HasArg(OPTIONAL_ARGUMENT);
  197. }
  198. /**
  199. * sets argument parsing politics into OPTIONAL_ARGUMENT
  200. * sets the <optional value> into given
  201. *
  202. * for details see NLastGetopt::TOpt
  203. *
  204. * @param val the new <optional value>
  205. * @param title the new name of argument in help output
  206. * @return self
  207. */
  208. TOpt& OptionalValue(const TString& val, const TString& title = "") {
  209. OptionalValue_ = val;
  210. return OptionalArgument(title);
  211. }
  212. /**
  213. * checks if "argument parsing politics" is OPTIONAL_ARGUMENT and the <optional value> is set.
  214. */
  215. bool HasOptionalValue() const {
  216. return OPTIONAL_ARGUMENT == HasArg_ && OptionalValue_;
  217. }
  218. /**
  219. * @return optional value
  220. * throws exception if optional value wasn't set
  221. */
  222. const TString& GetOptionalValue() const {
  223. return *OptionalValue_;
  224. }
  225. /**
  226. * sets <default value>
  227. * @return self
  228. */
  229. template <typename T>
  230. TOpt& DefaultValue(const T& val) {
  231. DefaultValue_ = ToString(val);
  232. return *this;
  233. }
  234. /**
  235. * checks if default value is set.
  236. */
  237. bool HasDefaultValue() const {
  238. return DefaultValue_.Defined();
  239. }
  240. /**
  241. * @return default value
  242. * throws exception if <default value> wasn't set
  243. */
  244. const TString& GetDefaultValue() const {
  245. return *DefaultValue_;
  246. }
  247. /**
  248. * sets the option to be required
  249. * @return self
  250. */
  251. TOpt& Required() {
  252. Required_ = true;
  253. return *this;
  254. }
  255. /**
  256. * allow only --option=arg parsing and disable --option arg
  257. * @return self
  258. */
  259. TOpt& DisableSpaceParse() {
  260. Y_ASSERT(GetHasArg() == OPTIONAL_ARGUMENT || GetHasArg() == REQUIRED_ARGUMENT);
  261. EqParseOnly_ = true;
  262. return *this;
  263. }
  264. /**
  265. * @return true if only --option=arg parse allowed
  266. */
  267. bool IsEqParseOnly() const {
  268. return EqParseOnly_;
  269. }
  270. /**
  271. * sets the option to be optional
  272. * @return self
  273. */
  274. TOpt& Optional() {
  275. Required_ = false;
  276. return *this;
  277. }
  278. /**
  279. * @return true if the option is required
  280. */
  281. bool IsRequired() const {
  282. return Required_;
  283. }
  284. /**
  285. * sets the option to be hidden (invisible in help)
  286. * @return self
  287. */
  288. TOpt& Hidden() {
  289. Hidden_ = true;
  290. return *this;
  291. }
  292. /**
  293. * @return true if the option is hidden
  294. */
  295. bool IsHidden() const {
  296. return Hidden_;
  297. }
  298. /**
  299. * sets the <user value>
  300. * @return self
  301. * for details see NLastGetopt::TOpt
  302. */
  303. TOpt& UserValue(const void* userval) {
  304. UserValue_ = userval;
  305. return *this;
  306. }
  307. /**
  308. * @return user value
  309. */
  310. const void* UserValue() const {
  311. return UserValue_;
  312. }
  313. /**
  314. * Set help string that appears with `--help`. Unless `CompletionHelp` is given, this message will also be used
  315. * in completion script. In this case, don't make it too long, don't start it with a capital letter and don't
  316. * end it with a full stop.
  317. *
  318. * Note that `Help`, `CompletionHelp` and `CompletionArgHelp` are not the same. `Help` is printed in program
  319. * usage (when you call `program --help`), `CompletionHelp` is printed when completer lists available
  320. * options, and `CompletionArgHelp` is printed when completer shows available values for the option.
  321. *
  322. * Example of good help message:
  323. *
  324. * ```
  325. * opts.AddLongOption('t', "timeout")
  326. * .Help("specify query timeout in milliseconds")
  327. * .CompletionHelp("specify query timeout")
  328. * .CompletionArgHelp("query timeout (ms) [default=500]");
  329. * ```
  330. *
  331. * Notice how `Help` and `CompletionArgHelp` have units in them, but `CompletionHelp` don't.
  332. *
  333. * Another good example is the help option:
  334. *
  335. * ```
  336. * opts.AddLongOption('h', "help")
  337. * .Help("print this message and exit")
  338. * .CompletionHelp("print help message and exit");
  339. * ```
  340. *
  341. * Notice how `Help` mentions 'this message', but `CompletionHelp` mentions just 'help message'.
  342. *
  343. * See more on completion descriptions codestyle:
  344. * https://github.com/zsh-users/zsh/blob/master/Etc/completion-style-guide#L43
  345. */
  346. TOpt& Help(const TString& help) {
  347. Help_ = help;
  348. return *this;
  349. }
  350. /**
  351. * Get help string.
  352. */
  353. const TString& GetHelp() const {
  354. return Help_;
  355. }
  356. TString GetChoicesHelp() const {
  357. return JoinSeq(", ", Choices_);
  358. }
  359. /**
  360. * Set help string that appears when argument completer lists available options.
  361. *
  362. * See `Help` function for info on how this is different from setting `Help` and `CompletionArgHelp`.
  363. *
  364. * Use shorter messages for this message. Don't start them with a capital letter and don't end them
  365. * with a full stop. De aware that argument name and default value will not be printed by completer.
  366. *
  367. * In zsh, these messages will look like this:
  368. *
  369. * ```
  370. * $ program -<tab><tab>
  371. * -- option --
  372. * --help -h -- print help message and exit
  373. * --timeout -t -- specify query timeout
  374. * ```
  375. */
  376. TOpt& CompletionHelp(const TString& help) {
  377. CompletionHelp_ = help;
  378. return *this;
  379. }
  380. /**
  381. * Get help string that appears when argument completer lists available options.
  382. */
  383. const TString& GetCompletionHelp() const {
  384. return CompletionHelp_ ? CompletionHelp_ : Help_;
  385. }
  386. /**
  387. * Set help string that appears when completer suggests available values.
  388. *
  389. * See `Help` function for info on how this is different from setting `Help` and `CompletionHelp`.
  390. *
  391. * In zsh, these messages will look like this:
  392. *
  393. * ```
  394. * $ program --timeout <tab><tab>
  395. * -- query timeout (ms) [default=500] --
  396. * 50 100 250 500 1000
  397. * ```
  398. */
  399. TOpt& CompletionArgHelp(const TString& help) {
  400. CompletionArgHelp_ = help;
  401. return *this;
  402. }
  403. /**
  404. * @return argument help string for use in completion script.
  405. */
  406. const TString& GetCompletionArgHelp() const {
  407. return CompletionArgHelp_ ? CompletionArgHelp_ : ArgTitle_;
  408. }
  409. /**
  410. * Let the completer know that this option can occur more than once.
  411. */
  412. TOpt& AllowMultipleCompletion(bool allowMultipleCompletion = true) {
  413. AllowMultipleCompletion_ = allowMultipleCompletion;
  414. return *this;
  415. }
  416. /**
  417. * @return true if completer will offer completion for this option multiple times.
  418. */
  419. bool MultipleCompletionAllowed() const {
  420. return AllowMultipleCompletion_;
  421. }
  422. /**
  423. * Tell the completer to disable further completion if this option is present.
  424. * This is useful for options like `--help`.
  425. *
  426. * Note: this only works in zsh.
  427. *
  428. * @return self
  429. */
  430. TOpt& IfPresentDisableCompletion(bool value = true) {
  431. IfPresentDisableCompletionForOptions(value);
  432. IfPresentDisableCompletionForFreeArgs(value);
  433. return *this;
  434. }
  435. /**
  436. * Tell the completer to disable completion for all options if this option is already present in the input.
  437. * Free arguments will still be completed.
  438. *
  439. * Note: this only works in zsh.
  440. *
  441. * @return self
  442. */
  443. TOpt& IfPresentDisableCompletionForOptions(bool value = true) {
  444. DisableCompletionForOptions_ = value;
  445. return *this;
  446. }
  447. /**
  448. * Tell the completer to disable option `c` if this option is already present in the input.
  449. * For example, if you have two options `-a` and `-r` that are mutually exclusive, disable `-r` for `-a` and
  450. * disable `-a` for `-r`, like this:
  451. *
  452. * ```
  453. * opts.AddLongOption('a', "acquire").IfPresentDisableCompletionFor('r');
  454. * opts.AddLongOption('r', "release").IfPresentDisableCompletionFor('a');
  455. * ```
  456. *
  457. * This way, if user enabled option `-a`, completer will not suggest option `-r`.
  458. *
  459. * Note that we don't have to disable all flags for a single option. That is, disabling `-r` in the above
  460. * example disables `--release` automatically.
  461. *
  462. * Note: this only works in zsh.
  463. *
  464. * @param c char option that should be disabled when completer hits this option.
  465. */
  466. TOpt& IfPresentDisableCompletionFor(char c) {
  467. DisableCompletionForChar_.push_back(c);
  468. return *this;
  469. }
  470. /**
  471. * Like `IfPresentDisableCompletionFor(char c)`, but for long options.
  472. */
  473. TOpt& IfPresentDisableCompletionFor(const TString& name) {
  474. DisableCompletionForLongName_.push_back(name);
  475. return *this;
  476. }
  477. /**
  478. * Like `IfPresentDisableCompletionFor(char c)`, but for long options.
  479. */
  480. TOpt& IfPresentDisableCompletionFor(const TOpt& opt);
  481. /**
  482. * Tell the completer to disable completion for the given free argument if this option is present.
  483. *
  484. * Note: this only works in zsh.
  485. *
  486. * @param arg index of free arg
  487. */
  488. TOpt& IfPresentDisableCompletionForFreeArg(size_t index) {
  489. DisableCompletionForFreeArg_.push_back(index);
  490. return *this;
  491. }
  492. /**
  493. * Assign a completer for this option.
  494. */
  495. TOpt& Completer(NComp::ICompleterPtr completer) {
  496. Completer_ = std::move(completer);
  497. return *this;
  498. }
  499. /**
  500. * Tell the completer to disable completion for the all free arguments if this option is present.
  501. *
  502. * Note: this only works in zsh.
  503. */
  504. TOpt& IfPresentDisableCompletionForFreeArgs(bool value = true) {
  505. DisableCompletionForFreeArgs_ = value;
  506. return *this;
  507. }
  508. /**
  509. * Run handlers for this option.
  510. */
  511. void FireHandlers(const TOptsParser* parser) const;
  512. private:
  513. TOpt& HandlerImpl(IOptHandler* handler) {
  514. Handlers_.push_back(handler);
  515. return *this;
  516. }
  517. public:
  518. template <typename TpFunc>
  519. TOpt& Handler0(TpFunc func) { // functor taking no parameters
  520. return HandlerImpl(new NPrivate::THandlerFunctor0<TpFunc>(func));
  521. }
  522. template <typename TpFunc>
  523. TOpt& Handler1(TpFunc func) { // functor taking one parameter
  524. return HandlerImpl(new NPrivate::THandlerFunctor1<TpFunc>(func));
  525. }
  526. template <typename TpArg, typename TpFunc>
  527. TOpt& Handler1T(TpFunc func) {
  528. return HandlerImpl(new NPrivate::THandlerFunctor1<TpFunc, TpArg>(func));
  529. }
  530. template <typename TpArg, typename TpFunc>
  531. TOpt& Handler1T(const TpArg& def, TpFunc func) {
  532. return HandlerImpl(new NPrivate::THandlerFunctor1<TpFunc, TpArg>(func, def));
  533. }
  534. template <typename TpArg, typename TpArg2, typename TpFunc>
  535. TOpt& Handler1T2(const TpArg2& def, TpFunc func) {
  536. return HandlerImpl(new NPrivate::THandlerFunctor1<TpFunc, TpArg>(func, def));
  537. }
  538. TOpt& Handler(void (*f)()) {
  539. return Handler0(f);
  540. }
  541. TOpt& Handler(void (*f)(const TOptsParser*)) {
  542. return Handler1(f);
  543. }
  544. TOpt& Handler(TAutoPtr<IOptHandler> handler) {
  545. return HandlerImpl(handler.Release());
  546. }
  547. template <typename T> // T extends IOptHandler
  548. TOpt& Handler(TAutoPtr<T> handler) {
  549. return HandlerImpl(handler.Release());
  550. }
  551. // Stores FromString<T>(arg) in *target
  552. // T maybe anything with FromString<T>(const TStringBuf&) defined
  553. template <typename TpVal, typename T>
  554. TOpt& StoreResultT(T* target) {
  555. return Handler1T<TpVal>(NPrivate::TStoreResultFunctor<T, TpVal>(target));
  556. }
  557. template <typename T>
  558. TOpt& StoreResult(T* target) {
  559. return StoreResultT<T>(target);
  560. }
  561. // Uses TMaybe<T> to store FromString<T>(arg)
  562. template <typename T>
  563. TOpt& StoreResult(TMaybe<T>* target) {
  564. return StoreResultT<T>(target);
  565. }
  566. template <typename T>
  567. TOpt& StoreResult(std::optional<T>* target) {
  568. return StoreResultT<T>(target);
  569. }
  570. template <typename TpVal, typename T, typename TpDef>
  571. TOpt& StoreResultT(T* target, const TpDef& def) {
  572. return Handler1T<TpVal>(def, NPrivate::TStoreResultFunctor<T, TpVal>(target));
  573. }
  574. template <typename T, typename TpDef>
  575. TOpt& StoreResult(T* target, const TpDef& def) {
  576. return StoreResultT<T>(target, def);
  577. }
  578. template <typename T>
  579. TOpt& StoreResultDef(T* target) {
  580. DefaultValue_ = ToString(*target);
  581. return StoreResultT<T>(target, *target);
  582. }
  583. template <typename T, typename TpDef>
  584. TOpt& StoreResultDef(T* target, const TpDef& def) {
  585. DefaultValue_ = ToString(def);
  586. return StoreResultT<T>(target, def);
  587. }
  588. // Sugar for storing flags (option without arguments) to boolean vars
  589. TOpt& SetFlag(bool* target) {
  590. return DefaultValue("0").StoreResult(target, true);
  591. }
  592. // Similar to store_true in Python's argparse
  593. TOpt& StoreTrue(bool* target) {
  594. return NoArgument().SetFlag(target);
  595. }
  596. // Similar to store_false in Python's argparse
  597. TOpt& StoreFalse(bool* target) {
  598. return NoArgument().StoreResult(target, false);
  599. }
  600. template <typename TpVal, typename T, typename TpFunc>
  601. TOpt& StoreMappedResultT(T* target, const TpFunc& func) {
  602. return Handler1T<TpVal>(NPrivate::TStoreMappedResultFunctor<T, TpFunc, TpVal>(target, func));
  603. }
  604. template <typename T, typename TpFunc>
  605. TOpt& StoreMappedResult(T* target, const TpFunc& func) {
  606. return StoreMappedResultT<T>(target, func);
  607. }
  608. // Stores given value in *target if the option is present.
  609. // TValue must be a copyable type, constructible from TParam.
  610. // T must be a copyable type, assignable from TValue.
  611. template <typename TValue, typename T, typename TParam>
  612. TOpt& StoreValueT(T* target, const TParam& value) {
  613. return Handler1(NPrivate::TStoreValueFunctor<T, TValue>(target, value));
  614. }
  615. // save value as target type
  616. template <typename T, typename TParam>
  617. TOpt& StoreValue(T* target, const TParam& value) {
  618. return StoreValueT<T>(target, value);
  619. }
  620. // save value as its original type (2nd template parameter)
  621. template <typename T, typename TValue>
  622. TOpt& StoreValue2(T* target, const TValue& value) {
  623. return StoreValueT<TValue>(target, value);
  624. }
  625. // Appends FromString<T>(arg) to *target for each argument
  626. template<class Container>
  627. TOpt& AppendTo(Container* target) {
  628. return Handler1T<typename Container::value_type>([target](auto&& value) { target->push_back(std::forward<decltype(value)>(value)); });
  629. }
  630. // Appends FromString<T>(arg) to *target for each argument
  631. template <typename T>
  632. TOpt& InsertTo(THashSet<T>* target) {
  633. return Handler1T<T>([target](auto&& value) { target->insert(std::forward<decltype(value)>(value)); });
  634. }
  635. // Appends FromString<T>(arg) to *target for each argument
  636. template <class Container>
  637. TOpt& InsertTo(Container* target) {
  638. return Handler1T<typename Container::value_type>([target](auto&& value) { target->insert(std::forward<decltype(value)>(value)); });
  639. }
  640. // Emplaces TString arg to *target for each argument
  641. template <typename T>
  642. TOpt& EmplaceTo(TVector<T>* target) {
  643. return Handler1T<TString>([target](TString arg) { target->emplace_back(std::move(arg)); } );
  644. }
  645. // Emplaces TString arg to *target for each argument
  646. template <class Container>
  647. TOpt& EmplaceTo(Container* target) {
  648. return Handler1T<TString>([target](TString arg) { target->emplace_back(std::move(arg)); } );
  649. }
  650. template <class Container>
  651. TOpt& SplitHandler(Container* target, const char delim) {
  652. return Handler(new NLastGetopt::TOptSplitHandler<Container>(target, delim));
  653. }
  654. template <class Container>
  655. TOpt& RangeSplitHandler(Container* target, const char elementsDelim, const char rangesDelim) {
  656. return Handler(new NLastGetopt::TOptRangeSplitHandler<Container>(target, elementsDelim, rangesDelim));
  657. }
  658. template <class TpFunc>
  659. TOpt& KVHandler(TpFunc func, const char kvdelim = '=') {
  660. return Handler(new NLastGetopt::TOptKVHandler<TpFunc>(func, kvdelim));
  661. }
  662. template <typename TIterator>
  663. TOpt& Choices(TIterator begin, TIterator end) {
  664. return Choices(THashSet<typename TIterator::value_type>{begin, end});
  665. }
  666. template <typename TValue>
  667. TOpt& Choices(THashSet<TValue> choices) {
  668. Choices_ = std::move(choices);
  669. return Handler1T<TValue>(
  670. [this] (const TValue& arg) {
  671. if (!Choices_.contains(arg)) {
  672. throw TUsageException() << " value '" << arg
  673. << "' is not allowed for option '" << GetName() << "'";
  674. }
  675. });
  676. }
  677. TOpt& Choices(TVector<TString> choices) {
  678. return Choices(
  679. THashSet<TString>{
  680. std::make_move_iterator(choices.begin()),
  681. std::make_move_iterator(choices.end())
  682. });
  683. }
  684. TOpt& ChoicesWithCompletion(TVector<NComp::TChoice> choices) {
  685. Completer(NComp::Choice(choices));
  686. THashSet<TString> choicesSet;
  687. choicesSet.reserve(choices.size());
  688. for (const auto& choice : choices) {
  689. choicesSet.insert(choice.Choice);
  690. }
  691. return Choices(std::move(choicesSet));
  692. }
  693. };
  694. /**
  695. * NLastGetopt::TFreeArgSpec is a storage of data about free argument.
  696. * The data is help information and (maybe) linked named argument.
  697. *
  698. * The help information consists of following:
  699. * help string
  700. * argument name (title)
  701. */
  702. struct TFreeArgSpec {
  703. TFreeArgSpec() = default;
  704. TFreeArgSpec(const TString& title, const TString& help = TString(), bool optional = false)
  705. : Title_(title)
  706. , Help_(help)
  707. , Optional_(optional)
  708. {
  709. }
  710. TString Title_;
  711. TString Help_;
  712. TString CompletionArgHelp_;
  713. bool Optional_ = false;
  714. NComp::ICompleterPtr Completer_ = nullptr;
  715. /**
  716. * Check if this argument have default values for its title and help.
  717. */
  718. bool IsDefault() const {
  719. return Title_.empty() && Help_.empty();
  720. }
  721. /**
  722. * Set argument title.
  723. */
  724. TFreeArgSpec& Title(TString title) {
  725. Title_ = std::move(title);
  726. return *this;
  727. }
  728. /**
  729. * Get argument title. If title is empty, returns a default one.
  730. */
  731. TStringBuf GetTitle(TStringBuf defaultTitle) const {
  732. return Title_ ? TStringBuf(Title_) : defaultTitle;
  733. }
  734. /**
  735. * Set help string that appears with `--help`. Unless `CompletionHelp` is given, this message will also be used
  736. * in completion script. In this case, don't make it too long, don't start it with a capital letter and don't
  737. * end it with a full stop.
  738. *
  739. * See `TOpt::Help` function for more on how `Help` and `CompletionArgHelp` differ one from another.
  740. */
  741. TFreeArgSpec& Help(TString help) {
  742. Help_ = std::move(help);
  743. return *this;
  744. }
  745. /**
  746. * Get help string that appears with `--help`.
  747. */
  748. TStringBuf GetHelp() const {
  749. return Help_;
  750. }
  751. /**
  752. * Set help string that appears when completer suggests values fot this argument.
  753. */
  754. TFreeArgSpec& CompletionArgHelp(TString completionArgHelp) {
  755. CompletionArgHelp_ = std::move(completionArgHelp);
  756. return *this;
  757. }
  758. /**
  759. * Get help string that appears when completer suggests values fot this argument.
  760. */
  761. TStringBuf GetCompletionArgHelp(TStringBuf defaultTitle) const {
  762. return CompletionArgHelp_ ? TStringBuf(CompletionArgHelp_) : GetTitle(defaultTitle);
  763. }
  764. /**
  765. * Mark this argument as optional. This setting only affects help printing, it doesn't affect parsing.
  766. */
  767. TFreeArgSpec& Optional(bool optional = true) {
  768. Optional_ = optional;
  769. return *this;
  770. }
  771. /**
  772. * Check if this argument is optional.
  773. */
  774. bool IsOptional() const {
  775. return Optional_;
  776. }
  777. /**
  778. * Set completer for this argument.
  779. */
  780. TFreeArgSpec& Completer(NComp::ICompleterPtr completer) {
  781. Completer_ = std::move(completer);
  782. return *this;
  783. }
  784. };
  785. }