Merge PR #1518 'Improve functional tests and perform explicit K_EVENT handling'

This commit is contained in:
Thiago de Arruda 2014-11-21 17:08:29 -03:00
commit af5eaf22c5
12 changed files with 98 additions and 80 deletions

View File

@ -593,9 +593,17 @@ edit (
* Get a character for Insert mode. Ignore K_IGNORE. * Get a character for Insert mode. Ignore K_IGNORE.
*/ */
lastc = c; /* remember previous char for CTRL-D */ lastc = c; /* remember previous char for CTRL-D */
event_enable_deferred();
do { do {
c = safe_vgetc(); c = safe_vgetc();
} while (c == K_IGNORE); } while (c == K_IGNORE);
event_disable_deferred();
if (c == K_EVENT) {
c = lastc;
event_process();
continue;
}
/* Don't want K_CURSORHOLD for the second key, e.g., after CTRL-V. */ /* Don't want K_CURSORHOLD for the second key, e.g., after CTRL-V. */
did_cursorhold = TRUE; did_cursorhold = TRUE;
@ -943,10 +951,6 @@ doESCkey:
did_cursorhold = TRUE; did_cursorhold = TRUE;
break; break;
case K_EVENT:
event_process();
break;
case K_HOME: /* <Home> */ case K_HOME: /* <Home> */
case K_KHOME: case K_KHOME:
case K_S_HOME: case K_S_HOME:

View File

@ -311,9 +311,16 @@ getcmdline (
/* Get a character. Ignore K_IGNORE, it should not do anything, such /* Get a character. Ignore K_IGNORE, it should not do anything, such
* as stop completion. */ * as stop completion. */
event_enable_deferred();
do { do {
c = safe_vgetc(); c = safe_vgetc();
} while (c == K_IGNORE); } while (c == K_IGNORE);
event_disable_deferred();
if (c == K_EVENT) {
event_process();
continue;
}
if (KeyTyped) { if (KeyTyped) {
some_key_typed = TRUE; some_key_typed = TRUE;
@ -769,11 +776,6 @@ getcmdline (
* Big switch for a typed command line character. * Big switch for a typed command line character.
*/ */
switch (c) { switch (c) {
case K_EVENT:
event_process();
// Force a redraw even though the command line didn't change
shell_resized();
goto cmdline_not_changed;
case K_BS: case K_BS:
case Ctrl_H: case Ctrl_H:
case K_DEL: case K_DEL:
@ -1885,8 +1887,6 @@ redraw:
} }
if (IS_SPECIAL(c1)) { if (IS_SPECIAL(c1)) {
// Process deferred events
event_process();
// Ignore other special key codes // Ignore other special key codes
continue; continue;
} }

View File

@ -2481,7 +2481,6 @@ inchar (
char_u dum[DUM_LEN + 1]; char_u dum[DUM_LEN + 1];
for (;; ) { for (;; ) {
event_process();
len = ui_inchar(dum, DUM_LEN, 0L, 0); len = ui_inchar(dum, DUM_LEN, 0L, 0);
if (len == 0 || (len == 1 && dum[0] == 3)) if (len == 0 || (len == 1 && dum[0] == 3))
break; break;

View File

@ -44,7 +44,6 @@
#include "nvim/term.h" #include "nvim/term.h"
#include "nvim/ui.h" #include "nvim/ui.h"
#include "nvim/os/os.h" #include "nvim/os/os.h"
#include "nvim/os/event.h"
/* /*
* To be able to scroll back at the "more" and "hit-enter" prompts we need to * To be able to scroll back at the "more" and "hit-enter" prompts we need to
@ -2076,9 +2075,6 @@ static int do_more_prompt(int typed_char)
toscroll = 0; toscroll = 0;
switch (c) { switch (c) {
case K_EVENT:
event_process();
break;
case BS: /* scroll one line back */ case BS: /* scroll one line back */
case K_BS: case K_BS:
case 'k': case 'k':
@ -2738,8 +2734,6 @@ do_dialog (
break; break;
default: /* Could be a hotkey? */ default: /* Could be a hotkey? */
if (c < 0) { /* special keys are ignored here */ if (c < 0) { /* special keys are ignored here */
// drain event queue to prevent infinite loop
event_process();
continue; continue;
} }
if (c == ':' && ex_cmd) { if (c == ':' && ex_cmd) {

View File

@ -312,7 +312,6 @@ static const struct nv_cmd {
{K_F8, farsi_fkey, 0, 0}, {K_F8, farsi_fkey, 0, 0},
{K_F9, farsi_fkey, 0, 0}, {K_F9, farsi_fkey, 0, 0},
{K_CURSORHOLD, nv_cursorhold, NV_KEEPREG, 0}, {K_CURSORHOLD, nv_cursorhold, NV_KEEPREG, 0},
{K_EVENT, nv_event, NV_KEEPREG, 0},
}; };
/* Number of commands in nv_cmds[]. */ /* Number of commands in nv_cmds[]. */
@ -483,7 +482,15 @@ normal_cmd (
/* /*
* Get the command character from the user. * Get the command character from the user.
*/ */
event_enable_deferred();
c = safe_vgetc(); c = safe_vgetc();
event_disable_deferred();
if (c == K_EVENT) {
event_process();
return;
}
LANGMAP_ADJUST(c, true); LANGMAP_ADJUST(c, true);
/* /*
@ -7373,8 +7380,3 @@ static void nv_cursorhold(cmdarg_T *cap)
did_cursorhold = true; did_cursorhold = true;
cap->retval |= CA_COMMAND_BUSY; /* don't call edit() now */ cap->retval |= CA_COMMAND_BUSY; /* don't call edit() now */
} }
static void nv_event(cmdarg_T *cap)
{
event_process();
}

View File

@ -18,6 +18,8 @@
#include "nvim/vim.h" #include "nvim/vim.h"
#include "nvim/memory.h" #include "nvim/memory.h"
#include "nvim/misc2.h" #include "nvim/misc2.h"
#include "nvim/term.h"
#include "nvim/screen.h"
#include "nvim/lib/klist.h" #include "nvim/lib/klist.h"
@ -39,6 +41,7 @@ typedef struct {
// loop(to avoid recursion), but before returning from // loop(to avoid recursion), but before returning from
// `event_poll` // `event_poll`
static klist_t(Event) *deferred_events = NULL, *immediate_events = NULL; static klist_t(Event) *deferred_events = NULL, *immediate_events = NULL;
static int deferred_events_allowed = 0;
void event_init(void) void event_init(void)
{ {
@ -134,7 +137,17 @@ void event_poll(int ms)
bool event_has_deferred(void) bool event_has_deferred(void)
{ {
return !kl_empty(deferred_events); return deferred_events_allowed && !kl_empty(deferred_events);
}
void event_enable_deferred(void)
{
++deferred_events_allowed;
}
void event_disable_deferred(void)
{
--deferred_events_allowed;
} }
// Queue an event // Queue an event
@ -146,6 +159,11 @@ void event_push(Event event, bool deferred)
void event_process(void) void event_process(void)
{ {
process_events_from(deferred_events); process_events_from(deferred_events);
if (must_redraw) {
update_screen(0);
out_flush();
}
} }
static void process_events_from(klist_t(Event) *queue) static void process_events_from(klist_t(Event) *queue)

View File

@ -84,13 +84,11 @@ void input_stop(void)
// Low level input function. // Low level input function.
int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt) int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt)
{ {
InbufPollResult result; if (rbuffer_pending(input_buffer)) {
return (int)rbuffer_read(input_buffer, (char *)buf, (size_t)maxlen);
if (event_has_deferred()) {
// Return pending event bytes
return push_event_key(buf, maxlen);
} }
InbufPollResult result;
if (ms >= 0) { if (ms >= 0) {
if ((result = inbuf_poll(ms)) == kInputNone) { if ((result = inbuf_poll(ms)) == kInputNone) {
return 0; return 0;
@ -110,24 +108,27 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt)
} }
} }
// If there are deferred events, return the keys directly
if (event_has_deferred()) {
return push_event_key(buf, maxlen);
}
// If input was put directly in typeahead buffer bail out here. // If input was put directly in typeahead buffer bail out here.
if (typebuf_changed(tb_change_cnt)) { if (typebuf_changed(tb_change_cnt)) {
return 0; return 0;
} }
if (result == kInputEof) { if (rbuffer_pending(input_buffer)) {
read_error_exit(); // Safe to convert rbuffer_read to int, it will never overflow since we use
return 0; // relatively small buffers.
return (int)rbuffer_read(input_buffer, (char *)buf, (size_t)maxlen);
} }
// Safe to convert rbuffer_read to int, it will never overflow since // If there are deferred events, return the keys directly
// we use relatively small buffers. if (event_has_deferred()) {
return (int)rbuffer_read(input_buffer, (char *)buf, (size_t)maxlen); return push_event_key(buf, maxlen);
}
if (result == kInputEof) {
read_error_exit();
}
return 0;
} }
// Check if a character is available for reading // Check if a character is available for reading
@ -320,9 +321,8 @@ static int push_event_key(uint8_t *buf, int maxlen)
static bool input_ready(void) static bool input_ready(void)
{ {
return typebuf_was_filled || // API call filled typeahead return typebuf_was_filled || // API call filled typeahead
event_has_deferred() || // Events must be processed
(!embedded_mode && (
rbuffer_pending(input_buffer) > 0 || // Stdin input rbuffer_pending(input_buffer) > 0 || // Stdin input
eof)); // Stdin closed event_has_deferred() || // Events must be processed
(!embedded_mode && eof); // Stdin closed
} }

View File

@ -42,7 +42,6 @@ local function request(method, ...)
if not loop_stopped then if not loop_stopped then
-- Except when the loop has been stopped by a notification triggered -- Except when the loop has been stopped by a notification triggered
-- by the initial request, for example. -- by the initial request, for example.
session:request('vim_eval', '1')
end end
return rv return rv
end end
@ -99,25 +98,20 @@ local function nvim_eval(expr)
return request('vim_eval', expr) return request('vim_eval', expr)
end end
local function nvim_feed(input, mode) local function nvim_feed(input)
mode = mode or '' while #input > 0 do
request('vim_feedkeys', input, mode) local written = request('vim_input', input)
end input = input:sub(written + 1)
local function buffer_slice(start, stop, buffer_idx)
local include_end = false
if not stop then
stop = -1
include_end = true
end end
local buffer = request('vim_get_buffers')[buffer_idx or 1]
local slice = request('buffer_get_line_slice', buffer, start or 0, stop,
true, include_end)
return table.concat(slice, '\n')
end end
local function nvim_replace_termcodes(input) local function nvim_replace_termcodes(input)
return request('vim_replace_termcodes', input, false, true, true) -- small hack to stop <C-@> from being replaced by the internal
-- representation(which is different and won't work for vim_input)
local temp_replacement = 'CCCCCCCCC@@@@@@@@@@'
input = input:gsub('<[Cc][-]@>', temp_replacement)
local rv = request('vim_replace_termcodes', input, false, true, true)
return rv:gsub(temp_replacement, '\000')
end end
local function dedent(str) local function dedent(str)
@ -150,7 +144,7 @@ end
local function rawfeed(...) local function rawfeed(...)
for _, v in ipairs({...}) do for _, v in ipairs({...}) do
nvim_feed(dedent(v), 'nt') nvim_feed(dedent(v))
end end
end end
@ -166,19 +160,19 @@ local function clear()
end end
local function insert(...) local function insert(...)
nvim_feed('i', 'nt') nvim_feed('i')
rawfeed(...) rawfeed(...)
nvim_feed(nvim_replace_termcodes('<ESC>'), 'nt') nvim_feed(nvim_replace_termcodes('<ESC>'))
end end
local function execute(...) local function execute(...)
for _, v in ipairs({...}) do for _, v in ipairs({...}) do
if v:sub(1, 1) ~= '/' then if v:sub(1, 1) ~= '/' then
-- not a search command, prefix with colon -- not a search command, prefix with colon
nvim_feed(':', 'nt') nvim_feed(':')
end end
nvim_feed(v, 'nt') nvim_feed(v)
nvim_feed(nvim_replace_termcodes('<CR>'), 'nt') nvim_feed(nvim_replace_termcodes('<CR>'))
end end
end end
@ -200,10 +194,6 @@ local function neq(expected, actual)
return assert.are_not.same(expected, actual) return assert.are_not.same(expected, actual)
end end
local function expect(contents, first, last, buffer_index)
return eq(dedent(contents), buffer_slice(first, last, buffer_index))
end
local function ok(expr) local function ok(expr)
assert.is_true(expr) assert.is_true(expr)
end end
@ -233,6 +223,10 @@ local function curbuf(method, ...)
end end
local function curbuf_contents() local function curbuf_contents()
-- Before inspecting the buffer, execute 'vim_eval' to wait until all
-- previously sent keys are processed(vim_eval is a deferred function, and
-- only processed after all input)
session:request('vim_eval', '1')
return table.concat(curbuf('get_line_slice', 0, -1, true, true), '\n') return table.concat(curbuf('get_line_slice', 0, -1, true, true), '\n')
end end
@ -252,6 +246,10 @@ local function curtab(method, ...)
return tabpage(method, tab, ...) return tabpage(method, tab, ...)
end end
local function expect(contents)
return eq(dedent(contents), curbuf_contents())
end
clear() clear()
return { return {

View File

@ -37,7 +37,7 @@ describe('jobs', function()
end) end)
it('allows interactive commands', function() it('allows interactive commands', function()
nvim('command', notify_str('v:job_data[1]', 'v:job_data[2]')) nvim('command', notify_str('v:job_data[1]', 'get(v:job_data, 2)'))
nvim('command', "let j = jobstart('xxx', 'cat', ['-'])") nvim('command', "let j = jobstart('xxx', 'cat', ['-'])")
neq(0, eval('j')) neq(0, eval('j'))
nvim('command', 'call jobsend(j, "abc\\n")') nvim('command', 'call jobsend(j, "abc\\n")')
@ -46,9 +46,8 @@ describe('jobs', function()
eq({'notification', 'stdout', {{'123', 'xyz'}}}, next_message()) eq({'notification', 'stdout', {{'123', 'xyz'}}}, next_message())
nvim('command', 'call jobsend(j, [123, "xyz"])') nvim('command', 'call jobsend(j, [123, "xyz"])')
eq({'notification', 'stdout', {{'123', 'xyz'}}}, next_message()) eq({'notification', 'stdout', {{'123', 'xyz'}}}, next_message())
nvim('command', notify_str('v:job_data[1])'))
nvim('command', "call jobstop(j)") nvim('command', "call jobstop(j)")
eq({'notification', 'exit', {}}, next_message()) eq({'notification', 'exit', {0}}, next_message())
end) end)
it('preserves NULs', function() it('preserves NULs', function()
@ -59,9 +58,10 @@ describe('jobs', function()
file:close() file:close()
-- v:job_data preserves NULs. -- v:job_data preserves NULs.
nvim('command', notify_str('v:job_data[1]', 'v:job_data[2]')) nvim('command', notify_str('v:job_data[1]', 'get(v:job_data, 2)'))
nvim('command', "let j = jobstart('xxx', 'cat', ['"..filename.."'])") nvim('command', "let j = jobstart('xxx', 'cat', ['"..filename.."'])")
eq({'notification', 'stdout', {{'abc\ndef'}}}, next_message()) eq({'notification', 'stdout', {{'abc\ndef'}}}, next_message())
eq({'notification', 'exit', {0}}, next_message())
os.remove(filename) os.remove(filename)
-- jobsend() preserves NULs. -- jobsend() preserves NULs.
@ -72,12 +72,13 @@ describe('jobs', function()
end) end)
it('will hold data if it does not end in a newline', function() it('will hold data if it does not end in a newline', function()
nvim('command', notify_str('v:job_data[1]', 'v:job_data[2]')) nvim('command', notify_str('v:job_data[1]', 'get(v:job_data, 2)'))
nvim('command', "let j = jobstart('xxx', 'cat', ['-'])") nvim('command', "let j = jobstart('xxx', 'cat', ['-'])")
nvim('command', 'call jobsend(j, "abc\\nxyz")') nvim('command', 'call jobsend(j, "abc\\nxyz")')
eq({'notification', 'stdout', {{'abc'}}}, next_message()) eq({'notification', 'stdout', {{'abc'}}}, next_message())
nvim('command', "call jobstop(j)") nvim('command', "call jobstop(j)")
eq({'notification', 'stdout', {{'xyz'}}}, next_message()) eq({'notification', 'stdout', {{'xyz'}}}, next_message())
eq({'notification', 'exit', {0}}, next_message())
end) end)
it('will not allow jobsend/stop on a non-existent job', function() it('will not allow jobsend/stop on a non-existent job', function()

View File

@ -31,7 +31,7 @@ describe('BufEnter with modelines', function()
execute('sp Xxx') execute('sp Xxx')
-- Append text with autoindent to this file -- Append text with autoindent to this file
feed('G?this is a<Esc>') feed('G?this is a<CR>')
feed('othis should be auto-indented<Esc>') feed('othis should be auto-indented<Esc>')
-- Go to Xxx, no autocmd anymore -- Go to Xxx, no autocmd anymore
@ -39,7 +39,7 @@ describe('BufEnter with modelines', function()
execute('buf Xxx') execute('buf Xxx')
-- Append text without autoindent to Xxx -- Append text without autoindent to Xxx
feed('G?this is a<Esc>') feed('G?this is a<CR>')
feed('othis should be in column 1<Esc>') feed('othis should be in column 1<Esc>')
execute('wq') execute('wq')

View File

@ -3,6 +3,7 @@
local helpers = require('test.functional.helpers') local helpers = require('test.functional.helpers')
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
local execute, expect = helpers.execute, helpers.expect local execute, expect = helpers.execute, helpers.expect
local eval = helpers.eval
describe('v:hlsearch', function() describe('v:hlsearch', function()
setup(clear) setup(clear)
@ -44,7 +45,7 @@ describe('v:hlsearch', function()
execute('$put=r') execute('$put=r')
execute('call garbagecollect(1)') execute('call garbagecollect(1)')
execute('call getchar()') execute('call getchar()')
execute('1d') execute('1d', '1d')
-- Assert buffer contents. -- Assert buffer contents.
expect([[ expect([[

View File

@ -10,6 +10,7 @@ local eq, clear, eval, feed, nvim =
local function create_file_with_nuls(name) local function create_file_with_nuls(name)
return function() return function()
feed('ipart1<C-V>000part2<C-V>000part3<ESC>:w '..name..'<CR>') feed('ipart1<C-V>000part2<C-V>000part3<ESC>:w '..name..'<CR>')
eval('1') -- wait for the file to be created
end end
end end