From e3122ab2c19248b590cb0143610439ec050766b7 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Wed, 5 Jul 2023 22:00:32 +1000 Subject: [PATCH] Refactor prompt history handling Share incremental regex logic, pass the synthetized nature of keys through to input handlers. --- src/input_handler.cc | 55 ++++++++++++++------------------------------ src/normal.cc | 40 +++++++++----------------------- 2 files changed, 28 insertions(+), 67 deletions(-) diff --git a/src/input_handler.cc b/src/input_handler.cc index bbf9e7ea..66d30391 100644 --- a/src/input_handler.cc +++ b/src/input_handler.cc @@ -31,7 +31,7 @@ public: InputMode(const InputMode&) = delete; InputMode& operator=(const InputMode&) = delete; - void handle_key(Key key) { RefPtr keep_alive{this}; on_key(key); } + void handle_key(Key key, bool synthesized) { RefPtr keep_alive{this}; on_key(key, synthesized); } virtual void paste(StringView content); virtual void on_enabled() {} @@ -57,7 +57,7 @@ public: Insertion& last_insert() { return m_input_handler.m_last_insert; } protected: - virtual void on_key(Key key) = 0; + virtual void on_key(Key key, bool synthesized) = 0; void push_mode(InputMode* new_mode) { @@ -260,7 +260,7 @@ public: } } - void on_key(Key key) override + void on_key(Key key, bool) override { kak_assert(m_state != State::PopOnEnabled); ScopedSetBool set_in_on_key{m_in_on_key}; @@ -646,7 +646,7 @@ public: context().client().menu_select(0); } - void on_key(Key key) override + void on_key(Key key, bool) override { auto match_filter = [this](const DisplayLine& choice) { for (auto& atom : choice) @@ -808,9 +808,11 @@ public: m_line_editor.reset(std::move(initstr), m_empty_text); } - void on_key(Key key) override + void on_key(Key key, bool synthesized) override { const String& line = m_line_editor.line(); + if (not synthesized) + m_was_interactive = true; auto can_auto_insert_completion = [&] { const bool has_completions = not m_completions.candidates.empty(); @@ -1064,16 +1066,6 @@ public: } } - bool was_interactive() - { - return m_was_interactive; - } - - void set_was_interactive() - { - m_was_interactive = true; - } - DisplayLine mode_line() const override { return { "prompt", context().faces()["StatusLineMode"] }; @@ -1210,7 +1202,7 @@ private: void history_push(StringView entry) { - if (entry.empty() or not was_interactive() or + if (entry.empty() or not m_was_interactive or (m_flags & PromptFlags::DropHistoryEntriesWithBlankPrefix and is_horizontal_blank(entry[0_byte]))) return; @@ -1227,7 +1219,7 @@ public: : InputMode(input_handler), m_name{std::move(name)}, m_callback(std::move(callback)), m_keymap_mode(keymap_mode), m_idle_timer{Clock::now() + get_idle_timeout(context()), std::move(idle_callback)} {} - void on_key(Key key) override + void on_key(Key key, bool) override { // maintain hooks disabled in the callback if they were before pop_mode ScopedSetBool disable_hooks(context().hooks_disabled(), @@ -1306,7 +1298,7 @@ public: } } - void on_key(Key key) override + void on_key(Key key, bool) override { auto& buffer = context().buffer(); @@ -1697,7 +1689,7 @@ void InputHandler::repeat_last_insert() // refill last_insert, this is very inefficient, but necessary at the moment // to properly handle insert completion m_last_insert.keys.push_back(key); - current_mode().handle_key(key); + current_mode().handle_key(key, true); } kak_assert(dynamic_cast(¤t_mode()) != nullptr); } @@ -1718,17 +1710,10 @@ void InputHandler::prompt(StringView prompt, String initstr, String emptystr, void InputHandler::set_prompt_face(Face prompt_face) { - auto* prompt = dynamic_cast(¤t_mode()); - if (prompt) + if (auto* prompt = dynamic_cast(¤t_mode())) prompt->set_prompt_face(prompt_face); } -bool InputHandler::history_enabled() const -{ - auto* prompt = dynamic_cast(¤t_mode()); - return prompt and prompt->was_interactive(); -} - void InputHandler::menu(Vector choices, MenuCallback callback) { push_mode(new InputModes::Menu(*this, std::move(choices), std::move(callback))); @@ -1779,18 +1764,12 @@ void InputHandler::handle_key(Key key) const bool was_recording = is_recording(); ++m_handle_key_level; - auto dec = on_scope_end([this]{ - --m_handle_key_level; - if (m_handle_key_level == 0) - for (auto& mode : m_mode_stack) - if (auto* prompt = dynamic_cast(&*mode)) - prompt->set_was_interactive(); - }); + auto dec = on_scope_end([this]{ --m_handle_key_level;} ); - auto process_key = [&](Key key) { + auto process_key = [&](Key key, bool synthesized) { if (m_last_insert.recording) m_last_insert.keys.push_back(key); - current_mode().handle_key(key); + current_mode().handle_key(key, synthesized); }; const auto keymap_mode = current_mode().keymap_mode(); @@ -1800,10 +1779,10 @@ void InputHandler::handle_key(Key key) ScopedSetBool noninteractive{context().noninteractive()}; for (auto& k : keymaps.get_mapping_keys(key, keymap_mode)) - process_key(k); + process_key(k, true); } else - process_key(key); + process_key(key, m_handle_key_level > 1); // do not record the key that made us enter or leave recording mode, // and the ones that are triggered recursively by previous keys. diff --git a/src/normal.cc b/src/normal.cc index 1c264216..f03ba24e 100644 --- a/src/normal.cc +++ b/src/normal.cc @@ -834,7 +834,8 @@ void regex_prompt(Context& context, String prompt, char reg, T func) [&](auto&& m) { candidates.push_back(m.candidate().str()); return true; }); return {(int)(word.begin() - regex.begin()), pos, std::move(candidates) }; }, - [=, func=T(std::move(func)), selection_edition=std::make_shared(context)] + [=, func=T(std::move(func)), saved_reg=RegisterManager::instance()[reg].save(context), + selection_edition=std::make_shared(context)] (StringView str, PromptEvent event, Context& context) mutable { try { @@ -857,6 +858,11 @@ void regex_prompt(Context& context, String prompt, char reg, T func) if (event == PromptEvent::Validate) context.push_jump(); + else + RegisterManager::instance()[reg].restore(context, saved_reg); + + if (not str.empty() and event == PromptEvent::Change) // Ensure search register based highlighters work incrementally + RegisterManager::instance()[reg].set(context, str.str()); if (not str.empty() or event == PromptEvent::Validate) func(Regex{str.empty() ? default_regex : str, direction_flags(mode)}, event, context); @@ -930,13 +936,8 @@ void search(Context& context, NormalParams params) const int count = params.count; regex_prompt(context, prompt.str(), reg, - [reg, count, saved_reg = RegisterManager::instance()[reg].save(context)] + [reg, count] (const Regex& regex, PromptEvent event, Context& context) { - RegisterManager::instance()[reg].restore(context, saved_reg); - if (event == PromptEvent::Abort) - return; - RegisterManager::instance()[reg].set(context, regex.str()); - if (regex.empty() or regex.str().empty()) return; @@ -1017,14 +1018,8 @@ void select_regex(Context& context, NormalParams params) auto prompt = capture ? format("select (capture {}):", capture) : "select:"_str; regex_prompt(context, std::move(prompt), reg, - [reg, capture, saved_reg = RegisterManager::instance()[reg].save(context)] + [reg, capture] (Regex ex, PromptEvent event, Context& context) { - RegisterManager::instance()[reg].restore(context, saved_reg); - if (event == PromptEvent::Abort) - return; - if (context.input_handler().history_enabled()) - RegisterManager::instance()[reg].set(context, ex.str()); - auto& selections = context.selections(); auto& buffer = selections.buffer(); if (not ex.empty() and not ex.str().empty()) @@ -1039,14 +1034,8 @@ void split_regex(Context& context, NormalParams params) auto prompt = capture ? format("split (on capture {}):", (int)capture) : "split:"_str; regex_prompt(context, std::move(prompt), reg, - [reg, capture, saved_reg = RegisterManager::instance()[reg].save(context)] + [reg, capture] (Regex ex, PromptEvent event, Context& context) { - RegisterManager::instance()[reg].restore(context, saved_reg); - if (event == PromptEvent::Abort) - return; - if (context.input_handler().history_enabled()) - RegisterManager::instance()[reg].set(context, ex.str()); - auto& selections = context.selections(); auto& buffer = selections.buffer(); if (not ex.empty() and not ex.str().empty()) @@ -1142,15 +1131,8 @@ void keep(Context& context, NormalParams params) const char reg = to_lower(params.reg ? params.reg : '/'); regex_prompt(context, prompt.str(), reg, - [reg, saved_reg = RegisterManager::instance()[reg].save(context), - selection_edition=std::make_shared(context)] + [reg, selection_edition=std::make_shared(context)] (const Regex& regex, PromptEvent event, Context& context) { - RegisterManager::instance()[reg].restore(context, saved_reg); - if (event == PromptEvent::Abort) - return; - if (context.input_handler().history_enabled()) - RegisterManager::instance()[reg].set(context, regex.str()); - if (regex.empty() or regex.str().empty()) return;