aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThiago de Arruda <tpadilha84@gmail.com>2015-10-01 15:37:20 -0300
committerThiago de Arruda <tpadilha84@gmail.com>2015-10-01 15:37:20 -0300
commit536c0ba27e79929eb30850d8e11f2ed026930ab3 (patch)
tree40873cf933b5ba5cff44d1ea07db2b3f2663020e
parentafe8a32be01d006d6c25f69b4aa1b6e92464ab63 (diff)
parent5d185c77726dfff20b87d97897d2bb237e95d95a (diff)
downloadrneovim-536c0ba27e79929eb30850d8e11f2ed026930ab3.tar.gz
rneovim-536c0ba27e79929eb30850d8e11f2ed026930ab3.tar.bz2
rneovim-536c0ba27e79929eb30850d8e11f2ed026930ab3.zip
Merge PR #3360 'More fixes for 0.1'
-rw-r--r--src/nvim/ex_cmds.c5
-rw-r--r--src/nvim/ex_docmd.c2
-rw-r--r--src/nvim/ex_getln.c2
-rw-r--r--src/nvim/getchar.c29
-rw-r--r--src/nvim/keymap.c1
-rw-r--r--src/nvim/keymap.h3
-rw-r--r--src/nvim/os/input.c9
-rw-r--r--src/nvim/rbuffer.c18
-rw-r--r--src/nvim/rbuffer.h2
-rw-r--r--src/nvim/tui/input.c106
-rw-r--r--src/nvim/tui/input.h4
-rw-r--r--test/functional/helpers.lua1
-rw-r--r--test/functional/shell/bang_filter_spec.lua49
-rw-r--r--test/functional/terminal/helpers.lua46
-rw-r--r--test/functional/terminal/tui_spec.lua106
-rw-r--r--test/functional/ui/input_spec.lua70
-rw-r--r--test/functional/ui/screen.lua3
17 files changed, 374 insertions, 82 deletions
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 6cb379f0b4..81abf2fa63 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -1246,8 +1246,9 @@ do_shell (
// 1" command to the terminal.
ui_cursor_goto(msg_row, msg_col);
(void)call_shell(cmd, flags, NULL);
- did_check_timestamps = FALSE;
- need_check_timestamps = TRUE;
+ msg_didout = true;
+ did_check_timestamps = false;
+ need_check_timestamps = true;
// put the message cursor at the end of the screen, avoids wait_return()
// to overwrite the text that the external command showed
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 3c09a3a2f8..f7162896ff 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -7624,7 +7624,7 @@ void update_topline_cursor(void)
*/
static void ex_normal(exarg_T *eap)
{
- if (curbuf->terminal) {
+ if (curbuf->terminal && State & TERM_FOCUS) {
EMSG("Can't re-enter normal mode from terminal mode");
return;
}
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index a9d371d0eb..9739090d7c 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -302,7 +302,7 @@ getcmdline (
input_enable_events();
do {
c = safe_vgetc();
- } while (c == K_IGNORE);
+ } while (c == K_IGNORE || c == K_PASTE);
input_disable_events();
if (c == K_EVENT) {
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 604425b3ba..990d0fb8e2 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -153,6 +153,7 @@ static char_u typebuf_init[TYPELEN_INIT]; /* initial typebuf.tb_buf */
static char_u noremapbuf_init[TYPELEN_INIT]; /* initial typebuf.tb_noremap */
static int last_recorded_len = 0; /* number of last recorded chars */
+static const uint8_t ui_toggle[] = { K_SPECIAL, KS_EXTRA, KE_PASTE, 0 };
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "getchar.c.generated.h"
@@ -1873,14 +1874,15 @@ static int vgetorpeek(int advance)
}
}
- /* Check for match with 'pastetoggle' */
- if (*p_pt != NUL && mp == NULL && (State & (INSERT|NORMAL))) {
- for (mlen = 0; mlen < typebuf.tb_len && p_pt[mlen];
- ++mlen)
- if (p_pt[mlen] != typebuf.tb_buf[typebuf.tb_off
- + mlen])
- break;
- if (p_pt[mlen] == NUL) { /* match */
+ // Check for a key that can toggle the 'paste' option
+ if (mp == NULL && (State & (INSERT|NORMAL))) {
+ bool match = typebuf_match_len(ui_toggle, &mlen);
+ if (!match && mlen != typebuf.tb_len && *p_pt != NUL) {
+ // didn't match ui_toggle_key and didn't try the whole typebuf,
+ // check the 'pastetoggle'
+ match = typebuf_match_len(p_pt, &mlen);
+ }
+ if (match) {
/* write chars to script file(s) */
if (mlen > typebuf.tb_maplen)
gotchars(typebuf.tb_buf + typebuf.tb_off
@@ -4238,3 +4240,14 @@ static char_u * translate_mapping (
ga_append(&ga, NUL);
return (char_u *)(ga.ga_data);
}
+
+static bool typebuf_match_len(const uint8_t *str, int *mlen)
+{
+ int i;
+ for (i = 0; i < typebuf.tb_len && str[i]; i++) {
+ if (str[i] != typebuf.tb_buf[typebuf.tb_off + i])
+ break;
+ }
+ *mlen = i;
+ return str[i] == NUL; // matched the whole string
+}
diff --git a/src/nvim/keymap.c b/src/nvim/keymap.c
index 0c5c24184e..bf4f5e8c4d 100644
--- a/src/nvim/keymap.c
+++ b/src/nvim/keymap.c
@@ -284,6 +284,7 @@ static struct key_name_entry {
{K_SNR, (char_u *)"SNR"},
{K_PLUG, (char_u *)"Plug"},
{K_CURSORHOLD, (char_u *)"CursorHold"},
+ {K_PASTE, (char_u *)"Paste"},
{0, NULL}
};
diff --git a/src/nvim/keymap.h b/src/nvim/keymap.h
index 38b96b1b8c..119bff943a 100644
--- a/src/nvim/keymap.h
+++ b/src/nvim/keymap.h
@@ -247,6 +247,8 @@ enum key_extra {
, KE_FOCUSGAINED /* focus gained */
, KE_FOCUSLOST /* focus lost */
, KE_EVENT // event
+ , KE_PASTE // special key to toggle the 'paste' option.
+ // sent only by UIs
};
/*
@@ -437,6 +439,7 @@ enum key_extra {
#define K_CURSORHOLD TERMCAP2KEY(KS_EXTRA, KE_CURSORHOLD)
#define K_EVENT TERMCAP2KEY(KS_EXTRA, KE_EVENT)
+#define K_PASTE TERMCAP2KEY(KS_EXTRA, KE_PASTE)
/* Bits for modifier mask */
/* 0x01 cannot be used, because the modifier must be 0x02 or higher */
diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c
index 09f162f79d..e2cff2f9c0 100644
--- a/src/nvim/os/input.c
+++ b/src/nvim/os/input.c
@@ -171,10 +171,17 @@ size_t input_enqueue(String keys)
}
if (*ptr == '<') {
- // Invalid key sequence, skip until the next '>' or until *end
+ char *old_ptr = ptr;
+ // Invalid or incomplete key sequence, skip until the next '>' or until
+ // *end
do {
ptr++;
} while (ptr < end && *ptr != '>');
+ if (*ptr != '>') {
+ // Incomplete key sequence, return without consuming.
+ ptr = old_ptr;
+ break;
+ }
ptr++;
continue;
}
diff --git a/src/nvim/rbuffer.c b/src/nvim/rbuffer.c
index 0a04ba1954..b3805a3a28 100644
--- a/src/nvim/rbuffer.c
+++ b/src/nvim/rbuffer.c
@@ -24,11 +24,13 @@ RBuffer *rbuffer_new(size_t capacity)
rv->size = 0;
rv->write_ptr = rv->read_ptr = rv->start_ptr;
rv->end_ptr = rv->start_ptr + capacity;
+ rv->temp = NULL;
return rv;
}
void rbuffer_free(RBuffer *buf)
{
+ xfree(buf->temp);
xfree(buf);
}
@@ -69,12 +71,20 @@ char *rbuffer_write_ptr(RBuffer *buf, size_t *write_count) FUNC_ATTR_NONNULL_ALL
return buf->write_ptr;
}
-// Set read and write pointer for an empty RBuffer to the beginning of the
-// buffer.
+// Reset an RBuffer so read_ptr is at the beginning of the memory. If
+// necessary, this moves existing data by allocating temporary memory.
void rbuffer_reset(RBuffer *buf) FUNC_ATTR_NONNULL_ALL
{
- if (buf->size == 0) {
- buf->write_ptr = buf->read_ptr = buf->start_ptr;
+ size_t temp_size;
+ if ((temp_size = rbuffer_size(buf))) {
+ if (buf->temp == NULL) {
+ buf->temp = xmalloc(rbuffer_capacity(buf));
+ }
+ rbuffer_read(buf, buf->temp, buf->size);
+ }
+ buf->read_ptr = buf->write_ptr = buf->start_ptr;
+ if (temp_size) {
+ rbuffer_write(buf, buf->temp, temp_size);
}
}
diff --git a/src/nvim/rbuffer.h b/src/nvim/rbuffer.h
index b205db0b5a..35fb16508e 100644
--- a/src/nvim/rbuffer.h
+++ b/src/nvim/rbuffer.h
@@ -72,6 +72,8 @@ struct rbuffer {
rbuffer_callback full_cb, nonfull_cb;
void *data;
size_t size;
+ // helper memory used to by rbuffer_reset if required
+ char *temp;
char *end_ptr, *read_ptr, *write_ptr;
char start_ptr[];
};
diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c
index 6c362540d0..32b3f1583c 100644
--- a/src/nvim/tui/input.c
+++ b/src/nvim/tui/input.c
@@ -9,7 +9,8 @@
#include "nvim/os/input.h"
#include "nvim/event/rstream.h"
-#define PASTETOGGLE_KEY "<f37>"
+#define PASTETOGGLE_KEY "<Paste>"
+#define KEY_BUFFER_SIZE 0xfff
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "tui/input.c.generated.h"
@@ -20,6 +21,9 @@ void term_input_init(TermInput *input, Loop *loop)
input->loop = loop;
input->paste_enabled = false;
input->in_fd = 0;
+ input->key_buffer = rbuffer_new(KEY_BUFFER_SIZE);
+ uv_mutex_init(&input->key_buffer_mutex);
+ uv_cond_init(&input->key_buffer_cond);
const char *term = os_getenv("TERM");
if (!term) {
@@ -34,15 +38,13 @@ void term_input_init(TermInput *input, Loop *loop)
rstream_init_fd(loop, &input->read_stream, input->in_fd, 0xfff, input);
// initialize a timer handle for handling ESC with libtermkey
time_watcher_init(loop, &input->timer_handle, input);
- // Set the pastetoggle option to a special key that will be sent when
- // \e[20{0,1}~/ are received
- Error err = ERROR_INIT;
- vim_set_option(cstr_as_string("pastetoggle"),
- STRING_OBJ(cstr_as_string(PASTETOGGLE_KEY)), &err);
}
void term_input_destroy(TermInput *input)
{
+ rbuffer_free(input->key_buffer);
+ uv_mutex_destroy(&input->key_buffer_mutex);
+ uv_cond_destroy(&input->key_buffer_cond);
time_watcher_close(&input->timer_handle, NULL);
stream_close(&input->read_stream, NULL);
termkey_destroy(input->tk);
@@ -59,25 +61,56 @@ void term_input_stop(TermInput *input)
time_watcher_stop(&input->timer_handle);
}
-static void input_enqueue_event(void **argv)
+static void input_done_event(void **argv)
{
- char *buf = argv[0];
- input_enqueue(cstr_as_string(buf));
- xfree(buf);
+ input_done();
}
-static void input_done_event(void **argv)
+static void wait_input_enqueue(void **argv)
{
- input_done();
+ TermInput *input = argv[0];
+ RBUFFER_UNTIL_EMPTY(input->key_buffer, buf, len) {
+ size_t consumed = input_enqueue((String){.data = buf, .size = len});
+ if (consumed) {
+ rbuffer_consumed(input->key_buffer, consumed);
+ }
+ rbuffer_reset(input->key_buffer);
+ if (consumed < len) {
+ break;
+ }
+ }
+ uv_mutex_lock(&input->key_buffer_mutex);
+ input->waiting = false;
+ uv_cond_signal(&input->key_buffer_cond);
+ uv_mutex_unlock(&input->key_buffer_mutex);
}
-static void enqueue_input(char *buf, size_t size)
+static void flush_input(TermInput *input, bool wait_until_empty)
{
- loop_schedule(&loop, event_create(1, input_enqueue_event, 1,
- xstrndup(buf, size)));
+ size_t drain_boundary = wait_until_empty ? 0 : 0xff;
+ do {
+ uv_mutex_lock(&input->key_buffer_mutex);
+ loop_schedule(&loop, event_create(1, wait_input_enqueue, 1, input));
+ input->waiting = true;
+ while (input->waiting) {
+ uv_cond_wait(&input->key_buffer_cond, &input->key_buffer_mutex);
+ }
+ uv_mutex_unlock(&input->key_buffer_mutex);
+ } while (rbuffer_size(input->key_buffer) > drain_boundary);
}
-static void forward_simple_utf8(TermKeyKey *key)
+static void enqueue_input(TermInput *input, char *buf, size_t size)
+{
+ if (rbuffer_size(input->key_buffer) >
+ rbuffer_capacity(input->key_buffer) - 0xff) {
+ // don't ever let the buffer get too full or we risk putting incomplete keys
+ // into it
+ flush_input(input, false);
+ }
+ rbuffer_write(input->key_buffer, buf, size);
+}
+
+static void forward_simple_utf8(TermInput *input, TermKeyKey *key)
{
size_t len = 0;
char buf[64];
@@ -92,11 +125,10 @@ static void forward_simple_utf8(TermKeyKey *key)
ptr++;
}
- buf[len] = 0;
- enqueue_input(buf, len);
+ enqueue_input(input, buf, len);
}
-static void forward_modified_utf8(TermKey *tk, TermKeyKey *key)
+static void forward_modified_utf8(TermInput *input, TermKeyKey *key)
{
size_t len;
char buf[64];
@@ -105,19 +137,19 @@ static void forward_modified_utf8(TermKey *tk, TermKeyKey *key)
&& key->code.sym == TERMKEY_SYM_ESCAPE) {
len = (size_t)snprintf(buf, sizeof(buf), "<Esc>");
} else {
- len = termkey_strfkey(tk, buf, sizeof(buf), key, TERMKEY_FORMAT_VIM);
+ len = termkey_strfkey(input->tk, buf, sizeof(buf), key, TERMKEY_FORMAT_VIM);
}
- enqueue_input(buf, len);
+ enqueue_input(input, buf, len);
}
-static void forward_mouse_event(TermKey *tk, TermKeyKey *key)
+static void forward_mouse_event(TermInput *input, TermKeyKey *key)
{
char buf[64];
size_t len = 0;
int button, row, col;
TermKeyMouseEvent ev;
- termkey_interpret_mouse(tk, key, &ev, &button, &row, &col);
+ termkey_interpret_mouse(input->tk, key, &ev, &button, &row, &col);
if (ev != TERMKEY_MOUSE_PRESS && ev != TERMKEY_MOUSE_DRAG) {
return;
@@ -159,7 +191,7 @@ static void forward_mouse_event(TermKey *tk, TermKeyKey *key)
}
len += (size_t)snprintf(buf + len, sizeof(buf) - len, "><%d,%d>", col, row);
- enqueue_input(buf, len);
+ enqueue_input(input, buf, len);
}
static TermKeyResult tk_getkey(TermKey *tk, TermKeyKey *key, bool force)
@@ -189,17 +221,17 @@ static void tk_getkeys(TermInput *input, bool force)
while ((result = tk_getkey(input->tk, &key, force)) == TERMKEY_RES_KEY) {
if (key.type == TERMKEY_TYPE_UNICODE && !key.modifiers) {
- forward_simple_utf8(&key);
+ forward_simple_utf8(input, &key);
} else if (key.type == TERMKEY_TYPE_UNICODE ||
key.type == TERMKEY_TYPE_FUNCTION ||
key.type == TERMKEY_TYPE_KEYSYM) {
- forward_modified_utf8(input->tk, &key);
+ forward_modified_utf8(input, &key);
} else if (key.type == TERMKEY_TYPE_MOUSE) {
- forward_mouse_event(input->tk, &key);
+ forward_mouse_event(input, &key);
}
}
- if (result != TERMKEY_RES_AGAIN) {
+ if (result != TERMKEY_RES_AGAIN || input->paste_enabled) {
return;
}
@@ -230,21 +262,7 @@ static bool handle_bracketed_paste(TermInput *input)
if (input->paste_enabled == enable) {
return true;
}
- if (enable) {
- // Get the current mode
- int state = get_real_state();
- if (state & NORMAL) {
- // Enter insert mode
- enqueue_input("i", 1);
- } else if (state & VISUAL) {
- // Remove the selected text and enter insert mode
- enqueue_input("c", 1);
- } else if (!(state & INSERT)) {
- // Don't mess with the paste option
- return true;
- }
- }
- enqueue_input(PASTETOGGLE_KEY, sizeof(PASTETOGGLE_KEY) - 1);
+ enqueue_input(input, PASTETOGGLE_KEY, sizeof(PASTETOGGLE_KEY) - 1);
input->paste_enabled = enable;
return true;
}
@@ -326,7 +344,7 @@ static void read_cb(Stream *stream, RBuffer *buf, size_t c, void *data,
}
}
} while (rbuffer_size(input->read_stream.buffer));
-
+ flush_input(input, true);
// Make sure the next input escape sequence fits into the ring buffer
// without wrap around, otherwise it could be misinterpreted.
rbuffer_reset(input->read_stream.buffer);
diff --git a/src/nvim/tui/input.h b/src/nvim/tui/input.h
index 033f53b4e2..d7ee2b9e52 100644
--- a/src/nvim/tui/input.h
+++ b/src/nvim/tui/input.h
@@ -10,10 +10,14 @@
typedef struct term_input {
int in_fd;
bool paste_enabled;
+ bool waiting;
TermKey *tk;
TimeWatcher timer_handle;
Loop *loop;
Stream read_stream;
+ RBuffer *key_buffer;
+ uv_mutex_t key_buffer_mutex;
+ uv_cond_t key_buffer_cond;
} TermInput;
#ifdef INCLUDE_GENERATED_DECLARATIONS
diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua
index 9cd1fd7ab3..80cb1e5ce3 100644
--- a/test/functional/helpers.lua
+++ b/test/functional/helpers.lua
@@ -372,5 +372,6 @@ return {
set_session = set_session,
write_file = write_file,
rmdir = rmdir,
+ mkdir = lfs.mkdir,
exc_exec = exc_exec,
}
diff --git a/test/functional/shell/bang_filter_spec.lua b/test/functional/shell/bang_filter_spec.lua
new file mode 100644
index 0000000000..964dbd1029
--- /dev/null
+++ b/test/functional/shell/bang_filter_spec.lua
@@ -0,0 +1,49 @@
+-- Specs for bang/filter commands
+
+local helpers = require('test.functional.helpers')
+local feed, execute, clear = helpers.feed, helpers.execute, helpers.clear
+local mkdir, write_file, rmdir = helpers.mkdir, helpers.write_file, helpers.rmdir
+
+local Screen = require('test.functional.ui.screen')
+
+
+describe('issues', function()
+ local screen
+
+ before_each(function()
+ clear()
+ rmdir('bang_filter_spec')
+ mkdir('bang_filter_spec')
+ write_file('bang_filter_spec/f1', 'f1')
+ write_file('bang_filter_spec/f2', 'f2')
+ write_file('bang_filter_spec/f3', 'f3')
+ screen = Screen.new()
+ screen:attach()
+ end)
+
+ after_each(function()
+ rmdir('bang_filter_spec')
+ end)
+
+ it('#3269 Last line of shell output is not truncated', function()
+ execute([[nnoremap <silent>\l :!ls bang_filter_spec<cr>]])
+ feed([[\l]])
+ screen:expect([[
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ :!ls bang_filter_spec |
+ |
+ f1 |
+ f2 |
+ f3 |
+ Press ENTER or type command to continue^ |
+ ]])
+ end)
+
+end)
diff --git a/test/functional/terminal/helpers.lua b/test/functional/terminal/helpers.lua
index e488495139..ae13aab277 100644
--- a/test/functional/terminal/helpers.lua
+++ b/test/functional/terminal/helpers.lua
@@ -1,7 +1,7 @@
local helpers = require('test.functional.helpers')
local Screen = require('test.functional.ui.screen')
local nvim_dir = helpers.nvim_dir
-local execute, nvim = helpers.execute, helpers.nvim
+local execute, nvim, wait = helpers.execute, helpers.nvim, helpers.wait
local function feed_data(data)
nvim('set_var', 'term_data', data)
@@ -31,13 +31,15 @@ local function clear_attrs() feed_termcode('[0;10m') end
local function enable_mouse() feed_termcode('[?1002h') end
local function disable_mouse() feed_termcode('[?1002l') end
+local default_command = '["'..nvim_dir..'/tty-test'..'"]'
-local function screen_setup(extra_height)
+local function screen_setup(extra_height, command)
nvim('command', 'highlight TermCursor cterm=reverse')
nvim('command', 'highlight TermCursorNC ctermbg=11')
nvim('set_var', 'terminal_scrollback_buffer_size', 10)
if not extra_height then extra_height = 0 end
+ if not command then command = default_command end
local screen = Screen.new(50, 7 + extra_height)
screen:set_default_attr_ids({
[1] = {reverse = true}, -- focused cursor
@@ -56,25 +58,29 @@ local function screen_setup(extra_height)
-- tty-test puts the terminal into raw mode and echoes all input. tests are
-- done by feeding it with terminfo codes to control the display and
-- verifying output with screen:expect.
- execute('enew | call termopen(["'..nvim_dir..'/tty-test"]) | startinsert')
- -- wait for "tty ready" to be printed before each test or the terminal may
- -- still be in canonical mode(will echo characters for example)
- --
- local empty_line = ' '
- local expected = {
- 'tty ready ',
- '{1: } ',
- empty_line,
- empty_line,
- empty_line,
- empty_line,
- }
- for i = 1, extra_height do
- table.insert(expected, empty_line)
- end
+ execute('enew | call termopen('..command..') | startinsert')
+ if command == default_command then
+ -- wait for "tty ready" to be printed before each test or the terminal may
+ -- still be in canonical mode(will echo characters for example)
+ --
+ local empty_line = ' '
+ local expected = {
+ 'tty ready ',
+ '{1: } ',
+ empty_line,
+ empty_line,
+ empty_line,
+ empty_line,
+ }
+ for i = 1, extra_height do
+ table.insert(expected, empty_line)
+ end
- table.insert(expected, '-- TERMINAL -- ')
- screen:expect(table.concat(expected, '\n'))
+ table.insert(expected, '-- TERMINAL -- ')
+ screen:expect(table.concat(expected, '\n'))
+ else
+ wait()
+ end
return screen
end
diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua
new file mode 100644
index 0000000000..d604703fee
--- /dev/null
+++ b/test/functional/terminal/tui_spec.lua
@@ -0,0 +1,106 @@
+-- Some sanity checks for the TUI using the builtin terminal emulator
+-- as a simple way to send keys and assert screen state.
+local Screen = require('test.functional.ui.screen')
+local helpers = require('test.functional.helpers')
+local thelpers = require('test.functional.terminal.helpers')
+local feed = thelpers.feed_data
+local execute = helpers.execute
+
+describe('tui', function()
+ local screen
+
+ before_each(function()
+ helpers.clear()
+ screen = thelpers.screen_setup(0, '["'..helpers.nvim_prog..'", "-u", "NONE", "--cmd", "set noswapfile"]')
+ screen.timeout = 30000 -- pasting can be really slow in the TUI
+ screen:expect([[
+ {1: } |
+ ~ |
+ ~ |
+ ~ |
+ [No Name] |
+ |
+ -- TERMINAL -- |
+ ]])
+ end)
+
+ after_each(function()
+ screen:detach()
+ end)
+
+ it('accepts basic utf-8 input', function()
+ feed('iabc\ntest1\ntest2')
+ screen:expect([[
+ abc |
+ test1 |
+ test2{1: } |
+ ~ |
+ [No Name] [+] |
+ -- INSERT -- |
+ -- TERMINAL -- |
+ ]])
+ feed('\x1b')
+ screen:expect([[
+ abc |
+ test1 |
+ test{1:2} |
+ ~ |
+ [No Name] [+] |
+ |
+ -- TERMINAL -- |
+ ]])
+ end)
+
+ it('automatically sends <Paste> for bracketed paste sequences', function()
+ feed('i\x1b[200~')
+ screen:expect([[
+ {1: } |
+ ~ |
+ ~ |
+ ~ |
+ [No Name] |
+ -- INSERT (paste) -- |
+ -- TERMINAL -- |
+ ]])
+ feed('pasted from terminal')
+ screen:expect([[
+ pasted from terminal{1: } |
+ ~ |
+ ~ |
+ ~ |
+ [No Name] [+] |
+ -- INSERT (paste) -- |
+ -- TERMINAL -- |
+ ]])
+ feed('\x1b[201~')
+ screen:expect([[
+ pasted from terminal{1: } |
+ ~ |
+ ~ |
+ ~ |
+ [No Name] [+] |
+ -- INSERT -- |
+ -- TERMINAL -- |
+ ]])
+ end)
+
+ it('can handle arbitrarily long bursts of input', function()
+ execute('set ruler')
+ local t = {}
+ for i = 1, 3000 do
+ t[i] = 'item ' .. tostring(i)
+ end
+ feed('i\x1b[200~')
+ feed(table.concat(t, '\n'))
+ feed('\x1b[201~')
+ screen:expect([[
+ item 2997 |
+ item 2998 |
+ item 2999 |
+ item 3000{1: } |
+ [No Name] [+] 3000,10 Bot|
+ -- INSERT -- |
+ -- TERMINAL -- |
+ ]])
+ end)
+end)
diff --git a/test/functional/ui/input_spec.lua b/test/functional/ui/input_spec.lua
index 81af908045..a7c8e02def 100644
--- a/test/functional/ui/input_spec.lua
+++ b/test/functional/ui/input_spec.lua
@@ -2,6 +2,7 @@ local helpers = require('test.functional.helpers')
local clear, execute, nvim = helpers.clear, helpers.execute, helpers.nvim
local feed, next_message, eq = helpers.feed, helpers.next_message, helpers.eq
local expect = helpers.expect
+local Screen = require('test.functional.ui.screen')
describe('mappings', function()
local cid
@@ -40,7 +41,76 @@ describe('mappings', function()
end)
end)
+describe('feeding large chunks of input with <Paste>', function()
+ local screen
+ before_each(function()
+ clear()
+ screen = Screen.new()
+ screen:attach()
+ execute('set ruler')
+ end)
+
+ it('ok', function()
+ local t = {}
+ for i = 1, 20000 do
+ t[i] = 'item ' .. tostring(i)
+ end
+ feed('i<Paste>')
+ screen:expect([[
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ -- INSERT (paste) -- |
+ ]])
+ feed(table.concat(t, '<Enter>'))
+ screen:expect([[
+ item 19988 |
+ item 19989 |
+ item 19990 |
+ item 19991 |
+ item 19992 |
+ item 19993 |
+ item 19994 |
+ item 19995 |
+ item 19996 |
+ item 19997 |
+ item 19998 |
+ item 19999 |
+ item 20000^ |
+ -- INSERT (paste) -- |
+ ]])
+ feed('<Paste>')
+ screen:expect([[
+ item 19988 |
+ item 19989 |
+ item 19990 |
+ item 19991 |
+ item 19992 |
+ item 19993 |
+ item 19994 |
+ item 19995 |
+ item 19996 |
+ item 19997 |
+ item 19998 |
+ item 19999 |
+ item 20000^ |
+ -- INSERT -- 20000,11 Bot |
+ ]])
+ end)
+end)
+
describe('input utf sequences that contain CSI/K_SPECIAL', function()
+ before_each(clear)
it('ok', function()
feed('i…<esc>')
expect('…')
diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua
index 08c4bfae0b..1be83d745e 100644
--- a/test/functional/ui/screen.lua
+++ b/test/functional/ui/screen.lua
@@ -163,6 +163,7 @@ function Screen.new(width, height)
height = 14
end
local self = setmetatable({
+ timeout = default_screen_timeout,
title = '',
icon = '',
bell = false,
@@ -248,7 +249,7 @@ function Screen:wait(check, timeout)
return true
end
- run(nil, notification_cb, nil, timeout or default_screen_timeout)
+ run(nil, notification_cb, nil, timeout or self.timeout)
if not checked then
err = check()
end