diff options
author | Björn Linse <bjorn.linse@gmail.com> | 2019-09-06 20:10:56 +0200 |
---|---|---|
committer | Björn Linse <bjorn.linse@gmail.com> | 2019-09-08 15:24:14 +0200 |
commit | e6b7613e89cc274198eec014180da6034442b3b6 (patch) | |
tree | e7deeaeb8f9b0da7b60f3efe06cde3434650d7d1 | |
parent | fa90f6cdaae800d9bfbc4f28ec04fb7456751dbe (diff) | |
download | rneovim-e6b7613e89cc274198eec014180da6034442b3b6.tar.gz rneovim-e6b7613e89cc274198eec014180da6034442b3b6.tar.bz2 rneovim-e6b7613e89cc274198eec014180da6034442b3b6.zip |
refactor: allow us to process a child queue only while waiting on input
-rw-r--r-- | src/nvim/eval.c | 4 | ||||
-rw-r--r-- | src/nvim/ex_cmds.c | 2 | ||||
-rw-r--r-- | src/nvim/getchar.c | 12 | ||||
-rw-r--r-- | src/nvim/getchar.h | 5 | ||||
-rw-r--r-- | src/nvim/main.c | 2 | ||||
-rw-r--r-- | src/nvim/message.c | 10 | ||||
-rw-r--r-- | src/nvim/misc1.c | 20 | ||||
-rw-r--r-- | src/nvim/os/input.c | 72 | ||||
-rw-r--r-- | src/nvim/os/input.h | 1 | ||||
-rw-r--r-- | src/nvim/state.c | 4 | ||||
-rw-r--r-- | src/nvim/ui.c | 12 | ||||
-rw-r--r-- | src/nvim/ui.h | 3 |
12 files changed, 69 insertions, 78 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 8e848483a7..0aa0e8c165 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -9941,9 +9941,7 @@ static void f_getchar(typval_T *argvars, typval_T *rettv, FunPtr fptr) if (argvars[0].v_type == VAR_UNKNOWN) { // getchar(): blocking wait. if (!(char_avail() || using_script() || input_available())) { - input_enable_events(); - (void)os_inchar(NULL, 0, -1, 0); - input_disable_events(); + (void)os_inchar(NULL, 0, -1, 0, main_loop.events); if (!multiqueue_empty(main_loop.events)) { multiqueue_process_events(main_loop.events); continue; diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index a0fbde008b..c3e1e69a63 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -5673,7 +5673,6 @@ void ex_substitute(exarg_T *eap) } block_autocmds(); // Disable events during command preview. - input_disable_events(); char_u *save_eap = eap->arg; garray_T save_view; @@ -5716,7 +5715,6 @@ void ex_substitute(exarg_T *eap) restore_search_patterns(); win_size_restore(&save_view); ga_clear(&save_view); - input_enable_events(); unblock_autocmds(); } diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 318b36860e..2469bb5baa 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -1532,8 +1532,9 @@ int safe_vgetc(void) int c; c = vgetc(); - if (c == NUL) - c = get_keystroke(); + if (c == NUL) { + c = get_keystroke(NULL); + } return c; } @@ -2447,9 +2448,10 @@ int inchar( char_u dum[DUM_LEN + 1]; for (;; ) { - len = os_inchar(dum, DUM_LEN, 0L, 0); - if (len == 0 || (len == 1 && dum[0] == 3)) + len = os_inchar(dum, DUM_LEN, 0L, 0, NULL); + if (len == 0 || (len == 1 && dum[0] == 3)) { break; + } } return retesc; } @@ -2460,7 +2462,7 @@ int inchar( // Fill up to a third of the buffer, because each character may be // 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 diff --git a/src/nvim/getchar.h b/src/nvim/getchar.h index a40ea7730a..01f60ccf49 100644 --- a/src/nvim/getchar.h +++ b/src/nvim/getchar.h @@ -57,9 +57,8 @@ struct map_arguments { }; typedef struct map_arguments MapArguments; -#define KEYLEN_PART_KEY -1 /* keylen value for incomplete key-code */ -#define KEYLEN_PART_MAP -2 /* keylen value for incomplete mapping */ -#define KEYLEN_REMOVED 9999 /* keylen value for removed sequence */ +#define KEYLEN_PART_KEY -1 // keylen value for incomplete key-code +#define KEYLEN_PART_MAP -2 // keylen value for incomplete mapping /// Maximum number of streams to read script from enum { NSCRIPT = 15 }; diff --git a/src/nvim/main.c b/src/nvim/main.c index 50e495c1e6..4335dab1f9 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -144,6 +144,8 @@ void event_init(void) { log_init(); loop_init(&main_loop, NULL); + resize_events = multiqueue_new_child(main_loop.events); + // early msgpack-rpc initialization msgpack_rpc_init_method_table(); msgpack_rpc_helpers_init(); diff --git a/src/nvim/message.c b/src/nvim/message.c index c499aa5f0c..5b5f14b99d 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -2587,8 +2587,10 @@ static int do_more_prompt(int typed_char) if (used_typed_char != NUL) { c = used_typed_char; /* was typed at hit-enter prompt */ used_typed_char = NUL; - } else - c = get_keystroke(); + } else { + c = get_keystroke(resize_events); + multiqueue_process_events(resize_events); + } toscroll = 0; @@ -3307,8 +3309,8 @@ do_dialog ( hotkeys = msg_show_console_dialog(message, buttons, dfltbutton); for (;; ) { - /* Get a typed character directly from the user. */ - c = get_keystroke(); + // Get a typed character directly from the user. + c = get_keystroke(NULL); switch (c) { case CAR: /* User accepts default option */ case NL: diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c index bb95cd5737..ab3520dd73 100644 --- a/src/nvim/misc1.c +++ b/src/nvim/misc1.c @@ -560,7 +560,7 @@ int ask_yesno(const char *const str, const bool direct) // Same highlighting as for wait_return. smsg_attr(HL_ATTR(HLF_R), "%s (y/n)?", str); if (direct) { - r = get_keystroke(); + r = get_keystroke(NULL); } else { r = plain_vgetc(); } @@ -614,7 +614,7 @@ int is_mouse_key(int c) * Disadvantage: typeahead is ignored. * Translates the interrupt character for unix to ESC. */ -int get_keystroke(void) +int get_keystroke(MultiQueue *events) { char_u *buf = NULL; int buflen = 150; @@ -644,7 +644,7 @@ int get_keystroke(void) /* First time: blocking wait. Second time: wait up to 100ms for a * 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) { // Replace zero and CSI by a special key code. n = fix_input_buffer(buf + len, n); @@ -653,18 +653,12 @@ int get_keystroke(void) } else if (len > 0) ++waited; /* keep track of the waiting time */ - if (n == KEYLEN_REMOVED) { /* key code removed */ - if (must_redraw != 0 && !need_wait_return && (State & CMDLINE) == 0) { - /* Redrawing was postponed, do it now. */ - update_screen(0); - setcursor(); /* put cursor back where it belongs */ - } - continue; - } - if (n > 0) /* found a termcode: adjust length */ + if (n > 0) { // found a termcode: adjust length len = n; - if (len == 0) /* nothing typed yet */ + } + if (len == 0) { // nothing typed yet continue; + } /* Handle modifier and/or special key code. */ n = buf[0]; diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index 83ac3dfa62..c1580c5fc3 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -38,7 +38,6 @@ static Stream read_stream = { .closed = true }; // Input before UI starts. static RBuffer *input_buffer = NULL; static bool input_eof = false; static int global_fd = -1; -static int events_enabled = 0; static bool blocking = false; #ifdef INCLUDE_GENERATED_DECLARATIONS @@ -89,7 +88,7 @@ static void cursorhold_event(void **argv) 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 // 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); } -// Low level input function -int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt) +/// Low level input function +/// +/// 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)) { 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; if (ms >= 0) { - if ((result = inbuf_poll(ms)) == kInputNone) { + if ((result = inbuf_poll(ms, events)) == kInputNone) { return 0; } } else { - if ((result = inbuf_poll((int)p_ut)) == kInputNone) { + if ((result = inbuf_poll((int)p_ut, events)) == 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(); + create_cursorhold_event(events == main_loop.events); } else { 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 (maxlen && pending_events()) { + if (maxlen && pending_events(events)) { 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 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. @@ -170,15 +173,6 @@ void os_breakcheck(void) 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. /// @@ -383,27 +377,37 @@ bool input_blocking(void) 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) { 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 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); + DLOG("blocking... events_enabled=%d events_pending=%d", events != NULL, + events && !multiqueue_empty(events)); + LOOP_PROCESS_EVENTS_UNTIL(&main_loop, NULL, ms, + input_ready(events) || input_eof); blocking = false; if (do_profiling == PROF_YES && ms) { prof_inchar_exit(); } - return input_ready(); + if (input_ready(events)) { + return kInputAvail; + } else { + return input_eof ? kInputEof : kInputNone; + } } void input_done(void) @@ -416,16 +420,6 @@ 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) -{ - 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, bool at_eof) { @@ -478,11 +472,11 @@ static int push_event_key(uint8_t *buf, int maxlen) } // 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 || 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. @@ -495,7 +489,7 @@ static void read_error_exit(void) 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); } diff --git a/src/nvim/os/input.h b/src/nvim/os/input.h index 5902677a35..d571965408 100644 --- a/src/nvim/os/input.h +++ b/src/nvim/os/input.h @@ -5,6 +5,7 @@ #include <stdbool.h> #include "nvim/api/private/defs.h" +#include "nvim/event/multiqueue.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "os/input.h.generated.h" diff --git a/src/nvim/state.c b/src/nvim/state.c index dbf04eebec..81bc078a88 100644 --- a/src/nvim/state.c +++ b/src/nvim/state.c @@ -46,14 +46,12 @@ getkey: // Event was made available after the last multiqueue_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. - (void)os_inchar(NULL, 0, -1, 0); - input_disable_events(); + (void)os_inchar(NULL, 0, -1, 0, main_loop.events); // If an event was put into the queue, we send K_EVENT directly. key = !multiqueue_empty(main_loop.events) ? K_EVENT diff --git a/src/nvim/ui.c b/src/nvim/ui.c index 94fae0a774..d8c9a3e780 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -174,7 +174,7 @@ void ui_refresh(void) } if (updating_screen) { - ui_schedule_refresh(); + deferred_refresh_event(NULL); return; } @@ -228,11 +228,11 @@ static void ui_refresh_event(void **argv) void ui_schedule_refresh(void) { - // TODO(bfredl): "fast" is not optimal. UI should be refreshed only at - // deferred processing plus a few more blocked-on-input situtions like - // wait_return(), but not any os_breakcheck(). Alternatively make this - // defered and make wait_return() process deferred events already. - loop_schedule_fast(&main_loop, event_create(ui_refresh_event, 0)); + loop_schedule_fast(&main_loop, event_create(deferred_refresh_event, 0)); +} +static void deferred_refresh_event(void **argv) +{ + multiqueue_put(resize_events, ui_refresh_event, 0); } void ui_default_colors_set(void) diff --git a/src/nvim/ui.h b/src/nvim/ui.h index e1dd18a289..1f549160db 100644 --- a/src/nvim/ui.h +++ b/src/nvim/ui.h @@ -66,4 +66,7 @@ struct ui_t { # include "ui.h.generated.h" # include "ui_events_call.h.generated.h" #endif + + +EXTERN MultiQueue *resize_events; #endif // NVIM_UI_H |