last_getopt_opt.h 26 KB

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