diff options
author | Josh Rahm <joshuarahm@gmail.com> | 2024-11-19 22:57:13 +0000 |
---|---|---|
committer | Josh Rahm <joshuarahm@gmail.com> | 2024-11-19 22:57:13 +0000 |
commit | 9be89f131f87608f224f0ee06d199fcd09d32176 (patch) | |
tree | 11022dcfa9e08cb4ac5581b16734196128688d48 /test/functional/api | |
parent | ff7ed8f586589d620a806c3758fac4a47a8e7e15 (diff) | |
parent | 88085c2e80a7e3ac29aabb6b5420377eed99b8b6 (diff) | |
download | rneovim-9be89f131f87608f224f0ee06d199fcd09d32176.tar.gz rneovim-9be89f131f87608f224f0ee06d199fcd09d32176.tar.bz2 rneovim-9be89f131f87608f224f0ee06d199fcd09d32176.zip |
Merge remote-tracking branch 'upstream/master' into mix_20240309
Diffstat (limited to 'test/functional/api')
-rw-r--r-- | test/functional/api/buffer_spec.lua | 117 | ||||
-rw-r--r-- | test/functional/api/buffer_updates_spec.lua | 6 | ||||
-rw-r--r-- | test/functional/api/extmark_spec.lua | 44 | ||||
-rw-r--r-- | test/functional/api/version_spec.lua | 14 | ||||
-rw-r--r-- | test/functional/api/vim_spec.lua | 515 | ||||
-rw-r--r-- | test/functional/api/window_spec.lua | 281 |
6 files changed, 556 insertions, 421 deletions
diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua index cf69958fd8..3775c8c7b7 100644 --- a/test/functional/api/buffer_spec.lua +++ b/test/functional/api/buffer_spec.lua @@ -125,11 +125,6 @@ describe('api/buf', function() it('cursor position is maintained consistently with viewport', function() local screen = Screen.new(20, 12) - screen:set_default_attr_ids { - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - [2] = { reverse = true, bold = true }, - [3] = { reverse = true }, - } screen:attach() local lines = { 'line1', 'line2', 'line3', 'line4', 'line5', 'line6' } @@ -143,11 +138,11 @@ describe('api/buf', function() grid = [[ ^ | {1:~ }|*4 - {2:[No Name] }| + {3:[No Name] }| line5 | line6 | {1:~ }|*2 - {3:[No Name] [+] }| + {2:[No Name] [+] }| | ]], } @@ -158,11 +153,11 @@ describe('api/buf', function() grid = [[ ^ | {1:~ }|*4 - {2:[No Name] }| + {3:[No Name] }| boogalo 5 | line6 | {1:~ }|*2 - {3:[No Name] [+] }| + {2:[No Name] [+] }| | ]], } @@ -172,11 +167,11 @@ describe('api/buf', function() grid = [[ | {1:~ }|*4 - {3:[No Name] }| + {2:[No Name] }| boogalo 5 | ^line6 | {1:~ }|*2 - {2:[No Name] [+] }| + {3:[No Name] [+] }| | ]], } @@ -216,11 +211,6 @@ describe('api/buf', function() local screen before_each(function() screen = Screen.new(20, 12) - screen:set_default_attr_ids { - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - [2] = { reverse = true, bold = true }, - [3] = { reverse = true }, - } screen:attach() api.nvim_buf_set_lines( 0, @@ -243,12 +233,12 @@ describe('api/buf', function() grid = [[ | {1:~ }|*4 - {3:[No Name] }| + {2:[No Name] }| www | xxx | yyy | ^zzz | - {2:[No Name] }| + {3:[No Name] }| | ]], } @@ -258,12 +248,12 @@ describe('api/buf', function() grid = [[ | {1:~ }|*4 - {3:[No Name] }| + {2:[No Name] }| www | xxx | yyy | ^zzz | - {2:[No Name] [+] }| + {3:[No Name] [+] }| | ]], } @@ -274,12 +264,12 @@ describe('api/buf', function() grid = [[ | {1:~ }|*4 - {3:[No Name] }| + {2:[No Name] }| wwweeee | xxx | yyy | ^zzz | - {2:[No Name] [+] }| + {3:[No Name] [+] }| | ]], } @@ -290,12 +280,12 @@ describe('api/buf', function() grid = [[ | {1:~ }|*4 - {3:[No Name] }| + {2:[No Name] }| wwweeee | xxx | yyy | ^zzz | - {2:[No Name] [+] }| + {3:[No Name] [+] }| | ]], unchanged = true, @@ -306,12 +296,12 @@ describe('api/buf', function() grid = [[ | {1:~ }|*4 - {3:[No Name] }| + {2:[No Name] }| wwweeee | xxx | ^yyy | zzz | - {2:[No Name] [+] }| + {3:[No Name] [+] }| | ]], } @@ -321,12 +311,12 @@ describe('api/buf', function() grid = [[ | {1:~ }|*4 - {3:[No Name] }| + {2:[No Name] }| mmmeeeee | wwweeee | xxx | ^yyy | - {2:[No Name] [+] }| + {3:[No Name] [+] }| | ]], } @@ -343,12 +333,12 @@ describe('api/buf', function() grid = [[ ^ | {1:~ }|*4 - {2:[No Name] }| + {3:[No Name] }| www | xxx | yyy | zzz | - {3:[No Name] }| + {2:[No Name] }| | ]], } @@ -358,12 +348,12 @@ describe('api/buf', function() grid = [[ ^ | {1:~ }|*4 - {2:[No Name] }| + {3:[No Name] }| www | xxx | yyy | zzz | - {3:[No Name] [+] }| + {2:[No Name] [+] }| | ]], } @@ -374,12 +364,12 @@ describe('api/buf', function() grid = [[ ^ | {1:~ }|*4 - {2:[No Name] }| + {3:[No Name] }| wwweeee | xxx | yyy | zzz | - {3:[No Name] [+] }| + {2:[No Name] [+] }| | ]], } @@ -389,12 +379,12 @@ describe('api/buf', function() grid = [[ ^ | {1:~ }|*4 - {2:[No Name] }| + {3:[No Name] }| wwweeee | xxx | yyy | zzz | - {3:[No Name] [+] }| + {2:[No Name] [+] }| | ]], unchanged = true, @@ -416,12 +406,12 @@ describe('api/buf', function() ccc | ddd | www | - {2:[No Name] }| + {3:[No Name] }| www | xxx | yyy | zzz | - {3:[No Name] }| + {2:[No Name] }| | ]], } @@ -434,12 +424,12 @@ describe('api/buf', function() ddd | www | xxx | - {2:[No Name] [+] }| + {3:[No Name] [+] }| www | xxx | yyy | zzz | - {3:[No Name] [+] }| + {2:[No Name] [+] }| | ]], } @@ -453,12 +443,12 @@ describe('api/buf', function() ddd | wwweeee | xxx | - {2:[No Name] [+] }| + {3:[No Name] [+] }| wwweeee | xxx | yyy | zzz | - {3:[No Name] [+] }| + {2:[No Name] [+] }| | ]], } @@ -471,12 +461,12 @@ describe('api/buf', function() ddd | mmm | wwweeee | - {2:[No Name] [+] }| + {3:[No Name] [+] }| wwweeee | xxx | yyy | zzz | - {3:[No Name] [+] }| + {2:[No Name] [+] }| | ]], } @@ -745,10 +735,6 @@ describe('api/buf', function() it("set_lines of invisible buffer doesn't move cursor in current window", function() local screen = Screen.new(20, 5) - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - [2] = { bold = true }, - }) screen:attach() insert([[ @@ -771,7 +757,7 @@ describe('api/buf', function() A real window | with proper tex^t | {1:~ }| - {2:-- INSERT --} | + {5:-- INSERT --} | ]]) end) @@ -1756,11 +1742,6 @@ describe('api/buf', function() local screen before_each(function() screen = Screen.new(20, 12) - screen:set_default_attr_ids { - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - [2] = { reverse = true, bold = true }, - [3] = { reverse = true }, - } screen:attach() api.nvim_buf_set_lines( 0, @@ -1783,12 +1764,12 @@ describe('api/buf', function() grid = [[ | {1:~ }|*4 - {3:[No Name] }| + {2:[No Name] }| www | xxx | yyy | ^zzz | - {2:[No Name] }| + {3:[No Name] }| | ]], } @@ -1798,12 +1779,12 @@ describe('api/buf', function() grid = [[ | {1:~ }|*4 - {3:[No Name] }| + {2:[No Name] }| www | xxx | yyy | ^zzz | - {2:[No Name] [+] }| + {3:[No Name] [+] }| | ]], } @@ -1820,12 +1801,12 @@ describe('api/buf', function() grid = [[ ^ | {1:~ }|*4 - {2:[No Name] }| + {3:[No Name] }| www | xxx | yyy | zzz | - {3:[No Name] }| + {2:[No Name] }| | ]], } @@ -1835,12 +1816,12 @@ describe('api/buf', function() grid = [[ ^ | {1:~ }|*4 - {2:[No Name] }| + {3:[No Name] }| www | xxx | yyy | zzz | - {3:[No Name] [+] }| + {2:[No Name] [+] }| | ]], } @@ -1861,12 +1842,12 @@ describe('api/buf', function() ccc | ddd | www | - {2:[No Name] }| + {3:[No Name] }| www | xxx | yyy | zzz | - {3:[No Name] }| + {2:[No Name] }| | ]], } @@ -1879,12 +1860,12 @@ describe('api/buf', function() ddd | www | xxx | - {2:[No Name] [+] }| + {3:[No Name] [+] }| www | xxx | yyy | zzz | - {3:[No Name] [+] }| + {2:[No Name] [+] }| | ]], } @@ -1910,6 +1891,8 @@ describe('api/buf', function() eq({ '' }, get_text(0, 0, 18, 0, 20, {})) eq({ 'ext' }, get_text(0, -2, 1, -2, 4, {})) eq({ 'hello foo!', 'text', 'm' }, get_text(0, 0, 0, 2, 1, {})) + eq({ 'hello foo!' }, get_text(0, 0, -987654321, 0, 987654321, {})) + eq({ '' }, get_text(0, 0, -15, 0, -20, {})) end) it('errors on out-of-range', function() @@ -1923,7 +1906,7 @@ describe('api/buf', function() it('errors when start is greater than end', function() eq("'start' is higher than 'end'", pcall_err(get_text, 0, 1, 0, 0, 0, {})) - eq('start_col must be less than end_col', pcall_err(get_text, 0, 0, 1, 0, 0, {})) + eq('start_col must be less than or equal to end_col', pcall_err(get_text, 0, 0, 1, 0, 0, {})) end) end) diff --git a/test/functional/api/buffer_updates_spec.lua b/test/functional/api/buffer_updates_spec.lua index e030b45396..527394bfd1 100644 --- a/test/functional/api/buffer_updates_spec.lua +++ b/test/functional/api/buffer_updates_spec.lua @@ -27,12 +27,10 @@ end local function sendkeys(keys) api.nvim_input(keys) - -- give nvim some time to process msgpack requests before possibly sending + -- Wait for Nvim to fully process pending input before possibly sending -- more key presses - otherwise they all pile up in the queue and get -- processed at once - local ntime = os.clock() + 0.1 - repeat - until os.clock() > ntime + n.poke_eventloop() end local function open(activate, lines) diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index 7b2fe209ba..52d8fd5097 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -1758,13 +1758,13 @@ describe('API/extmarks', function() command('1d 2') eq(0, #get_extmarks(-1, 0, -1, {})) -- mark is not removed when deleting bytes before the range - set_extmark( - ns, - 3, - 0, - 4, - { invalidate = true, undo_restore = false, hl_group = 'Error', end_col = 7 } - ) + set_extmark(ns, 3, 0, 4, { + invalidate = true, + undo_restore = true, + hl_group = 'Error', + end_col = 7, + right_gravity = false, + }) feed('dw') eq(3, get_extmark_by_id(ns, 3, { details = true })[3].end_col) -- mark is not removed when deleting bytes at the start of the range @@ -1778,15 +1778,18 @@ describe('API/extmarks', function() eq(1, get_extmark_by_id(ns, 3, { details = true })[3].end_col) -- mark is removed when all bytes in the range are deleted feed('hx') - eq({}, get_extmark_by_id(ns, 3, {})) + eq(true, get_extmark_by_id(ns, 3, { details = true })[3].invalid) + -- mark is restored with undo_restore == true if pos did not change + command('undo') + eq(nil, get_extmark_by_id(ns, 3, { details = true })[3].invalid) -- multiline mark is not removed when start of its range is deleted - set_extmark( - ns, - 4, - 1, - 4, - { undo_restore = false, invalidate = true, hl_group = 'Error', end_col = 7, end_row = 3 } - ) + set_extmark(ns, 4, 1, 4, { + undo_restore = false, + invalidate = true, + hl_group = 'Error', + end_col = 7, + end_row = 3, + }) feed('ddDdd') eq({ 0, 0 }, get_extmark_by_id(ns, 4, {})) -- multiline mark is removed when entirety of its range is deleted @@ -1795,10 +1798,15 @@ describe('API/extmarks', function() end) it('can set a URL', function() - set_extmark(ns, 1, 0, 0, { url = 'https://example.com', end_col = 3 }) + local url1 = 'https://example.com' + local url2 = 'http://127.0.0.1' + set_extmark(ns, 1, 0, 0, { url = url1, end_col = 3 }) + set_extmark(ns, 2, 0, 3, { url = url2, hl_group = 'Search', end_col = 5 }) local extmarks = get_extmarks(ns, 0, -1, { details = true }) - eq(1, #extmarks) - eq('https://example.com', extmarks[1][4].url) + eq(2, #extmarks) + eq(url1, extmarks[1][4].url) + eq(url2, extmarks[2][4].url) + eq('Search', extmarks[2][4].hl_group) end) it('respects priority', function() diff --git a/test/functional/api/version_spec.lua b/test/functional/api/version_spec.lua index 5dad9978b7..617786eb2d 100644 --- a/test/functional/api/version_spec.lua +++ b/test/functional/api/version_spec.lua @@ -58,10 +58,18 @@ describe('api metadata', function() return by_name end - -- Remove metadata that is not essential to backwards-compatibility. - local function filter_function_metadata(f) + -- Remove or patch metadata that is not essential to backwards-compatibility. + local function normalize_func_metadata(f) + -- Dictionary was renamed to Dict. That doesn't break back-compat because clients don't actually + -- use the `return_type` field (evidence: "ArrayOf(…)" didn't break clients). + f.return_type = f.return_type:gsub('Dictionary', 'Dict') + f.deprecated_since = nil for idx, _ in ipairs(f.parameters) do + -- Dictionary was renamed to Dict. Doesn't break back-compat because clients don't actually + -- use the `parameters` field of API metadata (evidence: "ArrayOf(…)" didn't break clients). + f.parameters[idx][1] = f.parameters[idx][1]:gsub('Dictionary', 'Dict') + f.parameters[idx][2] = '' -- Remove parameter name. end @@ -141,7 +149,7 @@ describe('api metadata', function() ) end else - eq(filter_function_metadata(f), filter_function_metadata(funcs_new[f.name])) + eq(normalize_func_metadata(f), normalize_func_metadata(funcs_new[f.name])) end end funcs_compat[level] = name_table(old_api[level].functions) diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index fd0535aa51..af4d4854f5 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -367,14 +367,11 @@ describe('API', function() it('displays messages when opts.output=false', function() local screen = Screen.new(40, 8) screen:attach() - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - }) api.nvim_exec2("echo 'hello'", { output = false }) screen:expect { grid = [[ ^ | - {0:~ }|*6 + {1:~ }|*6 hello | ]], } @@ -383,14 +380,11 @@ describe('API', function() it("doesn't display messages when output=true", function() local screen = Screen.new(40, 6) screen:attach() - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - }) api.nvim_exec2("echo 'hello'", { output = true }) screen:expect { grid = [[ ^ | - {0:~ }|*4 + {1:~ }|*4 | ]], } @@ -403,7 +397,7 @@ describe('API', function() screen:expect { grid = [[ ^ | - {0:~ }|*4 + {1:~ }|*4 15 | ]], } @@ -699,7 +693,7 @@ describe('API', function() pcall_err(request, 'nvim_call_dict_function', "{ 'f': '' }", 'f', { 1, 2 }) ) eq( - 'dict argument type must be String or Dictionary', + 'dict argument type must be String or Dict', pcall_err(request, 'nvim_call_dict_function', 42, 'f', { 1, 2 }) ) eq( @@ -1307,12 +1301,136 @@ describe('API', function() end) it('crlf=false does not break lines at CR, CRLF', function() api.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') + local expected = 'line 1\r\n\r\rline 2\nline 3\rline 4\r' + expect(expected) eq({ 0, 3, 14, 0 }, fn.getpos('.')) + feed('u') -- Undo. + expect('') + feed('.') -- Dot-repeat. + expect(expected) + end) + describe('repeating a paste via redo/recording', function() + -- Test with indent and control chars and multibyte chars containing 0x80 bytes + local text = dedent(([[ + foo + bar + baz + !!!%s!!!%s!!!%s!!! + 最…倒…倀… + ]]):format('\0', '\2\3\6\21\22\23\24\27', '\127')) + before_each(function() + api.nvim_set_option_value('autoindent', true, {}) + end) + local function test_paste_repeat_normal_insert(is_insert) + feed('qr' .. (is_insert and 'i' or '')) + eq('r', fn.reg_recording()) + api.nvim_paste(text, true, -1) + feed(is_insert and '<Esc>' or '') + expect(text) + feed('.') + expect(text:rep(2)) + feed('q') + eq('', fn.reg_recording()) + feed('3.') + expect(text:rep(5)) + feed('2@r') + expect(text:rep(9)) + end + it('works in Normal mode', function() + test_paste_repeat_normal_insert(false) + end) + it('works in Insert mode', function() + test_paste_repeat_normal_insert(true) + end) + local function test_paste_repeat_visual_select(is_select) + insert(('xxx\n'):rep(5)) + feed('ggqr' .. (is_select and 'gH' or 'V')) + api.nvim_paste(text, true, -1) + feed('q') + expect(text .. ('xxx\n'):rep(4)) + feed('2@r') + expect(text:rep(3) .. ('xxx\n'):rep(2)) + end + it('works in Visual mode (recording only)', function() + test_paste_repeat_visual_select(false) + end) + it('works in Select mode (recording only)', function() + test_paste_repeat_visual_select(true) + end) + end) + it('in a mapping recorded in a macro', function() + command([[nnoremap <F2> <Cmd>call nvim_paste('foo', v:false, -1)<CR>]]) + feed('qr<F2>$q') + expect('foo') + feed('@r') -- repeating a macro containing the mapping should only paste once + expect('foofoo') + end) + local function test_paste_cancel_error(is_error) + before_each(function() + exec_lua(([[ + vim.paste = (function(overridden) + return function(lines, phase) + for i, line in ipairs(lines) do + if line == 'CANCEL' then + %s + end + end + return overridden(lines, phase) + end + end)(vim.paste) + ]]):format(is_error and 'error("fake fail")' or 'return false')) + end) + local function check_paste_cancel_error(data, crlf, phase) + if is_error then + eq('fake fail', pcall_err(api.nvim_paste, data, crlf, phase)) + else + eq(false, api.nvim_paste(data, crlf, phase)) + end + end + it('in phase -1', function() + feed('A') + check_paste_cancel_error('CANCEL', true, -1) + feed('<Esc>') + expect('') + feed('.') + expect('') + end) + it('in phase 1', function() + feed('A') + check_paste_cancel_error('CANCEL', true, 1) + feed('<Esc>') + expect('') + feed('.') + expect('') + end) + it('in phase 2', function() + feed('A') + eq(true, api.nvim_paste('aaa', true, 1)) + expect('aaa') + check_paste_cancel_error('CANCEL', true, 2) + feed('<Esc>') + expect('aaa') + feed('.') + expect('aaaaaa') + end) + it('in phase 3', function() + feed('A') + eq(true, api.nvim_paste('aaa', true, 1)) + expect('aaa') + eq(true, api.nvim_paste('bbb', true, 2)) + expect('aaabbb') + check_paste_cancel_error('CANCEL', true, 3) + feed('<Esc>') + expect('aaabbb') + feed('.') + expect('aaabbbaaabbb') + end) + end + describe('vim.paste() cancel', function() + test_paste_cancel_error(false) end) - it('vim.paste() failure', function() - api.nvim_exec_lua('vim.paste = (function(lines, phase) error("fake fail") end)', {}) - eq('fake fail', pcall_err(request, 'nvim_paste', 'line 1\nline 2\nline 3', false, 1)) + describe('vim.paste() error', function() + test_paste_cancel_error(true) end) end) @@ -1441,6 +1559,28 @@ describe('API', function() it('cannot handle NULs', function() eq(0, api.nvim_strwidth('\0abc')) end) + + it('can handle emoji with variant selectors and ZWJ', function() + local selector = '❤️' + eq(2, fn.strchars(selector)) + eq(1, fn.strcharlen(selector)) + eq(2, api.nvim_strwidth(selector)) + + local no_selector = '❤' + eq(1, fn.strchars(no_selector)) + eq(1, fn.strcharlen(no_selector)) + eq(1, api.nvim_strwidth(no_selector)) + + local selector_zwj_selector = '🏳️⚧️' + eq(5, fn.strchars(selector_zwj_selector)) + eq(1, fn.strcharlen(selector_zwj_selector)) + eq(2, api.nvim_strwidth(selector_zwj_selector)) + + local emoji_zwj_emoji = '🧑🌾' + eq(3, fn.strchars(emoji_zwj_emoji)) + eq(1, fn.strcharlen(emoji_zwj_emoji)) + eq(2, api.nvim_strwidth(emoji_zwj_emoji)) + end) end) describe('nvim_get_current_line, nvim_set_current_line', function() @@ -1503,9 +1643,11 @@ describe('API', function() it('nvim_get_vvar, nvim_set_vvar', function() eq('Key is read-only: count', pcall_err(request, 'nvim_set_vvar', 'count', 42)) - eq('Dictionary is locked', pcall_err(request, 'nvim_set_vvar', 'nosuchvar', 42)) + eq('Dict is locked', pcall_err(request, 'nvim_set_vvar', 'nosuchvar', 42)) api.nvim_set_vvar('errmsg', 'set by API') eq('set by API', api.nvim_get_vvar('errmsg')) + api.nvim_set_vvar('completed_item', { word = 'a', user_data = vim.empty_dict() }) + eq({}, api.nvim_get_vvar('completed_item')['user_data']) api.nvim_set_vvar('errmsg', 42) eq('42', eval('v:errmsg')) api.nvim_set_vvar('oldfiles', { 'one', 'two' }) @@ -1533,16 +1675,12 @@ describe('API', function() eq({ 1, 5 }, api.nvim_win_get_cursor(0)) local screen = Screen.new(60, 3) - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - [1] = { background = Screen.colors.Yellow }, - }) screen:attach() eq(1, eval('v:hlsearch')) screen:expect { grid = [[ - {1:foo} {1:^foo} {1:foo} | - {0:~ }| + {10:foo} {10:^foo} {10:foo} | + {1:~ }| | ]], } @@ -1551,7 +1689,7 @@ describe('API', function() screen:expect { grid = [[ foo ^foo foo | - {0:~ }| + {1:~ }| | ]], } @@ -1559,8 +1697,8 @@ describe('API', function() eq(1, eval('v:hlsearch')) screen:expect { grid = [[ - {1:foo} {1:^foo} {1:foo} | - {0:~ }| + {10:foo} {10:^foo} {10:foo} | + {1:~ }| | ]], } @@ -1581,9 +1719,9 @@ describe('API', function() eq(val2, request('vim_del_var', 'lua')) end) - it('truncates values with NULs in them', function() + it('preserves values with NULs in them', function() api.nvim_set_var('xxx', 'ab\0cd') - eq('ab', api.nvim_get_var('xxx')) + eq('ab\000cd', api.nvim_get_var('xxx')) end) end) @@ -2144,7 +2282,7 @@ describe('API', function() end) describe('nvim_load_context', function() - it('sets current editor state to given context dictionary', function() + it('sets current editor state to given context dict', function() local opts = { types = { 'regs', 'jumps', 'bufs', 'gvars' } } eq({}, parse_context(api.nvim_get_context(opts))) @@ -2160,7 +2298,7 @@ describe('API', function() eq({ 1, 2, 3 }, eval('[g:one, g:Two, g:THREE]')) end) - it('errors when context dictionary is invalid', function() + it('errors when context dict is invalid', function() eq( 'E474: Failed to convert list to msgpack string buffer', pcall_err(api.nvim_load_context, { regs = { {} }, jumps = { {} } }) @@ -2254,12 +2392,6 @@ describe('API', function() before_each(function() screen = Screen.new(40, 8) screen:attach() - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - [1] = { bold = true, foreground = Screen.colors.SeaGreen }, - [2] = { bold = true, reverse = true }, - [3] = { foreground = Screen.colors.Blue }, - }) end) it('prints long messages correctly #20534', function() @@ -2287,11 +2419,11 @@ describe('API', function() screen:expect { grid = [[ | - {0:~ }|*3 - {2: }| + {1:~ }|*3 + {3: }| | a | - {1:Press ENTER or type command to continue}^ | + {6:Press ENTER or type command to continue}^ | ]], } feed('<CR>') @@ -2299,12 +2431,12 @@ describe('API', function() screen:expect { grid = [[ | - {0:~ }|*2 - {2: }| + {1:~ }|*2 + {3: }| b | | c | - {1:Press ENTER or type command to continue}^ | + {6:Press ENTER or type command to continue}^ | ]], } end) @@ -2314,11 +2446,11 @@ describe('API', function() screen:expect { grid = [[ | - {0:~ }|*3 - {2: }| - aaa{3:^@}bbb{3:^@^@}ccc | - ddd{3:^@^@^@}eee | - {1:Press ENTER or type command to continue}^ | + {1:~ }|*3 + {3: }| + aaa{18:^@}bbb{18:^@^@}ccc | + ddd{18:^@^@^@}eee | + {6:Press ENTER or type command to continue}^ | ]], } end) @@ -2330,20 +2462,14 @@ describe('API', function() before_each(function() screen = Screen.new(40, 8) screen:attach() - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - [1] = { foreground = Screen.colors.White, background = Screen.colors.Red }, - [2] = { bold = true, foreground = Screen.colors.SeaGreen }, - [3] = { bold = true, reverse = true }, - }) end) it('can show one line', function() async_meths.nvim_err_write('has bork\n') screen:expect([[ ^ | - {0:~ }|*6 - {1:has bork} | + {1:~ }|*6 + {9:has bork} | ]]) end) @@ -2351,11 +2477,11 @@ describe('API', function() async_meths.nvim_err_write('something happened\nvery bad\n') screen:expect([[ | - {0:~ }|*3 + {1:~ }|*3 {3: }| - {1:something happened} | - {1:very bad} | - {2:Press ENTER or type command to continue}^ | + {9:something happened} | + {9:very bad} | + {6:Press ENTER or type command to continue}^ | ]]) end) @@ -2363,13 +2489,13 @@ describe('API', function() async_meths.nvim_err_write('FAILURE\nERROR\nEXCEPTION\nTRACEBACK\n') screen:expect([[ | - {0:~ }| + {1:~ }| {3: }| - {1:FAILURE} | - {1:ERROR} | - {1:EXCEPTION} | - {1:TRACEBACK} | - {2:Press ENTER or type command to continue}^ | + {9:FAILURE} | + {9:ERROR} | + {9:EXCEPTION} | + {9:TRACEBACK} | + {6:Press ENTER or type command to continue}^ | ]]) end) @@ -2379,8 +2505,8 @@ describe('API', function() async_meths.nvim_err_write('fail\n') screen:expect([[ ^ | - {0:~ }|*6 - {1:very fail} | + {1:~ }|*6 + {9:very fail} | ]]) n.poke_eventloop() @@ -2388,11 +2514,11 @@ describe('API', function() async_meths.nvim_err_write('more fail\ntoo fail\n') screen:expect([[ | - {0:~ }|*3 + {1:~ }|*3 {3: }| - {1:more fail} | - {1:too fail} | - {2:Press ENTER or type command to continue}^ | + {9:more fail} | + {9:too fail} | + {6:Press ENTER or type command to continue}^ | ]]) feed('<cr>') -- exit the press ENTER screen end) @@ -2402,11 +2528,11 @@ describe('API', function() screen:expect { grid = [[ | - {0:~ }|*3 + {1:~ }|*3 {3: }| - {1:aaa^@bbb^@^@ccc} | - {1:ddd^@^@^@eee} | - {2:Press ENTER or type command to continue}^ | + {9:aaa^@bbb^@^@ccc} | + {9:ddd^@^@^@eee} | + {6:Press ENTER or type command to continue}^ | ]], } end) @@ -2418,30 +2544,24 @@ describe('API', function() before_each(function() screen = Screen.new(40, 8) screen:attach() - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - [1] = { foreground = Screen.colors.White, background = Screen.colors.Red }, - [2] = { bold = true, foreground = Screen.colors.SeaGreen }, - [3] = { bold = true, reverse = true }, - }) end) it('shows only one return prompt after all lines are shown', function() async_meths.nvim_err_writeln('FAILURE\nERROR\nEXCEPTION\nTRACEBACK') screen:expect([[ | - {0:~ }| + {1:~ }| {3: }| - {1:FAILURE} | - {1:ERROR} | - {1:EXCEPTION} | - {1:TRACEBACK} | - {2:Press ENTER or type command to continue}^ | + {9:FAILURE} | + {9:ERROR} | + {9:EXCEPTION} | + {9:TRACEBACK} | + {6:Press ENTER or type command to continue}^ | ]]) feed('<CR>') screen:expect([[ ^ | - {0:~ }|*6 + {1:~ }|*6 | ]]) end) @@ -2964,6 +3084,13 @@ describe('API', function() return ('%s(%s)%s'):format(typ, args, rest) end end + + it('does not crash parsing invalid VimL expression #29648', function() + api.nvim_input(':<C-r>=') + api.nvim_input('1bork/') + assert_alive() + end) + require('test.unit.viml.expressions.parser_tests')(it, _check_parsing, hl, fmtn) end) @@ -3102,9 +3229,6 @@ describe('API', function() eq(1, api.nvim_get_current_buf()) local screen = Screen.new(20, 4) - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - }) screen:attach() -- @@ -3201,7 +3325,7 @@ describe('API', function() end) describe('nvim_get_runtime_file', function() - local p = n.alter_slashes + local p = t.fix_slashes it('can find files', function() eq({}, api.nvim_get_runtime_file('bork.borkbork', false)) eq({}, api.nvim_get_runtime_file('bork.borkbork', true)) @@ -3210,36 +3334,36 @@ describe('API', function() local val = api.nvim_get_runtime_file('autoload/remote/*.vim', true) eq(2, #val) if endswith(val[1], 'define.vim') then - ok(endswith(val[1], p 'autoload/remote/define.vim')) - ok(endswith(val[2], p 'autoload/remote/host.vim')) + ok(endswith(p(val[1]), 'autoload/remote/define.vim')) + ok(endswith(p(val[2]), 'autoload/remote/host.vim')) else - ok(endswith(val[1], p 'autoload/remote/host.vim')) - ok(endswith(val[2], p 'autoload/remote/define.vim')) + ok(endswith(p(val[1]), 'autoload/remote/host.vim')) + ok(endswith(p(val[2]), 'autoload/remote/define.vim')) end val = api.nvim_get_runtime_file('autoload/remote/*.vim', false) eq(1, #val) ok( - endswith(val[1], p 'autoload/remote/define.vim') - or endswith(val[1], p 'autoload/remote/host.vim') + endswith(p(val[1]), 'autoload/remote/define.vim') + or endswith(p(val[1]), 'autoload/remote/host.vim') ) val = api.nvim_get_runtime_file('lua', true) eq(1, #val) - ok(endswith(val[1], p 'lua')) + ok(endswith(p(val[1]), 'lua')) val = api.nvim_get_runtime_file('lua/vim', true) eq(1, #val) - ok(endswith(val[1], p 'lua/vim')) + ok(endswith(p(val[1]), 'lua/vim')) end) it('can find directories', function() local val = api.nvim_get_runtime_file('lua/', true) eq(1, #val) - ok(endswith(val[1], p 'lua/')) + ok(endswith(p(val[1]), 'lua/')) val = api.nvim_get_runtime_file('lua/vim/', true) eq(1, #val) - ok(endswith(val[1], p 'lua/vim/')) + ok(endswith(p(val[1]), 'lua/vim/')) eq({}, api.nvim_get_runtime_file('foobarlang/', true)) end) @@ -3253,6 +3377,16 @@ describe('API', function() exc_exec("echo nvim_get_runtime_file('{', v:false)") ) end) + it('preserves order of runtimepath', function() + local vimruntime = fn.getenv('VIMRUNTIME') + local rtp = string.format('%s/syntax,%s/ftplugin', vimruntime, vimruntime) + api.nvim_set_option_value('runtimepath', rtp, {}) + + local val = api.nvim_get_runtime_file('vim.vim', true) + eq(2, #val) + eq(p(val[1]), vimruntime .. '/syntax/vim.vim') + eq(p(val[2]), vimruntime .. '/ftplugin/vim.vim') + end) end) describe('nvim_get_all_options_info', function() @@ -3458,13 +3592,6 @@ describe('API', function() before_each(function() screen = Screen.new(40, 8) screen:attach() - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - [1] = { bold = true, foreground = Screen.colors.SeaGreen }, - [2] = { bold = true, reverse = true }, - [3] = { foreground = Screen.colors.Brown, bold = true }, -- Statement - [4] = { foreground = Screen.colors.SlateBlue }, -- Special - }) command('highlight Statement gui=bold guifg=Brown') command('highlight Special guifg=SlateBlue') end) @@ -3474,7 +3601,7 @@ describe('API', function() screen:expect { grid = [[ ^ | - {0:~ }|*6 + {1:~ }|*6 msg | ]], } @@ -3489,8 +3616,8 @@ describe('API', function() screen:expect { grid = [[ ^ | - {0:~ }|*6 - msg_a{3:msg_b}{4:msg_c} | + {1:~ }|*6 + msg_a{15:msg_b}{16:msg_c} | ]], } end) @@ -3500,11 +3627,11 @@ describe('API', function() screen:expect { grid = [[ | - {0:~ }|*3 - {2: }| - {3:msg_a} | - {3:msg_a}{4:msg_b} | - {1:Press ENTER or type command to continue}^ | + {1:~ }|*3 + {3: }| + {15:msg_a} | + {15:msg_a}{16:msg_b} | + {6:Press ENTER or type command to continue}^ | ]], } end) @@ -3528,24 +3655,16 @@ describe('API', function() before_each(function() screen = Screen.new(100, 35) screen:attach() - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - [1] = { background = Screen.colors.Plum1 }, - [2] = { background = tonumber('0xffff40'), bg_indexed = true }, - [3] = { - background = Screen.colors.Plum1, - fg_indexed = true, - foreground = tonumber('0x00e000'), - }, - [4] = { bold = true, reverse = true, background = Screen.colors.Plum1 }, - [5] = { - foreground = Screen.colors.Blue, + screen:add_extra_attr_ids { + [100] = { background = tonumber('0xffff40'), bg_indexed = true }, + [101] = { background = Screen.colors.LightMagenta, - bold = true, + foreground = tonumber('0x00e000'), + fg_indexed = true, }, - [6] = { bold = true }, - [7] = { reverse = true, background = Screen.colors.LightMagenta }, - }) + [102] = { background = Screen.colors.LightMagenta, reverse = true }, + [103] = { background = Screen.colors.LightMagenta, bold = true, reverse = true }, + } end) it('can batch process sequences', function() @@ -3561,38 +3680,38 @@ describe('API', function() screen:expect { grid = [[ ^ | - {0:~}{1::smile }{0: }| - {0:~}{1: }{2:oooo$$$$$$$$$$$$oooo}{1: }{0: }| - {0:~}{1: }{2:oo$$$$$$$$$$$$$$$$$$$$$$$$o}{1: }{0: }| - {0:~}{1: }{2:oo$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$o}{1: }{2:o$}{1: }{2:$$}{1: }{2:o$}{1: }{0: }| - {0:~}{1: }{2:o}{1: }{2:$}{1: }{2:oo}{1: }{2:o$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$o}{1: }{2:$$}{1: }{2:$$}{1: }{2:$$o$}{1: }{0: }| - {0:~}{1: }{2:oo}{1: }{2:$}{1: }{2:$}{1: "}{2:$}{1: }{2:o$$$$$$$$$}{1: }{2:$$$$$$$$$$$$$}{1: }{2:$$$$$$$$$o}{1: }{2:$$$o$$o$}{1: }{0: }| - {0:~}{1: "}{2:$$$$$$o$}{1: }{2:o$$$$$$$$$}{1: }{2:$$$$$$$$$$$}{1: }{2:$$$$$$$$$$o}{1: }{2:$$$$$$$$}{1: }{0: }| - {0:~}{1: }{2:$$$$$$$}{1: }{2:$$$$$$$$$$$}{1: }{2:$$$$$$$$$$$}{1: }{2:$$$$$$$$$$$$$$$$$$$$$$$}{1: }{0: }| - {0:~}{1: }{2:$$$$$$$$$$$$$$$$$$$$$$$}{1: }{2:$$$$$$$$$$$$$}{1: }{2:$$$$$$$$$$$$$$}{1: """}{2:$$$}{1: }{0: }| - {0:~}{1: "}{2:$$$}{1:""""}{2:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1: "}{2:$$$}{1: }{0: }| - {0:~}{1: }{2:$$$}{1: }{2:o$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1: "}{2:$$$o}{1: }{0: }| - {0:~}{1: }{2:o$$}{1:" }{2:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1: }{2:$$$o}{1: }{0: }| - {0:~}{1: }{2:$$$}{1: }{2:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1:" "}{2:$$$$$$ooooo$$$$o}{1: }{0: }| - {0:~}{1: }{2:o$$$oooo$$$$$}{1: }{2:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1: }{2:o$$$$$$$$$$$$$$$$$}{1: }{0: }| - {0:~}{1: }{2:$$$$$$$$}{1:"}{2:$$$$}{1: }{2:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1: }{2:$$$$}{1:"""""""" }{0: }| - {0:~}{1: """" }{2:$$$$}{1: "}{2:$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1:" }{2:o$$$}{1: }{0: }| - {0:~}{1: "}{2:$$$o}{1: """}{2:$$$$$$$$$$$$$$$$$$}{1:"}{2:$$}{1:" }{2:$$$}{1: }{0: }| - {0:~}{1: }{2:$$$o}{1: "}{2:$$}{1:""}{2:$$$$$$}{1:"""" }{2:o$$$}{1: }{0: }| - {0:~}{1: }{2:$$$$o}{1: }{2:o$$$}{1:" }{0: }| - {0:~}{1: "}{2:$$$$o}{1: }{2:o$$$$$$o}{1:"}{2:$$$$o}{1: }{2:o$$$$}{1: }{0: }| - {0:~}{1: "}{2:$$$$$oo}{1: ""}{2:$$$$o$$$$$o}{1: }{2:o$$$$}{1:"" }{0: }| - {0:~}{1: ""}{2:$$$$$oooo}{1: "}{2:$$$o$$$$$$$$$}{1:""" }{0: }| - {0:~}{1: ""}{2:$$$$$$$oo}{1: }{2:$$$$$$$$$$}{1: }{0: }| - {0:~}{1: """"}{2:$$$$$$$$$$$}{1: }{0: }| - {0:~}{1: }{2:$$$$$$$$$$$$}{1: }{0: }| - {0:~}{1: }{2:$$$$$$$$$$}{1:" }{0: }| - {0:~}{1: "}{2:$$$}{1:"""" }{0: }| - {0:~}{1: }{0: }| - {0:~}{3:Press ENTER or type command to continue}{1: }{0: }| - {0:~}{4:term://~/config2/docs/pres//32693:vim --clean +smile 29,39 All}{0: }| - {0:~}{1::call nvim__screenshot("smile2.cat") }{0: }| - {0:~ }|*2 + {1:~}{4::smile }{1: }| + {1:~}{4: }{100:oooo$$$$$$$$$$$$oooo}{4: }{1: }| + {1:~}{4: }{100:oo$$$$$$$$$$$$$$$$$$$$$$$$o}{4: }{1: }| + {1:~}{4: }{100:oo$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$o}{4: }{100:o$}{4: }{100:$$}{4: }{100:o$}{4: }{1: }| + {1:~}{4: }{100:o}{4: }{100:$}{4: }{100:oo}{4: }{100:o$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$o}{4: }{100:$$}{4: }{100:$$}{4: }{100:$$o$}{4: }{1: }| + {1:~}{4: }{100:oo}{4: }{100:$}{4: }{100:$}{4: "}{100:$}{4: }{100:o$$$$$$$$$}{4: }{100:$$$$$$$$$$$$$}{4: }{100:$$$$$$$$$o}{4: }{100:$$$o$$o$}{4: }{1: }| + {1:~}{4: "}{100:$$$$$$o$}{4: }{100:o$$$$$$$$$}{4: }{100:$$$$$$$$$$$}{4: }{100:$$$$$$$$$$o}{4: }{100:$$$$$$$$}{4: }{1: }| + {1:~}{4: }{100:$$$$$$$}{4: }{100:$$$$$$$$$$$}{4: }{100:$$$$$$$$$$$}{4: }{100:$$$$$$$$$$$$$$$$$$$$$$$}{4: }{1: }| + {1:~}{4: }{100:$$$$$$$$$$$$$$$$$$$$$$$}{4: }{100:$$$$$$$$$$$$$}{4: }{100:$$$$$$$$$$$$$$}{4: """}{100:$$$}{4: }{1: }| + {1:~}{4: "}{100:$$$}{4:""""}{100:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{4: "}{100:$$$}{4: }{1: }| + {1:~}{4: }{100:$$$}{4: }{100:o$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{4: "}{100:$$$o}{4: }{1: }| + {1:~}{4: }{100:o$$}{4:" }{100:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{4: }{100:$$$o}{4: }{1: }| + {1:~}{4: }{100:$$$}{4: }{100:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{4:" "}{100:$$$$$$ooooo$$$$o}{4: }{1: }| + {1:~}{4: }{100:o$$$oooo$$$$$}{4: }{100:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{4: }{100:o$$$$$$$$$$$$$$$$$}{4: }{1: }| + {1:~}{4: }{100:$$$$$$$$}{4:"}{100:$$$$}{4: }{100:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{4: }{100:$$$$}{4:"""""""" }{1: }| + {1:~}{4: """" }{100:$$$$}{4: "}{100:$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{4:" }{100:o$$$}{4: }{1: }| + {1:~}{4: "}{100:$$$o}{4: """}{100:$$$$$$$$$$$$$$$$$$}{4:"}{100:$$}{4:" }{100:$$$}{4: }{1: }| + {1:~}{4: }{100:$$$o}{4: "}{100:$$}{4:""}{100:$$$$$$}{4:"""" }{100:o$$$}{4: }{1: }| + {1:~}{4: }{100:$$$$o}{4: }{100:o$$$}{4:" }{1: }| + {1:~}{4: "}{100:$$$$o}{4: }{100:o$$$$$$o}{4:"}{100:$$$$o}{4: }{100:o$$$$}{4: }{1: }| + {1:~}{4: "}{100:$$$$$oo}{4: ""}{100:$$$$o$$$$$o}{4: }{100:o$$$$}{4:"" }{1: }| + {1:~}{4: ""}{100:$$$$$oooo}{4: "}{100:$$$o$$$$$$$$$}{4:""" }{1: }| + {1:~}{4: ""}{100:$$$$$$$oo}{4: }{100:$$$$$$$$$$}{4: }{1: }| + {1:~}{4: """"}{100:$$$$$$$$$$$}{4: }{1: }| + {1:~}{4: }{100:$$$$$$$$$$$$}{4: }{1: }| + {1:~}{4: }{100:$$$$$$$$$$}{4:" }{1: }| + {1:~}{4: "}{100:$$$}{4:"""" }{1: }| + {1:~}{4: }{1: }| + {1:~}{101:Press ENTER or type command to continue}{4: }{1: }| + {1:~}{103:term://~/config2/docs/pres//32693:vim --clean +smile 29,39 All}{1: }| + {1:~}{4::call nvim__screenshot("smile2.cat") }{1: }| + {1:~ }|*2 | ]], } @@ -3624,9 +3743,9 @@ describe('API', function() screen:expect { grid = [[ | - {0:~}{1:^ }{0: }| - {0:~}{1: }{0: }|*4 - {0:~ }|*3 + {1:~}{4:^ }{1: }| + {1:~}{4: }{1: }|*4 + {1:~ }|*3 | ]], } @@ -3635,10 +3754,10 @@ describe('API', function() screen:expect { grid = [[ | - {0:~}{7: }{1: }{0: }| - {0:~}{1: }{0: }|*4 - {0:~ }|*3 - {6:-- TERMINAL --} | + {1:~}{102: }{4: }{1: }| + {1:~}{4: }{1: }|*4 + {1:~ }|*3 + {5:-- TERMINAL --} | ]], } @@ -3651,10 +3770,10 @@ describe('API', function() screen:expect { grid = [[ | - {0:~}{1:herrejösses!}{7: }{1: }{0: }| - {0:~}{1: }{0: }|*4 - {0:~ }|*3 - {6:-- TERMINAL --} | + {1:~}{4:herrejösses!}{102: }{4: }{1: }| + {1:~}{4: }{1: }|*4 + {1:~ }|*3 + {5:-- TERMINAL --} | ]], } eq('ba\024blaherrejösses!', exec_lua [[ return stream ]]) @@ -3933,11 +4052,11 @@ describe('API', function() )) eq( { - str = '3 ', - width = 2, + str = ' 3 ', + width = 9, highlights = { { group = 'LineNr', start = 0 }, - { group = 'ErrorMsg', start = 1 }, + { group = 'ErrorMsg', start = 8 }, }, }, api.nvim_eval_statusline('%l%#ErrorMsg# ', { use_statuscol_lnum = 3, highlights = true }) @@ -4472,10 +4591,6 @@ describe('API', function() end) it('does not interfere with printing line in Ex mode #19400', function() local screen = Screen.new(60, 7) - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText - [1] = { bold = true, reverse = true }, -- MsgSeparator - }) screen:attach() insert([[ foo @@ -4484,8 +4599,8 @@ describe('API', function() screen:expect([[ foo | bar | - {0:~ }|*2 - {1: }| + {1:~ }|*2 + {3: }| Entering Ex mode. Type "visual" to go to Normal mode. | :1^ | ]]) @@ -4494,7 +4609,7 @@ describe('API', function() screen:expect([[ foo | bar | - {1: }| + {3: }| Entering Ex mode. Type "visual" to go to Normal mode. | :1 | foo | @@ -4934,14 +5049,11 @@ describe('API', function() it("doesn't display messages when output=true", function() local screen = Screen.new(40, 6) screen:attach() - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - }) api.nvim_cmd({ cmd = 'echo', args = { [['hello']] } }, { output = true }) screen:expect { grid = [[ ^ | - {0:~ }|*4 + {1:~ }|*4 | ]], } @@ -4954,7 +5066,7 @@ describe('API', function() screen:expect { grid = [[ ^ | - {0:~ }|*4 + {1:~ }|*4 15 | ]], } @@ -5020,12 +5132,29 @@ describe('API', function() it('nvim__redraw', function() local screen = Screen.new(60, 5) screen:attach() - local win = api.nvim_get_current_win() eq('at least one action required', pcall_err(api.nvim__redraw, {})) eq('at least one action required', pcall_err(api.nvim__redraw, { buf = 0 })) eq('at least one action required', pcall_err(api.nvim__redraw, { win = 0 })) eq("cannot use both 'buf' and 'win'", pcall_err(api.nvim__redraw, { buf = 0, win = 0 })) + local win = api.nvim_get_current_win() + -- Can move cursor to recently opened window and window is flushed #28868 feed(':echo getchar()<CR>') + local newwin = api.nvim_open_win(0, false, { + relative = 'editor', + width = 1, + height = 1, + row = 1, + col = 10, + }) + api.nvim__redraw({ win = newwin, cursor = true }) + screen:expect({ + grid = [[ + | + {1:~ }{4:^ }{1: }| + {1:~ }|*2 + :echo getchar() | + ]], + }) fn.setline(1, 'foobar') command('vnew') fn.setline(1, 'foobaz') @@ -5034,11 +5163,13 @@ describe('API', function() screen:expect({ grid = [[ foobaz │foobar | - {1:~ }│{1:~ }|*2 + {1:~ }{4:^f}{1: }│{1:~ }| + {1:~ }│{1:~ }| {3:[No Name] [+] }{2:[No Name] [+] }| - ^:echo getchar() | + :echo getchar() | ]], }) + api.nvim_win_close(newwin, true) -- Can update the grid cursor position #20793 api.nvim__redraw({ cursor = true }) screen:expect({ diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua index 15b9b0945c..5ce93f9e04 100644 --- a/test/functional/api/window_spec.lua +++ b/test/functional/api/window_spec.lua @@ -85,7 +85,7 @@ describe('API/win', function() [[ local cmdwin_buf = vim.api.nvim_get_current_buf() local new_win, new_buf = ... - vim.api.nvim_buf_call(new_buf, function() + vim._with({buf = new_buf}, function() vim.api.nvim_win_set_buf(new_win, cmdwin_buf) end) ]], @@ -100,7 +100,7 @@ describe('API/win', function() [[ local cmdwin_win = vim.api.nvim_get_current_win() local new_win, new_buf = ... - vim.api.nvim_win_call(new_win, function() + vim._with({win = new_win}, function() vim.api.nvim_win_set_buf(cmdwin_win, new_buf) end) ]], @@ -164,17 +164,12 @@ describe('API/win', function() eq('typing\n some dumb text', curbuf_contents()) end) - it('does not leak memory when using invalid window ID with invalid pos', function() + it('no memory leak when using invalid window ID with invalid pos', function() eq('Invalid window id: 1', pcall_err(api.nvim_win_set_cursor, 1, { 'b\na' })) end) it('updates the screen, and also when the window is unfocused', function() local screen = Screen.new(30, 9) - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue }, - [2] = { bold = true, reverse = true }, - [3] = { reverse = true }, - }) screen:attach() insert('prologue') @@ -221,10 +216,10 @@ describe('API/win', function() grid = [[ ^ | {1:~ }|*2 - {2:[No Name] }| + {3:[No Name] }| prologue | |*2 - {3:[No Name] [+] }| + {2:[No Name] [+] }| | ]], } @@ -235,10 +230,10 @@ describe('API/win', function() grid = [[ ^ | {1:~ }|*2 - {2:[No Name] }| + {3:[No Name] }| |*2 epilogue | - {3:[No Name] [+] }| + {2:[No Name] [+] }| | ]], } @@ -249,10 +244,10 @@ describe('API/win', function() grid = [[ ^ | {1:~ }|*2 - {2:[No Name] }| + {3:[No Name] }| prologue | |*2 - {3:[No Name] [+] }| + {2:[No Name] [+] }| | ]], } @@ -286,12 +281,6 @@ describe('API/win', function() it('updates cursorline and statusline ruler in non-current window', function() local screen = Screen.new(60, 8) - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue }, -- NonText - [2] = { background = Screen.colors.Grey90 }, -- CursorLine - [3] = { bold = true, reverse = true }, -- StatusLine - [4] = { reverse = true }, -- StatusLineNC - }) screen:attach() command('set ruler') command('set cursorline') @@ -306,31 +295,25 @@ describe('API/win', function() aaa │aaa | bbb │bbb | ccc │ccc | - {2:dd^d }│{2:ddd }| + {21:dd^d }│{21:ddd }| {1:~ }│{1:~ }|*2 - {3:[No Name] [+] 4,3 All }{4:[No Name] [+] 4,3 All}| + {3:[No Name] [+] 4,3 All }{2:[No Name] [+] 4,3 All}| | ]]) api.nvim_win_set_cursor(oldwin, { 1, 0 }) screen:expect([[ - aaa │{2:aaa }| + aaa │{21:aaa }| bbb │bbb | ccc │ccc | - {2:dd^d }│ddd | + {21:dd^d }│ddd | {1:~ }│{1:~ }|*2 - {3:[No Name] [+] 4,3 All }{4:[No Name] [+] 1,1 All}| + {3:[No Name] [+] 4,3 All }{2:[No Name] [+] 1,1 All}| | ]]) end) it('updates cursorcolumn in non-current window', function() local screen = Screen.new(60, 8) - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue }, -- NonText - [2] = { background = Screen.colors.Grey90 }, -- CursorColumn - [3] = { bold = true, reverse = true }, -- StatusLine - [4] = { reverse = true }, -- StatusLineNC - }) screen:attach() command('set cursorcolumn') insert([[ @@ -341,22 +324,22 @@ describe('API/win', function() local oldwin = curwin() command('vsplit') screen:expect([[ - aa{2:a} │aa{2:a} | - bb{2:b} │bb{2:b} | - cc{2:c} │cc{2:c} | + aa{21:a} │aa{21:a} | + bb{21:b} │bb{21:b} | + cc{21:c} │cc{21:c} | dd^d │ddd | {1:~ }│{1:~ }|*2 - {3:[No Name] [+] }{4:[No Name] [+] }| + {3:[No Name] [+] }{2:[No Name] [+] }| | ]]) api.nvim_win_set_cursor(oldwin, { 2, 0 }) screen:expect([[ - aa{2:a} │{2:a}aa | - bb{2:b} │bbb | - cc{2:c} │{2:c}cc | - dd^d │{2:d}dd | + aa{21:a} │{21:a}aa | + bb{21:b} │bbb | + cc{21:c} │{21:c}cc | + dd^d │{21:d}dd | {1:~ }│{1:~ }|*2 - {3:[No Name] [+] }{4:[No Name] [+] }| + {3:[No Name] [+] }{2:[No Name] [+] }| | ]]) end) @@ -655,7 +638,7 @@ describe('API/win', function() feed('q:') exec_lua( [[ - vim.api.nvim_win_call(..., function() + vim._with({win = ...}, function() vim.api.nvim_win_close(0, true) end) ]], @@ -674,7 +657,7 @@ describe('API/win', function() exec_lua( [[ local otherwin, cmdwin = ... - vim.api.nvim_win_call(otherwin, function() + vim._with({win = otherwin}, function() vim.api.nvim_win_close(cmdwin, true) end) ]], @@ -788,7 +771,7 @@ describe('API/win', function() }) exec_lua( [[ - vim.api.nvim_win_call(..., function() + vim._with({win = ...}, function() vim.api.nvim_win_hide(0) end) ]], @@ -807,7 +790,7 @@ describe('API/win', function() exec_lua( [[ local otherwin, cmdwin = ... - vim.api.nvim_win_call(otherwin, function() + vim._with({win = otherwin}, function() vim.api.nvim_win_hide(cmdwin) end) ]], @@ -874,22 +857,6 @@ describe('API/win', function() it('with two diff windows', function() local X = api.nvim_get_vvar('maxcol') local screen = Screen.new(45, 22) - screen:set_default_attr_ids({ - [0] = { foreground = Screen.colors.Blue1, bold = true }, - [1] = { foreground = Screen.colors.Blue4, background = Screen.colors.Grey }, - [2] = { foreground = Screen.colors.Brown }, - [3] = { - foreground = Screen.colors.Blue1, - background = Screen.colors.LightCyan1, - bold = true, - }, - [4] = { background = Screen.colors.LightBlue }, - [5] = { foreground = Screen.colors.Blue4, background = Screen.colors.LightGrey }, - [6] = { background = Screen.colors.Plum1 }, - [7] = { background = Screen.colors.Red, bold = true }, - [8] = { reverse = true }, - [9] = { bold = true, reverse = true }, - }) screen:attach() exec([[ set diffopt+=context:2 number @@ -902,35 +869,35 @@ describe('API/win', function() feed('24gg') screen:expect { grid = [[ - {1: }{2: }{3:----------------}│{1: }{2: 1 }{4:00000001! }| - {1: }{2: }{3:----------------}│{1: }{2: 2 }{4:00000002!! }| - {1: }{2: 1 }00000003!!! │{1: }{2: 3 }00000003!!! | - {1: }{2: 2 }00000004!!!! │{1: }{2: 4 }00000004!!!! | - {1:+ }{2: 3 }{5:+-- 14 lines: 00}│{1:+ }{2: 5 }{5:+-- 14 lines: 00}| - {1: }{2: 17 }00000019!!!!!!!!│{1: }{2: 19 }00000019!!!!!!!!| - {1: }{2: 18 }00000020!!!!!!!!│{1: }{2: 20 }00000020!!!!!!!!| - {1: }{2: }{3:----------------}│{1: }{2: 21 }{4:00000025!!!!!!!!}| - {1: }{2: }{3:----------------}│{1: }{2: 22 }{4:00000026!!!!!!!!}| - {1: }{2: }{3:----------------}│{1: }{2: 23 }{4:00000027!!!!!!!!}| - {1: }{2: 19 }00000028!!!!!!!!│{1: }{2: 24 }^00000028!!!!!!!!| - {1: }{2: 20 }00000029!!!!!!!!│{1: }{2: 25 }00000029!!!!!!!!| - {1:+ }{2: 21 }{5:+-- 14 lines: 00}│{1:+ }{2: 26 }{5:+-- 14 lines: 00}| - {1: }{2: 35 }00000044!!!!!!!!│{1: }{2: 40 }00000044!!!!!!!!| - {1: }{2: 36 }00000045!!!!!!!!│{1: }{2: 41 }00000045!!!!!!!!| - {1: }{2: 37 }{4:00000046!!!!!!!!}│{1: }{2: }{3:----------------}| - {1: }{2: 38 }{4:00000047!!!!!!!!}│{1: }{2: }{3:----------------}| - {1: }{2: 39 }{4:00000048!!!!!!!!}│{1: }{2: }{3:----------------}| - {1: }{2: 40 }{4:00000049!!!!!!!!}│{1: }{2: }{3:----------------}| - {1: }{2: 41 }{4:00000050!!!!!!!!}│{1: }{2: }{3:----------------}| - {8:[No Name] [+] }{9:[No Name] [+] }| + {7: }{8: }{23:----------------}│{7: }{8: 1 }{22:00000001! }| + {7: }{8: }{23:----------------}│{7: }{8: 2 }{22:00000002!! }| + {7: }{8: 1 }00000003!!! │{7: }{8: 3 }00000003!!! | + {7: }{8: 2 }00000004!!!! │{7: }{8: 4 }00000004!!!! | + {7:+ }{8: 3 }{13:+-- 14 lines: 00}│{7:+ }{8: 5 }{13:+-- 14 lines: 00}| + {7: }{8: 17 }00000019!!!!!!!!│{7: }{8: 19 }00000019!!!!!!!!| + {7: }{8: 18 }00000020!!!!!!!!│{7: }{8: 20 }00000020!!!!!!!!| + {7: }{8: }{23:----------------}│{7: }{8: 21 }{22:00000025!!!!!!!!}| + {7: }{8: }{23:----------------}│{7: }{8: 22 }{22:00000026!!!!!!!!}| + {7: }{8: }{23:----------------}│{7: }{8: 23 }{22:00000027!!!!!!!!}| + {7: }{8: 19 }00000028!!!!!!!!│{7: }{8: 24 }^00000028!!!!!!!!| + {7: }{8: 20 }00000029!!!!!!!!│{7: }{8: 25 }00000029!!!!!!!!| + {7:+ }{8: 21 }{13:+-- 14 lines: 00}│{7:+ }{8: 26 }{13:+-- 14 lines: 00}| + {7: }{8: 35 }00000044!!!!!!!!│{7: }{8: 40 }00000044!!!!!!!!| + {7: }{8: 36 }00000045!!!!!!!!│{7: }{8: 41 }00000045!!!!!!!!| + {7: }{8: 37 }{22:00000046!!!!!!!!}│{7: }{8: }{23:----------------}| + {7: }{8: 38 }{22:00000047!!!!!!!!}│{7: }{8: }{23:----------------}| + {7: }{8: 39 }{22:00000048!!!!!!!!}│{7: }{8: }{23:----------------}| + {7: }{8: 40 }{22:00000049!!!!!!!!}│{7: }{8: }{23:----------------}| + {7: }{8: 41 }{22:00000050!!!!!!!!}│{7: }{8: }{23:----------------}| + {2:[No Name] [+] }{3:[No Name] [+] }| | ]], } screen:try_resize(45, 3) screen:expect { grid = [[ - {1: }{2: 19 }00000028!!!!!!!!│{1: }{2: 24 }^00000028!!!!!!!!| - {8:[No Name] [+] }{9:[No Name] [+] }| + {7: }{8: 19 }00000028!!!!!!!!│{7: }{8: 24 }^00000028!!!!!!!!| + {2:[No Name] [+] }{3:[No Name] [+] }| | ]], } @@ -1008,11 +975,6 @@ describe('API/win', function() it('with wrapped lines', function() local X = api.nvim_get_vvar('maxcol') local screen = Screen.new(45, 22) - screen:set_default_attr_ids({ - [0] = { foreground = Screen.colors.Blue1, bold = true }, - [1] = { foreground = Screen.colors.Brown }, - [2] = { background = Screen.colors.Yellow }, - }) screen:attach() exec([[ set number cpoptions+=n @@ -1035,26 +997,26 @@ describe('API/win', function() ) screen:expect { grid = [[ - {1: 1 }^foobar-foobar-foobar-foobar-foobar-foobar| + {8: 1 }^foobar-foobar-foobar-foobar-foobar-foobar| -foobar-foobar-foobar-foobar-foobar-foobar-fo| obar-foobar-foobar-foobar-foobar-foobar-fooba| r-foobar-foobar-foobar-foobar-foobar-foobar-f| oobar-foobar-foobar-foobar-foobar-foobar-foob| ar-foobar-foobar-foobar-foobar- | - {1: 2 }foobar-foobar-foobar-foobar-foobar-foobar| + {8: 2 }foobar-foobar-foobar-foobar-foobar-foobar| -foobar-foobar-foobar-foobar-foobar-foobar-fo| - obar-foobar-fo{2:???????????????}obar-foobar-foob| + obar-foobar-fo{10:???????????????}obar-foobar-foob| ar-foobar-foobar-foobar-foobar-foobar-foobar-| foobar-foobar-foobar-foobar-foobar-foobar-foo| bar-foobar-foobar-foobar-foobar-foobar-foobar| - | - {1: 3 }foobar-foobar-foobar-foobar-foobar-foobar| + {8: 3 }foobar-foobar-foobar-foobar-foobar-foobar| -foobar-foobar-foobar-foobar-foobar-foobar-fo| obar-foobar-foobar-foobar-foobar-foobar-fooba| r-foobar-foobar-foobar-foobar-foobar-foobar-f| - oobar-foobar-foobar-foob{2:!!!!!!!!!!!!!!!!!!!!!}| - {2:!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!}| - {2:!!!!!!!!!}ar-foobar-foobar-foobar-foobar-fooba| + oobar-foobar-foobar-foob{10:!!!!!!!!!!!!!!!!!!!!!}| + {10:!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!}| + {10:!!!!!!!!!}ar-foobar-foobar-foobar-foobar-fooba| r-foobar-foobar- | | ]], @@ -1062,7 +1024,7 @@ describe('API/win', function() screen:try_resize(45, 2) screen:expect { grid = [[ - {1: 1 }^foobar-foobar-foobar-foobar-foobar-foobar| + {8: 1 }^foobar-foobar-foobar-foobar-foobar-foobar| | ]], } @@ -1216,7 +1178,7 @@ describe('API/win', function() exec_lua, [[ local cmdwin_buf = vim.api.nvim_get_current_buf() - vim.api.nvim_buf_call(vim.api.nvim_create_buf(false, true), function() + vim._with({buf = vim.api.nvim_create_buf(false, true)}, function() vim.api.nvim_open_win(cmdwin_buf, false, { relative='editor', row=5, col=5, width=5, height=5, }) @@ -1847,6 +1809,38 @@ describe('API/win', function() eq(topdir .. '/Xacd', fn.getcwd()) end) end) + + it('no memory leak with valid title and invalid footer', function() + eq( + 'title/footer must be string or array', + pcall_err(api.nvim_open_win, 0, false, { + relative = 'editor', + row = 10, + col = 10, + height = 10, + width = 10, + border = 'single', + title = { { 'TITLE' } }, + footer = 0, + }) + ) + end) + + it('no memory leak with invalid title and valid footer', function() + eq( + 'title/footer must be string or array', + pcall_err(api.nvim_open_win, 0, false, { + relative = 'editor', + row = 10, + col = 10, + height = 10, + width = 10, + border = 'single', + title = 0, + footer = { { 'FOOTER' } }, + }) + ) + end) end) describe('set_config', function() @@ -2563,10 +2557,6 @@ describe('API/win', function() it('updates statusline when moving bottom split', function() local screen = Screen.new(10, 10) - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText - [1] = { bold = true, reverse = true }, -- StatusLine - }) screen:attach() exec([[ set laststatus=0 @@ -2575,10 +2565,10 @@ describe('API/win', function() ]]) screen:expect([[ ^ | - {0:~ }|*3 - {1:[No Name] }| + {1:~ }|*3 + {3:[No Name] }| | - {0:~ }|*3 + {1:~ }|*3 | ]]) end) @@ -2807,61 +2797,35 @@ describe('API/win', function() border = 'single', }) eq( - 'title/footer cannot be an empty array', - pcall_err(api.nvim_win_set_config, win, { title = {} }) + 'title/footer must be string or array', + pcall_err(api.nvim_win_set_config, win, { title = 0 }) ) command('redraw!') assert_alive() - end) - - it('no crash with invalid footer', function() - local win = api.nvim_open_win(0, true, { - width = 10, - height = 10, - relative = 'editor', - row = 10, - col = 10, - footer = { { 'test' } }, - border = 'single', - }) eq( 'title/footer cannot be an empty array', - pcall_err(api.nvim_win_set_config, win, { footer = {} }) + pcall_err(api.nvim_win_set_config, win, { title = {} }) ) command('redraw!') assert_alive() end) - end) - describe('set_config', function() - it('no crash with invalid title', function() + it('no crash with invalid footer', function() local win = api.nvim_open_win(0, true, { width = 10, height = 10, relative = 'editor', row = 10, col = 10, - title = { { 'test' } }, + footer = { { 'test' } }, border = 'single', }) eq( - 'title/footer cannot be an empty array', - pcall_err(api.nvim_win_set_config, win, { title = {} }) + 'title/footer must be string or array', + pcall_err(api.nvim_win_set_config, win, { footer = 0 }) ) command('redraw!') assert_alive() - end) - - it('no crash with invalid footer', function() - local win = api.nvim_open_win(0, true, { - width = 10, - height = 10, - relative = 'editor', - row = 10, - col = 10, - footer = { { 'test' } }, - border = 'single', - }) eq( 'title/footer cannot be an empty array', pcall_err(api.nvim_win_set_config, win, { footer = {} }) @@ -2869,5 +2833,48 @@ describe('API/win', function() command('redraw!') assert_alive() end) + + describe('no crash or memory leak', function() + local win + + before_each(function() + win = api.nvim_open_win(0, false, { + relative = 'editor', + row = 10, + col = 10, + height = 10, + width = 10, + border = 'single', + title = { { 'OLD_TITLE' } }, + footer = { { 'OLD_FOOTER' } }, + }) + end) + + it('with valid title and invalid footer', function() + eq( + 'title/footer must be string or array', + pcall_err(api.nvim_win_set_config, win, { + title = { { 'NEW_TITLE' } }, + footer = 0, + }) + ) + command('redraw!') + assert_alive() + eq({ { 'OLD_TITLE' } }, api.nvim_win_get_config(win).title) + end) + + it('with invalid title and valid footer', function() + eq( + 'title/footer must be string or array', + pcall_err(api.nvim_win_set_config, win, { + title = 0, + footer = { { 'NEW_FOOTER' } }, + }) + ) + command('redraw!') + assert_alive() + eq({ { 'OLD_FOOTER' } }, api.nvim_win_get_config(win).footer) + end) + end) end) end) |