Refactor Hook management to have a well defined list of hooks

Hooks are now an enum class instead of passing strings around.
This commit is contained in:
Maxime Coste 2018-10-23 08:15:53 +11:00
parent e399bf7562
commit dfc11d1c43
15 changed files with 182 additions and 98 deletions

View File

@ -114,16 +114,16 @@ void Buffer::on_registered()
return; return;
} }
run_hook_in_own_context("BufCreate", m_name); run_hook_in_own_context(Hook::BufCreate, m_name);
if (m_flags & Flags::File) if (m_flags & Flags::File)
{ {
if (m_flags & Buffer::Flags::New) if (m_flags & Buffer::Flags::New)
run_hook_in_own_context("BufNewFile", m_name); run_hook_in_own_context(Hook::BufNewFile, m_name);
else else
{ {
kak_assert(m_fs_timestamp != InvalidTime); kak_assert(m_fs_timestamp != InvalidTime);
run_hook_in_own_context("BufOpenFile", m_name); run_hook_in_own_context(Hook::BufOpenFile, m_name);
} }
} }
@ -139,7 +139,7 @@ void Buffer::on_unregistered()
return; return;
options().unregister_watcher(*this); options().unregister_watcher(*this);
run_hook_in_own_context("BufClose", m_name); run_hook_in_own_context(Hook::BufClose, m_name);
} }
Buffer::~Buffer() Buffer::~Buffer()
@ -687,11 +687,11 @@ void Buffer::on_option_changed(const Option& option)
else else
m_flags &= ~Flags::ReadOnly; m_flags &= ~Flags::ReadOnly;
} }
run_hook_in_own_context("BufSetOption", run_hook_in_own_context(Hook::BufSetOption,
format("{}={}", option.name(), option.get_as_string(Quoting::Kakoune))); format("{}={}", option.name(), option.get_as_string(Quoting::Kakoune)));
} }
void Buffer::run_hook_in_own_context(StringView hook_name, StringView param, String client_name) void Buffer::run_hook_in_own_context(Hook hook, StringView param, String client_name)
{ {
if (m_flags & Buffer::Flags::NoHooks) if (m_flags & Buffer::Flags::NoHooks)
return; return;
@ -699,7 +699,7 @@ void Buffer::run_hook_in_own_context(StringView hook_name, StringView param, Str
InputHandler hook_handler{{ *this, Selection{} }, InputHandler hook_handler{{ *this, Selection{} },
Context::Flags::Draft, Context::Flags::Draft,
std::move(client_name)}; std::move(client_name)};
hooks().run_hook(hook_name, param, hook_handler.context()); hooks().run_hook(hook, param, hook_handler.context());
} }
Optional<BufferCoord> Buffer::last_modification_coord() const Optional<BufferCoord> Buffer::last_modification_coord() const

View File

@ -199,7 +199,7 @@ public:
ValueMap& values() const { return m_values; } ValueMap& values() const { return m_values; }
void run_hook_in_own_context(StringView hook_name, StringView param, void run_hook_in_own_context(Hook hook, StringView param,
String client_name = {}); String client_name = {});
void reload(StringView data, timespec fs_timestamp = InvalidTime); void reload(StringView data, timespec fs_timestamp = InvalidTime);

View File

@ -107,7 +107,7 @@ Buffer* create_fifo_buffer(String name, int fd, Buffer::Flags flags, bool scroll
auto watcher_deleter = [buffer](FDWatcher* watcher) { auto watcher_deleter = [buffer](FDWatcher* watcher) {
kak_assert(buffer->flags() & Buffer::Flags::Fifo); kak_assert(buffer->flags() & Buffer::Flags::Fifo);
watcher->close_fd(); watcher->close_fd();
buffer->run_hook_in_own_context("BufCloseFifo", ""); buffer->run_hook_in_own_context(Hook::BufCloseFifo, "");
buffer->flags() &= ~(Buffer::Flags::Fifo | Buffer::Flags::NoUndo); buffer->flags() &= ~(Buffer::Flags::Fifo | Buffer::Flags::NoUndo);
delete watcher; delete watcher;
}; };
@ -157,12 +157,12 @@ Buffer* create_fifo_buffer(String name, int fd, Buffer::Flags flags, bool scroll
} }
while (--loops and fd_readable(fifo)); while (--loops and fd_readable(fifo));
buffer->run_hook_in_own_context("BufReadFifo", buffer->name()); buffer->run_hook_in_own_context(Hook::BufReadFifo, buffer->name());
}), std::move(watcher_deleter)); }), std::move(watcher_deleter));
buffer->values()[fifo_watcher_id] = Value(std::move(watcher)); buffer->values()[fifo_watcher_id] = Value(std::move(watcher));
buffer->flags() = flags | Buffer::Flags::Fifo | Buffer::Flags::NoUndo; buffer->flags() = flags | Buffer::Flags::Fifo | Buffer::Flags::NoUndo;
buffer->run_hook_in_own_context("BufOpenFifo", buffer->name()); buffer->run_hook_in_own_context(Hook::BufOpenFifo, buffer->name());
return buffer; return buffer;
} }

View File

@ -57,7 +57,7 @@ Client::Client(std::unique_ptr<UserInterface>&& ui,
m_pending_keys.push_back(key); m_pending_keys.push_back(key);
}); });
m_window->hooks().run_hook("WinDisplay", m_window->buffer().name(), context()); m_window->hooks().run_hook(Hook::WinDisplay, m_window->buffer().name(), context());
force_redraw(); force_redraw();
} }
@ -91,20 +91,20 @@ bool Client::process_pending_inputs()
context().name(), key_to_str(key))); context().name(), key_to_str(key)));
if (key == Key::FocusIn) if (key == Key::FocusIn)
context().hooks().run_hook("FocusIn", context().name(), context()); context().hooks().run_hook(Hook::FocusIn, context().name(), context());
else if (key == Key::FocusOut) else if (key == Key::FocusOut)
context().hooks().run_hook("FocusOut", context().name(), context()); context().hooks().run_hook(Hook::FocusOut, context().name(), context());
else else
m_input_handler.handle_key(key); m_input_handler.handle_key(key);
context().hooks().run_hook("RawKey", key_to_str(key), context()); context().hooks().run_hook(Hook::RawKey, key_to_str(key), context());
} }
catch (Kakoune::runtime_error& error) catch (Kakoune::runtime_error& error)
{ {
write_to_debug_buffer(format("Error: {}", error.what())); write_to_debug_buffer(format("Error: {}", error.what()));
context().print_status({ fix_atom_text(error.what().str()), context().print_status({ fix_atom_text(error.what().str()),
context().faces()["Error"] }); context().faces()["Error"] });
context().hooks().run_hook("RuntimeError", error.what(), context()); context().hooks().run_hook(Hook::RuntimeError, error.what(), context());
} }
} }
return not keys.empty(); return not keys.empty();
@ -188,7 +188,7 @@ void Client::change_buffer(Buffer& buffer)
context().set_window(*m_window); context().set_window(*m_window);
m_window->set_dimensions(m_ui->dimensions()); m_window->set_dimensions(m_ui->dimensions());
m_window->hooks().run_hook("WinDisplay", buffer.name(), context()); m_window->hooks().run_hook(Hook::WinDisplay, buffer.name(), context());
force_redraw(); force_redraw();
} }
@ -284,7 +284,7 @@ void Client::reload_buffer()
context().print_status({ format("'{}' reloaded", buffer.display_name()), context().print_status({ format("'{}' reloaded", buffer.display_name()),
context().faces()["Information"] }); context().faces()["Information"] });
m_window->hooks().run_hook("BufReload", buffer.name(), context()); m_window->hooks().run_hook(Hook::BufReload, buffer.name(), context());
} }
catch (runtime_error& error) catch (runtime_error& error)
{ {

View File

@ -67,7 +67,7 @@ Client* ClientManager::create_client(std::unique_ptr<UserInterface>&& ui, int pi
{ {
client->context().print_status({ fix_atom_text(error.what().str()), client->context().print_status({ fix_atom_text(error.what().str()),
client->context().faces()["Error"] }); client->context().faces()["Error"] });
client->context().hooks().run_hook("RuntimeError", error.what(), client->context().hooks().run_hook(Hook::RuntimeError, error.what(),
client->context()); client->context());
} }

View File

@ -344,9 +344,9 @@ void do_write_buffer(Context& context, Optional<String> filename, bool sync_file
auto effective_filename = not filename ? buffer.name() : parse_filename(*filename); auto effective_filename = not filename ? buffer.name() : parse_filename(*filename);
context.hooks().run_hook("BufWritePre", effective_filename, context); context.hooks().run_hook(Hook::BufWritePre, effective_filename, context);
write_buffer_to_file(buffer, effective_filename, force, sync_file); write_buffer_to_file(buffer, effective_filename, force, sync_file);
context.hooks().run_hook("BufWritePost", effective_filename, context); context.hooks().run_hook(Hook::BufWritePost, effective_filename, context);
} }
template<bool force = false> template<bool force = false>
@ -395,9 +395,9 @@ void write_all_buffers(Context& context, bool sync = false)
buffer->is_modified()) buffer->is_modified())
and !(buffer->flags() & Buffer::Flags::ReadOnly)) and !(buffer->flags() & Buffer::Flags::ReadOnly))
{ {
buffer->run_hook_in_own_context("BufWritePre", buffer->name(), context.name()); buffer->run_hook_in_own_context(Hook::BufWritePre, buffer->name(), context.name());
write_buffer_to_file(*buffer, buffer->name(), sync); write_buffer_to_file(*buffer, buffer->name(), sync);
buffer->run_hook_in_own_context("BufWritePost", buffer->name(), context.name()); buffer->run_hook_in_own_context(Hook::BufWritePost, buffer->name(), context.name());
} }
} }
} }
@ -819,20 +819,10 @@ const CommandDesc remove_highlighter_cmd = {
} }
}; };
static constexpr auto hooks = {
"BufCreate", "BufNewFile", "BufOpenFile", "BufClose", "BufWritePost", "BufReload",
"BufWritePre", "BufOpenFifo", "BufCloseFifo", "BufReadFifo", "BufSetOption",
"InsertBegin", "InsertChar", "InsertDelete", "InsertEnd", "InsertIdle", "InsertKey",
"InsertMove", "InsertCompletionHide", "InsertCompletionShow", "InsertCompletionSelect",
"KakBegin", "KakEnd", "FocusIn", "FocusOut", "GlobalSetOption", "RuntimeError", "PromptIdle",
"NormalBegin", "NormalEnd", "NormalIdle", "NormalKey", "ModeChange", "RawKey",
"WinClose", "WinCreate", "WinDisplay", "WinResize", "WinSetOption",
};
static Completions complete_hooks(const Context&, CompletionFlags, static Completions complete_hooks(const Context&, CompletionFlags,
const String& prefix, ByteCount cursor_pos) const String& prefix, ByteCount cursor_pos)
{ {
return { 0_byte, cursor_pos, complete(prefix, cursor_pos, hooks) }; return { 0_byte, cursor_pos, complete(prefix, cursor_pos, enum_desc(Meta::Type<Hook>{}) | transform(&EnumDesc<Hook>::name)) };
} }
const CommandDesc add_hook_cmd = { const CommandDesc add_hook_cmd = {
@ -860,7 +850,9 @@ const CommandDesc add_hook_cmd = {
context, flags, prefix, cursor_pos); }), context, flags, prefix, cursor_pos); }),
[](const ParametersParser& parser, Context& context, const ShellContext&) [](const ParametersParser& parser, Context& context, const ShellContext&)
{ {
if (not contains(hooks, parser[1])) auto descs = enum_desc(Meta::Type<Hook>{});
auto it = find_if(descs, [&](const EnumDesc<Hook>& desc) { return desc.name == parser[1]; });
if (it == descs.end())
throw runtime_error{format("no such hook: '{}'", parser[1])}; throw runtime_error{format("no such hook: '{}'", parser[1])};
Regex regex{parser[2], RegexCompileFlags::Optimize}; Regex regex{parser[2], RegexCompileFlags::Optimize};
@ -873,7 +865,7 @@ const CommandDesc add_hook_cmd = {
const auto flags = (parser.get_switch("always") ? HookFlags::Always : HookFlags::None) | const auto flags = (parser.get_switch("always") ? HookFlags::Always : HookFlags::None) |
(parser.get_switch("once") ? HookFlags::Once : HookFlags::None); (parser.get_switch("once") ? HookFlags::Once : HookFlags::None);
get_scope(parser[0], context).hooks().add_hook(parser[1], group.str(), flags, get_scope(parser[0], context).hooks().add_hook(it->value, group.str(), flags,
std::move(regex), command); std::move(regex), command);
} }
}; };

View File

@ -18,6 +18,10 @@ struct Array
constexpr const T* begin() const { return m_data; } constexpr const T* begin() const { return m_data; }
constexpr const T* end() const { return m_data+N; } constexpr const T* end() const { return m_data+N; }
constexpr T& operator[](int i) { return m_data[i]; }
constexpr T* begin() { return m_data; }
constexpr T* end() { return m_data+N; }
constexpr operator ArrayView<T>() { return {m_data, N}; } constexpr operator ArrayView<T>() { return {m_data, N}; }
constexpr operator ConstArrayView<T>() const { return {m_data, N}; } constexpr operator ConstArrayView<T>() const { return {m_data, N}; }

View File

@ -14,7 +14,7 @@
namespace Kakoune namespace Kakoune
{ {
struct HookManager::Hook struct HookManager::HookData
{ {
String group; String group;
HookFlags flags; HookFlags flags;
@ -26,23 +26,23 @@ HookManager::HookManager() : m_parent(nullptr) {}
HookManager::HookManager(HookManager& parent) : SafeCountable{}, m_parent(&parent) {} HookManager::HookManager(HookManager& parent) : SafeCountable{}, m_parent(&parent) {}
HookManager::~HookManager() = default; HookManager::~HookManager() = default;
void HookManager::add_hook(StringView hook_name, String group, HookFlags flags, Regex filter, String commands) void HookManager::add_hook(Hook hook, String group, HookFlags flags, Regex filter, String commands)
{ {
auto& hooks = m_hooks[hook_name]; auto& hooks = m_hooks[to_underlying(hook)];
hooks.emplace_back(new Hook{std::move(group), flags, std::move(filter), std::move(commands)}); hooks.emplace_back(new HookData{std::move(group), flags, std::move(filter), std::move(commands)});
} }
void HookManager::remove_hooks(const Regex& regex) void HookManager::remove_hooks(const Regex& regex)
{ {
for (auto& list : m_hooks) for (auto& list : m_hooks)
{ {
auto it = std::remove_if(list.value.begin(), list.value.end(), auto it = std::remove_if(list.begin(), list.end(),
[&](const std::unique_ptr<Hook>& h) [&](const std::unique_ptr<HookData>& h)
{ return regex_match(h->group.begin(), h->group.end(), regex); }); { return regex_match(h->group.begin(), h->group.end(), regex); });
if (not m_running_hooks.empty()) // we are running some hooks, defer deletion if (not m_running_hooks.empty()) // we are running some hooks, defer deletion
m_hooks_trash.insert(m_hooks_trash.end(), std::make_move_iterator(it), m_hooks_trash.insert(m_hooks_trash.end(), std::make_move_iterator(it),
std::make_move_iterator(list.value.end())); std::make_move_iterator(list.end()));
list.value.erase(it, list.value.end()); list.erase(it, list.end());
} }
} }
@ -51,7 +51,7 @@ CandidateList HookManager::complete_hook_group(StringView prefix, ByteCount pos_
CandidateList res; CandidateList res;
for (auto& list : m_hooks) for (auto& list : m_hooks)
{ {
auto container = list.value | transform([](const std::unique_ptr<Hook>& h) -> const String& { return h->group; }); auto container = list | transform([](const std::unique_ptr<HookData>& h) -> const String& { return h->group; });
for (auto& c : complete(prefix, pos_in_token, container)) for (auto& c : complete(prefix, pos_in_token, container))
{ {
if (!contains(res, c)) if (!contains(res, c))
@ -61,25 +61,23 @@ CandidateList HookManager::complete_hook_group(StringView prefix, ByteCount pos_
return res; return res;
} }
void HookManager::run_hook(StringView hook_name, StringView param, Context& context) void HookManager::run_hook(Hook hook, StringView param, Context& context)
{ {
const bool only_always = context.hooks_disabled(); const bool only_always = context.hooks_disabled();
if (m_parent) if (m_parent)
m_parent->run_hook(hook_name, param, context); m_parent->run_hook(hook, param, context);
auto hook_list = m_hooks.find(hook_name); auto& hook_list = m_hooks[to_underlying(hook)];
if (hook_list == m_hooks.end()) auto hook_name = enum_desc(Meta::Type<Hook>{})[to_underlying(hook)].name;
return; if (contains(m_running_hooks, std::make_pair(hook, param)))
if (contains(m_running_hooks, std::make_pair(hook_name, param)))
{ {
auto error = format("recursive call of hook {}/{}, not executing", hook_name, param); auto error = format("recursive call of hook {}/{}, not executing", hook_name, param);
write_to_debug_buffer(error); write_to_debug_buffer(error);
return; return;
} }
m_running_hooks.emplace_back(hook_name, param); m_running_hooks.emplace_back(hook, param);
auto pop_running_hook = on_scope_end([this]{ auto pop_running_hook = on_scope_end([this]{
m_running_hooks.pop_back(); m_running_hooks.pop_back();
if (m_running_hooks.empty()) if (m_running_hooks.empty())
@ -92,9 +90,9 @@ void HookManager::run_hook(StringView hook_name, StringView param, Context& cont
auto& disabled_hooks = context.options()["disabled_hooks"].get<Regex>(); auto& disabled_hooks = context.options()["disabled_hooks"].get<Regex>();
struct ToRun { Hook* hook; MatchResults<const char*> captures; }; struct ToRun { HookData* hook; MatchResults<const char*> captures; };
Vector<ToRun> hooks_to_run; // The m_hooks_trash vector ensure hooks wont die during this method Vector<ToRun> hooks_to_run; // The m_hooks_trash vector ensure hooks wont die during this method
for (auto& hook : hook_list->value) for (auto& hook : hook_list)
{ {
MatchResults<const char*> captures; MatchResults<const char*> captures;
if ((not only_always or (hook->flags & HookFlags::Always)) and if ((not only_always or (hook->flags & HookFlags::Always)) and
@ -124,11 +122,11 @@ void HookManager::run_hook(StringView hook_name, StringView param, Context& cont
if (to_run.hook->flags & HookFlags::Once) if (to_run.hook->flags & HookFlags::Once)
{ {
auto it = find(hook_list->value, to_run.hook); auto it = find(hook_list, to_run.hook);
if (it != hook_list->value.end()) if (it != hook_list.end())
{ {
m_hooks_trash.push_back(std::move(*it)); m_hooks_trash.push_back(std::move(*it));
hook_list->value.erase(it); hook_list.erase(it);
} }
} }
} }

View File

@ -4,6 +4,8 @@
#include "hash_map.hh" #include "hash_map.hh"
#include "completion.hh" #include "completion.hh"
#include "safe_ptr.hh" #include "safe_ptr.hh"
#include "meta.hh"
#include "enum.hh"
namespace Kakoune namespace Kakoune
{ {
@ -11,6 +13,94 @@ namespace Kakoune
class Context; class Context;
class Regex; class Regex;
enum class Hook
{
BufCreate,
BufNewFile,
BufOpenFile,
BufClose,
BufWritePost,
BufReload,
BufWritePre,
BufOpenFifo,
BufCloseFifo,
BufReadFifo,
BufSetOption,
InsertBegin,
InsertChar,
InsertDelete,
InsertEnd,
InsertIdle,
InsertKey,
InsertMove,
InsertCompletionHide,
InsertCompletionShow,
InsertCompletionSelect,
KakBegin,
KakEnd,
FocusIn,
FocusOut,
GlobalSetOption,
RuntimeError,
PromptIdle,
NormalBegin,
NormalEnd,
NormalIdle,
NormalKey,
ModeChange,
RawKey,
WinClose,
WinCreate,
WinDisplay,
WinResize,
WinSetOption
};
constexpr auto enum_desc(Meta::Type<Hook>)
{
return make_array<EnumDesc<Hook>, 39>({
{Hook::BufCreate, "BufCreate"},
{Hook::BufNewFile, "BufNewFile"},
{Hook::BufOpenFile, "BufOpenFile"},
{Hook::BufClose, "BufClose"},
{Hook::BufWritePost, "BufWritePost"},
{Hook::BufReload, "BufReload"},
{Hook::BufWritePre, "BufWritePre"},
{Hook::BufOpenFifo, "BufOpenFifo"},
{Hook::BufCloseFifo, "BufCloseFifo"},
{Hook::BufReadFifo, "BufReadFifo"},
{Hook::BufSetOption, "BufSetOption"},
{Hook::InsertBegin, "InsertBegin"},
{Hook::InsertChar, "InsertChar"},
{Hook::InsertDelete, "InsertDelete"},
{Hook::InsertEnd, "InsertEnd"},
{Hook::InsertIdle, "InsertIdle"},
{Hook::InsertKey, "InsertKey"},
{Hook::InsertMove, "InsertMove"},
{Hook::InsertCompletionHide, "InsertCompletionHide"},
{Hook::InsertCompletionShow, "InsertCompletionShow"},
{Hook::InsertCompletionSelect, "InsertCompletionSelect"},
{Hook::KakBegin, "KakBegin"},
{Hook::KakEnd, "KakEnd"},
{Hook::FocusIn, "FocusIn"},
{Hook::FocusOut, "FocusOut"},
{Hook::GlobalSetOption, "GlobalSetOption"},
{Hook::RuntimeError, "RuntimeError"},
{Hook::PromptIdle, "PromptIdle"},
{Hook::NormalBegin, "NormalBegin"},
{Hook::NormalEnd, "NormalEnd"},
{Hook::NormalIdle, "NormalIdle"},
{Hook::NormalKey, "NormalKey"},
{Hook::ModeChange, "ModeChange"},
{Hook::RawKey, "RawKey"},
{Hook::WinClose, "WinClose"},
{Hook::WinCreate, "WinCreate"},
{Hook::WinDisplay, "WinDisplay"},
{Hook::WinResize, "WinResize"},
{Hook::WinSetOption, "WinSetOption"},
});
}
enum class HookFlags enum class HookFlags
{ {
None = 0, None = 0,
@ -25,25 +115,24 @@ public:
HookManager(HookManager& parent); HookManager(HookManager& parent);
~HookManager(); ~HookManager();
void add_hook(StringView hook_name, String group, HookFlags flags, void add_hook(Hook hook, String group, HookFlags flags,
Regex filter, String commands); Regex filter, String commands);
void remove_hooks(const Regex& regex); void remove_hooks(const Regex& regex);
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(Hook hook, StringView param, Context& context);
Context& context);
private: private:
HookManager(); HookManager();
// the only one allowed to construct a root hook manager // the only one allowed to construct a root hook manager
friend class Scope; friend class Scope;
struct Hook; struct HookData;
SafePtr<HookManager> m_parent; SafePtr<HookManager> m_parent;
HashMap<String, Vector<std::unique_ptr<Hook>, MemoryDomain::Hooks>, MemoryDomain::Hooks> m_hooks; Array<Vector<std::unique_ptr<HookData>, MemoryDomain::Hooks>, enum_desc(Meta::Type<Hook>{}).size()> m_hooks;
mutable Vector<std::pair<StringView, StringView>, MemoryDomain::Hooks> m_running_hooks; mutable Vector<std::pair<Hook, StringView>, MemoryDomain::Hooks> m_running_hooks;
mutable Vector<std::unique_ptr<Hook>, MemoryDomain::Hooks> m_hooks_trash; mutable Vector<std::unique_ptr<HookData>, MemoryDomain::Hooks> m_hooks_trash;
}; };
} }

View File

@ -166,7 +166,7 @@ public:
m_idle_timer{TimePoint::max(), m_idle_timer{TimePoint::max(),
context().flags() & Context::Flags::Draft ? context().flags() & Context::Flags::Draft ?
Timer::Callback{} : [this](Timer&) { Timer::Callback{} : [this](Timer&) {
context().hooks().run_hook("NormalIdle", "", context()); context().hooks().run_hook(Hook::NormalIdle, "", context());
}}, }},
m_fs_check_timer{TimePoint::max(), m_fs_check_timer{TimePoint::max(),
context().flags() & Context::Flags::Draft ? context().flags() & Context::Flags::Draft ?
@ -198,7 +198,7 @@ public:
m_hooks_disabled = false; m_hooks_disabled = false;
} }
context().hooks().run_hook("NormalBegin", "", context()); context().hooks().run_hook(Hook::NormalBegin, "", context());
} }
void on_disabled(bool temporary) override void on_disabled(bool temporary) override
@ -212,7 +212,7 @@ public:
m_hooks_disabled = false; m_hooks_disabled = false;
} }
context().hooks().run_hook("NormalEnd", "", context()); context().hooks().run_hook(Hook::NormalEnd, "", context());
} }
void on_key(Key key) override void on_key(Key key) override
@ -314,7 +314,7 @@ public:
} }
} }
context().hooks().run_hook("NormalKey", key_to_str(key), context()); context().hooks().run_hook(Hook::NormalKey, key_to_str(key), context());
if (enabled() and not transient) // The hook might have changed mode if (enabled() and not transient) // The hook might have changed mode
m_idle_timer.set_next_date(Clock::now() + get_idle_timeout(context())); m_idle_timer.set_next_date(Clock::now() + get_idle_timeout(context()));
} }
@ -753,7 +753,7 @@ public:
m_callback(m_line_editor.line(), PromptEvent::Change, context()); m_callback(m_line_editor.line(), PromptEvent::Change, context());
m_line_changed = false; m_line_changed = false;
} }
context().hooks().run_hook("PromptIdle", "", context()); context().hooks().run_hook(Hook::PromptIdle, "", context());
}}, }},
m_line_editor{context().faces()} m_line_editor{context().faces()}
{ {
@ -1128,7 +1128,7 @@ public:
m_idle_timer{TimePoint::max(), context().flags() & Context::Flags::Draft ? m_idle_timer{TimePoint::max(), context().flags() & Context::Flags::Draft ?
Timer::Callback{} : [this](Timer&) { Timer::Callback{} : [this](Timer&) {
m_completer.update(m_auto_complete); m_completer.update(m_auto_complete);
context().hooks().run_hook("InsertIdle", "", context()); context().hooks().run_hook(Hook::InsertIdle, "", context());
}} }}
{ {
context().buffer().throw_if_read_only(); context().buffer().throw_if_read_only();
@ -1138,7 +1138,7 @@ public:
last_insert().keys.clear(); last_insert().keys.clear();
last_insert().disable_hooks = context().hooks_disabled(); last_insert().disable_hooks = context().hooks_disabled();
last_insert().count = count; last_insert().count = count;
context().hooks().run_hook("InsertBegin", "", context()); context().hooks().run_hook(Hook::InsertBegin, "", context());
prepare(mode, count); prepare(mode, count);
} }
@ -1185,7 +1185,7 @@ public:
if (m_in_end) if (m_in_end)
throw runtime_error("asked to exit insert mode while running InsertEnd hook"); throw runtime_error("asked to exit insert mode while running InsertEnd hook");
m_in_end = true; m_in_end = true;
context().hooks().run_hook("InsertEnd", "", context()); context().hooks().run_hook(Hook::InsertEnd, "", context());
m_completer.reset(); m_completer.reset();
pop_mode(); pop_mode();
@ -1209,7 +1209,7 @@ public:
SelectionList{buffer, std::move(sels)}.erase(); SelectionList{buffer, std::move(sels)}.erase();
if (not main_char.empty()) if (not main_char.empty())
context().hooks().run_hook("InsertDelete", main_char, context()); context().hooks().run_hook(Hook::InsertDelete, main_char, context());
} }
else if (key == Key::Delete) else if (key == Key::Delete)
{ {
@ -1328,7 +1328,7 @@ public:
if (auto cp = get_raw_codepoint(key)) if (auto cp = get_raw_codepoint(key))
{ {
insert(*cp); insert(*cp);
context().hooks().run_hook("InsertKey", key_to_str(key), context()); context().hooks().run_hook(Hook::InsertKey, key_to_str(key), context());
if (enabled() and not transient) if (enabled() and not transient)
m_idle_timer.set_next_date(Clock::now() + get_idle_timeout(context())); m_idle_timer.set_next_date(Clock::now() + get_idle_timeout(context()));
} }
@ -1341,9 +1341,9 @@ public:
return; return;
} }
context().hooks().run_hook("InsertKey", key_to_str(key), context()); context().hooks().run_hook(Hook::InsertKey, key_to_str(key), context());
if (moved) if (moved)
context().hooks().run_hook("InsertMove", key_to_str(key), context()); context().hooks().run_hook(Hook::InsertMove, key_to_str(key), context());
if (update_completions and enabled() and not transient) // Hooks might have disabled us if (update_completions and enabled() and not transient) // Hooks might have disabled us
m_idle_timer.set_next_date(Clock::now() + get_idle_timeout(context())); m_idle_timer.set_next_date(Clock::now() + get_idle_timeout(context()));
@ -1386,7 +1386,7 @@ private:
{ {
String str{key}; String str{key};
context().selections().insert(str, InsertMode::InsertCursor); context().selections().insert(str, InsertMode::InsertCursor);
context().hooks().run_hook("InsertChar", str, context()); context().hooks().run_hook(Hook::InsertChar, str, context());
} }
void prepare(InsertMode mode, int count) void prepare(InsertMode mode, int count)
@ -1430,7 +1430,7 @@ private:
} }
selections.set(std::move(new_sels), selections.set(std::move(new_sels),
selections.main_index() * count + count - 1); selections.main_index() * count + count - 1);
context().hooks().run_hook("InsertChar", "\n", context()); context().hooks().run_hook(Hook::InsertChar, "\n", context());
break; break;
} }
case InsertMode::OpenLineAbove: case InsertMode::OpenLineAbove:
@ -1448,7 +1448,7 @@ private:
} }
selections.set(std::move(new_sels), selections.set(std::move(new_sels),
selections.main_index() * count + count - 1); selections.main_index() * count + count - 1);
context().hooks().run_hook("InsertChar", "\n", context()); context().hooks().run_hook(Hook::InsertChar, "\n", context());
break; break;
} }
case InsertMode::InsertAtLineBegin: case InsertMode::InsertAtLineBegin:
@ -1503,7 +1503,7 @@ void InputHandler::push_mode(InputMode* new_mode)
m_mode_stack.emplace_back(new_mode); m_mode_stack.emplace_back(new_mode);
new_mode->on_enabled(); new_mode->on_enabled();
context().hooks().run_hook("ModeChange", format("{}:{}", prev_name, new_mode->name()), context()); context().hooks().run_hook(Hook::ModeChange, format("{}:{}", prev_name, new_mode->name()), context());
} }
void InputHandler::pop_mode(InputMode* mode) void InputHandler::pop_mode(InputMode* mode)
@ -1517,7 +1517,7 @@ void InputHandler::pop_mode(InputMode* mode)
m_mode_stack.pop_back(); m_mode_stack.pop_back();
current_mode().on_enabled(); current_mode().on_enabled();
context().hooks().run_hook("ModeChange", format("{}:{}", prev_name, current_mode().name()), context()); context().hooks().run_hook(Hook::ModeChange, format("{}:{}", prev_name, current_mode().name()), context());
} }
void InputHandler::reset_normal_mode() void InputHandler::reset_normal_mode()
@ -1531,7 +1531,7 @@ void InputHandler::reset_normal_mode()
m_mode_stack.resize(1); m_mode_stack.resize(1);
current_mode().on_enabled(); current_mode().on_enabled();
context().hooks().run_hook("ModeChange", format("{}:{}", prev_name, current_mode().name()), context()); context().hooks().run_hook(Hook::ModeChange, format("{}:{}", prev_name, current_mode().name()), context());
} }
void InputHandler::insert(InsertMode mode, int count) void InputHandler::insert(InsertMode mode, int count)

View File

@ -455,7 +455,7 @@ void InsertCompleter::select(int index, bool relative, Vector<Key>& keystrokes)
{ {
const auto param = (m_current_candidate == m_completions.candidates.size() - 1) ? const auto param = (m_current_candidate == m_completions.candidates.size() - 1) ?
StringView{} : candidate.completion; StringView{} : candidate.completion;
m_context.hooks().run_hook("InsertCompletionSelect", param, m_context); m_context.hooks().run_hook(Hook::InsertCompletionSelect, param, m_context);
} }
} }
@ -479,7 +479,7 @@ void InsertCompleter::reset()
{ {
m_context.client().menu_hide(); m_context.client().menu_hide();
m_context.client().info_hide(); m_context.client().info_hide();
m_context.hooks().run_hook("InsertCompletionHide", "", m_context); m_context.hooks().run_hook(Hook::InsertCompletionHide, "", m_context);
} }
} }
} }
@ -536,7 +536,7 @@ void InsertCompleter::menu_show()
m_context.client().menu_show(std::move(menu_entries), m_completions.begin, m_context.client().menu_show(std::move(menu_entries), m_completions.begin,
MenuStyle::Inline); MenuStyle::Inline);
m_context.client().menu_select(m_current_candidate); m_context.client().menu_select(m_current_candidate);
m_context.hooks().run_hook("InsertCompletionShow", "", m_context); m_context.hooks().run_hook(Hook::InsertCompletionShow, "", m_context);
} }
void InsertCompleter::on_option_changed(const Option& opt) void InsertCompleter::on_option_changed(const Option& opt)

View File

@ -674,7 +674,7 @@ int run_server(StringView session, StringView server_init,
{ {
Context empty_context{Context::EmptyContextFlag{}}; Context empty_context{Context::EmptyContextFlag{}};
global_scope.hooks().run_hook("KakBegin", session, empty_context); global_scope.hooks().run_hook(Hook::KakBegin, session, empty_context);
} }
if (not files.empty()) try if (not files.empty()) try
@ -776,7 +776,7 @@ int run_server(StringView session, StringView server_init,
{ {
Context empty_context{Context::EmptyContextFlag{}}; Context empty_context{Context::EmptyContextFlag{}};
global_scope.hooks().run_hook("KakEnd", "", empty_context); global_scope.hooks().run_hook(Hook::KakEnd, "", empty_context);
} }
return local_client_exit; return local_client_exit;

View File

@ -18,7 +18,7 @@ GlobalScope::~GlobalScope()
void GlobalScope::on_option_changed(const Option& option) void GlobalScope::on_option_changed(const Option& option)
{ {
Context empty_context{Context::EmptyContextFlag{}}; Context empty_context{Context::EmptyContextFlag{}};
hooks().run_hook("GlobalSetOption", hooks().run_hook(Hook::GlobalSetOption,
format("{}={}", option.name(), option.get_as_string(Quoting::Kakoune)), format("{}={}", option.name(), option.get_as_string(Quoting::Kakoune)),
empty_context); empty_context);
} }

View File

@ -25,7 +25,7 @@ Window::Window(Buffer& buffer)
m_buffer(&buffer), m_buffer(&buffer),
m_builtin_highlighters{highlighters()} m_builtin_highlighters{highlighters()}
{ {
run_hook_in_own_context("WinCreate", buffer.name()); run_hook_in_own_context(Hook::WinCreate, buffer.name());
options().register_watcher(*this); options().register_watcher(*this);
@ -40,7 +40,7 @@ Window::Window(Buffer& buffer)
Window::~Window() Window::~Window()
{ {
run_hook_in_own_context("WinClose", buffer().name()); run_hook_in_own_context(Hook::WinClose, buffer().name());
options().unregister_watcher(*this); options().unregister_watcher(*this);
} }
@ -195,7 +195,7 @@ void Window::set_dimensions(DisplayCoord dimensions)
if (m_dimensions != dimensions) if (m_dimensions != dimensions)
{ {
m_dimensions = dimensions; m_dimensions = dimensions;
run_hook_in_own_context("WinResize", format("{}.{}", dimensions.line, run_hook_in_own_context(Hook::WinResize, format("{}.{}", dimensions.line,
dimensions.column)); dimensions.column));
} }
} }
@ -339,15 +339,14 @@ void Window::clear_display_buffer()
void Window::on_option_changed(const Option& option) void Window::on_option_changed(const Option& option)
{ {
run_hook_in_own_context("WinSetOption", format("{}={}", option.name(), run_hook_in_own_context(Hook::WinSetOption, format("{}={}", option.name(),
option.get_as_string(Quoting::Kakoune))); option.get_as_string(Quoting::Kakoune)));
// an highlighter might depend on the option, so we need to redraw // an highlighter might depend on the option, so we need to redraw
force_redraw(); force_redraw();
} }
void Window::run_hook_in_own_context(StringView hook_name, StringView param, void Window::run_hook_in_own_context(Hook hook, StringView param, String client_name)
String client_name)
{ {
if (m_buffer->flags() & Buffer::Flags::NoHooks) if (m_buffer->flags() & Buffer::Flags::NoHooks)
return; return;
@ -359,6 +358,6 @@ void Window::run_hook_in_own_context(StringView hook_name, StringView param,
if (m_client) if (m_client)
hook_handler.context().set_client(*m_client); hook_handler.context().set_client(*m_client);
hooks().run_hook(hook_name, param, hook_handler.context()); hooks().run_hook(hook, param, hook_handler.context());
} }
} }

View File

@ -12,6 +12,8 @@
namespace Kakoune namespace Kakoune
{ {
enum class Hook;
// A Window is a view onto a Buffer // A Window is a view onto a Buffer
class Window final : public SafeCountable, public Scope, private OptionManagerWatcher class Window final : public SafeCountable, public Scope, private OptionManagerWatcher
{ {
@ -52,7 +54,7 @@ private:
void on_option_changed(const Option& option) override; void on_option_changed(const Option& option) override;
DisplaySetup compute_display_setup(const Context& context) const; DisplaySetup compute_display_setup(const Context& context) const;
void run_hook_in_own_context(StringView hook_name, StringView param, void run_hook_in_own_context(Hook hook, StringView param,
String client_name = ""); String client_name = "");
SafePtr<Buffer> m_buffer; SafePtr<Buffer> m_buffer;