diff options
| author | Johannes Altmanninger <aclopte@gmail.com> | 2022-12-11 19:30:02 +0100 |
|---|---|---|
| committer | Johannes Altmanninger <aclopte@gmail.com> | 2023-03-11 16:21:57 +0100 |
| commit | b2cf74bb4a8286c5a191c54e947c0b2c9bb7cf96 (patch) | |
| tree | e1a41d87f4b1379f96356c43fa52dc9fb784f36b /src/input_handler.cc | |
| parent | ad36585b7ad236bea7d1c02b0679ae371c3c2a9e (diff) | |
Implement bracketed paste
Text pasted into Kakoune's normal mode is interpreted as command
sequence, which is probably never what the user wants. Text
pasted during insert mode will be inserted fine but may trigger
auto-indentation hooks which is likely not what users want.
Bracketed paste is pair of escape codes sent by terminals that allow
applications to distinguish between pasted text and typed text.
Let's use this feature to always insert pasted text verbatim, skipping
keymap lookup and the InsertChar hook. In future, we could add a
dedicated Paste hook.
We need to make a decision on whether to paste before or after the
selection. I chose "before" because that's what I'm used to.
TerminalUI::set_on_key has
EventManager::instance().force_signal(0);
I'm not sure if we want the same for TerminalUI::set_on_paste?
I assume it doesn't matter because they are always called in tandem.
Closes #2465
Diffstat (limited to 'src/input_handler.cc')
| -rw-r--r-- | src/input_handler.cc | 50 |
1 files changed, 48 insertions, 2 deletions
diff --git a/src/input_handler.cc b/src/input_handler.cc index 69ef3385..a24ddfa2 100644 --- a/src/input_handler.cc +++ b/src/input_handler.cc @@ -32,6 +32,7 @@ public: InputMode& operator=(const InputMode&) = delete; void handle_key(Key key) { RefPtr<InputMode> keep_alive{this}; on_key(key); } + virtual void paste(StringView content); virtual void on_enabled() {} virtual void on_disabled(bool temporary) {} @@ -71,6 +72,28 @@ private: InputHandler& m_input_handler; }; +void InputMode::paste(StringView content) +{ + try + { + Buffer& buffer = context().buffer(); + ScopedEdition edition{context()}; + ScopedSelectionEdition selection_edition{context()}; + context().selections().for_each([&buffer, content=std::move(content)] + (size_t index, Selection& sel) { + BufferRange range = buffer.insert(sel.min(), content); + sel.min() = range.begin; + sel.max() = range.end > range.begin ? buffer.char_prev(range.end) : range.begin; + }, false); + } + catch (Kakoune::runtime_error& error) + { + write_to_debug_buffer(format("Error: {}", error.what())); + context().print_status({error.what().str(), context().faces()["Error"] }); + context().hooks().run_hook(Hook::RuntimeError, error.what(), context()); + } +} + namespace InputModes { @@ -1015,6 +1038,17 @@ public: m_idle_timer.set_next_date(Clock::now() + get_idle_timeout(context())); } + void paste(StringView content) override + { + m_line_editor.insert(content); + clear_completions(); + m_refresh_completion_pending = true; + display(); + m_line_changed = true; + if (not (context().flags() & Context::Flags::Draft)) + m_idle_timer.set_next_date(Clock::now() + get_idle_timeout(context())); + } + void set_prompt_face(Face face) { if (face != m_prompt_face) @@ -1433,6 +1467,12 @@ public: m_idle_timer.set_next_date(Clock::now() + get_idle_timeout(context())); } + void paste(StringView content) override + { + insert(ConstArrayView{content}); + m_idle_timer.set_next_date(Clock::now() + get_idle_timeout(context())); + } + DisplayLine mode_line() const override { auto num_sel = context().selections().size(); @@ -1462,7 +1502,8 @@ private: selections.sort_and_merge_overlapping(); } - void insert(ConstArrayView<String> strings) + template<typename S> + void insert(ConstArrayView<S> strings) { m_completer.try_accept(); context().selections().for_each([strings, &buffer=context().buffer()] @@ -1474,7 +1515,7 @@ private: void insert(Codepoint key) { String str{key}; - insert(str); + insert(ConstArrayView{str}); context().hooks().run_hook(Hook::InsertChar, str, context()); } @@ -1644,6 +1685,11 @@ void InputHandler::repeat_last_insert() kak_assert(dynamic_cast<InputModes::Normal*>(¤t_mode()) != nullptr); } +void InputHandler::paste(StringView content) +{ + current_mode().paste(content); +} + void InputHandler::prompt(StringView prompt, String initstr, String emptystr, Face prompt_face, PromptFlags flags, char history_register, PromptCompleter completer, PromptCallback callback) |
