CommandManager: support per command configurable completion

This commit is contained in:
Maxime Coste 2011-09-16 09:18:51 +00:00
parent aeea1c610c
commit 63191f1900
2 changed files with 85 additions and 14 deletions

View File

@ -1,20 +1,24 @@
#include "command_manager.hh" #include "command_manager.hh"
#include "utils.hh" #include "utils.hh"
#include "assert.hh"
#include <algorithm> #include <algorithm>
namespace Kakoune 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<std::string>& command_names, Command command) void CommandManager::register_command(const std::vector<std::string>& command_names, Command command,
const CommandCompleter& completer)
{ {
for (auto command_name : command_names) for (auto command_name : command_names)
register_command(command_name, command); register_command(command_name, command, completer);
} }
typedef std::vector<std::pair<size_t, size_t>> TokenList; typedef std::vector<std::pair<size_t, size_t>> TokenList;
@ -65,7 +69,7 @@ void CommandManager::execute(const std::string& command_line)
it->second - it->first)); 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) 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; 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); params.push_back(command_line.substr(it->first,
std::string prefix = command_line.substr(tokens[1].first, cursor_pos); it->second - it->first));
result.candidates = complete_filename(prefix); }
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; return result;
} }
return Completions(cursor_pos, cursor_pos);
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);
} }
} }

View File

@ -5,6 +5,7 @@
#include <vector> #include <vector>
#include <unordered_map> #include <unordered_map>
#include <functional> #include <functional>
#include <initializer_list>
#include "exception.hh" #include "exception.hh"
#include "completion.hh" #include "completion.hh"
@ -20,17 +21,53 @@ struct wrong_argument_count : runtime_error
typedef std::vector<std::string> CommandParameters; typedef std::vector<std::string> CommandParameters;
typedef std::function<void (const CommandParameters&)> Command; typedef std::function<void (const CommandParameters&)> Command;
typedef std::function<CandidateList (const CommandParameters&,
size_t, size_t)> CommandCompleter;
class PerArgumentCommandCompleter
{
public:
typedef std::function<CandidateList (const std::string&, size_t)> ArgumentCompleter;
typedef std::vector<ArgumentCompleter> ArgumentCompleterList;
PerArgumentCommandCompleter(const ArgumentCompleterList& completers)
: m_completers(completers) {}
PerArgumentCommandCompleter(ArgumentCompleterList&& completers)
: m_completers(completers) {}
PerArgumentCommandCompleter(std::initializer_list<ArgumentCompleter> 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 class CommandManager
{ {
public: public:
void execute(const std::string& command_line); void execute(const std::string& command_line);
Completions complete(const std::string& command_line, size_t cursor_pos); 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::string& command_name,
void register_command(const std::vector<std::string>& command_names, Command command); Command command,
const CommandCompleter& completer = CommandCompleter());
void register_command(const std::vector<std::string>& command_names,
Command command,
const CommandCompleter& completer = CommandCompleter());
private: private:
std::unordered_map<std::string, Command> m_commands; struct CommandAndCompleter
{
Command command;
CommandCompleter completer;
};
std::unordered_map<std::string, CommandAndCompleter> m_commands;
}; };
} }