diff options
-rw-r--r-- | src/nvim/ex_getln.c | 2 | ||||
-rw-r--r-- | src/nvim/getchar.c | 5 | ||||
-rw-r--r-- | src/nvim/main.c | 54 | ||||
-rw-r--r-- | src/nvim/misc1.c | 1 | ||||
-rw-r--r-- | src/nvim/os/event.h | 9 | ||||
-rw-r--r-- | src/nvim/os/input.c | 6 | ||||
-rw-r--r-- | src/nvim/os/shell.c | 1 | ||||
-rw-r--r-- | src/nvim/tui/tui.c | 40 | ||||
-rw-r--r-- | src/nvim/ui.c | 5 | ||||
-rw-r--r-- | test/functional/ui/screen.lua | 2 |
10 files changed, 63 insertions, 62 deletions
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index c9e990b713..d5f7a218f4 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -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 */ diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 41b3d9dda8..96ce586a9e 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -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 diff --git a/src/nvim/main.c b/src/nvim/main.c index 9479d80f31..2f1e6e6d3b 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -268,16 +268,26 @@ int main(int argc, char **argv) /* Set the break level after the terminal is initialized. */ debug_break_level = params.use_debug_break_level; + bool reading_input = !params.headless && (params.input_isatty + || params.output_isatty || params.err_isatty); + + if (reading_input) { + // Its possible that one of the startup commands(arguments, sourced scripts + // or plugins) will prompt the user, so start reading from a tty stream + // now. + int fd = fileno(stdin); + if (!params.input_isatty || params.edit_type == EDIT_STDIN) { + // use stderr or stdout since stdin is not a tty and/or could be used to + // read the file we'll edit when the "-" argument is given(eg: cat file | + // nvim -) + fd = params.err_isatty ? fileno(stderr) : fileno(stdout); + } + input_start_stdin(fd); + } + /* Execute --cmd arguments. */ exe_pre_commands(¶ms); - if (!params.headless && params.input_isatty) { - // Its possible that one of the scripts sourced at startup will prompt the - // user, so start stdin now. TODO(tarruda): This is only for compatibility. - // Startup user prompting should be done in the VimEnter autocmd - input_start_stdin(); - } - /* Source startup scripts. */ source_startup_scripts(¶ms); @@ -358,22 +368,19 @@ int main(int argc, char **argv) if (params.edit_type == EDIT_STDIN && !recoverymode) read_stdin(); - if (!params.headless) { - if ((params.output_isatty || params.err_isatty) - && (need_wait_return || msg_didany)) { - // Since at this point there's no UI instance running yet, error messages - // would have been printed to stdout. Before starting (which can result in - // a alternate screen buffer being shown) we need confirmation that the - // user has seen the messages and that is done with a call to wait_return. - TIME_MSG("waiting for return"); - wait_return(TRUE); - } - if (params.input_isatty) { - // Stop reading from stdin, the UI module will take over now. - input_stop_stdin(); - } + if (reading_input && (need_wait_return || msg_didany)) { + // Since at this point there's no UI instance running yet, error messages + // would have been printed to stdout. Before starting (which can result in + // a alternate screen buffer being shown) we need confirmation that the + // user has seen the messages and that is done with a call to wait_return. + TIME_MSG("waiting for return"); + wait_return(TRUE); + } + if (!params.headless) { + // Stop reading from stdin, the UI layer will take over now + input_stop_stdin(); ui_builtin_start(); } @@ -1465,11 +1472,6 @@ static void check_tty(mparm_T *parmp) TIME_MSG("Warning delay"); } - - if (parmp->edit_type != EDIT_STDIN && !parmp->input_isatty) { - // read commands from directly from stdin - input_start_stdin(); - } } /* diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c index 07cbc0f7c4..c9f3fbd511 100644 --- a/src/nvim/misc1.c +++ b/src/nvim/misc1.c @@ -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 diff --git a/src/nvim/os/event.h b/src/nvim/os/event.h index 986db51431..db02b38c7f 100644 --- a/src/nvim/os/event.h +++ b/src/nvim/os/event.h @@ -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 diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index 00efa28161..a409a9ed13 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -46,7 +46,7 @@ void input_init(void) input_buffer = rbuffer_new(INPUT_BUFFER_SIZE + MAX_KEY_CODE_LEN); } -void input_start_stdin(void) +void input_start_stdin(int fd) { if (read_stream) { return; @@ -54,7 +54,7 @@ void input_start_stdin(void) read_buffer = rbuffer_new(READ_BUFFER_SIZE); read_stream = rstream_new(read_cb, read_buffer, NULL); - rstream_set_file(read_stream, fileno(stdin)); + rstream_set_file(read_stream, fd); rstream_start(read_stream); } @@ -69,7 +69,7 @@ void input_stop_stdin(void) read_stream = NULL; } -// Low level input function. +// Low level input function int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt) { if (rbuffer_pending(input_buffer)) { diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c index 290d6a9ec9..6fcb62a5f3 100644 --- a/src/nvim/os/shell.c +++ b/src/nvim/os/shell.c @@ -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(); diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 4f858456f9..4736e7a8ba 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -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); } } diff --git a/src/nvim/ui.c b/src/nvim/ui.c index 2189021d22..443b50da87 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -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); diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index 2cebaf048c..f79d634536 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -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 |