1
1
mirror of https://github.com/mawww/kakoune.git synced 2024-11-23 15:23:29 +03:00

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.
This commit is contained in:
Maxime Coste 2024-07-22 17:43:37 +10:00
parent 6f562aa0ad
commit e938d724f1
14 changed files with 72 additions and 44 deletions

View File

@ -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());

View File

@ -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);

View File

@ -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*>(&current_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;

View File

@ -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

View File

@ -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())

View File

@ -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();

View File

@ -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)
{

View File

@ -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, {}));
}

View File

@ -0,0 +1 @@
Qofo<c-x><c-w><tab><esc>Qq

View File

@ -0,0 +1 @@
foobar

View File

@ -0,0 +1,3 @@
foobar
foobar
foobar

View File

@ -0,0 +1 @@
map global insert <tab> <c-n>