diff --git a/src/commands.cc b/src/commands.cc index 17570843..9ba39591 100644 --- a/src/commands.cc +++ b/src/commands.cc @@ -805,24 +805,8 @@ const CommandDesc add_hook_cmd = { Regex regex{parser[2], Regex::optimize | Regex::ECMAScript}; const String& command = parser[3]; - - auto hook_func = [=](StringView param, Context& context) { - ScopedSetBool disable_history{context.history_disabled()}; - - MatchResults res; - if (not regex_match(param.begin(), param.end(), res, regex)) - return; - - EnvVarMap env_vars{ {"hook_param", param.str()} }; - for (size_t i = 0; i < res.size(); ++i) - env_vars.insert({format("hook_param_capture_{}", i), - {res[i].first, res[i].second}}); - - CommandManager::instance().execute(command, context, - { {}, std::move(env_vars) }); - }; auto group = parser.get_switch("group").value_or(StringView{}); - get_scope(parser[0], context).hooks().add_hook(parser[1], group.str(), std::move(hook_func)); + get_scope(parser[0], context).hooks().add_hook(parser[1], group.str(), std::move(regex), command); } }; diff --git a/src/hook_manager.cc b/src/hook_manager.cc index 9a412373..52da2d28 100644 --- a/src/hook_manager.cc +++ b/src/hook_manager.cc @@ -6,16 +6,17 @@ #include "buffer_utils.hh" #include "display_buffer.hh" #include "face_registry.hh" +#include "command_manager.hh" #include "regex.hh" #include "option.hh" namespace Kakoune { -void HookManager::add_hook(StringView hook_name, String group, HookFunc func) +void HookManager::add_hook(StringView hook_name, String group, Regex filter, String commands) { auto& hooks = m_hooks[hook_name]; - hooks.emplace_back(new Hook{std::move(group), std::move(func)}); + hooks.emplace_back(new Hook{std::move(group), std::move(filter), {}, std::move(commands)}); } void HookManager::remove_hooks(StringView group) @@ -84,8 +85,9 @@ void HookManager::run_hook(StringView hook_name, Vector hooks_to_run; // The m_hooks_trash vector ensure hooks wont die during this method for (auto& hook : hook_list->value) { - if (hook->group.empty() or disabled_hooks.empty() or - not regex_match(hook->group.begin(), hook->group.end(), disabled_hooks)) + if ((hook->group.empty() or disabled_hooks.empty() or + not regex_match(hook->group.begin(), hook->group.end(), disabled_hooks)) + and regex_match(param.begin(), param.end(), hook->captures, hook->filter)) hooks_to_run.push_back(hook.get()); } @@ -96,7 +98,16 @@ void HookManager::run_hook(StringView hook_name, { if (debug_flags & DebugFlags::Hooks) write_to_debug_buffer(format("hook {}({})/{}", hook_name, param, hook->group)); - hook->func(param, context); + + ScopedSetBool disable_history{context.history_disabled()}; + + EnvVarMap env_vars{ {"hook_param", param.str()} }; + for (size_t i = 0; i < hook->captures.size(); ++i) + env_vars.insert({format("hook_param_capture_{}", i), + {hook->captures[i].first, hook->captures[i].second}}); + + CommandManager::instance().execute(hook->commands, context, + { {}, std::move(env_vars) }); } catch (runtime_error& err) { diff --git a/src/hook_manager.hh b/src/hook_manager.hh index e2e238ea..8614b7a5 100644 --- a/src/hook_manager.hh +++ b/src/hook_manager.hh @@ -4,19 +4,19 @@ #include "hash_map.hh" #include "completion.hh" #include "safe_ptr.hh" +#include "regex.hh" namespace Kakoune { class Context; -using HookFunc = std::function; class HookManager : public SafeCountable { public: HookManager(HookManager& parent) : m_parent(&parent) {} - void add_hook(StringView hook_name, String group, HookFunc func); + void add_hook(StringView hook_name, String group, Regex filter, String commands); void remove_hooks(StringView group); CandidateList complete_hook_group(StringView prefix, ByteCount pos_in_token); void run_hook(StringView hook_name, StringView param, @@ -31,7 +31,9 @@ private: struct Hook { String group; - HookFunc func; + Regex filter; + MatchResults captures; + String commands; }; SafePtr m_parent;