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:
parent
71b003b684
commit
6e4bb5fbc5
|
@ -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*>(¤t_mode()) != nullptr);
|
kak_assert(dynamic_cast<InputModes::Normal*>(¤t_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.
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
|
|
1
test/regression/5122-dot-fails-after-macro-replay/cmd
Normal file
1
test/regression/5122-dot-fails-after-macro-replay/cmd
Normal file
|
@ -0,0 +1 @@
|
||||||
|
QA?<esc>Qq.
|
1
test/regression/5122-dot-fails-after-macro-replay/in
Normal file
1
test/regression/5122-dot-fails-after-macro-replay/in
Normal file
|
@ -0,0 +1 @@
|
||||||
|
|
1
test/regression/5122-dot-fails-after-macro-replay/out
Normal file
1
test/regression/5122-dot-fails-after-macro-replay/out
Normal file
|
@ -0,0 +1 @@
|
||||||
|
???
|
Loading…
Reference in New Issue
Block a user