cli.h 2.7 KB

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