diff options
-rw-r--r-- | src/nvim/getchar.c | 2 | ||||
-rw-r--r-- | src/nvim/normal.c | 32 | ||||
-rw-r--r-- | src/nvim/os/input.c | 11 |
3 files changed, 37 insertions, 8 deletions
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 990d0fb8e2..b77a030158 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -1131,7 +1131,7 @@ static void gotchars(char_u *chars, int len) * - While reading a script file. * - When no_u_sync is non-zero. */ -static void may_sync_undo(void) +void may_sync_undo(void) { if ((!(State & (INSERT + CMDLINE)) || arrow_used) && scriptin[curscript] == NULL) diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 1f2d6f9caf..8f08fe2eed 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -464,10 +464,34 @@ void normal_enter(bool cmdwin, bool noexmode) continue; } - input_enable_events(); - int c = safe_vgetc(); - input_disable_events(); - if (!normal_execute(&state, c)) { + int key; + + if (char_avail() || using_script() || input_available()) { + // Don't block for events if there's a character already available for + // processing. Characters can come from mappings, scripts and other + // sources, so this scenario is very common. + key = safe_vgetc(); + } else if (!queue_empty(loop.events)) { + // Event was made available after the last queue_process_events call + key = K_EVENT; + } else { + input_enable_events(); + // Flush screen updates before blocking + ui_flush(); + // 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. If an event was put into the queue, we send K_EVENT + // directly. + (void)os_inchar(NULL, 0, -1, 0); + input_disable_events(); + key = !queue_empty(loop.events) ? K_EVENT : safe_vgetc(); + } + + if (key == K_EVENT) { + may_sync_undo(); + } + + if (!normal_execute(&state, key)) { break; } } diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index 9061a5ce2e..df803609ae 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -91,7 +91,7 @@ static void create_cursorhold_event(void) // Low level input function int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt) { - if (rbuffer_size(input_buffer)) { + if (maxlen && rbuffer_size(input_buffer)) { return (int)rbuffer_read(input_buffer, (char *)buf, (size_t)maxlen); } @@ -116,14 +116,14 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt) return 0; } - if (rbuffer_size(input_buffer)) { + if (maxlen && rbuffer_size(input_buffer)) { // 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); } // If there are events, return the keys directly - if (pending_events()) { + if (maxlen && pending_events()) { return push_event_key(buf, maxlen); } @@ -324,6 +324,11 @@ void input_done(void) input_eof = true; } +bool input_available(void) +{ + return rbuffer_size(input_buffer) != 0; +} + // This is a replacement for the old `WaitForChar` function in os_unix.c static InbufPollResult inbuf_poll(int ms) { |