aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/tui/input.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/tui/input.c')
-rw-r--r--src/nvim/tui/input.c44
1 files changed, 36 insertions, 8 deletions
diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c
index bdbb5e4872..b9e2d2c9ee 100644
--- a/src/nvim/tui/input.c
+++ b/src/nvim/tui/input.c
@@ -7,7 +7,6 @@
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
#include "nvim/event/defs.h"
-#include "nvim/func_attr.h"
#include "nvim/macros_defs.h"
#include "nvim/main.h"
#include "nvim/map_defs.h"
@@ -28,6 +27,11 @@
#define READ_STREAM_SIZE 0xfff
#define KEY_BUFFER_SIZE 0xfff
+/// Size of libtermkey's internal input buffer. The buffer may grow larger than
+/// this when processing very long escape sequences, but will shrink back to
+/// this size afterward
+#define INPUT_BUFFER_SIZE 256
+
static const struct kitty_key_map_entry {
int key;
const char *name;
@@ -140,6 +144,7 @@ void tinput_init(TermInput *input, Loop *loop)
input->tk = termkey_new_abstract(term,
TERMKEY_FLAG_UTF8 | TERMKEY_FLAG_NOSTART);
+ termkey_set_buffer_size(input->tk, INPUT_BUFFER_SIZE);
termkey_hook_terminfo_getstr(input->tk, input->tk_ti_hook_fn, input);
termkey_start(input->tk);
@@ -148,7 +153,6 @@ void tinput_init(TermInput *input, Loop *loop)
// setup input handle
rstream_init_fd(loop, &input->read_stream, input->in_fd, READ_STREAM_SIZE);
- termkey_set_buffer_size(input->tk, rbuffer_capacity(input->read_stream.buffer));
// initialize a timer handle for handling ESC with libtermkey
time_watcher_init(loop, &input->timer_handle, input);
@@ -692,20 +696,44 @@ static void handle_raw_buffer(TermInput *input, bool force)
}
// Push through libtermkey (translates to "<keycode>" strings, etc.).
RBUFFER_UNTIL_EMPTY(input->read_stream.buffer, ptr, len) {
- size_t consumed = termkey_push_bytes(input->tk, ptr, MIN(count, len));
- // termkey_push_bytes can return (size_t)-1, so it is possible that
- // `consumed > rbuffer_size(input->read_stream.buffer)`, but since tk_getkeys is
- // called soon, it shouldn't happen.
+ const size_t size = MIN(count, len);
+ if (size > termkey_get_buffer_remaining(input->tk)) {
+ // We are processing a very long escape sequence. Increase termkey's
+ // internal buffer size. We don't handle out of memory situations so
+ // abort if it fails
+ const size_t delta = size - termkey_get_buffer_remaining(input->tk);
+ const size_t bufsize = termkey_get_buffer_size(input->tk);
+ if (!termkey_set_buffer_size(input->tk, MAX(bufsize + delta, bufsize * 2))) {
+ abort();
+ }
+ }
+
+ size_t consumed = termkey_push_bytes(input->tk, ptr, size);
+
+ // We resize termkey's buffer when it runs out of space, so this should
+ // never happen
assert(consumed <= rbuffer_size(input->read_stream.buffer));
rbuffer_consumed(input->read_stream.buffer, consumed);
- // Process the keys now: there is no guarantee `count` will
- // fit into libtermkey's input buffer.
+
+ // Process the input buffer now for any keys
tk_getkeys(input, false);
+
if (!(count -= consumed)) {
break;
}
}
} while (rbuffer_size(input->read_stream.buffer));
+
+ const size_t tk_size = termkey_get_buffer_size(input->tk);
+ const size_t tk_remaining = termkey_get_buffer_remaining(input->tk);
+ const size_t tk_count = tk_size - tk_remaining;
+ if (tk_count < INPUT_BUFFER_SIZE && tk_size > INPUT_BUFFER_SIZE) {
+ // If the termkey buffer was resized to handle a large input sequence then
+ // shrink it back down to its original size.
+ if (!termkey_set_buffer_size(input->tk, INPUT_BUFFER_SIZE)) {
+ abort();
+ }
+ }
}
static void tinput_read_cb(Stream *stream, RBuffer *buf, size_t count_, void *data, bool eof)