aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbfredl <bjorn.linse@gmail.com>2022-09-18 11:37:22 +0200
committerGitHub <noreply@github.com>2022-09-18 11:37:22 +0200
commite63538f21c90112faafc65ae12766d1f9abd5bc0 (patch)
treef211af5f1926cb1fdde6083f2b51a52241c19967 /src
parent6d557e324fd4223fff3279a0112f40431c540163 (diff)
parent644a3f48b117abd1d0d0aab5ec96cd62392ca0f1 (diff)
downloadrneovim-e63538f21c90112faafc65ae12766d1f9abd5bc0.tar.gz
rneovim-e63538f21c90112faafc65ae12766d1f9abd5bc0.tar.bz2
rneovim-e63538f21c90112faafc65ae12766d1f9abd5bc0.zip
Merge pull request #20198 from zeertzjq/cursorhold
fix(events): make CursorHold behave as documented
Diffstat (limited to 'src')
-rw-r--r--src/nvim/getchar.c2
-rw-r--r--src/nvim/os/input.c24
-rw-r--r--src/nvim/state.c2
3 files changed, 24 insertions, 4 deletions
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index c93810df8d..fd0acce25f 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -1666,7 +1666,7 @@ static void getchar_common(typval_T *argvars, typval_T *rettv)
if (!char_avail()) {
// flush output before waiting
ui_flush();
- (void)os_inchar(NULL, 0, -1, 0, main_loop.events);
+ (void)os_inchar(NULL, 0, -1, typebuf.tb_change_cnt, main_loop.events);
if (!multiqueue_empty(main_loop.events)) {
state_handle_k_event();
continue;
diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c
index ea9f31d776..8fc4a5dce5 100644
--- a/src/nvim/os/input.c
+++ b/src/nvim/os/input.c
@@ -38,6 +38,8 @@ static RBuffer *input_buffer = NULL;
static bool input_eof = false;
static int global_fd = -1;
static bool blocking = false;
+static int cursorhold_time = 0; ///< time waiting for CursorHold event
+static int cursorhold_tb_change_cnt = 0; ///< tb_change_cnt when waiting started
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "os/input.c.generated.h"
@@ -97,13 +99,25 @@ static void create_cursorhold_event(bool events_enabled)
multiqueue_put(main_loop.events, cursorhold_event, 0);
}
+static void restart_cursorhold_wait(int tb_change_cnt)
+{
+ cursorhold_time = 0;
+ cursorhold_tb_change_cnt = tb_change_cnt;
+}
+
/// Low level input function
///
/// wait until either the input buffer is non-empty or, if `events` is not NULL
/// until `events` is non-empty.
int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *events)
{
+ // This check is needed so that feeding typeahead from RPC can prevent CursorHold.
+ if (tb_change_cnt != cursorhold_tb_change_cnt) {
+ restart_cursorhold_wait(tb_change_cnt);
+ }
+
if (maxlen && rbuffer_size(input_buffer)) {
+ restart_cursorhold_wait(tb_change_cnt);
return (int)rbuffer_read(input_buffer, (char *)buf, (size_t)maxlen);
}
@@ -118,18 +132,23 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *e
return 0;
}
} else {
- if ((result = inbuf_poll((int)p_ut, events)) == kInputNone) {
+ uint64_t wait_start = os_hrtime();
+ assert((int)p_ut >= cursorhold_time);
+ if ((result = inbuf_poll((int)p_ut - cursorhold_time, events)) == kInputNone) {
if (read_stream.closed && silent_mode) {
// Drained eventloop & initial input; exit silent/batch-mode (-es/-Es).
read_error_exit();
}
-
+ restart_cursorhold_wait(tb_change_cnt);
if (trigger_cursorhold() && !typebuf_changed(tb_change_cnt)) {
create_cursorhold_event(events == main_loop.events);
} else {
before_blocking();
result = inbuf_poll(-1, events);
}
+ } else {
+ cursorhold_time += (int)((os_hrtime() - wait_start) / 1000000);
+ cursorhold_time = MIN(cursorhold_time, (int)p_ut);
}
}
@@ -141,6 +160,7 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *e
}
if (maxlen && rbuffer_size(input_buffer)) {
+ restart_cursorhold_wait(tb_change_cnt);
// Safe to convert rbuffer_read to int, it will never overflow since we use
// relatively small buffers.
return (int)rbuffer_read(input_buffer, (char *)buf, (size_t)maxlen);
diff --git a/src/nvim/state.c b/src/nvim/state.c
index 458eed960f..8b07c484e6 100644
--- a/src/nvim/state.c
+++ b/src/nvim/state.c
@@ -65,7 +65,7 @@ getkey:
// Call `os_inchar` directly to block for events or user input without
// consuming anything from `input_buffer`(os/input.c) or calling the
// mapping engine.
- (void)os_inchar(NULL, 0, -1, 0, main_loop.events);
+ (void)os_inchar(NULL, 0, -1, typebuf.tb_change_cnt, main_loop.events);
// If an event was put into the queue, we send K_EVENT directly.
if (!multiqueue_empty(main_loop.events)) {
key = K_EVENT;