#pragma once #include #include #include #include #include #include namespace lumacs { class EditorCore; // Forward declaration /// @brief Result of command execution. struct CommandResult { bool success; std::string message; CommandResult(bool s = true, std::string msg = "") : success(s), message(std::move(msg)) {} }; /// @brief Function signature for executable commands. /// Takes a vector of string arguments and returns a CommandResult. using CommandFunction = std::function&)>; /// @brief Metadata and implementation of a named command. struct Command { std::string name; ///< Unique command name (e.g., "find-file"). std::string description; ///< Human-readable help text. CommandFunction function; ///< The implementation function. std::vector aliases; ///< Alternative names. bool interactive; ///< Whether this command can be called interactively (M-x). Command(std::string n, std::string desc, CommandFunction func, std::vector alias = {}, bool inter = true) : name(std::move(n)), description(std::move(desc)), function(std::move(func)), aliases(std::move(alias)), interactive(inter) {} }; /// @brief A possible completion match for user input. struct CompletionCandidate { std::string text; ///< The completion text. int score; ///< Matching score (higher is better). std::string description;///< Extra info (e.g., file type, command desc). CompletionCandidate(std::string t, int s = 0, std::string desc = "") : text(std::move(t)), score(s), description(std::move(desc)) {} bool operator<(const CompletionCandidate& other) const { if (score != other.score) return score > other.score; // Higher score first return text < other.text; // Alphabetical for same score } }; /// @brief Provider function for generating completions. using CompletionProvider = std::function(const std::string& input)>; /// @brief Utility class for filesystem completions. class FileSystemCompletionProvider { public: /// @brief Complete paths (files and directories) relative to CWD or absolute. std::vector complete_path(const std::string& input) const; /// @brief Complete directory paths only. std::vector complete_directory(const std::string& input) const; /// @brief Complete files, optionally filtered by extension. std::vector complete_file(const std::string& input, const std::vector& extensions = {}) const; private: bool is_absolute_path(const std::string& path) const; std::string normalize_path(const std::string& path) const; int calculate_path_score(const std::string& candidate, const std::string& input) const; }; /// @brief Central registry for commands and completion logic. /// /// The CommandSystem manages: /// - Registration of named commands. /// - Execution of commands by name. /// - Parsing of command strings. /// - Autocompletion providers for different contexts (M-x, Find File, etc.). class CommandSystem { public: explicit CommandSystem(EditorCore& core); ~CommandSystem() = default; // === Command Registration === /// @brief Register a command object. void register_command(std::unique_ptr command); /// @brief Helper to register a command. void register_command(const std::string& name, const std::string& description, CommandFunction function, const std::vector& aliases = {}, bool interactive = true); // === Command Execution === /// @brief Execute a named command with arguments. /// @return Result indicating success/failure and message. CommandResult execute(const std::string& command_name, const std::vector& args = {}); /// @brief Parse and execute a raw command string (e.g., "find-file src/main.cpp"). CommandResult execute_string(const std::string& command_string); // === Command Lookup === /// @brief Check if a command exists. bool has_command(const std::string& name) const; /// @brief Get a command by name. std::shared_ptr get_command(const std::string& name) const; /// @brief Get names of all registered commands. std::vector get_all_command_names() const; /// @brief Get names of commands marked as interactive. std::vector get_interactive_command_names() const; // === Completion System === /// @brief Get completions for command names (M-x). std::vector complete_command(const std::string& input) const; /// @brief Get completions for buffer names (C-x b). std::vector complete_buffer_name(const std::string& input) const; /// @brief Get completions for file paths (C-x C-f). std::vector complete_file_path(const std::string& input) const; /// @brief Get completions for theme names. std::vector complete_theme_name(const std::string& input) const; /// @brief Register a custom completion provider for a command argument. void register_completion_provider(const std::string& command_name, CompletionProvider provider); /// @brief Get completions for a specific command's arguments. std::vector get_completions(const std::string& command_name, const std::string& input) const; // === Utilities === /// @brief Calculate fuzzy match score between candidate and input. static int fuzzy_match_score(const std::string& candidate, const std::string& input); /// @brief Check if candidate matches input fuzzily. static bool fuzzy_match(const std::string& candidate, const std::string& input); private: EditorCore& core_; std::unordered_map> commands_; std::unordered_map completion_providers_; FileSystemCompletionProvider fs_provider_; void register_builtin_commands(); std::vector parse_command_string(const std::string& command_string) const; }; } // namespace lumacs