tui/input: defer nvim_paste properly.

Otherwise cursor and redraw code for normal and insert mode will not run. The
"tickle" workaround was used for this instead, and can now be removed.

The builtin vim.lua got the name
[string "-- Nvim-Lua stdlib: thevimmodule (:help l..."]
in error messages. Fix it to something reasonable.
This commit is contained in:
Björn Linse 2019-08-29 12:16:31 +02:00
parent 8a03acb8da
commit 7a85792884
4 changed files with 58 additions and 17 deletions

View File

@ -1283,8 +1283,6 @@ theend:
api_free_array(args); api_free_array(args);
if (cancel || phase == -1 || phase == 3) { // End of paste-stream. if (cancel || phase == -1 || phase == 3) { // End of paste-stream.
draining = false; draining = false;
// XXX: Tickle main loop to ensure cursor is updated.
loop_schedule_deferred(&main_loop, event_create(loop_dummy_event, 0));
} }
return !cancel; return !cancel;

View File

@ -269,7 +269,9 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
#endif #endif
// vim // vim
if (luaL_dostring(lstate, (char *)&vim_module[0])) { const char *code = (char *)&vim_module[0];
if (luaL_loadbuffer(lstate, code, strlen(code), "@vim.lua")
|| lua_pcall(lstate, 0, LUA_MULTRET, 0)) {
nlua_error(lstate, _("E5106: Error while creating vim module: %.*s")); nlua_error(lstate, _("E5106: Error while creating vim module: %.*s"));
return 1; return 1;
} }

View File

@ -106,17 +106,15 @@ static void tinput_wait_enqueue(void **argv)
RBUFFER_UNTIL_EMPTY(input->key_buffer, buf, len) { RBUFFER_UNTIL_EMPTY(input->key_buffer, buf, len) {
const String keys = { .data = buf, .size = len }; const String keys = { .data = buf, .size = len };
if (input->paste) { if (input->paste) {
Error err = ERROR_INIT; String copy = copy_string(keys);
// Paste phase: "continue" (unless handler canceled). multiqueue_put(main_loop.events, tinput_paste_event, 3,
input->paste = !nvim_paste(keys, true, input->paste, &err) copy.data, copy.size, (intptr_t)input->paste);
? 0 : (1 == input->paste ? 2 : input->paste); if (input->paste == 1) {
// Paste phase: "continue"
input->paste = 2;
}
rbuffer_consumed(input->key_buffer, len); rbuffer_consumed(input->key_buffer, len);
rbuffer_reset(input->key_buffer); rbuffer_reset(input->key_buffer);
if (ERROR_SET(&err)) {
// TODO(justinmk): emsgf() does not display, why?
msg_printf_attr(HL_ATTR(HLF_E)|MSG_HIST, "paste: %s", err.msg);
api_clear_error(&err);
}
} else { } else {
const size_t consumed = input_enqueue(keys); const size_t consumed = input_enqueue(keys);
if (consumed) { if (consumed) {
@ -134,6 +132,33 @@ static void tinput_wait_enqueue(void **argv)
uv_mutex_unlock(&input->key_buffer_mutex); uv_mutex_unlock(&input->key_buffer_mutex);
} }
static void tinput_paste_event(void **argv)
{
static bool canceled = false;
String keys = { .data = argv[0], .size = (size_t)argv[1] };
intptr_t phase = (intptr_t)argv[2];
if (phase == -1 || phase == 1) {
canceled = false;
}
Error err = ERROR_INIT;
if (!canceled) {
if (!nvim_paste(keys, true, phase, &err)) {
// paste failed, ingore further segments of the same paste
canceled = true;
}
}
if (ERROR_SET(&err)) {
emsgf("paste: %s", err.msg);
api_clear_error(&err);
}
api_free_string(keys);
}
static void tinput_flush(TermInput *input, bool wait_until_empty) static void tinput_flush(TermInput *input, bool wait_until_empty)
{ {
size_t drain_boundary = wait_until_empty ? 0 : 0xff; size_t drain_boundary = wait_until_empty ? 0 : 0xff;

View File

@ -352,15 +352,23 @@ describe('TUI', function()
]]} ]]}
-- Start pasting... -- Start pasting...
feed_data('\027[200~line 1\nline 2\n') feed_data('\027[200~line 1\nline 2\n')
expect_child_buf_lines({'foo',''}) screen:expect{grid=[[
screen:expect{any='paste: Error executing lua'} foo |
|
{5: }|
{8:paste: Error executing lua: [string "<nvim>"]:2: f}|
{8:ake fail} |
{10:Press ENTER or type command to continue}{1: } |
{3:-- TERMINAL --} |
]]}
-- Remaining chunks are discarded after vim.paste() failure. -- Remaining chunks are discarded after vim.paste() failure.
feed_data('line 3\nline 4\n') feed_data('line 3\nline 4\n')
feed_data('line 5\nline 6\n') feed_data('line 5\nline 6\n')
feed_data('line 7\nline 8\n') feed_data('line 7\nline 8\n')
-- Stop paste. -- Stop paste.
feed_data('\027[201~') feed_data('\027[201~')
feed_data('\n') -- <Enter> feed_data('\n') -- <CR>
expect_child_buf_lines({'foo',''})
--Dot-repeat/redo is not modified by failed paste. --Dot-repeat/redo is not modified by failed paste.
feed_data('.') feed_data('.')
screen:expect{grid=[[ screen:expect{grid=[[
@ -388,7 +396,7 @@ describe('TUI', function()
vim.paste = _G.save_paste_fn vim.paste = _G.save_paste_fn
]], {}) ]], {})
feed_data('\027[200~line A\nline B\n\027[201~') feed_data('\027[200~line A\nline B\n\027[201~')
feed_data('\n') -- <Enter> feed_data('\n') -- <CR>
screen:expect{grid=[[ screen:expect{grid=[[
foo | foo |
typed input...line A | typed input...line A |
@ -414,7 +422,15 @@ describe('TUI', function()
it("paste: 'nomodifiable' buffer", function() it("paste: 'nomodifiable' buffer", function()
child_session:request('nvim_command', 'set nomodifiable') child_session:request('nvim_command', 'set nomodifiable')
feed_data('\027[200~fail 1\nfail 2\n\027[201~') feed_data('\027[200~fail 1\nfail 2\n\027[201~')
screen:expect{any='Vim:E21'} screen:expect{grid=[[
|
{4:~ }|
{5: }|
{8:paste: Error executing lua: vim.lua:194: Vim:E21: }|
{8:Cannot make changes, 'modifiable' is off} |
{10:Press ENTER or type command to continue}{1: } |
{3:-- TERMINAL --} |
]]}
feed_data('\n') -- <Enter> feed_data('\n') -- <Enter>
child_session:request('nvim_command', 'set modifiable') child_session:request('nvim_command', 'set modifiable')
feed_data('\027[200~success 1\nsuccess 2\n\027[201~') feed_data('\027[200~success 1\nsuccess 2\n\027[201~')