From 63191f1900fe805db49654605ffe4eba9fc547b9 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Fri, 16 Sep 2011 09:18:51 +0000 Subject: [PATCH] CommandManager: support per command configurable completion --- src/command_manager.cc | 56 +++++++++++++++++++++++++++++++++--------- src/command_manager.hh | 43 +++++++++++++++++++++++++++++--- 2 files changed, 85 insertions(+), 14 deletions(-) diff --git a/src/command_manager.cc b/src/command_manager.cc index 26751db4..791b1f94 100644 --- a/src/command_manager.cc +++ b/src/command_manager.cc @@ -1,20 +1,24 @@ #include "command_manager.hh" #include "utils.hh" +#include "assert.hh" + #include namespace Kakoune { -void CommandManager::register_command(const std::string& command_name, Command command) +void CommandManager::register_command(const std::string& command_name, Command command, + const CommandCompleter& completer) { - m_commands[command_name] = command; + m_commands[command_name] = CommandAndCompleter { command, completer }; } -void CommandManager::register_command(const std::vector& command_names, Command command) +void CommandManager::register_command(const std::vector& command_names, Command command, + const CommandCompleter& completer) { for (auto command_name : command_names) - register_command(command_name, command); + register_command(command_name, command, completer); } typedef std::vector> TokenList; @@ -65,7 +69,7 @@ void CommandManager::execute(const std::string& command_line) it->second - it->first)); } - command_it->second(params); + command_it->second.command(params); } Completions CommandManager::complete(const std::string& command_line, size_t cursor_pos) @@ -96,14 +100,44 @@ Completions CommandManager::complete(const std::string& command_line, size_t cur return result; } - if (token_to_complete == 1) // filename completion + + assert(not tokens.empty()); + std::string command_name = + command_line.substr(tokens[0].first, + tokens[0].second - tokens[0].first); + + auto command_it = m_commands.find(command_name); + if (command_it == m_commands.end() or not command_it->second.completer) + return Completions(); + + CommandParameters params; + for (auto it = tokens.begin() + 1; it != tokens.end(); ++it) { - Completions result(tokens[1].first, cursor_pos); - std::string prefix = command_line.substr(tokens[1].first, cursor_pos); - result.candidates = complete_filename(prefix); - return result; + params.push_back(command_line.substr(it->first, + it->second - it->first)); } - return Completions(cursor_pos, cursor_pos); + Completions result(tokens[token_to_complete].first, cursor_pos); + size_t cursor_pos_in_token = cursor_pos - tokens[token_to_complete].first; + + result.candidates = command_it->second.completer(params, + token_to_complete - 1, + cursor_pos_in_token); + return result; +} + +CandidateList PerArgumentCommandCompleter::operator()(const CommandParameters& params, + size_t token_to_complete, + size_t pos_in_token) const +{ + if (token_to_complete >= m_completers.size()) + return CandidateList(); + + // it is possible to try to complete a new argument + assert(token_to_complete <= params.size()); + + const std::string& argument = token_to_complete < params.size() ? + params[token_to_complete] : std::string(); + return m_completers[token_to_complete](argument, pos_in_token); } } diff --git a/src/command_manager.hh b/src/command_manager.hh index e46c5a77..037ec2c9 100644 --- a/src/command_manager.hh +++ b/src/command_manager.hh @@ -5,6 +5,7 @@ #include #include #include +#include #include "exception.hh" #include "completion.hh" @@ -20,17 +21,53 @@ struct wrong_argument_count : runtime_error typedef std::vector CommandParameters; typedef std::function Command; +typedef std::function CommandCompleter; + +class PerArgumentCommandCompleter +{ +public: + typedef std::function ArgumentCompleter; + typedef std::vector ArgumentCompleterList; + + PerArgumentCommandCompleter(const ArgumentCompleterList& completers) + : m_completers(completers) {} + + PerArgumentCommandCompleter(ArgumentCompleterList&& completers) + : m_completers(completers) {} + + PerArgumentCommandCompleter(std::initializer_list completers) + : m_completers(completers) {} + + CandidateList operator()(const CommandParameters& params, + size_t token_to_complete, + size_t pos_in_token) const; + +private: + ArgumentCompleterList m_completers; +}; + class CommandManager { public: void execute(const std::string& command_line); Completions complete(const std::string& command_line, size_t cursor_pos); - void register_command(const std::string& command_name, Command command); - void register_command(const std::vector& command_names, Command command); + void register_command(const std::string& command_name, + Command command, + const CommandCompleter& completer = CommandCompleter()); + + void register_command(const std::vector& command_names, + Command command, + const CommandCompleter& completer = CommandCompleter()); private: - std::unordered_map m_commands; + struct CommandAndCompleter + { + Command command; + CommandCompleter completer; + }; + std::unordered_map m_commands; }; }