modchooser.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. #include "completer.h"
  2. #include "completer_command.h"
  3. #include "completion_generator.h"
  4. #include "last_getopt.h"
  5. #include "modchooser.h"
  6. #include <library/cpp/colorizer/colors.h>
  7. #include <util/stream/output.h>
  8. #include <util/stream/format.h>
  9. #include <util/generic/yexception.h>
  10. #include <util/generic/ptr.h>
  11. #include <util/string/builder.h>
  12. #include <util/string/join.h>
  13. class PtrWrapper: public TMainClass {
  14. public:
  15. explicit PtrWrapper(const TMainFunctionPtr main)
  16. : Main(main)
  17. {
  18. }
  19. int operator()(const int argc, const char** argv) override {
  20. return Main(argc, argv);
  21. }
  22. private:
  23. TMainFunctionPtr Main;
  24. };
  25. class PtrvWrapper: public TMainClass {
  26. public:
  27. explicit PtrvWrapper(const TMainFunctionPtrV main)
  28. : Main(main)
  29. {
  30. }
  31. int operator()(const int argc, const char** argv) override {
  32. TVector<TString> nargv(argv, argv + argc);
  33. return Main(nargv);
  34. }
  35. private:
  36. TMainFunctionPtrV Main;
  37. };
  38. class ClassWrapper: public TMainClass {
  39. public:
  40. explicit ClassWrapper(TMainClassV* main)
  41. : Main(main)
  42. {
  43. }
  44. int operator()(const int argc, const char** argv) override {
  45. TVector<TString> nargv(argv, argv + argc);
  46. return (*Main)(nargv);
  47. }
  48. private:
  49. TMainClassV* Main;
  50. };
  51. TModChooser::TMode::TMode(const TString& name, TMainClass* main, const TString& descr, bool hidden, bool noCompletion)
  52. : Name(name)
  53. , Main(main)
  54. , Description(descr)
  55. , Hidden(hidden)
  56. , NoCompletion(noCompletion)
  57. {
  58. }
  59. TModChooser::TModChooser()
  60. : ModesHelpOption("-?") // Default help option in last_getopt
  61. , VersionHandler(nullptr)
  62. , ShowSeparated(true)
  63. , SvnRevisionOptionDisabled(false)
  64. , PrintShortCommandInUsage(false)
  65. {
  66. }
  67. TModChooser::~TModChooser() = default;
  68. void TModChooser::AddMode(const TString& mode, const TMainFunctionRawPtr func, const TString& description, bool hidden, bool noCompletion) {
  69. AddMode(mode, TMainFunctionPtr(func), description, hidden, noCompletion);
  70. }
  71. void TModChooser::AddMode(const TString& mode, const TMainFunctionRawPtrV func, const TString& description, bool hidden, bool noCompletion) {
  72. AddMode(mode, TMainFunctionPtrV(func), description, hidden, noCompletion);
  73. }
  74. void TModChooser::AddMode(const TString& mode, const TMainFunctionPtr func, const TString& description, bool hidden, bool noCompletion) {
  75. Wrappers.push_back(MakeHolder<PtrWrapper>(func));
  76. AddMode(mode, Wrappers.back().Get(), description, hidden, noCompletion);
  77. }
  78. void TModChooser::AddMode(const TString& mode, const TMainFunctionPtrV func, const TString& description, bool hidden, bool noCompletion) {
  79. Wrappers.push_back(MakeHolder<PtrvWrapper>(func));
  80. AddMode(mode, Wrappers.back().Get(), description, hidden, noCompletion);
  81. }
  82. void TModChooser::AddMode(const TString& mode, TMainClass* func, const TString& description, bool hidden, bool noCompletion) {
  83. if (Modes.FindPtr(mode)) {
  84. ythrow yexception() << "TMode '" << mode << "' already exists in TModChooser.";
  85. }
  86. Modes[mode] = UnsortedModes.emplace_back(MakeHolder<TMode>(mode, func, description, hidden, noCompletion)).Get();
  87. }
  88. void TModChooser::AddMode(const TString& mode, TMainClassV* func, const TString& description, bool hidden, bool noCompletion) {
  89. Wrappers.push_back(MakeHolder<ClassWrapper>(func));
  90. AddMode(mode, Wrappers.back().Get(), description, hidden, noCompletion);
  91. }
  92. void TModChooser::AddGroupModeDescription(const TString& description, bool hidden, bool noCompletion) {
  93. UnsortedModes.push_back(MakeHolder<TMode>(TString(), nullptr, description.data(), hidden, noCompletion));
  94. }
  95. void TModChooser::SetDefaultMode(const TString& mode) {
  96. DefaultMode = mode;
  97. }
  98. void TModChooser::AddAlias(const TString& alias, const TString& mode) {
  99. if (!Modes.FindPtr(mode)) {
  100. ythrow yexception() << "TMode '" << mode << "' not found in TModChooser.";
  101. }
  102. Modes[mode]->Aliases.push_back(alias);
  103. Modes[alias] = Modes[mode];
  104. }
  105. void TModChooser::SetDescription(const TString& descr) {
  106. Description = descr;
  107. }
  108. void TModChooser::SetModesHelpOption(const TString& helpOption) {
  109. ModesHelpOption = helpOption;
  110. }
  111. void TModChooser::SetVersionHandler(TVersionHandlerPtr handler) {
  112. VersionHandler = handler;
  113. }
  114. void TModChooser::SetSeparatedMode(bool separated) {
  115. ShowSeparated = separated;
  116. }
  117. void TModChooser::SetSeparationString(const TString& str) {
  118. SeparationString = str;
  119. }
  120. void TModChooser::SetPrintShortCommandInUsage(bool printShortCommandInUsage = false) {
  121. PrintShortCommandInUsage = printShortCommandInUsage;
  122. }
  123. void TModChooser::DisableSvnRevisionOption() {
  124. SvnRevisionOptionDisabled = true;
  125. }
  126. void TModChooser::AddCompletions(TString progName, const TString& name, bool hidden, bool noCompletion) {
  127. if (CompletionsGenerator == nullptr) {
  128. CompletionsGenerator = NLastGetopt::MakeCompletionMod(this, std::move(progName), name);
  129. AddMode(name, CompletionsGenerator.Get(), "generate autocompletion files", hidden, noCompletion);
  130. }
  131. }
  132. int TModChooser::Run(const int argc, const char** argv) const {
  133. Y_ENSURE(argc, "Can't run TModChooser with empty list of arguments.");
  134. bool shiftArgs = true;
  135. TString modeName;
  136. if (argc == 1) {
  137. if (DefaultMode.empty()) {
  138. PrintHelp(argv[0]);
  139. return 0;
  140. } else {
  141. modeName = DefaultMode;
  142. shiftArgs = false;
  143. }
  144. } else {
  145. modeName = argv[1];
  146. }
  147. if (modeName == "-h" || modeName == "--help" || modeName == "-?") {
  148. PrintHelp(argv[0]);
  149. return 0;
  150. }
  151. if (VersionHandler && (modeName == "-v" || modeName == "--version")) {
  152. VersionHandler();
  153. return 0;
  154. }
  155. if (!SvnRevisionOptionDisabled && modeName == "--svnrevision") {
  156. NLastGetopt::PrintVersionAndExit(nullptr);
  157. }
  158. auto modeIter = Modes.find(modeName);
  159. if (modeIter == Modes.end() && !DefaultMode.empty()) {
  160. modeIter = Modes.find(DefaultMode);
  161. shiftArgs = false;
  162. }
  163. if (modeIter == Modes.end()) {
  164. Cerr << "Unknown mode " << modeName.Quote() << "." << Endl;
  165. PrintHelp(argv[0]);
  166. return 1;
  167. }
  168. if (shiftArgs) {
  169. TString firstArg;
  170. TVector<const char*> nargv(Reserve(argc));
  171. if (PrintShortCommandInUsage) {
  172. firstArg = modeIter->second->Name;
  173. } else {
  174. firstArg = argv[0] + TString(" ") + modeIter->second->Name;
  175. }
  176. nargv.push_back(firstArg.data());
  177. for (int i = 2; i < argc; ++i) {
  178. nargv.push_back(argv[i]);
  179. }
  180. // According to the standard, "argv[argc] shall be a null pointer" (5.1.2.2.1).
  181. // http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1336
  182. nargv.push_back(nullptr);
  183. return (*modeIter->second->Main)(nargv.size() - 1, nargv.data());
  184. } else {
  185. return (*modeIter->second->Main)(argc, argv);
  186. }
  187. }
  188. int TModChooser::Run(const TVector<TString>& argv) const {
  189. TVector<const char*> nargv(Reserve(argv.size() + 1));
  190. for (auto& arg : argv) {
  191. nargv.push_back(arg.c_str());
  192. }
  193. // According to the standard, "argv[argc] shall be a null pointer" (5.1.2.2.1).
  194. // http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1336
  195. nargv.push_back(nullptr);
  196. return Run(nargv.size() - 1, nargv.data());
  197. }
  198. size_t TModChooser::TMode::CalculateFullNameLen() const {
  199. size_t len = Name.size();
  200. if (Aliases) {
  201. len += 2;
  202. for (auto& alias : Aliases) {
  203. len += alias.size() + 1;
  204. }
  205. }
  206. return len;
  207. }
  208. TString TModChooser::TMode::FormatFullName(size_t pad) const {
  209. TStringBuilder name;
  210. if (Aliases) {
  211. name << "{";
  212. }
  213. name << NColorizer::StdErr().GreenColor();
  214. name << Name;
  215. name << NColorizer::StdErr().OldColor();
  216. if (Aliases) {
  217. for (const auto& alias : Aliases) {
  218. name << "|" << NColorizer::StdErr().GreenColor() << alias << NColorizer::StdErr().OldColor();
  219. }
  220. name << "}";
  221. }
  222. auto len = CalculateFullNameLen();
  223. if (pad > len) {
  224. name << TString(" ") * (pad - len);
  225. }
  226. return name;
  227. }
  228. void TModChooser::PrintHelp(const TString& progName) const {
  229. Cerr << Description << Endl << Endl;
  230. Cerr << NColorizer::StdErr().BoldColor() << "Usage" << NColorizer::StdErr().OldColor() << ": " << progName << " MODE [MODE_OPTIONS]" << Endl;
  231. Cerr << Endl;
  232. Cerr << NColorizer::StdErr().BoldColor() << "Modes" << NColorizer::StdErr().OldColor() << ":" << Endl;
  233. size_t maxModeLen = 0;
  234. for (const auto& [name, mode] : Modes) {
  235. if (name != mode->Name)
  236. continue; // this is an alias
  237. maxModeLen = Max(maxModeLen, mode->CalculateFullNameLen());
  238. }
  239. if (ShowSeparated) {
  240. for (const auto& unsortedMode : UnsortedModes)
  241. if (!unsortedMode->Hidden) {
  242. if (unsortedMode->Name.size()) {
  243. Cerr << " " << unsortedMode->FormatFullName(maxModeLen + 4) << unsortedMode->Description << Endl;
  244. } else {
  245. Cerr << SeparationString << Endl;
  246. Cerr << unsortedMode->Description << Endl;
  247. }
  248. }
  249. } else {
  250. for (const auto& mode : Modes) {
  251. if (mode.first != mode.second->Name)
  252. continue; // this is an alias
  253. if (!mode.second->Hidden) {
  254. Cerr << " " << mode.second->FormatFullName(maxModeLen + 4) << mode.second->Description << Endl;
  255. }
  256. }
  257. }
  258. Cerr << Endl;
  259. Cerr << "To get help for specific mode type '" << progName << " MODE " << ModesHelpOption << "'" << Endl;
  260. if (VersionHandler)
  261. Cerr << "To print program version type '" << progName << " --version'" << Endl;
  262. if (!SvnRevisionOptionDisabled) {
  263. Cerr << "To print svn revision type --svnrevision" << Endl;
  264. }
  265. return;
  266. }
  267. TVersionHandlerPtr TModChooser::GetVersionHandler() const {
  268. return VersionHandler;
  269. }
  270. bool TModChooser::IsSvnRevisionOptionDisabled() const {
  271. return SvnRevisionOptionDisabled;
  272. }
  273. int TMainClassArgs::Run(int argc, const char** argv) {
  274. return DoRun(NLastGetopt::TOptsParseResult(&GetOptions(), argc, argv));
  275. }
  276. const NLastGetopt::TOpts& TMainClassArgs::GetOptions() {
  277. if (Opts_.Empty()) {
  278. Opts_ = NLastGetopt::TOpts();
  279. RegisterOptions(Opts_.GetRef());
  280. }
  281. return Opts_.GetRef();
  282. }
  283. void TMainClassArgs::RegisterOptions(NLastGetopt::TOpts& opts) {
  284. opts.AddHelpOption('h');
  285. }
  286. int TMainClassArgs::operator()(const int argc, const char** argv) {
  287. return Run(argc, argv);
  288. }
  289. int TMainClassModes::operator()(const int argc, const char** argv) {
  290. return Run(argc, argv);
  291. }
  292. int TMainClassModes::Run(int argc, const char** argv) {
  293. auto& chooser = GetSubModes();
  294. return chooser.Run(argc, argv);
  295. }
  296. const TModChooser& TMainClassModes::GetSubModes() {
  297. if (Modes_.Empty()) {
  298. Modes_.ConstructInPlace();
  299. RegisterModes(Modes_.GetRef());
  300. }
  301. return Modes_.GetRef();
  302. }
  303. void TMainClassModes::RegisterModes(TModChooser& modes) {
  304. modes.SetModesHelpOption("-h");
  305. }