diff --git a/src/buffer.cc b/src/buffer.cc index 9bc6c6a6..cddf58c7 100644 --- a/src/buffer.cc +++ b/src/buffer.cc @@ -533,7 +533,7 @@ void Buffer::on_option_changed(const Option& option) void Buffer::run_hook_in_own_context(const String& hook_name, StringView param) { - InputHandler hook_handler({ *this, Selection{} }); + InputHandler hook_handler({ *this, Selection{} }, Context::Flags::Transient); hooks().run_hook(hook_name, param, hook_handler.context()); } diff --git a/src/client.cc b/src/client.cc index c0c90336..69e1aaea 100644 --- a/src/client.cc +++ b/src/client.cc @@ -22,7 +22,7 @@ Client::Client(std::unique_ptr&& ui, EnvVarMap env_vars, String name) : m_ui{std::move(ui)}, m_window{std::move(window)}, - m_input_handler{std::move(selections), + m_input_handler{std::move(selections), Context::Flags::None, std::move(name)}, m_env_vars(env_vars) { diff --git a/src/commands.cc b/src/commands.cc index 71c4e561..80dd696e 100644 --- a/src/commands.cc +++ b/src/commands.cc @@ -1032,7 +1032,8 @@ void context_wrap(const ParametersParser& parser, Context& context, Func func) for (auto& name : names) { Buffer& buffer = BufferManager::instance().get_buffer(name); - InputHandler input_handler{{ buffer, Selection{} }}; + InputHandler input_handler{{ buffer, Selection{} }, + Context::Flags::Transient}; Context& c = input_handler.context(); // Propagate user hooks disabled status to the temporary context @@ -1056,7 +1057,9 @@ void context_wrap(const ParametersParser& parser, Context& context, Func func) if (parser.has_option("draft")) { - InputHandler input_handler(real_context->selections(), real_context->name()); + InputHandler input_handler(real_context->selections(), + Context::Flags::Transient, + real_context->name()); Context& c = input_handler.context(); // We do not want this draft context to commit undo groups if the real one is diff --git a/src/context.cc b/src/context.cc index b88400dc..84b83405 100644 --- a/src/context.cc +++ b/src/context.cc @@ -13,9 +13,10 @@ Context::Context() = default; Context::~Context() = default; Context::Context(InputHandler& input_handler, SelectionList selections, - String name) + Flags flags, String name) : m_input_handler{&input_handler}, m_selections{std::move(selections)}, + m_flags(flags), m_name(std::move(name)) {} diff --git a/src/context.hh b/src/context.hh index be602033..dd94fab9 100644 --- a/src/context.hh +++ b/src/context.hh @@ -3,6 +3,7 @@ #include "selection.hh" #include "optional.hh" +#include "flags.hh" namespace Kakoune { @@ -56,9 +57,15 @@ private: class Context { public: + enum class Flags + { + None = 0, + Transient = 1, + }; + Context(); Context(InputHandler& input_handler, SelectionList selections, - String name = ""); + Flags flags, String name = ""); ~Context(); Context(const Context&) = delete; @@ -120,6 +127,8 @@ public: Disableable& history_support() { return m_history_support; } const Disableable& history_support() const { return m_history_support; } + Flags flags() const { return m_flags; } + private: void begin_edition(); void end_edition(); @@ -127,6 +136,8 @@ private: friend struct ScopedEdition; + Flags m_flags; + safe_ptr m_input_handler; safe_ptr m_window; safe_ptr m_client; @@ -145,6 +156,9 @@ private: Disableable m_history_support; }; +template<> +struct WithBitOps : std::true_type {}; + struct ScopedEdition { ScopedEdition(Context& context) diff --git a/src/event_manager.cc b/src/event_manager.cc index e9776e55..26a57eab 100644 --- a/src/event_manager.cc +++ b/src/event_manager.cc @@ -30,18 +30,19 @@ void FDWatcher::close_fd() Timer::Timer(TimePoint date, Callback callback, EventMode mode) : m_date{date}, m_callback{std::move(callback)}, m_mode(mode) { - if (EventManager::has_instance()) + if (m_callback and EventManager::has_instance()) EventManager::instance().m_timers.push_back(this); } Timer::~Timer() { - if (EventManager::has_instance()) + if (m_callback and EventManager::has_instance()) unordered_erase(EventManager::instance().m_timers, this); } void Timer::run(EventMode mode) { + kak_assert(m_callback); if (mode == m_mode) { m_date = TimePoint::max(); diff --git a/src/input_handler.cc b/src/input_handler.cc index ae6ac83b..4cc6d5ee 100644 --- a/src/input_handler.cc +++ b/src/input_handler.cc @@ -52,17 +52,21 @@ static constexpr std::chrono::milliseconds fs_check_timeout{500}; class Normal : public InputMode { public: - Normal(InputHandler& input_handler) + Normal(InputHandler& input_handler, bool with_timers = true) : InputMode(input_handler), - m_idle_timer{Clock::now() + idle_timeout, [this](Timer& timer) { + m_idle_timer{Clock::now() + idle_timeout, + context().flags() & Context::Flags::Transient ? + Timer::Callback() : Timer::Callback([this](Timer& timer) { context().hooks().run_hook("NormalIdle", "", context()); - }}, - m_fs_check_timer{Clock::now() + fs_check_timeout, [this](Timer& timer) { + })}, + m_fs_check_timer{Clock::now() + fs_check_timeout, + context().flags() & Context::Flags::Transient ? + Timer::Callback() : Timer::Callback([this](Timer& timer) { if (not context().has_client()) return; context().client().check_buffer_fs_timestamp(); timer.set_next_date(Clock::now() + fs_check_timeout); - }} + })} {} void on_enabled() override @@ -1034,9 +1038,10 @@ void InputMode::reset_normal_mode() m_input_handler.reset_normal_mode(); } -InputHandler::InputHandler(SelectionList selections, String name) - : m_mode(new InputModes::Normal(*this)), - m_context(*this, std::move(selections), std::move(name)) +InputHandler::InputHandler(SelectionList selections, Context::Flags flags, String name) + : m_context(*this, std::move(selections), flags, std::move(name)), + m_mode(new InputModes::Normal(*this)) + { } diff --git a/src/input_handler.hh b/src/input_handler.hh index 858ad360..f65d4978 100644 --- a/src/input_handler.hh +++ b/src/input_handler.hh @@ -38,7 +38,9 @@ enum class KeymapMode : int; class InputHandler : public SafeCountable { public: - InputHandler(SelectionList selections, String name = ""); + InputHandler(SelectionList selections, + Context::Flags flags = Context::Flags::None, + String name = ""); ~InputHandler(); // switch to insert mode @@ -80,6 +82,7 @@ public: DisplayLine mode_line() const; void clear_mode_trash(); + private: Context m_context; diff --git a/src/main.cc b/src/main.cc index 51e14aca..8b5d0114 100644 --- a/src/main.cc +++ b/src/main.cc @@ -441,7 +441,10 @@ int run_filter(StringView keystr, memoryview files, bool quiet) { try { - InputHandler input_handler{{ buffer, Selection{{0,0}, buffer.back_coord()} }}; + InputHandler input_handler{ + { buffer, {{0,0}, buffer.back_coord()} }, + Context::Flags::Transient + }; for (auto& key : keys) input_handler.handle_key(key); diff --git a/src/window.cc b/src/window.cc index 0e345834..b46aaaaf 100644 --- a/src/window.cc +++ b/src/window.cc @@ -21,9 +21,8 @@ Window::Window(Buffer& buffer) : Scope(buffer), m_buffer(&buffer) { - InputHandler hook_handler{{ *m_buffer, Selection{} }}; - hook_handler.context().set_window(*this); - hooks().run_hook("WinCreate", buffer.name(), hook_handler.context()); + run_hook_in_own_context("WinCreate", buffer.name()); + options().register_watcher(*this); m_builtin_highlighters.add_child({"tabulations"_str, make_simple_highlighter(expand_tabulations)}); @@ -36,9 +35,7 @@ Window::Window(Buffer& buffer) Window::~Window() { - InputHandler hook_handler{{ *m_buffer, Selection{} }}; - hook_handler.context().set_window(*this); - hooks().run_hook("WinClose", buffer().name(), hook_handler.context()); + run_hook_in_own_context("WinClose", buffer().name()); options().unregister_watcher(*this); } @@ -266,10 +263,10 @@ ByteCoordAndTarget Window::offset_coord(ByteCoordAndTarget coord, LineCount offs BufferRange range{ std::min(line, coord.line), std::max(line,coord.line)+1}; - InputHandler hook_handler{{ *m_buffer, Selection{} } }; - hook_handler.context().set_window(*this); - m_highlighters.highlight(hook_handler.context(), HighlightFlags::MoveOnly, display_buffer, range); - m_builtin_highlighters.highlight(hook_handler.context(), HighlightFlags::MoveOnly, display_buffer, range); + InputHandler input_handler{{ *m_buffer, Selection{} }, Context::Flags::Transient}; + input_handler.context().set_window(*this); + m_highlighters.highlight(input_handler.context(), HighlightFlags::MoveOnly, display_buffer, range); + m_builtin_highlighters.highlight(input_handler.context(), HighlightFlags::MoveOnly, display_buffer, range); CharCount column = coord.target == -1 ? find_display_column(lines[0], buffer(), coord) : coord.target; return { find_buffer_coord(lines[1], buffer(), column), column }; @@ -278,12 +275,17 @@ ByteCoordAndTarget Window::offset_coord(ByteCoordAndTarget coord, LineCount offs void Window::on_option_changed(const Option& option) { String desc = option.name() + "=" + option.get_as_string(); - InputHandler hook_handler{{ *m_buffer, Selection{} }}; - hook_handler.context().set_window(*this); - hooks().run_hook("WinSetOption", desc, hook_handler.context()); + run_hook_in_own_context("WinSetOption", desc); // an highlighter might depend on the option, so we need to redraw forget_timestamp(); } + +void Window::run_hook_in_own_context(const String& hook_name, StringView param) +{ + InputHandler hook_handler({ *m_buffer, Selection{} }, Context::Flags::Transient); + hook_handler.context().set_window(*this); + hooks().run_hook(hook_name, param, hook_handler.context()); +} } diff --git a/src/window.hh b/src/window.hh index c5efdf27..978fb374 100644 --- a/src/window.hh +++ b/src/window.hh @@ -48,6 +48,8 @@ private: void on_option_changed(const Option& option) override; void scroll_to_keep_selection_visible_ifn(const Context& context); + void run_hook_in_own_context(const String& hook_name, StringView param); + safe_ptr m_buffer; CharCoord m_position;