Hooks can have an (shareable) identifier, and thus be removed

This commit is contained in:
Maxime Coste 2013-04-11 14:29:10 +02:00
parent 172f46f679
commit 107e95622d
3 changed files with 41 additions and 22 deletions

View File

@ -73,7 +73,7 @@ Buffer* open_fifo(const String& name , const String& filename, Context& context)
} }
}); });
buffer->hooks().add_hook("BufClose", buffer->hooks().add_hook("BufClose", "",
[buffer, watcher](const String&, const Context&) { [buffer, watcher](const String&, const Context&) {
// Check if fifo is still alive, else watcher is already dead // Check if fifo is still alive, else watcher is already dead
if (buffer->flags() & Buffer::Flags::Fifo) if (buffer->flags() & Buffer::Flags::Fifo)
@ -313,30 +313,36 @@ void rm_filter(const CommandParameters& params, Context& context)
group.remove(parser[0]); group.remove(parser[0]);
} }
static HookManager& get_hook_manager(const String& scope, Context& context)
{
if (scope == "global")
return GlobalHooks::instance();
else if (scope == "buffer")
return context.buffer().hooks();
else if (scope == "window")
return context.window().hooks();
throw runtime_error("error: no such hook container " + scope);
}
void add_hook(const CommandParameters& params, Context& context) void add_hook(const CommandParameters& params, Context& context)
{ {
if (params.size() != 4) ParametersParser parser(params, { { "id", true } }, ParametersParser::Flags::None, 4, 4);
throw wrong_argument_count();
// copy so that the lambda gets a copy as well // copy so that the lambda gets a copy as well
Regex regex(params[2].begin(), params[2].end()); Regex regex(parser[2].begin(), parser[2].end());
String command = params[3]; String command = parser[3];
auto hook_func = [=](const String& param, Context& context) { auto hook_func = [=](const String& param, Context& context) {
if (boost::regex_match(param.begin(), param.end(), regex)) if (boost::regex_match(param.begin(), param.end(), regex))
CommandManager::instance().execute(command, context, {}, CommandManager::instance().execute(command, context, {},
{ { "hook_param", param } }); { { "hook_param", param } });
}; };
String id = parser.has_option("id") ? parser.option_value("id") : "";
get_hook_manager(parser[0], context).add_hook(parser[1], id, hook_func);
}
const String& scope = params[0]; void rm_hooks(const CommandParameters& params, Context& context)
const String& name = params[1]; {
if (scope == "global") ParametersParser parser(params, {}, ParametersParser::Flags::None, 2, 2);
GlobalHooks::instance().add_hook(name, hook_func); get_hook_manager(parser[0], context).remove_hooks(parser[1]);
else if (scope == "buffer")
context.buffer().hooks().add_hook(name, hook_func);
else if (scope == "window")
context.window().hooks().add_hook(name , hook_func);
else
throw runtime_error("error: no such hook container " + scope);
} }
EnvVarMap params_to_env_var_map(const CommandParameters& params) EnvVarMap params_to_env_var_map(const CommandParameters& params)
@ -895,6 +901,7 @@ void register_commands()
cm.register_commands({ "rf", "rmfilter" }, rm_filter, group_rm_completer(get_filters)); cm.register_commands({ "rf", "rmfilter" }, rm_filter, group_rm_completer(get_filters));
cm.register_command("hook", add_hook); cm.register_command("hook", add_hook);
cm.register_command("rmhooks", rm_hooks);
cm.register_command("source", exec_commands_in_file, filename_completer); cm.register_command("source", exec_commands_in_file, filename_completer);

View File

@ -5,9 +5,18 @@
namespace Kakoune namespace Kakoune
{ {
void HookManager::add_hook(const String& hook_name, HookFunc hook) void HookManager::add_hook(const String& hook_name, String id, HookFunc hook)
{ {
m_hook[hook_name].push_back(hook); auto& hooks = m_hook[hook_name];
hooks.append({std::move(id), std::move(hook)});
}
void HookManager::remove_hooks(const String& id)
{
if (id.empty())
throw runtime_error("invalid id");
for (auto& hooks : m_hook)
hooks.second.remove_all(id);
} }
void HookManager::run_hook(const String& hook_name, void HookManager::run_hook(const String& hook_name,
@ -25,11 +34,12 @@ void HookManager::run_hook(const String& hook_name,
{ {
try try
{ {
hook(param, context); hook.second(param, context);
} }
catch (runtime_error& err) catch (runtime_error& err)
{ {
write_debug("error running hook " + hook_name + ": " + err.what()); write_debug("error running hook " + hook_name + "/" +
hook.first + ": " + err.what());
} }
} }
} }

View File

@ -1,6 +1,7 @@
#ifndef hook_manager_hh_INCLUDED #ifndef hook_manager_hh_INCLUDED
#define hook_manager_hh_INCLUDED #define hook_manager_hh_INCLUDED
#include "idvaluemap.hh"
#include "utils.hh" #include "utils.hh"
#include <unordered_map> #include <unordered_map>
@ -16,7 +17,8 @@ class HookManager
public: public:
HookManager(HookManager& parent) : m_parent(&parent) {} HookManager(HookManager& parent) : m_parent(&parent) {}
void add_hook(const String& hook_name, HookFunc hook); void add_hook(const String& hook_name, String id, HookFunc hook);
void remove_hooks(const String& id);
void run_hook(const String& hook_name, const String& param, void run_hook(const String& hook_name, const String& param,
Context& context) const; Context& context) const;
@ -27,7 +29,7 @@ private:
friend class GlobalHooks; friend class GlobalHooks;
HookManager* m_parent; HookManager* m_parent;
std::unordered_map<String, std::vector<HookFunc>> m_hook; std::unordered_map<String, idvaluemap<String, HookFunc>> m_hook;
}; };
class GlobalHooks : public HookManager, class GlobalHooks : public HookManager,