aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/getchar.c2
-rw-r--r--src/nvim/normal.c32
-rw-r--r--src/nvim/os/input.c11
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)
{