diff options
-rw-r--r-- | runtime/lua/vim/_editor.lua | 104 | ||||
-rw-r--r-- | src/nvim/eval/funcs.c | 18 | ||||
-rw-r--r-- | src/nvim/mouse.c | 16 | ||||
-rw-r--r-- | src/nvim/testdir/test_functions.vim | 69 | ||||
-rw-r--r-- | test/functional/api/vim_spec.lua | 427 | ||||
-rw-r--r-- | test/functional/terminal/tui_spec.lua | 14 |
6 files changed, 565 insertions, 83 deletions
diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua index a0c60a7dcf..d4db4850bd 100644 --- a/runtime/lua/vim/_editor.lua +++ b/runtime/lua/vim/_editor.lua @@ -128,7 +128,7 @@ local function inspect(object, options) -- luacheck: no unused end do - local tdots, tick, got_line1 = 0, 0, false + local tdots, tick, got_line1, undo_started, trailing_nl = 0, 0, false, false, false --- Paste handler, invoked by |nvim_paste()| when a conforming UI --- (such as the |TUI|) pastes text into the editor. @@ -156,44 +156,80 @@ do --- - 3: ends the paste (exactly once) ---@returns false if client should cancel the paste. function vim.paste(lines, phase) - local call = vim.api.nvim_call_function local now = vim.loop.now() - local mode = call('mode', {}):sub(1,1) - if phase < 2 then -- Reset flags. - tdots, tick, got_line1 = now, 0, false - elseif mode ~= 'c' then + local is_first_chunk = phase < 2 + local is_last_chunk = phase == -1 or phase == 3 + if is_first_chunk then -- Reset flags. + tdots, tick, got_line1, undo_started, trailing_nl = now, 0, false, false, false + end + if #lines == 0 then + lines = {''} + end + if #lines == 1 and lines[1] == '' and not is_last_chunk then + -- An empty chunk can cause some edge cases in streamed pasting, + -- so don't do anything unless it is the last chunk. + return true + end + -- Note: mode doesn't always start with "c" in cmdline mode, so use getcmdtype() instead. + if vim.fn.getcmdtype() ~= '' then -- cmdline-mode: paste only 1 line. + if not got_line1 then + got_line1 = (#lines > 1) + vim.api.nvim_set_option('paste', true) -- For nvim_input(). + -- Escape "<" and control characters + local line1 = lines[1]:gsub('<', '<lt>'):gsub('(%c)', '\022%1') + vim.api.nvim_input(line1) + vim.api.nvim_set_option('paste', false) + end + return true + end + local mode = vim.api.nvim_get_mode().mode + if undo_started then vim.api.nvim_command('undojoin') end - if mode == 'c' and not got_line1 then -- cmdline-mode: paste only 1 line. - got_line1 = (#lines > 1) - vim.api.nvim_set_option('paste', true) -- For nvim_input(). - local line1 = lines[1]:gsub('<', '<lt>'):gsub('[\r\n\012\027]', ' ') -- Scrub. - vim.api.nvim_input(line1) - vim.api.nvim_set_option('paste', false) - elseif mode ~= 'c' then - if phase < 2 and mode:find('^[vV\22sS\19]') then - vim.api.nvim_command([[exe "normal! \<Del>"]]) - vim.api.nvim_put(lines, 'c', false, true) - elseif phase < 2 and not mode:find('^[iRt]') then - vim.api.nvim_put(lines, 'c', true, true) - -- XXX: Normal-mode: workaround bad cursor-placement after first chunk. - vim.api.nvim_command('normal! a') - elseif phase < 2 and mode == 'R' then - local nchars = 0 - for _, line in ipairs(lines) do - nchars = nchars + line:len() + if mode:find('^i') or mode:find('^n?t') then -- Insert mode or Terminal buffer + vim.api.nvim_put(lines, 'c', false, true) + elseif phase < 2 and mode:find('^R') and not mode:find('^Rv') then -- Replace mode + -- TODO: implement Replace mode streamed pasting + -- TODO: support Virtual Replace mode + local nchars = 0 + for _, line in ipairs(lines) do + nchars = nchars + line:len() + end + local row, col = unpack(vim.api.nvim_win_get_cursor(0)) + local bufline = vim.api.nvim_buf_get_lines(0, row-1, row, true)[1] + local firstline = lines[1] + firstline = bufline:sub(1, col)..firstline + lines[1] = firstline + lines[#lines] = lines[#lines]..bufline:sub(col + nchars + 1, bufline:len()) + vim.api.nvim_buf_set_lines(0, row-1, row, false, lines) + elseif mode:find('^[nvV\22sS\19]') then -- Normal or Visual or Select mode + if mode:find('^n') then -- Normal mode + -- When there was a trailing new line in the previous chunk, + -- the cursor is on the first character of the next line, + -- so paste before the cursor instead of after it. + vim.api.nvim_put(lines, 'c', not trailing_nl, false) + else -- Visual or Select mode + vim.api.nvim_command([[exe "silent normal! \<Del>"]]) + local del_start = vim.fn.getpos("'[") + local cursor_pos = vim.fn.getpos('.') + if mode:find('^[VS]') then -- linewise + if cursor_pos[2] < del_start[2] then -- replacing lines at eof + -- create a new line + vim.api.nvim_put({''}, 'l', true, true) + end + vim.api.nvim_put(lines, 'c', false, false) + else + -- paste after cursor when replacing text at eol, otherwise paste before cursor + vim.api.nvim_put(lines, 'c', cursor_pos[3] < del_start[3], false) end - local row, col = unpack(vim.api.nvim_win_get_cursor(0)) - local bufline = vim.api.nvim_buf_get_lines(0, row-1, row, true)[1] - local firstline = lines[1] - firstline = bufline:sub(1, col)..firstline - lines[1] = firstline - lines[#lines] = lines[#lines]..bufline:sub(col + nchars + 1, bufline:len()) - vim.api.nvim_buf_set_lines(0, row-1, row, false, lines) - else - vim.api.nvim_put(lines, 'c', false, true) end + -- put cursor at the end of the text instead of one character after it + vim.fn.setpos('.', vim.fn.getpos("']")) + trailing_nl = lines[#lines] == '' + else -- Don't know what to do in other modes + return false end + undo_started = true if phase ~= -1 and (now - tdots >= 100) then local dots = ('.'):rep(tick % 4) tdots = now @@ -202,7 +238,7 @@ do -- message when there are zero dots. vim.api.nvim_command(('echo "%s"'):format(dots)) end - if phase == -1 or phase == 3 then + if is_last_chunk then vim.api.nvim_command('redraw'..(tick > 1 and '|echo ""' or '')) end return true -- Paste will not continue if not returning `true`. diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index b74f9759ac..738ed7f85e 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -3734,7 +3734,7 @@ static void f_getmousepos(typval_T *argvars, typval_T *rettv, FunPtr fptr) varnumber_T winid = 0; varnumber_T winrow = 0; varnumber_T wincol = 0; - linenr_T line = 0; + linenr_T lnum = 0; varnumber_T column = 0; tv_dict_alloc_ret(rettv); @@ -3753,18 +3753,8 @@ static void f_getmousepos(typval_T *argvars, typval_T *rettv, FunPtr fptr) winrow = row + 1 + wp->w_border_adj[0]; // Adjust by 1 for top border wincol = col + 1 + wp->w_border_adj[3]; // Adjust by 1 for left border if (row >= 0 && row < wp->w_height && col >= 0 && col < wp->w_width) { - char_u *p; - int count; - - mouse_comp_pos(wp, &row, &col, &line); - - // limit to text length plus one - p = ml_get_buf(wp->w_buffer, line, false); - count = (int)STRLEN(p); - if (col > count) { - col = count; - } - + (void)mouse_comp_pos(wp, &row, &col, &lnum); + col = vcol2col(wp, lnum, col); column = col + 1; } } @@ -3772,7 +3762,7 @@ static void f_getmousepos(typval_T *argvars, typval_T *rettv, FunPtr fptr) tv_dict_add_nr(d, S_LEN("winid"), winid); tv_dict_add_nr(d, S_LEN("winrow"), winrow); tv_dict_add_nr(d, S_LEN("wincol"), wincol); - tv_dict_add_nr(d, S_LEN("line"), (varnumber_T)line); + tv_dict_add_nr(d, S_LEN("line"), (varnumber_T)lnum); tv_dict_add_nr(d, S_LEN("column"), column); } diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c index 5d007fb173..6b27ce9d7b 100644 --- a/src/nvim/mouse.c +++ b/src/nvim/mouse.c @@ -535,6 +535,22 @@ static win_T *mouse_find_grid_win(int *gridp, int *rowp, int *colp) return NULL; } +/// Convert a virtual (screen) column to a character column. +/// The first column is one. +colnr_T vcol2col(win_T *const wp, const linenr_T lnum, const colnr_T vcol) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT +{ + // try to advance to the specified column + char_u *ptr = ml_get_buf(wp->w_buffer, lnum, false); + char_u *const line = ptr; + colnr_T count = 0; + while (count < vcol && *ptr != NUL) { + count += win_lbr_chartabsize(wp, line, ptr, count, NULL); + MB_PTR_ADV(ptr); + } + return (colnr_T)(ptr - line); +} + /// Set UI mouse depending on current mode and 'mouse'. /// /// Emits mouse_on/mouse_off UI event (unless 'mouse' is empty). diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim index 994d74601a..c2b5653a29 100644 --- a/src/nvim/testdir/test_functions.vim +++ b/src/nvim/testdir/test_functions.vim @@ -1762,6 +1762,75 @@ func Test_getcurpos_setpos() call assert_equal([0, 0, 0, 0, 0], getcurpos(1999)) endfunc +func Test_getmousepos() + enew! + call setline(1, "\t\t\t1234") + " call test_setmouse(1, 1) + call nvim_input_mouse('left', 'press', '', 0, 0, 0) + call getchar() " wait for and consume the mouse press + call assert_equal(#{ + \ screenrow: 1, + \ screencol: 1, + \ winid: win_getid(), + \ winrow: 1, + \ wincol: 1, + \ line: 1, + \ column: 1, + \ }, getmousepos()) + " call test_setmouse(1, 25) + call nvim_input_mouse('left', 'press', '', 0, 0, 24) + call getchar() " wait for and consume the mouse press + call assert_equal(#{ + \ screenrow: 1, + \ screencol: 25, + \ winid: win_getid(), + \ winrow: 1, + \ wincol: 25, + \ line: 1, + \ column: 4, + \ }, getmousepos()) + " call test_setmouse(1, 50) + call nvim_input_mouse('left', 'press', '', 0, 0, 49) + call getchar() " wait for and consume the mouse press + call assert_equal(#{ + \ screenrow: 1, + \ screencol: 50, + \ winid: win_getid(), + \ winrow: 1, + \ wincol: 50, + \ line: 1, + \ column: 8, + \ }, getmousepos()) + + " If the mouse is positioned past the last buffer line, "line" and "column" + " should act like it's positioned on the last buffer line. + " call test_setmouse(2, 25) + call nvim_input_mouse('left', 'press', '', 0, 1, 24) + call getchar() " wait for and consume the mouse press + call assert_equal(#{ + \ screenrow: 2, + \ screencol: 25, + \ winid: win_getid(), + \ winrow: 2, + \ wincol: 25, + \ line: 1, + \ column: 4, + \ }, getmousepos()) + " call test_setmouse(2, 50) + call nvim_input_mouse('left', 'press', '', 0, 1, 49) + call getchar() " wait for and consume the mouse press + call assert_equal(#{ + \ screenrow: 2, + \ screencol: 50, + \ winid: win_getid(), + \ winrow: 2, + \ wincol: 50, + \ line: 1, + \ column: 8, + \ }, getmousepos()) + bwipe! +endfunc + func HasDefault(msg = 'msg') return a:msg endfunc diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index e945a6c706..af6872760a 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -636,34 +636,374 @@ describe('API', function() eq('Invalid phase: 4', pcall_err(request, 'nvim_paste', 'foo', true, 4)) end) - it('stream: multiple chunks form one undo-block', function() - nvim('paste', '1/chunk 1 (start)\n', true, 1) - nvim('paste', '1/chunk 2 (end)\n', true, 3) - local expected1 = [[ - 1/chunk 1 (start) - 1/chunk 2 (end) - ]] - expect(expected1) - nvim('paste', '2/chunk 1 (start)\n', true, 1) - nvim('paste', '2/chunk 2\n', true, 2) - expect([[ - 1/chunk 1 (start) - 1/chunk 2 (end) - 2/chunk 1 (start) - 2/chunk 2 - ]]) - nvim('paste', '2/chunk 3\n', true, 2) - nvim('paste', '2/chunk 4 (end)\n', true, 3) - expect([[ - 1/chunk 1 (start) - 1/chunk 2 (end) - 2/chunk 1 (start) - 2/chunk 2 - 2/chunk 3 - 2/chunk 4 (end) - ]]) - feed('u') -- Undo. - expect(expected1) + local function run_streamed_paste_tests() + it('stream: multiple chunks form one undo-block', function() + nvim('paste', '1/chunk 1 (start)\n', true, 1) + nvim('paste', '1/chunk 2 (end)\n', true, 3) + local expected1 = [[ + 1/chunk 1 (start) + 1/chunk 2 (end) + ]] + expect(expected1) + nvim('paste', '2/chunk 1 (start)\n', true, 1) + nvim('paste', '2/chunk 2\n', true, 2) + expect([[ + 1/chunk 1 (start) + 1/chunk 2 (end) + 2/chunk 1 (start) + 2/chunk 2 + ]]) + nvim('paste', '2/chunk 3\n', true, 2) + nvim('paste', '2/chunk 4 (end)\n', true, 3) + expect([[ + 1/chunk 1 (start) + 1/chunk 2 (end) + 2/chunk 1 (start) + 2/chunk 2 + 2/chunk 3 + 2/chunk 4 (end) + ]]) + feed('u') -- Undo. + expect(expected1) + end) + it('stream: Insert mode', function() + -- If nvim_paste() calls :undojoin without making any changes, this makes it an error. + feed('afoo<Esc>u') + feed('i') + nvim('paste', 'aaaaaa', false, 1) + nvim('paste', 'bbbbbb', false, 2) + nvim('paste', 'cccccc', false, 2) + nvim('paste', 'dddddd', false, 3) + expect('aaaaaabbbbbbccccccdddddd') + feed('<Esc>u') + expect('') + end) + describe('stream: Normal mode', function() + describe('on empty line', function() + before_each(function() + -- If nvim_paste() calls :undojoin without making any changes, this makes it an error. + feed('afoo<Esc>u') + end) + after_each(function() + feed('u') + expect('') + end) + it('pasting one line', function() + nvim('paste', 'aaaaaa', false, 1) + nvim('paste', 'bbbbbb', false, 2) + nvim('paste', 'cccccc', false, 2) + nvim('paste', 'dddddd', false, 3) + expect('aaaaaabbbbbbccccccdddddd') + end) + it('pasting multiple lines', function() + nvim('paste', 'aaaaaa\n', false, 1) + nvim('paste', 'bbbbbb\n', false, 2) + nvim('paste', 'cccccc\n', false, 2) + nvim('paste', 'dddddd', false, 3) + expect([[ + aaaaaa + bbbbbb + cccccc + dddddd]]) + end) + end) + describe('not at the end of a line', function() + before_each(function() + feed('i||<Esc>') + -- If nvim_paste() calls :undojoin without making any changes, this makes it an error. + feed('afoo<Esc>u') + feed('0') + end) + after_each(function() + feed('u') + expect('||') + end) + it('pasting one line', function() + nvim('paste', 'aaaaaa', false, 1) + nvim('paste', 'bbbbbb', false, 2) + nvim('paste', 'cccccc', false, 2) + nvim('paste', 'dddddd', false, 3) + expect('|aaaaaabbbbbbccccccdddddd|') + end) + it('pasting multiple lines', function() + nvim('paste', 'aaaaaa\n', false, 1) + nvim('paste', 'bbbbbb\n', false, 2) + nvim('paste', 'cccccc\n', false, 2) + nvim('paste', 'dddddd', false, 3) + expect([[ + |aaaaaa + bbbbbb + cccccc + dddddd|]]) + end) + end) + describe('at the end of a line', function() + before_each(function() + feed('i||<Esc>') + -- If nvim_paste() calls :undojoin without making any changes, this makes it an error. + feed('afoo<Esc>u') + feed('2|') + end) + after_each(function() + feed('u') + expect('||') + end) + it('pasting one line', function() + nvim('paste', 'aaaaaa', false, 1) + nvim('paste', 'bbbbbb', false, 2) + nvim('paste', 'cccccc', false, 2) + nvim('paste', 'dddddd', false, 3) + expect('||aaaaaabbbbbbccccccdddddd') + end) + it('pasting multiple lines', function() + nvim('paste', 'aaaaaa\n', false, 1) + nvim('paste', 'bbbbbb\n', false, 2) + nvim('paste', 'cccccc\n', false, 2) + nvim('paste', 'dddddd', false, 3) + expect([[ + ||aaaaaa + bbbbbb + cccccc + dddddd]]) + end) + end) + end) + describe('stream: Visual mode', function() + describe('neither end at the end of a line', function() + before_each(function() + feed('i|xxx<CR>xxx|<Esc>') + -- If nvim_paste() calls :undojoin without making any changes, this makes it an error. + feed('afoo<Esc>u') + feed('3|vhk') + end) + after_each(function() + feed('u') + expect([[ + |xxx + xxx|]]) + end) + it('with non-empty chunks', function() + nvim('paste', 'aaaaaa', false, 1) + nvim('paste', 'bbbbbb', false, 2) + nvim('paste', 'cccccc', false, 2) + nvim('paste', 'dddddd', false, 3) + expect('|aaaaaabbbbbbccccccdddddd|') + end) + it('with empty first chunk', function() + nvim('paste', '', false, 1) + nvim('paste', 'bbbbbb', false, 2) + nvim('paste', 'cccccc', false, 2) + nvim('paste', 'dddddd', false, 3) + expect('|bbbbbbccccccdddddd|') + end) + it('with all chunks empty', function() + nvim('paste', '', false, 1) + nvim('paste', '', false, 2) + nvim('paste', '', false, 2) + nvim('paste', '', false, 3) + expect('||') + end) + end) + describe('cursor at the end of a line', function() + before_each(function() + feed('i||xxx<CR>xxx<Esc>') + -- If nvim_paste() calls :undojoin without making any changes, this makes it an error. + feed('afoo<Esc>u') + feed('3|vko') + end) + after_each(function() + feed('u') + expect([[ + ||xxx + xxx]]) + end) + it('with non-empty chunks', function() + nvim('paste', 'aaaaaa', false, 1) + nvim('paste', 'bbbbbb', false, 2) + nvim('paste', 'cccccc', false, 2) + nvim('paste', 'dddddd', false, 3) + expect('||aaaaaabbbbbbccccccdddddd') + end) + it('with empty first chunk', function() + nvim('paste', '', false, 1) + nvim('paste', 'bbbbbb', false, 2) + nvim('paste', 'cccccc', false, 2) + nvim('paste', 'dddddd', false, 3) + expect('||bbbbbbccccccdddddd') + end) + end) + describe('other end at the end of a line', function() + before_each(function() + feed('i||xxx<CR>xxx<Esc>') + -- If nvim_paste() calls :undojoin without making any changes, this makes it an error. + feed('afoo<Esc>u') + feed('3|vk') + end) + after_each(function() + feed('u') + expect([[ + ||xxx + xxx]]) + end) + it('with non-empty chunks', function() + nvim('paste', 'aaaaaa', false, 1) + nvim('paste', 'bbbbbb', false, 2) + nvim('paste', 'cccccc', false, 2) + nvim('paste', 'dddddd', false, 3) + expect('||aaaaaabbbbbbccccccdddddd') + end) + it('with empty first chunk', function() + nvim('paste', '', false, 1) + nvim('paste', 'bbbbbb', false, 2) + nvim('paste', 'cccccc', false, 2) + nvim('paste', 'dddddd', false, 3) + expect('||bbbbbbccccccdddddd') + end) + end) + end) + describe('stream: linewise Visual mode', function() + before_each(function() + feed('i123456789<CR>987654321<CR>123456789<Esc>') + -- If nvim_paste() calls :undojoin without making any changes, this makes it an error. + feed('afoo<Esc>u') + end) + after_each(function() + feed('u') + expect([[ + 123456789 + 987654321 + 123456789]]) + end) + describe('selecting the start of a file', function() + before_each(function() + feed('ggV') + end) + it('pasting text without final new line', function() + nvim('paste', 'aaaaaa\n', false, 1) + nvim('paste', 'bbbbbb\n', false, 2) + nvim('paste', 'cccccc\n', false, 2) + nvim('paste', 'dddddd', false, 3) + expect([[ + aaaaaa + bbbbbb + cccccc + dddddd987654321 + 123456789]]) + end) + it('pasting text with final new line', function() + nvim('paste', 'aaaaaa\n', false, 1) + nvim('paste', 'bbbbbb\n', false, 2) + nvim('paste', 'cccccc\n', false, 2) + nvim('paste', 'dddddd\n', false, 3) + expect([[ + aaaaaa + bbbbbb + cccccc + dddddd + 987654321 + 123456789]]) + end) + end) + describe('selecting the middle of a file', function() + before_each(function() + feed('2ggV') + end) + it('pasting text without final new line', function() + nvim('paste', 'aaaaaa\n', false, 1) + nvim('paste', 'bbbbbb\n', false, 2) + nvim('paste', 'cccccc\n', false, 2) + nvim('paste', 'dddddd', false, 3) + expect([[ + 123456789 + aaaaaa + bbbbbb + cccccc + dddddd123456789]]) + end) + it('pasting text with final new line', function() + nvim('paste', 'aaaaaa\n', false, 1) + nvim('paste', 'bbbbbb\n', false, 2) + nvim('paste', 'cccccc\n', false, 2) + nvim('paste', 'dddddd\n', false, 3) + expect([[ + 123456789 + aaaaaa + bbbbbb + cccccc + dddddd + 123456789]]) + end) + end) + describe('selecting the end of a file', function() + before_each(function() + feed('3ggV') + end) + it('pasting text without final new line', function() + nvim('paste', 'aaaaaa\n', false, 1) + nvim('paste', 'bbbbbb\n', false, 2) + nvim('paste', 'cccccc\n', false, 2) + nvim('paste', 'dddddd', false, 3) + expect([[ + 123456789 + 987654321 + aaaaaa + bbbbbb + cccccc + dddddd]]) + end) + it('pasting text with final new line', function() + nvim('paste', 'aaaaaa\n', false, 1) + nvim('paste', 'bbbbbb\n', false, 2) + nvim('paste', 'cccccc\n', false, 2) + nvim('paste', 'dddddd\n', false, 3) + expect([[ + 123456789 + 987654321 + aaaaaa + bbbbbb + cccccc + dddddd + ]]) + end) + end) + describe('selecting the whole file', function() + before_each(function() + feed('ggVG') + end) + it('pasting text without final new line', function() + nvim('paste', 'aaaaaa\n', false, 1) + nvim('paste', 'bbbbbb\n', false, 2) + nvim('paste', 'cccccc\n', false, 2) + nvim('paste', 'dddddd', false, 3) + expect([[ + aaaaaa + bbbbbb + cccccc + dddddd]]) + end) + it('pasting text with final new line', function() + nvim('paste', 'aaaaaa\n', false, 1) + nvim('paste', 'bbbbbb\n', false, 2) + nvim('paste', 'cccccc\n', false, 2) + nvim('paste', 'dddddd\n', false, 3) + expect([[ + aaaaaa + bbbbbb + cccccc + dddddd + ]]) + end) + end) + end) + end + describe('without virtualedit,', function() + run_streamed_paste_tests() + end) + describe('with virtualedit=onemore,', function() + before_each(function() + command('set virtualedit=onemore') + end) + run_streamed_paste_tests() end) it('non-streaming', function() -- With final "\n". @@ -738,6 +1078,37 @@ describe('API', function() eeffgghh iijjkkll]]) end) + it('when searching in Visual mode', function() + feed('v/') + nvim('paste', 'aabbccdd', true, -1) + eq('aabbccdd', funcs.getcmdline()) + expect('') + end) + it('pasting with empty last chunk in Cmdline mode', function() + local screen = Screen.new(20, 4) + screen:attach() + feed(':') + nvim('paste', 'Foo', true, 1) + nvim('paste', '', true, 3) + screen:expect([[ + | + ~ | + ~ | + :Foo^ | + ]]) + end) + it('pasting text with control characters in Cmdline mode', function() + local screen = Screen.new(20, 4) + screen:attach() + feed(':') + nvim('paste', 'normal! \023\022\006\027', true, -1) + screen:expect([[ + | + ~ | + ~ | + :normal! ^W^V^F^[^ | + ]]) + end) it('crlf=false does not break lines at CR, CRLF', function() nvim('paste', 'line 1\r\n\r\rline 2\nline 3\rline 4\r', false, -1) expect('line 1\r\n\r\rline 2\nline 3\rline 4\r') diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index faf44fa01d..c37cde06ab 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -323,7 +323,7 @@ describe('TUI', function() feed_data('just paste it™') feed_data('\027[201~') screen:expect{grid=[[ - thisjust paste it™{1:3} is here | + thisjust paste it{1:™}3 is here | | {4:~ }| {4:~ }| @@ -379,7 +379,7 @@ describe('TUI', function() end) it('paste: normal-mode (+CRLF #10872)', function() - feed_data(':set ruler') + feed_data(':set ruler | echo') wait_for_mode('c') feed_data('\n') wait_for_mode('n') @@ -423,13 +423,13 @@ describe('TUI', function() expect_child_buf_lines(expected_crlf) feed_data('u') expect_child_buf_lines({''}) + feed_data(':echo') + wait_for_mode('c') + feed_data('\n') + wait_for_mode('n') -- CRLF input feed_data('\027[200~'..table.concat(expected_lf,'\r\n')..'\027[201~') - screen:expect{ - grid=expected_grid1:gsub( - ':set ruler *', - '3 fewer lines; before #1 0 seconds ago '), - attr_ids=expected_attr} + screen:expect{grid=expected_grid1, attr_ids=expected_attr} expect_child_buf_lines(expected_crlf) end) |