diff options
-rw-r--r-- | src/nvim/eval.c | 33 | ||||
-rw-r--r-- | test/functional/eval/timer_spec.lua | 68 |
2 files changed, 85 insertions, 16 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c index cae032f437..dce2f32707 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -9527,24 +9527,35 @@ static void f_getchar(typval_T *argvars, typval_T *rettv, FunPtr fptr) varnumber_T n; int error = FALSE; - /* Position the cursor. Needed after a message that ends in a space. */ - ui_cursor_goto(msg_row, msg_col); - ++no_mapping; ++allow_keys; for (;; ) { - if (argvars[0].v_type == VAR_UNKNOWN) - /* getchar(): blocking wait. */ + // Position the cursor. Needed after a message that ends in a space, + // or if event processing caused a redraw. + ui_cursor_goto(msg_row, msg_col); + + 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(); + if (!multiqueue_empty(main_loop.events)) { + multiqueue_process_events(main_loop.events); + continue; + } + } n = safe_vgetc(); - else if (get_tv_number_chk(&argvars[0], &error) == 1) - /* getchar(1): only check if char avail */ + } else if (get_tv_number_chk(&argvars[0], &error) == 1) { + // getchar(1): only check if char avail n = vpeekc_any(); - else if (error || vpeekc_any() == NUL) - /* illegal argument or getchar(0) and no char avail: return zero */ + } else if (error || vpeekc_any() == NUL) { + // illegal argument or getchar(0) and no char avail: return zero n = 0; - else - /* getchar(0) and char avail: return char */ + } else { + // getchar(0) and char avail: return char n = safe_vgetc(); + } if (n == K_IGNORE) continue; diff --git a/test/functional/eval/timer_spec.lua b/test/functional/eval/timer_spec.lua index 295c763d74..fba9466b78 100644 --- a/test/functional/eval/timer_spec.lua +++ b/test/functional/eval/timer_spec.lua @@ -3,6 +3,7 @@ local Screen = require('test.functional.ui.screen') local ok, feed, eq, eval = helpers.ok, helpers.feed, helpers.eq, helpers.eval local source, nvim_async, run = helpers.source, helpers.nvim_async, helpers.run local clear, execute, funcs = helpers.clear, helpers.execute, helpers.funcs +local curbufmeths = helpers.curbufmeths describe('timers', function() before_each(function() @@ -62,19 +63,76 @@ describe('timers', function() end) it('are paused when event processing is disabled', function() - -- this is not the intended behavior, but at least there will - -- not be a burst of queued up callbacks - execute("call timer_start(50, 'MyHandler', {'repeat': 2})") + execute("call timer_start(50, 'MyHandler', {'repeat': -1})") run(nil, nil, nil, 100) local count = eval("g:val") + -- shows two line error message and thus invokes the return prompt. + -- if we start to allow event processing here, we need to change this test. + execute("throw 'fatal error'") + run(nil, nil, nil, 300) + feed("<cr>") + local diff = eval("g:val") - count + ok(0 <= diff and diff <= 4) + end) + + it('are triggered in blocking getchar() call', function() + execute("call timer_start(50, 'MyHandler', {'repeat': -1})") nvim_async("command", "let g:c = getchar()") run(nil, nil, nil, 300) feed("c") - local diff = eval("g:val") - count - ok(0 <= diff and diff <= 2) + local count = eval("g:val") + ok(count >= 5) eq(99, eval("g:c")) end) + it('can invoke redraw in blocking getchar() call', function() + local screen = Screen.new(40, 6) + screen:attach() + screen:set_default_attr_ids({ + [1] = {bold=true, foreground=Screen.colors.Blue}, + }) + + curbufmeths.set_lines(0, -1, true, {"ITEM 1", "ITEM 2"}) + source([[ + func! AddItem(timer) + call nvim_buf_set_lines(0, 2, 2, v:true, ['ITEM 3']) + redraw + endfunc + call timer_start(200, 'AddItem') + ]]) + nvim_async("command", "let g:c2 = getchar()") + + screen:expect([[ + ITEM 1 | + ITEM 2 | + {1:~ }| + {1:~ }| + {1:~ }| + ^ | + ]]) + + screen:sleep(200) + screen:expect([[ + ITEM 1 | + ITEM 2 | + ITEM 3 | + {1:~ }| + {1:~ }| + ^ | + ]]) + + feed("3") + eq(51, eval("g:c2")) + screen:expect([[ + ^ITEM 1 | + ITEM 2 | + ITEM 3 | + {1:~ }| + {1:~ }| + | + ]]) + end) + it('can be stopped', function() local t = eval("timer_start(50, 'MyHandler', {'repeat': -1})") eq(0,eval("g:val")) |