Merge pull request #5384 from bfredl/getchar_event

allow event processing in getchar()
This commit is contained in:
Björn Linse 2016-10-15 10:36:34 +02:00 committed by GitHub
commit 9477c5bb5b
2 changed files with 85 additions and 16 deletions

View File

@ -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;

View File

@ -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"))