From 9333f86ab7d0e85d9f658bfe455860771de9b997 Mon Sep 17 00:00:00 2001 From: erw7 Date: Fri, 20 Mar 2020 03:31:10 +0900 Subject: [PATCH] TUI: do not use "nvim_get_option" in tui thread Since "nvim_get_option" is executed on the tui thread as a C function instead of msgpack-rpc, it accesses global variables that may change on the main thread. --- src/nvim/options.lua | 2 ++ src/nvim/tui/input.c | 26 +++++++------------------- src/nvim/tui/input.h | 2 ++ src/nvim/tui/tui.c | 6 ++++++ test/functional/ui/options_spec.lua | 14 ++++++++++++++ 5 files changed, 31 insertions(+), 19 deletions(-) diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 02102fc168..e7c1a3fe88 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -2587,6 +2587,7 @@ return { type='bool', scope={'global'}, vi_def=true, vim=true, + redraw={'ui_option'}, varname='p_ttimeout', defaults={if_true={vi=true}} }, @@ -2594,6 +2595,7 @@ return { full_name='ttimeoutlen', abbreviation='ttm', type='number', scope={'global'}, vi_def=true, + redraw={'ui_option'}, varname='p_ttm', defaults={if_true={vi=50}} }, diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c index 951cb50c3c..bbee7e4712 100644 --- a/src/nvim/tui/input.c +++ b/src/nvim/tui/input.c @@ -31,6 +31,10 @@ void tinput_init(TermInput *input, Loop *loop) input->paste = 0; input->in_fd = STDIN_FILENO; input->waiting_for_bg_response = 0; + // The main thread is waiting for the UI thread to call CONTINUE, so it can + // safely access global variables. + input->ttimeout = (bool)p_ttimeout; + input->ttimeoutlen = p_ttm; input->key_buffer = rbuffer_new(KEY_BUFFER_SIZE); uv_mutex_init(&input->key_buffer_mutex); uv_cond_init(&input->key_buffer_cond); @@ -285,21 +289,6 @@ static TermKeyResult tk_getkey(TermKey *tk, TermKeyKey *key, bool force) static void tinput_timer_cb(TimeWatcher *watcher, void *data); -static int get_key_code_timeout(void) -{ - Integer ms = -1; - // Check 'ttimeout' to determine if we should send ESC after 'ttimeoutlen'. - Error err = ERROR_INIT; - if (nvim_get_option(cstr_as_string("ttimeout"), &err).data.boolean) { - Object rv = nvim_get_option(cstr_as_string("ttimeoutlen"), &err); - if (!ERROR_SET(&err)) { - ms = rv.data.integer; - } - } - api_clear_error(&err); - return (int)ms; -} - static void tk_getkeys(TermInput *input, bool force) { TermKeyKey key; @@ -324,12 +313,11 @@ static void tk_getkeys(TermInput *input, bool force) // yet contain all the bytes required. `key` structure indicates what // termkey_getkey_force() would return. - int ms = get_key_code_timeout(); - - if (ms > 0) { + if (input->ttimeout && input->ttimeoutlen >= 0) { // Stop the current timer if already running time_watcher_stop(&input->timer_handle); - time_watcher_start(&input->timer_handle, tinput_timer_cb, (uint32_t)ms, 0); + time_watcher_start(&input->timer_handle, tinput_timer_cb, + (uint64_t)input->ttimeoutlen, 0); } else { tk_getkeys(input, true); } diff --git a/src/nvim/tui/input.h b/src/nvim/tui/input.h index 77bd6fa132..b30546c815 100644 --- a/src/nvim/tui/input.h +++ b/src/nvim/tui/input.h @@ -12,7 +12,9 @@ typedef struct term_input { // Phases: -1=all 0=disabled 1=first-chunk 2=continue 3=last-chunk int8_t paste; bool waiting; + bool ttimeout; int8_t waiting_for_bg_response; + long ttimeoutlen; TermKey *tk; #if TERMKEY_VERSION_MAJOR > 0 || TERMKEY_VERSION_MINOR > 18 TermKey_Terminfo_Getstr_Hook *tk_ti_hook_fn; ///< libtermkey terminfo hook diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 22f4501be2..99abdd033b 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -1292,6 +1292,12 @@ static void tui_option_set(UI *ui, String name, Object value) data->print_attr_id = -1; invalidate(ui, 0, data->grid.height, 0, data->grid.width); } + if (strequal(name.data, "ttimeout")) { + data->input.ttimeout = value.data.boolean; + } + if (strequal(name.data, "ttimeoutlen")) { + data->input.ttimeoutlen = (long)value.data.integer; + } } static void tui_raw_line(UI *ui, Integer g, Integer linerow, Integer startcol, diff --git a/test/functional/ui/options_spec.lua b/test/functional/ui/options_spec.lua index 581e196bbb..9646c3fdad 100644 --- a/test/functional/ui/options_spec.lua +++ b/test/functional/ui/options_spec.lua @@ -20,6 +20,8 @@ describe('UI receives option updates', function() pumblend=0, showtabline=1, termguicolors=false, + ttimeout=true, + ttimeoutlen=50, ext_cmdline=false, ext_popupmenu=false, ext_tabline=false, @@ -108,6 +110,18 @@ describe('UI receives option updates', function() eq(expected, screen.options) end) + command("set nottimeout") + expected.ttimeout = false + screen:expect(function() + eq(expected, screen.options) + end) + + command("set ttimeoutlen=100") + expected.ttimeoutlen = 100 + screen:expect(function() + eq(expected, screen.options) + end) + command("set all&") screen:expect(function() eq(defaults, screen.options)