command_system.hpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. #pragma once
  2. #include <string>
  3. #include <vector>
  4. #include <functional>
  5. #include <unordered_map>
  6. #include <optional>
  7. #include <variant>
  8. #include "lumacs/i_command_target.hpp" // New include for ICommandTarget
  9. // #include "lumacs/editor_core.hpp" // Required for EditorCore definition - moved to .cpp
  10. namespace lumacs {
  11. class EditorCore; // Forward declaration
  12. class MinibufferManager; // Forward declare MinibufferManager for interactive args
  13. /// @brief Defines the status of a command execution.
  14. enum class CommandStatus {
  15. Success,
  16. Failure,
  17. PendingInput // Indicates the command is waiting for user input
  18. };
  19. /// @brief Represents the result of a command execution.
  20. struct CommandResult {
  21. CommandStatus status;
  22. std::string message;
  23. // Potentially add more fields, like return value, error code, etc.
  24. };
  25. /// @brief Context object passed to command functions for argument access and interaction.
  26. class CommandContext {
  27. public:
  28. CommandContext(ICommandTarget& target, MinibufferManager& minibuffer_manager, const std::vector<std::string>& args)
  29. : target_(target), minibuffer_manager_(minibuffer_manager), args_(args) {} // Corrected initializer list order
  30. /// @brief Get argument at index as string.
  31. std::optional<std::string> get_string_arg(size_t index) const;
  32. /// @brief Get argument at index as integer.
  33. std::optional<int> get_int_arg(size_t index) const;
  34. // TODO: Add more typed accessors as needed (bool, double, etc.)
  35. /// @brief Prompts the user for a string argument.
  36. std::optional<std::string> read_string(const std::string& prompt);
  37. /// @brief Prompts the user for a file path.
  38. std::optional<std::string> read_file_path(const std::string& prompt);
  39. // Access to core components for command logic
  40. ICommandTarget& target() { return target_; }
  41. /// @brief Get all gathered arguments.
  42. [[nodiscard]] const std::vector<std::string>& get_args() const { return args_; }
  43. private:
  44. ICommandTarget& target_; // Declared first
  45. MinibufferManager& minibuffer_manager_; // Declared second
  46. std::vector<std::string> args_; // Declared third
  47. };
  48. /// @brief Type for command functions.
  49. /// Commands take a CommandContext reference and return a CommandResult.
  50. using CommandFunction = std::function<CommandResult(CommandContext&)>;
  51. /// @brief Represents a single command.
  52. struct Command {
  53. std::string name;
  54. CommandFunction function;
  55. std::string doc_string; // Documentation for the command
  56. bool interactive; // Whether the command can be called interactively (e.g., via M-x)
  57. std::string interactive_spec; // Emacs-like interactive spec for argument gathering
  58. std::vector<std::string> aliases; // New: list of alias names for this command
  59. Command(std::string name, CommandFunction func, std::string doc = "", bool interactive = false, std::string i_spec = "", std::vector<std::string> aliases = {})
  60. : name(std::move(name)), function(std::move(func)), doc_string(std::move(doc)), interactive(interactive), interactive_spec(std::move(i_spec)), aliases(std::move(aliases)) {}
  61. };
  62. /// @brief Manages the registration and execution of editor commands.
  63. class CommandSystem {
  64. public:
  65. explicit CommandSystem(EditorCore& core, MinibufferManager& minibuffer_manager);
  66. /// @brief Registers a command with the system.
  67. void register_command(const std::string& name, CommandFunction function,
  68. const std::string& doc_string = "", bool interactive = false,
  69. std::string interactive_spec = "", std::vector<std::string> aliases = {});
  70. /// @brief Clears all registered commands and aliases.
  71. void clear_commands();
  72. /// @brief Executes a command by name with given arguments.
  73. /// @param name The name of the command to execute.
  74. /// @param args Arguments for the command.
  75. /// @return CommandResult indicating success/failure and a message.
  76. CommandResult execute(const std::string& name, const std::vector<std::string>& args);
  77. /// @brief Get a list of all registered command names.
  78. std::vector<std::string> get_command_names() const;
  79. /// @brief Get documentation for a specific command.
  80. std::optional<std::string> get_command_doc_string(const std::string& name) const;
  81. /// @brief Get the interactive spec for a specific command.
  82. std::optional<std::string> get_command_interactive_spec(const std::string& name) const;
  83. /// @brief Executes a command interactively, prompting the user for arguments if needed.
  84. /// @param name The name of the command to execute.
  85. /// @return CommandResult indicating success/failure and a message, or a pending state.
  86. CommandResult execute_interactive(const std::string& name);
  87. private:
  88. EditorCore& core_; // Reference to EditorCore
  89. MinibufferManager& minibuffer_manager_; // Reference to MinibufferManager
  90. std::unordered_map<std::string, Command> commands_;
  91. std::unordered_map<std::string, std::string> alias_map_; // Maps alias to canonical command name
  92. // State for interactive command execution
  93. std::optional<Command> current_interactive_command_;
  94. size_t current_interactive_spec_index_ = 0;
  95. std::vector<std::string> gathered_interactive_args_;
  96. CommandResult process_next_interactive_argument();
  97. };
  98. } // namespace lumacs