aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/os/input.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/os/input.c')
-rw-r--r--src/nvim/os/input.c121
1 files changed, 78 insertions, 43 deletions
diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c
index 0c46dc96ee..f62253cbce 100644
--- a/src/nvim/os/input.c
+++ b/src/nvim/os/input.c
@@ -1,3 +1,6 @@
+// This is an open source non-commercial project. Dear PVS-Studio, please check
+// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
+
#include <assert.h>
#include <string.h>
#include <stdbool.h>
@@ -19,7 +22,8 @@
#include "nvim/getchar.h"
#include "nvim/main.h"
#include "nvim/misc1.h"
-#include "nvim/misc2.h"
+#include "nvim/state.h"
+#include "nvim/msgpack_rpc/channel.h"
#define READ_BUFFER_SIZE 0xfff
#define INPUT_BUFFER_SIZE (READ_BUFFER_SIZE * 4)
@@ -30,24 +34,23 @@ typedef enum {
kInputEof
} InbufPollResult;
-static Stream read_stream = {.closed = true};
+static Stream read_stream = { .closed = true }; // Input before UI starts.
static RBuffer *input_buffer = NULL;
static bool input_eof = false;
-static int global_fd = 0;
+static int global_fd = -1;
static int events_enabled = 0;
+static bool blocking = false;
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "os/input.c.generated.h"
#endif
-// Helper function used to push bytes from the 'event' key sequence partially
-// between calls to os_inchar when maxlen < 3
void input_init(void)
{
input_buffer = rbuffer_new(INPUT_BUFFER_SIZE + MAX_KEY_CODE_LEN);
}
-/// Gets the file from which input was gathered at startup.
+/// Global TTY (or pipe for "-es") input stream, before UI starts.
int input_global_fd(void)
{
return global_fd;
@@ -60,8 +63,8 @@ void input_start(int fd)
}
global_fd = fd;
- rstream_init_fd(&main_loop, &read_stream, fd, READ_BUFFER_SIZE, NULL);
- rstream_start(&read_stream, read_cb);
+ rstream_init_fd(&main_loop, &read_stream, fd, READ_BUFFER_SIZE);
+ rstream_start(&read_stream, input_read_cb, NULL);
}
void input_stop(void)
@@ -71,7 +74,7 @@ void input_stop(void)
}
rstream_stop(&read_stream);
- stream_close(&read_stream, NULL);
+ stream_close(&read_stream, NULL, NULL);
}
static void cursorhold_event(void **argv)
@@ -87,8 +90,8 @@ static void create_cursorhold_event(void)
// have been called(inbuf_poll would return kInputAvail)
// TODO(tarruda): Cursorhold should be implemented as a timer set during the
// `state_check` callback for the states where it can be triggered.
- assert(!events_enabled || queue_empty(main_loop.events));
- queue_put(main_loop.events, cursorhold_event, 0);
+ assert(!events_enabled || multiqueue_empty(main_loop.events));
+ multiqueue_put(main_loop.events, cursorhold_event, 0);
}
// Low level input function
@@ -105,6 +108,11 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt)
}
} else {
if ((result = inbuf_poll((int)p_ut)) == kInputNone) {
+ if (read_stream.closed && silent_mode) {
+ // Drained eventloop & initial input; exit silent/batch-mode (-es/-Es).
+ read_error_exit();
+ }
+
if (trigger_cursorhold() && !typebuf_changed(tb_change_cnt)) {
create_cursorhold_event();
} else {
@@ -146,9 +154,15 @@ bool os_char_avail(void)
// Check for CTRL-C typed by reading all available characters.
void os_breakcheck(void)
{
+ int save_us = updating_screen;
+ // We do not want screen_resize() to redraw here.
+ updating_screen++;
+
if (!got_int) {
loop_poll_events(&main_loop, 0);
}
+
+ updating_screen = save_us;
}
void input_enable_events(void)
@@ -172,12 +186,14 @@ bool os_isatty(int fd)
size_t input_enqueue(String keys)
{
- char *ptr = keys.data, *end = ptr + keys.size;
+ char *ptr = keys.data;
+ char *end = ptr + keys.size;
while (rbuffer_space(input_buffer) >= 6 && ptr < end) {
uint8_t buf[6] = { 0 };
- unsigned int new_size = trans_special((const uint8_t **)&ptr, keys.size,
- buf, true);
+ unsigned int new_size
+ = trans_special((const uint8_t **)&ptr, (size_t)(end - ptr), buf, true,
+ false);
if (new_size) {
new_size = handle_mouse_event(&ptr, buf, new_size);
@@ -187,8 +203,7 @@ size_t input_enqueue(String keys)
if (*ptr == '<') {
char *old_ptr = ptr;
- // Invalid or incomplete key sequence, skip until the next '>' or until
- // *end
+ // Invalid or incomplete key sequence, skip until the next '>' or *end.
do {
ptr++;
} while (ptr < end && *ptr != '>');
@@ -266,29 +281,32 @@ static unsigned int handle_mouse_event(char **ptr, uint8_t *buf,
}
static int orig_num_clicks = 0;
- static int orig_mouse_code = 0;
- static int orig_mouse_col = 0;
- static int orig_mouse_row = 0;
- static uint64_t orig_mouse_time = 0; // time of previous mouse click
- uint64_t mouse_time = os_hrtime(); // time of current mouse click
-
- // compute the time elapsed since the previous mouse click and
- // convert p_mouse from ms to ns
- uint64_t timediff = mouse_time - orig_mouse_time;
- uint64_t mouset = (uint64_t)p_mouset * 1000000;
- if (mouse_code == orig_mouse_code
- && timediff < mouset
- && orig_num_clicks != 4
- && orig_mouse_col == mouse_col
- && orig_mouse_row == mouse_row) {
- orig_num_clicks++;
- } else {
- orig_num_clicks = 1;
+ if (mouse_code != KE_LEFTRELEASE && mouse_code != KE_RIGHTRELEASE
+ && mouse_code != KE_MIDDLERELEASE) {
+ static int orig_mouse_code = 0;
+ static int orig_mouse_col = 0;
+ static int orig_mouse_row = 0;
+ static uint64_t orig_mouse_time = 0; // time of previous mouse click
+ uint64_t mouse_time = os_hrtime(); // time of current mouse click (ns)
+
+ // compute the time elapsed since the previous mouse click and
+ // convert p_mouse from ms to ns
+ uint64_t timediff = mouse_time - orig_mouse_time;
+ uint64_t mouset = (uint64_t)p_mouset * 1000000;
+ if (mouse_code == orig_mouse_code
+ && timediff < mouset
+ && orig_num_clicks != 4
+ && orig_mouse_col == mouse_col
+ && orig_mouse_row == mouse_row) {
+ orig_num_clicks++;
+ } else {
+ orig_num_clicks = 1;
+ }
+ orig_mouse_code = mouse_code;
+ orig_mouse_col = mouse_col;
+ orig_mouse_row = mouse_row;
+ orig_mouse_time = mouse_time;
}
- orig_mouse_code = mouse_code;
- orig_mouse_col = mouse_col;
- orig_mouse_row = mouse_row;
- orig_mouse_time = mouse_time;
uint8_t modifiers = 0;
if (orig_num_clicks == 2) {
@@ -316,13 +334,27 @@ static unsigned int handle_mouse_event(char **ptr, uint8_t *buf,
return bufsize;
}
+/// @return true if the main loop is blocked and waiting for input.
+bool input_blocking(void)
+{
+ return blocking;
+}
+
static bool input_poll(int ms)
{
if (do_profiling == PROF_YES && ms) {
prof_inchar_enter();
}
+ if ((ms == - 1 || ms > 0) && !events_enabled && !input_eof) {
+ // The pending input provoked a blocking wait. Do special events now. #6247
+ blocking = true;
+ multiqueue_process_events(ch_before_blocking_events);
+ }
+ DLOG("blocking... events_enabled=%d events_pending=%d", events_enabled,
+ !multiqueue_empty(main_loop.events));
LOOP_PROCESS_EVENTS_UNTIL(&main_loop, NULL, ms, input_ready() || input_eof);
+ blocking = false;
if (do_profiling == PROF_YES && ms) {
prof_inchar_exit();
@@ -351,11 +383,11 @@ static InbufPollResult inbuf_poll(int ms)
return input_eof ? kInputEof : kInputNone;
}
-static void read_cb(Stream *stream, RBuffer *buf, size_t c, void *data,
- bool at_eof)
+static void input_read_cb(Stream *stream, RBuffer *buf, size_t c, void *data,
+ bool at_eof)
{
if (at_eof) {
- input_eof = true;
+ input_done();
}
assert(rbuffer_space(input_buffer) >= rbuffer_size(buf));
@@ -386,6 +418,8 @@ static void process_interrupts(void)
}
}
+// Helper function used to push bytes from the 'event' key sequence partially
+// between calls to os_inchar when maxlen < 3
static int push_event_key(uint8_t *buf, int maxlen)
{
static const uint8_t key[3] = { K_SPECIAL, KS_EXTRA, KE_EVENT };
@@ -411,13 +445,14 @@ static bool input_ready(void)
// Exit because of an input read error.
static void read_error_exit(void)
{
- if (silent_mode) /* Normal way to exit for "ex -s" */
+ if (silent_mode) { // Normal way to exit for "nvim -es".
getout(0);
+ }
STRCPY(IObuff, _("Vim: Error reading input, exiting...\n"));
preserve_exit();
}
static bool pending_events(void)
{
- return events_enabled && !queue_empty(main_loop.events);
+ return events_enabled && !multiqueue_empty(main_loop.events);
}