Refactor last insert recording logic

Only record non-synthetized insertions, removing the need to
re-record on replay and fixing the last replay getting dropped by
macro execution.

Fixes #5122
This commit is contained in:
Maxime Coste 2024-03-23 16:25:32 +11:00
parent 71b003b684
commit 6e4bb5fbc5
6 changed files with 35 additions and 35 deletions

View File

@ -56,7 +56,6 @@ public:
} }
using Insertion = InputHandler::Insertion; using Insertion = InputHandler::Insertion;
Insertion& last_insert() { return m_input_handler.m_last_insert; }
protected: protected:
virtual void on_key(Key key, bool synthesized) = 0; virtual void on_key(Key key, bool synthesized) = 0;
@ -1140,11 +1139,12 @@ private:
class Insert : public InputMode class Insert : public InputMode
{ {
public: public:
Insert(InputHandler& input_handler, InsertMode mode, int count) Insert(InputHandler& input_handler, InsertMode mode, int count, Insertion* last_insert)
: InputMode(input_handler), : InputMode(input_handler),
m_edition(context()), m_edition(context()),
m_selection_edition(context()), m_selection_edition(context()),
m_completer(context()), m_completer(context()),
m_last_insert(last_insert),
m_restore_cursor(mode == InsertMode::Append), m_restore_cursor(mode == InsertMode::Append),
m_auto_complete{context().options()["autocomplete"].get<AutoComplete>() & AutoComplete::Insert}, m_auto_complete{context().options()["autocomplete"].get<AutoComplete>() & AutoComplete::Insert},
m_idle_timer{TimePoint::max(), context().flags() & Context::Flags::Draft ? m_idle_timer{TimePoint::max(), context().flags() & Context::Flags::Draft ?
@ -1157,11 +1157,14 @@ public:
{ {
context().buffer().throw_if_read_only(); context().buffer().throw_if_read_only();
last_insert().recording.set(); if (m_last_insert)
last_insert().mode = mode; {
last_insert().keys.clear(); m_last_insert->recording.set();
last_insert().disable_hooks = context().hooks_disabled(); m_last_insert->mode = mode;
last_insert().count = count; m_last_insert->keys.clear();
m_last_insert->disable_hooks = context().hooks_disabled();
m_last_insert->count = count;
}
prepare(mode, count); prepare(mode, count);
} }
@ -1177,7 +1180,8 @@ public:
if (not from_push) if (not from_push)
{ {
last_insert().recording.unset(); if (m_last_insert)
m_last_insert->recording.unset();
auto& selections = context().selections(); auto& selections = context().selections();
if (m_restore_cursor) if (m_restore_cursor)
@ -1291,11 +1295,11 @@ public:
} }
else if (key == ctrl('n') or key == ctrl('p') or key.modifiers == Key::Modifiers::MenuSelect) else if (key == ctrl('n') or key == ctrl('p') or key.modifiers == Key::Modifiers::MenuSelect)
{ {
if (not synthesized) if (m_last_insert and not synthesized)
last_insert().keys.pop_back(); m_last_insert->keys.pop_back();
bool relative = key.modifiers != Key::Modifiers::MenuSelect; bool relative = key.modifiers != Key::Modifiers::MenuSelect;
int index = relative ? (key == ctrl('n') ? 1 : -1) : key.key; int index = relative ? (key == ctrl('n') ? 1 : -1) : key.key;
m_completer.select(index, relative, last_insert().keys); m_completer.select(index, relative, m_last_insert ? &m_last_insert->keys : nullptr);
update_completions = false; update_completions = false;
} }
else if (key == ctrl('x')) else if (key == ctrl('x'))
@ -1494,6 +1498,7 @@ private:
ScopedEdition m_edition; ScopedEdition m_edition;
ScopedSelectionEdition m_selection_edition; ScopedSelectionEdition m_selection_edition;
InsertCompleter m_completer; InsertCompleter m_completer;
Insertion* m_last_insert;
const bool m_restore_cursor; const bool m_restore_cursor;
bool m_auto_complete; bool m_auto_complete;
Timer m_idle_timer; Timer m_idle_timer;
@ -1550,7 +1555,7 @@ void InputHandler::reset_normal_mode()
void InputHandler::insert(InsertMode mode, int count) void InputHandler::insert(InsertMode mode, int count)
{ {
push_mode(new InputModes::Insert(*this, mode, count)); push_mode(new InputModes::Insert(*this, mode, count, m_handle_key_level <= 1 ? &m_last_insert : nullptr));
} }
void InputHandler::repeat_last_insert() void InputHandler::repeat_last_insert()
@ -1562,19 +1567,12 @@ void InputHandler::repeat_last_insert()
m_last_insert.recording) m_last_insert.recording)
throw runtime_error{"repeating last insert not available in this context"}; throw runtime_error{"repeating last insert not available in this context"};
Vector<Key> keys;
swap(keys, m_last_insert.keys);
ScopedSetBool disable_hooks(context().hooks_disabled(), ScopedSetBool disable_hooks(context().hooks_disabled(),
m_last_insert.disable_hooks); m_last_insert.disable_hooks);
push_mode(new InputModes::Insert(*this, m_last_insert.mode, m_last_insert.count)); push_mode(new InputModes::Insert(*this, m_last_insert.mode, m_last_insert.count, nullptr));
for (auto& key : keys) for (auto& key : m_last_insert.keys)
{
// refill last_insert, this is very inefficient, but necessary at the moment
// to properly handle insert completion
m_last_insert.keys.push_back(key);
handle_key(key); handle_key(key);
}
kak_assert(dynamic_cast<InputModes::Normal*>(&current_mode()) != nullptr); kak_assert(dynamic_cast<InputModes::Normal*>(&current_mode()) != nullptr);
} }
@ -1645,10 +1643,6 @@ void InputHandler::handle_key(Key key)
++m_handle_key_level; ++m_handle_key_level;
auto dec = on_scope_end([this]{ --m_handle_key_level;} ); auto dec = on_scope_end([this]{ --m_handle_key_level;} );
auto process_key = [&](Key key, bool synthesized) {
current_mode().handle_key(key, synthesized);
};
if (m_last_insert.recording and m_handle_key_level <= 1) if (m_last_insert.recording and m_handle_key_level <= 1)
m_last_insert.keys.push_back(key); m_last_insert.keys.push_back(key);
@ -1659,10 +1653,10 @@ void InputHandler::handle_key(Key key)
ScopedSetBool noninteractive{context().noninteractive()}; ScopedSetBool noninteractive{context().noninteractive()};
for (auto& k : keymaps.get_mapping_keys(key, keymap_mode)) for (auto& k : keymaps.get_mapping_keys(key, keymap_mode))
process_key(k, true); current_mode().handle_key(k, true);
} }
else else
process_key(key, m_handle_key_level > 1); current_mode().handle_key(key, m_handle_key_level > 1);
// do not record the key that made us enter or leave recording mode, // do not record the key that made us enter or leave recording mode,
// and the ones that are triggered recursively by previous keys. // and the ones that are triggered recursively by previous keys.

View File

@ -413,7 +413,7 @@ InsertCompleter::~InsertCompleter()
m_options.unregister_watcher(*this); m_options.unregister_watcher(*this);
} }
void InsertCompleter::select(int index, bool relative, Vector<Key>& keystrokes) void InsertCompleter::select(int index, bool relative, Vector<Key>* keystrokes)
{ {
m_enabled = true; m_enabled = true;
if (not setup_ifn()) if (not setup_ifn())
@ -450,12 +450,15 @@ void InsertCompleter::select(int index, bool relative, Vector<Key>& keystrokes)
m_context.client().menu_select(m_current_candidate); m_context.client().menu_select(m_current_candidate);
} }
if (keystrokes)
{
for (auto i = 0_byte; i < prefix_len; ++i) for (auto i = 0_byte; i < prefix_len; ++i)
keystrokes.emplace_back(Key::Backspace); keystrokes->emplace_back(Key::Backspace);
for (auto i = 0_byte; i < suffix_len; ++i) for (auto i = 0_byte; i < suffix_len; ++i)
keystrokes.emplace_back(Key::Delete); keystrokes->emplace_back(Key::Delete);
for (auto& c : candidate.completion) for (auto& c : candidate.completion)
keystrokes.emplace_back(c); keystrokes->emplace_back(c);
}
if (not candidate.on_select.empty()) if (not candidate.on_select.empty())
CommandManager::instance().execute(candidate.on_select, m_context); CommandManager::instance().execute(candidate.on_select, m_context);

View File

@ -78,7 +78,7 @@ public:
InsertCompleter& operator=(const InsertCompleter&) = delete; InsertCompleter& operator=(const InsertCompleter&) = delete;
~InsertCompleter(); ~InsertCompleter();
void select(int index, bool relative, Vector<Key>& keystrokes); void select(int index, bool relative, Vector<Key>* keystrokes);
void update(bool allow_implicit); void update(bool allow_implicit);
void try_accept(); void try_accept();
void reset(); void reset();

View File

@ -0,0 +1 @@
QA?<esc>Qq.

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@
???