aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/CMakeLists.txt6
-rw-r--r--test/functional/api/buffer_spec.lua704
-rw-r--r--test/functional/api/extmark_spec.lua9
-rw-r--r--test/functional/api/highlight_spec.lua9
-rw-r--r--test/functional/api/server_notifications_spec.lua3
-rw-r--r--test/functional/helpers.lua5
-rw-r--r--test/functional/legacy/memory_usage_spec.lua8
-rw-r--r--test/functional/lua/buffer_updates_spec.lua56
-rw-r--r--test/functional/lua/fs_spec.lua12
-rw-r--r--test/functional/plugin/lsp/utils_spec.lua96
-rw-r--r--test/functional/plugin/lsp_spec.lua2
-rw-r--r--test/functional/terminal/edit_spec.lua1
-rw-r--r--test/functional/ui/decorations_spec.lua319
-rw-r--r--test/functional/ui/float_spec.lua193
-rw-r--r--test/functional/ui/screen.lua2
-rw-r--r--test/functional/ui/statuscolumn_spec.lua18
-rw-r--r--test/functional/vimscript/system_spec.lua4
-rw-r--r--test/old/testdir/check.vim8
-rw-r--r--test/old/testdir/test_autocmd.vim4
-rw-r--r--test/old/testdir/test_edit.vim4
-rw-r--r--test/old/testdir/test_filetype.vim1
-rw-r--r--test/old/testdir/test_functions.vim5
-rw-r--r--test/old/testdir/test_listdict.vim2
-rw-r--r--test/old/testdir/test_normal.vim7
-rw-r--r--test/old/testdir/test_substitute.vim14
-rw-r--r--test/old/testdir/test_vimscript.vim6
-rw-r--r--test/old/testdir/test_virtualedit.vim2
-rw-r--r--test/unit/helpers.lua11
-rw-r--r--test/unit/marktree_spec.lua233
29 files changed, 1628 insertions, 116 deletions
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 77fe7b3b82..e9be79edc0 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -27,7 +27,7 @@ if(LUA_HAS_FFI)
-P ${PROJECT_SOURCE_DIR}/cmake/RunTests.cmake
DEPENDS ${UNITTEST_PREREQS}
USES_TERMINAL)
- add_dependencies(unittest test_deps)
+ add_dependencies(unittest lua-dev-deps)
else()
message(WARNING "disabling unit tests: no Luajit FFI in ${LUA_PRG}")
endif()
@@ -66,5 +66,5 @@ add_custom_target(benchmark
DEPENDS ${BENCHMARK_PREREQS}
USES_TERMINAL)
-add_dependencies(functionaltest test_deps)
-add_dependencies(benchmark test_deps)
+add_dependencies(functionaltest lua-dev-deps)
+add_dependencies(benchmark lua-dev-deps)
diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua
index 292e5a2d56..9833ebee4c 100644
--- a/test/functional/api/buffer_spec.lua
+++ b/test/functional/api/buffer_spec.lua
@@ -848,6 +848,710 @@ describe('api/buf', function()
eq({1, 4}, meths.win_get_cursor(win2))
end)
+ describe('when text is being added right at cursor position #22526', function()
+ it('updates the cursor position in NORMAL mode', function()
+ insert([[
+ abcd]])
+
+ -- position the cursor on 'c'
+ curwin('set_cursor', {1, 2})
+ -- add 'xxx' before 'c'
+ set_text(0, 2, 0, 2, {'xxx'})
+ eq({'abxxxcd'}, get_lines(0, -1, true))
+ -- cursor should be on 'c'
+ eq({1, 5}, curwin('get_cursor'))
+ end)
+
+ it('updates the cursor position only in non-current window when in INSERT mode', function()
+ insert([[
+ abcd]])
+
+ -- position the cursor on 'c'
+ curwin('set_cursor', {1, 2})
+ -- open vertical split
+ feed('<c-w>v')
+ -- get into INSERT mode to treat cursor
+ -- as being after 'b', not on 'c'
+ feed('i')
+ -- add 'xxx' between 'b' and 'c'
+ set_text(0, 2, 0, 2, {'xxx'})
+ eq({'abxxxcd'}, get_lines(0, -1, true))
+ -- in the current window cursor should stay after 'b'
+ eq({1, 2}, curwin('get_cursor'))
+ -- quit INSERT mode
+ feed('<esc>')
+ -- close current window
+ feed('<c-w>c')
+ -- in another window cursor should be on 'c'
+ eq({1, 5}, curwin('get_cursor'))
+ end)
+ end)
+
+ describe('when text is being deleted right at cursor position', function()
+ it('leaves cursor at the same position in NORMAL mode', function()
+ insert([[
+ abcd]])
+
+ -- position the cursor on 'b'
+ curwin('set_cursor', {1, 1})
+ -- delete 'b'
+ set_text(0, 1, 0, 2, {})
+ eq({'acd'}, get_lines(0, -1, true))
+ -- cursor is now on 'c'
+ eq({1, 1}, curwin('get_cursor'))
+ end)
+
+ it('leaves cursor at the same position in INSERT mode in current and non-current window', function()
+ insert([[
+ abcd]])
+
+ -- position the cursor on 'b'
+ curwin('set_cursor', {1, 1})
+ -- open vertical split
+ feed('<c-w>v')
+ -- get into INSERT mode to treat cursor
+ -- as being after 'a', not on 'b'
+ feed('i')
+ -- delete 'b'
+ set_text(0, 1, 0, 2, {})
+ eq({'acd'}, get_lines(0, -1, true))
+ -- cursor in the current window should stay after 'a'
+ eq({1, 1}, curwin('get_cursor'))
+ -- quit INSERT mode
+ feed('<esc>')
+ -- close current window
+ feed('<c-w>c')
+ -- cursor in non-current window should stay on 'c'
+ eq({1, 1}, curwin('get_cursor'))
+ end)
+ end)
+
+ describe('when cursor is inside replaced row range', function()
+ it('keeps cursor at the same position if cursor is at start_row, but before start_col', function()
+ insert([[
+ This should be first
+ then there is a line we do not want
+ and finally the last one]])
+
+ -- position the cursor on ' ' before 'first'
+ curwin('set_cursor', {1, 14})
+
+ set_text(0, 15, 2, 11, {
+ 'the line we do not want',
+ 'but hopefully',
+ })
+
+ eq({
+ 'This should be the line we do not want',
+ 'but hopefully the last one',
+ }, get_lines(0, -1, true))
+ -- cursor should stay at the same position
+ eq({1, 14}, curwin('get_cursor'))
+ end)
+
+ it('keeps cursor at the same position if cursor is at start_row and column is still valid', function()
+ insert([[
+ This should be first
+ then there is a line we do not want
+ and finally the last one]])
+
+ -- position the cursor on 'f' in 'first'
+ curwin('set_cursor', {1, 15})
+
+ set_text(0, 15, 2, 11, {
+ 'the line we do not want',
+ 'but hopefully',
+ })
+
+ eq({
+ 'This should be the line we do not want',
+ 'but hopefully the last one',
+ }, get_lines(0, -1, true))
+ -- cursor should stay at the same position
+ eq({1, 15}, curwin('get_cursor'))
+ end)
+
+ it('adjusts cursor column to keep it valid if start_row got smaller', function()
+ insert([[
+ This should be first
+ then there is a line we do not want
+ and finally the last one]])
+
+ -- position the cursor on 't' in 'first'
+ curwin('set_cursor', {1, 19})
+
+ local cursor = exec_lua([[
+ vim.api.nvim_buf_set_text(0, 0, 15, 2, 24, {'last'})
+ return vim.api.nvim_win_get_cursor(0)
+ ]])
+
+ eq({ 'This should be last' }, get_lines(0, -1, true))
+ -- cursor should end up on 't' in 'last'
+ eq({1, 18}, curwin('get_cursor'))
+ -- immediate call to nvim_win_get_cursor should have returned the same position
+ eq({1, 18}, cursor)
+ end)
+
+ it('adjusts cursor column to keep it valid if start_row got smaller in INSERT mode', function()
+ insert([[
+ This should be first
+ then there is a line we do not want
+ and finally the last one]])
+
+ -- position the cursor on 't' in 'first'
+ curwin('set_cursor', {1, 19})
+ -- enter INSERT mode to treat cursor as being after 't'
+ feed('a')
+
+ local cursor = exec_lua([[
+ vim.api.nvim_buf_set_text(0, 0, 15, 2, 24, {'last'})
+ return vim.api.nvim_win_get_cursor(0)
+ ]])
+
+ eq({ 'This should be last' }, get_lines(0, -1, true))
+ -- cursor should end up after 't' in 'last'
+ eq({1, 19}, curwin('get_cursor'))
+ -- immediate call to nvim_win_get_cursor should have returned the same position
+ eq({1, 19}, cursor)
+ end)
+
+ it('adjusts cursor column to keep it valid in a row after start_row if it got smaller', function()
+ insert([[
+ This should be first
+ then there is a line we do not want
+ and finally the last one]])
+
+ -- position the cursor on 'w' in 'want'
+ curwin('set_cursor', {2, 31})
+
+ local cursor = exec_lua([[
+ vim.api.nvim_buf_set_text(0, 0, 15, 2, 11, {
+ '1',
+ 'then 2',
+ 'and then',
+ })
+ return vim.api.nvim_win_get_cursor(0)
+ ]])
+
+ eq({
+ 'This should be 1',
+ 'then 2',
+ 'and then the last one',
+ }, get_lines(0, -1, true))
+ -- cursor column should end up at the end of a row
+ eq({2, 5}, curwin('get_cursor'))
+ -- immediate call to nvim_win_get_cursor should have returned the same position
+ eq({2, 5}, cursor)
+ end)
+
+ it('adjusts cursor column to keep it valid in a row after start_row if it got smaller in INSERT mode', function()
+ insert([[
+ This should be first
+ then there is a line we do not want
+ and finally the last one]])
+
+ -- position the cursor on 'w' in 'want'
+ curwin('set_cursor', {2, 31})
+ -- enter INSERT mode
+ feed('a')
+
+ local cursor = exec_lua([[
+ vim.api.nvim_buf_set_text(0, 0, 15, 2, 11, {
+ '1',
+ 'then 2',
+ 'and then',
+ })
+ return vim.api.nvim_win_get_cursor(0)
+ ]])
+
+ eq({
+ 'This should be 1',
+ 'then 2',
+ 'and then the last one',
+ }, get_lines(0, -1, true))
+ -- cursor column should end up at the end of a row
+ eq({2, 6}, curwin('get_cursor'))
+ -- immediate call to nvim_win_get_cursor should have returned the same position
+ eq({2, 6}, cursor)
+ end)
+
+ it('adjusts cursor line and column to keep it inside replacement range', function()
+ insert([[
+ This should be first
+ then there is a line we do not want
+ and finally the last one]])
+
+ -- position the cursor on 'n' in 'finally'
+ curwin('set_cursor', {3, 6})
+
+ local cursor = exec_lua([[
+ vim.api.nvim_buf_set_text(0, 0, 15, 2, 11, {
+ 'the line we do not want',
+ 'but hopefully',
+ })
+ return vim.api.nvim_win_get_cursor(0)
+ ]])
+
+ eq({
+ 'This should be the line we do not want',
+ 'but hopefully the last one',
+ }, get_lines(0, -1, true))
+ -- cursor should end up on 'y' in 'hopefully'
+ -- to stay in the range, because it got smaller
+ eq({2, 12}, curwin('get_cursor'))
+ -- immediate call to nvim_win_get_cursor should have returned the same position
+ eq({2, 12}, cursor)
+ end)
+
+ it('adjusts cursor line and column if replacement is empty', function()
+ insert([[
+ This should be first
+ then there is a line we do not want
+ and finally the last one]])
+
+ -- position the cursor on 'r' in 'there'
+ curwin('set_cursor', {2, 8})
+
+ local cursor = exec_lua([[
+ vim.api.nvim_buf_set_text(0, 0, 15, 2, 12, {})
+ return vim.api.nvim_win_get_cursor(0)
+ ]])
+
+ eq({ 'This should be the last one' }, get_lines(0, -1, true))
+ -- cursor should end up on the next column after deleted range
+ eq({1, 15}, curwin('get_cursor'))
+ -- immediate call to nvim_win_get_cursor should have returned the same position
+ eq({1, 15}, cursor)
+ end)
+
+ it('adjusts cursor line and column if replacement is empty and start_col == 0', function()
+ insert([[
+ This should be first
+ then there is a line we do not want
+ and finally the last one]])
+
+ -- position the cursor on 'r' in 'there'
+ curwin('set_cursor', {2, 8})
+
+ local cursor = exec_lua([[
+ vim.api.nvim_buf_set_text(0, 0, 0, 2, 4, {})
+ return vim.api.nvim_win_get_cursor(0)
+ ]])
+
+ eq({ 'finally the last one' }, get_lines(0, -1, true))
+ -- cursor should end up in column 0
+ eq({1, 0}, curwin('get_cursor'))
+ -- immediate call to nvim_win_get_cursor should have returned the same position
+ eq({1, 0}, cursor)
+ end)
+
+ it('adjusts cursor column if replacement ends at cursor row, after cursor column', function()
+ insert([[
+ This should be first
+ then there is a line we do not want
+ and finally the last one]])
+
+ -- position the cursor on 'y' in 'finally'
+ curwin('set_cursor', {3, 10})
+ set_text(0, 15, 2, 11, { '1', 'this 2', 'and then' })
+
+ eq({
+ 'This should be 1',
+ 'this 2',
+ 'and then the last one',
+ }, get_lines(0, -1, true))
+ -- cursor should end up on 'n' in 'then'
+ eq({3, 7}, curwin('get_cursor'))
+ end)
+
+ it('adjusts cursor column if replacement ends at cursor row, at cursor column in INSERT mode', function()
+ insert([[
+ This should be first
+ then there is a line we do not want
+ and finally the last one]])
+
+ -- position the cursor on 'y' at 'finally'
+ curwin('set_cursor', {3, 10})
+ -- enter INSERT mode to treat cursor as being between 'l' and 'y'
+ feed('i')
+ set_text(0, 15, 2, 11, { '1', 'this 2', 'and then' })
+
+ eq({
+ 'This should be 1',
+ 'this 2',
+ 'and then the last one',
+ }, get_lines(0, -1, true))
+ -- cursor should end up after 'n' in 'then'
+ eq({3, 8}, curwin('get_cursor'))
+ end)
+
+ it('adjusts cursor column if replacement is inside of a single line', function()
+ insert([[
+ This should be first
+ then there is a line we do not want
+ and finally the last one]])
+
+ -- position the cursor on 'y' in 'finally'
+ curwin('set_cursor', {3, 10})
+ set_text(2, 4, 2, 11, { 'then' })
+
+ eq({
+ 'This should be first',
+ 'then there is a line we do not want',
+ 'and then the last one',
+ }, get_lines(0, -1, true))
+ -- cursor should end up on 'n' in 'then'
+ eq({3, 7}, curwin('get_cursor'))
+ end)
+
+ it('does not move cursor column after end of a line', function()
+ insert([[
+ This should be the only line here
+ !!!]])
+
+ -- position cursor on the last '1'
+ curwin('set_cursor', {2, 2})
+
+ local cursor = exec_lua([[
+ vim.api.nvim_buf_set_text(0, 0, 33, 1, 3, {})
+ return vim.api.nvim_win_get_cursor(0)
+ ]])
+
+ eq({ 'This should be the only line here' }, get_lines(0, -1, true))
+ -- cursor should end up on '!'
+ eq({1, 32}, curwin('get_cursor'))
+ -- immediate call to nvim_win_get_cursor should have returned the same position
+ eq({1, 32}, cursor)
+ end)
+
+ it('does not move cursor column before start of a line', function()
+ insert('\n!!!')
+
+ -- position cursor on the last '1'
+ curwin('set_cursor', {2, 2})
+
+ local cursor = exec_lua([[
+ vim.api.nvim_buf_set_text(0, 0, 0, 1, 3, {})
+ return vim.api.nvim_win_get_cursor(0)
+ ]])
+
+ eq({ '' }, get_lines(0, -1, true))
+ -- cursor should end up on '!'
+ eq({1, 0}, curwin('get_cursor'))
+ -- immediate call to nvim_win_get_cursor should have returned the same position
+ eq({1, 0}, cursor)
+ end)
+
+ describe('with virtualedit', function()
+ it('adjusts cursor line and column to keep it inside replacement range if cursor is not after eol', function()
+ insert([[
+ This should be first
+ then there is a line we do not want
+ and finally the last one]])
+
+ -- position cursor on 't' in 'want'
+ curwin('set_cursor', {2, 34})
+ -- turn on virtualedit
+ command('set virtualedit=all')
+
+ local cursor = exec_lua([[
+ vim.api.nvim_buf_set_text(0, 0, 15, 2, 11, {
+ 'the line we do not want',
+ 'but hopefully',
+ })
+ return vim.api.nvim_win_get_cursor(0)
+ ]])
+
+ eq({
+ 'This should be the line we do not want',
+ 'but hopefully the last one',
+ }, get_lines(0, -1, true))
+ -- cursor should end up on 'y' in 'hopefully'
+ -- to stay in the range
+ eq({2, 12}, curwin('get_cursor'))
+ -- immediate call to nvim_win_get_cursor should have returned the same position
+ eq({2, 12}, cursor)
+ -- coladd should be 0
+ eq(0, exec_lua([[
+ return vim.fn.winsaveview().coladd
+ ]]))
+ end)
+
+ it('does not change cursor screen column when cursor is after eol and row got shorter', function()
+ insert([[
+ This should be first
+ then there is a line we do not want
+ and finally the last one]])
+
+ -- position cursor on 't' in 'want'
+ curwin('set_cursor', {2, 34})
+ -- turn on virtualedit
+ command('set virtualedit=all')
+ -- move cursor after eol
+ exec_lua([[
+ vim.fn.winrestview({ coladd = 5 })
+ ]])
+
+ local cursor = exec_lua([[
+ vim.api.nvim_buf_set_text(0, 0, 15, 2, 11, {
+ 'the line we do not want',
+ 'but hopefully',
+ })
+ return vim.api.nvim_win_get_cursor(0)
+ ]])
+
+ eq({
+ 'This should be the line we do not want',
+ 'but hopefully the last one',
+ }, get_lines(0, -1, true))
+ -- cursor should end up at eol of a new row
+ eq({2, 26}, curwin('get_cursor'))
+ -- immediate call to nvim_win_get_cursor should have returned the same position
+ eq({2, 26}, cursor)
+ -- coladd should be increased so that cursor stays in the same screen column
+ eq(13, exec_lua([[
+ return vim.fn.winsaveview().coladd
+ ]]))
+ end)
+
+ it('does not change cursor screen column when cursor is after eol and row got longer', function()
+ insert([[
+ This should be first
+ then there is a line we do not want
+ and finally the last one]])
+
+ -- position cursor on 't' in 'first'
+ curwin('set_cursor', {1, 19})
+ -- turn on virtualedit
+ command('set virtualedit=all')
+ -- move cursor after eol
+ exec_lua([[
+ vim.fn.winrestview({ coladd = 21 })
+ ]])
+
+ local cursor = exec_lua([[
+ vim.api.nvim_buf_set_text(0, 0, 15, 2, 11, {
+ 'the line we do not want',
+ 'but hopefully',
+ })
+ return vim.api.nvim_win_get_cursor(0)
+ ]])
+
+ eq({
+ 'This should be the line we do not want',
+ 'but hopefully the last one',
+ }, get_lines(0, -1, true))
+ -- cursor should end up at eol of a new row
+ eq({1, 38}, curwin('get_cursor'))
+ -- immediate call to nvim_win_get_cursor should have returned the same position
+ eq({1, 38}, cursor)
+ -- coladd should be increased so that cursor stays in the same screen column
+ eq(2, exec_lua([[
+ return vim.fn.winsaveview().coladd
+ ]]))
+ end)
+
+ it('does not change cursor screen column when cursor is after eol and row extended past cursor column', function()
+ insert([[
+ This should be first
+ then there is a line we do not want
+ and finally the last one]])
+
+ -- position cursor on 't' in 'first'
+ curwin('set_cursor', {1, 19})
+ -- turn on virtualedit
+ command('set virtualedit=all')
+ -- move cursor after eol just a bit
+ exec_lua([[
+ vim.fn.winrestview({ coladd = 3 })
+ ]])
+
+ local cursor = exec_lua([[
+ vim.api.nvim_buf_set_text(0, 0, 15, 2, 11, {
+ 'the line we do not want',
+ 'but hopefully',
+ })
+ return vim.api.nvim_win_get_cursor(0)
+ ]])
+
+ eq({
+ 'This should be the line we do not want',
+ 'but hopefully the last one',
+ }, get_lines(0, -1, true))
+ -- cursor should stay at the same screen column
+ eq({1, 22}, curwin('get_cursor'))
+ -- immediate call to nvim_win_get_cursor should have returned the same position
+ eq({1, 22}, cursor)
+ -- coladd should become 0
+ eq(0, exec_lua([[
+ return vim.fn.winsaveview().coladd
+ ]]))
+ end)
+
+ it('does not change cursor screen column when cursor is after eol and row range decreased', function()
+ insert([[
+ This should be first
+ then there is a line we do not want
+ and one more
+ and finally the last one]])
+
+ -- position cursor on 'e' in 'more'
+ curwin('set_cursor', {3, 11})
+ -- turn on virtualedit
+ command('set virtualedit=all')
+ -- move cursor after eol
+ exec_lua([[
+ vim.fn.winrestview({ coladd = 28 })
+ ]])
+
+ local cursor = exec_lua([[
+ vim.api.nvim_buf_set_text(0, 0, 15, 3, 11, {
+ 'the line we do not want',
+ 'but hopefully',
+ })
+ return vim.api.nvim_win_get_cursor(0)
+ ]])
+
+ eq({
+ 'This should be the line we do not want',
+ 'but hopefully the last one',
+ }, get_lines(0, -1, true))
+ -- cursor should end up at eol of a new row
+ eq({2, 26}, curwin('get_cursor'))
+ -- immediate call to nvim_win_get_cursor should have returned the same position
+ eq({2, 26}, cursor)
+ -- coladd should be increased so that cursor stays in the same screen column
+ eq(13, exec_lua([[
+ return vim.fn.winsaveview().coladd
+ ]]))
+ end)
+ end)
+ end)
+
+ describe('when cursor is at end_row and after end_col', function()
+ it('adjusts cursor column when only a newline is added or deleted', function()
+ insert([[
+ first line
+ second
+ line]])
+
+ -- position the cursor on 'i'
+ curwin('set_cursor', {3, 2})
+ set_text(1, 6, 2, 0, {})
+ eq({'first line', 'second line'}, get_lines(0, -1, true))
+ -- cursor should stay on 'i'
+ eq({2, 8}, curwin('get_cursor'))
+
+ -- add a newline back
+ set_text(1, 6, 1, 6, {'', ''})
+ eq({'first line', 'second', ' line'}, get_lines(0, -1, true))
+ -- cursor should return back to the original position
+ eq({3, 2}, curwin('get_cursor'))
+ end)
+
+ it('adjusts cursor column if the range is not bound to either start or end of a line', function()
+ insert([[
+ This should be first
+ then there is a line we do not want
+ and finally the last one]])
+
+ -- position the cursor on 'h' in 'the'
+ curwin('set_cursor', {3, 13})
+ set_text(0, 14, 2, 11, {})
+ eq({'This should be the last one'}, get_lines(0, -1, true))
+ -- cursor should stay on 'h'
+ eq({1, 16}, curwin('get_cursor'))
+ -- add deleted lines back
+ set_text(0, 14, 0, 14, {
+ ' first',
+ 'then there is a line we do not want',
+ 'and finally',
+ })
+ eq({
+ 'This should be first',
+ 'then there is a line we do not want',
+ 'and finally the last one',
+ }, get_lines(0, -1, true))
+ -- cursor should return back to the original position
+ eq({3, 13}, curwin('get_cursor'))
+ end)
+
+ it('adjusts cursor column if replacing lines in range, not just deleting and adding', function()
+ insert([[
+ This should be first
+ then there is a line we do not want
+ and finally the last one]])
+
+ -- position the cursor on 's' in 'last'
+ curwin('set_cursor', {3, 18})
+ set_text(0, 15, 2, 11, {
+ 'the line we do not want',
+ 'but hopefully',
+ })
+
+ eq({
+ 'This should be the line we do not want',
+ 'but hopefully the last one',
+ }, get_lines(0, -1, true))
+ -- cursor should stay on 's'
+ eq({2, 20}, curwin('get_cursor'))
+
+ set_text(0, 15, 1, 13, {
+ 'first',
+ 'then there is a line we do not want',
+ 'and finally',
+ })
+
+ eq({
+ 'This should be first',
+ 'then there is a line we do not want',
+ 'and finally the last one',
+ }, get_lines(0, -1, true))
+ -- cursor should return back to the original position
+ eq({3, 18}, curwin('get_cursor'))
+ end)
+
+ it('does not move cursor column after end of a line', function()
+ insert([[
+ This should be the only line here
+ ]])
+
+ -- position cursor at the empty line
+ curwin('set_cursor', {2, 0})
+
+ local cursor = exec_lua([[
+ vim.api.nvim_buf_set_text(0, 0, 33, 1, 0, {'!'})
+ return vim.api.nvim_win_get_cursor(0)
+ ]])
+
+ eq({ 'This should be the only line here!' }, get_lines(0, -1, true))
+ -- cursor should end up on '!'
+ eq({1, 33}, curwin('get_cursor'))
+ -- immediate call to nvim_win_get_cursor should have returned the same position
+ eq({1, 33}, cursor)
+ end)
+
+ it('does not move cursor column before start of a line', function()
+ insert('\n')
+
+ eq({ '', '' }, get_lines(0, -1, true))
+
+ -- position cursor on the last '1'
+ curwin('set_cursor', {2, 2})
+
+ local cursor = exec_lua([[
+ vim.api.nvim_buf_set_text(0, 0, 0, 1, 0, {''})
+ return vim.api.nvim_win_get_cursor(0)
+ ]])
+
+ eq({ '' }, get_lines(0, -1, true))
+ -- cursor should end up on '!'
+ eq({1, 0}, curwin('get_cursor'))
+ -- immediate call to nvim_win_get_cursor should have returned the same position
+ eq({1, 0}, cursor)
+ end)
+ end)
+
it('can handle NULs', function()
set_text(0, 0, 0, 0, {'ab\0cd'})
eq('ab\0cd', curbuf_depr('get_line', 0))
diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua
index 6d8e3d8e0a..a917432dab 100644
--- a/test/functional/api/extmark_spec.lua
+++ b/test/functional/api/extmark_spec.lua
@@ -753,7 +753,14 @@ describe('API/extmarks', function()
})
end)
- -- TODO(bfredl): add more tests!
+ it('can get overlapping extmarks', function()
+ set_extmark(ns, 1, 0, 0, {end_row = 5, end_col=0})
+ set_extmark(ns, 2, 2, 5, {end_row = 2, end_col=30})
+ set_extmark(ns, 3, 0, 5, {end_row = 2, end_col=10})
+ set_extmark(ns, 4, 0, 0, {end_row = 1, end_col=0})
+ eq({{ 2, 2, 5 }}, get_extmarks(ns, {2, 0}, {2, -1}, { overlap=false }))
+ eq({{ 1, 0, 0 }, { 3, 0, 5}, {2, 2, 5}}, get_extmarks(ns, {2, 0}, {2, -1}, { overlap=true }))
+ end)
end)
it('replace works', function()
diff --git a/test/functional/api/highlight_spec.lua b/test/functional/api/highlight_spec.lua
index 5fa2235018..492fd73223 100644
--- a/test/functional/api/highlight_spec.lua
+++ b/test/functional/api/highlight_spec.lua
@@ -439,6 +439,15 @@ describe('API: get highlight', function()
eq('Highlight id out of bounds', pcall_err(meths.get_hl, 0, { name = 'Test set hl' }))
end)
+ it('nvim_get_hl with create flag', function()
+ eq({}, nvim("get_hl", 0, {name = 'Foo', create = false}))
+ eq(0, funcs.hlexists('Foo'))
+ meths.get_hl(0, {name = 'Bar', create = true})
+ eq(1, funcs.hlexists('Bar'))
+ meths.get_hl(0, {name = 'FooBar'})
+ eq(1, funcs.hlexists('FooBar'))
+ end)
+
it('can get all highlights in current namespace', function()
local ns = get_ns()
meths.set_hl(ns, 'Test_hl', { bg = '#B4BEFE' })
diff --git a/test/functional/api/server_notifications_spec.lua b/test/functional/api/server_notifications_spec.lua
index 53642858b2..bc43f6564d 100644
--- a/test/functional/api/server_notifications_spec.lua
+++ b/test/functional/api/server_notifications_spec.lua
@@ -6,9 +6,7 @@ local eq, clear, eval, command, nvim, next_msg =
local meths = helpers.meths
local exec_lua = helpers.exec_lua
local retry = helpers.retry
-local is_ci = helpers.is_ci
local assert_alive = helpers.assert_alive
-local skip = helpers.skip
local testlog = 'Xtest-server-notify-log'
@@ -90,7 +88,6 @@ describe('notify', function()
end)
it('cancels stale events on channel close', function()
- skip(is_ci(), 'hangs on CI #14083 #15251')
local catchan = eval("jobstart(['cat'], {'rpc': v:true})")
local catpath = eval('exepath("cat")')
eq({id=catchan, argv={catpath}, stream='job', mode='rpc', client = {}}, exec_lua ([[
diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua
index b98cf97e7e..6f5397a089 100644
--- a/test/functional/helpers.lua
+++ b/test/functional/helpers.lua
@@ -857,6 +857,11 @@ function module.testprg(name)
return ('%s/%s%s'):format(module.nvim_dir, name, ext)
end
+function module.is_asan()
+ local version = module.eval('execute("verbose version")')
+ return version:match('-fsanitize=[a-z,]*address')
+end
+
-- Returns a valid, platform-independent Nvim listen address.
-- Useful for communicating with child instances.
function module.new_pipename()
diff --git a/test/functional/legacy/memory_usage_spec.lua b/test/functional/legacy/memory_usage_spec.lua
index bf37315914..5f722e5190 100644
--- a/test/functional/legacy/memory_usage_spec.lua
+++ b/test/functional/legacy/memory_usage_spec.lua
@@ -11,14 +11,10 @@ local load_adjust = helpers.load_adjust
local write_file = helpers.write_file
local is_os = helpers.is_os
local is_ci = helpers.is_ci
-
-local function isasan()
- local version = eval('execute("verbose version")')
- return version:match('-fsanitize=[a-z,]*address')
-end
+local is_asan = helpers.is_asan
clear()
-if isasan() then
+if is_asan() then
pending('ASAN build is difficult to estimate memory usage', function() end)
return
elseif is_os('win') then
diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua
index c19891a794..51e4548edb 100644
--- a/test/functional/lua/buffer_updates_spec.lua
+++ b/test/functional/lua/buffer_updates_spec.lua
@@ -826,53 +826,53 @@ describe('lua: nvim_buf_attach on_bytes', function()
feed("<esc>u")
check_events {
- { "test1", "bytes", 1, 8, 0, 0, 0, 0, 1, 1, 0, 4, 4 },
- { "test1", "bytes", 1, 8, 0, 0, 0, 0, 4, 4, 0, 0, 0 }
+ { "test1", "bytes", 1, 9, 0, 0, 0, 0, 1, 1, 0, 4, 4 },
+ { "test1", "bytes", 1, 9, 0, 0, 0, 0, 4, 4, 0, 0, 0 }
}
-- in REPLACE mode
feed("R<tab><tab>")
check_events {
- { "test1", "bytes", 1, 9, 0, 0, 0, 0, 1, 1, 0, 1, 1 },
- { "test1", "bytes", 1, 10, 0, 1, 1, 0, 0, 0, 0, 1, 1 },
- { "test1", "bytes", 1, 11, 0, 2, 2, 0, 1, 1, 0, 1, 1 },
- { "test1", "bytes", 1, 12, 0, 3, 3, 0, 0, 0, 0, 1, 1 },
- { "test1", "bytes", 1, 13, 0, 0, 0, 0, 4, 4, 0, 1, 1 },
+ { "test1", "bytes", 1, 10, 0, 0, 0, 0, 1, 1, 0, 1, 1 },
+ { "test1", "bytes", 1, 11, 0, 1, 1, 0, 0, 0, 0, 1, 1 },
+ { "test1", "bytes", 1, 12, 0, 2, 2, 0, 1, 1, 0, 1, 1 },
+ { "test1", "bytes", 1, 13, 0, 3, 3, 0, 0, 0, 0, 1, 1 },
+ { "test1", "bytes", 1, 14, 0, 0, 0, 0, 4, 4, 0, 1, 1 },
}
feed("<esc>u")
check_events {
- { "test1", "bytes", 1, 14, 0, 0, 0, 0, 1, 1, 0, 4, 4 },
- { "test1", "bytes", 1, 14, 0, 2, 2, 0, 2, 2, 0, 1, 1 },
- { "test1", "bytes", 1, 14, 0, 0, 0, 0, 2, 2, 0, 1, 1 }
+ { "test1", "bytes", 1, 16, 0, 0, 0, 0, 1, 1, 0, 4, 4 },
+ { "test1", "bytes", 1, 16, 0, 2, 2, 0, 2, 2, 0, 1, 1 },
+ { "test1", "bytes", 1, 16, 0, 0, 0, 0, 2, 2, 0, 1, 1 }
}
-- in VISUALREPLACE mode
feed("gR<tab><tab>")
check_events {
- { "test1", "bytes", 1, 15, 0, 0, 0, 0, 1, 1, 0, 1, 1 };
- { "test1", "bytes", 1, 16, 0, 1, 1, 0, 1, 1, 0, 1, 1 };
- { "test1", "bytes", 1, 17, 0, 2, 2, 0, 1, 1, 0, 1, 1 };
- { "test1", "bytes", 1, 18, 0, 3, 3, 0, 1, 1, 0, 1, 1 };
- { "test1", "bytes", 1, 19, 0, 3, 3, 0, 1, 1, 0, 0, 0 };
- { "test1", "bytes", 1, 20, 0, 3, 3, 0, 0, 0, 0, 1, 1 };
- { "test1", "bytes", 1, 22, 0, 2, 2, 0, 1, 1, 0, 0, 0 };
- { "test1", "bytes", 1, 23, 0, 2, 2, 0, 0, 0, 0, 1, 1 };
- { "test1", "bytes", 1, 25, 0, 1, 1, 0, 1, 1, 0, 0, 0 };
- { "test1", "bytes", 1, 26, 0, 1, 1, 0, 0, 0, 0, 1, 1 };
- { "test1", "bytes", 1, 28, 0, 0, 0, 0, 1, 1, 0, 0, 0 };
- { "test1", "bytes", 1, 29, 0, 0, 0, 0, 0, 0, 0, 1, 1 };
- { "test1", "bytes", 1, 31, 0, 0, 0, 0, 4, 4, 0, 1, 1 };
+ { "test1", "bytes", 1, 17, 0, 0, 0, 0, 1, 1, 0, 1, 1 };
+ { "test1", "bytes", 1, 18, 0, 1, 1, 0, 1, 1, 0, 1, 1 };
+ { "test1", "bytes", 1, 19, 0, 2, 2, 0, 1, 1, 0, 1, 1 };
+ { "test1", "bytes", 1, 20, 0, 3, 3, 0, 1, 1, 0, 1, 1 };
+ { "test1", "bytes", 1, 21, 0, 3, 3, 0, 1, 1, 0, 0, 0 };
+ { "test1", "bytes", 1, 22, 0, 3, 3, 0, 0, 0, 0, 1, 1 };
+ { "test1", "bytes", 1, 24, 0, 2, 2, 0, 1, 1, 0, 0, 0 };
+ { "test1", "bytes", 1, 25, 0, 2, 2, 0, 0, 0, 0, 1, 1 };
+ { "test1", "bytes", 1, 27, 0, 1, 1, 0, 1, 1, 0, 0, 0 };
+ { "test1", "bytes", 1, 28, 0, 1, 1, 0, 0, 0, 0, 1, 1 };
+ { "test1", "bytes", 1, 30, 0, 0, 0, 0, 1, 1, 0, 0, 0 };
+ { "test1", "bytes", 1, 31, 0, 0, 0, 0, 0, 0, 0, 1, 1 };
+ { "test1", "bytes", 1, 33, 0, 0, 0, 0, 4, 4, 0, 1, 1 };
}
-- inserting tab after other tabs
command("set sw=4")
feed("<esc>0a<tab>")
check_events {
- { "test1", "bytes", 1, 32, 0, 1, 1, 0, 0, 0, 0, 1, 1 };
- { "test1", "bytes", 1, 33, 0, 2, 2, 0, 0, 0, 0, 1, 1 };
- { "test1", "bytes", 1, 34, 0, 3, 3, 0, 0, 0, 0, 1, 1 };
- { "test1", "bytes", 1, 35, 0, 4, 4, 0, 0, 0, 0, 1, 1 };
- { "test1", "bytes", 1, 36, 0, 1, 1, 0, 4, 4, 0, 1, 1 };
+ { "test1", "bytes", 1, 34, 0, 1, 1, 0, 0, 0, 0, 1, 1 };
+ { "test1", "bytes", 1, 35, 0, 2, 2, 0, 0, 0, 0, 1, 1 };
+ { "test1", "bytes", 1, 36, 0, 3, 3, 0, 0, 0, 0, 1, 1 };
+ { "test1", "bytes", 1, 37, 0, 4, 4, 0, 0, 0, 0, 1, 1 };
+ { "test1", "bytes", 1, 38, 0, 1, 1, 0, 4, 4, 0, 1, 1 };
}
end)
diff --git a/test/functional/lua/fs_spec.lua b/test/functional/lua/fs_spec.lua
index 2c7b3ff324..6bdb9ed79d 100644
--- a/test/functional/lua/fs_spec.lua
+++ b/test/functional/lua/fs_spec.lua
@@ -1,4 +1,5 @@
local helpers = require('test.functional.helpers')(after_each)
+local uv = require('luv')
local clear = helpers.clear
local exec_lua = helpers.exec_lua
@@ -288,11 +289,12 @@ describe('vim.fs', function()
eq('/', exec_lua [[ return vim.fs.normalize('/') ]])
end)
it('works with ~', function()
- eq( exec_lua([[
- local home = ...
- return home .. '/src/foo'
- ]], is_os('win') and vim.fs.normalize(os.getenv('USERPROFILE')) or os.getenv('HOME')
- ) , exec_lua [[ return vim.fs.normalize('~/src/foo') ]])
+ eq(
+ exec_lua([[
+ local home = ...
+ return home .. '/src/foo'
+ ]], vim.fs.normalize(uv.os_homedir())),
+ exec_lua [[ return vim.fs.normalize('~/src/foo') ]])
end)
it('works with environment variables', function()
local xdg_config_home = test_build_dir .. '/.config'
diff --git a/test/functional/plugin/lsp/utils_spec.lua b/test/functional/plugin/lsp/utils_spec.lua
index c91fffa90f..f544255d81 100644
--- a/test/functional/plugin/lsp/utils_spec.lua
+++ b/test/functional/plugin/lsp/utils_spec.lua
@@ -1,4 +1,6 @@
local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local feed = helpers.feed
local eq = helpers.eq
local exec_lua = helpers.exec_lua
@@ -85,4 +87,98 @@ describe('vim.lsp.util', function()
eq(expected, stylize_markdown(lines, opts))
end)
end)
+
+ describe("make_floating_popup_options", function ()
+
+ local function assert_anchor(anchor_bias, expected_anchor)
+ local opts = exec_lua([[
+ local args = { ... }
+ local anchor_bias = args[1]
+ return vim.lsp.util.make_floating_popup_options(30, 10, { anchor_bias = anchor_bias })
+ ]], anchor_bias)
+
+ eq(expected_anchor, string.sub(opts.anchor, 1, 1))
+ end
+
+ local screen
+ before_each(function ()
+ helpers.clear()
+ screen = Screen.new(80, 80)
+ screen:attach()
+ feed("79i<CR><Esc>") -- fill screen with empty lines
+ end)
+
+ describe('when on the first line it places window below', function ()
+ before_each(function ()
+ feed('gg')
+ end)
+
+ it('for anchor_bias = "auto"', function ()
+ assert_anchor('auto', 'N')
+ end)
+
+ it('for anchor_bias = "above"', function ()
+ assert_anchor('above', 'N')
+ end)
+
+ it('for anchor_bias = "below"', function ()
+ assert_anchor('below', 'N')
+ end)
+ end)
+
+ describe('when on the last line it places window above', function ()
+ before_each(function ()
+ feed('G')
+ end)
+
+ it('for anchor_bias = "auto"', function ()
+ assert_anchor('auto', 'S')
+ end)
+
+ it('for anchor_bias = "above"', function ()
+ assert_anchor('above', 'S')
+ end)
+
+ it('for anchor_bias = "below"', function ()
+ assert_anchor('below', 'S')
+ end)
+ end)
+
+ describe('with 20 lines above, 59 lines below', function ()
+ before_each(function ()
+ feed('gg20j')
+ end)
+
+ it('places window below for anchor_bias = "auto"', function ()
+ assert_anchor('auto', 'N')
+ end)
+
+ it('places window above for anchor_bias = "above"', function ()
+ assert_anchor('above', 'S')
+ end)
+
+ it('places window below for anchor_bias = "below"', function ()
+ assert_anchor('below', 'N')
+ end)
+ end)
+
+ describe('with 59 lines above, 20 lines below', function ()
+ before_each(function ()
+ feed('G20k')
+ end)
+
+ it('places window above for anchor_bias = "auto"', function ()
+ assert_anchor('auto', 'S')
+ end)
+
+ it('places window above for anchor_bias = "above"', function ()
+ assert_anchor('above', 'S')
+ end)
+
+ it('places window below for anchor_bias = "below"', function ()
+ assert_anchor('below', 'N')
+ end)
+ end)
+ end)
+
end)
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index 3eb89b4556..e0a8badb67 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -1787,7 +1787,7 @@ describe('LSP', function()
eq({
'First line of text';
}, buf_lines(1))
- eq({ 1, 6 }, funcs.nvim_win_get_cursor(0))
+ eq({ 1, 17 }, funcs.nvim_win_get_cursor(0))
end)
it('fix the cursor row', function()
diff --git a/test/functional/terminal/edit_spec.lua b/test/functional/terminal/edit_spec.lua
index db5dba7374..29361bc0fa 100644
--- a/test/functional/terminal/edit_spec.lua
+++ b/test/functional/terminal/edit_spec.lua
@@ -36,7 +36,6 @@ describe(':edit term://*', function()
end)
it("runs TermOpen early enough to set buffer-local 'scrollback'", function()
- if helpers.skip(helpers.is_os('win')) then return end
local columns, lines = 20, 4
local scr = get_screen(columns, lines)
local rep = 97
diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 62dbd57202..daa4b4bdb3 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -103,7 +103,7 @@ describe('decorations providers', function()
]]}
check_trace {
{ "start", 4 };
- { "win", 1000, 1, 0, 8 };
+ { "win", 1000, 1, 0, 6 };
{ "line", 1000, 1, 0 };
{ "line", 1000, 1, 1 };
{ "line", 1000, 1, 2 };
@@ -128,7 +128,7 @@ describe('decorations providers', function()
check_trace {
{ "start", 5 };
{ "buf", 1, 5 };
- { "win", 1000, 1, 0, 8 };
+ { "win", 1000, 1, 0, 6 };
{ "line", 1000, 1, 6 };
{ "end", 5 };
}
@@ -195,7 +195,7 @@ describe('decorations providers', function()
check_trace {
{ "start", 5 };
- { "win", 1000, 1, 0, 5 };
+ { "win", 1000, 1, 0, 3 };
{ "line", 1000, 1, 0 };
{ "line", 1000, 1, 1 };
{ "line", 1000, 1, 2 };
@@ -691,6 +691,12 @@ describe('extmark decorations', function()
[33] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGray};
[34] = {background = Screen.colors.Yellow};
[35] = {background = Screen.colors.Yellow, bold = true, foreground = Screen.colors.Blue};
+ [36] = {foreground = Screen.colors.Blue1, bold = true, background = Screen.colors.Red};
+ [37] = {background = Screen.colors.WebGray, foreground = Screen.colors.DarkBlue};
+ [38] = {background = Screen.colors.LightBlue};
+ [39] = {foreground = Screen.colors.Blue1, background = Screen.colors.LightCyan1, bold = true};
+ [40] = {reverse = true};
+ [41] = {bold = true, reverse = true};
}
ns = meths.create_namespace 'test'
@@ -858,6 +864,104 @@ describe('extmark decorations', function()
]]}
end)
+ it('overlay virtual text works with wrapped lines #25158', function()
+ screen:try_resize(50, 6)
+ insert(('ab'):rep(100))
+ for i = 0, 9 do
+ meths.buf_set_extmark(0, ns, 0, 42 + i, { virt_text={{tostring(i), 'ErrorMsg'}}, virt_text_pos='overlay'})
+ meths.buf_set_extmark(0, ns, 0, 91 + i, { virt_text={{tostring(i), 'ErrorMsg'}}, virt_text_pos='overlay', virt_text_hide=true})
+ end
+ screen:expect{grid=[[
+ ababababababababababababababababababababab{4:01234567}|
+ {4:89}abababababababababababababababababababa{4:012345678}|
+ {4:9}babababababababababababababababababababababababab|
+ ababababababababababababababababababababababababa^b|
+ {1:~ }|
+ |
+ ]]}
+
+ command('set showbreak=++')
+ screen:expect{grid=[[
+ ababababababababababababababababababababab{4:01234567}|
+ {1:++}{4:89}abababababababababababababababababababa{4:0123456}|
+ {1:++}{4:789}babababababababababababababababababababababab|
+ {1:++}abababababababababababababababababababababababab|
+ {1:++}ababa^b |
+ |
+ ]]}
+
+ feed('2gkvg0')
+ screen:expect{grid=[[
+ ababababababababababababababababababababab{4:01234567}|
+ {1:++}{4:89}abababababababababababababababababababa{4:0123456}|
+ {1:++}^a{18:babab}ababababababababababababababababababababab|
+ {1:++}abababababababababababababababababababababababab|
+ {1:++}ababab |
+ {24:-- VISUAL --} |
+ ]]}
+
+ feed('o')
+ screen:expect{grid=[[
+ ababababababababababababababababababababab{4:01234567}|
+ {1:++}{4:89}abababababababababababababababababababa{4:0123456}|
+ {1:++}{18:ababa}^bababababababababababababababababababababab|
+ {1:++}abababababababababababababababababababababababab|
+ {1:++}ababab |
+ {24:-- VISUAL --} |
+ ]]}
+
+ feed('gk')
+ screen:expect{grid=[[
+ ababababababababababababababababababababab{4:01234567}|
+ {1:++}{4:89}aba^b{18:ababababababababababababababababababababab}|
+ {1:++}{18:a}{4:89}babababababababababababababababababababababab|
+ {1:++}abababababababababababababababababababababababab|
+ {1:++}ababab |
+ {24:-- VISUAL --} |
+ ]]}
+
+ feed('o')
+ screen:expect{grid=[[
+ ababababababababababababababababababababab{4:01234567}|
+ {1:++}{4:89}aba{18:bababababababababababababababababababababab}|
+ {1:++}^a{4:89}babababababababababababababababababababababab|
+ {1:++}abababababababababababababababababababababababab|
+ {1:++}ababab |
+ {24:-- VISUAL --} |
+ ]]}
+
+ feed('<Esc>$')
+ command('set number showbreak=')
+ screen:expect{grid=[[
+ {2: 1 }ababababababababababababababababababababab{4:0123}|
+ {2: }{4:456789}abababababababababababababababababababa{4:0}|
+ {2: }{4:123456789}babababababababababababababababababab|
+ {2: }ababababababababababababababababababababababab|
+ {2: }abababababababa^b |
+ |
+ ]]}
+
+ command('set cpoptions+=n')
+ screen:expect{grid=[[
+ {2: 1 }ababababababababababababababababababababab{4:0123}|
+ {4:456789}abababababababababababababababababababa{4:01234}|
+ {4:56789}babababababababababababababababababababababab|
+ ababababababababababababababababababababababababab|
+ aba^b |
+ |
+ ]]}
+
+ feed('0g$hi<Tab>')
+ screen:expect{grid=[[
+ {2: 1 }ababababababababababababababababababababab{4:01} |
+ {4:^23456789}abababababababababababababababababababa{4:0}|
+ {4:123456789}babababababababababababababababababababab|
+ ababababababababababababababababababababababababab|
+ abababab |
+ {24:-- INSERT --} |
+ ]]}
+ end)
+
it('virt_text_hide hides overlay virtual text when extmark is off-screen', function()
screen:try_resize(50, 3)
command('set nowrap')
@@ -1027,12 +1131,12 @@ describe('extmark decorations', function()
it('can have virtual text of right_align and fixed win_col position', function()
insert(example_text)
feed 'gg'
- meths.buf_set_extmark(0, ns, 1, 0, { virt_text={{'Very', 'ErrorMsg'}}, virt_text_win_col=31, hl_mode='blend'})
+ meths.buf_set_extmark(0, ns, 1, 0, { virt_text={{'Very', 'ErrorMsg'}}, virt_text_win_col=31, hl_mode='blend'})
meths.buf_set_extmark(0, ns, 1, 0, { virt_text={{'VERY', 'ErrorMsg'}}, virt_text_pos='right_align', hl_mode='blend'})
- meths.buf_set_extmark(0, ns, 2, 10, { virt_text={{'Much', 'ErrorMsg'}}, virt_text_win_col=31, hl_mode='blend'})
+ meths.buf_set_extmark(0, ns, 2, 10, { virt_text={{'Much', 'ErrorMsg'}}, virt_text_win_col=31, hl_mode='blend'})
meths.buf_set_extmark(0, ns, 2, 10, { virt_text={{'MUCH', 'ErrorMsg'}}, virt_text_pos='right_align', hl_mode='blend'})
- meths.buf_set_extmark(0, ns, 3, 15, { virt_text={{'Error', 'ErrorMsg'}}, virt_text_win_col=31, hl_mode='blend'})
- meths.buf_set_extmark(0, ns, 3, 15, { virt_text={{'ERROR', 'ErrorMsg'}}, virt_text_pos='right_align', hl_mode='blend'})
+ meths.buf_set_extmark(0, ns, 3, 14, { virt_text={{'Error', 'ErrorMsg'}}, virt_text_win_col=31, hl_mode='blend'})
+ meths.buf_set_extmark(0, ns, 3, 14, { virt_text={{'ERROR', 'ErrorMsg'}}, virt_text_pos='right_align', hl_mode='blend'})
meths.buf_set_extmark(0, ns, 7, 21, { virt_text={{'-', 'NonText'}}, virt_text_win_col=4, hl_mode='blend'})
meths.buf_set_extmark(0, ns, 7, 21, { virt_text={{'-', 'NonText'}}, virt_text_pos='right_align', hl_mode='blend'})
-- empty virt_text should not change anything
@@ -1190,40 +1294,78 @@ describe('extmark decorations', function()
|
]]}
- command 'set cpoptions-=n nonumber nowrap'
+ command 'set cpoptions-=n nowrap'
screen:expect{grid=[[
- for _,item in ipairs(items) do |
- local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}|
- if |
- hl_id_cell ~= nil then {4:Much} {4:MUCH}|
- --^ -- -- -- -- -- -- --{4:Error}- -- -- h{4:ERROR}|
- end |
- for _ = 1, (count or 1) do |
- local cell = line[colpos] |
- {1:-} cell.text = text {1:-}|
- cell.hl_id = hl_id |
- colpos = colpos+1 |
- end |
- end |
+ {2: 1 }for _,item in ipairs(items) do |
+ {2: 2 } local text, hl_id_cell, cou{4:Very} unpack{4:VERY}|
+ {2: 3 } if |
+ {2: 4 }hl_id_cell ~= nil then {4:Much} {4:MUCH}|
+ {2: 5 } --^ -- -- -- -- -- -- --{4:Error}- -- {4:ERROR}|
+ {2: 6 } end |
+ {2: 7 } for _ = 1, (count or 1) do |
+ {2: 8 } local cell = line[colpos] |
+ {2: 9 } {1:-} cell.text = text {1:-}|
+ {2: 10 } cell.hl_id = hl_id |
+ {2: 11 } colpos = colpos+1 |
+ {2: 12 } end |
+ {2: 13 }end |
{1:~ }|
|
]]}
- feed '8zl'
+ feed '12zl'
screen:expect{grid=[[
- em in ipairs(items) do |
- l text, hl_id_cell, count = unp{4:Very}item) {4:VERY}|
- |
- ll ~= nil then {4:Much} {4:MUCH}|
- --^ -- -- -- -- -- -- -- -- -- -{4:Error}hl_id = h{4:ERROR}|
- |
- _ = 1, (count or 1) do |
- local cell = line[colpos] |
- cell{1:-}text = text {1:-}|
- cell.hl_id = hl_id |
- colpos = colpos+1 |
- |
+ {2: 1 }n ipairs(items) do |
+ {2: 2 }xt, hl_id_cell, count = unpack({4:Very}) {4:VERY}|
+ {2: 3 } |
+ {2: 4 }= nil then {4:Much} {4:MUCH}|
+ {2: 5 }^- -- -- -- -- -- -- -- -- -- --{4:Error}d = h{4:ERROR}|
+ {2: 6 } |
+ {2: 7 }1, (count or 1) do |
+ {2: 8 }l cell = line[colpos] |
+ {2: 9 }.tex{1:-} = text {1:-}|
+ {2: 10 }.hl_id = hl_id |
+ {2: 11 }os = colpos+1 |
+ {2: 12 } |
+ {2: 13 } |
+ {1:~ }|
|
+ ]]}
+
+ feed('fhi<Tab>')
+ screen:expect{grid=[[
+ {2: 1 }n ipairs(items) do |
+ {2: 2 }xt, hl_id_cell, count = unpack({4:Very}) {4:VERY}|
+ {2: 3 } |
+ {2: 4 }= nil then {4:Much} {4:MUCH}|
+ {2: 5 }- -- -- -- -- -- -- -- -- -- --{4:Error}^hl_id{4:ERROR}|
+ {2: 6 } |
+ {2: 7 }1, (count or 1) do |
+ {2: 8 }l cell = line[colpos] |
+ {2: 9 }.tex{1:-} = text {1:-}|
+ {2: 10 }.hl_id = hl_id |
+ {2: 11 }os = colpos+1 |
+ {2: 12 } |
+ {2: 13 } |
+ {1:~ }|
+ {24:-- INSERT --} |
+ ]]}
+
+ feed('<Esc>0')
+ screen:expect{grid=[[
+ {2: 1 }for _,item in ipairs(items) do |
+ {2: 2 } local text, hl_id_cell, cou{4:Very} unpack{4:VERY}|
+ {2: 3 } if |
+ {2: 4 }hl_id_cell ~= nil then {4:Much} {4:MUCH}|
+ {2: 5 }^ -- -- -- -- -- -- -- --{4:Error}- -- {4:ERROR}|
+ {2: 6 } end |
+ {2: 7 } for _ = 1, (count or 1) do |
+ {2: 8 } local cell = line[colpos] |
+ {2: 9 } {1:-} cell.text = text {1:-}|
+ {2: 10 } cell.hl_id = hl_id |
+ {2: 11 } colpos = colpos+1 |
+ {2: 12 } end |
+ {2: 13 }end |
{1:~ }|
|
]]}
@@ -1235,20 +1377,21 @@ describe('extmark decorations', function()
22222
33333]])
command('1,2fold')
- command('set nowrap')
screen:try_resize(50, 3)
feed('zb')
-- XXX: the behavior of overlay virtual text at non-zero column is strange:
-- 1. With 'wrap' it is never shown.
-- 2. With 'nowrap' it is shown only if the extmark is hidden before leftcol.
meths.buf_set_extmark(0, ns, 0, 0, { virt_text = {{'AA', 'Underlined'}}, hl_mode = 'combine', virt_text_pos = 'overlay' })
- meths.buf_set_extmark(0, ns, 0, 1, { virt_text = {{'BB', 'Underlined'}}, hl_mode = 'combine', virt_text_win_col = 10 })
+ meths.buf_set_extmark(0, ns, 0, 5, { virt_text = {{'BB', 'Underlined'}}, hl_mode = 'combine', virt_text_win_col = 10 })
meths.buf_set_extmark(0, ns, 0, 2, { virt_text = {{'CC', 'Underlined'}}, hl_mode = 'combine', virt_text_pos = 'right_align' })
screen:expect{grid=[[
{29:AA}{33:- 2 lin}{29:BB}{33:: 11111·····························}{29:CC}|
3333^3 |
|
]]}
+ command('set nowrap')
+ screen:expect_unchanged()
feed('zl')
screen:expect{grid=[[
{29:AA}{33:- 2 lin}{29:BB}{33:: 11111·····························}{29:CC}|
@@ -1269,6 +1412,38 @@ describe('extmark decorations', function()
]]}
end)
+ it('virtual text works below diff filler lines', function()
+ screen:try_resize(53, 8)
+ insert([[
+ aaaaa
+ bbbbb
+ ccccc
+ ddddd
+ eeeee]])
+ command('rightbelow vnew')
+ insert([[
+ bbbbb
+ ccccc
+ ddddd
+ eeeee]])
+ command('windo diffthis')
+ meths.buf_set_extmark(0, ns, 0, 0, { virt_text = {{'AA', 'Underlined'}}, virt_text_pos = 'overlay' })
+ meths.buf_set_extmark(0, ns, 0, 0, { virt_text = {{'BB', 'Underlined'}}, virt_text_win_col = 10 })
+ meths.buf_set_extmark(0, ns, 0, 0, { virt_text = {{'CC', 'Underlined'}}, virt_text_pos = 'right_align' })
+ screen:expect{grid=[[
+ {37: }{38:aaaaa }│{37: }{39:------------------------}|
+ {37: }bbbbb │{37: }{28:AA}bbb {28:BB} {28:CC}|
+ {37: }ccccc │{37: }ccccc |
+ {37: }ddddd │{37: }ddddd |
+ {37: }eeeee │{37: }eeee^e |
+ {1:~ }│{1:~ }|
+ {40:[No Name] [+] }{41:[No Name] [+] }|
+ |
+ ]]}
+ command('windo set wrap')
+ screen:expect_unchanged()
+ end)
+
it('can have virtual text which combines foreground and background groups', function()
screen:set_default_attr_ids {
[1] = {bold=true, foreground=Screen.colors.Blue};
@@ -1652,6 +1827,70 @@ describe('extmark decorations', function()
{24:-- VISUAL BLOCK --} |
]])
end)
+
+ it('supports multiline highlights', function()
+ insert(example_text)
+ feed 'gg'
+ for _,i in ipairs {1,2,3,5,6,7} do
+ for _,j in ipairs {2,5,10,15} do
+ meths.buf_set_extmark(0, ns, i, j, { end_col=j+2, hl_group = 'NonText'})
+ end
+ end
+ screen:expect{grid=[[
+ ^for _,item in ipairs(items) do |
+ {1: }l{1:oc}al {1:te}xt,{1: h}l_id_cell, count = unpack(item) |
+ {1: }i{1:f }hl_{1:id}_ce{1:ll} ~= nil then |
+ {1: } {1: } hl{1:_i}d ={1: h}l_id_cell |
+ end |
+ {1: }f{1:or} _ {1:= }1, {1:(c}ount or 1) do |
+ {1: } {1: } lo{1:ca}l c{1:el}l = line[colpos] |
+ {1: } {1: } ce{1:ll}.te{1:xt} = text |
+ cell.hl_id = hl_id |
+ colpos = colpos+1 |
+ end |
+ end |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+ feed'5<c-e>'
+ screen:expect{grid=[[
+ ^ {1: }f{1:or} _ {1:= }1, {1:(c}ount or 1) do |
+ {1: } {1: } lo{1:ca}l c{1:el}l = line[colpos] |
+ {1: } {1: } ce{1:ll}.te{1:xt} = text |
+ cell.hl_id = hl_id |
+ colpos = colpos+1 |
+ end |
+ end |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
+ meths.buf_set_extmark(0, ns, 1, 0, { end_line=8, end_col=10, hl_group = 'ErrorMsg'})
+ screen:expect{grid=[[
+ {4:^ }{36: }{4:f}{36:or}{4: _ }{36:= }{4:1, }{36:(c}{4:ount or 1) do} |
+ {4: }{36: }{4: }{36: }{4: lo}{36:ca}{4:l c}{36:el}{4:l = line[colpos]} |
+ {4: }{36: }{4: }{36: }{4: ce}{36:ll}{4:.te}{36:xt}{4: = text} |
+ {4: ce}ll.hl_id = hl_id |
+ colpos = colpos+1 |
+ end |
+ end |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+ end)
end)
describe('decorations: inline virtual text', function()
@@ -4136,7 +4375,6 @@ l5
end)
it('can add multiple signs (single extmark)', function()
- pending('TODO(lewis6991): Support ranged signs')
insert(example_test3)
feed 'gg'
@@ -4158,7 +4396,6 @@ l5
end)
it('can add multiple signs (multiple extmarks)', function()
- pending('TODO(lewis6991): Support ranged signs')
insert(example_test3)
feed'gg'
@@ -4219,7 +4456,6 @@ l5
end)
it('can add multiple signs (multiple extmarks) 3', function()
- pending('TODO(lewis6991): Support ranged signs')
insert(example_test3)
feed 'gg'
@@ -4289,7 +4525,6 @@ l5
end)
it('works with old signs (with range)', function()
- pending('TODO(lewis6991): Support ranged signs')
insert(example_test3)
feed 'gg'
@@ -4304,7 +4539,7 @@ l5
screen:expect{grid=[[
S3S4S1^l1 |
- S2S3x l2 |
+ x S2S3l2 |
S5S3{1: }l3 |
S3{1: }l4 |
S3{1: }l5 |
@@ -4317,8 +4552,6 @@ l5
end)
it('can add a ranged sign (with start out of view)', function()
- pending('TODO(lewis6991): Support ranged signs')
-
insert(example_test3)
command 'set signcolumn=yes:2'
feed 'gg'
diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua
index 0cf8a124ff..e37b3ccb5f 100644
--- a/test/functional/ui/float_spec.lua
+++ b/test/functional/ui/float_spec.lua
@@ -3319,7 +3319,6 @@ describe('float window', function()
]])
end
-
meths.win_set_config(win, {relative='win', win=oldwin, row=1, col=10, anchor='NW'})
if multigrid then
screen:expect{grid=[[
@@ -3765,6 +3764,198 @@ describe('float window', function()
end
end)
+ it('anchored to another floating window updated in the same call #14735', function()
+ feed('i<CR><CR><CR><Esc>')
+
+ exec([[
+ let b1 = nvim_create_buf(v:true, v:false)
+ let b2 = nvim_create_buf(v:true, v:false)
+ let b3 = nvim_create_buf(v:true, v:false)
+ let b4 = nvim_create_buf(v:true, v:false)
+ let b5 = nvim_create_buf(v:true, v:false)
+ let b6 = nvim_create_buf(v:true, v:false)
+ let b7 = nvim_create_buf(v:true, v:false)
+ let b8 = nvim_create_buf(v:true, v:false)
+ call setbufline(b1, 1, '1')
+ call setbufline(b2, 1, '2')
+ call setbufline(b3, 1, '3')
+ call setbufline(b4, 1, '4')
+ call setbufline(b5, 1, '5')
+ call setbufline(b6, 1, '6')
+ call setbufline(b7, 1, '7')
+ call setbufline(b8, 1, '8')
+ let o1 = #{relative: 'editor', row: 1, col: 10, width: 5, height: 1}
+ let w1 = nvim_open_win(b1, v:false, o1)
+ let o2 = extendnew(o1, #{col: 30})
+ let w2 = nvim_open_win(b2, v:false, o2)
+ let o3 = extendnew(o1, #{relative: 'win', win: w1, anchor: 'NE', col: 0})
+ let w3 = nvim_open_win(b3, v:false, o3)
+ let o4 = extendnew(o3, #{win: w2})
+ let w4 = nvim_open_win(b4, v:false, o4)
+ let o5 = extendnew(o3, #{win: w3, anchor: 'SE', row: 0})
+ let w5 = nvim_open_win(b5, v:false, o5)
+ let o6 = extendnew(o5, #{win: w4})
+ let w6 = nvim_open_win(b6, v:false, o6)
+ let o7 = extendnew(o5, #{win: w5, anchor: 'SW', col: 5})
+ let w7 = nvim_open_win(b7, v:false, o7)
+ let o8 = extendnew(o7, #{win: w6})
+ let w8 = nvim_open_win(b8, v:false, o8)
+ ]])
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ |
+ |
+ |
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 5
+ {1:1 }|
+ ## grid 6
+ {1:2 }|
+ ## grid 7
+ {1:3 }|
+ ## grid 8
+ {1:4 }|
+ ## grid 9
+ {1:5 }|
+ ## grid 10
+ {1:6 }|
+ ## grid 11
+ {1:7 }|
+ ## grid 12
+ {1:8 }|
+ ]], float_pos={
+ [5] = {{id = 1002}, "NW", 1, 1, 10, true, 50};
+ [6] = {{id = 1003}, "NW", 1, 1, 30, true, 50};
+ [7] = {{id = 1004}, "NE", 5, 1, 0, true, 50};
+ [8] = {{id = 1005}, "NE", 6, 1, 0, true, 50};
+ [9] = {{id = 1006}, "SE", 7, 0, 0, true, 50};
+ [10] = {{id = 1007}, "SE", 8, 0, 0, true, 50};
+ [11] = {{id = 1008}, "SW", 9, 0, 5, true, 50};
+ [12] = {{id = 1009}, "SW", 10, 0, 5, true, 50};
+ }}
+ else
+ screen:expect([[
+ {1:7 } {1:8 } |
+ {1:5 } {1:1 } {1:6 } {1:2 } |
+ {1:3 } {1:4 } |
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end
+
+ -- Reconfigure in different directions
+ exec([[
+ let o1 = extendnew(o1, #{anchor: 'NW'})
+ call nvim_win_set_config(w8, o1)
+ let o2 = extendnew(o2, #{anchor: 'NW'})
+ call nvim_win_set_config(w4, o2)
+ let o3 = extendnew(o3, #{win: w8})
+ call nvim_win_set_config(w2, o3)
+ let o4 = extendnew(o4, #{win: w4})
+ call nvim_win_set_config(w1, o4)
+ let o5 = extendnew(o5, #{win: w2})
+ call nvim_win_set_config(w6, o5)
+ let o6 = extendnew(o6, #{win: w1})
+ call nvim_win_set_config(w3, o6)
+ let o7 = extendnew(o7, #{win: w6})
+ call nvim_win_set_config(w5, o7)
+ let o8 = extendnew(o8, #{win: w3})
+ call nvim_win_set_config(w7, o8)
+ ]])
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ |
+ |
+ |
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 5
+ {1:1 }|
+ ## grid 6
+ {1:2 }|
+ ## grid 7
+ {1:3 }|
+ ## grid 8
+ {1:4 }|
+ ## grid 9
+ {1:5 }|
+ ## grid 10
+ {1:6 }|
+ ## grid 11
+ {1:7 }|
+ ## grid 12
+ {1:8 }|
+ ]], float_pos={
+ [5] = {{id = 1002}, "NE", 8, 1, 0, true, 50};
+ [6] = {{id = 1003}, "NE", 12, 1, 0, true, 50};
+ [7] = {{id = 1004}, "SE", 5, 0, 0, true, 50};
+ [8] = {{id = 1005}, "NW", 1, 1, 30, true, 50};
+ [9] = {{id = 1006}, "SW", 10, 0, 5, true, 50};
+ [10] = {{id = 1007}, "SE", 6, 0, 0, true, 50};
+ [11] = {{id = 1008}, "SW", 7, 0, 5, true, 50};
+ [12] = {{id = 1009}, "NW", 1, 1, 10, true, 50};
+ }}
+ else
+ screen:expect([[
+ {1:5 } {1:7 } |
+ {1:6 } {1:8 } {1:3 } {1:4 } |
+ {1:2 } {1:1 } |
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end
+
+ -- Not clear how cycles should behave, but they should not hang or crash
+ exec([[
+ let o1 = extendnew(o1, #{relative: 'win', win: w7})
+ call nvim_win_set_config(w1, o1)
+ let o2 = extendnew(o2, #{relative: 'win', win: w8})
+ call nvim_win_set_config(w2, o2)
+ let o3 = extendnew(o3, #{win: w1})
+ call nvim_win_set_config(w3, o3)
+ let o4 = extendnew(o4, #{win: w2})
+ call nvim_win_set_config(w4, o4)
+ let o5 = extendnew(o5, #{win: w3})
+ call nvim_win_set_config(w5, o5)
+ let o6 = extendnew(o6, #{win: w4})
+ call nvim_win_set_config(w6, o6)
+ let o7 = extendnew(o7, #{win: w5})
+ call nvim_win_set_config(w7, o7)
+ let o8 = extendnew(o8, #{win: w6})
+ call nvim_win_set_config(w8, o8)
+ redraw
+ ]])
+ end)
+
it('can be placed relative text in a window', function()
screen:try_resize(30,5)
local firstwin = meths.get_current_win().id
diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua
index 2307fd106b..be7c2f291c 100644
--- a/test/functional/ui/screen.lua
+++ b/test/functional/ui/screen.lua
@@ -1270,7 +1270,7 @@ end
function Screen:render(headers, attr_state, preview)
headers = headers and (self._options.ext_multigrid or self._options._debug_float)
local rv = {}
- for igrid,grid in pairs(self._grids) do
+ for igrid,grid in vim.spairs(self._grids) do
if headers then
local suffix = ""
if igrid > 1 and self.win_position[igrid] == nil
diff --git a/test/functional/ui/statuscolumn_spec.lua b/test/functional/ui/statuscolumn_spec.lua
index ee235cd6b5..742976cbe2 100644
--- a/test/functional/ui/statuscolumn_spec.lua
+++ b/test/functional/ui/statuscolumn_spec.lua
@@ -532,6 +532,24 @@ describe('statuscolumn', function()
eq('0 3 r 7', eval("g:testvar"))
meths.input_mouse('right', 'press', '', 0, 3, 0)
eq('0 4 r 7', eval("g:testvar"))
+
+ command('rightbelow vsplit')
+ meths.input_mouse('left', 'press', '', 0, 0, 27)
+ eq('0 1 l 4', eval("g:testvar"))
+ meths.input_mouse('right', 'press', '', 0, 3, 27)
+ eq('0 1 r 7', eval("g:testvar"))
+ command('setlocal rightleft')
+ meths.input_mouse('left', 'press', '', 0, 0, 52)
+ eq('0 1 l 4', eval("g:testvar"))
+ meths.input_mouse('right', 'press', '', 0, 3, 52)
+ eq('0 1 r 7', eval("g:testvar"))
+ command('wincmd H')
+ meths.input_mouse('left', 'press', '', 0, 0, 25)
+ eq('0 1 l 4', eval("g:testvar"))
+ meths.input_mouse('right', 'press', '', 0, 3, 25)
+ eq('0 1 r 7', eval("g:testvar"))
+ command('close')
+
command('set laststatus=2 winbar=%f')
command('let g:testvar = ""')
-- Check that winbar click doesn't register as statuscolumn click
diff --git a/test/functional/vimscript/system_spec.lua b/test/functional/vimscript/system_spec.lua
index 762e8877ce..90aab48d61 100644
--- a/test/functional/vimscript/system_spec.lua
+++ b/test/functional/vimscript/system_spec.lua
@@ -335,12 +335,12 @@ describe('system()', function()
if is_os('win') then
eq("echoed\n", eval('system("echo echoed")'))
else
- eq("echoed", eval('system("echo -n echoed")'))
+ eq("echoed", eval('system("printf echoed")'))
end
end)
it('to backgrounded command does not crash', function()
-- This is indeterminate, just exercise the codepath. May get E5677.
- feed_command('call system(has("win32") ? "start /b /wait cmd /c echo echoed" : "echo -n echoed &")')
+ feed_command('call system(has("win32") ? "start /b /wait cmd /c echo echoed" : "printf echoed &")')
local v_errnum = string.match(eval("v:errmsg"), "^E%d*:")
if v_errnum then
eq("E5677:", v_errnum)
diff --git a/test/old/testdir/check.vim b/test/old/testdir/check.vim
index 281514db17..af1a80250c 100644
--- a/test/old/testdir/check.vim
+++ b/test/old/testdir/check.vim
@@ -100,6 +100,14 @@ func CheckLinux()
endif
endfunc
+" Command to check for not running on a BSD system.
+command CheckNotBSD call CheckNotBSD()
+func CheckNotBSD()
+ if has('bsd')
+ throw 'Skipped: does not work on BSD'
+ endif
+endfunc
+
" Command to check that making screendumps is supported.
" Caller must source screendump.vim
command CheckScreendump call CheckScreendump()
diff --git a/test/old/testdir/test_autocmd.vim b/test/old/testdir/test_autocmd.vim
index 79f8ee43c1..0afa3417ec 100644
--- a/test/old/testdir/test_autocmd.vim
+++ b/test/old/testdir/test_autocmd.vim
@@ -2002,8 +2002,8 @@ endfunc
" Test for BufUnload autocommand that unloads all the other buffers
func Test_bufunload_all()
let g:test_is_flaky = 1
- call writefile(['Test file Xxx1'], 'Xxx1', 'D')"
- call writefile(['Test file Xxx2'], 'Xxx2', 'D')"
+ call writefile(['Test file Xxx1'], 'Xxx1', 'D')
+ call writefile(['Test file Xxx2'], 'Xxx2', 'D')
let content =<< trim [CODE]
func UnloadAllBufs()
diff --git a/test/old/testdir/test_edit.vim b/test/old/testdir/test_edit.vim
index 0f3c62a092..03796ad816 100644
--- a/test/old/testdir/test_edit.vim
+++ b/test/old/testdir/test_edit.vim
@@ -1235,7 +1235,7 @@ func Test_edit_LEFT_RIGHT()
endfunc
func Test_edit_MOUSE()
- " This is a simple test, since we not really using the mouse here
+ " This is a simple test, since we're not really using the mouse here
CheckFeature mouse
10new
call setline(1, range(1, 100))
@@ -1817,7 +1817,7 @@ func Test_edit_charconvert()
close!
set charconvert&
- " 'charconvert' function doesn't create a output file
+ " 'charconvert' function doesn't create an output file
func Cconv1()
endfunc
set charconvert=Cconv1()
diff --git a/test/old/testdir/test_filetype.vim b/test/old/testdir/test_filetype.vim
index 1dd255ccf9..b2b6ad80bb 100644
--- a/test/old/testdir/test_filetype.vim
+++ b/test/old/testdir/test_filetype.vim
@@ -427,6 +427,7 @@ func s:GetFilenameChecks() abort
\ 'mrxvtrc': ['mrxvtrc', '.mrxvtrc'],
\ 'msidl': ['file.odl', 'file.mof'],
\ 'msql': ['file.msql'],
+ \ 'mojo': ['file.mojo', 'file.🔥'],
\ 'mupad': ['file.mu'],
\ 'mush': ['file.mush'],
\ 'muttrc': ['Muttngrc', 'Muttrc', '.muttngrc', '.muttngrc-file', '.muttrc', '.muttrc-file', '/.mutt/muttngrc', '/.mutt/muttngrc-file', '/.mutt/muttrc', '/.mutt/muttrc-file', '/.muttng/muttngrc', '/.muttng/muttngrc-file', '/.muttng/muttrc', '/.muttng/muttrc-file', '/etc/Muttrc.d/file', '/etc/Muttrc.d/file.rc', 'Muttngrc-file', 'Muttrc-file', 'any/.mutt/muttngrc', 'any/.mutt/muttngrc-file', 'any/.mutt/muttrc', 'any/.mutt/muttrc-file', 'any/.muttng/muttngrc', 'any/.muttng/muttngrc-file', 'any/.muttng/muttrc', 'any/.muttng/muttrc-file', 'any/etc/Muttrc.d/file', 'muttngrc', 'muttngrc-file', 'muttrc', 'muttrc-file'],
diff --git a/test/old/testdir/test_functions.vim b/test/old/testdir/test_functions.vim
index eff4e36f34..3e1e5a4816 100644
--- a/test/old/testdir/test_functions.vim
+++ b/test/old/testdir/test_functions.vim
@@ -290,6 +290,7 @@ endfunc
func Test_strptime()
CheckFunction strptime
+ CheckNotBSD
CheckNotMSWindows
if exists('$TZ')
@@ -305,6 +306,8 @@ func Test_strptime()
call assert_fails('call strptime()', 'E119:')
call assert_fails('call strptime("xxx")', 'E119:')
+ " This fails on BSD 14 and returns
+ " -2209078800 instead of 0
call assert_equal(0, strptime("%Y", ''))
call assert_equal(0, strptime("%Y", "xxx"))
@@ -2630,7 +2633,7 @@ func Test_state()
call term_sendkeys(buf, getstate)
call WaitForAssert({-> assert_match('state: mSc; mode: n', term_getline(buf, 6))}, 1000)
- " A operator is pending
+ " An operator is pending
call term_sendkeys(buf, ":call RunTimer()\<CR>y")
call TermWait(buf, 25)
call term_sendkeys(buf, "y")
diff --git a/test/old/testdir/test_listdict.vim b/test/old/testdir/test_listdict.vim
index 0918e2cd98..fef7c6a9bc 100644
--- a/test/old/testdir/test_listdict.vim
+++ b/test/old/testdir/test_listdict.vim
@@ -346,7 +346,7 @@ func Test_dict_big()
endtry
call assert_equal('Vim(let):E716: "1500"', str)
- " lookup each items
+ " lookup each item
for i in range(1500)
call assert_equal(3000 - i, d[i])
endfor
diff --git a/test/old/testdir/test_normal.vim b/test/old/testdir/test_normal.vim
index 08a3c57a94..3c21041899 100644
--- a/test/old/testdir/test_normal.vim
+++ b/test/old/testdir/test_normal.vim
@@ -347,7 +347,7 @@ func Test_normal06_formatprg()
CheckNotMSWindows
" uses sed to number non-empty lines
- call writefile(['#!/bin/sh', 'sed ''/./=''|sed ''/./{', 'N', 's/\n/ /', '}'''], 'Xsed_format.sh')
+ call writefile(['#!/bin/sh', 'sed ''/./=''|sed ''/./{', 'N', 's/\n/ /', '}'''], 'Xsed_format.sh', 'D')
call system('chmod +x ./Xsed_format.sh')
let text = ['a', '', 'c', '', ' ', 'd', 'e']
let expected = ['1 a', '', '3 c', '', '5 ', '6 d', '7 e']
@@ -378,11 +378,10 @@ func Test_normal06_formatprg()
" clean up
set formatprg=
setlocal formatprg=
- call delete('Xsed_format.sh')
endfunc
func Test_normal07_internalfmt()
- " basic test for internal formmatter to textwidth of 12
+ " basic test for internal formatter to textwidth of 12
let list=range(1,11)
call map(list, 'v:val." "')
10new
@@ -2588,7 +2587,7 @@ func Test_normal33_g_cmd2()
exe "norm! G0\<c-v>4k4ly"
exe "norm! gvood"
call assert_equal(['', 'abfgh', 'abfgh', 'abfgh', 'fgh', 'fgh', 'fgh', 'fgh', 'fgh'], getline(1,'$'))
- " gv cannot be used in operator pending mode
+ " gv cannot be used in operator pending mode
call assert_beeps('normal! cgv')
" gv should beep without a previously selected visual area
new
diff --git a/test/old/testdir/test_substitute.vim b/test/old/testdir/test_substitute.vim
index a6640aac30..8dff0cda52 100644
--- a/test/old/testdir/test_substitute.vim
+++ b/test/old/testdir/test_substitute.vim
@@ -1425,4 +1425,18 @@ func Test_z_substitute_expr_leak()
delfunc SubExpr
endfunc
+func Test_substitute_expr_switch_win()
+ func R()
+ wincmd x
+ return 'XXXX'
+ endfunc
+ new Xfoobar
+ let bufnr = bufnr('%')
+ put ="abcdef"
+ silent! s/\%')/\=R()
+ call assert_fails(':%s/./\=R()/g', 'E565:')
+ delfunc R
+ exe bufnr .. "bw!"
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_vimscript.vim b/test/old/testdir/test_vimscript.vim
index 9b1b7f7b23..6ce59e1a2e 100644
--- a/test/old/testdir/test_vimscript.vim
+++ b/test/old/testdir/test_vimscript.vim
@@ -3109,7 +3109,7 @@ endfunc
" should be given.
"
" This test reuses the function MESSAGES() from the previous test.
-" This functions checks the messages in g:msgfile.
+" This function checks the messages in g:msgfile.
"-------------------------------------------------------------------------------
func Test_nested_while_error()
@@ -3236,7 +3236,7 @@ endfunc
" error messages should be given.
"
" This test reuses the function MESSAGES() from the previous test.
-" This functions checks the messages in g:msgfile.
+" This function checks the messages in g:msgfile.
"-------------------------------------------------------------------------------
func Test_nested_cont_break_error()
@@ -3344,7 +3344,7 @@ endfunc
" should be given.
"
" This test reuses the function MESSAGES() from the previous test.
-" This functions checks the messages in g:msgfile.
+" This function check the messages in g:msgfile.
"-------------------------------------------------------------------------------
func Test_nested_endtry_error()
diff --git a/test/old/testdir/test_virtualedit.vim b/test/old/testdir/test_virtualedit.vim
index f97b3f987d..6ff51e36fb 100644
--- a/test/old/testdir/test_virtualedit.vim
+++ b/test/old/testdir/test_virtualedit.vim
@@ -236,7 +236,7 @@ func Test_ve_completion()
set virtualedit=
endfunc
-" Using "C" then then <CR> moves the last remaining character to the next
+" Using "C" then <CR> moves the last remaining character to the next
" line. (Mary Ellen Foster)
func Test_ve_del_to_eol()
new
diff --git a/test/unit/helpers.lua b/test/unit/helpers.lua
index e9b97266d0..43b6980702 100644
--- a/test/unit/helpers.lua
+++ b/test/unit/helpers.lua
@@ -849,6 +849,16 @@ local function ptr2key(ptr)
return ffi.string(s)
end
+local function is_asan()
+ cimport('./src/nvim/version.h')
+ local status, res = pcall(function() return lib.version_cflags end)
+ if status then
+ return ffi.string(res):match('-fsanitize=[a-z,]*address')
+ else
+ return false
+ end
+end
+
local module = {
cimport = cimport,
cppimport = cppimport,
@@ -876,6 +886,7 @@ local module = {
ptr2addr = ptr2addr,
ptr2key = ptr2key,
debug_log = debug_log,
+ is_asan = is_asan,
}
module = global_helpers.tbl_extend('error', module, global_helpers)
return function()
diff --git a/test/unit/marktree_spec.lua b/test/unit/marktree_spec.lua
index 3c96bc5f58..32300c167c 100644
--- a/test/unit/marktree_spec.lua
+++ b/test/unit/marktree_spec.lua
@@ -87,13 +87,18 @@ local function dosplice(tree, shadow, start, old_extent, new_extent)
shadowsplice(shadow, start, old_extent, new_extent)
end
+local ns = 10
local last_id = nil
-local function put(tree, row, col, gravitate)
+local function put(tree, row, col, gravitate, end_row, end_col, end_gravitate)
last_id = last_id + 1
local my_id = last_id
- lib.marktree_put_test(tree, my_id, row, col, gravitate);
+ end_row = end_row or -1
+ end_col = end_col or -1
+ end_gravitate = end_gravitate or false
+
+ lib.marktree_put_test(tree, ns, my_id, row, col, gravitate, end_row, end_col, end_gravitate);
return my_id
end
@@ -102,7 +107,7 @@ describe('marktree', function()
last_id = 0
end)
- itp('works', function()
+ itp('works', function()
local tree = ffi.new("MarkTree[1]") -- zero initialized by luajit
local shadow = {}
local iter = ffi.new("MarkTreeIter[1]")
@@ -129,7 +134,7 @@ describe('marktree', function()
eq({}, id2pos)
for i,ipos in pairs(shadow) do
- local p = lib.marktree_lookup_ns(tree, -1, i, false, iter)
+ local p = lib.marktree_lookup_ns(tree, ns, i, false, iter)
eq(ipos[1], p.pos.row)
eq(ipos[2], p.pos.col)
local k = lib.marktree_itr_current(iter)
@@ -210,10 +215,224 @@ describe('marktree', function()
lib.marktree_itr_get(tree, 10, 10, iter)
lib.marktree_del_itr(tree, iter, false)
- eq(11, iter[0].node.key[iter[0].i].pos.col)
+ eq(11, iter[0].x.key[iter[0].i].pos.col)
lib.marktree_itr_get(tree, 11, 11, iter)
lib.marktree_del_itr(tree, iter, false)
- eq(12, iter[0].node.key[iter[0].i].pos.col)
- end)
+ eq(12, iter[0].x.key[iter[0].i].pos.col)
+ end)
+
+ itp("'intersect_mov' function works correctly", function()
+ local function mov(x, y, w)
+ local xa = ffi.new("uint64_t[?]", #x)
+ for i, xi in ipairs(x) do xa[i-1] = xi end
+ local ya = ffi.new("uint64_t[?]", #y)
+ for i, yi in ipairs(y) do ya[i-1] = yi end
+ local wa = ffi.new("uint64_t[?]", #w)
+ for i, wi in ipairs(w) do wa[i-1] = wi end
+
+ local dummy_size = #x + #y + #w
+ local wouta = ffi.new("uint64_t[?]", dummy_size)
+ local douta = ffi.new("uint64_t[?]", dummy_size)
+ local wsize = ffi.new("size_t[1]")
+ wsize[0] = dummy_size
+ local dsize = ffi.new("size_t[1]")
+ dsize[0] = dummy_size
+
+ local status = lib.intersect_mov_test(xa, #x, ya, #y, wa, #w, wouta, wsize, douta, dsize)
+ if status == 0 then error'wowza' end
+
+ local wout, dout = {}, {}
+ for i = 0,tonumber(wsize[0])-1 do table.insert(wout, tonumber(wouta[i])) end
+ for i = 0,tonumber(dsize[0])-1 do table.insert(dout, tonumber(douta[i])) end
+ return {wout, dout}
+ end
+
+ eq({{}, {}}, mov({}, {2, 3}, {2, 3}))
+ eq({{2, 3}, {}}, mov({}, {}, {2, 3}))
+ eq({{2, 3}, {}}, mov({2, 3}, {}, {}))
+ eq({{}, {2,3}}, mov({}, {2,3}, {}))
+
+ eq({{1, 5}, {}}, mov({1,2,5}, {2, 3}, {3}))
+ eq({{1, 2}, {}}, mov({1,2,5}, {5, 10}, {10}))
+ eq({{1, 2}, {5}}, mov({1,2}, {5, 10}, {10}))
+ eq({{1,3,5,7,9}, {2,4,6,8,10}}, mov({1,3,5,7,9}, {2,4,6,8,10}, {}))
+ eq({{1,3,5,7,9}, {2,6,10}}, mov({1,3,5,7,9}, {2,4,6,8,10}, {4, 8}))
+ eq({{1,4,7}, {2,5,8}}, mov({1,3,4,6,7,9}, {2,3,5,6,8,9}, {}))
+ eq({{1,4,7}, {}}, mov({1,3,4,6,7,9}, {2,3,5,6,8,9}, {2,5,8}))
+ eq({{0,1,4,7,10}, {}}, mov({1,3,4,6,7,9}, {2,3,5,6,8,9}, {0,2,5,8,10}))
+ end)
+
+
+ local function check_intersections(tree)
+ lib.marktree_check(tree)
+ -- to debug stuff disable this branch
+ if true == true then
+ ok(lib.marktree_check_intersections(tree))
+ return
+ end
+
+ local str1 = lib.mt_inspect(tree, true, true)
+ local dot1 = ffi.string(str1.data, str1.size)
+
+ local val = lib.marktree_check_intersections(tree)
+ if not val then
+ local str2 = lib.mt_inspect(tree, true, true)
+ local dot2 = ffi.string(str2.data, str2.size)
+ print("actual:\n\n".."Xafile.dot".."\n\nexpected:\n\n".."Xefile.dot".."\n")
+ print("nivå", tree[0].root.level);
+ io.stdout:flush()
+ local afil = io.open("Xafile.dot", "wb")
+ afil:write(dot1)
+ afil:close()
+ local efil = io.open("Xefile.dot", "wb")
+ efil:write(dot2)
+ efil:close()
+ ok(false)
+ else
+ ffi.C.xfree(str1.data)
+ end
+ end
+
+ itp('works with intersections', function()
+ local tree = ffi.new("MarkTree[1]") -- zero initialized by luajit
+
+ local ids = {}
+
+ for i = 1,80 do
+ table.insert(ids, put(tree, 1, i, false, 2, 100-i, false))
+ check_intersections(tree)
+ end
+ for i = 1,80 do
+ lib.marktree_del_pair_test(tree, ns, ids[i])
+ check_intersections(tree)
+ end
+ ids = {}
+
+ for i = 1,80 do
+ table.insert(ids, put(tree, 1, i, false, 2, 100-i, false))
+ check_intersections(tree)
+ end
+
+ for i = 1,10 do
+ for j = 1,8 do
+ local ival = (j-1)*10+i
+ lib.marktree_del_pair_test(tree, ns, ids[ival])
+ check_intersections(tree)
+ end
+ end
+ end)
+
+ itp('works with intersections with a big tree', function()
+ local tree = ffi.new("MarkTree[1]") -- zero initialized by luajit
+
+ local ids = {}
+
+ for i = 1,1000 do
+ table.insert(ids, put(tree, 1, i, false, 2, 1000-i, false))
+ if i % 10 == 1 then
+ check_intersections(tree)
+ end
+ end
+
+ check_intersections(tree)
+ eq(2000, tree[0].n_keys)
+ ok(tree[0].root.level >= 2)
+
+ local iter = ffi.new("MarkTreeIter[1]")
+
+ local k = 0
+ for i = 1,20 do
+ for j = 1,50 do
+ k = k + 1
+ local ival = (j-1)*20+i
+ if false == true then -- if there actually is a failure, this branch will fail out at the actual spot of the error
+ lib.marktree_lookup_ns(tree, ns, ids[ival], false, iter)
+ lib.marktree_del_itr(tree, iter, false)
+ check_intersections(tree)
+
+ lib.marktree_lookup_ns(tree, ns, ids[ival], true, iter)
+ lib.marktree_del_itr(tree, iter, false)
+ check_intersections(tree)
+ else
+ lib.marktree_del_pair_test(tree, ns, ids[ival])
+ if k % 5 == 1 then
+ check_intersections(tree)
+ end
+ end
+ end
+ end
+
+ eq(0, tree[0].n_keys)
+ end)
+
+ itp('works with intersections with a even bigger tree', function()
+ local tree = ffi.new("MarkTree[1]") -- zero initialized by luajit
+
+ local ids = {}
+
+ -- too much overhead on ASAN
+ local size_factor = helpers.is_asan() and 3 or 10
+
+ local at_row = {}
+ for i = 1, 10 do
+ at_row[i] = {}
+ end
+
+ local size = 1000*size_factor
+ local k = 1
+ while k <= size do
+ for row1 = 1,9 do
+ for row2 = row1,10 do -- note row2 can be == row1, leads to empty ranges being tested when k > size/2
+ if k > size then
+ break
+ end
+ local id = put(tree, row1, k, false, row2, size-k, false)
+ table.insert(ids, id)
+ for i = row1+1, row2 do
+ table.insert(at_row[i], id)
+ end
+ --if tree[0].root.level == 4 then error("kk"..k) end
+ if k % 100*size_factor == 1 or (k < 2000 and k%100 == 1) then
+ check_intersections(tree)
+ end
+ k = k + 1
+ end
+ end
+ end
+
+ eq(2*size, tree[0].n_keys)
+ ok(tree[0].root.level >= 3)
+ check_intersections(tree)
+
+ local iter = ffi.new("MarkTreeIter[1]")
+ local pair = ffi.new("MTPair[1]")
+ for i = 1,10 do
+ -- use array as set and not {[id]=true} map, to detect duplicates
+ local set = {}
+ eq(true, ffi.C.marktree_itr_get_overlap(tree, i, 0, iter))
+ while ffi.C.marktree_itr_step_overlap(tree, iter, pair) do
+ local id = tonumber(pair[0].start.id)
+ table.insert(set, id)
+ end
+ table.sort(set)
+ eq(at_row[i], set)
+ end
+
+ k = 0
+ for i = 1,100 do
+ for j = 1,(10*size_factor) do
+ k = k + 1
+ local ival = (j-1)*100+i
+ lib.marktree_del_pair_test(tree, ns, ids[ival])
+ -- just a few stickprov, if there is trouble we need to check
+ -- everyone using the code in the "big tree" case above
+ if k % 100*size_factor == 0 or (k > 3000 and k % 200 == 0) then
+ check_intersections(tree)
+ end
+ end
+ end
+
+ eq(0, tree[0].n_keys)
+ end)
end)