aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjörn Linse <bjorn.linse@gmail.com>2019-08-31 11:18:35 +0200
committerGitHub <noreply@github.com>2019-08-31 11:18:35 +0200
commit25e0a449bb6619fc534fa862c2f591657be1e1d5 (patch)
treebf3d8beff647c8e1e5b39c746088843d629338ef
parent8a03acb8dad4abaf507d502b11a66bd5a2b5e51e (diff)
parent2c605d1f22a243bc34b680f69c7c8cfe01b80887 (diff)
downloadrneovim-25e0a449bb6619fc534fa862c2f591657be1e1d5.tar.gz
rneovim-25e0a449bb6619fc534fa862c2f591657be1e1d5.tar.bz2
rneovim-25e0a449bb6619fc534fa862c2f591657be1e1d5.zip
Merge pull request #10878 from bfredl/pastedefer
TUI: defer nvim_paste event properly
-rw-r--r--src/nvim/api/vim.c2
-rw-r--r--src/nvim/event/loop.c12
-rw-r--r--src/nvim/lua/executor.c4
-rw-r--r--src/nvim/message.c2
-rw-r--r--src/nvim/ops.c22
-rw-r--r--src/nvim/tui/input.c35
-rw-r--r--src/nvim/tui/tui.c2
-rw-r--r--src/nvim/ui.c6
-rw-r--r--test/functional/api/vim_spec.lua29
-rw-r--r--test/functional/terminal/tui_spec.lua26
10 files changed, 108 insertions, 32 deletions
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index a39ee5d038..21cba96ba7 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -1283,8 +1283,6 @@ theend:
api_free_array(args);
if (cancel || phase == -1 || phase == 3) { // End of paste-stream.
draining = false;
- // XXX: Tickle main loop to ensure cursor is updated.
- loop_schedule_deferred(&main_loop, event_create(loop_dummy_event, 0));
}
return !cancel;
diff --git a/src/nvim/event/loop.c b/src/nvim/event/loop.c
index 529ddd8eba..a01bbc9888 100644
--- a/src/nvim/event/loop.c
+++ b/src/nvim/event/loop.c
@@ -71,7 +71,7 @@ bool loop_poll_events(Loop *loop, int ms)
return timeout_expired;
}
-/// Schedules an event from another thread.
+/// Schedules a fast event from another thread.
///
/// @note Event is queued into `fast_events`, which is processed outside of the
/// primary `events` queue by loop_poll_events(). For `main_loop`, that
@@ -79,7 +79,7 @@ bool loop_poll_events(Loop *loop, int ms)
/// (VimState.execute), so redraw and other side-effects are likely to be
/// skipped.
/// @see loop_schedule_deferred
-void loop_schedule(Loop *loop, Event event)
+void loop_schedule_fast(Loop *loop, Event event)
{
uv_mutex_lock(&loop->mutex);
multiqueue_put_event(loop->thread_events, event);
@@ -87,15 +87,15 @@ void loop_schedule(Loop *loop, Event event)
uv_mutex_unlock(&loop->mutex);
}
-/// Schedules an event from another thread. Unlike loop_schedule(), the event
-/// is forwarded to `Loop.events`, instead of being processed immediately.
+/// Schedules an event from another thread. Unlike loop_schedule_fast(), the
+/// event is forwarded to `Loop.events`, instead of being processed immediately.
///
-/// @see loop_schedule
+/// @see loop_schedule_fast
void loop_schedule_deferred(Loop *loop, Event event)
{
Event *eventp = xmalloc(sizeof(*eventp));
*eventp = event;
- loop_schedule(loop, event_create(loop_deferred_event, 2, loop, eventp));
+ loop_schedule_fast(loop, event_create(loop_deferred_event, 2, loop, eventp));
}
static void loop_deferred_event(void **argv)
{
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index 3de1b531e6..f51aa3c6d4 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -269,7 +269,9 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
#endif
// 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"));
return 1;
}
diff --git a/src/nvim/message.c b/src/nvim/message.c
index 9bea9f5c4a..c8deaa590c 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -753,7 +753,7 @@ void msg_schedule_emsgf(const char *const fmt, ...)
va_end(ap);
char *s = xstrdup((char *)IObuff);
- loop_schedule(&main_loop, event_create(msg_emsgf_event, 1, s));
+ multiqueue_put(main_loop.events, msg_emsgf_event, 1, s);
}
/*
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index df4452cd4a..bfd02d4ff1 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -5685,9 +5685,6 @@ end:
/// @param[out] reg Expected to be empty
bool prepare_yankreg_from_object(yankreg_T *reg, String regtype, size_t lines)
{
- if (regtype.size > 1) {
- return false;
- }
char type = regtype.data ? regtype.data[0] : NUL;
switch (type) {
@@ -5707,6 +5704,23 @@ bool prepare_yankreg_from_object(yankreg_T *reg, String regtype, size_t lines)
return false;
}
+ reg->y_width = 0;
+ if (regtype.size > 1) {
+ if (reg->y_type != kMTBlockWise) {
+ return false;
+ }
+
+ // allow "b7" for a block at least 7 spaces wide
+ if (!ascii_isdigit(regtype.data[1])) {
+ return false;
+ }
+ const char *p = regtype.data+1;
+ reg->y_width = getdigits_int((char_u **)&p)-1;
+ if (regtype.size > (size_t)(p-regtype.data)) {
+ return false;
+ }
+ }
+
reg->y_array = xcalloc(lines, sizeof(uint8_t *));
reg->y_size = lines;
reg->additional_data = NULL;
@@ -5743,7 +5757,7 @@ void finish_yankreg_from_object(yankreg_T *reg, bool clipboard_adjust)
}
}
assert(maxlen <= INT_MAX);
- reg->y_width = (int)maxlen - 1;
+ reg->y_width = MAX(reg->y_width, (int)maxlen - 1);
}
}
diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c
index 1f67e6ce13..ed9b410a19 100644
--- a/src/nvim/tui/input.c
+++ b/src/nvim/tui/input.c
@@ -106,17 +106,15 @@ static void tinput_wait_enqueue(void **argv)
RBUFFER_UNTIL_EMPTY(input->key_buffer, buf, len) {
const String keys = { .data = buf, .size = len };
if (input->paste) {
- Error err = ERROR_INIT;
- // Paste phase: "continue" (unless handler canceled).
- input->paste = !nvim_paste(keys, true, input->paste, &err)
- ? 0 : (1 == input->paste ? 2 : input->paste);
+ String copy = copy_string(keys);
+ multiqueue_put(main_loop.events, tinput_paste_event, 3,
+ copy.data, copy.size, (intptr_t)input->paste);
+ if (input->paste == 1) {
+ // Paste phase: "continue"
+ input->paste = 2;
+ }
rbuffer_consumed(input->key_buffer, len);
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 {
const size_t consumed = input_enqueue(keys);
if (consumed) {
@@ -134,12 +132,27 @@ static void tinput_wait_enqueue(void **argv)
uv_mutex_unlock(&input->key_buffer_mutex);
}
+static void tinput_paste_event(void **argv)
+{
+ String keys = { .data = argv[0], .size = (size_t)argv[1] };
+ intptr_t phase = (intptr_t)argv[2];
+
+ Error err = ERROR_INIT;
+ nvim_paste(keys, true, phase, &err);
+ 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)
{
size_t drain_boundary = wait_until_empty ? 0 : 0xff;
do {
uv_mutex_lock(&input->key_buffer_mutex);
- loop_schedule(&main_loop, event_create(tinput_wait_enqueue, 1, input));
+ loop_schedule_fast(&main_loop, event_create(tinput_wait_enqueue, 1, input));
input->waiting = true;
while (input->waiting) {
uv_cond_wait(&input->key_buffer_cond, &input->key_buffer_mutex);
@@ -497,7 +510,7 @@ static void tinput_read_cb(Stream *stream, RBuffer *buf, size_t count_,
TermInput *input = data;
if (eof) {
- loop_schedule(&main_loop, event_create(tinput_done_event, 0));
+ loop_schedule_fast(&main_loop, event_create(tinput_done_event, 0));
return;
}
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index ea8f9d9f71..6e1b7ef2db 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -454,7 +454,7 @@ static void tui_scheduler(Event event, void *d)
{
UI *ui = d;
TUIData *data = ui->data;
- loop_schedule(data->loop, event); // `tui_loop` local to tui_main().
+ loop_schedule_fast(data->loop, event); // `tui_loop` local to tui_main().
}
#ifdef UNIX
diff --git a/src/nvim/ui.c b/src/nvim/ui.c
index fc4a3a403d..5d191314ba 100644
--- a/src/nvim/ui.c
+++ b/src/nvim/ui.c
@@ -228,7 +228,11 @@ static void ui_refresh_event(void **argv)
void ui_schedule_refresh(void)
{
- loop_schedule(&main_loop, event_create(ui_refresh_event, 0));
+ // TODO(bfredl): "fast" is not optimal. UI should be refreshed only at
+ // deferred processing plus a few more blocked-on-input situtions like
+ // wait_return(), but not any os_breakcheck(). Alternatively make this
+ // defered and make wait_return() process deferred events already.
+ loop_schedule_fast(&main_loop, event_create(ui_refresh_event, 0));
}
void ui_default_colors_set(void)
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index 6f7661dd76..02e83c4d58 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -518,6 +518,35 @@ describe('API', function()
line 3]])
eq({0,3,6,0}, funcs.getpos('.'))
end)
+
+ it('allows block width', function()
+ -- behave consistently with setreg(); support "\022{NUM}" return by getregtype()
+ meths.put({'line 1','line 2','line 3'}, 'l', false, false)
+ expect([[
+ line 1
+ line 2
+ line 3
+ ]])
+
+ -- larger width create spaces
+ meths.put({'a', 'bc'}, 'b3', false, false)
+ expect([[
+ a line 1
+ bc line 2
+ line 3
+ ]])
+ -- smaller width is ignored
+ meths.put({'xxx', 'yyy'}, '\0221', false, true)
+ expect([[
+ xxxa line 1
+ yyybc line 2
+ line 3
+ ]])
+ eq({false, "Invalid type: 'bx'"},
+ meth_pcall(meths.put, {'xxx', 'yyy'}, 'bx', false, true))
+ eq({false, "Invalid type: 'b3x'"},
+ meth_pcall(meths.put, {'xxx', 'yyy'}, 'b3x', false, true))
+ end)
end)
describe('nvim_strwidth', function()
diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua
index 8d8c0e3647..07c91d43e1 100644
--- a/test/functional/terminal/tui_spec.lua
+++ b/test/functional/terminal/tui_spec.lua
@@ -352,15 +352,23 @@ describe('TUI', function()
]]}
-- Start pasting...
feed_data('\027[200~line 1\nline 2\n')
- expect_child_buf_lines({'foo',''})
- screen:expect{any='paste: Error executing lua'}
+ screen:expect{grid=[[
+ 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.
feed_data('line 3\nline 4\n')
feed_data('line 5\nline 6\n')
feed_data('line 7\nline 8\n')
-- Stop paste.
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.
feed_data('.')
screen:expect{grid=[[
@@ -388,7 +396,7 @@ describe('TUI', function()
vim.paste = _G.save_paste_fn
]], {})
feed_data('\027[200~line A\nline B\n\027[201~')
- feed_data('\n') -- <Enter>
+ feed_data('\n') -- <CR>
screen:expect{grid=[[
foo |
typed input...line A |
@@ -414,7 +422,15 @@ describe('TUI', function()
it("paste: 'nomodifiable' buffer", function()
child_session:request('nvim_command', 'set nomodifiable')
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>
child_session:request('nvim_command', 'set modifiable')
feed_data('\027[200~success 1\nsuccess 2\n\027[201~')