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.c90
1 files changed, 56 insertions, 34 deletions
diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c
index bdbb5e4872..214474ff51 100644
--- a/src/nvim/tui/input.c
+++ b/src/nvim/tui/input.c
@@ -6,14 +6,16 @@
#include "klib/kvec.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
-#include "nvim/event/defs.h"
-#include "nvim/func_attr.h"
+#include "nvim/event/loop.h"
+#include "nvim/event/stream.h"
#include "nvim/macros_defs.h"
#include "nvim/main.h"
#include "nvim/map_defs.h"
#include "nvim/memory.h"
#include "nvim/option_vars.h"
#include "nvim/os/os.h"
+#include "nvim/os/os_defs.h"
+#include "nvim/rbuffer.h"
#include "nvim/strings.h"
#include "nvim/tui/input.h"
#include "nvim/tui/input_defs.h"
@@ -28,6 +30,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 +147,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,17 +156,17 @@ 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);
+ uv_timer_init(&loop->uv, &input->timer_handle);
+ input->timer_handle.data = input;
}
void tinput_destroy(TermInput *input)
{
map_destroy(int, &kitty_key_map);
rbuffer_free(input->key_buffer);
- time_watcher_close(&input->timer_handle, NULL);
+ uv_close((uv_handle_t *)&input->timer_handle, NULL);
stream_close(&input->read_stream, NULL, NULL);
termkey_destroy(input->tk);
}
@@ -171,7 +179,7 @@ void tinput_start(TermInput *input)
void tinput_stop(TermInput *input)
{
rstream_stop(&input->read_stream);
- time_watcher_stop(&input->timer_handle);
+ uv_timer_stop(&input->timer_handle);
}
static void tinput_done_event(void **argv)
@@ -231,13 +239,13 @@ static size_t handle_termkey_modifiers(TermKeyKey *key, char *buf, size_t buflen
{
size_t len = 0;
if (key->modifiers & TERMKEY_KEYMOD_SHIFT) { // Shift
- len += (size_t)snprintf(buf + len, sizeof(buf) - len, "S-");
+ len += (size_t)snprintf(buf + len, buflen - len, "S-");
}
if (key->modifiers & TERMKEY_KEYMOD_ALT) { // Alt
- len += (size_t)snprintf(buf + len, sizeof(buf) - len, "A-");
+ len += (size_t)snprintf(buf + len, buflen - len, "A-");
}
if (key->modifiers & TERMKEY_KEYMOD_CTRL) { // Ctrl
- len += (size_t)snprintf(buf + len, sizeof(buf) - len, "C-");
+ len += (size_t)snprintf(buf + len, buflen - len, "C-");
}
assert(len < buflen);
return len;
@@ -364,15 +372,6 @@ static void forward_mouse_event(TermInput *input, TermKeyKey *key)
button = last_pressed_button;
}
- if (ev == TERMKEY_MOUSE_UNKNOWN && !(key->code.mouse[0] & 0x20)) {
- int code = key->code.mouse[0] & ~0x3c;
- // https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Other-buttons
- if (code == 66 || code == 67) {
- ev = TERMKEY_MOUSE_PRESS;
- button = code + 4 - 64;
- }
- }
-
if ((button == 0 && ev != TERMKEY_MOUSE_RELEASE)
|| (ev != TERMKEY_MOUSE_PRESS && ev != TERMKEY_MOUSE_DRAG && ev != TERMKEY_MOUSE_RELEASE)) {
return;
@@ -461,17 +460,16 @@ static void tk_getkeys(TermInput *input, bool force)
if (input->ttimeout && input->ttimeoutlen >= 0) {
// Stop the current timer if already running
- time_watcher_stop(&input->timer_handle);
- time_watcher_start(&input->timer_handle, tinput_timer_cb,
- (uint64_t)input->ttimeoutlen, 0);
+ uv_timer_stop(&input->timer_handle);
+ uv_timer_start(&input->timer_handle, tinput_timer_cb, (uint64_t)input->ttimeoutlen, 0);
} else {
tk_getkeys(input, true);
}
}
-static void tinput_timer_cb(TimeWatcher *watcher, void *data)
+static void tinput_timer_cb(uv_timer_t *handle)
{
- TermInput *input = (TermInput *)data;
+ TermInput *input = handle->data;
// If the raw buffer is not empty, process the raw buffer first because it is
// processing an incomplete bracketed paster sequence.
if (rbuffer_size(input->read_stream.buffer)) {
@@ -484,8 +482,8 @@ static void tinput_timer_cb(TimeWatcher *watcher, void *data)
/// Handle focus events.
///
/// If the upcoming sequence of bytes in the input stream matches the termcode
-/// for "focus gained" or "focus lost", consume that sequence and schedule an
-/// event on the main loop.
+/// for "focus gained" or "focus lost", consume that sequence and send an event
+/// to Nvim server.
///
/// @param input the input stream
/// @return true iff handle_focus_event consumed some input
@@ -692,20 +690,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)
@@ -713,7 +735,7 @@ static void tinput_read_cb(Stream *stream, RBuffer *buf, size_t count_, void *da
TermInput *input = data;
if (eof) {
- loop_schedule_fast(&main_loop, event_create(tinput_done_event, 0));
+ loop_schedule_fast(&main_loop, event_create(tinput_done_event, NULL));
return;
}
@@ -728,8 +750,8 @@ static void tinput_read_cb(Stream *stream, RBuffer *buf, size_t count_, void *da
int64_t ms = input->ttimeout
? (input->ttimeoutlen >= 0 ? input->ttimeoutlen : 0) : 0;
// Stop the current timer if already running
- time_watcher_stop(&input->timer_handle);
- time_watcher_start(&input->timer_handle, tinput_timer_cb, (uint32_t)ms, 0);
+ uv_timer_stop(&input->timer_handle);
+ uv_timer_start(&input->timer_handle, tinput_timer_cb, (uint32_t)ms, 0);
return;
}