modchooser.h 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. #pragma once
  2. #include "last_getopt_opts.h"
  3. #include <util/generic/map.h>
  4. #include <util/generic/string.h>
  5. #include <util/generic/vector.h>
  6. #include <functional>
  7. //! Mode function with vector of cli arguments.
  8. using TMainFunctionPtrV = std::function<int(const TVector<TString>&)> ;
  9. using TMainFunctionRawPtrV = int (*)(const TVector<TString>& argv);
  10. //! Mode function with classic argc and argv arguments.
  11. using TMainFunctionPtr = std::function<int(int, const char**)> ;
  12. using TMainFunctionRawPtr = int (*)(const int argc, const char** argv);
  13. //! Mode class with vector of cli arguments.
  14. class TMainClassV {
  15. public:
  16. virtual int operator()(const TVector<TString>& argv) = 0;
  17. virtual ~TMainClassV() = default;
  18. };
  19. //! Mode class with classic argc and argv arguments.
  20. class TMainClass {
  21. public:
  22. virtual int operator()(int argc, const char** argv) = 0;
  23. virtual ~TMainClass() = default;
  24. };
  25. //! Function to handle '--version' parameter
  26. typedef void (*TVersionHandlerPtr)();
  27. /*! Main class for handling different modes in single tool.
  28. *
  29. * You can add modes for this class, use autogenerated help with
  30. * list of modes and automatically call necessary mode in run().
  31. *
  32. * In first argv element mode get joined by space tool name and
  33. * current mode name.
  34. */
  35. class TModChooser {
  36. public:
  37. TModChooser();
  38. ~TModChooser();
  39. public:
  40. void AddMode(const TString& mode, TMainFunctionRawPtr func, const TString& description, bool hidden = false, bool noCompletion = false);
  41. void AddMode(const TString& mode, TMainFunctionRawPtrV func, const TString& description, bool hidden = false, bool noCompletion = false);
  42. void AddMode(const TString& mode, TMainFunctionPtr func, const TString& description, bool hidden = false, bool noCompletion = false);
  43. void AddMode(const TString& mode, TMainFunctionPtrV func, const TString& description, bool hidden = false, bool noCompletion = false);
  44. void AddMode(const TString& mode, TMainClass* func, const TString& description, bool hidden = false, bool noCompletion = false);
  45. void AddMode(const TString& mode, TMainClassV* func, const TString& description, bool hidden = false, bool noCompletion = false);
  46. //! Hidden groups won't be displayed in 'help' block
  47. void AddGroupModeDescription(const TString& description, bool hidden = false, bool noCompletion = false);
  48. //! Set default mode (if not specified explicitly)
  49. void SetDefaultMode(const TString& mode);
  50. void AddAlias(const TString& alias, const TString& mode);
  51. //! Set main program description.
  52. void SetDescription(const TString& descr);
  53. //! Set modes help option name (-? is by default)
  54. void SetModesHelpOption(const TString& helpOption);
  55. //! Specify handler for '--version' parameter
  56. void SetVersionHandler(TVersionHandlerPtr handler);
  57. //! Set description show mode
  58. void SetSeparatedMode(bool separated = true);
  59. //! Set separation string
  60. void SetSeparationString(const TString& str);
  61. //! Set short command representation in Usage block
  62. void SetPrintShortCommandInUsage(bool printShortCommandInUsage);
  63. //! Help can be printed either to stdout and stderr. If set to false, then "--help" will be printed to stdout
  64. void SetHelpAlwaysToStdErr(bool helpAlwaysToStdErr) {
  65. HelpAlwaysToStdErr = helpAlwaysToStdErr;
  66. }
  67. void DisableSvnRevisionOption();
  68. void AddCompletions(TString progName, const TString& name = "completion", bool hidden = false, bool noCompletion = false);
  69. /*! Run appropriate mode.
  70. *
  71. * In this method following things happen:
  72. * 1) If first argument is -h/--help/-? then print short description of
  73. * all modes and exit with zero code.
  74. * 2) If first argument is -v/--version and version handler is specified,
  75. * then call it and exit with zero code.
  76. * 3) Find mode with the same name as first argument. If it's found then
  77. * call it and return its return code.
  78. * 4) If appropriate mode is not found - return non-zero code.
  79. */
  80. int Run(int argc, const char** argv) const;
  81. //! Run appropriate mode. Same as Run(const int, const char**)
  82. int Run(const TVector<TString>& argv) const;
  83. void PrintHelp(const TString& progName, bool toStdErr = false) const;
  84. struct TMode {
  85. TString Name;
  86. TMainClass* Main;
  87. TString Description;
  88. bool Hidden;
  89. bool NoCompletion;
  90. TVector<TString> Aliases;
  91. TMode()
  92. : Main(nullptr)
  93. {
  94. }
  95. TMode(const TString& name, TMainClass* main, const TString& descr, bool hidden, bool noCompletion);
  96. // Full name includes primary name and aliases. Also, will add ANSI colors.
  97. size_t CalculateFullNameLen() const;
  98. TString FormatFullName(size_t pad, const NColorizer::TColors& colors) const;
  99. };
  100. TVector<const TMode*> GetUnsortedModes() const {
  101. auto ret = TVector<const TMode*>(Reserve(UnsortedModes.size()));
  102. for (auto& mode : UnsortedModes) {
  103. ret.push_back(mode.Get());
  104. }
  105. return ret;
  106. }
  107. TVersionHandlerPtr GetVersionHandler() const;
  108. bool IsSvnRevisionOptionDisabled() const;
  109. private:
  110. //! Main program description.
  111. TString Description;
  112. //! Help option for modes.
  113. TString ModesHelpOption;
  114. //! Wrappers around all modes.
  115. TVector<THolder<TMainClass>> Wrappers;
  116. //! Modes
  117. TMap<TString, TMode*> Modes;
  118. TString DefaultMode;
  119. //! Handler for '--version' parameter
  120. TVersionHandlerPtr VersionHandler;
  121. //! When set to true, show descriptions unsorted and display separators
  122. bool ShowSeparated;
  123. //! When set to true, disables --svnrevision option, useful for opensource (git hosted) projects
  124. bool SvnRevisionOptionDisabled;
  125. //! When true - will print only 'mode name' in 'Usage' block
  126. bool PrintShortCommandInUsage;
  127. //! Text string used when displaying each separator
  128. TString SeparationString;
  129. //! Unsorted list of options
  130. TVector<THolder<TMode>> UnsortedModes;
  131. //! Mode that generates completions
  132. THolder<TMainClass> CompletionsGenerator;
  133. /*! Help message always output to StdErr
  134. *
  135. * If an error occurs, the help information will be printed to stderr regardless of the settings.
  136. * Setting below for success cases (return code == 0) like "./bin --help".
  137. * In this case by default help will be printed to stderr,
  138. * but it can be overridden by setting "HelpAlwaysToStdErr" to false see SetHelpAlwaysToStdErr() above,
  139. * then help message will be printed to stdout
  140. */
  141. bool HelpAlwaysToStdErr{true};
  142. };
  143. //! Mode class that allows introspecting its console arguments.
  144. class TMainClassArgs: public TMainClass {
  145. public:
  146. int operator()(int argc, const char** argv) final;
  147. public:
  148. //! Run this mode.
  149. int Run(int argc, const char** argv);
  150. //! Get console arguments for this mode.
  151. const NLastGetopt::TOpts& GetOptions();
  152. protected:
  153. //! Fill given empty `TOpts` with options.
  154. virtual void RegisterOptions(NLastGetopt::TOpts& opts);
  155. //! Actual mode logic. Takes parsed options and returns exit code.
  156. virtual int DoRun(NLastGetopt::TOptsParseResult&& parsedOptions) = 0;
  157. private:
  158. TMaybe<NLastGetopt::TOpts> Opts_;
  159. };
  160. //! Mode class that uses sub-modes to dispatch commands further.
  161. class TMainClassModes: public TMainClass {
  162. public:
  163. int operator()(int argc, const char** argv) final;
  164. public:
  165. //! Run this mode.
  166. int Run(int argc, const char** argv);
  167. //! Get sub-modes for this mode.
  168. const TModChooser& GetSubModes();
  169. protected:
  170. //! Fill given modchooser with sub-modes.
  171. virtual void RegisterModes(TModChooser& modes);
  172. private:
  173. TMaybe<TModChooser> Modes_;
  174. };