cli.h 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  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 "lambda_cast.h"
  16. #include "types.h"
  17. namespace cli {
  18. class cli {
  19. public:
  20. using args_t = std::vector<std::string>;
  21. using callback = std::function<void(args_t const &)>;
  22. private:
  23. std::istream &in_;
  24. std::string prompt_;
  25. std::unordered_map<std::string, size_t> arguments_;
  26. std::unordered_map<std::string, callback> callbacks_;
  27. bool eof_;
  28. public:
  29. cli(std::string const & prompt, std::istream &in = std::cin);
  30. cli(std::istream &in = std::cin);
  31. template <typename... Args>
  32. cli & register_callback(std::string const & handle,
  33. std::function<void(Args...)> cb);
  34. template <typename F>
  35. cli & register_callback(std::string const & handle, F && cb) {
  36. return register_callback(handle, lambdas::FFL(cb));
  37. }
  38. template <typename T>
  39. cli & register_query(std::string const & handle, std::function<T()> cb);
  40. template <typename F>
  41. cli & register_query(std::string const & handle, F && cb) {
  42. return register_query(handle, lambdas::FFL(cb));
  43. }
  44. void run() const;
  45. template <typename T, size_t I>
  46. static auto from_string(std::string const & value) {
  47. using E = std::tuple_element_t<I, T>;
  48. using V = std::remove_cv_t<std::remove_reference_t<E>>;
  49. return from_string<V>(value);
  50. }
  51. private:
  52. bool active() const;
  53. template <typename T> static T from_string(std::string const &);
  54. };
  55. template <typename... Args, size_t... Is>
  56. void cli_invoke(std::function<void(Args...)> cb, cli::args_t const & args,
  57. std::index_sequence<Is...>) {
  58. using tuple = std::tuple<Args...>;
  59. cb(cli::from_string<tuple, Is>(args[Is])...);
  60. }
  61. template <typename... Args>
  62. cli & cli::register_callback(std::string const & handle,
  63. std::function<void(Args...)> cb) {
  64. arguments_.emplace(handle, sizeof...(Args));
  65. callbacks_.emplace(handle, [=](args_t const & args) {
  66. if (sizeof...(Args) > args.size()) {
  67. std::cerr << "Missing Args in command '" << handle << "', " <<
  68. sizeof...(Args) << " required, but " << args.size() << " input\n";
  69. return;
  70. }
  71. cli_invoke(cb, args, std::make_index_sequence<sizeof...(Args)>());
  72. });
  73. return *this;
  74. }
  75. template <typename T> void cli_print(T const & value) {
  76. if constexpr (detail::is_container_v<T> && !detail::is_string_v<T>) {
  77. using ::cli::cli_print;
  78. for (auto & elem : value) {
  79. cli_print(elem);
  80. }
  81. } else {
  82. std::cout << " " << value << "\n";
  83. }
  84. }
  85. template <typename T>
  86. cli & cli::register_query(std::string const & handle, std::function<T()> cb) {
  87. arguments_.emplace(handle, 0);
  88. callbacks_.emplace(handle, [=](args_t const & args) {
  89. using ::cli::cli_print;
  90. cli_print(cb());
  91. });
  92. return *this;
  93. }
  94. }