From 4fd9ee4a6b908d86815f08c8880db73d9dda13dc Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Wed, 29 Oct 2014 17:30:45 -0300 Subject: input/job: process ctrl+c and do conversion in the read callback - Extract `process_interrupts` out of `convert_input` - Instead of waiting for os_breakcheck/os_inchar calls, call `convert_input` and `process_interrupts` directly from the read callback in input.c. - Remove the `settmode` calls from `job_wait`. Now that interrupts are processed in the event loop, there's no need to set the terminal to cooked which introduces other problems(ref 7.4.427) --- src/nvim/os/input.c | 18 +++++++++++------- src/nvim/os/job.c | 7 ------- 2 files changed, 11 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index e4501aeb82..e55b8183e0 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -116,7 +116,6 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt) return 0; } - convert_input(); // 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); @@ -132,8 +131,8 @@ bool os_char_avail(void) // In cooked mode we should get SIGINT, no need to check. void os_breakcheck(void) { - if (curr_tmode == TMODE_RAW && input_poll(0)) - convert_input(); + if (curr_tmode == TMODE_RAW) + input_poll(0); } /// Test whether a file descriptor refers to a terminal. @@ -220,6 +219,8 @@ static void read_cb(RStream *rstream, void *data, bool at_eof) } } + convert_input(); + process_interrupts(); started_reading = true; } @@ -260,7 +261,10 @@ static void convert_input(void) // data points to memory allocated by `string_convert_ext`, free it. free(data); } +} +static void process_interrupts(void) +{ if (!ctrl_c_interrupts) { return; } @@ -299,10 +303,10 @@ static int push_event_key(uint8_t *buf, int maxlen) // Check if there's pending input static bool input_ready(void) { - return typebuf_was_filled || // API call filled typeahead - event_has_deferred() || // Events must be processed + return typebuf_was_filled || // API call filled typeahead + event_has_deferred() || // Events must be processed (!embedded_mode && ( - rstream_pending(read_stream) > 0 || // Stdin input - eof)); // Stdin closed + rbuffer_pending(input_buffer) > 0 || // Stdin input + eof)); // Stdin closed } diff --git a/src/nvim/os/job.c b/src/nvim/os/job.c index 9a11ecd1fd..f8ad6874c9 100644 --- a/src/nvim/os/job.c +++ b/src/nvim/os/job.c @@ -15,7 +15,6 @@ #include "nvim/os/shell.h" #include "nvim/vim.h" #include "nvim/memory.h" -#include "nvim/term.h" #define EXIT_TIMEOUT 25 #define MAX_RUNNING_JOBS 100 @@ -277,10 +276,6 @@ void job_stop(Job *job) /// is possible on some OS. int job_wait(Job *job, int ms) FUNC_ATTR_NONNULL_ALL { - // switch to cooked so `got_int` will be set if the user interrupts - int old_mode = cur_tmode; - settmode(TMODE_COOK); - // Increase refcount to stop the job from being freed before we have a // chance to get the status. job->refcount++; @@ -296,8 +291,6 @@ int job_wait(Job *job, int ms) FUNC_ATTR_NONNULL_ALL event_poll(0); } - settmode(old_mode); - if (!--job->refcount) { int status = (int) job->status; // Manually invoke close_cb to free the job resources -- cgit From 94527245a5749b50c20cb057cc53ea4b1b2c624f Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Wed, 29 Oct 2014 22:51:22 -0300 Subject: input: Fix sizes of input/read buffers Input buffer must be bigger than read buffer to ensure it always has space for converted data. --- src/nvim/os/input.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index e55b8183e0..1b1a681a8b 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -20,8 +20,8 @@ #include "nvim/getchar.h" #include "nvim/term.h" -#define READ_BUFFER_SIZE 0xffff -#define INPUT_BUFFER_SIZE 4096 +#define READ_BUFFER_SIZE 0xfff +#define INPUT_BUFFER_SIZE (READ_BUFFER_SIZE * 4) typedef enum { kInputNone, -- cgit From 3800b24c5abecfb9d1ed1d5d36ddcd5a31a45609 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Wed, 29 Oct 2014 23:06:18 -0300 Subject: api: Add vim_input function and mark vim_feedkeys as deferred The `vim_feedkeys` must be deferred because it can potentially free the buffer passed to `os_inchar`(which in turns calls `vim_feedkeys` indirectly). The new `vim_input` function can be used to emulate user input(Since it does not mess with the typeahead, it is safe to execute without deferring). --- src/nvim/api/vim.c | 14 ++++++++++++++ src/nvim/os/input.c | 7 +++++++ 2 files changed, 21 insertions(+) (limited to 'src') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 9afefd6fa3..b6bac1588a 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -24,6 +24,7 @@ #include "nvim/misc2.h" #include "nvim/term.h" #include "nvim/getchar.h" +#include "nvim/os/input.h" #define LINE_BUFFER_SIZE 4096 @@ -51,6 +52,7 @@ void vim_command(String str, Error *err) /// @param mode specifies the mapping options /// @see feedkeys() void vim_feedkeys(String keys, String mode) + FUNC_ATTR_DEFERRED { bool remap = true; bool typed = false; @@ -78,6 +80,18 @@ void vim_feedkeys(String keys, String mode) typebuf_was_filled = true; } +/// Pass input keys to Neovim. Unlike `vim_feedkeys`, this will use a +/// lower-level input buffer and the call is not deferred. +/// This is the most reliable way to emulate real user input. +/// +/// @param keys to be typed +/// @return The number bytes actually written, which can be lower than +/// requested if the buffer becomes full. +Integer vim_input(String keys) +{ + return (Integer)input_enqueue(keys); +} + /// Replace any terminal codes with the internal representation /// /// @see replace_termcodes diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index 1b1a681a8b..d948a48b64 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -165,6 +165,13 @@ void input_buffer_restore(String str) free(str.data); } +size_t input_enqueue(String keys) +{ + size_t rv = rbuffer_write(input_buffer, keys.data, keys.size); + process_interrupts(); + return rv; +} + static bool input_poll(int ms) { event_poll_until(ms, input_ready()); -- cgit