diff options
Diffstat (limited to 'src/nvim/tui/term_input.inl')
-rw-r--r-- | src/nvim/tui/term_input.inl | 62 |
1 files changed, 54 insertions, 8 deletions
diff --git a/src/nvim/tui/term_input.inl b/src/nvim/tui/term_input.inl index 0c0e6c07c9..dba970e8f2 100644 --- a/src/nvim/tui/term_input.inl +++ b/src/nvim/tui/term_input.inl @@ -1,10 +1,12 @@ #include <termkey.h> #include "nvim/ascii.h" +#include "nvim/misc2.h" #include "nvim/os/os.h" #include "nvim/os/input.h" #include "nvim/os/rstream.h" +#define PASTETOGGLE_KEY "<f37>" struct term_input { int in_fd; @@ -113,7 +115,7 @@ static int get_key_code_timeout(void) bool timeout = false; // Check 'timeout' and 'ttimeout' to determine if we should send ESC // after 'ttimeoutlen'. See :help 'ttimeout' for more information - Error err; + Error err = ERROR_INIT; timeout = vim_get_option(cstr_as_string("timeout"), &err).data.boolean; if (!timeout) { timeout = vim_get_option(cstr_as_string("ttimeout"), &err).data.boolean; @@ -164,6 +166,49 @@ static void timer_cb(uv_timer_t *handle) tk_getkeys(handle->data, true); } +static bool handle_bracketed_paste(TermInput *input) +{ + char *ptr = rbuffer_read_ptr(input->read_buffer); + size_t len = rbuffer_pending(input->read_buffer); + if (len > 5 && (!strncmp(ptr, "\x1b[200~", 6) + || !strncmp(ptr, "\x1b[201~", 6))) { + bool enable = ptr[4] == '0'; + // Advance past the sequence + rbuffer_consumed(input->read_buffer, 6); + if (enable) { + // Get the current mode + int state = get_real_state(); + if (state & NORMAL) { + // Enter insert mode + input_enqueue(cstr_as_string("i")); + } else if (state & VISUAL) { + // Remove the selected text and enter insert mode + input_enqueue(cstr_as_string("c")); + } else if (!(state & INSERT)) { + // Don't mess with the paste option + return true; + } + } + input_enqueue(cstr_as_string(PASTETOGGLE_KEY)); + return true; + } + return false; +} + +static bool handle_forced_escape(TermInput *input) +{ + char *ptr = rbuffer_read_ptr(input->read_buffer); + size_t len = rbuffer_pending(input->read_buffer); + if (len > 1 && ptr[0] == ESC && ptr[1] == NUL) { + // skip the ESC and NUL and push one <esc> to the input buffer + termkey_push_bytes(input->tk, ptr, 1); + rbuffer_consumed(input->read_buffer, 2); + tk_getkeys(input, true); + return true; + } + return false; +} + static void read_cb(RStream *rstream, void *rstream_data, bool eof) { if (eof) { @@ -174,15 +219,11 @@ static void read_cb(RStream *rstream, void *rstream_data, bool eof) TermInput *input = rstream_data; do { - char *ptr = rbuffer_read_ptr(input->read_buffer); - size_t len = rbuffer_pending(input->read_buffer); - if (len > 1 && ptr[0] == ESC && ptr[1] == NUL) { - // skip the ESC and NUL and push one <esc> to the input buffer - termkey_push_bytes(input->tk, ptr, 1); - rbuffer_consumed(input->read_buffer, 2); - tk_getkeys(input, true); + if (handle_bracketed_paste(input) || handle_forced_escape(input)) { continue; } + char *ptr = rbuffer_read_ptr(input->read_buffer); + size_t len = rbuffer_pending(input->read_buffer); // Find the next 'esc' and push everything up to it(excluding) size_t i; for (i = ptr[0] == ESC ? 1 : 0; i < len; i++) { @@ -228,6 +269,11 @@ static TermInput *term_input_new(void) // initialize a timer handle for handling ESC with libtermkey uv_timer_init(uv_default_loop(), &rv->timer_handle); rv->timer_handle.data = rv; + // Set the pastetoggle option to a special key that will be sent when + // \e[20{0,1}~/ are received + Error err = ERROR_INIT; + vim_set_option(cstr_as_string("pastetoggle"), + STRING_OBJ(cstr_as_string(PASTETOGGLE_KEY)), &err); return rv; } |