cli.h 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. //
  2. // cli.h
  3. // tax-manager
  4. //
  5. // Created by Sam Jaffe on 10/8/20.
  6. // Copyright © 2020 Sam Jaffe. All rights reserved.
  7. //
  8. #pragma once
  9. #include <functional>
  10. #include <iostream>
  11. #include <string>
  12. #include <tuple>
  13. #include <unordered_map>
  14. #include <vector>
  15. #include <string_utils/cast.h>
  16. #include "lambda_cast.h"
  17. #include "types.h"
  18. namespace cli {
  19. class cli {
  20. public:
  21. using args_t = std::vector<std::string>;
  22. using callback = std::function<void(args_t const &)>;
  23. private:
  24. std::istream &in_;
  25. std::string prompt_;
  26. std::unordered_map<std::string, size_t> arguments_;
  27. std::unordered_map<std::string, callback> callbacks_;
  28. bool eof_;
  29. public:
  30. explicit cli(std::string const & prompt, std::istream &in = std::cin);
  31. explicit cli(std::istream &in = std::cin);
  32. template <typename... Args>
  33. cli & register_callback(std::string const & handle,
  34. std::function<void(Args...)> cb);
  35. template <typename F>
  36. cli & register_callback(std::string const & handle, F && cb) {
  37. return register_callback(handle, lambdas::FFL(cb));
  38. }
  39. template <typename T>
  40. cli & register_query(std::string const & handle, std::function<T()> cb);
  41. template <typename F>
  42. cli & register_query(std::string const & handle, F && cb) {
  43. return register_query(handle, lambdas::FFL(cb));
  44. }
  45. void run() const;
  46. private:
  47. bool active() const;
  48. cli(cli const &) = delete;
  49. cli(cli &&) = delete;
  50. cli &operator=(cli const &) = delete;
  51. cli &operator=(cli &&) = delete;
  52. };
  53. template <typename... Args, size_t... Is>
  54. void cli_invoke(std::function<void(Args...)> cb, cli::args_t const & args,
  55. std::index_sequence<Is...>) {
  56. std::tuple<std::decay_t<Args>...> object;
  57. if (string_utils::cast(object, args)) {
  58. cb(std::move(std::get<Is>(object))...);
  59. }
  60. }
  61. template <typename... Args>
  62. cli & cli::register_callback(std::string const & handle,
  63. std::function<void(Args...)> cb) {
  64. constexpr size_t N = sizeof...(Args);
  65. arguments_.emplace(handle, N);
  66. callbacks_.emplace(handle, [=](args_t args) {
  67. if (N > args.size()) {
  68. std::cerr << "Missing Args in command '" << handle << "', " <<
  69. N << " required, but " << args.size() << " input\n";
  70. return;
  71. }
  72. args.resize(N);
  73. cli_invoke(cb, args, std::make_index_sequence<N>());
  74. });
  75. return *this;
  76. }
  77. template <typename T> void cli_print(T const & value) {
  78. if constexpr (detail::is_container_v<T> && !detail::is_string_v<T>) {
  79. using ::cli::cli_print;
  80. for (auto & elem : value) {
  81. cli_print(elem);
  82. }
  83. } else if constexpr (detail::is_map_value_type_v<T>) {
  84. std::cout << " " << value.first << ": " << value.second << "\n";
  85. } else {
  86. std::cout << " " << value << "\n";
  87. }
  88. }
  89. template <typename T>
  90. cli & cli::register_query(std::string const & handle, std::function<T()> cb) {
  91. arguments_.emplace(handle, 0);
  92. callbacks_.emplace(handle, [=](args_t const & args) {
  93. using ::cli::cli_print;
  94. cli_print(cb());
  95. });
  96. return *this;
  97. }
  98. }