command_system.hpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. #pragma once
  2. #include <string>
  3. #include <functional>
  4. #include <memory>
  5. #include <vector>
  6. #include <unordered_map>
  7. #include <filesystem>
  8. namespace lumacs {
  9. class EditorCore; // Forward declaration
  10. /// @brief Result of command execution.
  11. struct CommandResult {
  12. bool success;
  13. std::string message;
  14. CommandResult(bool s = true, std::string msg = "")
  15. : success(s), message(std::move(msg)) {}
  16. };
  17. /// @brief Function signature for executable commands.
  18. /// Takes a vector of string arguments and returns a CommandResult.
  19. using CommandFunction = std::function<CommandResult(const std::vector<std::string>&)>;
  20. /// @brief Metadata and implementation of a named command.
  21. struct Command {
  22. std::string name; ///< Unique command name (e.g., "find-file").
  23. std::string description; ///< Human-readable help text.
  24. CommandFunction function; ///< The implementation function.
  25. std::vector<std::string> aliases; ///< Alternative names.
  26. bool interactive; ///< Whether this command can be called interactively (M-x).
  27. Command(std::string n, std::string desc, CommandFunction func,
  28. std::vector<std::string> alias = {}, bool inter = true)
  29. : name(std::move(n)), description(std::move(desc)),
  30. function(std::move(func)), aliases(std::move(alias)), interactive(inter) {}
  31. };
  32. /// @brief A possible completion match for user input.
  33. struct CompletionCandidate {
  34. std::string text; ///< The completion text.
  35. int score; ///< Matching score (higher is better).
  36. std::string description;///< Extra info (e.g., file type, command desc).
  37. CompletionCandidate(std::string t, int s = 0, std::string desc = "")
  38. : text(std::move(t)), score(s), description(std::move(desc)) {}
  39. bool operator<(const CompletionCandidate& other) const {
  40. if (score != other.score) return score > other.score; // Higher score first
  41. return text < other.text; // Alphabetical for same score
  42. }
  43. };
  44. /// @brief Provider function for generating completions.
  45. using CompletionProvider = std::function<std::vector<CompletionCandidate>(const std::string& input)>;
  46. /// @brief Utility class for filesystem completions.
  47. class FileSystemCompletionProvider {
  48. public:
  49. /// @brief Complete paths (files and directories) relative to CWD or absolute.
  50. std::vector<CompletionCandidate> complete_path(const std::string& input) const;
  51. /// @brief Complete directory paths only.
  52. std::vector<CompletionCandidate> complete_directory(const std::string& input) const;
  53. /// @brief Complete files, optionally filtered by extension.
  54. std::vector<CompletionCandidate> complete_file(const std::string& input, const std::vector<std::string>& extensions = {}) const;
  55. private:
  56. bool is_absolute_path(const std::string& path) const;
  57. std::string normalize_path(const std::string& path) const;
  58. int calculate_path_score(const std::string& candidate, const std::string& input) const;
  59. };
  60. /// @brief Central registry for commands and completion logic.
  61. ///
  62. /// The CommandSystem manages:
  63. /// - Registration of named commands.
  64. /// - Execution of commands by name.
  65. /// - Parsing of command strings.
  66. /// - Autocompletion providers for different contexts (M-x, Find File, etc.).
  67. class CommandSystem {
  68. public:
  69. explicit CommandSystem(EditorCore& core);
  70. ~CommandSystem() = default;
  71. // === Command Registration ===
  72. /// @brief Register a command object.
  73. void register_command(std::unique_ptr<Command> command);
  74. /// @brief Helper to register a command.
  75. void register_command(const std::string& name, const std::string& description,
  76. CommandFunction function, const std::vector<std::string>& aliases = {},
  77. bool interactive = true);
  78. // === Command Execution ===
  79. /// @brief Execute a named command with arguments.
  80. /// @return Result indicating success/failure and message.
  81. CommandResult execute(const std::string& command_name, const std::vector<std::string>& args = {});
  82. /// @brief Parse and execute a raw command string (e.g., "find-file src/main.cpp").
  83. CommandResult execute_string(const std::string& command_string);
  84. // === Command Lookup ===
  85. /// @brief Check if a command exists.
  86. bool has_command(const std::string& name) const;
  87. /// @brief Get a command by name.
  88. std::shared_ptr<Command> get_command(const std::string& name) const;
  89. /// @brief Get names of all registered commands.
  90. std::vector<std::string> get_all_command_names() const;
  91. /// @brief Get names of commands marked as interactive.
  92. std::vector<std::string> get_interactive_command_names() const;
  93. // === Completion System ===
  94. /// @brief Get completions for command names (M-x).
  95. std::vector<CompletionCandidate> complete_command(const std::string& input) const;
  96. /// @brief Get completions for buffer names (C-x b).
  97. std::vector<CompletionCandidate> complete_buffer_name(const std::string& input) const;
  98. /// @brief Get completions for file paths (C-x C-f).
  99. std::vector<CompletionCandidate> complete_file_path(const std::string& input) const;
  100. /// @brief Get completions for theme names.
  101. std::vector<CompletionCandidate> complete_theme_name(const std::string& input) const;
  102. /// @brief Register a custom completion provider for a command argument.
  103. void register_completion_provider(const std::string& command_name, CompletionProvider provider);
  104. /// @brief Get completions for a specific command's arguments.
  105. std::vector<CompletionCandidate> get_completions(const std::string& command_name, const std::string& input) const;
  106. // === Utilities ===
  107. /// @brief Calculate fuzzy match score between candidate and input.
  108. static int fuzzy_match_score(const std::string& candidate, const std::string& input);
  109. /// @brief Check if candidate matches input fuzzily.
  110. static bool fuzzy_match(const std::string& candidate, const std::string& input);
  111. private:
  112. EditorCore& core_;
  113. std::unordered_map<std::string, std::shared_ptr<Command>> commands_;
  114. std::unordered_map<std::string, CompletionProvider> completion_providers_;
  115. FileSystemCompletionProvider fs_provider_;
  116. void register_builtin_commands();
  117. std::vector<std::string> parse_command_string(const std::string& command_string) const;
  118. };
  119. } // namespace lumacs