#pragma once #include "last_getopt_opts.h" #include #include #include #include //! Mode function with vector of cli arguments. using TMainFunctionPtrV = std::function&)> ; using TMainFunctionRawPtrV = int (*)(const TVector& argv); //! Mode function with classic argc and argv arguments. using TMainFunctionPtr = std::function ; using TMainFunctionRawPtr = int (*)(const int argc, const char** argv); //! Mode class with vector of cli arguments. class TMainClassV { public: virtual int operator()(const TVector& argv) = 0; virtual ~TMainClassV() = default; }; //! Mode class with classic argc and argv arguments. class TMainClass { public: virtual int operator()(int argc, const char** argv) = 0; virtual ~TMainClass() = default; }; //! Function to handle '--version' parameter typedef void (*TVersionHandlerPtr)(); /*! Main class for handling different modes in single tool. * * You can add modes for this class, use autogenerated help with * list of modes and automatically call necessary mode in run(). * * In first argv element mode get joined by space tool name and * current mode name. */ class TModChooser { public: TModChooser(); ~TModChooser(); public: void AddMode(const TString& mode, TMainFunctionRawPtr func, const TString& description, bool hidden = false, bool noCompletion = false); void AddMode(const TString& mode, TMainFunctionRawPtrV func, const TString& description, bool hidden = false, bool noCompletion = false); void AddMode(const TString& mode, TMainFunctionPtr func, const TString& description, bool hidden = false, bool noCompletion = false); void AddMode(const TString& mode, TMainFunctionPtrV func, const TString& description, bool hidden = false, bool noCompletion = false); void AddMode(const TString& mode, TMainClass* func, const TString& description, bool hidden = false, bool noCompletion = false); void AddMode(const TString& mode, TMainClassV* func, const TString& description, bool hidden = false, bool noCompletion = false); //! Hidden groups won't be displayed in 'help' block void AddGroupModeDescription(const TString& description, bool hidden = false, bool noCompletion = false); //! Set default mode (if not specified explicitly) void SetDefaultMode(const TString& mode); void AddAlias(const TString& alias, const TString& mode); //! Set main program description. void SetDescription(const TString& descr); //! Set modes help option name (-? is by default) void SetModesHelpOption(const TString& helpOption); //! Specify handler for '--version' parameter void SetVersionHandler(TVersionHandlerPtr handler); //! Set description show mode void SetSeparatedMode(bool separated = true); //! Set separation string void SetSeparationString(const TString& str); //! Set short command representation in Usage block void SetPrintShortCommandInUsage(bool printShortCommandInUsage); //! Help can be printed either to stdout and stderr. If set to false, then "--help" will be printed to stdout void SetHelpAlwaysToStdErr(bool helpAlwaysToStdErr) { HelpAlwaysToStdErr = helpAlwaysToStdErr; } void DisableSvnRevisionOption(); void AddCompletions(TString progName, const TString& name = "completion", bool hidden = false, bool noCompletion = false); /*! Run appropriate mode. * * In this method following things happen: * 1) If first argument is -h/--help/-? then print short description of * all modes and exit with zero code. * 2) If first argument is -v/--version and version handler is specified, * then call it and exit with zero code. * 3) Find mode with the same name as first argument. If it's found then * call it and return its return code. * 4) If appropriate mode is not found - return non-zero code. */ int Run(int argc, const char** argv) const; //! Run appropriate mode. Same as Run(const int, const char**) int Run(const TVector& argv) const; void PrintHelp(const TString& progName, bool toStdErr = false) const; struct TMode { TString Name; TMainClass* Main; TString Description; bool Hidden; bool NoCompletion; TVector Aliases; TMode() : Main(nullptr) { } TMode(const TString& name, TMainClass* main, const TString& descr, bool hidden, bool noCompletion); // Full name includes primary name and aliases. Also, will add ANSI colors. size_t CalculateFullNameLen() const; TString FormatFullName(size_t pad, const NColorizer::TColors& colors) const; }; TVector GetUnsortedModes() const { auto ret = TVector(Reserve(UnsortedModes.size())); for (auto& mode : UnsortedModes) { ret.push_back(mode.Get()); } return ret; } TVersionHandlerPtr GetVersionHandler() const; bool IsSvnRevisionOptionDisabled() const; private: //! Main program description. TString Description; //! Help option for modes. TString ModesHelpOption; //! Wrappers around all modes. TVector> Wrappers; //! Modes TMap Modes; TString DefaultMode; //! Handler for '--version' parameter TVersionHandlerPtr VersionHandler; //! When set to true, show descriptions unsorted and display separators bool ShowSeparated; //! When set to true, disables --svnrevision option, useful for opensource (git hosted) projects bool SvnRevisionOptionDisabled; //! When true - will print only 'mode name' in 'Usage' block bool PrintShortCommandInUsage; //! Text string used when displaying each separator TString SeparationString; //! Unsorted list of options TVector> UnsortedModes; //! Mode that generates completions THolder CompletionsGenerator; /*! Help message always output to StdErr * * If an error occurs, the help information will be printed to stderr regardless of the settings. * Setting below for success cases (return code == 0) like "./bin --help". * In this case by default help will be printed to stderr, * but it can be overridden by setting "HelpAlwaysToStdErr" to false see SetHelpAlwaysToStdErr() above, * then help message will be printed to stdout */ bool HelpAlwaysToStdErr{true}; }; //! Mode class that allows introspecting its console arguments. class TMainClassArgs: public TMainClass { public: int operator()(int argc, const char** argv) final; public: //! Run this mode. int Run(int argc, const char** argv); //! Get console arguments for this mode. const NLastGetopt::TOpts& GetOptions(); protected: //! Fill given empty `TOpts` with options. virtual void RegisterOptions(NLastGetopt::TOpts& opts); //! Actual mode logic. Takes parsed options and returns exit code. virtual int DoRun(NLastGetopt::TOptsParseResult&& parsedOptions) = 0; private: TMaybe Opts_; }; //! Mode class that uses sub-modes to dispatch commands further. class TMainClassModes: public TMainClass { public: int operator()(int argc, const char** argv) final; public: //! Run this mode. int Run(int argc, const char** argv); //! Get sub-modes for this mode. const TModChooser& GetSubModes(); protected: //! Fill given modchooser with sub-modes. virtual void RegisterModes(TModChooser& modes); private: TMaybe Modes_; };