diff options
| author | Maxime Coste <mawww@kakoune.org> | 2024-07-22 17:43:37 +1000 |
|---|---|---|
| committer | Maxime Coste <mawww@kakoune.org> | 2024-07-22 20:22:14 +1000 |
| commit | e938d724f16ef06cbc97a4fedc20d56edf34e7f2 (patch) | |
| tree | bc5828353bdc26259b59bf6eadf8e7bb08b9f062 | |
| parent | 6f562aa0add09092d390f7ea2691959490234ed0 (diff) | |
Handle word completion when recording macros
Make last insert and macro recording closer together, paving the
way towards moving last insert to a register.
Use a FunctionRef for insert completer key insertion support.
| -rw-r--r-- | src/client.cc | 2 | ||||
| -rw-r--r-- | src/commands.cc | 4 | ||||
| -rw-r--r-- | src/input_handler.cc | 73 | ||||
| -rw-r--r-- | src/input_handler.hh | 13 | ||||
| -rw-r--r-- | src/insert_completer.cc | 9 | ||||
| -rw-r--r-- | src/insert_completer.hh | 3 | ||||
| -rw-r--r-- | src/main.cc | 2 | ||||
| -rw-r--r-- | src/normal.cc | 4 | ||||
| -rw-r--r-- | test/normal/macro/record-macro/cmd (renamed from test/normal/record-macro/cmd) | 0 | ||||
| -rw-r--r-- | test/normal/macro/record-macro/out (renamed from test/normal/record-macro/out) | 0 | ||||
| -rw-r--r-- | test/normal/macro/replay-macro-mapped-word-completion/cmd | 1 | ||||
| -rw-r--r-- | test/normal/macro/replay-macro-mapped-word-completion/in | 1 | ||||
| -rw-r--r-- | test/normal/macro/replay-macro-mapped-word-completion/out | 3 | ||||
| -rw-r--r-- | test/normal/macro/replay-macro-mapped-word-completion/rc | 1 |
14 files changed, 72 insertions, 44 deletions
diff --git a/src/client.cc b/src/client.cc index 6e5d082a..7cfea960 100644 --- a/src/client.cc +++ b/src/client.cc @@ -111,7 +111,7 @@ bool Client::process_pending_inputs() else { context().ensure_cursor_visible = true; - m_input_handler.handle_key(key); + m_input_handler.handle_key(key, false); } context().hooks().run_hook(Hook::RawKey, to_string(key), context()); diff --git a/src/commands.cc b/src/commands.cc index ef51555e..69fca0d6 100644 --- a/src/commands.cc +++ b/src/commands.cc @@ -2202,7 +2202,7 @@ const CommandDesc execute_keys_cmd = { ScopedSetBool disable_hooks(context.hooks_disabled(), not parser.get_switch("with-hooks")); for (auto& key : parser | transform(parse_keys) | flatten()) - context.input_handler().handle_key(key); + context.input_handler().handle_key(key, true); }); } }; @@ -2675,7 +2675,7 @@ void enter_user_mode(Context& context, String mode_name, KeymapMode mode, bool l ScopedEdition edition(context); for (auto& key : context.keymaps().get_mapping_keys(key, mode)) - context.input_handler().handle_key(key); + context.input_handler().handle_key(key, true); if (lock) enter_user_mode(context, std::move(mode_name), mode, true); diff --git a/src/input_handler.cc b/src/input_handler.cc index 15156c2b..2703b51a 100644 --- a/src/input_handler.cc +++ b/src/input_handler.cc @@ -67,15 +67,12 @@ public: protected: virtual void on_key(Key key, bool synthesized) = 0; - void push_mode(InputMode* new_mode) - { - m_input_handler.push_mode(new_mode); - } + void push_mode(InputMode* new_mode) { m_input_handler.push_mode(new_mode); } + void pop_mode() { m_input_handler.pop_mode(this); } + + void record_key(Key key) { m_input_handler.record_key(key); } + void drop_last_recorded_key() { m_input_handler.drop_last_recorded_key(); } - void pop_mode() - { - m_input_handler.pop_mode(this); - } private: InputHandler& m_input_handler; }; @@ -1307,11 +1304,10 @@ public: } else if (key == ctrl('n') or key == ctrl('p') or key.modifiers == Key::Modifiers::MenuSelect) { - if (m_last_insert) - m_last_insert->keys.pop_back(); + drop_last_recorded_key(); bool relative = key.modifiers != Key::Modifiers::MenuSelect; int index = relative ? (key == ctrl('n') ? 1 : -1) : key.key; - m_completer.select(index, relative, m_last_insert ? &m_last_insert->keys : nullptr); + m_completer.select(index, relative, [&](Key key) { record_key(key); }); update_completions = false; } else if (key == ctrl('x')) @@ -1585,7 +1581,7 @@ void InputHandler::repeat_last_insert() push_mode(new InputModes::Insert(*this, m_last_insert.mode, m_last_insert.count, nullptr)); for (auto& key : m_last_insert.keys) - handle_key(key); + handle_key(key, true); kak_assert(dynamic_cast<InputModes::Normal*>(¤t_mode()) != nullptr); } @@ -1647,18 +1643,16 @@ static bool is_valid(Key key) return ((key.modifiers & ~valid_mods) or key.key <= 0x10FFFF); } -void InputHandler::handle_key(Key key) +void InputHandler::handle_key(Key key, bool synthesized) { if (not is_valid(key)) return; - const bool was_recording = is_recording(); ++m_handle_key_level; auto dec = on_scope_end([this]{ --m_handle_key_level;} ); - auto process_key = [&](Key k, bool synthesized) { - if (m_last_insert.recording and m_handle_key_level <= 1) - m_last_insert.keys.push_back(k); + auto process_key = [this](Key k, bool synthesized) { + record_key(k); current_mode().handle_key(k, synthesized); }; @@ -1671,12 +1665,7 @@ void InputHandler::handle_key(Key key) process_key(k, true); } else - 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. - if (was_recording and is_recording() and m_handle_key_level == m_recording_level) - m_recorded_keys += to_string(key); + process_key(key, synthesized or m_handle_key_level > 1); if (m_handle_key_level < m_recording_level) { @@ -1686,6 +1675,29 @@ void InputHandler::handle_key(Key key) } } +void InputHandler::record_key(Key key) +{ + if (m_last_insert.recording and m_handle_key_level <= 1) + m_last_insert.keys.push_back(key); + if (is_recording() and m_handle_key_level == m_recording_level) + m_recorded_keys.push_back(key); +} + +void InputHandler::drop_last_recorded_key() +{ + if (m_last_insert.recording and m_handle_key_level <= 1) + { + kak_assert(not m_last_insert.keys.empty()); + m_last_insert.keys.pop_back(); + } + + if (is_recording() and m_handle_key_level == m_recording_level) + { + kak_assert(not m_recorded_keys.empty()); + m_recorded_keys.pop_back(); + } +} + void InputHandler::refresh_ifn() { current_mode().refresh_ifn(); @@ -1695,7 +1707,7 @@ void InputHandler::start_recording(char reg) { kak_assert(m_recording_reg == 0); m_recording_level = m_handle_key_level; - m_recorded_keys = ""; + m_recorded_keys.clear(); m_recording_reg = reg; } @@ -1707,10 +1719,17 @@ bool InputHandler::is_recording() const void InputHandler::stop_recording() { kak_assert(m_recording_reg != 0); - if (not m_recorded_keys.empty()) - RegisterManager::instance()[m_recording_reg].set( - context(), {m_recorded_keys}); + { + // Forget the key that got us to exit recording + if (m_handle_key_level == m_recording_level) + m_recorded_keys.pop_back(); + + String keys; + for (auto& key : m_recorded_keys) + keys += to_string(key); + RegisterManager::instance()[m_recording_reg].set(context(), {keys}); + } m_recording_reg = 0; m_recording_level = -1; diff --git a/src/input_handler.hh b/src/input_handler.hh index ba73d2b1..dd475c92 100644 --- a/src/input_handler.hh +++ b/src/input_handler.hh @@ -91,7 +91,7 @@ public: Timer::Callback idle_callback = Timer::Callback{}); // process the given key - void handle_key(Key key); + void handle_key(Key key, bool synthesized); void refresh_ifn(); @@ -131,6 +131,9 @@ private: void push_mode(InputMode* new_mode); void pop_mode(InputMode* current_mode); + void record_key(Key key); + void drop_last_recorded_key(); + struct Insertion{ NestedBool recording; InsertMode mode; @@ -139,11 +142,11 @@ private: int count; } m_last_insert = { {}, InsertMode::Insert, {}, false, 1 }; - char m_recording_reg = 0; - String m_recorded_keys; - int m_recording_level = -1; + int m_handle_key_level = 0; - int m_handle_key_level = 0; + char m_recording_reg = 0; + Vector<Key> m_recorded_keys; + int m_recording_level = -1; }; enum class AutoInfo diff --git a/src/insert_completer.cc b/src/insert_completer.cc index 3e1bcd2d..73c08a43 100644 --- a/src/insert_completer.cc +++ b/src/insert_completer.cc @@ -416,7 +416,7 @@ InsertCompleter::~InsertCompleter() m_options.unregister_watcher(*this); } -void InsertCompleter::select(int index, bool relative, Vector<Key>* keystrokes) +void InsertCompleter::select(int index, bool relative, FunctionRef<void (Key)> record_key) { m_enabled = true; if (not setup_ifn()) @@ -453,14 +453,13 @@ void InsertCompleter::select(int index, bool relative, Vector<Key>* keystrokes) m_context.client().menu_select(m_current_candidate); } - if (keystrokes) { for (auto i = 0_byte; i < prefix_len; ++i) - keystrokes->emplace_back(Key::Backspace); + record_key(Key::Backspace); for (auto i = 0_byte; i < suffix_len; ++i) - keystrokes->emplace_back(Key::Delete); + record_key(Key::Delete); for (auto& c : candidate.completion) - keystrokes->emplace_back(c); + record_key(c); } if (not candidate.on_select.empty()) diff --git a/src/insert_completer.hh b/src/insert_completer.hh index 3d5f2ca6..c624639d 100644 --- a/src/insert_completer.hh +++ b/src/insert_completer.hh @@ -5,6 +5,7 @@ #include "option.hh" #include "display_buffer.hh" #include "vector.hh" +#include "utils.hh" #include "optional.hh" @@ -78,7 +79,7 @@ public: InsertCompleter& operator=(const InsertCompleter&) = delete; ~InsertCompleter(); - void select(int index, bool relative, Vector<Key>* keystrokes); + void select(int index, bool relative, FunctionRef<void (Key)> record_key); void update(bool allow_implicit); void try_accept(); void reset(); diff --git a/src/main.cc b/src/main.cc index f2e31cab..e86ffae3 100644 --- a/src/main.cc +++ b/src/main.cc @@ -985,7 +985,7 @@ int run_filter(StringView keystr, ConstArrayView<StringView> files, bool quiet, }; for (auto& key : keys) - input_handler.handle_key(key); + input_handler.handle_key(key, true); } catch (runtime_error& err) { diff --git a/src/normal.cc b/src/normal.cc index af4d5fb1..9f1d3de7 100644 --- a/src/normal.cc +++ b/src/normal.cc @@ -1601,7 +1601,7 @@ void replay_macro(Context& context, NormalParams params) do { for (auto& key : keys) - context.input_handler().handle_key(key); + context.input_handler().handle_key(key, true); } while (--params.count > 0); } @@ -2073,7 +2073,7 @@ void exec_user_mappings(Context& context, NormalParams params) ScopedEdition edition(context); ScopedSelectionEdition selection_edition{context}; for (auto& key : context.keymaps().get_mapping_keys(key, KeymapMode::User)) - context.input_handler().handle_key(key); + context.input_handler().handle_key(key, true); }, "user mapping", build_autoinfo_for_mapping(context, KeymapMode::User, {})); } diff --git a/test/normal/record-macro/cmd b/test/normal/macro/record-macro/cmd index 72de722f..72de722f 100644 --- a/test/normal/record-macro/cmd +++ b/test/normal/macro/record-macro/cmd diff --git a/test/normal/record-macro/out b/test/normal/macro/record-macro/out index ead604b8..ead604b8 100644 --- a/test/normal/record-macro/out +++ b/test/normal/macro/record-macro/out diff --git a/test/normal/macro/replay-macro-mapped-word-completion/cmd b/test/normal/macro/replay-macro-mapped-word-completion/cmd new file mode 100644 index 00000000..34d8b4e6 --- /dev/null +++ b/test/normal/macro/replay-macro-mapped-word-completion/cmd @@ -0,0 +1 @@ +Qofo<c-x><c-w><tab><esc>Qq diff --git a/test/normal/macro/replay-macro-mapped-word-completion/in b/test/normal/macro/replay-macro-mapped-word-completion/in new file mode 100644 index 00000000..323fae03 --- /dev/null +++ b/test/normal/macro/replay-macro-mapped-word-completion/in @@ -0,0 +1 @@ +foobar diff --git a/test/normal/macro/replay-macro-mapped-word-completion/out b/test/normal/macro/replay-macro-mapped-word-completion/out new file mode 100644 index 00000000..96f98c7f --- /dev/null +++ b/test/normal/macro/replay-macro-mapped-word-completion/out @@ -0,0 +1,3 @@ +foobar +foobar +foobar diff --git a/test/normal/macro/replay-macro-mapped-word-completion/rc b/test/normal/macro/replay-macro-mapped-word-completion/rc new file mode 100644 index 00000000..71a61e52 --- /dev/null +++ b/test/normal/macro/replay-macro-mapped-word-completion/rc @@ -0,0 +1 @@ +map global insert <tab> <c-n> |
