diff options
author | zeertzjq <zeertzjq@outlook.com> | 2022-09-20 11:47:04 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-09-20 11:47:04 +0800 |
commit | a0e6e767a617d79983ac4982850dee6d95ed5b56 (patch) | |
tree | 6ca1b61512b8becb6a4cdcf8246c933a3ae4c50a | |
parent | 875b58e0941ef62a75992ce0e6496bb7879e0bbe (diff) | |
download | rneovim-a0e6e767a617d79983ac4982850dee6d95ed5b56.tar.gz rneovim-a0e6e767a617d79983ac4982850dee6d95ed5b56.tar.bz2 rneovim-a0e6e767a617d79983ac4982850dee6d95ed5b56.zip |
fix(tui): handle padding requirements for visual bell (#20238)
-rw-r--r-- | src/nvim/event/loop.c | 42 | ||||
-rw-r--r-- | src/nvim/tui/tui.c | 27 |
2 files changed, 55 insertions, 14 deletions
diff --git a/src/nvim/event/loop.c b/src/nvim/event/loop.c index 1b5cc23b09..eff120331e 100644 --- a/src/nvim/event/loop.c +++ b/src/nvim/event/loop.c @@ -31,41 +31,57 @@ void loop_init(Loop *loop, void *data) loop->poll_timer.data = xmalloc(sizeof(bool)); // "timeout expired" flag } -/// Processes one `Loop.uv` event (at most). -/// Processes all `Loop.fast_events` events. -/// Does NOT process `Loop.events`, that is an application-specific decision. +/// Process `Loop.uv` events with a timeout. /// /// @param loop -/// @param ms 0: non-blocking poll. -/// >0: timeout after `ms`. -/// <0: wait forever. -/// @returns true if `ms` timeout was reached -bool loop_poll_events(Loop *loop, int ms) +/// @param ms 0: non-blocking poll. +/// > 0: timeout after `ms`. +/// < 0: wait forever. +/// @param once true: process at most one `Loop.uv` event. +/// false: process until `ms` timeout (only has effect if `ms` > 0). +/// @return true if `ms` > 0 and was reached +bool loop_uv_run(Loop *loop, int ms, bool once) { if (loop->recursive++) { abort(); // Should not re-enter uv_run } uv_run_mode mode = UV_RUN_ONCE; - bool timeout_expired = false; + bool *timeout_expired = loop->poll_timer.data; + *timeout_expired = false; if (ms > 0) { - *((bool *)loop->poll_timer.data) = false; // reset "timeout expired" flag - // Dummy timer to ensure UV_RUN_ONCE does not block indefinitely for I/O. + // This timer ensures UV_RUN_ONCE does not block indefinitely for I/O. uv_timer_start(&loop->poll_timer, timer_cb, (uint64_t)ms, (uint64_t)ms); } else if (ms == 0) { // For ms == 0, do a non-blocking event poll. mode = UV_RUN_NOWAIT; } - uv_run(&loop->uv, mode); + do { + uv_run(&loop->uv, mode); + } while (ms > 0 && !once && !*timeout_expired); if (ms > 0) { - timeout_expired = *((bool *)loop->poll_timer.data); uv_timer_stop(&loop->poll_timer); } loop->recursive--; // Can re-enter uv_run now + return *timeout_expired; +} + +/// Processes one `Loop.uv` event (at most). +/// Processes all `Loop.fast_events` events. +/// Does NOT process `Loop.events`, that is an application-specific decision. +/// +/// @param loop +/// @param ms 0: non-blocking poll. +/// > 0: timeout after `ms`. +/// < 0: wait forever. +/// @return true if `ms` > 0 and was reached +bool loop_poll_events(Loop *loop, int ms) +{ + bool timeout_expired = loop_uv_run(loop, ms, true); multiqueue_process_events(loop->fast_events); return timeout_expired; } diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index fd92873508..5a331463e3 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -1616,7 +1616,7 @@ static void unibi_goto(UI *ui, int row, int col) memset(&vars, 0, sizeof(vars)); \ data->cork = true; \ retry: \ - unibi_format(vars, vars + 26, str, data->params, out, ui, NULL, NULL); \ + unibi_format(vars, vars + 26, str, data->params, out, ui, pad, ui); \ if (data->overflow) { \ data->bufpos = orig_pos; \ flush_buf(ui); \ @@ -1647,6 +1647,7 @@ static void out(void *ctx, const char *str, size_t len) if (len > available) { if (data->cork) { + // Called by unibi_format(): avoid flush_buf() halfway an escape sequence. data->overflow = true; return; } else { @@ -1658,6 +1659,30 @@ static void out(void *ctx, const char *str, size_t len) data->bufpos += len; } +/// Called by unibi_format() for padding instructions. +/// The following parameter descriptions are extracted from unibi_format(3) and terminfo(5). +/// +/// @param ctx the same as `ctx2` passed to unibi_format() +/// @param delay the delay in tenths of milliseconds +/// @param scale padding is proportional to the number of lines affected +/// @param force padding is mandatory +static void pad(void *ctx, size_t delay, int scale FUNC_ATTR_UNUSED, int force) +{ + if (!force) { + return; + } + + UI *ui = ctx; + TUIData *data = ui->data; + + if (data->overflow) { + return; + } + + flush_buf(ui); + loop_uv_run(data->loop, (int)(delay / 10), false); +} + static void unibi_set_if_empty(unibi_term *ut, enum unibi_string str, const char *val) { if (!unibi_get_str(ut, str)) { |