From 47ba36c66e0e38c5bb5c832bfa751d553f769baa Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Sun, 19 Jul 2020 12:56:55 +1000 Subject: [PATCH] Add a RegisterModified hook This one has been a long time coming, I am still concerned this could impact performance a lot. This hook does *not* trigger for capture registers (0-9) or any other dynamic registers (that are not writable). Fixes #859 --- doc/pages/hooks.asciidoc | 3 ++ src/hook_manager.hh | 2 ++ src/main.cc | 12 +++++--- src/register_manager.cc | 47 ++++++++++++++++++++++++++++++++ src/register_manager.hh | 59 ++++++++++------------------------------ 5 files changed, 74 insertions(+), 49 deletions(-) diff --git a/doc/pages/hooks.asciidoc b/doc/pages/hooks.asciidoc index aee7d876..a4253e25 100644 --- a/doc/pages/hooks.asciidoc +++ b/doc/pages/hooks.asciidoc @@ -175,6 +175,9 @@ name. Hooks with no description will always use an empty string. even with the `-with-hooks` option (see <>). +*RegisterModified* `register`:: + Triggered after a register has been written to. + *ModuleLoaded* `module`:: Triggered after a module is evaluated by the first `require-module` call diff --git a/src/hook_manager.hh b/src/hook_manager.hh index a6547fa0..4b8a8913 100644 --- a/src/hook_manager.hh +++ b/src/hook_manager.hh @@ -49,6 +49,7 @@ enum class Hook NormalKey, ModeChange, RawKey, + RegisterModified, WinClose, WinCreate, WinDisplay, @@ -93,6 +94,7 @@ constexpr auto enum_desc(Meta::Type) {Hook::NormalKey, "NormalKey"}, {Hook::ModeChange, "ModeChange"}, {Hook::RawKey, "RawKey"}, + {Hook::RegisterModified, "RegisterModified"}, {Hook::WinClose, "WinClose"}, {Hook::WinCreate, "WinCreate"}, {Hook::WinDisplay, "WinDisplay"}, diff --git a/src/main.cc b/src/main.cc index 63fea291..9385214f 100644 --- a/src/main.cc +++ b/src/main.cc @@ -350,25 +350,28 @@ void register_registers() { RegisterManager& register_manager = RegisterManager::instance(); - for (auto c : StringView{"abcdefghijklmnopqrstuvwxyz\"^@"}) - register_manager.add_register(c, std::make_unique()); + for (Codepoint c : StringView{"abcdefghijklmnopqrstuvwxyz\"^@"}) + register_manager.add_register(c, std::make_unique(String{c})); - for (auto c : StringView{"/|:\\"}) - register_manager.add_register(c, std::make_unique()); + for (Codepoint c : StringView{"/|:\\"}) + register_manager.add_register(c, std::make_unique(String{c})); using StringList = Vector; register_manager.add_register('%', make_dyn_reg( + "%", [](const Context& context) { return StringList{{context.buffer().display_name()}}; })); register_manager.add_register('.', make_dyn_reg( + ".", [](const Context& context) { auto content = context.selections_content(); return StringList{content.begin(), content.end()}; })); register_manager.add_register('#', make_dyn_reg( + "#", [](const Context& context) { const size_t count = context.selections().size(); StringList res; @@ -381,6 +384,7 @@ void register_registers() for (size_t i = 0; i < 10; ++i) { register_manager.add_register('0'+i, make_dyn_reg( + String{Codepoint('0'+i)}, [i](const Context& context) { StringList result; for (auto& sel : context.selections()) diff --git a/src/register_manager.cc b/src/register_manager.cc index 37c93628..65f9a7ce 100644 --- a/src/register_manager.cc +++ b/src/register_manager.cc @@ -1,12 +1,59 @@ #include "register_manager.hh" #include "assert.hh" +#include "context.hh" #include "hash_map.hh" #include "string_utils.hh" namespace Kakoune { +void StaticRegister::set(Context& context, ConstArrayView values, bool) +{ + m_content.assign(values.begin(), values.end()); + context.hooks().run_hook(Hook::RegisterModified, m_name, context); +} + +ConstArrayView StaticRegister::get(const Context&) +{ + if (m_content.empty()) + return ConstArrayView(String::ms_empty); + else + return ConstArrayView(m_content); +} + +const String& StaticRegister::get_main(const Context& context, size_t main_index) +{ + auto content = get(context); + return content[std::min(main_index, content.size() - 1)]; +} + +void HistoryRegister::set(Context& context, ConstArrayView values, bool restoring) +{ + constexpr size_t size_limit = 100; + + if (restoring) + return StaticRegister::set(context, values, true); + + for (auto& entry : values) + { + m_content.erase(std::remove(m_content.begin(), m_content.end(), entry), + m_content.end()); + m_content.push_back(entry); + } + + const size_t current_size = m_content.size(); + if (current_size > size_limit) + m_content.erase(m_content.begin(), m_content.begin() + (current_size - size_limit)); + + context.hooks().run_hook(Hook::RegisterModified, m_name, context); +} + +const String& HistoryRegister::get_main(const Context&, size_t) +{ + return m_content.empty() ? String::ms_empty : m_content.back(); +} + static const HashMap reg_names = { { "slash", '/' }, { "dquote", '"' }, diff --git a/src/register_manager.hh b/src/register_manager.hh index d82849c3..732d3449 100644 --- a/src/register_manager.hh +++ b/src/register_manager.hh @@ -33,26 +33,14 @@ public: class StaticRegister : public Register { public: - void set(Context&, ConstArrayView values, bool) override - { - m_content.assign(values.begin(), values.end()); - } + StaticRegister(String name) : m_name{std::move(name)} {} - ConstArrayView get(const Context&) override - { - if (m_content.empty()) - return ConstArrayView(String::ms_empty); - else - return ConstArrayView(m_content); - } - - const String& get_main(const Context& context, size_t main_index) override - { - auto content = get(context); - return content[std::min(main_index, content.size() - 1)]; - } + void set(Context& context, ConstArrayView values, bool) override; + ConstArrayView get(const Context&) override; + const String& get_main(const Context& context, size_t main_index) override; protected: + String m_name; Vector m_content; }; @@ -62,8 +50,8 @@ template class DynamicRegister : public StaticRegister { public: - DynamicRegister(Getter getter, Setter setter) - : m_getter(std::move(getter)), m_setter(std::move(setter)) {} + DynamicRegister(String name, Getter getter, Setter setter) + : StaticRegister(std::move(name)), m_getter(std::move(getter)), m_setter(std::move(setter)) {} void set(Context& context, ConstArrayView values, bool) override { @@ -85,45 +73,26 @@ private: class HistoryRegister : public StaticRegister { public: - void set(Context& context, ConstArrayView values, bool restoring) override - { - constexpr size_t size_limit = 100; + using StaticRegister::StaticRegister; - if (restoring) - return StaticRegister::set(context, values, true); - - for (auto& entry : values) - { - m_content.erase(std::remove(m_content.begin(), m_content.end(), entry), - m_content.end()); - m_content.push_back(entry); - } - - const size_t current_size = m_content.size(); - if (current_size > size_limit) - m_content.erase(m_content.begin(), m_content.begin() + (current_size - size_limit)); - } - - const String& get_main(const Context&, size_t) override - { - return m_content.empty() ? String::ms_empty : m_content.back(); - } + void set(Context& context, ConstArrayView values, bool restoring) override; + const String& get_main(const Context&, size_t) override; }; template -std::unique_ptr make_dyn_reg(Func func) +std::unique_ptr make_dyn_reg(String name, Func func) { auto setter = [](Context&, ConstArrayView) { throw runtime_error("this register is not assignable"); }; - return std::make_unique>(std::move(func), setter); + return std::make_unique>(name, std::move(func), setter); } template -std::unique_ptr make_dyn_reg(Getter getter, Setter setter) +std::unique_ptr make_dyn_reg(String name, Getter getter, Setter setter) { - return std::make_unique>(std::move(getter), std::move(setter)); + return std::make_unique>(name, std::move(getter), std::move(setter)); } class NullRegister : public Register