mirror of
https://github.com/neovim/neovim.git
synced 2025-09-06 03:18:16 +00:00
Merge pull request #17279 from zeertzjq/state-enter-vpeekc
fix(event-loop): call vpeekc() directly first to check for character
This commit is contained in:
@@ -3189,7 +3189,7 @@ static void getchar_common(typval_T *argvars, typval_T *rettv)
|
|||||||
if (argvars[0].v_type == VAR_UNKNOWN) {
|
if (argvars[0].v_type == VAR_UNKNOWN) {
|
||||||
// getchar(): blocking wait.
|
// getchar(): blocking wait.
|
||||||
// TODO(bfredl): deduplicate shared logic with state_enter ?
|
// TODO(bfredl): deduplicate shared logic with state_enter ?
|
||||||
if (!(char_avail() || using_script() || input_available())) {
|
if (!char_avail()) {
|
||||||
(void)os_inchar(NULL, 0, -1, 0, main_loop.events);
|
(void)os_inchar(NULL, 0, -1, 0, main_loop.events);
|
||||||
if (!multiqueue_empty(main_loop.events)) {
|
if (!multiqueue_empty(main_loop.events)) {
|
||||||
state_handle_k_event();
|
state_handle_k_event();
|
||||||
|
@@ -39,10 +39,16 @@ void state_enter(VimState *s)
|
|||||||
int key;
|
int key;
|
||||||
|
|
||||||
getkey:
|
getkey:
|
||||||
if (char_avail() || using_script() || input_available()) {
|
// Expand mappings first by calling vpeekc() directly.
|
||||||
// Don't block for events if there's a character already available for
|
// - If vpeekc() returns non-NUL, there is a character already available for processing, so
|
||||||
// processing. Characters can come from mappings, scripts and other
|
// don't block for events. vgetc() may still block, in case of an incomplete UTF-8 sequence.
|
||||||
// sources, so this scenario is very common.
|
// - If vpeekc() returns NUL, vgetc() will block, and there are three cases:
|
||||||
|
// - There is no input available.
|
||||||
|
// - All of available input maps to an empty string.
|
||||||
|
// - There is an incomplete mapping.
|
||||||
|
// A blocking wait for a character should only be done in the third case, which is the only
|
||||||
|
// case of the three where typebuf.tb_len > 0 after vpeekc() returns NUL.
|
||||||
|
if (vpeekc() != NUL || typebuf.tb_len > 0) {
|
||||||
key = safe_vgetc();
|
key = safe_vgetc();
|
||||||
} else if (!multiqueue_empty(main_loop.events)) {
|
} else if (!multiqueue_empty(main_loop.events)) {
|
||||||
// Event was made available after the last multiqueue_process_events call
|
// Event was made available after the last multiqueue_process_events call
|
||||||
@@ -55,9 +61,11 @@ getkey:
|
|||||||
// mapping engine.
|
// mapping engine.
|
||||||
(void)os_inchar(NULL, 0, -1, 0, main_loop.events);
|
(void)os_inchar(NULL, 0, -1, 0, main_loop.events);
|
||||||
// If an event was put into the queue, we send K_EVENT directly.
|
// If an event was put into the queue, we send K_EVENT directly.
|
||||||
key = !multiqueue_empty(main_loop.events)
|
if (!multiqueue_empty(main_loop.events)) {
|
||||||
? K_EVENT
|
key = K_EVENT;
|
||||||
: safe_vgetc();
|
} else {
|
||||||
|
goto getkey;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key == K_EVENT) {
|
if (key == K_EVENT) {
|
||||||
|
@@ -140,6 +140,25 @@ describe('input utf sequences that contain CSI (0x9B)', function()
|
|||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
describe('input split utf sequences', function()
|
||||||
|
it('ok', function()
|
||||||
|
local str = '►'
|
||||||
|
feed('i' .. str:sub(1, 1))
|
||||||
|
helpers.sleep(10)
|
||||||
|
feed(str:sub(2, 3))
|
||||||
|
expect('►')
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('can be mapped', function()
|
||||||
|
command('inoremap ► E296BA')
|
||||||
|
local str = '►'
|
||||||
|
feed('i' .. str:sub(1, 1))
|
||||||
|
helpers.sleep(10)
|
||||||
|
feed(str:sub(2, 3))
|
||||||
|
expect('E296BA')
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
describe('input non-printable chars', function()
|
describe('input non-printable chars', function()
|
||||||
after_each(function()
|
after_each(function()
|
||||||
os.remove('Xtest-overwrite')
|
os.remove('Xtest-overwrite')
|
||||||
|
@@ -272,4 +272,12 @@ describe('timers', function()
|
|||||||
]]
|
]]
|
||||||
eq("Vim(call):E48: Not allowed in sandbox", exc_exec("sandbox call timer_start(0, 'Scary')"))
|
eq("Vim(call):E48: Not allowed in sandbox", exc_exec("sandbox call timer_start(0, 'Scary')"))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('can be triggered after an empty string <expr> mapping', function()
|
||||||
|
local screen = Screen.new(40, 6)
|
||||||
|
screen:attach()
|
||||||
|
command([=[imap <expr> <F2> [timer_start(0, { _ -> execute("throw 'x'", "") }), ''][-1]]=])
|
||||||
|
feed('i<F2>')
|
||||||
|
screen:expect({any='E605: Exception not caught: x'})
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
Reference in New Issue
Block a user