src: Allow hooks to be run only once

This commit implements the -once flag on the `:hook` command, which
automatically removes a hook after it was run, to avoid having to
declare a group and remove it in the hook implementation.

Closes #2277
This commit is contained in:
Frank LENORMAND 2018-08-02 12:52:48 +03:00
parent ae75032936
commit e84dcf72c0
3 changed files with 20 additions and 8 deletions

View File

@ -842,7 +842,8 @@ const CommandDesc add_hook_cmd = {
" * window: hook is executed only for the current window\n", " * window: hook is executed only for the current window\n",
ParameterDesc{ 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" } }}, { "always", { false, "run hook even if hooks are disabled" } },
{ "once", { false, "run the hook only once" } } },
ParameterDesc::Flags::None, 4, 4 ParameterDesc::Flags::None, 4, 4
}, },
CommandFlags::None, CommandFlags::None,
@ -860,9 +861,9 @@ const CommandDesc add_hook_cmd = {
Regex regex{parser[2], RegexCompileFlags::Optimize}; Regex regex{parser[2], RegexCompileFlags::Optimize};
const String& command = parser[3]; const String& command = parser[3];
auto group = parser.get_switch("group").value_or(StringView{}); auto group = parser.get_switch("group").value_or(StringView{});
get_scope(parser[0], context).hooks().add_hook(parser[1], group.str(), const auto flags = (parser.get_switch("always") ? HookFlags::Always : HookFlags::None) \
parser.get_switch("always") ? | (parser.get_switch("once") ? HookFlags::Once : HookFlags::None);
HookFlags::Always : HookFlags::None, get_scope(parser[0], context).hooks().add_hook(parser[1], group.str(), flags,
std::move(regex), command); std::move(regex), command);
} }
}; };

View File

@ -63,7 +63,7 @@ CandidateList HookManager::complete_hook_group(StringView prefix, ByteCount pos_
return res; return res;
} }
void HookManager::run_hook(StringView hook_name, StringView param, Context& context) const void HookManager::run_hook(StringView hook_name, StringView param, Context& context)
{ {
const bool only_always = context.hooks_disabled(); const bool only_always = context.hooks_disabled();
@ -123,6 +123,16 @@ void HookManager::run_hook(StringView hook_name, StringView param, Context& cont
CommandManager::instance().execute(to_run.hook->commands, context, CommandManager::instance().execute(to_run.hook->commands, context,
{ {}, std::move(env_vars) }); { {}, std::move(env_vars) });
if (to_run.hook->flags & HookFlags::Once)
{
auto it = std::find_if(hook_list->value.begin(), hook_list->value.end(),
[&](const std::unique_ptr<Hook>& h)
{ return h.get() == to_run.hook; });
m_hooks_trash.push_back(std::move(*it));
hook_list->value.erase(it);
}
} }
catch (runtime_error& err) catch (runtime_error& err)
{ {

View File

@ -14,7 +14,8 @@ class Regex;
enum class HookFlags enum class HookFlags
{ {
None = 0, None = 0,
Always = 1 << 0 Always = 1 << 0,
Once = 1 << 1
}; };
constexpr bool with_bit_ops(Meta::Type<HookFlags>) { return true; } constexpr bool with_bit_ops(Meta::Type<HookFlags>) { return true; }
@ -29,7 +30,7 @@ public:
void remove_hooks(StringView group); void remove_hooks(StringView group);
CandidateList complete_hook_group(StringView prefix, ByteCount pos_in_token); CandidateList complete_hook_group(StringView prefix, ByteCount pos_in_token);
void run_hook(StringView hook_name, StringView param, void run_hook(StringView hook_name, StringView param,
Context& context) const; Context& context);
private: private:
HookManager(); HookManager();