mirror of
https://github.com/neovim/neovim.git
synced 2026-03-23 17:10:52 +00:00
ui: Refactor so that busy state won't be the default
Even though assuming nvim is busy most times is simpler, it has a problem: A lot of unnecessary busy_start/busy_stop notifications are sent to the UI. That's because in the majority of scenarios almost no time is spent between `event_poll` calls. This restores the normal behavior which is to call busy_start only when nvim is going to perform some task that can take a significant amount of time. Also improve the usage of buffering in the TUI when changing the cursor state.
This commit is contained in:
@@ -1364,6 +1364,7 @@ cmdline_changed:
|
||||
if (ccline.cmdlen == 0)
|
||||
i = 0;
|
||||
else {
|
||||
ui_busy_start();
|
||||
ui_flush();
|
||||
++emsg_off; /* So it doesn't beep if bad expr */
|
||||
/* Set the time limit to half a second. */
|
||||
@@ -1381,6 +1382,7 @@ cmdline_changed:
|
||||
} else if (char_avail())
|
||||
/* cancelled searching because a char was typed */
|
||||
incsearch_postponed = TRUE;
|
||||
ui_busy_stop();
|
||||
}
|
||||
if (i != 0)
|
||||
highlight_match = TRUE; /* highlight position */
|
||||
|
||||
@@ -2379,6 +2379,11 @@ inchar (
|
||||
int retesc = FALSE; /* return ESC with gotint */
|
||||
int script_char;
|
||||
|
||||
if (wait_time == -1L || wait_time > 100L) {
|
||||
// flush output before waiting
|
||||
ui_flush();
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't reset these when at the hit-return prompt, otherwise an endless
|
||||
* recursive loop may result (write error in swapfile, hit-return, timeout
|
||||
|
||||
@@ -2364,6 +2364,7 @@ int get_keystroke(void)
|
||||
|
||||
mapped_ctrl_c = FALSE; /* mappings are not used here */
|
||||
for (;; ) {
|
||||
// flush output before waiting
|
||||
ui_flush();
|
||||
/* Leave some room for check_termcode() to insert a key code into (max
|
||||
* 5 chars plus NUL). And fix_input_buffer() can triple the number of
|
||||
|
||||
@@ -8,15 +8,9 @@
|
||||
#include "nvim/os/job_defs.h"
|
||||
#include "nvim/os/time.h"
|
||||
|
||||
void ui_busy_start(void);
|
||||
void ui_busy_stop(void);
|
||||
|
||||
// Poll for events until a condition or timeout
|
||||
#define event_poll_until(timeout, condition) \
|
||||
do { \
|
||||
if (timeout < 0 || timeout > 100) { \
|
||||
ui_busy_stop(); \
|
||||
} \
|
||||
int remaining = timeout; \
|
||||
uint64_t before = (remaining > 0) ? os_hrtime() : 0; \
|
||||
while (!(condition)) { \
|
||||
@@ -32,9 +26,6 @@ void ui_busy_stop(void);
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
if (timeout < 0 || timeout > 100) { \
|
||||
ui_busy_start(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||
|
||||
@@ -241,6 +241,7 @@ static int shell(const char *cmd,
|
||||
// invoke busy_start here so event_poll_until wont change the busy state for
|
||||
// the UI
|
||||
ui_busy_start();
|
||||
ui_flush();
|
||||
status = job_wait(job, -1);
|
||||
ui_busy_stop();
|
||||
|
||||
|
||||
@@ -16,6 +16,11 @@
|
||||
#include "nvim/os/event.h"
|
||||
#include "nvim/tui/tui.h"
|
||||
|
||||
// Space reserved in the output buffer to restore the cursor to normal when
|
||||
// flushing. No existing terminal will require 32 bytes to do that.
|
||||
#define CNORM_COMMAND_MAX_SIZE 32
|
||||
#define OUTBUF_SIZE 0xffff
|
||||
|
||||
typedef struct term_input TermInput;
|
||||
|
||||
#include "term_input.inl"
|
||||
@@ -31,8 +36,8 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
unibi_var_t params[9];
|
||||
char buf[0xffff];
|
||||
size_t bufpos;
|
||||
char buf[OUTBUF_SIZE];
|
||||
size_t bufpos, bufsize;
|
||||
TermInput *input;
|
||||
uv_loop_t *write_loop;
|
||||
unibi_term *ut;
|
||||
@@ -81,13 +86,13 @@ typedef struct {
|
||||
void tui_start(void)
|
||||
{
|
||||
TUIData *data = xcalloc(1, sizeof(TUIData));
|
||||
data->busy = true;
|
||||
UI *ui = xcalloc(1, sizeof(UI));
|
||||
ui->data = data;
|
||||
data->attrs = data->print_attrs = EMPTY_ATTRS;
|
||||
data->fg = data->bg = -1;
|
||||
data->can_use_terminal_scroll = true;
|
||||
data->bufpos = 0;
|
||||
data->bufsize = sizeof(data->buf) - CNORM_COMMAND_MAX_SIZE;
|
||||
data->unibi_ext.enable_mouse = -1;
|
||||
data->unibi_ext.disable_mouse = -1;
|
||||
data->unibi_ext.enable_bracketed_paste = -1;
|
||||
@@ -108,7 +113,6 @@ void tui_start(void)
|
||||
data->ut = unibi_dummy();
|
||||
}
|
||||
fix_terminfo(data);
|
||||
unibi_out(ui, unibi_cursor_invisible);
|
||||
// Enter alternate screen and clear
|
||||
unibi_out(ui, unibi_enter_ca_mode);
|
||||
unibi_out(ui, unibi_clear_screen);
|
||||
@@ -172,6 +176,7 @@ static void tui_stop(UI *ui)
|
||||
tui_normal_mode(ui);
|
||||
tui_mouse_off(ui);
|
||||
unibi_out(ui, unibi_exit_attribute_mode);
|
||||
// cursor should be set to normal before exiting alternate screen
|
||||
unibi_out(ui, unibi_cursor_normal);
|
||||
unibi_out(ui, unibi_exit_ca_mode);
|
||||
// Disable bracketed paste
|
||||
@@ -661,7 +666,7 @@ static void out(void *ctx, const char *str, size_t len)
|
||||
{
|
||||
UI *ui = ctx;
|
||||
TUIData *data = ui->data;
|
||||
size_t available = sizeof(data->buf) - data->bufpos;
|
||||
size_t available = data->bufsize - data->bufpos;
|
||||
|
||||
if (len > available) {
|
||||
flush_buf(ui);
|
||||
@@ -786,29 +791,26 @@ end:
|
||||
static void flush_buf(UI *ui)
|
||||
{
|
||||
uv_write_t req;
|
||||
uv_buf_t buf[2];
|
||||
unsigned int buf_count = 1;
|
||||
|
||||
uv_buf_t buf;
|
||||
TUIData *data = ui->data;
|
||||
|
||||
buf[0].base = data->buf;
|
||||
buf[0].len = data->bufpos;
|
||||
|
||||
char normal_buf[64];
|
||||
if (!data->busy) {
|
||||
// Cannot use unibi_out(ui, unibi_cursor_normal), in case there is not
|
||||
// enough remaining space in data->buf.
|
||||
const char *str = unibi_get_str(data->ut, unibi_cursor_normal);
|
||||
buf[1].base = normal_buf;
|
||||
buf[1].len = unibi_run(str, data->params, normal_buf, sizeof(normal_buf));
|
||||
buf_count++;
|
||||
// not busy and the cursor is invisible(see below). Append a "cursor
|
||||
// normal" command to the end of the buffer.
|
||||
data->bufsize += CNORM_COMMAND_MAX_SIZE;
|
||||
unibi_out(ui, unibi_cursor_normal);
|
||||
data->bufsize -= CNORM_COMMAND_MAX_SIZE;
|
||||
}
|
||||
|
||||
uv_write(&req, (uv_stream_t *)&data->output_handle, buf, buf_count, NULL);
|
||||
buf.base = data->buf;
|
||||
buf.len = data->bufpos;
|
||||
uv_write(&req, (uv_stream_t *)&data->output_handle, &buf, 1, NULL);
|
||||
uv_run(data->write_loop, UV_RUN_DEFAULT);
|
||||
data->bufpos = 0;
|
||||
|
||||
if (!data->busy) {
|
||||
// not busy and cursor is visible(see above), append a "cursor invisible"
|
||||
// command to the beginning of the buffer for the next flush
|
||||
unibi_out(ui, unibi_cursor_invisible);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ static struct {
|
||||
} sr;
|
||||
static int current_attr_code = 0;
|
||||
static bool pending_cursor_update = false;
|
||||
static int busy = 1;
|
||||
static int busy = 0;
|
||||
static int height, width;
|
||||
|
||||
// This set of macros allow us to use UI_CALL to invoke any function on
|
||||
@@ -155,7 +155,6 @@ void ui_busy_start(void)
|
||||
{
|
||||
if (!(busy++)) {
|
||||
UI_CALL(busy_start);
|
||||
ui_flush();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,11 +162,9 @@ void ui_busy_stop(void)
|
||||
{
|
||||
if (!(--busy)) {
|
||||
UI_CALL(busy_stop);
|
||||
ui_flush();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ui_mouse_on(void)
|
||||
{
|
||||
UI_CALL(mouse_on);
|
||||
|
||||
@@ -166,7 +166,7 @@ function Screen.new(width, height)
|
||||
_cursor = {
|
||||
row = 1, col = 1
|
||||
},
|
||||
_busy = true
|
||||
_busy = false
|
||||
}, Screen)
|
||||
self:_handle_resize(width, height)
|
||||
return self
|
||||
|
||||
Reference in New Issue
Block a user