refactor: allow us to process a child queue only while waiting on input

This commit is contained in:
Björn Linse
2019-09-06 20:10:56 +02:00
parent fa90f6cdaa
commit e6b7613e89
12 changed files with 69 additions and 78 deletions

View File

@@ -9941,9 +9941,7 @@ static void f_getchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (argvars[0].v_type == VAR_UNKNOWN) { if (argvars[0].v_type == VAR_UNKNOWN) {
// getchar(): blocking wait. // getchar(): blocking wait.
if (!(char_avail() || using_script() || input_available())) { if (!(char_avail() || using_script() || input_available())) {
input_enable_events(); (void)os_inchar(NULL, 0, -1, 0, main_loop.events);
(void)os_inchar(NULL, 0, -1, 0);
input_disable_events();
if (!multiqueue_empty(main_loop.events)) { if (!multiqueue_empty(main_loop.events)) {
multiqueue_process_events(main_loop.events); multiqueue_process_events(main_loop.events);
continue; continue;

View File

@@ -5673,7 +5673,6 @@ void ex_substitute(exarg_T *eap)
} }
block_autocmds(); // Disable events during command preview. block_autocmds(); // Disable events during command preview.
input_disable_events();
char_u *save_eap = eap->arg; char_u *save_eap = eap->arg;
garray_T save_view; garray_T save_view;
@@ -5716,7 +5715,6 @@ void ex_substitute(exarg_T *eap)
restore_search_patterns(); restore_search_patterns();
win_size_restore(&save_view); win_size_restore(&save_view);
ga_clear(&save_view); ga_clear(&save_view);
input_enable_events();
unblock_autocmds(); unblock_autocmds();
} }

View File

@@ -1532,8 +1532,9 @@ int safe_vgetc(void)
int c; int c;
c = vgetc(); c = vgetc();
if (c == NUL) if (c == NUL) {
c = get_keystroke(); c = get_keystroke(NULL);
}
return c; return c;
} }
@@ -2447,9 +2448,10 @@ int inchar(
char_u dum[DUM_LEN + 1]; char_u dum[DUM_LEN + 1];
for (;; ) { for (;; ) {
len = os_inchar(dum, DUM_LEN, 0L, 0); len = os_inchar(dum, DUM_LEN, 0L, 0, NULL);
if (len == 0 || (len == 1 && dum[0] == 3)) if (len == 0 || (len == 1 && dum[0] == 3)) {
break; break;
}
} }
return retesc; return retesc;
} }
@@ -2460,7 +2462,7 @@ int inchar(
// Fill up to a third of the buffer, because each character may be // Fill up to a third of the buffer, because each character may be
// tripled below. // tripled below.
len = os_inchar(buf, maxlen / 3, (int)wait_time, tb_change_cnt); len = os_inchar(buf, maxlen / 3, (int)wait_time, tb_change_cnt, NULL);
} }
// If the typebuf was changed further down, it is like nothing was added by // If the typebuf was changed further down, it is like nothing was added by

View File

@@ -57,9 +57,8 @@ struct map_arguments {
}; };
typedef struct map_arguments MapArguments; typedef struct map_arguments MapArguments;
#define KEYLEN_PART_KEY -1 /* keylen value for incomplete key-code */ #define KEYLEN_PART_KEY -1 // keylen value for incomplete key-code
#define KEYLEN_PART_MAP -2 /* keylen value for incomplete mapping */ #define KEYLEN_PART_MAP -2 // keylen value for incomplete mapping
#define KEYLEN_REMOVED 9999 /* keylen value for removed sequence */
/// Maximum number of streams to read script from /// Maximum number of streams to read script from
enum { NSCRIPT = 15 }; enum { NSCRIPT = 15 };

View File

@@ -144,6 +144,8 @@ void event_init(void)
{ {
log_init(); log_init();
loop_init(&main_loop, NULL); loop_init(&main_loop, NULL);
resize_events = multiqueue_new_child(main_loop.events);
// early msgpack-rpc initialization // early msgpack-rpc initialization
msgpack_rpc_init_method_table(); msgpack_rpc_init_method_table();
msgpack_rpc_helpers_init(); msgpack_rpc_helpers_init();

View File

@@ -2587,8 +2587,10 @@ static int do_more_prompt(int typed_char)
if (used_typed_char != NUL) { if (used_typed_char != NUL) {
c = used_typed_char; /* was typed at hit-enter prompt */ c = used_typed_char; /* was typed at hit-enter prompt */
used_typed_char = NUL; used_typed_char = NUL;
} else } else {
c = get_keystroke(); c = get_keystroke(resize_events);
multiqueue_process_events(resize_events);
}
toscroll = 0; toscroll = 0;
@@ -3307,8 +3309,8 @@ do_dialog (
hotkeys = msg_show_console_dialog(message, buttons, dfltbutton); hotkeys = msg_show_console_dialog(message, buttons, dfltbutton);
for (;; ) { for (;; ) {
/* Get a typed character directly from the user. */ // Get a typed character directly from the user.
c = get_keystroke(); c = get_keystroke(NULL);
switch (c) { switch (c) {
case CAR: /* User accepts default option */ case CAR: /* User accepts default option */
case NL: case NL:

View File

@@ -560,7 +560,7 @@ int ask_yesno(const char *const str, const bool direct)
// Same highlighting as for wait_return. // Same highlighting as for wait_return.
smsg_attr(HL_ATTR(HLF_R), "%s (y/n)?", str); smsg_attr(HL_ATTR(HLF_R), "%s (y/n)?", str);
if (direct) { if (direct) {
r = get_keystroke(); r = get_keystroke(NULL);
} else { } else {
r = plain_vgetc(); r = plain_vgetc();
} }
@@ -614,7 +614,7 @@ int is_mouse_key(int c)
* Disadvantage: typeahead is ignored. * Disadvantage: typeahead is ignored.
* Translates the interrupt character for unix to ESC. * Translates the interrupt character for unix to ESC.
*/ */
int get_keystroke(void) int get_keystroke(MultiQueue *events)
{ {
char_u *buf = NULL; char_u *buf = NULL;
int buflen = 150; int buflen = 150;
@@ -644,7 +644,7 @@ int get_keystroke(void)
/* First time: blocking wait. Second time: wait up to 100ms for a /* First time: blocking wait. Second time: wait up to 100ms for a
* terminal code to complete. */ * terminal code to complete. */
n = os_inchar(buf + len, maxlen, len == 0 ? -1L : 100L, 0); n = os_inchar(buf + len, maxlen, len == 0 ? -1L : 100L, 0, events);
if (n > 0) { if (n > 0) {
// Replace zero and CSI by a special key code. // Replace zero and CSI by a special key code.
n = fix_input_buffer(buf + len, n); n = fix_input_buffer(buf + len, n);
@@ -653,18 +653,12 @@ int get_keystroke(void)
} else if (len > 0) } else if (len > 0)
++waited; /* keep track of the waiting time */ ++waited; /* keep track of the waiting time */
if (n == KEYLEN_REMOVED) { /* key code removed */ if (n > 0) { // found a termcode: adjust length
if (must_redraw != 0 && !need_wait_return && (State & CMDLINE) == 0) { len = n;
/* Redrawing was postponed, do it now. */ }
update_screen(0); if (len == 0) { // nothing typed yet
setcursor(); /* put cursor back where it belongs */
}
continue; continue;
} }
if (n > 0) /* found a termcode: adjust length */
len = n;
if (len == 0) /* nothing typed yet */
continue;
/* Handle modifier and/or special key code. */ /* Handle modifier and/or special key code. */
n = buf[0]; n = buf[0];

View File

@@ -38,7 +38,6 @@ static Stream read_stream = { .closed = true }; // Input before UI starts.
static RBuffer *input_buffer = NULL; static RBuffer *input_buffer = NULL;
static bool input_eof = false; static bool input_eof = false;
static int global_fd = -1; static int global_fd = -1;
static int events_enabled = 0;
static bool blocking = false; static bool blocking = false;
#ifdef INCLUDE_GENERATED_DECLARATIONS #ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -89,7 +88,7 @@ static void cursorhold_event(void **argv)
did_cursorhold = true; did_cursorhold = true;
} }
static void create_cursorhold_event(void) static void create_cursorhold_event(bool events_enabled)
{ {
// If events are enabled and the queue has any items, this function should not // If events are enabled and the queue has any items, this function should not
// have been called(inbuf_poll would return kInputAvail) // have been called(inbuf_poll would return kInputAvail)
@@ -99,8 +98,12 @@ static void create_cursorhold_event(void)
multiqueue_put(main_loop.events, cursorhold_event, 0); multiqueue_put(main_loop.events, cursorhold_event, 0);
} }
// Low level input function /// Low level input function
int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt) ///
/// 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)
{ {
if (maxlen && rbuffer_size(input_buffer)) { if (maxlen && rbuffer_size(input_buffer)) {
return (int)rbuffer_read(input_buffer, (char *)buf, (size_t)maxlen); return (int)rbuffer_read(input_buffer, (char *)buf, (size_t)maxlen);
@@ -108,21 +111,21 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt)
InbufPollResult result; InbufPollResult result;
if (ms >= 0) { if (ms >= 0) {
if ((result = inbuf_poll(ms)) == kInputNone) { if ((result = inbuf_poll(ms, events)) == kInputNone) {
return 0; return 0;
} }
} else { } else {
if ((result = inbuf_poll((int)p_ut)) == kInputNone) { if ((result = inbuf_poll((int)p_ut, events)) == kInputNone) {
if (read_stream.closed && silent_mode) { if (read_stream.closed && silent_mode) {
// Drained eventloop & initial input; exit silent/batch-mode (-es/-Es). // Drained eventloop & initial input; exit silent/batch-mode (-es/-Es).
read_error_exit(); read_error_exit();
} }
if (trigger_cursorhold() && !typebuf_changed(tb_change_cnt)) { if (trigger_cursorhold() && !typebuf_changed(tb_change_cnt)) {
create_cursorhold_event(); create_cursorhold_event(events == main_loop.events);
} else { } else {
before_blocking(); before_blocking();
result = inbuf_poll(-1); result = inbuf_poll(-1, events);
} }
} }
} }
@@ -139,7 +142,7 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt)
} }
// If there are events, return the keys directly // If there are events, return the keys directly
if (maxlen && pending_events()) { if (maxlen && pending_events(events)) {
return push_event_key(buf, maxlen); return push_event_key(buf, maxlen);
} }
@@ -153,7 +156,7 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt)
// Check if a character is available for reading // Check if a character is available for reading
bool os_char_avail(void) bool os_char_avail(void)
{ {
return inbuf_poll(0) == kInputAvail; return inbuf_poll(0, NULL) == kInputAvail;
} }
// Check for CTRL-C typed by reading all available characters. // Check for CTRL-C typed by reading all available characters.
@@ -170,15 +173,6 @@ void os_breakcheck(void)
updating_screen = save_us; updating_screen = save_us;
} }
void input_enable_events(void)
{
events_enabled++;
}
void input_disable_events(void)
{
events_enabled--;
}
/// Test whether a file descriptor refers to a terminal. /// Test whether a file descriptor refers to a terminal.
/// ///
@@ -383,27 +377,37 @@ bool input_blocking(void)
return blocking; return blocking;
} }
static bool input_poll(int ms) // This is a replacement for the old `WaitForChar` function in os_unix.c
static InbufPollResult inbuf_poll(int ms, MultiQueue *events)
{ {
if (input_ready(events)) {
return kInputAvail;
}
if (do_profiling == PROF_YES && ms) { if (do_profiling == PROF_YES && ms) {
prof_inchar_enter(); prof_inchar_enter();
} }
if ((ms == - 1 || ms > 0) && !events_enabled && !input_eof) { if ((ms == - 1 || ms > 0) && events == NULL && !input_eof) {
// The pending input provoked a blocking wait. Do special events now. #6247 // The pending input provoked a blocking wait. Do special events now. #6247
blocking = true; blocking = true;
multiqueue_process_events(ch_before_blocking_events); multiqueue_process_events(ch_before_blocking_events);
} }
DLOG("blocking... events_enabled=%d events_pending=%d", events_enabled, DLOG("blocking... events_enabled=%d events_pending=%d", events != NULL,
!multiqueue_empty(main_loop.events)); events && !multiqueue_empty(events));
LOOP_PROCESS_EVENTS_UNTIL(&main_loop, NULL, ms, input_ready() || input_eof); LOOP_PROCESS_EVENTS_UNTIL(&main_loop, NULL, ms,
input_ready(events) || input_eof);
blocking = false; blocking = false;
if (do_profiling == PROF_YES && ms) { if (do_profiling == PROF_YES && ms) {
prof_inchar_exit(); prof_inchar_exit();
} }
return input_ready(); if (input_ready(events)) {
return kInputAvail;
} else {
return input_eof ? kInputEof : kInputNone;
}
} }
void input_done(void) void input_done(void)
@@ -416,16 +420,6 @@ bool input_available(void)
return rbuffer_size(input_buffer) != 0; 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)
{
if (input_ready() || input_poll(ms)) {
return kInputAvail;
}
return input_eof ? kInputEof : kInputNone;
}
static void input_read_cb(Stream *stream, RBuffer *buf, size_t c, void *data, static void input_read_cb(Stream *stream, RBuffer *buf, size_t c, void *data,
bool at_eof) bool at_eof)
{ {
@@ -478,11 +472,11 @@ static int push_event_key(uint8_t *buf, int maxlen)
} }
// Check if there's pending input // Check if there's pending input
static bool input_ready(void) static bool input_ready(MultiQueue *events)
{ {
return (typebuf_was_filled // API call filled typeahead return (typebuf_was_filled // API call filled typeahead
|| rbuffer_size(input_buffer) // Input buffer filled || rbuffer_size(input_buffer) // Input buffer filled
|| pending_events()); // Events must be processed || pending_events(events)); // Events must be processed
} }
// Exit because of an input read error. // Exit because of an input read error.
@@ -495,7 +489,7 @@ static void read_error_exit(void)
preserve_exit(); preserve_exit();
} }
static bool pending_events(void) static bool pending_events(MultiQueue *events)
{ {
return events_enabled && !multiqueue_empty(main_loop.events); return events && !multiqueue_empty(events);
} }

View File

@@ -5,6 +5,7 @@
#include <stdbool.h> #include <stdbool.h>
#include "nvim/api/private/defs.h" #include "nvim/api/private/defs.h"
#include "nvim/event/multiqueue.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS #ifdef INCLUDE_GENERATED_DECLARATIONS
# include "os/input.h.generated.h" # include "os/input.h.generated.h"

View File

@@ -46,14 +46,12 @@ getkey:
// Event was made available after the last multiqueue_process_events call // Event was made available after the last multiqueue_process_events call
key = K_EVENT; key = K_EVENT;
} else { } else {
input_enable_events();
// Flush screen updates before blocking // Flush screen updates before blocking
ui_flush(); ui_flush();
// Call `os_inchar` directly to block for events or user input without // Call `os_inchar` directly to block for events or user input without
// consuming anything from `input_buffer`(os/input.c) or calling the // consuming anything from `input_buffer`(os/input.c) or calling the
// mapping engine. // mapping engine.
(void)os_inchar(NULL, 0, -1, 0); (void)os_inchar(NULL, 0, -1, 0, main_loop.events);
input_disable_events();
// If an event was put into the queue, we send K_EVENT directly. // If an event was put into the queue, we send K_EVENT directly.
key = !multiqueue_empty(main_loop.events) key = !multiqueue_empty(main_loop.events)
? K_EVENT ? K_EVENT

View File

@@ -174,7 +174,7 @@ void ui_refresh(void)
} }
if (updating_screen) { if (updating_screen) {
ui_schedule_refresh(); deferred_refresh_event(NULL);
return; return;
} }
@@ -228,11 +228,11 @@ static void ui_refresh_event(void **argv)
void ui_schedule_refresh(void) void ui_schedule_refresh(void)
{ {
// TODO(bfredl): "fast" is not optimal. UI should be refreshed only at loop_schedule_fast(&main_loop, event_create(deferred_refresh_event, 0));
// deferred processing plus a few more blocked-on-input situtions like }
// wait_return(), but not any os_breakcheck(). Alternatively make this static void deferred_refresh_event(void **argv)
// defered and make wait_return() process deferred events already. {
loop_schedule_fast(&main_loop, event_create(ui_refresh_event, 0)); multiqueue_put(resize_events, ui_refresh_event, 0);
} }
void ui_default_colors_set(void) void ui_default_colors_set(void)

View File

@@ -66,4 +66,7 @@ struct ui_t {
# include "ui.h.generated.h" # include "ui.h.generated.h"
# include "ui_events_call.h.generated.h" # include "ui_events_call.h.generated.h"
#endif #endif
EXTERN MultiQueue *resize_events;
#endif // NVIM_UI_H #endif // NVIM_UI_H