summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMaxime Coste <frrrwww@gmail.com>2011-09-16 09:18:51 +0000
committerMaxime Coste <frrrwww@gmail.com>2011-09-16 09:18:51 +0000
commit63191f1900fe805db49654605ffe4eba9fc547b9 (patch)
treee95e732c939611c27dfd4d5ff83cfe1456d4e625 /src
parentaeea1c610c5a6e5a8062166919cc5affece8f55d (diff)
CommandManager: support per command configurable completion
Diffstat (limited to 'src')
-rw-r--r--src/command_manager.cc56
-rw-r--r--src/command_manager.hh43
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 <algorithm>
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)
- register_command(command_name, command);
+ register_command(command_name, command, completer);
}
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));
}
- 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 <vector>
#include <unordered_map>
#include <functional>
+#include <initializer_list>
#include "exception.hh"
#include "completion.hh"
@@ -20,17 +21,53 @@ struct wrong_argument_count : runtime_error
typedef std::vector<std::string> CommandParameters;
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
{
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<std::string>& command_names, Command command);
+ void register_command(const std::string& command_name,
+ Command command,
+ const CommandCompleter& completer = CommandCompleter());
+
+ void register_command(const std::vector<std::string>& command_names,
+ Command command,
+ const CommandCompleter& completer = CommandCompleter());
private:
- std::unordered_map<std::string, Command> m_commands;
+ struct CommandAndCompleter
+ {
+ Command command;
+ CommandCompleter completer;
+ };
+ std::unordered_map<std::string, CommandAndCompleter> m_commands;
};
}