diff --git a/src/commands.cc b/src/commands.cc index 49381975..54e1a40e 100644 --- a/src/commands.cc +++ b/src/commands.cc @@ -790,7 +790,8 @@ const CommandDesc add_hook_cmd = { " (and any window for that buffer)\n" " * window: hook is executed only for the current window\n", ParameterDesc{ - { { "group", { true, "set hook group, see remove-hooks" } } }, + { { "group", { true, "set hook group, see remove-hooks" } }, + { "always", { false, "run hook even if hooks are disabled" } }}, ParameterDesc::Flags::None, 4, 4 }, CommandFlags::None, @@ -808,7 +809,10 @@ const CommandDesc add_hook_cmd = { Regex regex{parser[2], RegexCompileFlags::Optimize}; const String& command = parser[3]; auto group = parser.get_switch("group").value_or(StringView{}); - get_scope(parser[0], context).hooks().add_hook(parser[1], group.str(), std::move(regex), command); + get_scope(parser[0], context).hooks().add_hook(parser[1], group.str(), + parser.get_switch("always") ? + HookFlags::Always : HookFlags::None, + std::move(regex), command); } }; diff --git a/src/hook_manager.cc b/src/hook_manager.cc index b869c261..d0100467 100644 --- a/src/hook_manager.cc +++ b/src/hook_manager.cc @@ -16,6 +16,7 @@ namespace Kakoune struct HookManager::Hook { String group; + HookFlags flags; Regex filter; String commands; }; @@ -24,10 +25,10 @@ HookManager::HookManager() : m_parent(nullptr) {} HookManager::HookManager(HookManager& parent) : SafeCountable{}, m_parent(&parent) {} HookManager::~HookManager() = default; -void HookManager::add_hook(StringView hook_name, String group, Regex filter, String commands) +void HookManager::add_hook(StringView hook_name, String group, HookFlags flags, Regex filter, String commands) { auto& hooks = m_hooks[hook_name]; - hooks.emplace_back(new Hook{std::move(group), std::move(filter), std::move(commands)}); + hooks.emplace_back(new Hook{std::move(group), flags, std::move(filter), std::move(commands)}); } void HookManager::remove_hooks(StringView group) @@ -63,8 +64,7 @@ CandidateList HookManager::complete_hook_group(StringView prefix, ByteCount pos_ void HookManager::run_hook(StringView hook_name, StringView param, Context& context) const { - if (context.hooks_disabled()) - return; + const bool only_always = context.hooks_disabled(); if (m_parent) m_parent->run_hook(hook_name, param, context); @@ -98,7 +98,8 @@ void HookManager::run_hook(StringView hook_name, StringView param, Context& cont for (auto& hook : hook_list->value) { MatchResults captures; - if ((hook->group.empty() or disabled_hooks.empty() or + if ((not only_always or (hook->flags & HookFlags::Always)) and + (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(), captures, hook->filter)) hooks_to_run.push_back({ hook.get(), std::move(captures) }); diff --git a/src/hook_manager.hh b/src/hook_manager.hh index 215cdeb8..44fb9107 100644 --- a/src/hook_manager.hh +++ b/src/hook_manager.hh @@ -11,13 +11,21 @@ namespace Kakoune class Context; class Regex; +enum class HookFlags +{ + None = 0, + Always = 1 << 0 +}; +constexpr bool with_bit_ops(Meta::Type) { return true; } + class HookManager : public SafeCountable { public: HookManager(HookManager& parent); ~HookManager(); - void add_hook(StringView hook_name, String group, Regex filter, String commands); + void add_hook(StringView hook_name, String group, HookFlags flags, + 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,