From 8b2b1fba2abfb99186e3a1f0123251a3e2eae3fe Mon Sep 17 00:00:00 2001 From: glepnir Date: Fri, 3 May 2024 15:53:13 +0800 Subject: fix(float): missing default highlight for title Problem: there is missing default title highlight when highlight not defined in title text chunk. Solution: when attr is not set use default title highlight group. --- test/functional/ui/float_spec.lua | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'test/functional') diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua index 248220e28b..cdaae6cfee 100644 --- a/test/functional/ui/float_spec.lua +++ b/test/functional/ui/float_spec.lua @@ -2127,7 +2127,7 @@ describe('float window', function() ## grid 3 | ## grid 4 - {5:╔═════}🦄BB{5:╗}| + {5:╔═════}{11:🦄BB}{5:╗}| {5:║}{1: halloj! }{5:║}| {5:║}{1: BORDAA }{5:║}| {5:╚═════════╝}| @@ -2141,7 +2141,7 @@ describe('float window', function() screen:expect{grid=[[ ^ | {0:~ }| - {0:~ }{5:╔═════}🦄BB{5:╗}{0: }| + {0:~ }{5:╔═════}{11:🦄BB}{5:╗}{0: }| {0:~ }{5:║}{1: halloj! }{5:║}{0: }| {0:~ }{5:║}{1: BORDAA }{5:║}{0: }| {0:~ }{5:╚═════════╝}{0: }| @@ -2275,7 +2275,7 @@ describe('float window', function() {5:╔═════════╗}| {5:║}{1: halloj! }{5:║}| {5:║}{1: BORDAA }{5:║}| - {5:╚═════}🦄BB{5:╝}| + {5:╚═════}{11:🦄BB}{5:╝}| ]], float_pos={ [4] = { 1001, "NW", 1, 2, 5, true } }, win_viewport={ @@ -2289,7 +2289,7 @@ describe('float window', function() {0:~ }{5:╔═════════╗}{0: }| {0:~ }{5:║}{1: halloj! }{5:║}{0: }| {0:~ }{5:║}{1: BORDAA }{5:║}{0: }| - {0:~ }{5:╚═════}🦄BB{5:╝}{0: }| + {0:~ }{5:╚═════}{11:🦄BB}{5:╝}{0: }| | ]]} end @@ -2423,10 +2423,10 @@ describe('float window', function() ## grid 3 | ## grid 4 - {5:╔═════}🦄{7:BB}{5:╗}| + {5:╔═════}{11:🦄}{7:BB}{5:╗}| {5:║}{1: halloj! }{5:║}| {5:║}{1: BORDAA }{5:║}| - {5:╚═════}🦄{7:BB}{5:╝}| + {5:╚═════}{11:🦄}{7:BB}{5:╝}| ]], float_pos={ [4] = { 1001, "NW", 1, 2, 5, true } }, win_viewport={ @@ -2437,10 +2437,10 @@ describe('float window', function() screen:expect{grid=[[ ^ | {0:~ }| - {0:~ }{5:╔═════}🦄{7:BB}{5:╗}{0: }| + {0:~ }{5:╔═════}{11:🦄}{7:BB}{5:╗}{0: }| {0:~ }{5:║}{1: halloj! }{5:║}{0: }| {0:~ }{5:║}{1: BORDAA }{5:║}{0: }| - {0:~ }{5:╚═════}🦄{7:BB}{5:╝}{0: }| + {0:~ }{5:╚═════}{11:🦄}{7:BB}{5:╝}{0: }| | ]]} end -- cgit From bdb81afab3e5c43a33267666c2689feb284f6b52 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 25 May 2024 20:37:33 +0800 Subject: refactor(lua): rewrite vim.highlight.range() (#28986) - Use getregionpos(). - Use a single extmark for non-blockwise selection. --- test/functional/lua/highlight_spec.lua | 83 ++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) (limited to 'test/functional') diff --git a/test/functional/lua/highlight_spec.lua b/test/functional/lua/highlight_spec.lua index c9f2d0a47f..8f099ac233 100644 --- a/test/functional/lua/highlight_spec.lua +++ b/test/functional/lua/highlight_spec.lua @@ -1,5 +1,6 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() +local Screen = require('test.functional.ui.screen') local exec_lua = n.exec_lua local eq = t.eq @@ -9,6 +10,88 @@ local command = n.command local clear = n.clear local api = n.api +describe('vim.highlight.range', function() + local screen + + before_each(function() + clear() + screen = Screen.new(60, 6) + screen:add_extra_attr_ids({ + [100] = { foreground = Screen.colors.Blue, background = Screen.colors.Yellow, bold = true }, + }) + screen:attach() + api.nvim_set_option_value('list', true, {}) + api.nvim_set_option_value('listchars', 'eol:$', {}) + api.nvim_buf_set_lines(0, 0, -1, true, { + 'asdfghjkl', + '«口=口»', + 'qwertyuiop', + '口口=口口', + 'zxcvbnm', + }) + end) + + it('works with charwise selection', function() + exec_lua([[ + local ns = vim.api.nvim_create_namespace('') + vim.highlight.range(0, ns, 'Search', { 1, 5 }, { 3, 10 }) + ]]) + screen:expect([[ + ^asdfghjkl{1:$} | + «口{10:=口»}{100:$} | + {10:qwertyuiop}{100:$} | + {10:口口=口}口{1:$} | + zxcvbnm{1:$} | + | + ]]) + end) + + it('works with linewise selection', function() + exec_lua([[ + local ns = vim.api.nvim_create_namespace('') + vim.highlight.range(0, ns, 'Search', { 0, 0 }, { 4, 0 }, { regtype = 'V' }) + ]]) + screen:expect([[ + {10:^asdfghjkl}{100:$} | + {10:«口=口»}{100:$} | + {10:qwertyuiop}{100:$} | + {10:口口=口口}{100:$} | + {10:zxcvbnm}{100:$} | + | + ]]) + end) + + it('works with blockwise selection', function() + exec_lua([[ + local ns = vim.api.nvim_create_namespace('') + vim.highlight.range(0, ns, 'Search', { 0, 0 }, { 4, 4 }, { regtype = '\022' }) + ]]) + screen:expect([[ + {10:^asdf}ghjkl{1:$} | + {10:«口=}口»{1:$} | + {10:qwer}tyuiop{1:$} | + {10:口口}=口口{1:$} | + {10:zxcv}bnm{1:$} | + | + ]]) + end) + + it('works with blockwise selection with width', function() + exec_lua([[ + local ns = vim.api.nvim_create_namespace('') + vim.highlight.range(0, ns, 'Search', { 0, 4 }, { 4, 7 }, { regtype = '\0226' }) + ]]) + screen:expect([[ + ^asdf{10:ghjkl}{1:$} | + «口={10:口»}{1:$} | + qwer{10:tyuiop}{1:$} | + 口口{10:=口口}{1:$} | + zxcv{10:bnm}{1:$} | + | + ]]) + end) +end) + describe('vim.highlight.on_yank', function() before_each(function() clear() -- cgit From a4b554965510c9719c3d2bf22fdaa2d73081deb7 Mon Sep 17 00:00:00 2001 From: bfredl Date: Sat, 25 May 2024 10:20:10 +0200 Subject: refactor(tests): update screen:snapshot_util() to use new-style highlights This makes screen:snapshot_util() generate code with the new screen:add_extra_attr_ids { ... } pattern. For convenience, the old-style configuration is still detected and supported (until all tests have been refactored, which is my goal for the 0.11 cycle) Remove the last traces of the "ignore" attr anti-pattern. This code is no longer functional, it is just "ignore" argument being passed around like a hot potato at this point. --- test/functional/ui/screen.lua | 58 ++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 31 deletions(-) (limited to 'test/functional') diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index 4625ce8553..f8e95f7d88 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -255,6 +255,7 @@ end function Screen:set_default_attr_ids(attr_ids) self._default_attr_ids = attr_ids + self._attrs_overridden = true end function Screen:add_extra_attr_ids(extra_attr_ids) @@ -699,9 +700,9 @@ screen:redraw_debug() to show all intermediate screen states.]] end, expected) end -function Screen:expect_unchanged(intermediate, waittime_ms, ignore_attrs) +function Screen:expect_unchanged(intermediate, waittime_ms) -- Collect the current screen state. - local kwargs = self:get_snapshot(nil, ignore_attrs) + local kwargs = self:get_snapshot() if intermediate then kwargs.intermediate = true @@ -1536,13 +1537,14 @@ end -- Use snapshot_util({}) to generate a text-only (no attributes) test. -- -- @see Screen:redraw_debug() -function Screen:snapshot_util(attrs, ignore, request_cb) +function Screen:snapshot_util(request_cb) + -- TODO: simplify this later when existing tests have been updated self:sleep(250, request_cb) - self:print_snapshot(attrs, ignore) + self:print_snapshot() end -function Screen:redraw_debug(attrs, ignore, timeout) - self:print_snapshot(attrs, ignore) +function Screen:redraw_debug(timeout) + self:print_snapshot() local function notification_cb(method, args) assert(method == 'redraw') for _, update in ipairs(args) do @@ -1552,7 +1554,7 @@ function Screen:redraw_debug(attrs, ignore, timeout) end end self:_redraw(args) - self:print_snapshot(attrs, ignore) + self:print_snapshot() return true end if timeout == nil then @@ -1596,23 +1598,12 @@ end -- Returns the current screen state in the form of a screen:expect() -- keyword-args map. -function Screen:get_snapshot(attrs, ignore) - if ignore == nil then - ignore = self._default_attr_ignore - end +function Screen:get_snapshot() local attr_state = { ids = {}, - ignore = ignore, mutable = true, -- allow _row_repr to add missing highlights } - if attrs == nil then - attrs = self._default_attr_ids - elseif isempty(attrs) then - attrs = nil - attr_state.ids = nil - else - attr_state.modified = true - end + local attrs = self._default_attr_ids if attrs ~= nil then for i, a in pairs(attrs) do @@ -1708,9 +1699,10 @@ local function fmt_ext_state(name, state) end end -function Screen:_print_snapshot(attrs, ignore) - local kwargs, ext_state, attr_state = self:get_snapshot(attrs, ignore) +function Screen:_print_snapshot() + local kwargs, ext_state, attr_state = self:get_snapshot() local attrstr = '' + local modify_attrs = not self._attrs_overridden if attr_state.modified then local attrstrs = {} for i, a in pairs(attr_state.ids) do @@ -1721,16 +1713,20 @@ function Screen:_print_snapshot(attrs, ignore) dict = '{ ' .. self:_pprint_attrs(a) .. ' }' end local keyval = (type(i) == 'number') and '[' .. tostring(i) .. ']' or i - table.insert(attrstrs, ' ' .. keyval .. ' = ' .. dict .. ',') + if not (type(i) == 'number' and modify_attrs and i <= 30) then + table.insert(attrstrs, ' ' .. keyval .. ' = ' .. dict .. ',') + end + if modify_attrs then + self._default_attr_ids = attr_state.ids + end end - attrstr = (',\n attr_ids = {\n ' .. table.concat(attrstrs, '\n ') .. '\n },') - elseif isempty(attrs) then - attrstr = ',\n attr_ids = {},' + local fn_name = modify_attrs and 'add_extra_attr_ids' or 'set_default_attr_ids' + attrstr = ('screen:' .. fn_name .. ' {\n' .. table.concat(attrstrs, '\n') .. '\n}\n\n') end - local result = ('screen:expect({\n grid = [[\n %s\n ]]%s'):format( - kwargs.grid:gsub('\n', '\n '), - attrstr + local result = ('%sscreen:expect({\n grid = [[\n %s\n ]]'):format( + attrstr, + kwargs.grid:gsub('\n', '\n ') ) for _, k in ipairs(ext_keys) do if ext_state[k] ~= nil and not (k == 'win_viewport' and not self.options.ext_multigrid) then @@ -1742,8 +1738,8 @@ function Screen:_print_snapshot(attrs, ignore) return result end -function Screen:print_snapshot(attrs, ignore) - print('\n' .. self:_print_snapshot(attrs, ignore) .. '\n') +function Screen:print_snapshot() + print('\n' .. self:_print_snapshot() .. '\n') io.stdout:flush() end -- cgit From fb43741f80175ba5e26addb785162dd83d33c859 Mon Sep 17 00:00:00 2001 From: bfredl Date: Sat, 25 May 2024 19:18:57 +0200 Subject: refactor(tests): use more global highlight definitions --- test/functional/api/buffer_spec.lua | 113 ++++++--------- test/functional/api/vim_spec.lua | 277 +++++++++++++++--------------------- test/functional/api/window_spec.lua | 150 +++++++------------ 3 files changed, 213 insertions(+), 327 deletions(-) (limited to 'test/functional') diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua index cf69958fd8..f836c1c540 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] [+] }| | ]], } diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index fd0535aa51..b32f2b1cb2 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 | ]], } @@ -1533,16 +1527,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 +1541,7 @@ describe('API', function() screen:expect { grid = [[ foo ^foo foo | - {0:~ }| + {1:~ }| | ]], } @@ -1559,8 +1549,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:~ }| | ]], } @@ -2254,12 +2244,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 +2271,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('') @@ -2299,12 +2283,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 +2298,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 +2314,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 +2329,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 +2341,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 +2357,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 +2366,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('') -- exit the press ENTER screen end) @@ -2402,11 +2380,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 +2396,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('') screen:expect([[ ^ | - {0:~ }|*6 + {1:~ }|*6 | ]]) end) @@ -3102,9 +3074,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() -- @@ -3458,13 +3427,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 +3436,7 @@ describe('API', function() screen:expect { grid = [[ ^ | - {0:~ }|*6 + {1:~ }|*6 msg | ]], } @@ -3489,8 +3451,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 +3462,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 +3490,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 +3515,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 +3578,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 +3589,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 +3605,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 ]]) @@ -4472,10 +4426,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 +4434,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 +4444,7 @@ describe('API', function() screen:expect([[ foo | bar | - {1: }| + {3: }| Entering Ex mode. Type "visual" to go to Normal mode. | :1 | foo | @@ -4934,14 +4884,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 +4901,7 @@ describe('API', function() screen:expect { grid = [[ ^ | - {0:~ }|*4 + {1:~ }|*4 15 | ]], } diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua index 15b9b0945c..77611cc750 100644 --- a/test/functional/api/window_spec.lua +++ b/test/functional/api/window_spec.lua @@ -170,11 +170,6 @@ describe('API/win', function() 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) @@ -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| | ]], } @@ -2563,10 +2525,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 +2533,10 @@ describe('API/win', function() ]]) screen:expect([[ ^ | - {0:~ }|*3 - {1:[No Name] }| + {1:~ }|*3 + {3:[No Name] }| | - {0:~ }|*3 + {1:~ }|*3 | ]]) end) -- cgit From b90d7c36cf8a93e02d834eb53f5d0c8f19a9d7fa Mon Sep 17 00:00:00 2001 From: bfredl Date: Sun, 26 May 2024 09:34:29 +0200 Subject: refactor(tests): more global highlight definitions --- test/functional/core/fileio_spec.lua | 11 +- test/functional/core/job_spec.lua | 13 +- test/functional/editor/completion_spec.lua | 593 +++++++++++++-------------- test/functional/editor/mode_cmdline_spec.lua | 12 +- test/functional/editor/mode_insert_spec.lua | 20 +- test/functional/editor/tabpage_spec.lua | 23 +- 6 files changed, 319 insertions(+), 353 deletions(-) (limited to 'test/functional') diff --git a/test/functional/core/fileio_spec.lua b/test/functional/core/fileio_spec.lua index 5b0be1e83c..1c4f42eb43 100644 --- a/test/functional/core/fileio_spec.lua +++ b/test/functional/core/fileio_spec.lua @@ -276,11 +276,6 @@ describe('fileio', function() write_file('Xtest-overwrite-forced', 'foobar') command('set nofixendofline') local screen = Screen.new(40, 4) - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - [2] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, - [3] = { bold = true, foreground = Screen.colors.SeaGreen4 }, - }) screen:attach() command('set shortmess-=F') @@ -300,9 +295,9 @@ describe('fileio', function() -- use async feed_command because nvim basically hangs on the prompt feed_command('w') screen:expect([[ - {2:WARNING: The file has been changed since}| - {2: reading it!!!} | - {3:Do you really want to write to it (y/n)?}| + {9:WARNING: The file has been changed since}| + {9: reading it!!!} | + {6:Do you really want to write to it (y/n)?}| ^ | ]]) diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua index e1efc07452..bf10033f53 100644 --- a/test/functional/core/job_spec.lua +++ b/test/functional/core/job_spec.lua @@ -910,11 +910,6 @@ describe('jobs', function() it('hides cursor and flushes messages before blocking', function() local screen = Screen.new(50, 6) - screen:set_default_attr_ids({ - [0] = { foreground = Screen.colors.Blue, bold = true }, -- NonText - [1] = { bold = true, reverse = true }, -- MsgSeparator - [2] = { bold = true, foreground = Screen.colors.SeaGreen }, -- MoreMsg - }) screen:attach() command([[let g:id = jobstart([v:progpath, '--clean', '--headless'])]]) source([[ @@ -928,8 +923,8 @@ describe('jobs', function() screen:expect { grid = [[ | - {0:~ }|*2 - {1: }| + {1:~ }|*2 + {3: }| aaa | bbb | ]], @@ -938,11 +933,11 @@ describe('jobs', function() screen:expect { grid = [[ | - {1: }| + {3: }| aaa | bbb | ccc | - {2:Press ENTER or type command to continue}^ | + {6:Press ENTER or type command to continue}^ | ]], } feed('') diff --git a/test/functional/editor/completion_spec.lua b/test/functional/editor/completion_spec.lua index 62bb7e19f3..a28e449f49 100644 --- a/test/functional/editor/completion_spec.lua +++ b/test/functional/editor/completion_spec.lua @@ -18,19 +18,10 @@ describe('completion', function() clear() screen = Screen.new(60, 8) screen:attach() - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - [1] = { background = Screen.colors.LightMagenta }, - [2] = { background = Screen.colors.Grey }, - [3] = { bold = true }, - [4] = { bold = true, foreground = Screen.colors.SeaGreen }, - [5] = { foreground = Screen.colors.Red }, - [6] = { background = Screen.colors.Black }, - [7] = { foreground = Screen.colors.White, background = Screen.colors.Red }, - [8] = { reverse = true }, - [9] = { bold = true, reverse = true }, - [10] = { foreground = Screen.colors.Grey0, background = Screen.colors.Yellow }, - }) + screen:add_extra_attr_ids { + [100] = { foreground = Screen.colors.Gray0, background = Screen.colors.Yellow }, + [101] = { background = Screen.colors.Gray0 }, + } end) describe('v:completed_item', function() @@ -42,15 +33,15 @@ describe('completion', function() screen:expect([[ foo | foo^ | - {0:~ }|*5 - {3:-- Keyword Local completion (^N^P) The only match} | + {1:~ }|*5 + {5:-- Keyword Local completion (^N^P) The only match} | ]]) feed('') screen:expect([[ foo | ^ | - {0:~ }|*5 - {3:-- INSERT --} | + {1:~ }|*5 + {5:-- INSERT --} | ]]) feed('') eq({}, eval('v:completed_item')) @@ -104,10 +95,10 @@ describe('completion', function() eq('foo', eval('getline(1)')) screen:expect([[ foo^ | - {2:bar foobaz baz }{0: }| - {1:abbr kind menu }{0: }| - {0:~ }|*4 - {3:-- Omni completion (^O^N^P) }{4:match 1 of 2} | + {12:bar foobaz baz }{1: }| + {4:abbr kind menu }{1: }| + {1:~ }|*4 + {5:-- Omni completion (^O^N^P) }{6:match 1 of 2} | ]]) eq({ word = 'foo', @@ -136,24 +127,24 @@ describe('completion', function() screen:expect([[ foo | ^ | - {0:~ }|*5 - {3:-- INSERT --} | + {1:~ }|*5 + {5:-- INSERT --} | ]]) feed('') -- the ^X prompt, only test this once screen:expect([[ foo | ^ | - {0:~ }|*5 - {3:-- ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)} | + {1:~ }|*5 + {5:-- ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)} | ]]) feed('') screen:expect([[ foo | foo^ | - {2:foo }{0: }| - {0:~ }|*4 - {3:-- Keyword Local completion (^N^P) The only match} | + {12:foo }{1: }| + {1:~ }|*4 + {5:-- Keyword Local completion (^N^P) The only match} | ]]) feed('bar') eq('foobar', eval('getline(2)')) @@ -162,9 +153,9 @@ describe('completion', function() foo | foobar | foo^ | - {2:foo }{0: }| - {0:~ }|*3 - {3:-- INSERT --} | + {12:foo }{1: }| + {1:~ }|*3 + {5:-- INSERT --} | ]]) eq('foo', eval('getline(3)')) end) @@ -174,16 +165,16 @@ describe('completion', function() screen:expect([[ foo | ^ | - {2:foo }{0: }| - {0:~ }|*4 - {3:-- Keyword Local completion (^N^P) The only match} | + {12:foo }{1: }| + {1:~ }|*4 + {5:-- Keyword Local completion (^N^P) The only match} | ]]) feed('') screen:expect([[ foo | foo^ | - {0:~ }|*5 - {3:-- INSERT --} | + {1:~ }|*5 + {5:-- INSERT --} | ]]) feed('') eq('foo', eval('getline(2)')) @@ -191,9 +182,9 @@ describe('completion', function() screen:expect([[ foo |*2 ^ | - {2:foo }{0: }| - {0:~ }|*3 - {3:-- INSERT --} | + {12:foo }{1: }| + {1:~ }|*3 + {5:-- INSERT --} | ]]) feed('') eq('foo', eval('getline(3)')) @@ -204,16 +195,16 @@ describe('completion', function() screen:expect([[ foo | ^ | - {1:foo }{0: }| - {0:~ }|*4 - {3:-- Keyword Local completion (^N^P) }{5:Back at original} | + {4:foo }{1: }| + {1:~ }|*4 + {5:-- Keyword Local completion (^N^P) }{19:Back at original} | ]]) feed('b') screen:expect([[ foo | b^ | - {0:~ }|*5 - {3:-- Keyword Local completion (^N^P) }{5:Back at original} | + {1:~ }|*5 + {5:-- Keyword Local completion (^N^P) }{19:Back at original} | ]]) feed('ar') eq('bar', eval('getline(2)')) @@ -222,9 +213,9 @@ describe('completion', function() foo | bar | ^ | - {1:foo }{0: }| - {0:~ }|*3 - {3:-- INSERT --} | + {4:foo }{1: }| + {1:~ }|*3 + {5:-- INSERT --} | ]]) feed('bar') eq('bar', eval('getline(3)')) @@ -235,15 +226,15 @@ describe('completion', function() screen:expect([[ foo | ^ | - {1:foo }{0: }| - {0:~ }|*4 - {3:-- Keyword Local completion (^N^P) }{5:Back at original} | + {4:foo }{1: }| + {1:~ }|*4 + {5:-- Keyword Local completion (^N^P) }{19:Back at original} | ]]) feed('') screen:expect([[ foo | ^ | - {0:~ }|*5 + {1:~ }|*5 | ]]) eq('', eval('getline(2)')) @@ -252,16 +243,16 @@ describe('completion', function() foo | | ^ | - {1:foo }{0: }| - {0:~ }|*3 - {3:-- INSERT --} | + {4:foo }{1: }| + {1:~ }|*3 + {5:-- INSERT --} | ]]) feed('') screen:expect([[ foo | | ^ | - {0:~ }|*4 + {1:~ }|*4 | ]]) eq('', eval('getline(3)')) @@ -367,44 +358,44 @@ describe('completion', function() feed('i') screen:expect([[ ^ | - {1:January }{6: }{0: }| - {1:February }{6: }{0: }| - {1:March }{6: }{0: }| - {1:April }{2: }{0: }| - {1:May }{2: }{0: }| - {1:June }{2: }{0: }| - {3:-- User defined completion (^U^N^P) }{5:Back at original} | + {4:January }{101: }{1: }| + {4:February }{101: }{1: }| + {4:March }{101: }{1: }| + {4:April }{12: }{1: }| + {4:May }{12: }{1: }| + {4:June }{12: }{1: }| + {5:-- User defined completion (^U^N^P) }{19:Back at original} | ]]) feed('u') screen:expect([[ u^ | - {1:January }{0: }| - {1:February }{0: }| - {1:June }{0: }| - {1:July }{0: }| - {1:August }{0: }| - {0:~ }| - {3:-- User defined completion (^U^N^P) }{5:Back at original} | + {4:January }{1: }| + {4:February }{1: }| + {4:June }{1: }| + {4:July }{1: }| + {4:August }{1: }| + {1:~ }| + {5:-- User defined completion (^U^N^P) }{19:Back at original} | ]]) feed('g') screen:expect([[ ug^ | - {1:August }{0: }| - {0:~ }|*5 - {3:-- User defined completion (^U^N^P) }{5:Back at original} | + {4:August }{1: }| + {1:~ }|*5 + {5:-- User defined completion (^U^N^P) }{19:Back at original} | ]]) feed('') screen:expect([[ ug^ | - {2:August }{0: }| - {0:~ }|*5 - {3:-- User defined completion (^U^N^P) The only match} | + {12:August }{1: }| + {1:~ }|*5 + {5:-- User defined completion (^U^N^P) The only match} | ]]) feed('') screen:expect([[ August^ | - {0:~ }|*6 - {3:-- INSERT --} | + {1:~ }|*6 + {5:-- INSERT --} | ]]) expect('August') end) @@ -414,45 +405,45 @@ describe('completion', function() screen:expect([[ | Ja^ | - {1:January }{0: }| - {0:~ }|*4 - {3:-- User defined completion (^U^N^P) }{5:Back at original} | + {4:January }{1: }| + {1:~ }|*4 + {5:-- User defined completion (^U^N^P) }{19:Back at original} | ]]) feed('') screen:expect([[ | J^ | - {1:January }{0: }| - {1:June }{0: }| - {1:July }{0: }| - {0:~ }|*2 - {3:-- User defined completion (^U^N^P) }{5:Back at original} | + {4:January }{1: }| + {4:June }{1: }| + {4:July }{1: }| + {1:~ }|*2 + {5:-- User defined completion (^U^N^P) }{19:Back at original} | ]]) feed('') screen:expect([[ | January^ | - {2:January }{0: }| - {1:June }{0: }| - {1:July }{0: }| - {0:~ }|*2 - {3:-- User defined completion (^U^N^P) }{4:match 1 of 3} | + {12:January }{1: }| + {4:June }{1: }| + {4:July }{1: }| + {1:~ }|*2 + {5:-- User defined completion (^U^N^P) }{6:match 1 of 3} | ]]) feed('') screen:expect([[ | June^ | - {1:January }{0: }| - {2:June }{0: }| - {1:July }{0: }| - {0:~ }|*2 - {3:-- User defined completion (^U^N^P) }{4:match 2 of 3} | + {4:January }{1: }| + {12:June }{1: }| + {4:July }{1: }| + {1:~ }|*2 + {5:-- User defined completion (^U^N^P) }{6:match 2 of 3} | ]]) feed('') screen:expect([[ | Jun^e | - {0:~ }|*5 + {1:~ }|*5 | ]]) feed('.') @@ -460,7 +451,7 @@ describe('completion', function() | June | Jun^e | - {0:~ }|*4 + {1:~ }|*4 | ]]) expect([[ @@ -485,46 +476,46 @@ describe('completion', function() feed('i=TestComplete()') screen:expect([[ ^ | - {1:0 }{6: }{0: }| - {1:1 }{2: }{0: }| - {1:2 }{2: }{0: }| - {1:3 }{2: }{0: }| - {1:4 }{2: }{0: }| - {1:5 }{2: }{0: }| - {3:-- INSERT --} | + {4:0 }{101: }{1: }| + {4:1 }{12: }{1: }| + {4:2 }{12: }{1: }| + {4:3 }{12: }{1: }| + {4:4 }{12: }{1: }| + {4:5 }{12: }{1: }| + {5:-- INSERT --} | ]]) feed('7') screen:expect([[ 7^ | - {1:7 }{6: }{0: }| - {1:70 }{6: }{0: }| - {1:71 }{6: }{0: }| - {1:72 }{2: }{0: }| - {1:73 }{2: }{0: }| - {1:74 }{2: }{0: }| - {3:-- INSERT --} | + {4:7 }{101: }{1: }| + {4:70 }{101: }{1: }| + {4:71 }{101: }{1: }| + {4:72 }{12: }{1: }| + {4:73 }{12: }{1: }| + {4:74 }{12: }{1: }| + {5:-- INSERT --} | ]]) feed('') screen:expect([[ 7^ | - {2:7 }{6: }{0: }| - {1:70 }{6: }{0: }| - {1:71 }{6: }{0: }| - {1:72 }{2: }{0: }| - {1:73 }{2: }{0: }| - {1:74 }{2: }{0: }| - {3:-- INSERT --} | + {12:7 }{101: }{1: }| + {4:70 }{101: }{1: }| + {4:71 }{101: }{1: }| + {4:72 }{12: }{1: }| + {4:73 }{12: }{1: }| + {4:74 }{12: }{1: }| + {5:-- INSERT --} | ]]) feed('') screen:expect([[ 70^ | - {1:7 }{6: }{0: }| - {2:70 }{6: }{0: }| - {1:71 }{6: }{0: }| - {1:72 }{2: }{0: }| - {1:73 }{2: }{0: }| - {1:74 }{2: }{0: }| - {3:-- INSERT --} | + {4:7 }{101: }{1: }| + {12:70 }{101: }{1: }| + {4:71 }{101: }{1: }| + {4:72 }{12: }{1: }| + {4:73 }{12: }{1: }| + {4:74 }{12: }{1: }| + {5:-- INSERT --} | ]]) end) @@ -532,107 +523,107 @@ describe('completion', function() feed('i=TestComplete()') screen:expect([[ ^ | - {1:0 }{6: }{0: }| - {1:1 }{2: }{0: }| - {1:2 }{2: }{0: }| - {1:3 }{2: }{0: }| - {1:4 }{2: }{0: }| - {1:5 }{2: }{0: }| - {3:-- INSERT --} | + {4:0 }{101: }{1: }| + {4:1 }{12: }{1: }| + {4:2 }{12: }{1: }| + {4:3 }{12: }{1: }| + {4:4 }{12: }{1: }| + {4:5 }{12: }{1: }| + {5:-- INSERT --} | ]]) feed('') screen:expect([[ ^ | - {1:0 }{6: }{0: }| - {1:1 }{2: }{0: }| - {1:2 }{2: }{0: }| - {2:3 }{0: }| - {1:4 }{2: }{0: }| - {1:5 }{2: }{0: }| - {3:-- INSERT --} | + {4:0 }{101: }{1: }| + {4:1 }{12: }{1: }| + {4:2 }{12: }{1: }| + {12:3 }{1: }| + {4:4 }{12: }{1: }| + {4:5 }{12: }{1: }| + {5:-- INSERT --} | ]]) feed('') screen:expect([[ ^ | - {1:5 }{6: }{0: }| - {1:6 }{2: }{0: }| - {2:7 }{0: }| - {1:8 }{2: }{0: }| - {1:9 }{2: }{0: }| - {1:10 }{2: }{0: }| - {3:-- INSERT --} | + {4:5 }{101: }{1: }| + {4:6 }{12: }{1: }| + {12:7 }{1: }| + {4:8 }{12: }{1: }| + {4:9 }{12: }{1: }| + {4:10 }{12: }{1: }| + {5:-- INSERT --} | ]]) feed('') screen:expect([[ ^ | - {1:5 }{6: }{0: }| - {1:6 }{2: }{0: }| - {1:7 }{2: }{0: }| - {2:8 }{0: }| - {1:9 }{2: }{0: }| - {1:10 }{2: }{0: }| - {3:-- INSERT --} | + {4:5 }{101: }{1: }| + {4:6 }{12: }{1: }| + {4:7 }{12: }{1: }| + {12:8 }{1: }| + {4:9 }{12: }{1: }| + {4:10 }{12: }{1: }| + {5:-- INSERT --} | ]]) feed('') screen:expect([[ ^ | - {1:2 }{6: }{0: }| - {1:3 }{2: }{0: }| - {2:4 }{0: }| - {1:5 }{2: }{0: }| - {1:6 }{2: }{0: }| - {1:7 }{2: }{0: }| - {3:-- INSERT --} | + {4:2 }{101: }{1: }| + {4:3 }{12: }{1: }| + {12:4 }{1: }| + {4:5 }{12: }{1: }| + {4:6 }{12: }{1: }| + {4:7 }{12: }{1: }| + {5:-- INSERT --} | ]]) feed('') -- stop on first item screen:expect([[ ^ | - {2:0 }{6: }{0: }| - {1:1 }{2: }{0: }| - {1:2 }{2: }{0: }| - {1:3 }{2: }{0: }| - {1:4 }{2: }{0: }| - {1:5 }{2: }{0: }| - {3:-- INSERT --} | + {12:0 }{101: }{1: }| + {4:1 }{12: }{1: }| + {4:2 }{12: }{1: }| + {4:3 }{12: }{1: }| + {4:4 }{12: }{1: }| + {4:5 }{12: }{1: }| + {5:-- INSERT --} | ]]) feed('') -- when on first item, unselect screen:expect([[ ^ | - {1:0 }{6: }{0: }| - {1:1 }{2: }{0: }| - {1:2 }{2: }{0: }| - {1:3 }{2: }{0: }| - {1:4 }{2: }{0: }| - {1:5 }{2: }{0: }| - {3:-- INSERT --} | + {4:0 }{101: }{1: }| + {4:1 }{12: }{1: }| + {4:2 }{12: }{1: }| + {4:3 }{12: }{1: }| + {4:4 }{12: }{1: }| + {4:5 }{12: }{1: }| + {5:-- INSERT --} | ]]) feed('') -- when unselected, select last item screen:expect([[ ^ | - {1:95 }{2: }{0: }| - {1:96 }{2: }{0: }| - {1:97 }{2: }{0: }| - {1:98 }{2: }{0: }| - {1:99 }{2: }{0: }| - {2:100 }{6: }{0: }| - {3:-- INSERT --} | + {4:95 }{12: }{1: }| + {4:96 }{12: }{1: }| + {4:97 }{12: }{1: }| + {4:98 }{12: }{1: }| + {4:99 }{12: }{1: }| + {12:100 }{101: }{1: }| + {5:-- INSERT --} | ]]) feed('') screen:expect([[ ^ | - {1:94 }{2: }{0: }| - {1:95 }{2: }{0: }| - {2:96 }{0: }| - {1:97 }{2: }{0: }| - {1:98 }{2: }{0: }| - {1:99 }{6: }{0: }| - {3:-- INSERT --} | + {4:94 }{12: }{1: }| + {4:95 }{12: }{1: }| + {12:96 }{1: }| + {4:97 }{12: }{1: }| + {4:98 }{12: }{1: }| + {4:99 }{101: }{1: }| + {5:-- INSERT --} | ]]) feed('') screen:expect([[ 96^ | - {0:~ }|*6 - {3:-- INSERT --} | + {1:~ }|*6 + {5:-- INSERT --} | ]]) end) end) @@ -668,9 +659,9 @@ describe('completion', function() screen:expect([[ inc uninc indent unindent | ind^ | - {2:indent }{0: }| - {0:~ }|*4 - {3:-- Keyword Local completion (^N^P) }{4:match 1 of 2} | + {12:indent }{1: }| + {1:~ }|*4 + {5:-- Keyword Local completion (^N^P) }{6:match 1 of 2} | ]]) -- Indents when the item is selected @@ -678,8 +669,8 @@ describe('completion', function() screen:expect([[ inc uninc indent unindent | indent^ | - {0:~ }|*5 - {3:-- INSERT --} | + {1:~ }|*5 + {5:-- INSERT --} | ]]) -- Indents when completion is exited using ESC. feed('ind') @@ -687,7 +678,7 @@ describe('completion', function() inc uninc indent unindent | indent | in^d | - {0:~ }|*4 + {1:~ }|*4 | ]]) -- Works for unindenting too. @@ -699,9 +690,9 @@ describe('completion', function() indent | ind | unind^ | - {0:~ }{2: unindent }{0: }| - {0:~ }|*2 - {3:-- Keyword Local completion (^N^P) }{4:match 1 of 2} | + {1:~ }{12: unindent }{1: }| + {1:~ }|*2 + {5:-- Keyword Local completion (^N^P) }{6:match 1 of 2} | ]]) -- Works when going back and forth. feed('c') @@ -710,9 +701,9 @@ describe('completion', function() indent | ind | uninc^ | - {0:~ }{2: uninc }{0: }| - {0:~ }|*2 - {3:-- Keyword Local completion (^N^P) }{4:match 1 of 2} | + {1:~ }{12: uninc }{1: }| + {1:~ }|*2 + {5:-- Keyword Local completion (^N^P) }{6:match 1 of 2} | ]]) feed('d') screen:expect([[ @@ -720,9 +711,9 @@ describe('completion', function() indent | ind | unind^ | - {0:~ }{2: unindent }{0: }| - {0:~ }|*2 - {3:-- Keyword Local completion (^N^P) }{4:match 1 of 2} | + {1:~ }{12: unindent }{1: }| + {1:~ }|*2 + {5:-- Keyword Local completion (^N^P) }{6:match 1 of 2} | ]]) feed('') screen:expect([[ @@ -730,7 +721,7 @@ describe('completion', function() indent | ind | uninden^t | - {0:~ }|*3 + {1:~ }|*3 | ]]) end) @@ -741,15 +732,15 @@ describe('completion', function() screen:expect([[ ^foo | bar | - {0:~ }|*5 + {1:~ }|*5 | ]]) feed('A') screen:expect([[ foo^ | bar | - {0:~ }|*5 - {3:-- Whole line completion (^L^N^P) }{7:Pattern not found} | + {1:~ }|*5 + {5:-- Whole line completion (^L^N^P) }{9:Pattern not found} | ]]) eq(-1, eval('foldclosed(1)')) end) @@ -761,10 +752,10 @@ describe('completion', function() screen:expect([[ foobar fooegg | fooegg^ | - {1:foobar }{0: }| - {2:fooegg }{0: }| - {0:~ }|*3 - {3:-- Keyword completion (^N^P) }{4:match 1 of 2} | + {4:foobar }{1: }| + {12:fooegg }{1: }| + {1:~ }|*3 + {5:-- Keyword completion (^N^P) }{6:match 1 of 2} | ]]) assert_alive() @@ -773,10 +764,10 @@ describe('completion', function() grid = [[ foobar fooegg | fooegg^ | - {1:foobar }{0: }| - {2:fooegg }{0: }| - {0:~ }|*3 - {3:-- Keyword completion (^N^P) }{4:match 1 of 2} | + {4:foobar }{1: }| + {12:fooegg }{1: }| + {1:~ }|*3 + {5:-- Keyword completion (^N^P) }{6:match 1 of 2} | ]], unchanged = true, } @@ -786,10 +777,10 @@ describe('completion', function() screen:expect([[ foobar fooegg | foobar^ | - {2:foobar }{0: }| - {1:fooegg }{0: }| - {0:~ }|*3 - {3:-- Keyword completion (^N^P) }{4:match 2 of 2} | + {12:foobar }{1: }| + {4:fooegg }{1: }| + {1:~ }|*3 + {5:-- Keyword completion (^N^P) }{6:match 2 of 2} | ]]) end) @@ -800,7 +791,7 @@ describe('completion', function() screen:expect { grid = [[ | - {0:~ }|*6 + {1:~ }|*6 :lua CURRENT_TESTING_VAR^ | ]], } @@ -813,8 +804,8 @@ describe('completion', function() screen:expect { grid = [[ | - {0:~ }|*5 - {10:CURRENT_TESTING_BAR}{9: CURRENT_TESTING_FOO }| + {1:~ }|*5 + {100:CURRENT_TESTING_BAR}{3: CURRENT_TESTING_FOO }| :lua CURRENT_TESTING_BAR^ | ]], unchanged = true, @@ -847,30 +838,30 @@ describe('completion', function() feed('ifoo faa fee f') screen:expect([[ | - {8:[No Name] }| - {0::}foo faa fee f^ | - {0:~ }|*3 - {9:[Command Line] }| - {3:-- INSERT --} | + {2:[No Name] }| + {1::}foo faa fee f^ | + {1:~ }|*3 + {3:[Command Line] }| + {5:-- INSERT --} | ]]) feed('') screen:expect([[ | - {8:[No Name] }| - {0::}foo faa fee foo^ | - {0:~ }{2: foo }{0: }| - {0:~ }{1: faa }{0: }| - {0:~ }{1: fee }{0: }| - {9:[Command Line] }| - {3:-- Keyword Local completion (^N^P) }{4:match 1 of 3} | + {2:[No Name] }| + {1::}foo faa fee foo^ | + {1:~ }{12: foo }{1: }| + {1:~ }{4: faa }{1: }| + {1:~ }{4: fee }{1: }| + {3:[Command Line] }| + {5:-- Keyword Local completion (^N^P) }{6:match 1 of 3} | ]]) feed('') screen:expect([[ | - {8:[No Name] }| - {0::}foo faa fee foo | - {0:~ }|*3 - {9:[Command Line] }| + {2:[No Name] }| + {1::}foo faa fee foo | + {1:~ }|*3 + {3:[Command Line] }| :foo faa fee foo^ | ]]) end) @@ -903,9 +894,9 @@ describe('completion', function() feed('i=TestComplete()') screen:expect([[ ^ | - {1:1 3 2 }{0: }| - {0:~ }|*5 - {3:-- INSERT --} | + {4:1 3 2 }{1: }| + {1:~ }|*5 + {5:-- INSERT --} | ]]) end) end) @@ -918,12 +909,12 @@ describe('completion', function() grid = [[ *backers.txt* Nvim | Xnull^ | - {2:Xnull }{6: } | - {1:Xoxomoon }{6: } | - {1:Xu }{6: } NVIM REFERENCE MANUAL | - {1:Xpayn }{2: } | - {1:Xinity }{2: } | - {3:-- Keyword Local completion (^N^P) }{4:match 1 of 7} | + {12:Xnull }{101: } | + {4:Xoxomoon }{101: } | + {4:Xu }{101: } NVIM REFERENCE MANUAL | + {4:Xpayn }{12: } | + {4:Xinity }{12: } | + {5:-- Keyword Local completion (^N^P) }{6:match 1 of 7} | ]], } end) @@ -950,8 +941,8 @@ describe('completion', function() bar | foobar | f^ | - {0:~ }|*3 - {3:-- Keyword completion (^N^P) }{5:Back at original} | + {1:~ }|*3 + {5:-- Keyword completion (^N^P) }{19:Back at original} | ]], popupmenu = { anchor = { 1, 3, 0 }, @@ -970,8 +961,8 @@ describe('completion', function() bar | foobar | foob^ | - {0:~ }|*3 - {3:-- Keyword completion (^N^P) }{5:Back at original} | + {1:~ }|*3 + {5:-- Keyword completion (^N^P) }{19:Back at original} | ]], popupmenu = { anchor = { 1, 3, 0 }, @@ -992,10 +983,10 @@ describe('completion', function() bar | foobar | f^ | - {1:foo }{0: }| - {1:foobar }{0: }| - {0:~ }| - {3:-- Keyword completion (^N^P) }{5:Back at original} | + {4:foo }{1: }| + {4:foobar }{1: }| + {1:~ }| + {5:-- Keyword completion (^N^P) }{19:Back at original} | ]]) eq( { completed_item = {}, width = 15, height = 2, size = 2, col = 0, row = 4, scrollbar = false }, @@ -1007,10 +998,10 @@ describe('completion', function() bar | foobar | foo^ | - {2:foo }{0: }| - {1:foobar }{0: }| - {0:~ }| - {3:-- Keyword completion (^N^P) }{4:match 1 of 2} | + {12:foo }{1: }| + {4:foobar }{1: }| + {1:~ }| + {5:-- Keyword completion (^N^P) }{6:match 1 of 2} | ]]) eq('foo', eval('g:word')) feed('') @@ -1019,10 +1010,10 @@ describe('completion', function() bar | foobar | foobar^ | - {1:foo }{0: }| - {2:foobar }{0: }| - {0:~ }| - {3:-- Keyword completion (^N^P) }{4:match 2 of 2} | + {4:foo }{1: }| + {12:foobar }{1: }| + {1:~ }| + {5:-- Keyword completion (^N^P) }{6:match 2 of 2} | ]]) eq('foobar', eval('g:word')) feed('') @@ -1031,10 +1022,10 @@ describe('completion', function() bar | foobar | foobar^ | - {2:foo }{0: }| - {1:foobar }{0: }| - {0:~ }| - {3:-- Keyword completion (^N^P) }{4:match 1 of 2} | + {12:foo }{1: }| + {4:foobar }{1: }| + {1:~ }| + {5:-- Keyword completion (^N^P) }{6:match 1 of 2} | ]]) eq('foo', eval('g:word')) feed('') @@ -1043,10 +1034,10 @@ describe('completion', function() bar | foobar | foobar^ | - {1:foo }{0: }| - {2:foobar }{0: }| - {0:~ }| - {3:-- Keyword completion (^N^P) }{4:match 2 of 2} | + {4:foo }{1: }| + {12:foobar }{1: }| + {1:~ }| + {5:-- Keyword completion (^N^P) }{6:match 2 of 2} | ]]) eq('foobar', eval('g:word')) feed('') @@ -1061,11 +1052,11 @@ describe('completion', function() hullo | heeee | hello^ | - {2:hello }{0: }| - {1:hullo }{0: }| - {1:heeee }{0: }| - {0:~ }|*6 - {3:-- }{4:match 1 of 3} | + {12:hello }{1: }| + {4:hullo }{1: }| + {4:heeee }{1: }| + {1:~ }|*6 + {5:-- }{6:match 1 of 3} | ]]) command([[call timer_start(100, { -> execute('stopinsert') })]]) vim.uv.sleep(200) @@ -1075,7 +1066,7 @@ describe('completion', function() hullo | heee^e | hello | - {0:~ }|*9 + {1:~ }|*9 | ]]) end) @@ -1090,9 +1081,9 @@ describe('completion', function() screen:expect([[ ii | ii^ | - {2:ii }{0: }| - {0:~ }|*4 - {3:-- Keyword completion (^N^P) The only match} | + {12:ii }{1: }| + {1:~ }|*4 + {5:-- Keyword completion (^N^P) The only match} | ]]) assert_alive() end) @@ -1129,22 +1120,22 @@ describe('completion', function() screen:expect { grid = [[ foo^ | - {2:foo }{0: }| - {1:bar }{0: }| - {1:foa }{0: }| - {1:.hidden }{0: }| - {0:~ }|*3 - {3:-- }{4:match 1 of 4} | + {12:foo }{1: }| + {4:bar }{1: }| + {4:foa }{1: }| + {4:.hidden }{1: }| + {1:~ }|*3 + {5:-- }{6:match 1 of 4} | ]], } feed('ccf') screen:expect { grid = [[ foo^ | - {2:foo }{0: }| - {1:foa }{0: }| - {0:~ }|*5 - {3:-- }{4:match 1 of 2} | + {12:foo }{1: }| + {4:foa }{1: }| + {1:~ }|*5 + {5:-- }{6:match 1 of 2} | ]], } end) @@ -1168,10 +1159,10 @@ describe('completion', function() eq(eval('mark'), eval("nvim_buf_get_extmark_by_id(0, ns_id, mark_id, { 'details':1 })")) feed('0YppiaggI') screen:expect([[ - aaaa{7:^aa}aa | - {2:aaaa } | - {1:aaaaa } | - {3:-- Keyword completion (^N^P) }{4:match 1 of 2} | + aaaa{9:^aa}aa | + {12:aaaa } | + {4:aaaaa } | + {5:-- Keyword completion (^N^P) }{6:match 1 of 2} | ]]) feed('') eq(eval('mark'), eval("nvim_buf_get_extmark_by_id(0, ns_id, mark_id, { 'details':1 })")) @@ -1180,16 +1171,16 @@ describe('completion', function() feed('') screen:expect([[ aaaaa^ | - {1:aaaa } | - {2:aaaaa } | - {3:-- Keyword completion (^N^P) }{4:match 2 of 2} | + {4:aaaa } | + {12:aaaaa } | + {5:-- Keyword completion (^N^P) }{6:match 2 of 2} | ]]) feed('') screen:expect([[ - {7:aa}aa^ | + {9:aa}aa^ | aaaa | aaaaa | - {3:-- INSERT --} | + {5:-- INSERT --} | ]]) end) end) diff --git a/test/functional/editor/mode_cmdline_spec.lua b/test/functional/editor/mode_cmdline_spec.lua index 70bdc5d4c2..efd7a37c0b 100644 --- a/test/functional/editor/mode_cmdline_spec.lua +++ b/test/functional/editor/mode_cmdline_spec.lua @@ -48,18 +48,14 @@ describe('cmdline', function() it('redraws statusline when toggling overstrike', function() local screen = Screen.new(60, 4) - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText - [1] = { reverse = true, bold = true }, -- StatusLine - }) screen:attach() command('set laststatus=2 statusline=%!mode(1)') feed(':') screen:expect { grid = [[ | - {0:~ }| - {1:c }| + {1:~ }| + {3:c }| :^ | ]], } @@ -67,8 +63,8 @@ describe('cmdline', function() screen:expect { grid = [[ | - {0:~ }| - {1:cr }| + {1:~ }| + {3:cr }| :^ | ]], } diff --git a/test/functional/editor/mode_insert_spec.lua b/test/functional/editor/mode_insert_spec.lua index fb3dda4bf4..fc1e6c4ee4 100644 --- a/test/functional/editor/mode_insert_spec.lua +++ b/test/functional/editor/mode_insert_spec.lua @@ -180,12 +180,6 @@ describe('insert-mode', function() it('multi-char mapping updates screen properly #25626', function() local screen = Screen.new(60, 6) - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText - [1] = { bold = true, reverse = true }, -- StatusLine - [2] = { reverse = true }, -- StatusLineNC - [3] = { bold = true }, -- ModeMsg - }) screen:attach() command('vnew') insert('foo\nfoo\nfoo') @@ -197,10 +191,10 @@ describe('insert-mode', function() grid = [[ foo │ | foo │β^jβ | - foo │{0:~ }| - {0:~ }│{0:~ }| - {2:[No Name] [+] }{1:[No Name] [+] }| - {3:-- INSERT --} | + foo │{1:~ }| + {1:~ }│{1:~ }| + {2:[No Name] [+] }{3:[No Name] [+] }| + {5:-- INSERT --} | ]], } feed('k') @@ -208,9 +202,9 @@ describe('insert-mode', function() grid = [[ foo │ | foo │^βββ | - foo │{0:~ }| - {0:~ }│{0:~ }| - {2:[No Name] [+] }{1:[No Name] [+] }| + foo │{1:~ }| + {1:~ }│{1:~ }| + {2:[No Name] [+] }{3:[No Name] [+] }| | ]], } diff --git a/test/functional/editor/tabpage_spec.lua b/test/functional/editor/tabpage_spec.lua index 0b26494436..c20a6e5cb5 100644 --- a/test/functional/editor/tabpage_spec.lua +++ b/test/functional/editor/tabpage_spec.lua @@ -102,14 +102,9 @@ describe('tabpage', function() it('switching tabpage after setting laststatus=3 #19591', function() local screen = Screen.new(40, 8) - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - [1] = { bold = true, reverse = true }, -- StatusLine - [2] = { reverse = true }, -- TabLineFill - [3] = { bold = true }, -- TabLineSel - [4] = { background = Screen.colors.LightGrey, underline = true }, -- TabLine - [5] = { bold = true, foreground = Screen.colors.Magenta }, - }) + screen:add_extra_attr_ids { + [100] = { bold = true, foreground = Screen.colors.Fuchsia }, + } screen:attach() command('tabnew') @@ -118,18 +113,18 @@ describe('tabpage', function() command('tabnext') feed('') screen:expect([[ - {4: [No Name] }{3: [No Name] }{2: }{4:X}| + {24: [No Name] }{5: [No Name] }{2: }{24:X}| ^ | - {0:~ }|*4 - {1:[No Name] }| + {1:~ }|*4 + {3:[No Name] }| "[No Name]" --No lines in buffer-- | ]]) command('vnew') screen:expect([[ - {4: [No Name] }{3: }{5:2}{3: [No Name] }{2: }{4:X}| + {24: [No Name] }{5: }{100:2}{5: [No Name] }{2: }{24:X}| ^ │ | - {0:~ }│{0:~ }|*4 - {1:[No Name] }| + {1:~ }│{1:~ }|*4 + {3:[No Name] }| "[No Name]" --No lines in buffer-- | ]]) end) -- cgit From eb37241d38ad35b9e6bfac6379dd10e60aa0350c Mon Sep 17 00:00:00 2001 From: Riley Bruins Date: Sun, 26 May 2024 10:27:12 -0700 Subject: fix(tohtml): properly handle multiple hl groups #29012 Problem: :TOhtml doesn't properly handle virtual text when it has multiple highlight groups. It also improperly calculates position offset for multi-byte virt_text characters. Solution: Apply the `vim.api.nvim_strwidth` broadly to properly calculate character offset, and handle the cases where the `hl` argument can be a table of multiple hl groups. --- test/functional/plugin/tohtml_spec.lua | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/plugin/tohtml_spec.lua b/test/functional/plugin/tohtml_spec.lua index 200a5f34b2..be5bada901 100644 --- a/test/functional/plugin/tohtml_spec.lua +++ b/test/functional/plugin/tohtml_spec.lua @@ -287,7 +287,13 @@ describe(':TOhtml', function() 0, { virt_text = { { 'foo' } }, virt_text_pos = 'overlay' } ) - api.nvim_buf_set_extmark(0, ns, 2, 0, { virt_text = { { 'foo' } }, virt_text_pos = 'inline' }) + api.nvim_buf_set_extmark( + 0, + ns, + 2, + 0, + { virt_text = { { 'fo┊o', { 'Conceal', 'Comment' } } }, virt_text_pos = 'inline' } + ) --api.nvim_buf_set_extmark(0,ns,3,0,{virt_text={{'foo'}},virt_text_pos='right_align'}) run_tohtml_and_assert(screen) end) -- cgit From bc63ffcf39e8ad6c0925c0ad8503bfb3ed8497f3 Mon Sep 17 00:00:00 2001 From: luukvbaal Date: Sun, 26 May 2024 19:54:08 +0200 Subject: fix(tui): reset clear_region attributes during startup #28713 Problem: Fix added in #28676 worked accidentally(used variables were themselves uninitialized at this point during startup) and does not always work. Solution: Reset attributes when clearing regions during startup. --- test/functional/terminal/tui_spec.lua | 65 ++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 32 deletions(-) (limited to 'test/functional') diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index d4628ea626..efa65b7441 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -2003,38 +2003,39 @@ describe('TUI', function() ]]) end) - it('invalidated regions are cleared with terminal background attr', function() - local screen = Screen.new(50, 10) - screen:set_default_attr_ids({ [1] = { foreground = Screen.colors.Black } }) - screen:attach() - fn.termopen({ - nvim_prog, - '--clean', - '--cmd', - 'set termguicolors', - '--cmd', - 'sleep 10', - }, { - env = { - VIMRUNTIME = os.getenv('VIMRUNTIME'), - }, - }) - screen:expect({ - grid = [[ - {1:^ }| - {1: }|*8 - | - ]], - }) - screen:try_resize(51, 11) - screen:expect({ - grid = [[ - {1:^ }| - {1: }|*9 - | - ]], - }) - end) + -- #28667, #28668 + for _, guicolors in ipairs({ 'notermguicolors', 'termguicolors' }) do + it('has no black flicker when clearing regions during startup with ' .. guicolors, function() + local screen = Screen.new(50, 10) + screen:attach() + fn.termopen({ + nvim_prog, + '--clean', + '--cmd', + 'set ' .. guicolors, + '--cmd', + 'sleep 10', + }, { + env = { + VIMRUNTIME = os.getenv('VIMRUNTIME'), + }, + }) + screen:expect({ + grid = [[ + ^ | + |*9 + ]], + intermediate = true, + }) + screen:try_resize(51, 11) + screen:expect({ + grid = [[ + ^ | + |*10 + ]], + }) + end) + end it('argv[0] can be overridden #23953', function() if not exec_lua('return pcall(require, "ffi")') then -- cgit From 9a0239fdc8b380a8a32739a7c722fe90e3c2e910 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 27 May 2024 14:37:22 +0800 Subject: fix(drawline): don't draw beyond end of window (#29035) --- test/functional/ui/screen_basic_spec.lua | 37 ++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'test/functional') diff --git a/test/functional/ui/screen_basic_spec.lua b/test/functional/ui/screen_basic_spec.lua index 54580bf47c..85a653df36 100644 --- a/test/functional/ui/screen_basic_spec.lua +++ b/test/functional/ui/screen_basic_spec.lua @@ -4,6 +4,7 @@ local Screen = require('test.functional.ui.screen') local spawn, set_session, clear = n.spawn, n.set_session, n.clear local feed, command = n.feed, n.command +local exec = n.exec local insert = n.insert local eq = t.eq local fn, api = n.fn, n.api @@ -819,3 +820,39 @@ it("showcmd doesn't cause empty grid_line with redrawdebug=compositor #22593", f ]], } end) + +it("scrolling in narrow window doesn't draw over separator #29033", function() + clear() + local screen = Screen.new(60, 8) + screen:attach() + feed('100Oagg') + exec([[ + set number nowrap + vsplit + set scrollbind + wincmd l + set scrollbind + wincmd | + ]]) + screen:expect([[ + {8: }│{8: 1 }^a | + {8: }│{8: 2 }a | + {8: }│{8: 3 }a | + {8: }│{8: 4 }a | + {8: }│{8: 5 }a | + {8: }│{8: 6 }a | + {2:< }{3:[No Name] [+] }| + | + ]]) + feed('') + screen:expect([[ + {8: }│{8: 5 }^a | + {8: }│{8: 6 }a | + {8: }│{8: 7 }a | + {8: }│{8: 8 }a | + {8: }│{8: 9 }a | + {8: }│{8: 10 }a | + {2:< }{3:[No Name] [+] }| + | + ]]) +end) -- cgit From c4eb0b64bd4923a72fe737837cfe234c80fb539c Mon Sep 17 00:00:00 2001 From: Guilherme Soares <48023091+guilhas07@users.noreply.github.com> Date: Mon, 27 May 2024 13:20:03 +0200 Subject: fix(treesitter): find buffer in multiple windows #28922 Problem: 1. When interacting with multiple :InspectTree and the source buffer windows there is a high chance of errors due to the window ids not being updated and validated. 2. Not all InspectTree windows were closed when the source buffer was closed. Solution: 1. Update InspectTree window id on `CursorMoved` event and validate source buffer window id before trying to navigate to it. 2. Close all InspectTree windows --- test/functional/treesitter/inspect_tree_spec.lua | 53 ++++++++++++++++++++++++ 1 file changed, 53 insertions(+) (limited to 'test/functional') diff --git a/test/functional/treesitter/inspect_tree_spec.lua b/test/functional/treesitter/inspect_tree_spec.lua index f5acfe7c4a..b403cca735 100644 --- a/test/functional/treesitter/inspect_tree_spec.lua +++ b/test/functional/treesitter/inspect_tree_spec.lua @@ -114,4 +114,57 @@ describe('vim.treesitter.inspect_tree', function() (fenced_code_block_delimiter)))) ; [2, 0] - [2, 3] markdown ]] end) + + it('updates source and tree buffer windows and closes them correctly', function() + insert([[ + print() + ]]) + + -- setup two windows for the source buffer + exec_lua([[ + source_win = vim.api.nvim_get_current_win() + vim.api.nvim_open_win(0, false, { + win = 0, + split = 'left' + }) + ]]) + + -- setup three windows for the tree buffer + exec_lua([[ + vim.treesitter.start(0, 'lua') + vim.treesitter.inspect_tree() + tree_win = vim.api.nvim_get_current_win() + tree_win_copy_1 = vim.api.nvim_open_win(0, false, { + win = 0, + split = 'left' + }) + tree_win_copy_2 = vim.api.nvim_open_win(0, false, { + win = 0, + split = 'left' + }) + ]]) + + -- close original source window + exec_lua('vim.api.nvim_win_close(source_win, false)') + + -- navigates correctly to the remaining source buffer window + feed('') + eq('', n.api.nvim_get_vvar('errmsg')) + + -- close original tree window + exec_lua([[ + vim.api.nvim_set_current_win(tree_win_copy_1) + vim.api.nvim_win_close(tree_win, false) + ]]) + + -- navigates correctly to the remaining source buffer window + feed('') + eq('', n.api.nvim_get_vvar('errmsg')) + + -- close source buffer window and all remaining tree windows + t.pcall_err(exec_lua, 'vim.api.nvim_win_close(0, false)') + + eq(false, exec_lua('return vim.api.nvim_win_is_valid(tree_win_copy_1)')) + eq(false, exec_lua('return vim.api.nvim_win_is_valid(tree_win_copy_2)')) + end) end) -- cgit From 48251134ee59a3e2f0aeb89608fa820c21b25d4f Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Mon, 27 May 2024 08:08:23 -0500 Subject: perf: add fast path to vim.validate (#28977) For many small/simple functions (like those found in shared.lua), the runtime of vim.validate can far exceed the runtime of the function itself. Add an "overload" to vim.validate that uses a simple assertion pattern, rather than parsing a full "validation spec". --- test/functional/lua/vim_spec.lua | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index c8f94c6ffa..d50b646085 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -1408,7 +1408,25 @@ describe('lua stdlib', function() exec_lua("vim.validate{arg1={{}, 't' }, arg2={ 'foo', 's' }}") exec_lua("vim.validate{arg1={2, function(a) return (a % 2) == 0 end, 'even number' }}") exec_lua("vim.validate{arg1={5, {'n', 's'} }, arg2={ 'foo', {'n', 's'} }}") - + vim.validate('arg1', 5, 'number') + vim.validate('arg1', '5', 'string') + vim.validate('arg1', { 5 }, 'table') + vim.validate('arg1', function() + return 5 + end, 'function') + vim.validate('arg1', nil, 'number', true) + vim.validate('arg1', nil, 'string', true) + vim.validate('arg1', nil, 'table', true) + vim.validate('arg1', nil, 'function', true) + + matches('arg1: expected number, got nil', pcall_err(vim.validate, 'arg1', nil, 'number')) + matches('arg1: expected string, got nil', pcall_err(vim.validate, 'arg1', nil, 'string')) + matches('arg1: expected table, got nil', pcall_err(vim.validate, 'arg1', nil, 'table')) + matches('arg1: expected function, got nil', pcall_err(vim.validate, 'arg1', nil, 'function')) + matches('arg1: expected string, got number', pcall_err(vim.validate, 'arg1', 5, 'string')) + matches('arg1: expected table, got number', pcall_err(vim.validate, 'arg1', 5, 'table')) + matches('arg1: expected function, got number', pcall_err(vim.validate, 'arg1', 5, 'function')) + matches('arg1: expected number, got string', pcall_err(vim.validate, 'arg1', '5', 'number')) matches('expected table, got number', pcall_err(exec_lua, "vim.validate{ 1, 'x' }")) matches('invalid type name: x', pcall_err(exec_lua, "vim.validate{ arg1={ 1, 'x' }}")) matches('invalid type name: 1', pcall_err(exec_lua, 'vim.validate{ arg1={ 1, 1 }}')) -- cgit From 292365fa1b8f543ffa2240bb30af34051ad2d7c8 Mon Sep 17 00:00:00 2001 From: Ilia Choly Date: Mon, 27 May 2024 11:06:03 -0400 Subject: fix(lsp): do not detach from buffer if there are uninitialized clients (#29029) Problem: if on_lines is called before the LSP is initialized, the buffer is detached. Solution: check for uninitialized clients before detaching. --- test/functional/plugin/lsp_spec.lua | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'test/functional') diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index c95a96baca..0cf84b50c2 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -530,6 +530,34 @@ describe('LSP', function() ]]) end) + it('should allow on_lines + nvim_buf_delete during LSP initialization #28575', function() + clear() + exec_lua(create_server_definition) + exec_lua([[ + local initialized = false + local server = _create_server({ + handlers = { + initialize = function(method, params, callback) + vim.schedule(function() + callback(nil, { capabilities = {} }) + initialized = true + end) + end + } + }) + local bufnr = vim.api.nvim_create_buf(false, true) + vim.api.nvim_set_current_buf(bufnr) + local client_id = vim.lsp.start({ + name = 'detach-dummy', + cmd = server.cmd, + }) + vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {"hello"}) + vim.api.nvim_buf_delete(bufnr, {}) + local ok = vim.wait(1000, function() return initialized end) + assert(ok, "lsp did not initialize") + ]]) + end) + it('client should return settings via workspace/configuration handler', function() local expected_handlers = { { NIL, {}, { method = 'shutdown', client_id = 1 } }, -- cgit From ff097f2091e7a970e5b12960683b4dade5563040 Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Sun, 4 Feb 2024 14:13:23 -0800 Subject: feat(lsp): completion side effects --- test/functional/plugin/lsp/completion_spec.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'test/functional') diff --git a/test/functional/plugin/lsp/completion_spec.lua b/test/functional/plugin/lsp/completion_spec.lua index 2798d57381..1052b00dae 100644 --- a/test/functional/plugin/lsp/completion_spec.lua +++ b/test/functional/plugin/lsp/completion_spec.lua @@ -21,7 +21,7 @@ local function complete(line, candidates, lnum) local line, cursor_col, lnum, result = ... local line_to_cursor = line:sub(1, cursor_col) local client_start_boundary = vim.fn.match(line_to_cursor, '\\k*$') - local items, server_start_boundary = require("vim.lsp._completion")._convert_results( + local items, server_start_boundary = require("vim.lsp.completion")._convert_results( line, lnum, cursor_col, @@ -42,7 +42,7 @@ local function complete(line, candidates, lnum) ) end -describe('vim.lsp._completion', function() +describe('vim.lsp.completion', function() before_each(n.clear) -- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion @@ -159,6 +159,7 @@ describe('vim.lsp._completion', function() end, result.items) eq(expected, result) end) + it('uses correct start boundary', function() local completion_list = { isIncomplete = false, -- cgit From 490c2109e6139c268b64c6a88f4678f7c7af51ea Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Sat, 27 Apr 2024 14:59:39 -0700 Subject: test(lsp): add completion tests --- test/functional/plugin/lsp/completion_spec.lua | 232 ++++++++++++++++++++++++- 1 file changed, 231 insertions(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/plugin/lsp/completion_spec.lua b/test/functional/plugin/lsp/completion_spec.lua index 1052b00dae..5b7232ad7e 100644 --- a/test/functional/plugin/lsp/completion_spec.lua +++ b/test/functional/plugin/lsp/completion_spec.lua @@ -1,9 +1,16 @@ ---@diagnostic disable: no-unknown local t = require('test.testutil') +local t_lsp = require('test.functional.plugin.lsp.testutil') local n = require('test.functional.testnvim')() +local clear = n.clear local eq = t.eq +local neq = t.neq local exec_lua = n.exec_lua +local feed = n.feed +local retry = t.retry + +local create_server_definition = t_lsp.create_server_definition --- Convert completion results. --- @@ -25,6 +32,7 @@ local function complete(line, candidates, lnum) line, lnum, cursor_col, + 1, client_start_boundary, nil, result, @@ -42,7 +50,7 @@ local function complete(line, candidates, lnum) ) end -describe('vim.lsp.completion', function() +describe('vim.lsp.completion: item conversion', function() before_each(n.clear) -- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion @@ -187,6 +195,7 @@ describe('vim.lsp.completion', function() dup = 1, empty = 1, icase = 1, + info = '', kind = 'Module', menu = '', word = 'this_thread', @@ -241,6 +250,7 @@ describe('vim.lsp.completion', function() dup = 1, empty = 1, icase = 1, + info = '', kind = 'Module', menu = '', word = 'this_thread', @@ -279,4 +289,224 @@ describe('vim.lsp.completion', function() eq('item-property-has-priority', item.data) eq({ line = 1, character = 1 }, item.textEdit.range.start) end) + + it( + 'uses insertText as textEdit.newText if there are editRange defaults but no textEditText', + function() + --- @type lsp.CompletionList + local completion_list = { + isIncomplete = false, + itemDefaults = { + editRange = { + start = { line = 1, character = 1 }, + ['end'] = { line = 1, character = 4 }, + }, + insertTextFormat = 2, + data = 'foobar', + }, + items = { + { + insertText = 'the-insertText', + label = 'hello', + data = 'item-property-has-priority', + }, + }, + } + local result = complete('|', completion_list) + eq(1, #result.items) + local text = result.items[1].user_data.nvim.lsp.completion_item.textEdit.newText + eq('the-insertText', text) + end + ) +end) + +describe('vim.lsp.completion: protocol', function() + before_each(function() + clear() + exec_lua(create_server_definition) + exec_lua([[ + _G.capture = {} + vim.fn.complete = function(col, matches) + _G.capture.col = col + _G.capture.matches = matches + end + ]]) + end) + + after_each(clear) + + --- @param completion_result lsp.CompletionList + --- @return integer + local function create_server(completion_result) + return exec_lua( + [[ + local result = ... + local server = _create_server({ + capabilities = { + completionProvider = { + triggerCharacters = { '.' } + } + }, + handlers = { + ['textDocument/completion'] = function(_, _, callback) + callback(nil, result) + end + } + }) + + bufnr = vim.api.nvim_get_current_buf() + vim.api.nvim_win_set_buf(0, bufnr) + return vim.lsp.start({ name = 'dummy', cmd = server.cmd, on_attach = function(client, bufnr) + vim.lsp.completion.enable(true, client.id, bufnr) + end}) + ]], + completion_result + ) + end + + local function assert_matches(fn) + retry(nil, nil, function() + fn(exec_lua('return _G.capture.matches')) + end) + end + + --- @param pos { [1]: integer, [2]: integer } + local function trigger_at_pos(pos) + exec_lua( + [[ + local win = vim.api.nvim_get_current_win() + vim.api.nvim_win_set_cursor(win, ...) + vim.lsp.completion.trigger() + ]], + pos + ) + + retry(nil, nil, function() + neq(nil, exec_lua('return _G.capture.col')) + end) + end + + it('fetches completions and shows them using complete on trigger', function() + create_server({ + isIncomplete = false, + items = { + { + label = 'hello', + }, + }, + }) + + feed('ih') + trigger_at_pos({ 1, 1 }) + + assert_matches(function(matches) + eq({ + { + abbr = 'hello', + dup = 1, + empty = 1, + icase = 1, + info = '', + kind = 'Unknown', + menu = '', + user_data = { + nvim = { + lsp = { + client_id = 1, + completion_item = { + label = 'hello', + }, + }, + }, + }, + word = 'hello', + }, + }, matches) + end) + end) + + it('merges results from multiple clients', function() + create_server({ + isIncomplete = false, + items = { + { + label = 'hello', + }, + }, + }) + create_server({ + isIncomplete = false, + items = { + { + label = 'hallo', + }, + }, + }) + + feed('ih') + trigger_at_pos({ 1, 1 }) + + assert_matches(function(matches) + eq(2, #matches) + eq('hello', matches[1].word) + eq('hallo', matches[2].word) + end) + end) + + it('executes commands', function() + local completion_list = { + isIncomplete = false, + items = { + { + label = 'hello', + command = { + arguments = { '1', '0' }, + command = 'dummy', + title = '', + }, + }, + }, + } + local client_id = create_server(completion_list) + + exec_lua( + [[ + _G.called = false + local client = vim.lsp.get_client_by_id(...) + client.commands.dummy = function () + _G.called = true + end + ]], + client_id + ) + + feed('ih') + trigger_at_pos({ 1, 1 }) + + exec_lua( + [[ + local client_id, item = ... + vim.v.completed_item = { + user_data = { + nvim = { + lsp = { + client_id = client_id, + completion_item = item + } + } + } + } + ]], + client_id, + completion_list.items[1] + ) + + feed('') + + assert_matches(function(matches) + eq(1, #matches) + eq('hello', matches[1].word) + eq(true, exec_lua('return _G.called')) + end) + end) end) -- cgit From 7b16c1fa8451880c72769f6d3c311f24c74f4fc7 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 28 May 2024 06:39:07 +0800 Subject: fix(runtime): source c ftplugin properly for cpp on Windows (#29053) On Windows, '{' is currently not treated as a wildcard char, so another wildcard char is needed for the pattern to be treated as a wildcard. It may be worth trying to make '{' always a wildcard char in the future, but that'll be a bit harder as it'll be necessary to make sure '{' is escaped at various places. --- test/functional/lua/runtime_spec.lua | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'test/functional') diff --git a/test/functional/lua/runtime_spec.lua b/test/functional/lua/runtime_spec.lua index 4adce42c3e..c6b0577ebe 100644 --- a/test/functional/lua/runtime_spec.lua +++ b/test/functional/lua/runtime_spec.lua @@ -401,4 +401,12 @@ describe('runtime:', function() eq('ABab', eval('g:seq')) end) end) + + it('cpp ftplugin loads c ftplugin #29053', function() + eq('', eval('&commentstring')) + eq('', eval('&omnifunc')) + exec('edit file.cpp') + eq('/*%s*/', eval('&commentstring')) + eq('ccomplete#Complete', eval('&omnifunc')) + end) end) -- cgit From 5b6477be45c54ebac4dce6bda51028542167fd1f Mon Sep 17 00:00:00 2001 From: luukvbaal Date: Tue, 28 May 2024 11:43:56 +0200 Subject: fix(ui): flush ext_cmdline events before doing cmdpreview #27950 Problem: Unable to update the screen for external cmdline during cmdpreview. Solution: Flush the cmdline UI before cmdpreview state. --- test/functional/lua/ui_event_spec.lua | 53 +++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) (limited to 'test/functional') diff --git a/test/functional/lua/ui_event_spec.lua b/test/functional/lua/ui_event_spec.lua index 1e80c88403..0a6deaa41c 100644 --- a/test/functional/lua/ui_event_spec.lua +++ b/test/functional/lua/ui_event_spec.lua @@ -37,6 +37,9 @@ describe('vim.ui_attach', function() [2] = { bold = true }, [3] = { background = Screen.colors.Grey }, [4] = { background = Screen.colors.LightMagenta }, + [5] = { reverse = true }, + [6] = { reverse = true, bold = true }, + [7] = { background = Screen.colors.Yellow1 }, }) screen:attach() end) @@ -188,6 +191,56 @@ describe('vim.ui_attach', function() feed('versionv') n.assert_alive() end) + + it("preserved 'incsearch/command' screen state after :redraw from ext_cmdline", function() + exec_lua([[ + vim.cmd.norm('ifoobar') + vim.cmd('1split cmdline') + local buf = vim.api.nvim_get_current_buf() + vim.cmd.wincmd('p') + vim.ui_attach(ns, { ext_cmdline = true }, function(event, ...) + if event == 'cmdline_show' then + local content = select(1, ...) + vim.api.nvim_buf_set_lines(buf, -2, -1, false, {content[1][2]}) + vim.cmd('redraw') + end + return true + end) + ]]) + -- Updates a cmdline window + feed(':cmdline') + screen:expect({ + grid = [[ + cmdline | + {5:cmdline [+] }| + fooba^r | + {6:[No Name] [+] }| + | + ]], + }) + -- Does not clear 'incsearch' highlighting + feed('/foo') + screen:expect({ + grid = [[ + foo | + {5:cmdline [+] }| + {5:foo}ba^r | + {6:[No Name] [+] }| + | + ]], + }) + -- Shows new cmdline state during 'inccommand' + feed(':%s/bar/baz') + screen:expect({ + grid = [[ + %s/bar/baz | + {5:cmdline [+] }| + foo{7:ba^z} | + {6:[No Name] [+] }| + | + ]], + }) + end) end) describe('vim.ui_attach', function() -- cgit From b386334cdbbc3e9d79773243fdbd53091488e14d Mon Sep 17 00:00:00 2001 From: bfredl Date: Sun, 26 May 2024 11:36:18 +0200 Subject: refactor(shada): remove ShaDaReadDef secondary wrapper `FileDescriptor` is already a wrapper around an fd and a buffer. By allowing to just use the buffer without an fd, it can already handle in-memory reads. --- test/functional/shada/errors_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/shada/errors_spec.lua b/test/functional/shada/errors_spec.lua index a9084da929..e000d0988b 100644 --- a/test/functional/shada/errors_spec.lua +++ b/test/functional/shada/errors_spec.lua @@ -28,7 +28,7 @@ describe('ShaDa error handling', function() it('fails on zero', function() wshada('\000') eq( - 'Vim(rshada):E576: Error while reading ShaDa file: expected positive integer at position 0, but got nothing', + 'Vim(rshada):E576: Error while reading ShaDa file: expected positive integer at position 1, but got nothing', exc_exec(sdrcmd()) ) end) -- cgit From 8ba73f0e4cc6c82032a348a1d6c8d794ed150fd7 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Tue, 28 May 2024 08:51:44 -0500 Subject: feat(diagnostic): add vim.diagnostic.jump() (#26745) Deprecate vim.diagnostic.goto_prev() and vim.diagnostic.goto_next() in favor of a unified vim.diagnostic.jump() interface. We cannot name the function "goto()" because some of our tooling (luacheck and stylua) fail to parse it, presumably because "goto" is a keyword in newer versions of Lua. vim.diagnostic.jump() also allows moving to a specific diagnostic and moving by multiple diagnostics at a time (useful for creating mappings that use v:count). --- test/functional/lua/diagnostic_spec.lua | 289 +++++++++++++++++++++++--------- 1 file changed, 206 insertions(+), 83 deletions(-) (limited to 'test/functional') diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua index 05082bc132..76246fc2d1 100644 --- a/test/functional/lua/diagnostic_spec.lua +++ b/test/functional/lua/diagnostic_spec.lua @@ -843,17 +843,18 @@ describe('vim.diagnostic', function() end) end) - describe('get_next_pos()', function() + describe('get_next()', function() it('can find the next pos with only one namespace', function() eq( { 1, 1 }, exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), - }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - return vim.diagnostic.get_next_pos() - ]] + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { + make_error('Diagnostic #1', 1, 1, 1, 1), + }) + vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + local next = vim.diagnostic.get_next() + return { next.lnum, next.col } + ]] ) end) @@ -861,14 +862,15 @@ describe('vim.diagnostic', function() eq( { 4, 4 }, exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), - make_error('Diagnostic #2', 4, 4, 4, 4), - }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {3, 1}) - return vim.diagnostic.get_next_pos { namespace = diagnostic_ns } - ]] + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { + make_error('Diagnostic #1', 1, 1, 1, 1), + make_error('Diagnostic #2', 4, 4, 4, 4), + }) + vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, {3, 1}) + local next = vim.diagnostic.get_next({ namespace = diagnostic_ns }) + return { next.lnum, next.col } + ]] ) end) @@ -876,27 +878,29 @@ describe('vim.diagnostic', function() eq( { 1, 1 }, exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), - }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {3, 1}) - return vim.diagnostic.get_next_pos { namespace = diagnostic_ns } - ]] + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { + make_error('Diagnostic #1', 1, 1, 1, 1), + }) + vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, {3, 1}) + local next = vim.diagnostic.get_next({ namespace = diagnostic_ns }) + return { next.lnum, next.col } + ]] ) end) it('will not cycle when wrap is off', function() eq( - false, + vim.NIL, exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), - }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {3, 1}) - return vim.diagnostic.get_next_pos { namespace = diagnostic_ns, wrap = false } - ]] + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { + make_error('Diagnostic #1', 1, 1, 1, 1), + }) + vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, {3, 1}) + local next = vim.diagnostic.get_next({ namespace = diagnostic_ns, wrap = false }) + return next + ]] ) end) @@ -904,13 +908,14 @@ describe('vim.diagnostic', function() eq( { 4, 4 }, exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #2', 4, 4, 4, 4), - }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {vim.api.nvim_buf_line_count(0), 1}) - return vim.diagnostic.get_prev_pos { namespace = diagnostic_ns } - ]] + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { + make_error('Diagnostic #2', 4, 4, 4, 4), + }) + vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, {vim.api.nvim_buf_line_count(0), 1}) + local prev = vim.diagnostic.get_prev({ namespace = diagnostic_ns }) + return { prev.lnum, prev.col } + ]] ) end) @@ -918,15 +923,16 @@ describe('vim.diagnostic', function() eq( { 4, 0 }, exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 3, 9001, 3, 9001), - make_error('Diagnostic #2', 4, 0, 4, 0), - }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {1, 1}) - vim.diagnostic.goto_next { float = false } - return vim.diagnostic.get_next_pos { namespace = diagnostic_ns } - ]] + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { + make_error('Diagnostic #1', 3, 9001, 3, 9001), + make_error('Diagnostic #2', 4, 0, 4, 0), + }) + vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, {1, 1}) + vim.diagnostic.jump({ count = 1, float = false }) + local next = vim.diagnostic.get_next({ namespace = diagnostic_ns }) + return { next.lnum, next.col } + ]] ) end) @@ -935,13 +941,14 @@ describe('vim.diagnostic', function() { 4, 0 }, exec_lua [[ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 3, 9001, 3, 9001), - make_error('Diagnostic #2', 4, -1, 4, -1), + make_error('Diagnostic #1', 3, 9001, 3, 9001), + make_error('Diagnostic #2', 4, -1, 4, -1), }) vim.api.nvim_win_set_buf(0, diagnostic_bufnr) vim.api.nvim_win_set_cursor(0, {1, 1}) - vim.diagnostic.goto_next { float = false } - return vim.diagnostic.get_next_pos { namespace = diagnostic_ns } + vim.diagnostic.jump({ count = 1, float = false }) + local next = vim.diagnostic.get_next({ namespace = diagnostic_ns }) + return { next.lnum, next.col } ]] ) end) @@ -1044,33 +1051,35 @@ describe('vim.diagnostic', function() end) end) - describe('get_prev_pos()', function() - it('can find the prev pos with only one namespace', function() + describe('get_prev()', function() + it('can find the previous diagnostic with only one namespace', function() eq( { 1, 1 }, exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), - }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {3, 1}) - return vim.diagnostic.get_prev_pos() - ]] + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { + make_error('Diagnostic #1', 1, 1, 1, 1), + }) + vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, {3, 1}) + local prev = vim.diagnostic.get_prev() + return { prev.lnum, prev.col } + ]] ) end) - it('can find prev pos with two errors', function() + it('can find the previous diagnostic with two errors', function() eq( { 1, 1 }, exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), - make_error('Diagnostic #2', 4, 4, 4, 4), - }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {3, 1}) - return vim.diagnostic.get_prev_pos { namespace = diagnostic_ns } - ]] + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { + make_error('Diagnostic #1', 1, 1, 1, 1), + make_error('Diagnostic #2', 4, 4, 4, 4), + }) + vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, {3, 1}) + local prev = vim.diagnostic.get_prev({ namespace = diagnostic_ns }) + return { prev.lnum, prev.col } + ]] ) end) @@ -1078,27 +1087,29 @@ describe('vim.diagnostic', function() eq( { 4, 4 }, exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #2', 4, 4, 4, 4), - }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {3, 1}) - return vim.diagnostic.get_prev_pos { namespace = diagnostic_ns } - ]] + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { + make_error('Diagnostic #2', 4, 4, 4, 4), + }) + vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, {3, 1}) + local prev = vim.diagnostic.get_prev({ namespace = diagnostic_ns }) + return { prev.lnum, prev.col } + ]] ) end) it('respects wrap parameter', function() eq( - false, + vim.NIL, exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #2', 4, 4, 4, 4), - }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {3, 1}) - return vim.diagnostic.get_prev_pos { namespace = diagnostic_ns, wrap = false} - ]] + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { + make_error('Diagnostic #2', 4, 4, 4, 4), + }) + vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, {3, 1}) + local prev = vim.diagnostic.get_prev({ namespace = diagnostic_ns, wrap = false}) + return prev + ]] ) end) @@ -1126,6 +1137,118 @@ describe('vim.diagnostic', function() end) end) + describe('jump()', function() + before_each(function() + exec_lua([[ + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { + make_error('Diagnostic #1', 0, 0, 0, 2), + make_error('Diagnostic #2', 1, 1, 1, 4), + make_warning('Diagnostic #3', 2, -1, 2, -1), + make_info('Diagnostic #4', 3, 0, 3, 3), + }) + vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + ]]) + end) + + it('can move forward', function() + eq( + { 2, 1 }, + exec_lua([[ + vim.api.nvim_win_set_cursor(0, { 1, 0 }) + vim.diagnostic.jump({ count = 1 }) + return vim.api.nvim_win_get_cursor(0) + ]]) + ) + + eq( + { 4, 0 }, + exec_lua([[ + vim.api.nvim_win_set_cursor(0, { 1, 0 }) + vim.diagnostic.jump({ count = 3 }) + return vim.api.nvim_win_get_cursor(0) + ]]) + ) + + eq( + { 4, 0 }, + exec_lua([[ + vim.api.nvim_win_set_cursor(0, { 1, 0 }) + vim.diagnostic.jump({ count = math.huge, wrap = false }) + return vim.api.nvim_win_get_cursor(0) + ]]) + ) + end) + + it('can move backward', function() + eq( + { 3, 0 }, + exec_lua([[ + vim.api.nvim_win_set_cursor(0, { 4, 0 }) + vim.diagnostic.jump({ count = -1 }) + return vim.api.nvim_win_get_cursor(0) + ]]) + ) + + eq( + { 1, 0 }, + exec_lua([[ + vim.api.nvim_win_set_cursor(0, { 4, 0 }) + vim.diagnostic.jump({ count = -3 }) + return vim.api.nvim_win_get_cursor(0) + ]]) + ) + + eq( + { 1, 0 }, + exec_lua([[ + vim.api.nvim_win_set_cursor(0, { 4, 0 }) + vim.diagnostic.jump({ count = -math.huge, wrap = false }) + return vim.api.nvim_win_get_cursor(0) + ]]) + ) + end) + + it('can filter by severity', function() + eq( + { 3, 0 }, + exec_lua([[ + vim.api.nvim_win_set_cursor(0, { 1, 0 }) + vim.diagnostic.jump({ count = 1, severity = vim.diagnostic.severity.WARN }) + return vim.api.nvim_win_get_cursor(0) + ]]) + ) + + eq( + { 3, 0 }, + exec_lua([[ + vim.api.nvim_win_set_cursor(0, { 1, 0 }) + vim.diagnostic.jump({ count = 9999, severity = vim.diagnostic.severity.WARN }) + return vim.api.nvim_win_get_cursor(0) + ]]) + ) + end) + + it('can wrap', function() + eq( + { 1, 0 }, + exec_lua([[ + vim.api.nvim_win_set_cursor(0, { 4, 0 }) + vim.diagnostic.jump({ count = 1, wrap = true }) + return vim.api.nvim_win_get_cursor(0) + ]]) + ) + + eq( + { 4, 0 }, + exec_lua([[ + vim.api.nvim_win_set_cursor(0, { 1, 0 }) + vim.diagnostic.jump({ count = -1, wrap = true }) + return vim.api.nvim_win_get_cursor(0) + ]]) + ) + end) + end) + describe('get()', function() it('returns an empty table when no diagnostics are present', function() eq({}, exec_lua [[return vim.diagnostic.get(diagnostic_bufnr, {namespace=diagnostic_ns})]]) -- cgit From e6cfcaed184d4ecdc8a8638429e1bd9e1b3251dc Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Sat, 25 May 2024 10:23:05 -0700 Subject: feat(snippet): add default keymaps during snippet session --- test/functional/lua/snippet_spec.lua | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) (limited to 'test/functional') diff --git a/test/functional/lua/snippet_spec.lua b/test/functional/lua/snippet_spec.lua index 413aa93994..bca0a59cb4 100644 --- a/test/functional/lua/snippet_spec.lua +++ b/test/functional/lua/snippet_spec.lua @@ -1,3 +1,5 @@ +---@diagnostic disable: no-unknown + local t = require('test.testutil') local n = require('test.functional.testnvim')() @@ -16,11 +18,6 @@ local retry = t.retry describe('vim.snippet', function() before_each(function() clear() - - exec_lua([[ - vim.keymap.set({ 'i', 's' }, '', function() vim.snippet.jump(1) end, { buffer = true }) - vim.keymap.set({ 'i', 's' }, '', function() vim.snippet.jump(-1) end, { buffer = true }) - ]]) end) after_each(clear) @@ -286,4 +283,24 @@ describe('vim.snippet', function() ]] ) end) + + it('restores snippet navigation keymaps', function() + -- Create a buffer keymap in insert mode that deletes all lines. + local curbuf = api.nvim_get_current_buf() + exec_lua('vim.api.nvim_buf_set_keymap(..., "i", "", "normal ggdG", {})', curbuf) + + test_expand_success({ 'var $1 = $2' }, { 'var = ' }) + + -- While the snippet is active, should navigate between tabstops. + feed('x') + poke_eventloop() + feed('0') + eq({ 'var x = 0' }, buf_lines(0)) + + exec_lua('vim.snippet.stop()') + + -- After exiting the snippet, the buffer keymap should be restored. + feed('O') + eq({ '' }, buf_lines(0)) + end) end) -- cgit From 1c6d9200521acb2329be55ab8bec3056deade66a Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Tue, 28 May 2024 13:24:16 -0500 Subject: feat(defaults): use vim.diagnostic.jump() for default mappings (#29066) This allows the mappings to work with a count and also enables new ]D and [D mappings to go to the last/first diagnostic in the buffer. --- test/functional/lua/diagnostic_spec.lua | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'test/functional') diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua index 76246fc2d1..a4f882e363 100644 --- a/test/functional/lua/diagnostic_spec.lua +++ b/test/functional/lua/diagnostic_spec.lua @@ -969,7 +969,7 @@ describe('vim.diagnostic', function() eq( { 3, 0 }, exec_lua([[ - vim.diagnostic.goto_next({_highest = true}) + vim.diagnostic.jump({ count = 1, _highest = true }) return vim.api.nvim_win_get_cursor(0) ]]) ) @@ -977,7 +977,7 @@ describe('vim.diagnostic', function() eq( { 5, 0 }, exec_lua([[ - vim.diagnostic.goto_next({_highest = true}) + vim.diagnostic.jump({ count = 1, _highest = true }) return vim.api.nvim_win_get_cursor(0) ]]) ) @@ -998,7 +998,7 @@ describe('vim.diagnostic', function() eq( { 4, 0 }, exec_lua([[ - vim.diagnostic.goto_next({_highest = true}) + vim.diagnostic.jump({ count = 1, _highest = true }) return vim.api.nvim_win_get_cursor(0) ]]) ) @@ -1006,7 +1006,7 @@ describe('vim.diagnostic', function() eq( { 6, 0 }, exec_lua([[ - vim.diagnostic.goto_next({_highest = true}) + vim.diagnostic.jump({ count = 1, _highest = true }) return vim.api.nvim_win_get_cursor(0) ]]) ) @@ -1028,7 +1028,7 @@ describe('vim.diagnostic', function() eq( { 2, 0 }, exec_lua([[ - vim.diagnostic.goto_next() + vim.diagnostic.jump({ count = 1 }) return vim.api.nvim_win_get_cursor(0) ]]) ) @@ -1036,7 +1036,7 @@ describe('vim.diagnostic', function() eq( { 3, 0 }, exec_lua([[ - vim.diagnostic.goto_next() + vim.diagnostic.jump({ count = 1 }) return vim.api.nvim_win_get_cursor(0) ]]) ) @@ -1044,7 +1044,7 @@ describe('vim.diagnostic', function() eq( { 4, 0 }, exec_lua([[ - vim.diagnostic.goto_next() + vim.diagnostic.jump({ count = 1 }) return vim.api.nvim_win_get_cursor(0) ]]) ) @@ -1107,7 +1107,7 @@ describe('vim.diagnostic', function() }) vim.api.nvim_win_set_buf(0, diagnostic_bufnr) vim.api.nvim_win_set_cursor(0, {3, 1}) - local prev = vim.diagnostic.get_prev({ namespace = diagnostic_ns, wrap = false}) + local prev = vim.diagnostic.get_prev({ namespace = diagnostic_ns, wrap = false }) return prev ]] ) -- cgit From 0df2c6b5d09fab392dd1a14e4b2e6a3b03203aaa Mon Sep 17 00:00:00 2001 From: Mathias Fussenegger Date: Tue, 28 May 2024 21:37:46 +0200 Subject: feat(lsp): use fuzzy match on filterText instead of prefix match The `complete()` mechanism matches completion candidates against the typed text, so strict pre-filtering isn't necessary. This is a first step towards supporting postfix snippets (like `items@insert` in luals) --- test/functional/plugin/lsp/completion_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/plugin/lsp/completion_spec.lua b/test/functional/plugin/lsp/completion_spec.lua index 5b7232ad7e..078abdf653 100644 --- a/test/functional/plugin/lsp/completion_spec.lua +++ b/test/functional/plugin/lsp/completion_spec.lua @@ -228,7 +228,7 @@ describe('vim.lsp.completion: item conversion', function() }, }, { - filterText = 'notthis_thread', + filterText = 'no_match', insertText = 'notthis_thread', insertTextFormat = 1, kind = 9, -- cgit From b2bad0ac91ddb9b33c3547b6fd4f7278794818d9 Mon Sep 17 00:00:00 2001 From: Mathias Fussenegger Date: Tue, 28 May 2024 23:20:25 +0200 Subject: feat(lsp): support postfix snippets in completion --- test/functional/plugin/lsp/completion_spec.lua | 108 +++++++++++++++++-------- 1 file changed, 73 insertions(+), 35 deletions(-) (limited to 'test/functional') diff --git a/test/functional/plugin/lsp/completion_spec.lua b/test/functional/plugin/lsp/completion_spec.lua index 078abdf653..d7755dd0c4 100644 --- a/test/functional/plugin/lsp/completion_spec.lua +++ b/test/functional/plugin/lsp/completion_spec.lua @@ -78,32 +78,6 @@ describe('vim.lsp.completion: item conversion', function() textEdit = { newText = 'foobar', range = range0 }, }, { label = 'foocar', sortText = 'f', textEdit = { newText = 'foobar', range = range0 } }, - -- real-world snippet text - { - label = 'foocar', - sortText = 'g', - insertText = 'foodar', - insertTextFormat = 2, - textEdit = { - newText = 'foobar(${1:place holder}, ${2:more ...holder{\\}})', - range = range0, - }, - }, - { - label = 'foocar', - sortText = 'h', - insertText = 'foodar(${1:var1} typ1, ${2:var2} *typ2) {$0\\}', - insertTextFormat = 2, - }, - -- nested snippet tokens - { - label = 'foocar', - sortText = 'i', - insertText = 'foodar(${1:${2|typ1,typ2|}}) {$0\\}', - insertTextFormat = 2, - }, - -- braced tabstop - { label = 'foocar', sortText = 'j', insertText = 'foodar()${0}', insertTextFormat = 2 }, -- plain text { label = 'foocar', @@ -139,23 +113,87 @@ describe('vim.lsp.completion: item conversion', function() }, { abbr = 'foocar', - word = 'foobar(place holder, more ...holder{})', + word = 'foodar(${1:var1})', -- marked as PlainText, text is used as is + }, + } + local result = complete('|', completion_list) + result = vim.tbl_map(function(x) + return { + abbr = x.abbr, + word = x.word, + } + end, result.items) + eq(expected, result) + end) + + it('prefers wordlike components for snippets', function() + -- There are two goals here: + -- + -- 1. The `word` should match what the user started typing, so that vim.fn.complete() doesn't + -- filter it away, preventing snippet expansion + -- + -- For example, if they type `items@ins`, luals returns `table.insert(items, $0)` as + -- textEdit.newText and `insert` as label. + -- There would be no prefix match if textEdit.newText is used as `word` + -- + -- 2. If users do not expand a snippet, but continue typing, they should see a somewhat reasonable + -- `word` getting inserted. + -- + -- For example in: + -- + -- insertText: "testSuites ${1:Env}" + -- label: "testSuites" + -- + -- "testSuites" should have priority as `word`, as long as the full snippet gets expanded on accept () + local range0 = { + start = { line = 0, character = 0 }, + ['end'] = { line = 0, character = 0 }, + } + local completion_list = { + -- luals postfix snippet (typed text: items@ins|) + { + label = 'insert', + insertTextFormat = 2, + textEdit = { + newText = 'table.insert(items, $0)', + range = range0, + }, }, + + -- eclipse.jdt.ls `new` snippet { - abbr = 'foocar', - word = 'foodar(var1 typ1, var2 *typ2) {}', + label = 'new', + insertTextFormat = 2, + textEdit = { + newText = '${1:Object} ${2:foo} = new ${1}(${3});\n${0}', + range = range0, + }, + textEditText = '${1:Object} ${2:foo} = new ${1}(${3});\n${0}', }, + + -- eclipse.jdt.ls `List.copyO` function call completion { - abbr = 'foocar', - word = 'foodar(typ1) {}', + label = 'copyOf(Collection coll) : List', + insertTextFormat = 2, + insertText = 'copyOf', + textEdit = { + newText = 'copyOf(${1:coll})', + range = range0, + }, }, + } + local expected = { { - abbr = 'foocar', - word = 'foodar()', + abbr = 'copyOf(Collection coll) : List', + word = 'copyOf', }, { - abbr = 'foocar', - word = 'foodar(${1:var1})', + abbr = 'insert', + word = 'insert', + }, + { + abbr = 'new', + word = 'new', }, } local result = complete('|', completion_list) -- cgit From 5c33815448e11b514678f39cecc74e68131d4628 Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Thu, 30 May 2024 10:46:26 +0200 Subject: refactor(lsp): replace util.buf_versions with changedtick (#28943) `lsp.util.buf_versions` was already derived from changedtick (`on_lines` from `buf_attach` synced the version) As far as I can tell there is no need to keep track of the state in a separate table. --- test/functional/fixtures/fake-lsp-server.lua | 14 +++++------ .../functional/plugin/lsp/semantic_tokens_spec.lua | 24 +++++++++--------- test/functional/plugin/lsp_spec.lua | 29 ++++++++-------------- 3 files changed, 29 insertions(+), 38 deletions(-) (limited to 'test/functional') diff --git a/test/functional/fixtures/fake-lsp-server.lua b/test/functional/fixtures/fake-lsp-server.lua index f806869b40..9aafd38d4f 100644 --- a/test/functional/fixtures/fake-lsp-server.lua +++ b/test/functional/fixtures/fake-lsp-server.lua @@ -471,7 +471,7 @@ function tests.basic_check_buffer_open() languageId = '', text = table.concat({ 'testing', '123' }, '\n') .. '\n', uri = 'file://', - version = 0, + version = 2, }, }) expect_notification('finish') @@ -498,7 +498,7 @@ function tests.basic_check_buffer_open_and_change() languageId = '', text = table.concat({ 'testing', '123' }, '\n') .. '\n', uri = 'file://', - version = 0, + version = 2, }, }) expect_notification('textDocument/didChange', { @@ -534,7 +534,7 @@ function tests.basic_check_buffer_open_and_change_noeol() languageId = '', text = table.concat({ 'testing', '123' }, '\n'), uri = 'file://', - version = 0, + version = 2, }, }) expect_notification('textDocument/didChange', { @@ -569,7 +569,7 @@ function tests.basic_check_buffer_open_and_change_multi() languageId = '', text = table.concat({ 'testing', '123' }, '\n') .. '\n', uri = 'file://', - version = 0, + version = 2, }, }) expect_notification('textDocument/didChange', { @@ -614,7 +614,7 @@ function tests.basic_check_buffer_open_and_change_multi_and_close() languageId = '', text = table.concat({ 'testing', '123' }, '\n') .. '\n', uri = 'file://', - version = 0, + version = 2, }, }) expect_notification('textDocument/didChange', { @@ -672,7 +672,7 @@ function tests.basic_check_buffer_open_and_change_incremental() languageId = '', text = table.concat({ 'testing', '123' }, '\n') .. '\n', uri = 'file://', - version = 0, + version = 2, }, }) expect_notification('textDocument/didChange', { @@ -715,7 +715,7 @@ function tests.basic_check_buffer_open_and_change_incremental_editing() languageId = '', text = table.concat({ 'testing', '123' }, '\n'), uri = 'file://', - version = 0, + version = 2, }, }) expect_notification('textDocument/didChange', { diff --git a/test/functional/plugin/lsp/semantic_tokens_spec.lua b/test/functional/plugin/lsp/semantic_tokens_spec.lua index 7908c5d2e7..9babb080e7 100644 --- a/test/functional/plugin/lsp/semantic_tokens_spec.lua +++ b/test/functional/plugin/lsp/semantic_tokens_spec.lua @@ -111,6 +111,7 @@ describe('semantic token highlighting', function() end) it('buffer is highlighted when attached', function() + insert(text) exec_lua([[ bufnr = vim.api.nvim_get_current_buf() vim.api.nvim_win_set_buf(0, bufnr) @@ -118,8 +119,6 @@ describe('semantic token highlighting', function() client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) ]]) - insert(text) - screen:expect { grid = [[ #include | @@ -141,6 +140,7 @@ describe('semantic token highlighting', function() end) it('use LspTokenUpdate and highlight_token', function() + insert(text) exec_lua([[ vim.api.nvim_create_autocmd("LspTokenUpdate", { callback = function(args) @@ -157,8 +157,6 @@ describe('semantic token highlighting', function() client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) ]]) - insert(text) - screen:expect { grid = [[ #include | @@ -180,14 +178,17 @@ describe('semantic token highlighting', function() end) it('buffer is unhighlighted when client is detached', function() + insert(text) + exec_lua([[ bufnr = vim.api.nvim_get_current_buf() vim.api.nvim_win_set_buf(0, bufnr) client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) + vim.wait(1000, function() + return #server.messages > 1 + end) ]]) - insert(text) - exec_lua([[ vim.notify = function() end vim.lsp.buf_detach_client(bufnr, client_id) @@ -331,14 +332,13 @@ describe('semantic token highlighting', function() end) it('buffer is re-highlighted when force refreshed', function() + insert(text) exec_lua([[ bufnr = vim.api.nvim_get_current_buf() vim.api.nvim_win_set_buf(0, bufnr) client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) ]]) - insert(text) - screen:expect { grid = [[ #include | @@ -412,13 +412,14 @@ describe('semantic token highlighting', function() end) it('updates highlights with delta request on buffer change', function() + insert(text) + exec_lua([[ bufnr = vim.api.nvim_get_current_buf() vim.api.nvim_win_set_buf(0, bufnr) client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) ]]) - insert(text) screen:expect { grid = [[ #include | @@ -597,6 +598,7 @@ describe('semantic token highlighting', function() end) it('does not send delta requests if not supported by server', function() + insert(text) exec_lua( [[ local legend, response, edit_response = ... @@ -625,7 +627,6 @@ describe('semantic token highlighting', function() edit_response ) - insert(text) screen:expect { grid = [[ #include | @@ -1449,6 +1450,7 @@ int main() }, }) do it(test.it, function() + insert(test.text1) exec_lua(create_server_definition) exec_lua( [[ @@ -1485,8 +1487,6 @@ int main() test.response2 ) - insert(test.text1) - test.expected_screen1() local highlights = exec_lua([[ diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 0cf84b50c2..85891e59b5 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -255,7 +255,7 @@ describe('LSP', function() return end local expected_handlers = { - { NIL, {}, { method = 'shutdown', bufnr = 1, client_id = 1 } }, + { NIL, {}, { method = 'shutdown', bufnr = 1, client_id = 1, version = 2 } }, { NIL, {}, { method = 'test', client_id = 1 } }, } test_rpc_server { @@ -948,7 +948,11 @@ describe('LSP', function() it('should forward ContentModified to callback', function() local expected_handlers = { { NIL, {}, { method = 'finish', client_id = 1 } }, - { { code = -32801 }, NIL, { method = 'error_code_test', bufnr = 1, client_id = 1 } }, + { + { code = -32801 }, + NIL, + { method = 'error_code_test', bufnr = 1, client_id = 1, version = 2 }, + }, } local client --- @type vim.lsp.Client test_rpc_server { @@ -978,7 +982,7 @@ describe('LSP', function() it('should track pending requests to the language server', function() local expected_handlers = { { NIL, {}, { method = 'finish', client_id = 1 } }, - { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1 } }, + { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1, version = 2 } }, } local client --- @type vim.lsp.Client test_rpc_server { @@ -1045,7 +1049,7 @@ describe('LSP', function() it('should clear pending and cancel requests on reply', function() local expected_handlers = { { NIL, {}, { method = 'finish', client_id = 1 } }, - { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1 } }, + { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1, version = 2 } }, } local client --- @type vim.lsp.Client test_rpc_server { @@ -1084,7 +1088,7 @@ describe('LSP', function() it('should trigger LspRequest autocmd when requests table changes', function() local expected_handlers = { { NIL, {}, { method = 'finish', client_id = 1 } }, - { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1 } }, + { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1, version = 2 } }, } local client --- @type vim.lsp.Client test_rpc_server { @@ -1364,6 +1368,7 @@ describe('LSP', function() }, bufnr = 2, client_id = 1, + version = 2, }, }, { NIL, {}, { method = 'start', client_id = 1 } }, @@ -2117,7 +2122,6 @@ describe('LSP', function() local args = {...} local bufnr = select(1, ...) local text_edit = select(2, ...) - vim.lsp.util.buf_versions[bufnr] = 10 vim.lsp.util.apply_text_document_edit(text_edit, nil, 'utf-16') ]], target_bufnr, @@ -2134,7 +2138,6 @@ describe('LSP', function() [[ local args = {...} local versionedBuf = args[2] - vim.lsp.util.buf_versions[versionedBuf.bufnr] = versionedBuf.currentVersion vim.lsp.util.apply_text_document_edit(args[1], nil, 'utf-16') ]], edit, @@ -2239,18 +2242,6 @@ describe('LSP', function() } vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines) - - local update_changed_tick = function() - vim.lsp.util.buf_versions[bufnr] = vim.api.nvim_buf_get_var(bufnr, 'changedtick') - end - - update_changed_tick() - vim.api.nvim_buf_attach(bufnr, false, { - on_changedtick = function() - update_changed_tick() - end - }) - return {bufnr, vim.api.nvim_buf_get_var(bufnr, 'changedtick')} ]] -- cgit From d24f3d055ae7b3e9e47e9eb53a1dafb3ad44760c Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Thu, 30 May 2024 19:57:47 -0500 Subject: test: do not set termguicolors in test runner It's not clear why this is needed and it has adverse side effects on other tests. --- test/functional/testnvim.lua | 2 +- test/functional/ui/popupmenu_spec.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'test/functional') diff --git a/test/functional/testnvim.lua b/test/functional/testnvim.lua index 6b858e4d69..5f24ef3fe6 100644 --- a/test/functional/testnvim.lua +++ b/test/functional/testnvim.lua @@ -22,7 +22,7 @@ local runtime_set = 'set runtimepath^=./build/lib/nvim/' M.nvim_prog = (os.getenv('NVIM_PRG') or t.paths.test_build_dir .. '/bin/nvim') -- Default settings for the test session. M.nvim_set = ( - 'set shortmess+=IS background=light termguicolors noswapfile noautoindent startofline' + 'set shortmess+=IS background=light noswapfile noautoindent startofline' .. ' laststatus=1 undodir=. directory=. viewdir=. backupdir=.' .. ' belloff= wildoptions-=pum joinspaces noshowcmd noruler nomore redrawdebug=invalid' ) diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index 8f8604eecb..cc21a797e3 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -1129,7 +1129,7 @@ describe("builtin popupmenu 'pumblend'", function() [10] = { foreground = tonumber('0x000002') }, }) screen:attach({ rgb = false }) - command('set notermguicolors pumblend=10') + command('set pumblend=10') insert([[ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor -- cgit From d87ecfc8bc3c737e2e7f766d365e67dd08c3b600 Mon Sep 17 00:00:00 2001 From: Ilia Choly Date: Thu, 30 May 2024 13:11:21 -0400 Subject: docs(luacats): add tuple support --- test/functional/script/luacats_grammar_spec.lua | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'test/functional') diff --git a/test/functional/script/luacats_grammar_spec.lua b/test/functional/script/luacats_grammar_spec.lua index 6d444e1888..d6fff3f409 100644 --- a/test/functional/script/luacats_grammar_spec.lua +++ b/test/functional/script/luacats_grammar_spec.lua @@ -159,4 +159,11 @@ describe('luacats grammar', function() name = 'type', type = '`T`', }) + + test('@param type [number,string] this is a tuple type', { + desc = 'this is a tuple type', + kind = 'param', + name = 'type', + type = '[number,string]', + }) end) -- cgit From 5493fcd52f2eaab4b6a81c366529e80ca3dec535 Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Fri, 31 May 2024 08:25:40 -0500 Subject: test: remove checks for failed tests on Windows --- test/functional/core/startup_spec.lua | 6 ------ 1 file changed, 6 deletions(-) (limited to 'test/functional') diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua index a53625ab1b..1bb4ce2946 100644 --- a/test/functional/core/startup_spec.lua +++ b/test/functional/core/startup_spec.lua @@ -400,9 +400,6 @@ describe('startup', function() read_file('Xtest_startup_ttyout') ) end) - if is_os('win') then - assert_log('stream write failed. RPC canceled; closing channel', testlog) - end end) it('input from pipe: has("ttyin")==0 has("ttyout")==1', function() @@ -435,9 +432,6 @@ describe('startup', function() read_file('Xtest_startup_ttyout') ) end) - if is_os('win') then - assert_log('stream write failed. RPC canceled; closing channel', testlog) - end end) it('input from pipe (implicit) #7679', function() -- cgit From f2083bd55cafe861e9dffb1c1658e5b0983c5ef6 Mon Sep 17 00:00:00 2001 From: luukvbaal Date: Sat, 1 Jun 2024 12:10:35 +0200 Subject: fix(column): crash with 'signcolumn' set to "number" (#29003) Problem: Numberwidth may depend on number of signs with text in the buffer and is not handled correctly for extmark signs. Solution: Move legacy sign code for changed numberwidth so that it is handled properly for legacy and extmark signs alike. --- test/functional/ui/decorations_spec.lua | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'test/functional') diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua index 746bfb3262..3e67e33ddb 100644 --- a/test/functional/ui/decorations_spec.lua +++ b/test/functional/ui/decorations_spec.lua @@ -5497,6 +5497,26 @@ l5 api.nvim_buf_clear_namespace(0, ns, 0, -1) end) + + it([[correct numberwidth with 'signcolumn' set to "number" #28984]], function() + command('set number numberwidth=1 signcolumn=number') + api.nvim_buf_set_extmark(0, ns, 0, 0, { sign_text = 'S1' }) + screen:expect({ + grid = [[ + S1 ^ | + {1:~ }|*8 + | + ]] + }) + api.nvim_buf_del_extmark(0, ns, 1) + screen:expect({ + grid = [[ + {8:1 }^ | + {1:~ }|*8 + | + ]] + }) + end) end) describe('decorations: virt_text', function() -- cgit From 9eb0426002696fba4a7c5b9cadd8799a8ae18e6a Mon Sep 17 00:00:00 2001 From: Ilia Choly Date: Fri, 31 May 2024 11:47:32 -0400 Subject: fix(luacats): allow all types inside tuples --- test/functional/script/luacats_grammar_spec.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'test/functional') diff --git a/test/functional/script/luacats_grammar_spec.lua b/test/functional/script/luacats_grammar_spec.lua index d6fff3f409..9c6417f7bf 100644 --- a/test/functional/script/luacats_grammar_spec.lua +++ b/test/functional/script/luacats_grammar_spec.lua @@ -160,10 +160,10 @@ describe('luacats grammar', function() type = '`T`', }) - test('@param type [number,string] this is a tuple type', { + test('@param type [number,string,"good"|"bad"] this is a tuple type', { desc = 'this is a tuple type', kind = 'param', name = 'type', - type = '[number,string]', + type = '[number,string,"good"|"bad"]', }) end) -- cgit From 56337310efc765a760b7a1ca0040c7c6ce23574e Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 2 Jun 2024 15:18:30 +0800 Subject: test: add a test for #29119 --- test/functional/lua/buffer_updates_spec.lua | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'test/functional') diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua index d4af7e4732..6b575ad0ef 100644 --- a/test/functional/lua/buffer_updates_spec.lua +++ b/test/functional/lua/buffer_updates_spec.lua @@ -379,6 +379,25 @@ describe('lua buffer event callbacks: on_lines', function() ]], }) end) + + it('line lengths are correct when pressing TAB with folding #29119', function() + api.nvim_buf_set_lines(0, 0, -1, true, { 'a', 'b' }) + + exec_lua([[ + _G.res = {} + vim.o.foldmethod = 'indent' + vim.o.softtabstop = -1 + vim.api.nvim_buf_attach(0, false, { + on_lines = function(_, bufnr, _, row, _, end_row) + local lines = vim.api.nvim_buf_get_lines(bufnr, row, end_row, true) + table.insert(_G.res, lines) + end + }) + ]]) + + feed('i') + eq({ '\ta' }, exec_lua('return _G.res[#_G.res]')) + end) end) describe('lua: nvim_buf_attach on_bytes', function() -- cgit From 19be3d26830ced203631045f2f622e75e6d857a7 Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Sun, 2 Jun 2024 09:54:15 +0200 Subject: fix(lsp): trim trailing whitespace from completion words (#29122) the `complete()` mechanism doesn't play nicely with trailing newlines or tabs. A newline causes it to insert a null character, showing up as `^@`. --- test/functional/plugin/lsp/completion_spec.lua | 35 ++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'test/functional') diff --git a/test/functional/plugin/lsp/completion_spec.lua b/test/functional/plugin/lsp/completion_spec.lua index d7755dd0c4..d8a3e0acbd 100644 --- a/test/functional/plugin/lsp/completion_spec.lua +++ b/test/functional/plugin/lsp/completion_spec.lua @@ -126,6 +126,41 @@ describe('vim.lsp.completion: item conversion', function() eq(expected, result) end) + it('trims trailing newline or tab from textEdit', function() + local range0 = { + start = { line = 0, character = 0 }, + ['end'] = { line = 0, character = 0 }, + } + local items = { + { + detail = 'ansible.builtin', + filterText = 'lineinfile ansible.builtin.lineinfile builtin ansible', + kind = 7, + label = 'ansible.builtin.lineinfile', + sortText = '2_ansible.builtin.lineinfile', + textEdit = { + newText = 'ansible.builtin.lineinfile:\n ', + range = range0, + }, + }, + } + local result = complete('|', items) + result = vim.tbl_map(function(x) + return { + abbr = x.abbr, + word = x.word, + } + end, result.items) + + local expected = { + { + abbr = 'ansible.builtin.lineinfile', + word = 'ansible.builtin.lineinfile:', + }, + } + eq(expected, result) + end) + it('prefers wordlike components for snippets', function() -- There are two goals here: -- -- cgit From 054a287dbe6fe4308d26ec593da2057641f2bb9b Mon Sep 17 00:00:00 2001 From: Soham Shanbhag Date: Mon, 3 Jun 2024 16:48:43 +0900 Subject: feat(ftplugin): change 'commentstring' to `// %s` for C/C++ (#29085) Problem: The default commentstring for C/C++ can lead to invalid code when commenting and does not match the Nvim codebase. Solution: Change commentstring to `// %s` as used by Neovim. Also set all commentstrings that derive from the default C string explicitly (and correctly). --- test/functional/lua/runtime_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/lua/runtime_spec.lua b/test/functional/lua/runtime_spec.lua index c6b0577ebe..f63363d6d9 100644 --- a/test/functional/lua/runtime_spec.lua +++ b/test/functional/lua/runtime_spec.lua @@ -406,7 +406,7 @@ describe('runtime:', function() eq('', eval('&commentstring')) eq('', eval('&omnifunc')) exec('edit file.cpp') - eq('/*%s*/', eval('&commentstring')) + eq('// %s', eval('&commentstring')) eq('ccomplete#Complete', eval('&omnifunc')) end) end) -- cgit From 8cbb1f20e557461c8417583a7f69d53aaaef920b Mon Sep 17 00:00:00 2001 From: Ilia Choly Date: Tue, 4 Jun 2024 09:06:02 -0400 Subject: refactor(lua): use tuple syntax everywhere #29111 --- test/functional/plugin/lsp/completion_spec.lua | 2 +- test/functional/testnvim.lua | 2 +- test/functional/ui/screen.lua | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'test/functional') diff --git a/test/functional/plugin/lsp/completion_spec.lua b/test/functional/plugin/lsp/completion_spec.lua index d8a3e0acbd..0e81e4fddb 100644 --- a/test/functional/plugin/lsp/completion_spec.lua +++ b/test/functional/plugin/lsp/completion_spec.lua @@ -443,7 +443,7 @@ describe('vim.lsp.completion: protocol', function() end) end - --- @param pos { [1]: integer, [2]: integer } + --- @param pos [integer, integer] local function trigger_at_pos(pos) exec_lua( [[ diff --git a/test/functional/testnvim.lua b/test/functional/testnvim.lua index 6b858e4d69..746c7290ef 100644 --- a/test/functional/testnvim.lua +++ b/test/functional/testnvim.lua @@ -256,7 +256,7 @@ end --- @param notification_cb function? --- @param setup_cb function? --- @param timeout integer ---- @return {[1]: integer, [2]: string} +--- @return [integer, string] function M.run_session(lsession, request_cb, notification_cb, setup_cb, timeout) local on_request --- @type function? local on_notification --- @type function? diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index f8e95f7d88..932ddb070a 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -438,7 +438,7 @@ end --- @field mouse_enabled? boolean --- --- @field win_viewport? table> ---- @field float_pos? {[1]:integer,[2]:integer} +--- @field float_pos? [integer,integer] --- @field hl_groups? table --- --- The following keys should be used to expect the state of various ext_ -- cgit From b66106a46c5c6180c7f80852a8c822b400e73100 Mon Sep 17 00:00:00 2001 From: luukvbaal Date: Tue, 4 Jun 2024 15:09:12 +0200 Subject: fix(ui): superfluous showmode / excessive grid_cursor_goto #29089 Problem: Unsetting global variables earlier in #28578 to avoid recursiveness, caused superfluous or even unlimited showmode(). Solution: Partly revert #28578 so that the globals are unset at the end of showmode(), and avoid recursiveness for ext UI by adding a recursive function guard to each generated UI call that may call a Lua callback. --- test/functional/ui/messages_spec.lua | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'test/functional') diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua index ca52a265fa..07192800e5 100644 --- a/test/functional/ui/messages_spec.lua +++ b/test/functional/ui/messages_spec.lua @@ -1081,6 +1081,22 @@ stack traceback: }, }) end) + + it('does not do showmode unnecessarily #29086', function() + local screen_showmode = screen._handle_msg_showmode + local showmode = 0 + screen._handle_msg_showmode = function(...) + screen_showmode(...) + showmode = showmode + 1 + end + screen:expect({ + grid = [[ + ^ | + {1:~ }|*4 + ]], + }) + eq(showmode, 1) + end) end) describe('ui/builtin messages', function() -- cgit From 2e6d295f799c27372e5c0c44727fa613c81717fd Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Tue, 4 Jun 2024 17:21:37 +0200 Subject: fix(lsp): account for changedtick version gap on modified reset (#29170) Follow up to https://github.com/neovim/neovim/pull/28943 Fixes https://github.com/neovim/neovim/issues/29163 --- test/functional/plugin/lsp_spec.lua | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'test/functional') diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 85891e59b5..23f6b733d5 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -2133,15 +2133,13 @@ describe('LSP', function() }, buf_lines(target_bufnr)) end) it('skips the edit if the version of the edit is behind the local buffer ', function() - local apply_edit_mocking_current_version = function(edit, versionedBuf) + local apply_edit_mocking_current_version = function(edit) exec_lua( [[ local args = {...} - local versionedBuf = args[2] vim.lsp.util.apply_text_document_edit(args[1], nil, 'utf-16') ]], - edit, - versionedBuf + edit ) end @@ -2153,17 +2151,17 @@ describe('LSP', function() eq(baseText, buf_lines(target_bufnr)) -- Apply an edit for an old version, should skip - apply_edit_mocking_current_version( - text_document_edit(2), - { currentVersion = 7, bufnr = target_bufnr } - ) + apply_edit_mocking_current_version(text_document_edit(1)) eq(baseText, buf_lines(target_bufnr)) -- no change -- Sanity check that next version to current does apply change - apply_edit_mocking_current_version( - text_document_edit(8), - { currentVersion = 7, bufnr = target_bufnr } - ) + apply_edit_mocking_current_version(text_document_edit(exec_lua( + [[ + local bufnr = ... + return vim.b[bufnr].changedtick + ]], + target_bufnr + ))) eq({ 'First ↥ 🤦 🦄 line of text', '2nd line of 语text', -- cgit From f69937fdbd162630c35e119e67bbbf052558c0e0 Mon Sep 17 00:00:00 2001 From: Andre Toerien <49614525+AThePeanut4@users.noreply.github.com> Date: Tue, 4 Jun 2024 23:35:44 +0200 Subject: fix(diagnostic): fix float scope filtering (#29134) --- test/functional/lua/diagnostic_spec.lua | 114 ++++++++++++++++++++++++++++++-- 1 file changed, 107 insertions(+), 7 deletions(-) (limited to 'test/functional') diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua index a4f882e363..decb58dc4d 100644 --- a/test/functional/lua/diagnostic_spec.lua +++ b/test/functional/lua/diagnostic_spec.lua @@ -2291,6 +2291,38 @@ describe('vim.diagnostic', function() return lines ]] ) + + -- End position is exclusive + eq( + vim.NIL, + exec_lua [[ + local diagnostics = { + make_error("Syntax error", 1, 1, 2, 0), + } + vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) + vim.api.nvim_win_set_cursor(0, {1, 1}) + local _, winnr = vim.diagnostic.open_float(0, {header=false, pos={2,0}}) + return winnr + ]] + ) + + -- Works when width == 0 + eq( + { '1. Syntax error' }, + exec_lua [[ + local diagnostics = { + make_error("Syntax error", 2, 0, 2, 0), + } + vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) + vim.api.nvim_win_set_cursor(0, {1, 1}) + local float_bufnr, winnr = vim.diagnostic.open_float(0, {header=false, pos={2,1}}) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + ]] + ) end) it('can show diagnostics from a specific position', function() @@ -2299,7 +2331,7 @@ describe('vim.diagnostic', function() { 'Syntax error' }, exec_lua [[ local diagnostics = { - make_error("Syntax error", 1, 1, 1, 2), + make_error("Syntax error", 1, 1, 1, 3), make_warning("Some warning", 1, 3, 1, 4), } vim.api.nvim_win_set_buf(0, diagnostic_bufnr) @@ -2317,7 +2349,7 @@ describe('vim.diagnostic', function() { 'Some warning' }, exec_lua [[ local diagnostics = { - make_error("Syntax error", 1, 1, 1, 2), + make_error("Syntax error", 1, 1, 1, 3), make_warning("Some warning", 1, 3, 1, 4), } vim.api.nvim_win_set_buf(0, diagnostic_bufnr) @@ -2347,6 +2379,38 @@ describe('vim.diagnostic', function() return lines ]] ) + + -- End position is exclusive + eq( + vim.NIL, + exec_lua [[ + local diagnostics = { + make_error("Syntax error", 1, 1, 1, 3), + } + vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) + vim.api.nvim_win_set_cursor(0, {1, 1}) + local _, winnr = vim.diagnostic.open_float(0, {header=false, scope="cursor", pos={1,3}}) + return winnr + ]] + ) + + -- Works when width == 0 + eq( + { 'Syntax error' }, + exec_lua [[ + local diagnostics = { + make_error("Syntax error", 2, 0, 2, 0), + } + vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) + vim.api.nvim_win_set_cursor(0, {1, 1}) + local float_bufnr, winnr = vim.diagnostic.open_float({header=false, scope="cursor", pos={2,1}}) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + ]] + ) end) it( @@ -2755,20 +2819,32 @@ describe('vim.diagnostic', function() end) it('works for multi-line diagnostics #21949', function() - -- open float failed non diagnostic lnum - eq( - vim.NIL, - exec_lua [[ + -- create diagnostic + exec_lua [[ local diagnostics = { make_error("Error in two lines lnum is 1 and end_lnum is 2", 1, 1, 2, 3), } - local winids = {} vim.api.nvim_win_set_buf(0, diagnostic_bufnr) vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) + ]] + + -- open float failed non diagnostic lnum + eq( + vim.NIL, + exec_lua [[ + vim.api.nvim_win_set_cursor(0, {1, 0}) local _, winnr = vim.diagnostic.open_float(0, { header = false }) return winnr ]] ) + eq( + vim.NIL, + exec_lua [[ + vim.api.nvim_win_set_cursor(0, {1, 0}) + local _, winnr = vim.diagnostic.open_float(0, { header = false, scope = "cursor" }) + return winnr + ]] + ) -- can open a float window on lnum 1 eq( @@ -2782,6 +2858,18 @@ describe('vim.diagnostic', function() ]] ) + -- can open a cursor-scoped float window on lnum 1 + eq( + { 'Error in two lines lnum is 1 and end_lnum is 2' }, + exec_lua [[ + vim.api.nvim_win_set_cursor(0, {2, 1}) + local float_bufnr, winnr = vim.diagnostic.open_float(0, { header = false, scope = "cursor" }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + ]] + ) + -- can open a float window on end_lnum 2 eq( { '1. Error in two lines lnum is 1 and end_lnum is 2' }, @@ -2793,6 +2881,18 @@ describe('vim.diagnostic', function() return lines ]] ) + + -- can open a cursor-scoped float window on end_lnum 2 + eq( + { 'Error in two lines lnum is 1 and end_lnum is 2' }, + exec_lua [[ + vim.api.nvim_win_set_cursor(0, {3, 2}) + local float_bufnr, winnr = vim.diagnostic.open_float(0, { header = false, scope = "cursor" }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + ]] + ) end) end) -- cgit From 43bd9c9c1cacb2f069c7e84330a608623c874d74 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 5 Jun 2024 16:47:43 +0800 Subject: fix(lua): don't clamp -1 or v:maxcol in vim.highlight.range() (#29203) --- test/functional/lua/highlight_spec.lua | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'test/functional') diff --git a/test/functional/lua/highlight_spec.lua b/test/functional/lua/highlight_spec.lua index 8f099ac233..66095121b0 100644 --- a/test/functional/lua/highlight_spec.lua +++ b/test/functional/lua/highlight_spec.lua @@ -90,6 +90,22 @@ describe('vim.highlight.range', function() | ]]) end) + + it('can use -1 or v:maxcol to indicate end of line', function() + exec_lua([[ + local ns = vim.api.nvim_create_namespace('') + vim.highlight.range(0, ns, 'Search', { 0, 4 }, { 1, -1 }, {}) + vim.highlight.range(0, ns, 'Search', { 2, 6 }, { 3, vim.v.maxcol }, {}) + ]]) + screen:expect([[ + ^asdf{10:ghjkl}{100:$} | + {10:«口=口»}{100:$} | + qwerty{10:uiop}{100:$} | + {10:口口=口口}{1:$} | + zxcvbnm{1:$} | + | + ]]) + end) end) describe('vim.highlight.on_yank', function() -- cgit From d7651b27d54a87c5783c0a579af11da9a16a39aa Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Wed, 5 Jun 2024 08:27:56 -0500 Subject: fix(tui): move $COLORTERM check to _defaults.lua (#29197) We currently check $COLORTERM in the TUI process to determine if the terminal supports 24 bit color (truecolor). If $COLORTERM is "truecolor" or "24bit" then we automatically assume that the terminal supports truecolor, but if $COLORTERM is set to any other value we still query the terminal. The `rgb` flag of the UI struct is a boolean which only indicates whether the UI supports truecolor, but does not have a 3rd state that we can use to represent "we don't know if the UI supports truecolor". We currently use `rgb=false` to represent this "we don't know" state, and we use XTGETTCAP and DECRQSS queries to determine at runtime if the terminal supports truecolor. However, if $COLORTERM is set to a value besides "truecolor" or "24bit" (e.g. "256" or "16) that is a clear indication that the terminal _does not_ support truecolor, so it is incorrect to treat `rgb=false` as "we don't know" in that case. Instead, in the TUI process we only check for the terminfo capabilities. This must be done in the TUI process because we do not have access to this information in the core Neovim process when `_defaults.lua` runs. If the TUI cannot determine truecolor support from terminfo alone, we set `rgb=false` to indicate "we don't know if the terminal supports truecolor yet, keep checking". When we get to `_defaults.lua`, we can then check $COLORTERM and only query the terminal if it is unset. This means that users can explicitly opt out of truecolor determination by setting `COLORTERM=256` (or similar) in their environment. --- test/functional/terminal/tui_spec.lua | 55 +++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) (limited to 'test/functional') diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index efa65b7441..80df336cc4 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -2939,6 +2939,61 @@ describe('TUI', function() end) end) + it('does not query the terminal for truecolor support if $COLORTERM is set', function() + clear() + exec_lua([[ + vim.api.nvim_create_autocmd('TermRequest', { + callback = function(args) + local req = args.data + vim.g.termrequest = req + local xtgettcap = req:match('^\027P%+q([%x;]+)$') + if xtgettcap then + local t = {} + for cap in vim.gsplit(xtgettcap, ';') do + local resp = string.format('\027P1+r%s\027\\', xtgettcap) + vim.api.nvim_chan_send(vim.bo[args.buf].channel, resp) + t[vim.text.hexdecode(cap)] = true + end + vim.g.xtgettcap = t + return true + elseif req:match('^\027P$qm\027\\$') then + vim.g.decrqss = true + end + end, + }) + ]]) + + local child_server = new_pipename() + screen = tt.setup_child_nvim({ + '--listen', + child_server, + '-u', + 'NONE', + '-i', + 'NONE', + }, { + env = { + VIMRUNTIME = os.getenv('VIMRUNTIME'), + -- With COLORTERM=256, Nvim should not query the terminal and should not set 'tgc' + COLORTERM = '256', + TERM = 'xterm-256colors', + }, + }) + + screen:expect({ any = '%[No Name%]' }) + + local child_session = n.connect(child_server) + retry(nil, 1000, function() + local xtgettcap = eval("get(g:, 'xtgettcap', {})") + eq(nil, xtgettcap['Tc']) + eq(nil, xtgettcap['RGB']) + eq(nil, xtgettcap['setrgbf']) + eq(nil, xtgettcap['setrgbb']) + eq(0, eval([[get(g:, 'decrqss')]])) + eq({ true, 0 }, { child_session:request('nvim_eval', '&termguicolors') }) + end) + end) + it('queries the terminal for OSC 52 support', function() clear() exec_lua([[ -- cgit From cb6c0fda718e4503fc1bfc49a9fe92411f5f9005 Mon Sep 17 00:00:00 2001 From: sus-domesticus <134197728+sus-domesticus@users.noreply.github.com> Date: Thu, 6 Jun 2024 17:16:43 +0300 Subject: feat(editorconfig): add support for spelling_language (#28638) --- test/functional/plugin/editorconfig_spec.lua | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/plugin/editorconfig_spec.lua b/test/functional/plugin/editorconfig_spec.lua index 839a723405..242ed9b57f 100644 --- a/test/functional/plugin/editorconfig_spec.lua +++ b/test/functional/plugin/editorconfig_spec.lua @@ -16,8 +16,16 @@ local testdir = 'Xtest-editorconfig' local function test_case(name, expected) local filename = testdir .. pathsep .. name command('edit ' .. filename) + for opt, val in pairs(expected) do - eq(val, api.nvim_get_option_value(opt, { buf = 0 }), name) + local opt_info = api.nvim_get_option_info2(opt, {}) + if opt_info.scope == 'win' then + eq(val, api.nvim_get_option_value(opt, { win = 0 }), name) + elseif opt_info.scope == 'buf' then + eq(val, api.nvim_get_option_value(opt, { buf = 0 }), name) + else + eq(val, api.nvim_get_option_value(opt, {}), name) + end end end @@ -93,6 +101,12 @@ setup(function() [max_line_length.txt] max_line_length = 42 + + [short_spelling_language.txt] + spelling_language = de + + [long_spelling_language.txt] + spelling_language = en-NZ ]] ) end) @@ -222,4 +236,9 @@ But not this one eq(true, ok, err) end) + + it('sets spelllang', function() + test_case('short_spelling_language.txt', { spelllang = 'de' }) + test_case('long_spelling_language.txt', { spelllang = 'en_nz' }) + end) end) -- cgit From 6e45cd7f0026ee33b8c397b810dcfe5b4678bbd8 Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Fri, 7 Jun 2024 11:36:46 +0200 Subject: fix(lsp): revert buf_versions deprecation/replacement (#29217) * Revert "fix(lsp): account for changedtick version gap on modified reset (#29170)" This reverts commit 2e6d295f799c27372e5c0c44727fa613c81717fd. * Revert "refactor(lsp): replace util.buf_versions with changedtick (#28943)" This reverts commit 5c33815448e11b514678f39cecc74e68131d4628. --- test/functional/fixtures/fake-lsp-server.lua | 14 +++--- .../functional/plugin/lsp/semantic_tokens_spec.lua | 24 +++++----- test/functional/plugin/lsp_spec.lua | 51 +++++++++++++--------- 3 files changed, 50 insertions(+), 39 deletions(-) (limited to 'test/functional') diff --git a/test/functional/fixtures/fake-lsp-server.lua b/test/functional/fixtures/fake-lsp-server.lua index 9aafd38d4f..f806869b40 100644 --- a/test/functional/fixtures/fake-lsp-server.lua +++ b/test/functional/fixtures/fake-lsp-server.lua @@ -471,7 +471,7 @@ function tests.basic_check_buffer_open() languageId = '', text = table.concat({ 'testing', '123' }, '\n') .. '\n', uri = 'file://', - version = 2, + version = 0, }, }) expect_notification('finish') @@ -498,7 +498,7 @@ function tests.basic_check_buffer_open_and_change() languageId = '', text = table.concat({ 'testing', '123' }, '\n') .. '\n', uri = 'file://', - version = 2, + version = 0, }, }) expect_notification('textDocument/didChange', { @@ -534,7 +534,7 @@ function tests.basic_check_buffer_open_and_change_noeol() languageId = '', text = table.concat({ 'testing', '123' }, '\n'), uri = 'file://', - version = 2, + version = 0, }, }) expect_notification('textDocument/didChange', { @@ -569,7 +569,7 @@ function tests.basic_check_buffer_open_and_change_multi() languageId = '', text = table.concat({ 'testing', '123' }, '\n') .. '\n', uri = 'file://', - version = 2, + version = 0, }, }) expect_notification('textDocument/didChange', { @@ -614,7 +614,7 @@ function tests.basic_check_buffer_open_and_change_multi_and_close() languageId = '', text = table.concat({ 'testing', '123' }, '\n') .. '\n', uri = 'file://', - version = 2, + version = 0, }, }) expect_notification('textDocument/didChange', { @@ -672,7 +672,7 @@ function tests.basic_check_buffer_open_and_change_incremental() languageId = '', text = table.concat({ 'testing', '123' }, '\n') .. '\n', uri = 'file://', - version = 2, + version = 0, }, }) expect_notification('textDocument/didChange', { @@ -715,7 +715,7 @@ function tests.basic_check_buffer_open_and_change_incremental_editing() languageId = '', text = table.concat({ 'testing', '123' }, '\n'), uri = 'file://', - version = 2, + version = 0, }, }) expect_notification('textDocument/didChange', { diff --git a/test/functional/plugin/lsp/semantic_tokens_spec.lua b/test/functional/plugin/lsp/semantic_tokens_spec.lua index 9babb080e7..7908c5d2e7 100644 --- a/test/functional/plugin/lsp/semantic_tokens_spec.lua +++ b/test/functional/plugin/lsp/semantic_tokens_spec.lua @@ -111,7 +111,6 @@ describe('semantic token highlighting', function() end) it('buffer is highlighted when attached', function() - insert(text) exec_lua([[ bufnr = vim.api.nvim_get_current_buf() vim.api.nvim_win_set_buf(0, bufnr) @@ -119,6 +118,8 @@ describe('semantic token highlighting', function() client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) ]]) + insert(text) + screen:expect { grid = [[ #include | @@ -140,7 +141,6 @@ describe('semantic token highlighting', function() end) it('use LspTokenUpdate and highlight_token', function() - insert(text) exec_lua([[ vim.api.nvim_create_autocmd("LspTokenUpdate", { callback = function(args) @@ -157,6 +157,8 @@ describe('semantic token highlighting', function() client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) ]]) + insert(text) + screen:expect { grid = [[ #include | @@ -178,17 +180,14 @@ describe('semantic token highlighting', function() end) it('buffer is unhighlighted when client is detached', function() - insert(text) - exec_lua([[ bufnr = vim.api.nvim_get_current_buf() vim.api.nvim_win_set_buf(0, bufnr) client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) - vim.wait(1000, function() - return #server.messages > 1 - end) ]]) + insert(text) + exec_lua([[ vim.notify = function() end vim.lsp.buf_detach_client(bufnr, client_id) @@ -332,13 +331,14 @@ describe('semantic token highlighting', function() end) it('buffer is re-highlighted when force refreshed', function() - insert(text) exec_lua([[ bufnr = vim.api.nvim_get_current_buf() vim.api.nvim_win_set_buf(0, bufnr) client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) ]]) + insert(text) + screen:expect { grid = [[ #include | @@ -412,14 +412,13 @@ describe('semantic token highlighting', function() end) it('updates highlights with delta request on buffer change', function() - insert(text) - exec_lua([[ bufnr = vim.api.nvim_get_current_buf() vim.api.nvim_win_set_buf(0, bufnr) client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) ]]) + insert(text) screen:expect { grid = [[ #include | @@ -598,7 +597,6 @@ describe('semantic token highlighting', function() end) it('does not send delta requests if not supported by server', function() - insert(text) exec_lua( [[ local legend, response, edit_response = ... @@ -627,6 +625,7 @@ describe('semantic token highlighting', function() edit_response ) + insert(text) screen:expect { grid = [[ #include | @@ -1450,7 +1449,6 @@ int main() }, }) do it(test.it, function() - insert(test.text1) exec_lua(create_server_definition) exec_lua( [[ @@ -1487,6 +1485,8 @@ int main() test.response2 ) + insert(test.text1) + test.expected_screen1() local highlights = exec_lua([[ diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 23f6b733d5..0cf84b50c2 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -255,7 +255,7 @@ describe('LSP', function() return end local expected_handlers = { - { NIL, {}, { method = 'shutdown', bufnr = 1, client_id = 1, version = 2 } }, + { NIL, {}, { method = 'shutdown', bufnr = 1, client_id = 1 } }, { NIL, {}, { method = 'test', client_id = 1 } }, } test_rpc_server { @@ -948,11 +948,7 @@ describe('LSP', function() it('should forward ContentModified to callback', function() local expected_handlers = { { NIL, {}, { method = 'finish', client_id = 1 } }, - { - { code = -32801 }, - NIL, - { method = 'error_code_test', bufnr = 1, client_id = 1, version = 2 }, - }, + { { code = -32801 }, NIL, { method = 'error_code_test', bufnr = 1, client_id = 1 } }, } local client --- @type vim.lsp.Client test_rpc_server { @@ -982,7 +978,7 @@ describe('LSP', function() it('should track pending requests to the language server', function() local expected_handlers = { { NIL, {}, { method = 'finish', client_id = 1 } }, - { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1, version = 2 } }, + { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1 } }, } local client --- @type vim.lsp.Client test_rpc_server { @@ -1049,7 +1045,7 @@ describe('LSP', function() it('should clear pending and cancel requests on reply', function() local expected_handlers = { { NIL, {}, { method = 'finish', client_id = 1 } }, - { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1, version = 2 } }, + { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1 } }, } local client --- @type vim.lsp.Client test_rpc_server { @@ -1088,7 +1084,7 @@ describe('LSP', function() it('should trigger LspRequest autocmd when requests table changes', function() local expected_handlers = { { NIL, {}, { method = 'finish', client_id = 1 } }, - { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1, version = 2 } }, + { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1 } }, } local client --- @type vim.lsp.Client test_rpc_server { @@ -1368,7 +1364,6 @@ describe('LSP', function() }, bufnr = 2, client_id = 1, - version = 2, }, }, { NIL, {}, { method = 'start', client_id = 1 } }, @@ -2122,6 +2117,7 @@ describe('LSP', function() local args = {...} local bufnr = select(1, ...) local text_edit = select(2, ...) + vim.lsp.util.buf_versions[bufnr] = 10 vim.lsp.util.apply_text_document_edit(text_edit, nil, 'utf-16') ]], target_bufnr, @@ -2133,13 +2129,16 @@ describe('LSP', function() }, buf_lines(target_bufnr)) end) it('skips the edit if the version of the edit is behind the local buffer ', function() - local apply_edit_mocking_current_version = function(edit) + local apply_edit_mocking_current_version = function(edit, versionedBuf) exec_lua( [[ local args = {...} + local versionedBuf = args[2] + vim.lsp.util.buf_versions[versionedBuf.bufnr] = versionedBuf.currentVersion vim.lsp.util.apply_text_document_edit(args[1], nil, 'utf-16') ]], - edit + edit, + versionedBuf ) end @@ -2151,17 +2150,17 @@ describe('LSP', function() eq(baseText, buf_lines(target_bufnr)) -- Apply an edit for an old version, should skip - apply_edit_mocking_current_version(text_document_edit(1)) + apply_edit_mocking_current_version( + text_document_edit(2), + { currentVersion = 7, bufnr = target_bufnr } + ) eq(baseText, buf_lines(target_bufnr)) -- no change -- Sanity check that next version to current does apply change - apply_edit_mocking_current_version(text_document_edit(exec_lua( - [[ - local bufnr = ... - return vim.b[bufnr].changedtick - ]], - target_bufnr - ))) + apply_edit_mocking_current_version( + text_document_edit(8), + { currentVersion = 7, bufnr = target_bufnr } + ) eq({ 'First ↥ 🤦 🦄 line of text', '2nd line of 语text', @@ -2240,6 +2239,18 @@ describe('LSP', function() } vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines) + + local update_changed_tick = function() + vim.lsp.util.buf_versions[bufnr] = vim.api.nvim_buf_get_var(bufnr, 'changedtick') + end + + update_changed_tick() + vim.api.nvim_buf_attach(bufnr, false, { + on_changedtick = function() + update_changed_tick() + end + }) + return {bufnr, vim.api.nvim_buf_get_var(bufnr, 'changedtick')} ]] -- cgit From 2ce4a4d91e4abee0aab8b98c47eea9fbd4849ba6 Mon Sep 17 00:00:00 2001 From: Al Colmenar <57642956+alcolmenar@users.noreply.github.com> Date: Fri, 7 Jun 2024 02:54:43 -0700 Subject: fix(lsp): fix reverse sorting of same position text edits (#29212) Problem: Text edits with the same position (both line and character) were being reverse sorted prior to being applied which differs from the lsp spec Solution: Change the sort order for just the same position edits --- test/functional/plugin/lsp_spec.lua | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'test/functional') diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 0cf84b50c2..6d28b83be8 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -1789,9 +1789,9 @@ describe('LSP', function() } exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') eq({ - '', - '123', - 'fooFbar', + '3', + 'foo', + '12Fbar', '123irst guy', 'baz line of text', 'The next line of text', @@ -1813,9 +1813,9 @@ describe('LSP', function() } exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') eq({ - '', - '123', - 'fooFbar', + '3', + 'foo', + '12Fbar', '123irst guy', 'baz line of text', 'The next line of text', -- cgit From f3632e14e3a75114415050ab01c2d04a06036009 Mon Sep 17 00:00:00 2001 From: altermo <107814000+altermo@users.noreply.github.com> Date: Fri, 7 Jun 2024 17:33:40 +0200 Subject: feat: get/set namespace properties #28728 ref https://github.com/neovim/neovim/pull/28432 ref https://github.com/neovim/neovim/issues/28469 --- test/functional/lua/highlight_spec.lua | 14 +- test/functional/ui/decorations_spec.lua | 218 +++++++++++++++++--------------- 2 files changed, 123 insertions(+), 109 deletions(-) (limited to 'test/functional') diff --git a/test/functional/lua/highlight_spec.lua b/test/functional/lua/highlight_spec.lua index 66095121b0..ad709a06f1 100644 --- a/test/functional/lua/highlight_spec.lua +++ b/test/functional/lua/highlight_spec.lua @@ -4,7 +4,6 @@ local Screen = require('test.functional.ui.screen') local exec_lua = n.exec_lua local eq = t.eq -local neq = t.neq local eval = n.eval local command = n.command local clear = n.clear @@ -142,9 +141,11 @@ describe('vim.highlight.on_yank', function() vim.api.nvim_buf_set_mark(0,"]",1,1,{}) vim.highlight.on_yank({timeout = math.huge, on_macro = true, event = {operator = "y"}}) ]]) - neq({}, api.nvim__win_get_ns(0)) + local ns = api.nvim_create_namespace('hlyank') + local win = api.nvim_get_current_win() + eq({ win }, api.nvim__ns_get(ns).wins) command('wincmd w') - eq({}, api.nvim__win_get_ns(0)) + eq({ win }, api.nvim__ns_get(ns).wins) end) it('removes old highlight if new one is created before old one times out', function() @@ -154,14 +155,17 @@ describe('vim.highlight.on_yank', function() vim.api.nvim_buf_set_mark(0,"]",1,1,{}) vim.highlight.on_yank({timeout = math.huge, on_macro = true, event = {operator = "y"}}) ]]) - neq({}, api.nvim__win_get_ns(0)) + local ns = api.nvim_create_namespace('hlyank') + eq(api.nvim_get_current_win(), api.nvim__ns_get(ns).wins[1]) command('wincmd w') exec_lua([[ vim.api.nvim_buf_set_mark(0,"[",1,1,{}) vim.api.nvim_buf_set_mark(0,"]",1,1,{}) vim.highlight.on_yank({timeout = math.huge, on_macro = true, event = {operator = "y"}}) ]]) + local win = api.nvim_get_current_win() + eq({ win }, api.nvim__ns_get(ns).wins) command('wincmd w') - eq({}, api.nvim__win_get_ns(0)) + eq({ win }, api.nvim__ns_get(ns).wins) end) end) diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua index 3e67e33ddb..318dc8c197 100644 --- a/test/functional/ui/decorations_spec.lua +++ b/test/functional/ui/decorations_spec.lua @@ -5595,20 +5595,26 @@ describe('decorations: virt_text', function() end) describe('decorations: window scoped', function() - local screen, ns + local screen, ns, win_other local url = 'https://example.com' before_each(function() clear() screen = Screen.new(20, 10) screen:attach() screen:add_extra_attr_ids { - [100] = { special = Screen.colors.Red, undercurl = true }, - [101] = { url = "https://example.com" }, + [100] = { special = Screen.colors.Red, undercurl = true }, + [101] = { url = 'https://example.com' }, } ns = api.nvim_create_namespace 'test' insert('12345') + + win_other = api.nvim_open_win(0, false, { + col=0,row=0,width=20,height=10, + relative = 'win',style = 'minimal', + hide = true + }) end) local noextmarks = { @@ -5616,28 +5622,28 @@ describe('decorations: window scoped', function() 1234^5 | {1:~ }|*8 | - ]]} + ]], + } - local function set_scoped_extmark(line, col, opts) - return api.nvim_buf_set_extmark(0, ns, line, col, vim.tbl_extend('error', { scoped = true }, opts)) + local function set_extmark(line, col, opts) + return api.nvim_buf_set_extmark(0, ns, line, col, opts) end it('hl_group', function() - set_scoped_extmark(0, 0, { + set_extmark(0, 0, { hl_group = 'Comment', end_col = 3, }) - screen:expect(noextmarks) - - api.nvim__win_add_ns(0, ns) + api.nvim__ns_set(ns, { wins = { 0 } }) screen:expect { grid = [[ {18:123}4^5 | {1:~ }|*8 | - ]]} + ]], + } command 'split' command 'only' @@ -5646,48 +5652,55 @@ describe('decorations: window scoped', function() end) it('virt_text', function() - set_scoped_extmark(0, 0, { + set_extmark(0, 0, { virt_text = { { 'a', 'Comment' } }, virt_text_pos = 'eol', }) - set_scoped_extmark(0, 5, { + set_extmark(0, 5, { virt_text = { { 'b', 'Comment' } }, virt_text_pos = 'inline', }) - set_scoped_extmark(0, 1, { + set_extmark(0, 1, { virt_text = { { 'c', 'Comment' } }, virt_text_pos = 'overlay', }) - set_scoped_extmark(0, 1, { + set_extmark(0, 1, { virt_text = { { 'd', 'Comment' } }, virt_text_pos = 'right_align', }) - screen:expect(noextmarks) - - api.nvim__win_add_ns(0, ns) + api.nvim__ns_set(ns, { wins = { 0 } }) screen:expect { grid = [[ 1{18:c}34^5{18:b} {18:a} {18:d}| {1:~ }|*8 | - ]]} + ]], + } command 'split' command 'only' screen:expect(noextmarks) + + api.nvim__ns_set(ns, { wins = {} }) + + screen:expect { + grid = [[ + 1{18:c}34^5{18:b} {18:a} {18:d}| + {1:~ }|*8 + | + ]], + } end) it('virt_lines', function() - set_scoped_extmark(0, 0, { + set_extmark(0, 0, { virt_lines = { { { 'a', 'Comment' } } }, }) - screen:expect(noextmarks) - - api.nvim__win_add_ns(0, ns) + api.nvim__ns_set(ns, { wins = { 0 } }) screen:expect { grid = [[ @@ -5695,7 +5708,8 @@ describe('decorations: window scoped', function() {18:a} | {1:~ }|*7 | - ]]} + ]], + } command 'split' command 'only' @@ -5704,14 +5718,12 @@ describe('decorations: window scoped', function() end) it('redraws correctly with inline virt_text and wrapping', function() - set_scoped_extmark(0, 2, { - virt_text = {{ ('b'):rep(18), 'Comment' }}, - virt_text_pos = 'inline' + set_extmark(0, 2, { + virt_text = { { ('b'):rep(18), 'Comment' } }, + virt_text_pos = 'inline', }) - screen:expect(noextmarks) - - api.nvim__win_add_ns(0, ns) + api.nvim__ns_set(ns, { wins = { 0 } }) screen:expect { grid = [[ @@ -5719,9 +5731,10 @@ describe('decorations: window scoped', function() 34^5 | {1:~ }|*7 | - ]]} + ]], + } - api.nvim__win_del_ns(0, ns) + api.nvim__ns_set(ns, { wins = { win_other } }) screen:expect(noextmarks) end) @@ -5729,21 +5742,20 @@ describe('decorations: window scoped', function() pending('sign_text', function() -- TODO(altermo): The window signcolumn width is calculated wrongly (when `signcolumn=auto`) -- This happens in function `win_redraw_signcols` on line containing `buf_meta_total(buf, kMTMetaSignText) > 0` - set_scoped_extmark(0, 0, { + set_extmark(0, 0, { sign_text = 'a', sign_hl_group = 'Comment', }) - screen:expect(noextmarks) - - api.nvim__win_add_ns(0, ns) + api.nvim__ns_set(ns, { wins = { 0 } }) screen:expect { grid = [[ a 1234^5 | {2:~ }|*8 | - ]]} + ]], + } command 'split' command 'only' @@ -5752,30 +5764,34 @@ describe('decorations: window scoped', function() end) it('statuscolumn hl group', function() - set_scoped_extmark(0, 0, { - number_hl_group='comment', + set_extmark(0, 0, { + number_hl_group = 'comment', }) - set_scoped_extmark(0, 0, { - line_hl_group='comment', + set_extmark(0, 0, { + line_hl_group = 'comment', }) command 'set number' + api.nvim__ns_set(ns, { wins = { win_other } }) + screen:expect { grid = [[ {8: 1 }1234^5 | {1:~ }|*8 | - ]]} + ]], + } - api.nvim__win_add_ns(0, ns) + api.nvim__ns_set(ns, { wins = { 0 } }) screen:expect { grid = [[ {18: 1 1234^5 }| {1:~ }|*8 | - ]]} + ]], + } command 'split' command 'only' @@ -5785,36 +5801,43 @@ describe('decorations: window scoped', function() {8: 1 }1234^5 | {1:~ }|*8 | - ]]} + ]], + } end) it('spell', function() - api.nvim_buf_set_lines(0,0,-1,true,{'aa'}) + api.nvim_buf_set_lines(0, 0, -1, true, { 'aa' }) - set_scoped_extmark(0, 0, { - spell=true, - end_col=2, + set_extmark(0, 0, { + spell = true, + end_col = 2, }) command 'set spelloptions=noplainbuffer' command 'set spell' command 'syntax off' + screen:expect({ unchanged = true }) + + api.nvim__ns_set(ns, { wins = { win_other } }) + screen:expect { grid = [[ a^a | {1:~ }|*8 | - ]]} + ]], + } - api.nvim__win_add_ns(0, ns) + api.nvim__ns_set(ns, { wins = { 0 } }) screen:expect { grid = [[ {100:a^a} | {1:~ }|*8 | - ]]} + ]], + } command 'split' command 'only' @@ -5824,25 +5847,25 @@ describe('decorations: window scoped', function() a^a | {1:~ }|*8 | - ]]} + ]], + } end) it('url', function() - set_scoped_extmark(0, 0, { - end_col=3, - url=url, + set_extmark(0, 0, { + end_col = 3, + url = url, }) - screen:expect(noextmarks) - - api.nvim__win_add_ns(0, ns) + api.nvim__ns_set(ns, { wins = { 0 } }) screen:expect { grid = [[ {101:123}4^5 | {1:~ }|*8 | - ]]} + ]], + } command 'split' command 'only' @@ -5850,85 +5873,72 @@ describe('decorations: window scoped', function() screen:expect(noextmarks) end) - it('change extmarks scoped option', function() - local id = set_scoped_extmark(0, 0, { + it('change namespace scope', function() + set_extmark(0, 0, { hl_group = 'Comment', end_col = 3, }) - api.nvim__win_add_ns(0, ns) + api.nvim__ns_set(ns, { wins = { 0 } }) + eq({ wins={ api.nvim_get_current_win() } }, api.nvim__ns_get(ns)) screen:expect { grid = [[ {18:123}4^5 | {1:~ }|*8 | - ]]} + ]], + } command 'split' command 'only' screen:expect(noextmarks) - api.nvim_buf_set_extmark(0, ns, 0, 0, { - id = id, - hl_group = 'Comment', - end_col = 3, - scoped = false, - }) + api.nvim__ns_set(ns, { wins = { 0 } }) + eq({ wins={ api.nvim_get_current_win() } }, api.nvim__ns_get(ns)) screen:expect { grid = [[ {18:123}4^5 | {1:~ }|*8 | - ]]} + ]], + } - api.nvim_buf_set_extmark(0, ns, 0, 0, { - id = id, - hl_group = 'Comment', - end_col = 3, - scoped = true, + local win_new = api.nvim_open_win(0, false, { + col=0,row=0,width=20,height=10, + relative = 'win',style = 'minimal', + hide = true }) + api.nvim__ns_set(ns, { wins = { win_new } }) + eq({ wins={ win_new } }, api.nvim__ns_get(ns)) + screen:expect(noextmarks) end) - it('change namespace scope', function() - set_scoped_extmark(0, 0, { - hl_group = 'Comment', - end_col = 3, - }) + it('namespace get works', function() + eq({ wins = {} }, api.nvim__ns_get(ns)) - eq(true, api.nvim__win_add_ns(0, ns)) - eq({ ns }, api.nvim__win_get_ns(0)) + api.nvim__ns_set(ns, { wins = { 0 } }) - screen:expect { - grid = [[ - {18:123}4^5 | - {1:~ }|*8 - | - ]]} + eq({ wins = { api.nvim_get_current_win() } }, api.nvim__ns_get(ns)) - command 'split' - command 'only' - eq({}, api.nvim__win_get_ns(0)) + api.nvim__ns_set(ns, { wins = {} }) - screen:expect(noextmarks) + eq({ wins = {} }, api.nvim__ns_get(ns)) + end) - eq(true, api.nvim__win_add_ns(0, ns)) - eq({ ns }, api.nvim__win_get_ns(0)) + it('remove window from namespace scope when deleted', function () + api.nvim__ns_set(ns, { wins = { 0 } }) - screen:expect { - grid = [[ - {18:123}4^5 | - {1:~ }|*8 - | - ]]} + eq({ wins = { api.nvim_get_current_win() } }, api.nvim__ns_get(ns)) - eq(true, api.nvim__win_del_ns(0, ns)) - eq({}, api.nvim__win_get_ns(0)) + command 'split' + command 'only' - screen:expect(noextmarks) + eq({ wins = {} }, api.nvim__ns_get(ns)) end) end) + -- cgit From da6f68ee6966ebf434eee840b22a4f45e61d77dd Mon Sep 17 00:00:00 2001 From: Lennard Hofmann Date: Fri, 7 Jun 2024 21:43:17 +0200 Subject: fix(man): filter OSC 8 hyperlink markup #29171 Problem: `man cmake` shows "8;;https://cmake.orghttps://cmake.org8;;" Solution: Remove noise so that it shows as "https://cmake.org". See also: https://en.wikipedia.org/wiki/ANSI_escape_code#OSC --- test/functional/plugin/man_spec.lua | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'test/functional') diff --git a/test/functional/plugin/man_spec.lua b/test/functional/plugin/man_spec.lua index 978178191c..5e4ec53f8d 100644 --- a/test/functional/plugin/man_spec.lua +++ b/test/functional/plugin/man_spec.lua @@ -117,6 +117,29 @@ describe(':Man', function() ]]) end) + it('clears OSC 8 hyperlink markup from text', function() + feed( + [[ + ithis ]8;;http://example.com\Link Title]8;;\]] + ) + + screen:expect { + grid = [=[ + this {c:^[}]8;;http://example.com{c:^[}\Link Title{c:^[}]8;;{c:^[}^\ | + {eob:~ }|*3 + | + ]=], + } + + exec_lua [[require'man'.init_pager()]] + + screen:expect([[ + ^this Link Title | + {eob:~ }|*3 + | + ]]) + end) + it('highlights multibyte text', function() feed( [[ -- cgit From 9afa1fd35510c5fe485f4a1dfdabf94e5f051a1c Mon Sep 17 00:00:00 2001 From: dundargoc Date: Mon, 3 Jun 2024 19:04:28 +0200 Subject: feat(lua): add `vim._with` It's a function to perform operations in their own sealed context, similar to pythons `with`. This helps ease operations where you need to perform an operation in a specific context, and then restore the context. Marked as private for now as it's not ready for public use. The current plan is to start using this internally so we can discover and fix any problems. Once this is ready to be exposed it will be renamed to `vim.with`. Usage: ```lua local ret = vim._with({context = val}, function() return "hello" end) ``` , where `context` is any combination of: - `buf` - `emsg_silent` - `hide` - `horizontal` - `keepalt` - `keepjumps` - `keepmarks` - `keeppatterns` - `lockmarks` - `noautocmd` - `options` - `sandbox` - `silent` - `unsilent` - `win` (except for `win` and `buf` which can't be used at the same time). This list will most likely be expanded in the future. Work on https://github.com/neovim/neovim/issues/19832. Co-authored-by: Lewis Russell --- test/functional/lua/with_spec.lua | 292 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 292 insertions(+) create mode 100644 test/functional/lua/with_spec.lua (limited to 'test/functional') diff --git a/test/functional/lua/with_spec.lua b/test/functional/lua/with_spec.lua new file mode 100644 index 0000000000..36dee9630a --- /dev/null +++ b/test/functional/lua/with_spec.lua @@ -0,0 +1,292 @@ +local t = require('test.testutil') +local n = require('test.functional.testnvim')() +local Screen = require('test.functional.ui.screen') + +local fn = n.fn +local api = n.api +local command = n.command +local eq = t.eq +local exec_lua = n.exec_lua +local matches = t.matches +local pcall_err = t.pcall_err + +before_each(function() + n.clear() +end) + +describe('vim._with {buf = }', function() + it('does not trigger autocmd', function() + exec_lua [[ + local new = vim.api.nvim_create_buf(false, true) + vim.api.nvim_create_autocmd( { 'BufEnter', 'BufLeave', 'BufWinEnter', 'BufWinLeave' }, { + callback = function() _G.n = (_G.n or 0) + 1 end + }) + vim._with({buf = new}, function() + end) + assert(_G.n == nil) + ]] + end) + + it('trigger autocmd if changed within context', function() + exec_lua [[ + local new = vim.api.nvim_create_buf(false, true) + vim.api.nvim_create_autocmd( { 'BufEnter', 'BufLeave', 'BufWinEnter', 'BufWinLeave' }, { + callback = function() _G.n = (_G.n or 0) + 1 end + }) + vim._with({}, function() + vim.api.nvim_set_current_buf(new) + assert(_G.n ~= nil) + end) + ]] + end) + + it('can access buf options', function() + local buf1 = api.nvim_get_current_buf() + local buf2 = exec_lua [[ + buf2 = vim.api.nvim_create_buf(false, true) + return buf2 + ]] + + eq(false, api.nvim_get_option_value('autoindent', { buf = buf1 })) + eq(false, api.nvim_get_option_value('autoindent', { buf = buf2 })) + + local val = exec_lua [[ + return vim._with({buf = buf2}, function() + vim.cmd "set autoindent" + return vim.api.nvim_get_current_buf() + end) + ]] + + eq(false, api.nvim_get_option_value('autoindent', { buf = buf1 })) + eq(true, api.nvim_get_option_value('autoindent', { buf = buf2 })) + eq(buf1, api.nvim_get_current_buf()) + eq(buf2, val) + end) + + it('does not cause ml_get errors with invalid visual selection', function() + exec_lua [[ + local api = vim.api + local t = function(s) return api.nvim_replace_termcodes(s, true, true, true) end + api.nvim_buf_set_lines(0, 0, -1, true, {"a", "b", "c"}) + api.nvim_feedkeys(t "G", "txn", false) + vim._with({buf = api.nvim_create_buf(false, true)}, function() vim.cmd "redraw" end) + ]] + end) + + it('can be nested crazily with hidden buffers', function() + eq( + true, + exec_lua([[ + local function scratch_buf_call(fn) + local buf = vim.api.nvim_create_buf(false, true) + vim.api.nvim_set_option_value('cindent', true, {buf = buf}) + return vim._with({buf = buf}, function() + return vim.api.nvim_get_current_buf() == buf + and vim.api.nvim_get_option_value('cindent', {buf = buf}) + and fn() + end) and vim.api.nvim_buf_delete(buf, {}) == nil + end + + return scratch_buf_call(function() + return scratch_buf_call(function() + return scratch_buf_call(function() + return scratch_buf_call(function() + return scratch_buf_call(function() + return scratch_buf_call(function() + return scratch_buf_call(function() + return scratch_buf_call(function() + return scratch_buf_call(function() + return scratch_buf_call(function() + return scratch_buf_call(function() + return scratch_buf_call(function() + return true + end) + end) + end) + end) + end) + end) + end) + end) + end) + end) + end) + end) + ]]) + ) + end) + + it('can return values by reference', function() + eq( + { 4, 7 }, + exec_lua [[ + local val = {4, 10} + local ref = vim._with({ buf = 0}, function() return val end) + ref[2] = 7 + return val + ]] + ) + end) +end) + +describe('vim._with {win = }', function() + it('does not trigger autocmd', function() + exec_lua [[ + local old = vim.api.nvim_get_current_win() + vim.cmd("new") + local new = vim.api.nvim_get_current_win() + vim.api.nvim_create_autocmd( { 'WinEnter', 'WinLeave' }, { + callback = function() _G.n = (_G.n or 0) + 1 end + }) + vim._with({win = old}, function() + end) + assert(_G.n == nil) + ]] + end) + + it('trigger autocmd if changed within context', function() + exec_lua [[ + local old = vim.api.nvim_get_current_win() + vim.cmd("new") + local new = vim.api.nvim_get_current_win() + vim.api.nvim_create_autocmd( { 'WinEnter', 'WinLeave' }, { + callback = function() _G.n = (_G.n or 0) + 1 end + }) + vim._with({}, function() + vim.api.nvim_set_current_win(old) + assert(_G.n ~= nil) + end) + ]] + end) + + it('can access window options', function() + command('vsplit') + local win1 = api.nvim_get_current_win() + command('wincmd w') + local win2 = exec_lua [[ + win2 = vim.api.nvim_get_current_win() + return win2 + ]] + command('wincmd p') + + eq('', api.nvim_get_option_value('winhighlight', { win = win1 })) + eq('', api.nvim_get_option_value('winhighlight', { win = win2 })) + + local val = exec_lua [[ + return vim._with({win = win2}, function() + vim.cmd "setlocal winhighlight=Normal:Normal" + return vim.api.nvim_get_current_win() + end) + ]] + + eq('', api.nvim_get_option_value('winhighlight', { win = win1 })) + eq('Normal:Normal', api.nvim_get_option_value('winhighlight', { win = win2 })) + eq(win1, api.nvim_get_current_win()) + eq(win2, val) + end) + + it('does not cause ml_get errors with invalid visual selection', function() + -- Add lines to the current buffer and make another window looking into an empty buffer. + exec_lua [[ + _G.api = vim.api + _G.t = function(s) return api.nvim_replace_termcodes(s, true, true, true) end + _G.win_lines = api.nvim_get_current_win() + vim.cmd "new" + _G.win_empty = api.nvim_get_current_win() + api.nvim_set_current_win(win_lines) + api.nvim_buf_set_lines(0, 0, -1, true, {"a", "b", "c"}) + ]] + + -- Start Visual in current window, redraw in other window with fewer lines. + exec_lua [[ + api.nvim_feedkeys(t "G", "txn", false) + vim._with({win = win_empty}, function() vim.cmd "redraw" end) + ]] + + -- Start Visual in current window, extend it in other window with more lines. + exec_lua [[ + api.nvim_feedkeys(t "gg", "txn", false) + api.nvim_set_current_win(win_empty) + api.nvim_feedkeys(t "gg", "txn", false) + vim._with({win = win_lines}, function() api.nvim_feedkeys(t "G", "txn", false) end) + vim.cmd "redraw" + ]] + end) + + it('updates ruler if cursor moved', function() + local screen = Screen.new(30, 5) + screen:set_default_attr_ids { + [1] = { reverse = true }, + [2] = { bold = true, reverse = true }, + } + screen:attach() + exec_lua [[ + _G.api = vim.api + vim.opt.ruler = true + local lines = {} + for i = 0, 499 do lines[#lines + 1] = tostring(i) end + api.nvim_buf_set_lines(0, 0, -1, true, lines) + api.nvim_win_set_cursor(0, {20, 0}) + vim.cmd "split" + _G.win = api.nvim_get_current_win() + vim.cmd "wincmd w | redraw" + ]] + screen:expect [[ + 19 | + {1:[No Name] [+] 20,1 3%}| + ^19 | + {2:[No Name] [+] 20,1 3%}| + | + ]] + exec_lua [[ + vim._with({win = win}, function() api.nvim_win_set_cursor(0, {100, 0}) end) + vim.cmd "redraw" + ]] + screen:expect [[ + 99 | + {1:[No Name] [+] 100,1 19%}| + ^19 | + {2:[No Name] [+] 20,1 3%}| + | + ]] + end) + + it('can return values by reference', function() + eq( + { 7, 10 }, + exec_lua [[ + local val = {4, 10} + local ref = vim._with({win = 0}, function() return val end) + ref[1] = 7 + return val + ]] + ) + end) + + it('layout in current tabpage does not affect windows in others', function() + command('tab split') + local t2_move_win = api.nvim_get_current_win() + command('vsplit') + local t2_other_win = api.nvim_get_current_win() + command('tabprevious') + matches('E36: Not enough room$', pcall_err(command, 'execute "split|"->repeat(&lines)')) + command('vsplit') + + exec_lua('vim._with({win = ...}, function() vim.cmd.wincmd "J" end)', t2_move_win) + eq({ 'col', { { 'leaf', t2_other_win }, { 'leaf', t2_move_win } } }, fn.winlayout(2)) + end) +end) + +describe('vim._with {lockmarks = true}', function() + it('is reset', function() + local mark = exec_lua [[ + vim.api.nvim_buf_set_lines(0, 0, 0, false, {"marky", "snarky", "malarkey"}) + vim.api.nvim_buf_set_mark(0,"m",1,0, {}) + vim._with({lockmarks = true}, function() + vim.api.nvim_buf_set_lines(0, 0, 2, false, {"mass", "mess", "moss"}) + end) + return vim.api.nvim_buf_get_mark(0,"m") + ]] + t.eq(mark, { 1, 0 }) + end) +end) -- cgit From 20f22f75ee629ae2db4cd99e730fa0af26553177 Mon Sep 17 00:00:00 2001 From: Tom Praschan <13141438+tom-anders@users.noreply.github.com> Date: Mon, 10 Jun 2024 03:14:55 +0200 Subject: feat(lsp): include end_col, end_lnum in vim.lsp.buf.locations_to_items #29164 --- test/functional/plugin/lsp_spec.lua | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'test/functional') diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 6d28b83be8..50e9c0cc0f 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -2690,13 +2690,15 @@ describe('LSP', function() { filename = '/fake/uri', lnum = 1, + end_lnum = 2, col = 3, + end_col = 4, text = 'testing', user_data = { uri = 'file:///fake/uri', range = { start = { line = 0, character = 2 }, - ['end'] = { line = 0, character = 3 }, + ['end'] = { line = 1, character = 3 }, }, }, }, @@ -2710,7 +2712,7 @@ describe('LSP', function() uri = 'file:///fake/uri', range = { start = { line = 0, character = 2 }, - ['end'] = { line = 0, character = 3 }, + ['end'] = { line = 1, character = 3 }, } }, } @@ -2723,7 +2725,9 @@ describe('LSP', function() { filename = '/fake/uri', lnum = 1, + end_lnum = 1, col = 3, + end_col = 4, text = 'testing', user_data = { targetUri = 'file:///fake/uri', -- cgit From 4bd86120d41e3b01433004bf761beccb7f3a0167 Mon Sep 17 00:00:00 2001 From: Jon Huhn Date: Mon, 10 Jun 2024 06:23:03 -0500 Subject: fix(glob): handle overlapping `{}` condition elements #29236 This change fixes an issue where glob patterns like `{a,ab}` would not match `ab` because the first option `a` matches, then the end of the string is expected but `b` is found, and LPeg does not backtrack to try the next option `ab` which would match. The fix here is to also append the rest of the pattern to the generated LPeg pattern for each option. This changes a glob `{a,ab}` from being parsed as ("a" or "ab") "end of string" to ("a" "end of string" or "ab" "end of string") Here, matching against `ab` would try the first option, fail to match, then proceed to the next option, and match. The sacrifice this change makes is dropping support for nested `{}` conditions, which VSCode doesn't seem to support or test AFAICT. Fixes #28931 Co-authored-by: Sergey Slipchenko --- test/functional/lua/glob_spec.lua | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/lua/glob_spec.lua b/test/functional/lua/glob_spec.lua index 56cd4c9bb5..b3e1b79ee7 100644 --- a/test/functional/lua/glob_spec.lua +++ b/test/functional/lua/glob_spec.lua @@ -161,7 +161,7 @@ describe('glob', function() eq(false, match('{ab,cd}', 'a')) eq(true, match('{ab,cd}', 'cd')) eq(true, match('{a,b,c}', 'c')) - eq(true, match('{a,{b,c}}', 'c')) + eq(false, match('{a,{b,c}}', 'c')) -- {} cannot nest end) it('should match [] groups', function() @@ -223,6 +223,17 @@ describe('glob', function() eq(true, match('{[0-9],[a-z]}', '0')) eq(true, match('{[0-9],[a-z]}', 'a')) eq(false, match('{[0-9],[a-z]}', 'A')) + + -- glob is from willRename filter in typescript-language-server + -- https://github.com/typescript-language-server/typescript-language-server/blob/b224b878652438bcdd639137a6b1d1a6630129e4/src/lsp-server.ts#L266 + eq(true, match('**/*.{ts,js,jsx,tsx,mjs,mts,cjs,cts}', 'test.js')) + eq(true, match('**/*.{ts,js,jsx,tsx,mjs,mts,cjs,cts}', 'test.ts')) + eq(true, match('**/*.{ts,js,jsx,tsx,mjs,mts,cjs,cts}', 'test.mts')) + eq(true, match('**/*.{ts,js,jsx,tsx,mjs,mts,cjs,cts}', 'test.mjs')) + eq(true, match('**/*.{ts,js,jsx,tsx,mjs,mts,cjs,cts}', 'test.cjs')) + eq(true, match('**/*.{ts,js,jsx,tsx,mjs,mts,cjs,cts}', 'test.cts')) + eq(true, match('**/*.{ts,js,jsx,tsx,mjs,mts,cjs,cts}', 'test.jsx')) + eq(true, match('**/*.{ts,js,jsx,tsx,mjs,mts,cjs,cts}', 'test.tsx')) end) end) end) -- cgit From 1dcda865591b9bdda2fec1a1860efb4df56ea533 Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Mon, 10 Jun 2024 16:55:16 +0200 Subject: fix(column): clamp line number for legacy signs Problem: Legacy :sign API still allows placing signs beyond the end of the buffer. This is unaccounted for by the signcolumn tracking logic and is disallowed in general for the extmark API which implements it now. Solution: Clamp legacy sign line number to the length of the buffer. --- test/functional/ui/sign_spec.lua | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'test/functional') diff --git a/test/functional/ui/sign_spec.lua b/test/functional/ui/sign_spec.lua index b353b3738a..6f4bf5695d 100644 --- a/test/functional/ui/sign_spec.lua +++ b/test/functional/ui/sign_spec.lua @@ -577,4 +577,34 @@ describe('Signs', function() ]]) eq({}, eval('sign_getdefined()')) end) + + it('no crash when unplacing signs beyond end of buffer', function() + exec([[ + sign define S1 text=S1 + sign define S2 text=S2 + sign place 1 line=8 name=S1 + sign place 2 line=9 name=S2 + ]]) + -- Now placed at end of buffer + local s1 = { + grid = [[ + S2^ | + {0:~ }|*12 + | + ]], + } + screen:expect(s1) + -- Signcolumn tracking used to not count signs placed beyond end of buffer here + exec('set signcolumn=auto:9') + screen:expect({ + grid = [[ + S2S1^ | + {0:~ }|*12 + | + ]], + }) + -- Unplacing the sign does not crash by decrementing tracked signs below zero + exec('sign unplace 1') + screen:expect(s1) + end) end) -- cgit From 3ad977f01d97e84b576e6965c5c9e4f75c10cb35 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Tue, 11 Jun 2024 13:18:06 -0500 Subject: feat(terminal): add support for copying with OSC 52 in embedded terminal (#29117) When libvterm receives the OSC 52 escape sequence it ignores it because Nvim does not set any selection callbacks. Install selection callbacks that forward to the clipboard provider, so that setting the clipboard with OSC 52 in the embedded terminal writes to the system clipboard using the configured clipboard provider. --- test/functional/terminal/clipboard_spec.lua | 65 +++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 test/functional/terminal/clipboard_spec.lua (limited to 'test/functional') diff --git a/test/functional/terminal/clipboard_spec.lua b/test/functional/terminal/clipboard_spec.lua new file mode 100644 index 0000000000..4a1a0e29fd --- /dev/null +++ b/test/functional/terminal/clipboard_spec.lua @@ -0,0 +1,65 @@ +local t = require('test.testutil') +local n = require('test.functional.testnvim')() + +local eq = t.eq +local retry = t.retry + +local clear = n.clear +local fn = n.fn +local testprg = n.testprg +local exec_lua = n.exec_lua +local eval = n.eval + +describe(':terminal', function() + before_each(function() + clear() + + exec_lua([[ + local function clipboard(reg, type) + if type == 'copy' then + return function(lines) + local data = table.concat(lines, '\n') + vim.g.clipboard_data = data + end + end + + if type == 'paste' then + return function() + error() + end + end + + error('invalid type: ' .. type) + end + + vim.g.clipboard = { + name = 'Test', + copy = { + ['+'] = clipboard('+', 'copy'), + ['*'] = clipboard('*', 'copy'), + }, + paste = { + ['+'] = clipboard('+', 'paste'), + ['*'] = clipboard('*', 'paste'), + }, + } + ]]) + end) + + it('can write to the system clipboard', function() + eq('Test', eval('g:clipboard.name')) + + local text = 'Hello, world! This is some\nexample text\nthat spans multiple\nlines' + local encoded = exec_lua('return vim.base64.encode(...)', text) + + local function osc52(arg) + return string.format('\027]52;;%s\027\\', arg) + end + + fn.termopen({ testprg('shell-test'), '-t', osc52(encoded) }) + + retry(nil, 1000, function() + eq(text, exec_lua([[ return vim.g.clipboard_data ]])) + end) + end) +end) -- cgit From 8bf79bd13c4d37a96109c8a6a924acb59d8e8ae5 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 12 Jun 2024 15:35:54 +0100 Subject: fix(vim.wo): never allow non-zero bufnr --- test/functional/lua/vim_spec.lua | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'test/functional') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index d50b646085..0814f42545 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -2023,6 +2023,16 @@ describe('lua stdlib', function() vim.cmd "enew" ]] eq(100, fn.luaeval 'vim.wo.scrolloff') + + matches( + 'only bufnr=0 is supported', + pcall_err(exec_lua, 'vim.wo[0][10].signcolumn = "no"') + ) + + matches( + 'only bufnr=0 is supported', + pcall_err(exec_lua, 'local a = vim.wo[0][10].signcolumn') + ) end) describe('vim.opt', function() -- cgit From 2ca678f57de1cb4332d39337ae1c5a63a1ff434a Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 12 Jun 2024 15:47:42 +0100 Subject: test: fix vim.deprecate tests --- test/functional/lua/vim_spec.lua | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) (limited to 'test/functional') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 0814f42545..23bb9f0a2e 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -135,14 +135,15 @@ describe('lua stdlib', function() -- See MAINTAIN.md for the soft/hard deprecation policy describe(('vim.deprecate prerel=%s,'):format(prerel or 'nil'), function() - local curver = exec_lua('return vim.version()') --[[@as {major:number, minor:number}]] - -- "0.10" or "0.10-dev+xxx" - local curstr = ('%s.%s%s'):format(curver.major, curver.minor, prerel or '') - -- "0.10" or "0.11" - local nextver = ('%s.%s'):format(curver.major, curver.minor + (prerel and 0 or 1)) - local was_removed = prerel and 'was removed' or 'will be removed' + local curver --- @type {major:number, minor:number} + + before_each(function() + curver = exec_lua('return vim.version()') + end) it('plugin=nil, same message skipped', function() + -- "0.10" or "0.10-dev+xxx" + local curstr = ('%s.%s%s'):format(curver.major, curver.minor, prerel or '') eq( dedent( [[ @@ -162,6 +163,10 @@ describe('lua stdlib', function() end) it('plugin=nil, show error if hard-deprecated', function() + -- "0.10" or "0.11" + local nextver = ('%s.%s'):format(curver.major, curver.minor + (prerel and 0 or 1)) + + local was_removed = prerel and 'was removed' or 'will be removed' eq( dedent( [[ @@ -2024,15 +2029,9 @@ describe('lua stdlib', function() ]] eq(100, fn.luaeval 'vim.wo.scrolloff') - matches( - 'only bufnr=0 is supported', - pcall_err(exec_lua, 'vim.wo[0][10].signcolumn = "no"') - ) + matches('only bufnr=0 is supported', pcall_err(exec_lua, 'vim.wo[0][10].signcolumn = "no"')) - matches( - 'only bufnr=0 is supported', - pcall_err(exec_lua, 'local a = vim.wo[0][10].signcolumn') - ) + matches('only bufnr=0 is supported', pcall_err(exec_lua, 'local a = vim.wo[0][10].signcolumn')) end) describe('vim.opt', function() -- cgit From 3e09fbdf82a181f1c0be1513fd50a17bf5b0a754 Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Tue, 11 Jun 2024 11:10:34 -0500 Subject: feat(highlight): add StatusLineTerm and StatusLineTermNC groups These highlight groups are used for the statusline in :terminal windows. By default they link to StatusLine and StatusLineNC (respectively), so there is no visual difference unless a colorscheme defines these groups separately. --- test/functional/ui/cursor_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/ui/cursor_spec.lua b/test/functional/ui/cursor_spec.lua index 8bfceb8cce..f7eb8394bd 100644 --- a/test/functional/ui/cursor_spec.lua +++ b/test/functional/ui/cursor_spec.lua @@ -250,7 +250,7 @@ describe('ui/cursor', function() m.attr = { background = Screen.colors.DarkGray } end if m.id_lm then - m.id_lm = 69 + m.id_lm = 71 end end -- cgit From d38912b59f97a4da0a2d0a24af226e6dd27e9b2c Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Tue, 11 Jun 2024 11:10:34 -0500 Subject: refactor(terminal): move :terminal defaults to _defaults.lua --- test/functional/terminal/buffer_spec.lua | 6 +++--- test/functional/terminal/mouse_spec.lua | 8 +++++--- test/functional/terminal/testutil.lua | 4 ++++ test/functional/terminal/window_split_tab_spec.lua | 8 +++++--- 4 files changed, 17 insertions(+), 9 deletions(-) (limited to 'test/functional') diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua index 96abd9f543..4ad0862986 100644 --- a/test/functional/terminal/buffer_spec.lua +++ b/test/functional/terminal/buffer_spec.lua @@ -196,10 +196,10 @@ describe(':terminal buffer', function() screen:expect([[ ab^c | {4:~ }| - {5:========== }| + {17:========== }| rows: 2, cols: 50 | {2: } | - {1:========== }| + {18:========== }| | ]]) @@ -340,7 +340,7 @@ describe(':terminal buffer', function() eq(termbuf, eval('g:termbuf')) end) - it('TermReqeust synchronization #27572', function() + it('TermRequest synchronization #27572', function() command('autocmd! nvim_terminal TermRequest') local term = exec_lua([[ _G.input = {} diff --git a/test/functional/terminal/mouse_spec.lua b/test/functional/terminal/mouse_spec.lua index ad98dfc6c3..476e2a5fe5 100644 --- a/test/functional/terminal/mouse_spec.lua +++ b/test/functional/terminal/mouse_spec.lua @@ -14,10 +14,12 @@ describe(':terminal mouse', function() before_each(function() clear() api.nvim_set_option_value('statusline', '==========', {}) - command('highlight StatusLine cterm=NONE') - command('highlight StatusLineNC cterm=NONE') - command('highlight VertSplit cterm=NONE') screen = tt.screen_setup() + command('highlight StatusLine NONE') + command('highlight StatusLineNC NONE') + command('highlight StatusLineTerm NONE') + command('highlight StatusLineTermNC NONE') + command('highlight VertSplit NONE') local lines = {} for i = 1, 30 do table.insert(lines, 'line' .. tostring(i)) diff --git a/test/functional/terminal/testutil.lua b/test/functional/terminal/testutil.lua index f3fc5d3f93..45c73b1dc6 100644 --- a/test/functional/terminal/testutil.lua +++ b/test/functional/terminal/testutil.lua @@ -92,6 +92,8 @@ local function screen_setup(extra_rows, command, cols, env, screen_opts) api.nvim_command('highlight TermCursor cterm=reverse') api.nvim_command('highlight TermCursorNC ctermbg=11') + api.nvim_command('highlight StatusLineTerm ctermbg=2 ctermfg=0') + api.nvim_command('highlight StatusLineTermNC ctermbg=2 ctermfg=8') local screen = Screen.new(cols, 7 + extra_rows) screen:set_default_attr_ids({ @@ -111,6 +113,8 @@ local function screen_setup(extra_rows, command, cols, env, screen_opts) [14] = { underline = true, reverse = true, bold = true }, [15] = { underline = true, foreground = 12 }, [16] = { background = 248, foreground = 0 }, -- Visual in :terminal session + [17] = { background = 2, foreground = 0 }, -- StatusLineTerm + [18] = { background = 2, foreground = 8 }, -- StatusLineTermNC }) screen:attach(screen_opts or { rgb = false }) diff --git a/test/functional/terminal/window_split_tab_spec.lua b/test/functional/terminal/window_split_tab_spec.lua index 04d2e0bca7..ccd6a5218b 100644 --- a/test/functional/terminal/window_split_tab_spec.lua +++ b/test/functional/terminal/window_split_tab_spec.lua @@ -22,10 +22,12 @@ describe(':terminal', function() -- set the statusline to a constant value because of variables like pid -- and current directory and to improve visibility of splits api.nvim_set_option_value('statusline', '==========', {}) - command('highlight StatusLine cterm=NONE') - command('highlight StatusLineNC cterm=NONE') - command('highlight VertSplit cterm=NONE') screen = tt.screen_setup(3) + command('highlight StatusLine NONE') + command('highlight StatusLineNC NONE') + command('highlight StatusLineTerm NONE') + command('highlight StatusLineTermNC NONE') + command('highlight VertSplit NONE') end) after_each(function() -- cgit From 5def8714ad70e71e07773960269fff5c0c95e7ab Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Jun 2024 06:20:42 +0800 Subject: fix(terminal): set local values of window options (#29326) --- test/functional/terminal/buffer_spec.lua | 2 +- test/functional/terminal/window_spec.lua | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua index 4ad0862986..365a4f8035 100644 --- a/test/functional/terminal/buffer_spec.lua +++ b/test/functional/terminal/buffer_spec.lua @@ -196,7 +196,7 @@ describe(':terminal buffer', function() screen:expect([[ ab^c | {4:~ }| - {17:========== }| + {5:========== }| rows: 2, cols: 50 | {2: } | {18:========== }| diff --git a/test/functional/terminal/window_spec.lua b/test/functional/terminal/window_spec.lua index f85e26a66d..118ca266dd 100644 --- a/test/functional/terminal/window_spec.lua +++ b/test/functional/terminal/window_spec.lua @@ -12,6 +12,26 @@ local eval = n.eval local skip = t.skip local is_os = t.is_os +describe(':terminal window', function() + before_each(clear) + + it('sets local values of window options #29325', function() + command('setglobal wrap list') + command('terminal') + eq({ 0, 0, 1 }, eval('[&l:wrap, &wrap, &g:wrap]')) + eq({ 0, 0, 1 }, eval('[&l:list, &list, &g:list]')) + command('enew') + eq({ 1, 1, 1 }, eval('[&l:wrap, &wrap, &g:wrap]')) + eq({ 1, 1, 1 }, eval('[&l:list, &list, &g:list]')) + command('buffer #') + eq({ 0, 0, 1 }, eval('[&l:wrap, &wrap, &g:wrap]')) + eq({ 0, 0, 1 }, eval('[&l:list, &list, &g:list]')) + command('new') + eq({ 1, 1, 1 }, eval('[&l:wrap, &wrap, &g:wrap]')) + eq({ 1, 1, 1 }, eval('[&l:list, &list, &g:list]')) + end) +end) + describe(':terminal window', function() local screen -- cgit From 0a9c81d70964f905112857900fbaa6aae590a96d Mon Sep 17 00:00:00 2001 From: Ilia Choly Date: Fri, 14 Jun 2024 05:03:58 -0400 Subject: refactor(lsp): use metatable for buf_versions (#29304) This reduces the number of nil checks around buf_versions usage Test changes were lifted from 5c33815 Co-authored-by: Mathias Fussenegger --- .../functional/plugin/lsp/semantic_tokens_spec.lua | 24 +++++++++++----------- test/functional/plugin/lsp_spec.lua | 15 +++++++++----- 2 files changed, 22 insertions(+), 17 deletions(-) (limited to 'test/functional') diff --git a/test/functional/plugin/lsp/semantic_tokens_spec.lua b/test/functional/plugin/lsp/semantic_tokens_spec.lua index 7908c5d2e7..9babb080e7 100644 --- a/test/functional/plugin/lsp/semantic_tokens_spec.lua +++ b/test/functional/plugin/lsp/semantic_tokens_spec.lua @@ -111,6 +111,7 @@ describe('semantic token highlighting', function() end) it('buffer is highlighted when attached', function() + insert(text) exec_lua([[ bufnr = vim.api.nvim_get_current_buf() vim.api.nvim_win_set_buf(0, bufnr) @@ -118,8 +119,6 @@ describe('semantic token highlighting', function() client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) ]]) - insert(text) - screen:expect { grid = [[ #include | @@ -141,6 +140,7 @@ describe('semantic token highlighting', function() end) it('use LspTokenUpdate and highlight_token', function() + insert(text) exec_lua([[ vim.api.nvim_create_autocmd("LspTokenUpdate", { callback = function(args) @@ -157,8 +157,6 @@ describe('semantic token highlighting', function() client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) ]]) - insert(text) - screen:expect { grid = [[ #include | @@ -180,14 +178,17 @@ describe('semantic token highlighting', function() end) it('buffer is unhighlighted when client is detached', function() + insert(text) + exec_lua([[ bufnr = vim.api.nvim_get_current_buf() vim.api.nvim_win_set_buf(0, bufnr) client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) + vim.wait(1000, function() + return #server.messages > 1 + end) ]]) - insert(text) - exec_lua([[ vim.notify = function() end vim.lsp.buf_detach_client(bufnr, client_id) @@ -331,14 +332,13 @@ describe('semantic token highlighting', function() end) it('buffer is re-highlighted when force refreshed', function() + insert(text) exec_lua([[ bufnr = vim.api.nvim_get_current_buf() vim.api.nvim_win_set_buf(0, bufnr) client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) ]]) - insert(text) - screen:expect { grid = [[ #include | @@ -412,13 +412,14 @@ describe('semantic token highlighting', function() end) it('updates highlights with delta request on buffer change', function() + insert(text) + exec_lua([[ bufnr = vim.api.nvim_get_current_buf() vim.api.nvim_win_set_buf(0, bufnr) client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) ]]) - insert(text) screen:expect { grid = [[ #include | @@ -597,6 +598,7 @@ describe('semantic token highlighting', function() end) it('does not send delta requests if not supported by server', function() + insert(text) exec_lua( [[ local legend, response, edit_response = ... @@ -625,7 +627,6 @@ describe('semantic token highlighting', function() edit_response ) - insert(text) screen:expect { grid = [[ #include | @@ -1449,6 +1450,7 @@ int main() }, }) do it(test.it, function() + insert(test.text1) exec_lua(create_server_definition) exec_lua( [[ @@ -1485,8 +1487,6 @@ int main() test.response2 ) - insert(test.text1) - test.expected_screen1() local highlights = exec_lua([[ diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 50e9c0cc0f..b345a3288c 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -255,7 +255,7 @@ describe('LSP', function() return end local expected_handlers = { - { NIL, {}, { method = 'shutdown', bufnr = 1, client_id = 1 } }, + { NIL, {}, { method = 'shutdown', bufnr = 1, client_id = 1, version = 0 } }, { NIL, {}, { method = 'test', client_id = 1 } }, } test_rpc_server { @@ -948,7 +948,11 @@ describe('LSP', function() it('should forward ContentModified to callback', function() local expected_handlers = { { NIL, {}, { method = 'finish', client_id = 1 } }, - { { code = -32801 }, NIL, { method = 'error_code_test', bufnr = 1, client_id = 1 } }, + { + { code = -32801 }, + NIL, + { method = 'error_code_test', bufnr = 1, client_id = 1, version = 0 }, + }, } local client --- @type vim.lsp.Client test_rpc_server { @@ -978,7 +982,7 @@ describe('LSP', function() it('should track pending requests to the language server', function() local expected_handlers = { { NIL, {}, { method = 'finish', client_id = 1 } }, - { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1 } }, + { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1, version = 0 } }, } local client --- @type vim.lsp.Client test_rpc_server { @@ -1045,7 +1049,7 @@ describe('LSP', function() it('should clear pending and cancel requests on reply', function() local expected_handlers = { { NIL, {}, { method = 'finish', client_id = 1 } }, - { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1 } }, + { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1, version = 0 } }, } local client --- @type vim.lsp.Client test_rpc_server { @@ -1084,7 +1088,7 @@ describe('LSP', function() it('should trigger LspRequest autocmd when requests table changes', function() local expected_handlers = { { NIL, {}, { method = 'finish', client_id = 1 } }, - { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1 } }, + { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1, version = 0 } }, } local client --- @type vim.lsp.Client test_rpc_server { @@ -1364,6 +1368,7 @@ describe('LSP', function() }, bufnr = 2, client_id = 1, + version = 0, }, }, { NIL, {}, { method = 'start', client_id = 1 } }, -- cgit From 458473acb8d641cadb238726539b119762050a47 Mon Sep 17 00:00:00 2001 From: Evgeni Chasnovski Date: Fri, 14 Jun 2024 12:28:49 +0300 Subject: fix(highlight): add `StatusLineTerm`/`StatusLineTermNC` to `:color vim` (#29313) Problem: both `StatusLineTerm`/`StatusLineTermNC` are now explicitly used, but `:color vim` does not set them to the values used in Vim. This might be fine if `:color vim` is treated as "the state of default color scheme prior the big update", but it seems to be better treated as "Vim's default color scheme" (how it is documented in its header). Solution: add `StatusLineTerm`/`StatusLineTermNC` definitions to 'runtime/colors/vim.lua'. Use explicit foreground colors ('Whte'/'Black') instead of `guifg=bg` used in source, as the latter caused some problems in the past (if `Normal` is not defined, `nvim_set_hl()` can't recognize `'bg'` as the foreground value). Also realign the rest of the background conditional highlight groups. --- test/functional/terminal/tui_spec.lua | 38 ++++++++++++++++++++++++++++++----- test/functional/ui/searchhl_spec.lua | 9 ++++++++- test/functional/ui/wildmode_spec.lua | 12 +++++++++-- 3 files changed, 51 insertions(+), 8 deletions(-) (limited to 'test/functional') diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 80df336cc4..5269af760a 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -1056,6 +1056,11 @@ describe('TUI', function() if is_ci('github') then pending('tty-test complains about not owning the terminal -- actions/runner#241') end + screen:set_default_attr_ids({ + [1] = { reverse = true }, -- focused cursor + [3] = { bold = true }, + [19] = { bold = true, background = 121, foreground = 0 }, -- StatusLineTerm + }) child_exec_lua('vim.o.statusline="^^^^^^^"') child_exec_lua('vim.cmd.terminal(...)', testprg('tty-test')) feed_data('i') @@ -1063,7 +1068,7 @@ describe('TUI', function() tty ready | {1: } | |*2 - {5:^^^^^^^ }| + {19:^^^^^^^ }| {3:-- TERMINAL --} |*2 ]]) feed_data('\027[200~') @@ -1073,7 +1078,7 @@ describe('TUI', function() tty ready | hallo{1: } | |*2 - {5:^^^^^^^ }| + {19:^^^^^^^ }| {3:-- TERMINAL --} |*2 ]]) end) @@ -1548,10 +1553,32 @@ describe('TUI', function() screen:set_rgb_cterm(true) screen:set_default_attr_ids({ [1] = { { reverse = true }, { reverse = true } }, - [2] = { { bold = true, reverse = true }, { bold = true, reverse = true } }, + [2] = { + { bold = true, background = Screen.colors.LightGreen, foreground = Screen.colors.Black }, + { bold = true }, + }, [3] = { { bold = true }, { bold = true } }, [4] = { { fg_indexed = true, foreground = tonumber('0xe0e000') }, { foreground = 3 } }, [5] = { { foreground = tonumber('0xff8000') }, {} }, + [6] = { + { + fg_indexed = true, + bg_indexed = true, + bold = true, + background = tonumber('0x66ff99'), + foreground = Screen.colors.Black, + }, + { bold = true, background = 121, foreground = 0 }, + }, + [7] = { + { + fg_indexed = true, + bg_indexed = true, + background = tonumber('0x66ff99'), + foreground = Screen.colors.Black, + }, + { background = 121, foreground = 0 }, + }, }) child_exec_lua('vim.o.statusline="^^^^^^^"') @@ -1586,7 +1613,7 @@ describe('TUI', function() {1:t}ty ready | {4:text}colortext | |*2 - {2:^^^^^^^ }| + {6:^^^^^^^}{7: }| :set notermguicolors | {3:-- TERMINAL --} | ]], @@ -1973,6 +2000,7 @@ describe('TUI', function() [3] = { bold = true }, [4] = { foreground = tonumber('0x4040ff'), fg_indexed = true }, [5] = { bold = true, reverse = true }, + [6] = { foreground = Screen.colors.White, background = Screen.colors.DarkGreen }, }) screen:attach() fn.termopen({ @@ -1998,7 +2026,7 @@ describe('TUI', function() {2:~ }│{4:~ }|*5 {2:~ }│{5:[No Name] 0,0-1 All}| {2:~ }│ | - {5:new }{1:{MATCH:<.*[/\]nvim }}| + {5:new }{6:{MATCH:<.*[/\]nvim }}| | ]]) end) diff --git a/test/functional/ui/searchhl_spec.lua b/test/functional/ui/searchhl_spec.lua index 8bdf528412..493493da60 100644 --- a/test/functional/ui/searchhl_spec.lua +++ b/test/functional/ui/searchhl_spec.lua @@ -345,12 +345,19 @@ describe('search highlighting', function() bar baz foo bar foo baz]]) feed('/foo') + screen:set_default_attr_ids({ + [1] = { bold = true, foreground = Screen.colors.Blue }, + [2] = { background = Screen.colors.Yellow }, -- Search + [3] = { reverse = true }, + [4] = { bold = true, reverse = true }, + [5] = { foreground = Screen.colors.White, background = Screen.colors.DarkGreen }, + }) screen:expect([[ {3:foo} bar baz │{MATCH:%d+}: {2:foo}{MATCH:%s+}| bar baz {2:foo} │{MATCH:%d+}: {2:foo}{MATCH:%s+}| bar {2:foo} baz │{MATCH:%d+}: {2:foo}{MATCH:%s+}| {1:~ }│{MATCH:.*}|*2 - {5:[No Name] [+] }{3:term }| + {4:[No Name] [+] }{5:term }| /foo^ | ]]) end) diff --git a/test/functional/ui/wildmode_spec.lua b/test/functional/ui/wildmode_spec.lua index 0feec6bd03..6299852a69 100644 --- a/test/functional/ui/wildmode_spec.lua +++ b/test/functional/ui/wildmode_spec.lua @@ -199,9 +199,13 @@ describe("'wildmenu'", function() feed((':terminal "%s" REP 5000 !terminal_output!'):format(testprg('shell-test'))) feed('G') -- Follow :terminal output. feed([[:sign ]]) -- Invoke wildmenu. + screen:set_default_attr_ids { + [31] = { foreground = Screen.colors.Black, background = Screen.colors.Yellow }, + [32] = { bold = true, foreground = Screen.colors.White, background = Screen.colors.DarkGreen }, + } -- NB: in earlier versions terminal output was redrawn during cmdline mode. -- For now just assert that the screen remains unchanged. - screen:expect { any = '{31:define}{3: jump list > }|\n:sign define^ |' } + screen:expect { any = '{31:define}{32: jump list > }|\n:sign define^ |' } screen:expect_unchanged() -- cmdline CTRL-D display should also be preserved. @@ -259,9 +263,13 @@ describe("'wildmenu'", function() feed([[]]) feed([[:]]) -- Invoke wildmenu. + screen:set_default_attr_ids { + [31] = { foreground = Screen.colors.Black, background = Screen.colors.Yellow }, + [32] = { bold = true, foreground = Screen.colors.White, background = Screen.colors.DarkGreen }, + } -- Check only the last 2 lines, because the shell output is -- system-dependent. - screen:expect { any = '{31:!}{3: # & < = > @ > }|\n:!^' } + screen:expect { any = '{31:!}{32: # & < = > @ > }|\n:!^' } -- Because this test verifies a _lack_ of activity, we must wait the full timeout. -- So make it reasonable. screen:expect_unchanged(false, 1000) -- cgit From aa47af7e69bb32c4486510dce27f45d9028e0a6c Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Fri, 14 Jun 2024 19:32:34 +0200 Subject: fix(lsp): tune completion word extraction for decorated labels (#29331) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: For snippets lsp.completion prefers the label if it is shorter than the insertText or textEdit to support postfix completion cases but clangd adds decoration characters to labels. E.g.: `•INT16_C(c)` Solution: Use parse_snippet on insertText/textEdit before checking if it is shorter than the label. Fixes https://github.com/neovim/neovim/issues/29301 --- test/functional/plugin/lsp/completion_spec.lua | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/plugin/lsp/completion_spec.lua b/test/functional/plugin/lsp/completion_spec.lua index 0e81e4fddb..1b56d1740a 100644 --- a/test/functional/plugin/lsp/completion_spec.lua +++ b/test/functional/plugin/lsp/completion_spec.lua @@ -81,10 +81,21 @@ describe('vim.lsp.completion: item conversion', function() -- plain text { label = 'foocar', - sortText = 'k', + sortText = 'g', insertText = 'foodar(${1:var1})', insertTextFormat = 1, }, + { + label = '•INT16_C(c)', + insertText = 'INT16_C(${1:c})', + insertTextFormat = 2, + filterText = 'INT16_C', + sortText = 'h', + textEdit = { + newText = 'INT16_C(${1:c})', + range = range0, + }, + }, } local expected = { { @@ -115,6 +126,10 @@ describe('vim.lsp.completion: item conversion', function() abbr = 'foocar', word = 'foodar(${1:var1})', -- marked as PlainText, text is used as is }, + { + abbr = '•INT16_C(c)', + word = 'INT16_C', + }, } local result = complete('|', completion_list) result = vim.tbl_map(function(x) -- cgit From dc4037f612c6f3bbc76890adfa638d48ec238eee Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 13 Jun 2024 14:08:50 +0800 Subject: vim-patch:9.1.0476: Cannot see matched text in popup menu Problem: Cannot see matched text in popup menu Solution: Introduce 2 new highlighting groups: PmenuMatch and PmenuMatchSel (glepnir) closes: vim/vim#14694 https://github.com/vim/vim/commit/40c1c3317d92f8c2adadf744fab72e4458e2a9fa Co-authored-by: glepnir --- test/functional/ui/cursor_spec.lua | 4 +- test/functional/ui/popupmenu_spec.lua | 117 ++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+), 2 deletions(-) (limited to 'test/functional') diff --git a/test/functional/ui/cursor_spec.lua b/test/functional/ui/cursor_spec.lua index f7eb8394bd..619153724b 100644 --- a/test/functional/ui/cursor_spec.lua +++ b/test/functional/ui/cursor_spec.lua @@ -246,11 +246,11 @@ describe('ui/cursor', function() end end if m.hl_id then - m.hl_id = 64 + m.hl_id = 66 m.attr = { background = Screen.colors.DarkGray } end if m.id_lm then - m.id_lm = 71 + m.id_lm = 73 end end diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index cc21a797e3..0ce0fe4eab 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -1177,6 +1177,8 @@ describe('builtin popupmenu', function() ks = { foreground = Screen.colors.Red, background = Screen.colors.Grey }, xn = { foreground = Screen.colors.White, background = Screen.colors.Magenta }, xs = { foreground = Screen.colors.Black, background = Screen.colors.Grey }, + mn = { foreground = Screen.colors.Blue, background = Screen.colors.White }, + ms = { foreground = Screen.colors.Green, background = Screen.colors.White }, }) screen:attach({ ext_multigrid = multigrid }) end) @@ -4585,6 +4587,121 @@ describe('builtin popupmenu', function() ]]) end) end) + + -- oldtest: Test_pum_highlights_match() + it('can highlight matched text', function() + exec([[ + func Omni_test(findstart, base) + if a:findstart + return col(".") + endif + return { + \ 'words': [ + \ { 'word': 'foo',}, + \ { 'word': 'foobar',}, + \ { 'word': 'fooBaz',}, + \ { 'word': 'foobala',}, + \ { 'word': '你好',}, + \ { 'word': '你好吗',}, + \ { 'word': '你不好吗',}, + \ { 'word': '你可好吗',}, + \]} + endfunc + set omnifunc=Omni_test + set completeopt=menu,noinsert,fuzzy + hi PmenuMatchSel guifg=Green guibg=White + hi PmenuMatch guifg=Blue guibg=White + ]]) + feed('i') + local pum_start = [[ + ^ | + {s:foo }{1: }| + {n:foobar }{1: }| + {n:fooBaz }{1: }| + {n:foobala }{1: }| + {n:你好 }{1: }| + {n:你好吗 }{1: }| + {n:你不好吗 }{1: }| + {n:你可好吗 }{1: }| + {1:~ }|*10 + {2:-- }{5:match 1 of 8} | + ]] + screen:expect(pum_start) + feed('fo') + screen:expect([[ + fo^ | + {ms:fo}{s:o }{1: }| + {mn:fo}{n:obar }{1: }| + {mn:fo}{n:oBaz }{1: }| + {mn:fo}{n:obala }{1: }| + {1:~ }|*14 + {2:-- }{5:match 1 of 8} | + ]]) + feed('S') + screen:expect(pum_start) + feed('你') + screen:expect([[ + 你^ | + {ms:你}{s:好 }{1: }| + {mn:你}{n:好吗 }{1: }| + {mn:你}{n:不好吗 }{1: }| + {mn:你}{n:可好吗 }{1: }| + {1:~ }|*14 + {2:-- }{5:match 1 of 8} | + ]]) + feed('吗') + screen:expect([[ + 你吗^ | + {ms:你}{s:好}{ms:吗}{s: }{1: }| + {mn:你}{n:不好}{mn:吗}{n: }{1: }| + {mn:你}{n:可好}{mn:吗}{n: }{1: }| + {1:~ }|*15 + {2:-- }{5:match 1 of 8} | + ]]) + + feed('') + command('set rightleft') + feed('S') + screen:expect([[ + ^ | + {1: }{s: oof}| + {1: }{n: raboof}| + {1: }{n: zaBoof}| + {1: }{n: alaboof}| + {1: }{n: 好你}| + {1: }{n: 吗好你}| + {1: }{n: 吗好不你}| + {1: }{n: 吗好可你}| + {1: ~}|*10 + {2:-- }{5:match 1 of 8} | + ]]) + feed('fo') + screen:expect([[ + ^ of| + {1: }{s: o}{ms:of}| + {1: }{n: rabo}{mn:of}| + {1: }{n: zaBo}{mn:of}| + {1: }{n: alabo}{mn:of}| + {1: ~}|*14 + {2:-- }{5:match 1 of 8} | + ]]) + feed('') + command('set norightleft') + + command('set completeopt-=fuzzy') + feed('S') + screen:expect(pum_start) + feed('fo') + screen:expect([[ + fo^ | + {ms:fo}{s:o }{1: }| + {mn:fo}{n:obar }{1: }| + {mn:fo}{n:oBaz }{1: }| + {mn:fo}{n:obala }{1: }| + {1:~ }|*14 + {2:-- }{5:match 1 of 8} | + ]]) + end) end end -- cgit From aacd6c440d21bea9dbe9588da076d3351f9b228c Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 15 Jun 2024 04:47:53 +0800 Subject: vim-patch:9.1.0485: Matched text shouldn't be highlighted in "kind" and "menu" Problem: Matched text shouldn't be highlighted in "kind" and "menu". Solution: Pass hlf_T instead of the attribute. Fix indent. (zeertzjq) closes: vim/vim#14996 https://github.com/vim/vim/commit/afbe5359e981e5d19ad23c394aefe60395c3648e --- test/functional/ui/popupmenu_spec.lua | 72 +++++++++++++++++------------------ 1 file changed, 36 insertions(+), 36 deletions(-) (limited to 'test/functional') diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index 0ce0fe4eab..323be3bd4d 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -4597,14 +4597,14 @@ describe('builtin popupmenu', function() endif return { \ 'words': [ - \ { 'word': 'foo',}, - \ { 'word': 'foobar',}, - \ { 'word': 'fooBaz',}, - \ { 'word': 'foobala',}, - \ { 'word': '你好',}, - \ { 'word': '你好吗',}, - \ { 'word': '你不好吗',}, - \ { 'word': '你可好吗',}, + \ { 'word': 'foo', 'kind': 'fookind' }, + \ { 'word': 'foobar', 'kind': 'fookind' }, + \ { 'word': 'fooBaz', 'kind': 'fookind' }, + \ { 'word': 'foobala', 'kind': 'fookind' }, + \ { 'word': '你好' }, + \ { 'word': '你好吗' }, + \ { 'word': '你不好吗' }, + \ { 'word': '你可好吗' }, \]} endfunc set omnifunc=Omni_test @@ -4615,14 +4615,14 @@ describe('builtin popupmenu', function() feed('i') local pum_start = [[ ^ | - {s:foo }{1: }| - {n:foobar }{1: }| - {n:fooBaz }{1: }| - {n:foobala }{1: }| - {n:你好 }{1: }| - {n:你好吗 }{1: }| - {n:你不好吗 }{1: }| - {n:你可好吗 }{1: }| + {s:foo fookind }{1: }| + {n:foobar fookind }{1: }| + {n:fooBaz fookind }{1: }| + {n:foobala fookind }{1: }| + {n:你好 }{1: }| + {n:你好吗 }{1: }| + {n:你不好吗 }{1: }| + {n:你可好吗 }{1: }| {1:~ }|*10 {2:-- }{5:match 1 of 8} | ]] @@ -4630,10 +4630,10 @@ describe('builtin popupmenu', function() feed('fo') screen:expect([[ fo^ | - {ms:fo}{s:o }{1: }| - {mn:fo}{n:obar }{1: }| - {mn:fo}{n:oBaz }{1: }| - {mn:fo}{n:obala }{1: }| + {ms:fo}{s:o fookind }{1: }| + {mn:fo}{n:obar fookind }{1: }| + {mn:fo}{n:oBaz fookind }{1: }| + {mn:fo}{n:obala fookind }{1: }| {1:~ }|*14 {2:-- }{5:match 1 of 8} | ]]) @@ -4664,24 +4664,24 @@ describe('builtin popupmenu', function() feed('S') screen:expect([[ ^ | - {1: }{s: oof}| - {1: }{n: raboof}| - {1: }{n: zaBoof}| - {1: }{n: alaboof}| - {1: }{n: 好你}| - {1: }{n: 吗好你}| - {1: }{n: 吗好不你}| - {1: }{n: 吗好可你}| + {1: }{s: dnikoof oof}| + {1: }{n: dnikoof raboof}| + {1: }{n: dnikoof zaBoof}| + {1: }{n: dnikoof alaboof}| + {1: }{n: 好你}| + {1: }{n: 吗好你}| + {1: }{n: 吗好不你}| + {1: }{n: 吗好可你}| {1: ~}|*10 {2:-- }{5:match 1 of 8} | ]]) feed('fo') screen:expect([[ ^ of| - {1: }{s: o}{ms:of}| - {1: }{n: rabo}{mn:of}| - {1: }{n: zaBo}{mn:of}| - {1: }{n: alabo}{mn:of}| + {1: }{s: dnikoof o}{ms:of}| + {1: }{n: dnikoof rabo}{mn:of}| + {1: }{n: dnikoof zaBo}{mn:of}| + {1: }{n: dnikoofalabo}{mn:of}| {1: ~}|*14 {2:-- }{5:match 1 of 8} | ]]) @@ -4694,10 +4694,10 @@ describe('builtin popupmenu', function() feed('fo') screen:expect([[ fo^ | - {ms:fo}{s:o }{1: }| - {mn:fo}{n:obar }{1: }| - {mn:fo}{n:oBaz }{1: }| - {mn:fo}{n:obala }{1: }| + {ms:fo}{s:o fookind }{1: }| + {mn:fo}{n:obar fookind }{1: }| + {mn:fo}{n:oBaz fookind }{1: }| + {mn:fo}{n:obala fookind }{1: }| {1:~ }|*14 {2:-- }{5:match 1 of 8} | ]]) -- cgit From 61aabe0730b547b733faaf74ff181ec8c33f8b92 Mon Sep 17 00:00:00 2001 From: Jerry Date: Fri, 14 Jun 2024 19:21:16 -0700 Subject: fix(defaults): default @/Q broken when 'ignorecase' is set (#29343) Problem: When 'ignorecase' is set, the default keymap Q and Q would exit visual mode. This issue was raised in #28287 and a fix was applied in #28289. However, `==` operator is subject to user `ignorecase` setting. Solution: Switching to `==#` operator would guarantee case sensitive comparison between visual mode and linewise visual mode. Co-authored-by: Kuanju Chen --- test/functional/editor/macro_spec.lua | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'test/functional') diff --git a/test/functional/editor/macro_spec.lua b/test/functional/editor/macro_spec.lua index 27c5eddac8..680a70b78a 100644 --- a/test/functional/editor/macro_spec.lua +++ b/test/functional/editor/macro_spec.lua @@ -148,6 +148,23 @@ helloFOO]] eq({ 0, 1, 1, 0 }, fn.getpos('v')) end) + it('can be recorded and replayed in Visual mode when ignorecase', function() + command('set ignorecase') + insert('foo BAR BAR foo BAR foo BAR BAR BAR foo BAR BAR') + feed('0vqifofRq') + eq({ 0, 1, 7, 0 }, fn.getpos('.')) + eq({ 0, 1, 1, 0 }, fn.getpos('v')) + feed('Q') + eq({ 0, 1, 19, 0 }, fn.getpos('.')) + eq({ 0, 1, 1, 0 }, fn.getpos('v')) + feed('Q') + eq({ 0, 1, 27, 0 }, fn.getpos('.')) + eq({ 0, 1, 1, 0 }, fn.getpos('v')) + feed('@i') + eq({ 0, 1, 43, 0 }, fn.getpos('.')) + eq({ 0, 1, 1, 0 }, fn.getpos('v')) + end) + it('can be replayed with @ in blockwise Visual mode', function() insert [[ hello -- cgit From fd2ef4edf9cc1461edaf9f7ce34711d9b40a7fb8 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 15 Jun 2024 21:39:56 +0800 Subject: vim-patch:9.1.0488: Wrong padding for pum "kind" with 'rightleft' (#29352) Problem: Wrong padding for pum "kind" with 'rightleft'. Solution: Fix off-by-one error (zeertzjq). The screen_fill() above is end-exclusive, and - With 'rightleft' it fills `pum_col - pum_base_width - n + 1` to `col`, so the next `col` should be `pum_col - pum_base_width - n`. - With 'norightleft' it fills `col` to `pum_col - pum_base_width + n - 1`, so the next `col` should be `pum_col - pum_base_width + n`. closes: vim/vim#15004 https://github.com/vim/vim/commit/a2324373eb1c3f1777bc40cb6dcd5e895a15fe10 --- test/functional/ui/popupmenu_spec.lua | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'test/functional') diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index 323be3bd4d..177b2d707a 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -4664,10 +4664,10 @@ describe('builtin popupmenu', function() feed('S') screen:expect([[ ^ | - {1: }{s: dnikoof oof}| - {1: }{n: dnikoof raboof}| - {1: }{n: dnikoof zaBoof}| - {1: }{n: dnikoof alaboof}| + {1: }{s: dnikoof oof}| + {1: }{n: dnikoof raboof}| + {1: }{n: dnikoof zaBoof}| + {1: }{n: dnikoof alaboof}| {1: }{n: 好你}| {1: }{n: 吗好你}| {1: }{n: 吗好不你}| @@ -4678,10 +4678,10 @@ describe('builtin popupmenu', function() feed('fo') screen:expect([[ ^ of| - {1: }{s: dnikoof o}{ms:of}| - {1: }{n: dnikoof rabo}{mn:of}| - {1: }{n: dnikoof zaBo}{mn:of}| - {1: }{n: dnikoofalabo}{mn:of}| + {1: }{s: dnikoof o}{ms:of}| + {1: }{n: dnikoof rabo}{mn:of}| + {1: }{n: dnikoof zaBo}{mn:of}| + {1: }{n: dnikoof alabo}{mn:of}| {1: ~}|*14 {2:-- }{5:match 1 of 8} | ]]) -- cgit From 203540926df0ac6faae02e35ad12ae0221e210f6 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 15 Jun 2024 22:37:48 +0800 Subject: vim-patch:9.1.0491: Cmdline pum doesn't work properly with 'rightleft' (#29355) Problem: Cmdline pum doesn't work properly with 'rightleft'. Solution: Don't use curwin->w_p_rl in cmdline mode in pum_redraw(). Use a static variable since pum_may_redraw() may be called in any mode. Also correct position of other popups with 'rightleft'. (zeertzjq) closes: vim/vim#15005 https://github.com/vim/vim/commit/883018feff43413813770dd1e13d4f950aa38524 --- test/functional/ui/popupmenu_spec.lua | 71 +++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) (limited to 'test/functional') diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index 177b2d707a..76bef911ac 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -2530,6 +2530,7 @@ describe('builtin popupmenu', function() ]], } + -- oldtest: Test_wildmenu_pum_rightleft() feed('') screen:expect { grid = [[ @@ -4479,6 +4480,27 @@ describe('builtin popupmenu', function() feed('') + command('set rightleft') + feed('/X:popup PopUp') + screen:expect([[ + evif ruof eerht owt eno| + evif ruof eerht{7:^X} owt eno dna| + {n: odnU }wt erom eno| + {1: }{n: }{1: ~}| + {1: }{n: etsaP }{1: ~}| + {1: }{n: }{1: ~}| + {1: }{n: droW tceleS }{1: ~}| + {1: }{n: ecnetneS tceleS }{1: ~}| + {1: }{n: hpargaraP tceleS }{1: ~}| + {1: }{n: eniL tceleS }{1: ~}| + {1: }{n: kcolB tceleS }{1: ~}| + {1: }{n: llA tceleS }{1: ~}| + {1: ~}|*7 + :popup PopUp | + ]]) + feed('') + command('set norightleft') + -- Set an mapping to change a menu entry while it's displayed. -- The text should not change but the command does. -- Also verify that "changed" shows up, which means the mapping triggered. @@ -4535,6 +4557,55 @@ describe('builtin popupmenu', function() feed('') end) + -- oldtest: Test_mouse_popup_position() + it('position of right-click menu when clicking near edge', function() + screen:try_resize(50, 20) + exec([[ + set mousemodel=popup_setpos + aunmenu * + source $VIMRUNTIME/menu.vim + call setline(1, join(range(20))) + ]]) + + api.nvim_input_mouse('right', 'press', '', 0, 0, 45 - 1) + screen:expect([[ + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ^18 19 | + {1:~ }{n: Undo }| + {1:~ }{n: }| + {1:~ }{n: Paste }| + {1:~ }{n: }| + {1:~ }{n: Select Word }| + {1:~ }{n: Select Sentence }| + {1:~ }{n: Select Paragraph}| + {1:~ }{n: Select Line }| + {1:~ }{n: Select Block }| + {1:~ }{n: Select All }| + {1:~ }|*8 + | + ]]) + feed('') + + command('set rightleft') + api.nvim_input_mouse('right', 'press', '', 0, 0, 50 - 45) + screen:expect([[ + 91 8^1 71 61 51 41 31 21 11 01 9 8 7 6 5 4 3 2 1 0| + {n: odnU }{1: ~}| + {n: }{1: ~}| + {n: etsaP }{1: ~}| + {n: }{1: ~}| + {n: droW tceleS }{1: ~}| + {n: ecnetneS tceleS }{1: ~}| + {n:hpargaraP tceleS }{1: ~}| + {n: eniL tceleS }{1: ~}| + {n: kcolB tceleS }{1: ~}| + {n: llA tceleS }{1: ~}| + {1: ~}|*8 + | + ]]) + feed('') + command('set norightleft') + end) + describe('"kind" and "menu"', function() before_each(function() screen:try_resize(30, 8) -- cgit From ad70c9892d5b5ebcc106742386c99524f074bcea Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Sat, 15 Jun 2024 05:46:43 +0200 Subject: feat(column)!: rework 'statuscolumn' %r/l items Problem: A custom 'statuscolumn' needs to check a bunch of options and placed signs to replicate the default number column. Solution: Rework %l item to include the necessary logic to mimic the default number column. Remove now redundant %r item. --- test/functional/api/vim_spec.lua | 6 +- test/functional/terminal/window_spec.lua | 6 +- test/functional/ui/float_spec.lua | 12 +- test/functional/ui/statuscolumn_spec.lua | 354 ++++++++++++++++++------------- 4 files changed, 214 insertions(+), 164 deletions(-) (limited to 'test/functional') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index b32f2b1cb2..d28064447c 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -3887,11 +3887,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 }) diff --git a/test/functional/terminal/window_spec.lua b/test/functional/terminal/window_spec.lua index 118ca266dd..64534ca8dc 100644 --- a/test/functional/terminal/window_spec.lua +++ b/test/functional/terminal/window_spec.lua @@ -130,9 +130,9 @@ describe(':terminal window', function() ]]) feed_data('\nabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') screen:expect([[ - {7:++7 } | - {7:++8 }abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR| - {7:++9 }TUVWXYZ | + {7:++ 7 } | + {7:++ 8 }abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR| + {7:++ 9 }TUVWXYZ | {7:++10 }abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR| {7:++11 }TUVWXYZrows: 6, cols: 44 | {7:++12 }{1: } | diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua index cdaae6cfee..7aff47e50e 100644 --- a/test/functional/ui/float_spec.lua +++ b/test/functional/ui/float_spec.lua @@ -1532,9 +1532,9 @@ describe('float window', function() [2:----------------------------------------]|*6 [3:----------------------------------------]| ## grid 2 - {20:1}{19: }{20: }{22:^x}{21: }| - {14:2}{19: }{14: }{22:y} | - {14:3}{19: }{14: }{22: } | + {20: 1}{19: }{22:^x}{21: }| + {14: 2}{19: }{22:y} | + {14: 3}{19: }{22: } | {0:~ }|*3 ## grid 3 | @@ -1545,9 +1545,9 @@ describe('float window', function() ]], float_pos={[4] = {1001, "NW", 1, 4, 10, true}}} else screen:expect{grid=[[ - {20:1}{19: }{20: }{22:^x}{21: }| - {14:2}{19: }{14: }{22:y} | - {14:3}{19: }{14: }{22: } {15:x } | + {20: 1}{19: }{22:^x}{21: }| + {14: 2}{19: }{22:y} | + {14: 3}{19: }{22: } {15:x } | {0:~ }{15:y }{0: }| {0:~ }{15: }{0: }|*2 | diff --git a/test/functional/ui/statuscolumn_spec.lua b/test/functional/ui/statuscolumn_spec.lua index faf94bccbe..c388d347e2 100644 --- a/test/functional/ui/statuscolumn_spec.lua +++ b/test/functional/ui/statuscolumn_spec.lua @@ -94,46 +94,80 @@ describe('statuscolumn', function() end) it("works with 'number' and 'relativenumber'", function() - command([[set stc=%{&nu?v:lnum:''}%=%{&rnu?'\ '.v:relnum:''}│]]) - screen:expect([[ - {8:4 │}aaaaa | - {8:5 │}aaaaa | - {8:6 │}aaaaa | - {8:7 │}aaaaa | - {8:8 │}^aaaaa | - {8:9 │}aaaaa | - {8:10│}aaaaa | - {8:11│}aaaaa | - {8:12│}aaaaa | - {8:13│}aaaaa | - {8:14│}aaaaa | - {8:15│}aaaaa | - {8:16│}aaaaa | - | - ]]) - command([[set stc=%l%=%{&rnu?'\ ':''}%r│]]) + screen:expect([[ + {8: 4 }aaaaa | + {8: 5 }aaaaa | + {8: 6 }aaaaa | + {8: 7 }aaaaa | + {8: 8 }^aaaaa | + {8: 9 }aaaaa | + {8:10 }aaaaa | + {8:11 }aaaaa | + {8:12 }aaaaa | + {8:13 }aaaaa | + {8:14 }aaaaa | + {8:15 }aaaaa | + {8:16 }aaaaa | + | + ]]) + command([[set stc=%l\ ]]) screen:expect_unchanged() - command([[set stc=%{&nu?v:lnum:''}%=%{&rnu?'\ '.v:relnum:''}│]]) command('set relativenumber') screen:expect([[ - {8:4 4│}aaaaa | - {8:5 3│}aaaaa | - {8:6 2│}aaaaa | - {8:7 1│}aaaaa | - {8:8 0│}^aaaaa | - {8:9 1│}aaaaa | - {8:10 2│}aaaaa | - {8:11 3│}aaaaa | - {8:12 4│}aaaaa | - {8:13 5│}aaaaa | - {8:14 6│}aaaaa | - {8:15 7│}aaaaa | - {8:16 8│}aaaaa | - | - ]]) - command([[set stc=%l%=%{&rnu?'\ ':''}%r│]]) + {8: 4 }aaaaa | + {8: 3 }aaaaa | + {8: 2 }aaaaa | + {8: 1 }aaaaa | + {8:8 }^aaaaa | + {8: 1 }aaaaa | + {8: 2 }aaaaa | + {8: 3 }aaaaa | + {8: 4 }aaaaa | + {8: 5 }aaaaa | + {8: 6 }aaaaa | + {8: 7 }aaaaa | + {8: 8 }aaaaa | + | + ]]) + command('set stc=') + screen:expect_unchanged() + command([[set nonu stc=%l\ ]]) + screen:expect([[ + {8: 4 }aaaaa | + {8: 3 }aaaaa | + {8: 2 }aaaaa | + {8: 1 }aaaaa | + {8: 0 }^aaaaa | + {8: 1 }aaaaa | + {8: 2 }aaaaa | + {8: 3 }aaaaa | + {8: 4 }aaaaa | + {8: 5 }aaaaa | + {8: 6 }aaaaa | + {8: 7 }aaaaa | + {8: 8 }aaaaa | + | + ]]) + command('set nuw=1 stc=') screen:expect_unchanged() - command([[set stc=%{&nu?v:lnum:''}%=%{&rnu?'\ '.v:relnum:''}│]]) + -- Correct alignment with items before and after number column + command([[set nu stc=foo\ %l\ bar]]) + screen:expect([[ + {8:foo 4 bar}aaaaa | + {8:foo 3 bar}aaaaa | + {8:foo 2 bar}aaaaa | + {8:foo 1 bar}aaaaa | + {8:foo 8 bar}^aaaaa | + {8:foo 1 bar}aaaaa | + {8:foo 2 bar}aaaaa | + {8:foo 3 bar}aaaaa | + {8:foo 4 bar}aaaaa | + {8:foo 5 bar}aaaaa | + {8:foo 6 bar}aaaaa | + {8:foo 7 bar}aaaaa | + {8:foo 8 bar}aaaaa | + | + ]]) end) it("works with highlighted 'statuscolumn'", function() @@ -160,36 +194,36 @@ describe('statuscolumn', function() ]]) command('set relativenumber') screen:expect([[ - {1:4 }{8: 4│}aaaaa | - {1:5 3}{8:│}aaaaa | - {1:6 }{8: 2│}aaaaa | - {1:7 1}{8:│}aaaaa | - {1:8 }{8: 0│}^aaaaa | - {1:9 1}{8:│}aaaaa | - {1:10}{8: 2│}aaaaa | - {1:11 3}{8:│}aaaaa | - {1:12}{8: 4│}aaaaa | - {1:13 5}{8:│}aaaaa | - {1:14}{8: 6│}aaaaa | - {1:15 7}{8:│}aaaaa | - {1:16}{8: 8│}aaaaa | + {1:4 }{8: 4│}aaaaa | + {1:5 3}{8:│}aaaaa | + {1:6 }{8: 2│}aaaaa | + {1:7 1}{8:│}aaaaa | + {1:8 }{8: 0│}^aaaaa | + {1:9 1}{8:│}aaaaa | + {1:10 }{8: 2│}aaaaa | + {1:11 3}{8:│}aaaaa | + {1:12 }{8: 4│}aaaaa | + {1:13 5}{8:│}aaaaa | + {1:14 }{8: 6│}aaaaa | + {1:15 7}{8:│}aaaaa | + {1:16 }{8: 8│}aaaaa | | ]]) command('set nonumber') screen:expect([[ - {8:4│}aaaaa | - {1:3}{8:│}aaaaa | - {8:2│}aaaaa | - {1:1}{8:│}aaaaa | - {8:0│}^aaaaa | - {1:1}{8:│}aaaaa | - {8:2│}aaaaa | - {1:3}{8:│}aaaaa | - {8:4│}aaaaa | - {1:5}{8:│}aaaaa | - {8:6│}aaaaa | - {1:7}{8:│}aaaaa | - {8:8│}aaaaa | + {1: }{8:4│}aaaaa | + {1: 3}{8:│}aaaaa | + {1: }{8:2│}aaaaa | + {1: 1}{8:│}aaaaa | + {1: }{8:0│}^aaaaa | + {1: 1}{8:│}aaaaa | + {1: }{8:2│}aaaaa | + {1: 3}{8:│}aaaaa | + {1: }{8:4│}aaaaa | + {1: 5}{8:│}aaaaa | + {1: }{8:6│}aaaaa | + {1: 7}{8:│}aaaaa | + {1: }{8:8│}aaaaa | | ]]) end) @@ -305,36 +339,36 @@ describe('statuscolumn', function() -- v:relnum is the same value on wrapped lines command([[set stc=%C%=\ %{v:relnum}│%s\ ]]) screen:expect([[ - {2: }{1: 4│>>}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: 4│}{2: }{1: }aaaaaa | - {2: }{1: 3│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: 3│}{2: }{1: }aaaaaa | - {2: }{1: 2│}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: 2│}{2: }{1: }aaaaaa | - {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: 1│}{2: }{1: }aaaaaa | - {2:+}{4: 0│}{2: }{4: }{6:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| - {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: 1│}{2: }{1: }aaaaaa | - {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: 2│}{2: }{1: }aaaaaa | + {2: }{1: 4│>>}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: 4│}{2: }{1: }aaaaaaa | + {2: }{1: 3│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: 3│}{2: }{1: }aaaaaaa | + {2: }{1: 2│}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: 2│}{2: }{1: }aaaaaaa | + {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: 1│}{2: }{1: }aaaaaaa | + {2:+}{4: 0│}{2: }{4: }{6:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: 1│}{2: }{1: }aaaaaaa | + {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: 2│}{2: }{1: }aaaaaaa | | ]]) command([[set stc=%C%=\ %{v:virtnum?'':v:relnum}│%s\ ]]) screen:expect([[ - {2: }{1: 4│>>}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaa | - {2: }{1: 3│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaa | - {2: }{1: 2│}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaa | - {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaa | - {2:+}{4: 0│}{2: }{4: }{6:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| - {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaa | - {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaa | + {2: }{1: 4│>>}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: │}{2: }{1: }aaaaaaa | + {2: }{1: 3│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: │}{2: }{1: }aaaaaaa | + {2: }{1: 2│}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: │}{2: }{1: }aaaaaaa | + {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: │}{2: }{1: }aaaaaaa | + {2:+}{4: 0│}{2: }{4: }{6:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: │}{2: }{1: }aaaaaaa | + {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: │}{2: }{1: }aaaaaaa | | ]]) -- Up to 9 signs in a line @@ -347,75 +381,75 @@ describe('statuscolumn', function() command('sign place 10 line=6 name=piet2 buffer=1') command('sign place 11 line=6 name=piet1 buffer=1') screen:expect([[ - {2: }{1: 4│>>}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaa | - {2: }{1: 3│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaa | - {2: }{1: 2│>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaa | - {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaa | - {2:+}{4: 0│}{2: }{4: }{6:^+-- 1 line: aaaaaaaaaaaaaaaaa}| - {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaa | - {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaa | + {2: }{1: 4│>>}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaaa | + {2: }{1: 3│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaaa | + {2: }{1: 2│>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaaa | + {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaaa | + {2:+}{4: 0│}{2: }{4: }{6:^+-- 1 line: aaaaaaaaaaaaaaaa}| + {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaaa | + {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaaa | | ]]) -- Also test fold and sign column when 'cpoptions' includes "n" command('set cpoptions+=n') feed('Hgjg0') screen:expect([[ - {2: }{4: 0│}{1:>>}{2: }{4: }{5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| - {2: }{5:^aaaaaaaaaaaaaaaaaaaa }| - {2: }{1: 3│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }aaaaaaaaaaaaaaaaaaaa | - {2: }{1: 2│>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }aaaaaaaaaaaaaaaaaaaa | - {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }aaaaaaaaaaaaaaaaaaaa | - {2:+}{1: 4│}{2: }{1: }{3:+-- 1 line: aaaaaaaaaaaaaaaaa}| - {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }aaaaaaaaaaaaaaaaaaaa | - {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }aaaaaaaaaaaaaaaaaaaa | + {2: }{4: 0│}{1:>>}{2: }{4: }{5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {2: }{5:^aaaaaaaaaaaaaaaaaaaaa }| + {2: }{1: 3│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }aaaaaaaaaaaaaaaaaaaaa | + {2: }{1: 2│>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }aaaaaaaaaaaaaaaaaaaaa | + {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }aaaaaaaaaaaaaaaaaaaaa | + {2:+}{1: 4│}{2: }{1: }{3:+-- 1 line: aaaaaaaaaaaaaaaa}| + {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }aaaaaaaaaaaaaaaaaaaaa | + {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }aaaaaaaaaaaaaaaaaaaaa | | ]]) command('set breakindent') command('sign unplace 2') feed('J2gjg0') screen:expect([[ - {2: }{4: 0│}{1:>>}{2: }{4: }{5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| - {2: } {5:aaaaaaaaaaaaaaaaaaaa aaaaaaaaa}| - {2: } {5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| - {2: } {5:^aaaaaaaaaaa }| - {2: }{1: 1│>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: } aaaaaaaaaaaaaaaaaaaa | - {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: } aaaaaaaaaaaaaaaaaaaa | - {2:+}{1: 3│}{2: }{1: }{3:+-- 1 line: aaaaaaaaaaaaaaaaa}| - {2: }{1: 4│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: } aaaaaaaaaaaaaaaaaaaa | - {2: }{1: 5│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: } aaaaaaaaaaaaaaaaaaaa | + {2: }{4: 0│}{1:>>}{2: }{4: }{5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {2: } {5:aaaaaaaaaaaaaaaaaaaaa aaaaaaa}| + {2: } {5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {2: } {5:^aaaaaaaaaaaaaa }| + {2: }{1: 1│>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: } aaaaaaaaaaaaaaaaaaaaa | + {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: } aaaaaaaaaaaaaaaaaaaaa | + {2:+}{1: 3│}{2: }{1: }{3:+-- 1 line: aaaaaaaaaaaaaaaa}| + {2: }{1: 4│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: } aaaaaaaaaaaaaaaaaaaaa | + {2: }{1: 5│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: } aaaaaaaaaaaaaaaaaaaaa | | ]]) command('set nobreakindent') feed('$g0') screen:expect([[ - {2: }{4: 0│}{1:>>}{2: }{4: }{5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| - {2: }{5:aaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaa}| + {2: }{4: 0│}{1:>>}{2: }{4: }{5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {2: }{5:aaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaa}| {2: }{5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| - {2: }{5:^aaa }| - {2: }{1: 1│>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }aaaaaaaaaaaaaaaaaaaa | - {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }aaaaaaaaaaaaaaaaaaaa | - {2:+}{1: 3│}{2: }{1: }{3:+-- 1 line: aaaaaaaaaaaaaaaaa}| - {2: }{1: 4│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }aaaaaaaaaaaaaaaaaaaa | - {2: }{1: 5│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }aaaaaaaaaaaaaaaaaaaa | + {2: }{5:^aaaa }| + {2: }{1: 1│>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }aaaaaaaaaaaaaaaaaaaaa | + {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }aaaaaaaaaaaaaaaaaaaaa | + {2:+}{1: 3│}{2: }{1: }{3:+-- 1 line: aaaaaaaaaaaaaaaa}| + {2: }{1: 4│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }aaaaaaaaaaaaaaaaaaaaa | + {2: }{1: 5│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }aaaaaaaaaaaaaaaaaaaaa | | ]]) command('silent undo') @@ -427,7 +461,23 @@ describe('statuscolumn', function() virt_lines_above = true, virt_lines = {{{"virt_line above", ""}}} }) vim.api.nvim_buf_set_extmark(0, ns, 4, 0, { virt_lines = {{{"virt_line", ""}}} }) ]]) - command('set foldcolumn=0 signcolumn=no') + command('set foldcolumn=0 signcolumn=number stc=%l') + screen:expect([[ + {1:>>}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | + {1: 5}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | + {1: }virt_line | + {1: }virt_line above | + {1:>>}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | + {1: 7}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | + {4: 8}{6:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {1: 9}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | + {1:10}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | + {1:11}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | + {1:12}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | + {1:13}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | + {1:14}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | + | + ]]) command( [[set stc=%{v:virtnum<0?'virtual':(!v:virtnum?'buffer':'wrapped')}%=%{'\ '.v:virtnum.'\ '.v:lnum}]] ) @@ -533,8 +583,8 @@ describe('statuscolumn', function() command([[set stc=%6s\ %l]]) exec_lua('vim.api.nvim_buf_set_extmark(0, ns, 7, 0, {sign_text = "𒀀"})') screen:expect([[ - {8: 𒀀 8 }^aaaaa | - {8: }{7: }{8: 9 }aaaaa | + {8: 𒀀 8}^aaaaa | + {8: }{7: }{8: 9}aaaaa | | ]]) end) @@ -644,26 +694,26 @@ describe('statuscolumn', function() -- clicking an item does not drag mouse api.nvim_input_mouse('left', 'press', '', 0, 0, 0) screen:expect([[ - {0:8 }^aaaaa | + {0: 8}^aaaaa | {1: Echo } | ]]) api.nvim_input_mouse('left', 'press', '', 0, 1, 5) api.nvim_input_mouse('left', 'release', '', 0, 1, 5) screen:expect([[ - {0:8 }^aaaaa | + {0: 8}^aaaaa | 0 1 l 8 | ]]) command('echo') -- clicking outside to close the menu does not drag mouse api.nvim_input_mouse('left', 'press', '', 0, 0, 0) screen:expect([[ - {0:8 }^aaaaa | + {0: 8}^aaaaa | {1: Echo } | ]]) api.nvim_input_mouse('left', 'press', '', 0, 0, 10) api.nvim_input_mouse('left', 'release', '', 0, 0, 10) screen:expect([[ - {0:8 }^aaaaa | + {0: 8}^aaaaa | | ]]) end) @@ -749,9 +799,9 @@ describe('statuscolumn', function() it('works with cmdwin', function() feed(':set stc=%lq:k$') screen:expect([[ - {8:7 }aaaaa | - {8:8 }aaaaa | - {8:9 }aaaaa | + {8: 7}aaaaa | + {8: 8}aaaaa | + {8: 9}aaaaa | {8:10}aaaaa | {2:[No Name] [+] }| {1::}{8:1}set stc=%^l | @@ -899,16 +949,16 @@ describe('statuscolumn', function() command([[set spell stc=%l\ ]]) command('call setline(8, "This is a line that contains ᶏ multibyte character.")') screen:expect([[ - {8:8 }^This is a line that contains {31:ᶏ}| + {8: 8 }^This is a line that contains {31:ᶏ}| {8: } {31:multibyte} character. | - {8:9 }{31:aaaaa} | + {8: 9 }{31:aaaaa} | | ]]) end) it('line increase properly redraws buffer text with relativenumber #27709', function() screen:try_resize(33, 4) - command([[set rnu nuw=3 stc=%l\ ]]) + command([[set rnu nuw=3 stc=%{v:lnum}\ ]]) command('call setline(1, range(1, 99))') feed('Gyyp') screen:expect([[ -- cgit From 20a7eebec086129e605041d32916f36df50890de Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 17 Jun 2024 06:42:11 +0800 Subject: vim-patch:9.1.0494: Wrong matched text highlighted in pum with 'rightleft' (#29371) Problem: Wrong matched text highlighted in pum with 'rightleft'. Solution: Match using the original text instead of the reversed text. (zeertzjq) closes: vim/vim#15020 https://github.com/vim/vim/commit/63901e89638d683ecbc8e3323170dd485657fd1d --- test/functional/ui/popupmenu_spec.lua | 82 +++++++++++++++++++++++++++-------- 1 file changed, 64 insertions(+), 18 deletions(-) (limited to 'test/functional') diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index 76bef911ac..4ea60194c2 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -1177,8 +1177,8 @@ describe('builtin popupmenu', function() ks = { foreground = Screen.colors.Red, background = Screen.colors.Grey }, xn = { foreground = Screen.colors.White, background = Screen.colors.Magenta }, xs = { foreground = Screen.colors.Black, background = Screen.colors.Grey }, - mn = { foreground = Screen.colors.Blue, background = Screen.colors.White }, - ms = { foreground = Screen.colors.Green, background = Screen.colors.White }, + mn = { foreground = Screen.colors.Blue, background = Screen.colors.Magenta }, + ms = { foreground = Screen.colors.Blue, background = Screen.colors.Grey }, }) screen:attach({ ext_multigrid = multigrid }) end) @@ -4669,6 +4669,7 @@ describe('builtin popupmenu', function() return { \ 'words': [ \ { 'word': 'foo', 'kind': 'fookind' }, + \ { 'word': 'foofoo', 'kind': 'fookind' }, \ { 'word': 'foobar', 'kind': 'fookind' }, \ { 'word': 'fooBaz', 'kind': 'fookind' }, \ { 'word': 'foobala', 'kind': 'fookind' }, @@ -4680,13 +4681,14 @@ describe('builtin popupmenu', function() endfunc set omnifunc=Omni_test set completeopt=menu,noinsert,fuzzy - hi PmenuMatchSel guifg=Green guibg=White - hi PmenuMatch guifg=Blue guibg=White + hi PmenuMatchSel guifg=Blue guibg=Grey + hi PmenuMatch guifg=Blue guibg=Magenta ]]) feed('i') local pum_start = [[ ^ | {s:foo fookind }{1: }| + {n:foofoo fookind }{1: }| {n:foobar fookind }{1: }| {n:fooBaz fookind }{1: }| {n:foobala fookind }{1: }| @@ -4694,19 +4696,20 @@ describe('builtin popupmenu', function() {n:你好吗 }{1: }| {n:你不好吗 }{1: }| {n:你可好吗 }{1: }| - {1:~ }|*10 - {2:-- }{5:match 1 of 8} | + {1:~ }|*9 + {2:-- }{5:match 1 of 9} | ]] screen:expect(pum_start) feed('fo') screen:expect([[ fo^ | {ms:fo}{s:o fookind }{1: }| + {mn:fo}{n:ofoo fookind }{1: }| {mn:fo}{n:obar fookind }{1: }| {mn:fo}{n:oBaz fookind }{1: }| {mn:fo}{n:obala fookind }{1: }| - {1:~ }|*14 - {2:-- }{5:match 1 of 8} | + {1:~ }|*13 + {2:-- }{5:match 1 of 9} | ]]) feed('S') screen:expect(pum_start) @@ -4718,7 +4721,7 @@ describe('builtin popupmenu', function() {mn:你}{n:不好吗 }{1: }| {mn:你}{n:可好吗 }{1: }| {1:~ }|*14 - {2:-- }{5:match 1 of 8} | + {2:-- }{5:match 1 of 9} | ]]) feed('吗') screen:expect([[ @@ -4727,15 +4730,16 @@ describe('builtin popupmenu', function() {mn:你}{n:不好}{mn:吗}{n: }{1: }| {mn:你}{n:可好}{mn:吗}{n: }{1: }| {1:~ }|*15 - {2:-- }{5:match 1 of 8} | + {2:-- }{5:match 1 of 9} | ]]) - feed('') + command('set rightleft') feed('S') - screen:expect([[ + local pum_start_rl = [[ ^ | {1: }{s: dnikoof oof}| + {1: }{n: dnikoof oofoof}| {1: }{n: dnikoof raboof}| {1: }{n: dnikoof zaBoof}| {1: }{n: dnikoof alaboof}| @@ -4743,18 +4747,41 @@ describe('builtin popupmenu', function() {1: }{n: 吗好你}| {1: }{n: 吗好不你}| {1: }{n: 吗好可你}| - {1: ~}|*10 - {2:-- }{5:match 1 of 8} | - ]]) + {1: ~}|*9 + {2:-- }{5:match 1 of 9} | + ]] + screen:expect(pum_start_rl) feed('fo') screen:expect([[ ^ of| {1: }{s: dnikoof o}{ms:of}| + {1: }{n: dnikoof oofo}{mn:of}| {1: }{n: dnikoof rabo}{mn:of}| {1: }{n: dnikoof zaBo}{mn:of}| {1: }{n: dnikoof alabo}{mn:of}| + {1: ~}|*13 + {2:-- }{5:match 1 of 9} | + ]]) + feed('S') + screen:expect(pum_start_rl) + feed('你') + screen:expect([[ + ^ 你| + {1: }{s: 好}{ms:你}| + {1: }{n: 吗好}{mn:你}| + {1: }{n: 吗好不}{mn:你}| + {1: }{n: 吗好可}{mn:你}| {1: ~}|*14 - {2:-- }{5:match 1 of 8} | + {2:-- }{5:match 1 of 9} | + ]]) + feed('吗') + screen:expect([[ + ^ 吗你| + {1: }{s: }{ms:吗}{s:好}{ms:你}| + {1: }{n: }{mn:吗}{n:好不}{mn:你}| + {1: }{n: }{mn:吗}{n:好可}{mn:你}| + {1: ~}|*15 + {2:-- }{5:match 1 of 9} | ]]) feed('') command('set norightleft') @@ -4766,12 +4793,31 @@ describe('builtin popupmenu', function() screen:expect([[ fo^ | {ms:fo}{s:o fookind }{1: }| + {mn:fo}{n:ofoo fookind }{1: }| {mn:fo}{n:obar fookind }{1: }| {mn:fo}{n:oBaz fookind }{1: }| {mn:fo}{n:obala fookind }{1: }| - {1:~ }|*14 - {2:-- }{5:match 1 of 8} | + {1:~ }|*13 + {2:-- }{5:match 1 of 9} | ]]) + feed('') + + command('set rightleft') + feed('S') + screen:expect(pum_start_rl) + feed('fo') + screen:expect([[ + ^ of| + {1: }{s: dnikoof o}{ms:of}| + {1: }{n: dnikoof oofo}{mn:of}| + {1: }{n: dnikoof rabo}{mn:of}| + {1: }{n: dnikoof zaBo}{mn:of}| + {1: }{n: dnikoof alabo}{mn:of}| + {1: ~}|*13 + {2:-- }{5:match 1 of 9} | + ]]) + feed('') + command('set norightleft') end) end end -- cgit From c429c5f86fb8286bbb28e96985d9cc212155201b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 18 Jun 2024 05:49:33 +0800 Subject: vim-patch:9.1.0495: Matched text isn't highlighted in cmdline pum Problem: Matched text isn't highlighted in cmdline pum. Solution: Use cmdline completion pattern in cmdline mode. (zeertzjq) closes: vim/vim#15029 https://github.com/vim/vim/commit/d8c9340fc67ca19f82ec3e77ec38296424e758cf Cherry-pick syntax.txt change from runtime update. --- test/functional/ui/popupmenu_spec.lua | 60 +++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) (limited to 'test/functional') diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index 4ea60194c2..fac863ead0 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -3550,6 +3550,66 @@ describe('builtin popupmenu', function() | ]]) end) + + -- oldtest: Test_wildmenu_pum_hl_match() + it('highlighting matched text in cmdline pum', function() + exec([[ + set wildoptions=pum,fuzzy + hi PmenuMatchSel guifg=Blue guibg=Grey + hi PmenuMatch guifg=Blue guibg=Magenta + ]]) + + feed(':sign plc') + screen:expect([[ + | + {1:~ }|*16 + {1:~ }{s: }{ms:pl}{s:a}{ms:c}{s:e }{1: }| + {1:~ }{n: un}{mn:pl}{n:a}{mn:c}{n:e }{1: }| + :sign place^ | + ]]) + feed('') + screen:expect([[ + | + {1:~ }|*16 + {1:~ }{n: }{mn:pl}{n:a}{mn:c}{n:e }{1: }| + {1:~ }{s: un}{ms:pl}{s:a}{ms:c}{s:e }{1: }| + :sign unplace^ | + ]]) + feed('') + screen:expect([[ + | + {1:~ }|*16 + {1:~ }{n: }{mn:pl}{n:a}{mn:c}{n:e }{1: }| + {1:~ }{n: un}{mn:pl}{n:a}{mn:c}{n:e }{1: }| + :sign plc^ | + ]]) + feed('') + command('set wildoptions-=fuzzy') + feed(':sign un') + screen:expect([[ + | + {1:~ }|*16 + {1:~ }{s: }{ms:un}{s:define }{1: }| + {1:~ }{n: }{mn:un}{n:place }{1: }| + :sign undefine^ | + ]]) + feed('') + screen:expect([[ + | + {1:~ }|*16 + {1:~ }{n: }{mn:un}{n:define }{1: }| + {1:~ }{s: }{ms:un}{s:place }{1: }| + :sign unplace^ | + ]]) + feed('') + screen:expect([[ + | + {1:~ }|*16 + {1:~ }{n: }{mn:un}{n:define }{1: }| + {1:~ }{n: }{mn:un}{n:place }{1: }| + :sign un^ | + ]]) + end) end it("'pumheight'", function() -- cgit From c2491fbab43fc506f7f902c72206d890e01688a5 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 18 Jun 2024 06:02:01 +0800 Subject: vim-patch:9.1.0496: matched text is highlighted case-sensitively Problem: matched text is highlighted case-sensitively Solution: use MB_STRNICMP, update highlighting when the base changes (glepnir) fixes: vim/vim#15021 closes: vim/vim#15023 https://github.com/vim/vim/commit/f189138b39a11ed5cf3adea6610469b478841aba Co-authored-by: glepnir --- test/functional/ui/popupmenu_spec.lua | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'test/functional') diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index fac863ead0..a1a21eb317 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -4739,6 +4739,20 @@ describe('builtin popupmenu', function() \ { 'word': '你可好吗' }, \]} endfunc + + func Comp() + let col = col('.') + if getline('.') == 'f' + let col -= 1 + endif + call complete(col, [ + \ #{word: "foo", icase: 1}, + \ #{word: "Foobar", icase: 1}, + \ #{word: "fooBaz", icase: 1}, + \]) + return '' + endfunc + set omnifunc=Omni_test set completeopt=menu,noinsert,fuzzy hi PmenuMatchSel guifg=Blue guibg=Grey @@ -4878,6 +4892,20 @@ describe('builtin popupmenu', function() ]]) feed('') command('set norightleft') + + feed('S=Comp()f') + screen:expect([[ + f^ | + {ms:f}{s:oo }{1: }| + {mn:F}{n:oobar }{1: }| + {mn:f}{n:ooBaz }{1: }| + {1:~ }|*15 + {2:-- INSERT --} | + ]]) + feed('o=Comp()') + screen:expect_unchanged(true) + + feed('') end) end end -- cgit From 948f2beed4ea55a9c2cce3cff894359b94fba748 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 18 Jun 2024 09:47:10 +0800 Subject: fix(lua): find length of completion prefix earlier (#29384) Do the expansion right after setting the expand context, so that the length of the completion prefix can be set, but don't do that directly in set_one_cmd_context(), as that's also called by getcmdcompltype(). --- test/functional/editor/completion_spec.lua | 52 ++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'test/functional') diff --git a/test/functional/editor/completion_spec.lua b/test/functional/editor/completion_spec.lua index a28e449f49..b42310fa81 100644 --- a/test/functional/editor/completion_spec.lua +++ b/test/functional/editor/completion_spec.lua @@ -812,11 +812,63 @@ describe('completion', function() } end) + it('prefix is not included in completion for cmdline mode', function() + feed(':lua math.a') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {100:abs}{3: acos asin atan atan2 }| + :lua math.abs^ | + ]]) + feed('') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {3:abs }{100:acos}{3: asin atan atan2 }| + :lua math.acos^ | + ]]) + end) + + it('prefix is not included in completion for i_CTRL-X_CTRL-V #19623', function() + feed('ilua math.a') + screen:expect([[ + lua math.abs^ | + {1:~ }{12: abs }{1: }| + {1:~ }{4: acos }{1: }| + {1:~ }{4: asin }{1: }| + {1:~ }{4: atan }{1: }| + {1:~ }{4: atan2 }{1: }| + {1:~ }| + {5:-- Command-line completion (^V^N^P) }{6:match 1 of 5} | + ]]) + feed('') + screen:expect([[ + lua math.acos^ | + {1:~ }{4: abs }{1: }| + {1:~ }{12: acos }{1: }| + {1:~ }{4: asin }{1: }| + {1:~ }{4: atan }{1: }| + {1:~ }{4: atan2 }{1: }| + {1:~ }| + {5:-- Command-line completion (^V^N^P) }{6:match 2 of 5} | + ]]) + end) + it('provides completion from `getcompletion()`', function() eq({ 'vim' }, fn.getcompletion('vi', 'lua')) eq({ 'api' }, fn.getcompletion('vim.ap', 'lua')) eq({ 'tbl_filter' }, fn.getcompletion('vim.tbl_fil', 'lua')) eq({ 'vim' }, fn.getcompletion('print(vi', 'lua')) + eq({ 'abs', 'acos', 'asin', 'atan', 'atan2' }, fn.getcompletion('math.a', 'lua')) + eq({ 'abs', 'acos', 'asin', 'atan', 'atan2' }, fn.getcompletion('lua math.a', 'cmdline')) -- fuzzy completion is not supported, so the result should be the same command('set wildoptions+=fuzzy') eq({ 'vim' }, fn.getcompletion('vi', 'lua')) -- cgit From 1a1c766049826b6049610edda8f72eac1f75b38d Mon Sep 17 00:00:00 2001 From: Rafael Kitover Date: Tue, 18 Jun 2024 03:23:52 +0000 Subject: refactor: Windows tilde expansion followup (#29380) Followup to #28515: Rename the static os_homedir() to os_uv_homedir() to emphasize that it is a wrapper around a libuv function. Add the function os_get_homedir() to os/env.c to return the cached homedir value as a const. Must be called after homedir is initialized or it fails. The difference between this function and the static os_uv_homedir() is that the latter gets the homedir from libuv and is used to initialize homedir in init_homedir(), while os_get_homedir() just returns homedir as a const if it's initialized and is public. Use the os_get_homedir() accessor for ~/ expansion on Windows to make the code more concise. Add a Windows section to main_spec.lua with tests for expanding ~/ and ~\ prefixes for files passed in on the command-line. Signed-off-by: Rafael Kitover --- test/functional/core/main_spec.lua | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'test/functional') diff --git a/test/functional/core/main_spec.lua b/test/functional/core/main_spec.lua index 5e903726db..a6e917b4b2 100644 --- a/test/functional/core/main_spec.lua +++ b/test/functional/core/main_spec.lua @@ -193,4 +193,26 @@ describe('command-line option', function() matches('Run "nvim %-V1 %-v"', fn.system({ nvim_prog_abs(), '-v' })) matches('Compilation: .*Run :checkhealth', fn.system({ nvim_prog_abs(), '-V1', '-v' })) end) + + if is_os('win') then + for _, prefix in ipairs({ '~/', '~\\' }) do + it('expands ' .. prefix .. ' on Windows', function() + local fname = os.getenv('USERPROFILE') .. '\\nvim_test.txt' + finally(function() + os.remove(fname) + end) + write_file(fname, 'some text') + eq( + 'some text', + fn.system({ + nvim_prog_abs(), + '-es', + '+%print', + '+q', + prefix .. 'nvim_test.txt', + }):gsub('\n', '') + ) + end) + end + end end) -- cgit From b0c336eaf8e7dd0e52e08195f46fd309fc138ea1 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 18 Jun 2024 12:02:31 +0800 Subject: refactor(lua): remove unnecessary strlen() in nlua_expand_pat() (#29388) Also change the initial value of `status` to `FAIL`, as that'll avoid unnecessary assignments. --- test/functional/editor/completion_spec.lua | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'test/functional') diff --git a/test/functional/editor/completion_spec.lua b/test/functional/editor/completion_spec.lua index b42310fa81..405af5fcfd 100644 --- a/test/functional/editor/completion_spec.lua +++ b/test/functional/editor/completion_spec.lua @@ -816,22 +816,14 @@ describe('completion', function() feed(':lua math.a') screen:expect([[ | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| + {1:~ }|*5 {100:abs}{3: acos asin atan atan2 }| :lua math.abs^ | ]]) feed('') screen:expect([[ | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| + {1:~ }|*5 {3:abs }{100:acos}{3: asin atan atan2 }| :lua math.acos^ | ]]) -- cgit From 102971a396724594a00f7e31cbeec55cdb536f17 Mon Sep 17 00:00:00 2001 From: luukvbaal Date: Wed, 19 Jun 2024 00:00:39 +0200 Subject: fix(mouse): early return when clicking in padded 'statuscolumn' (#29394) Problem: Hit assert when clicking inside a padded 'statuscolumn' that is padded beyond the length of the allocated click_defs. Solution: Still consider this a "in_statuscol" click, but return early when about to execute the click func. --- test/functional/ui/statuscolumn_spec.lua | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'test/functional') diff --git a/test/functional/ui/statuscolumn_spec.lua b/test/functional/ui/statuscolumn_spec.lua index c388d347e2..7ee7f38d07 100644 --- a/test/functional/ui/statuscolumn_spec.lua +++ b/test/functional/ui/statuscolumn_spec.lua @@ -91,6 +91,10 @@ describe('statuscolumn', function() {8:2 }aaaaa | | ]]) + -- Doesn't crash when clicking inside padded area without click_defs + command('set numberwidth=10') + api.nvim_input_mouse('left', 'press', '', 0, 0, 5) + assert_alive() end) it("works with 'number' and 'relativenumber'", function() -- cgit From a2a3e8412e6d4e9a952c57a5298016cae8bf5229 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 19 Jun 2024 07:42:56 +0800 Subject: vim-patch:8.2.5047: CurSearch highlight is often wrong Problem: CurSearch highlight is often wrong. Solution: Remember the last highlighted position and redraw when needed. https://github.com/vim/vim/commit/368137aa525982984beed73940af481ac53a62af Co-authored-by: Bram Moolenaar --- test/functional/ui/searchhl_spec.lua | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/ui/searchhl_spec.lua b/test/functional/ui/searchhl_spec.lua index 493493da60..eab265cbb1 100644 --- a/test/functional/ui/searchhl_spec.lua +++ b/test/functional/ui/searchhl_spec.lua @@ -197,7 +197,8 @@ describe('search highlighting', function() } end) - it('works for multiline match', function() + -- oldtest: Test_hlsearch_cursearch() + it('works for multiline match, no duplicate highlight', function() command([[call setline(1, ['one', 'foo', 'bar', 'baz', 'foo the foo and foo', 'bar'])]]) feed('gg/foo') screen:expect([[ @@ -281,6 +282,28 @@ describe('search highlighting', function() {2:hij}kl | /efg\nhij | ]]) + + -- check clearing CurSearch when using it for another match + feed('G?^abcdY') + screen:expect([[ + --- | + {1:abcd}efg | + hijkl | + --- | + {2:^abcd}efg | + hijkl | + ?^abcd | + ]]) + feed('kkP') + screen:expect([[ + --- | + {1:abcd}efg | + {2:^abcd}efg | + hijkl | + --- | + {1:abcd}efg | + ?^abcd | + ]]) end) end) -- cgit From b1c439cef6cae54745f3bf446596c1b7e417c80e Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 19 Jun 2024 09:20:24 +0800 Subject: fix(drawline): don't draw beyond end of window with 'rnu' (#29406) --- test/functional/ui/diff_spec.lua | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'test/functional') diff --git a/test/functional/ui/diff_spec.lua b/test/functional/ui/diff_spec.lua index e79621f364..bad35dd2af 100644 --- a/test/functional/ui/diff_spec.lua +++ b/test/functional/ui/diff_spec.lua @@ -1346,6 +1346,46 @@ it("diff mode doesn't restore invalid 'foldcolumn' value #21647", function() eq('0', api.nvim_get_option_value('foldcolumn', {})) end) +it("'relativenumber' doesn't draw beyond end of window in diff mode #29403", function() + local screen = Screen.new(60, 12) + screen:attach() + command('set relativenumber') + feed('10aagg') + command('vnew') + feed('abgg') + command('windo diffthis') + command('wincmd |') + screen:expect([[ + {8: }│{7: }{8: 0 }{27:^a}{4: }| + {8: }│{7: }{8: 1 }{22:a }| + {8: }│{7: }{8: 2 }{22:a }| + {8: }│{7: }{8: 3 }{22:a }| + {8: }│{7: }{8: 4 }{22:a }| + {8: }│{7: }{8: 5 }{22:a }| + {8: }│{7: }{8: 6 }{22:a }| + {8: }│{7: }{8: 7 }{22:a }| + {8: }│{7: }{8: 8 }{22:a }| + {8: }│{7: }{8: 9 }{22:a }| + {2:< }{3:[No Name] [+] }| + | + ]]) + feed('j') + screen:expect([[ + {8: }│{7: }{8: 1 }{27:a}{4: }| + {8: }│{7: }{8: 0 }{22:^a }| + {8: }│{7: }{8: 1 }{22:a }| + {8: }│{7: }{8: 2 }{22:a }| + {8: }│{7: }{8: 3 }{22:a }| + {8: }│{7: }{8: 4 }{22:a }| + {8: }│{7: }{8: 5 }{22:a }| + {8: }│{7: }{8: 6 }{22:a }| + {8: }│{7: }{8: 7 }{22:a }| + {8: }│{7: }{8: 8 }{22:a }| + {2:< }{3:[No Name] [+] }| + | + ]]) +end) + -- oldtest: Test_diff_binary() it('diff mode works properly if file contains NUL bytes vim-patch:8.2.3925', function() local screen = Screen.new(40, 20) -- cgit From 0e3e1e6b6d8370f1fcc9887d5cb931b131450a1c Mon Sep 17 00:00:00 2001 From: Jaehwang Jung Date: Thu, 20 Jun 2024 22:37:09 +0900 Subject: fix(treesitter): don't open fold when o/O adds a line below #28709 Problem: `o`-ing on a folded line opens the fold, because the new line gets the fold level from the above line (level '='), which extends the fold to the new line. `O` has a similar problem when run on the line below a fold. Solution: Use -1 for the added line to get the lower level from the above/below line. --- test/functional/treesitter/fold_spec.lua | 63 +++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/treesitter/fold_spec.lua b/test/functional/treesitter/fold_spec.lua index a7f278aa01..6d33544cd4 100644 --- a/test/functional/treesitter/fold_spec.lua +++ b/test/functional/treesitter/fold_spec.lua @@ -646,6 +646,67 @@ import hello]]) } end) + it('does not extend closed fold with `o`/`O`', function() + local screen = Screen.new(60, 24) + screen:attach() + + insert(test_text) + parse('c') + command([[set foldmethod=expr foldexpr=v:lua.vim.treesitter.foldexpr() foldcolumn=1]]) + + feed('5ggzco') + screen:expect({ + grid = [[ + {7:-}void ui_refresh(void) | + {7:│}{ | + {7:│} int width = INT_MAX, height = INT_MAX; | + {7:│} bool ext_widgets[kUIExtCount]; | + {7:+}{13:+--- 3 lines: for (UIExtension i = 0; (int)i < kUIExtCount}| + {7:│}^ | + {7:│} | + {7:│} bool inclusive = ui_override(); | + {7:-} for (size_t i = 0; i < ui_count; i++) { | + {7:2} UI *ui = uis[i]; | + {7:2} width = MIN(ui->width, width); | + {7:2} height = MIN(ui->height, height); | + {7:2} foo = BAR(ui->bazaar, bazaar); | + {7:-} for (UIExtension j = 0; (int)j < kUIExtCount; j++) { | + {7:3} ext_widgets[j] &= (ui->ui_ext[j] || inclusive); | + {7:3} } | + {7:2} } | + {7:│}} | + {1:~ }|*5 + {5:-- INSERT --} | + ]], + }) + + feed('O') + screen:expect({ + grid = [[ + {7:-}void ui_refresh(void) | + {7:│}{ | + {7:│} int width = INT_MAX, height = INT_MAX; | + {7:│} bool ext_widgets[kUIExtCount]; | + {7:+}{13:+--- 3 lines: for (UIExtension i = 0; (int)i < kUIExtCount}| + {7:│}^ | + {7:│} |*2 + {7:│} bool inclusive = ui_override(); | + {7:-} for (size_t i = 0; i < ui_count; i++) { | + {7:2} UI *ui = uis[i]; | + {7:2} width = MIN(ui->width, width); | + {7:2} height = MIN(ui->height, height); | + {7:2} foo = BAR(ui->bazaar, bazaar); | + {7:-} for (UIExtension j = 0; (int)j < kUIExtCount; j++) { | + {7:3} ext_widgets[j] &= (ui->ui_ext[j] || inclusive); | + {7:3} } | + {7:2} } | + {7:│}} | + {1:~ }|*4 + {5:-- INSERT --} | + ]], + }) + end) + it("doesn't open folds that are not touched", function() local screen = Screen.new(40, 8) screen:set_default_attr_ids({ @@ -674,7 +735,7 @@ t2]]) grid = [[ {1:-}# h1 | {1:│}t1 | - {1:│}^ | + {1:-}^ | {1:+}{2:+-- 2 lines: # h2·····················}| {3:~ }|*3 {4:-- INSERT --} | -- cgit From 5a8a34dafa2aa9e11df405745008543eef644bdc Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 22 Jun 2024 21:17:36 +0800 Subject: fix(filetype): source ftdetect/* after creating scripts.vim autocmds (#29445) --- test/functional/core/startup_spec.lua | 40 +++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) (limited to 'test/functional') diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua index 1bb4ce2946..45f8294b16 100644 --- a/test/functional/core/startup_spec.lua +++ b/test/functional/core/startup_spec.lua @@ -1325,31 +1325,59 @@ describe('runtime:', function() end) it("loads ftdetect/*.{vim,lua} respecting 'rtp' order", function() - local ftdetect_folder = table.concat({ xconfig, 'nvim', 'ftdetect' }, pathsep) - local after_ftdetect_folder = table.concat({ xconfig, 'nvim', 'after', 'ftdetect' }, pathsep) + local rtp_folder = table.concat({ xconfig, 'nvim' }, pathsep) + local after_rtp_folder = table.concat({ rtp_folder, 'after' }, pathsep) + local ftdetect_folder = table.concat({ rtp_folder, 'ftdetect' }, pathsep) + local after_ftdetect_folder = table.concat({ after_rtp_folder, 'ftdetect' }, pathsep) mkdir_p(ftdetect_folder) mkdir_p(after_ftdetect_folder) finally(function() rmdir(ftdetect_folder) rmdir(after_ftdetect_folder) end) + write_file(table.concat({ rtp_folder, 'scripts.vim' }, pathsep), [[let g:aseq ..= 'S']]) + write_file(table.concat({ after_rtp_folder, 'scripts.vim' }, pathsep), [[let g:aseq ..= 's']]) -- A .lua file is loaded after a .vim file if they only differ in extension. -- All files in after/ftdetect/ are loaded after all files in ftdetect/. - write_file(table.concat({ ftdetect_folder, 'new-ft.vim' }, pathsep), [[let g:seq ..= 'A']]) + write_file( + table.concat({ ftdetect_folder, 'new-ft.vim' }, pathsep), + [[ + let g:seq ..= 'A' + autocmd BufRead,BufNewFile FTDETECT let g:aseq ..= 'A' + ]] + ) write_file( table.concat({ ftdetect_folder, 'new-ft.lua' }, pathsep), - [[vim.g.seq = vim.g.seq .. 'B']] + [[ + vim.g.seq = vim.g.seq .. 'B' + vim.api.nvim_create_autocmd({ 'BufRead', 'BufNewFile' }, { + pattern = 'FTDETECT', + command = "let g:aseq ..= 'B'", + }) + ]] ) write_file( table.concat({ after_ftdetect_folder, 'new-ft.vim' }, pathsep), - [[let g:seq ..= 'a']] + [[ + let g:seq ..= 'a' + autocmd BufRead,BufNewFile FTDETECT let g:aseq ..= 'a' + ]] ) write_file( table.concat({ after_ftdetect_folder, 'new-ft.lua' }, pathsep), - [[vim.g.seq = vim.g.seq .. 'b']] + [[ + vim.g.seq = vim.g.seq .. 'b' + vim.api.nvim_create_autocmd({ 'BufRead', 'BufNewFile' }, { + pattern = 'FTDETECT', + command = "let g:aseq ..= 'b'", + }) + ]] ) clear { args_rm = { '-u' }, args = { '--cmd', 'let g:seq = ""' }, env = xenv } eq('ABab', eval('g:seq')) + command('let g:aseq = ""') + command('edit FTDETECT') + eq('SsABab', eval('g:aseq')) end) end) -- cgit From da4e8dc5b04a82c6dd483f6c5345a81d8b375bec Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Sun, 23 Jun 2024 13:50:21 +0200 Subject: fix(treesitter): do not modify highlight state for _on_spell_nav Problem: Treesitter highlighter clears the already populated highlight state when performing spell checking while drawing a smoothscrolled topline. Solution: Save and restore the highlight state in the highlighter's _on_spell_nav callback. --- test/functional/treesitter/highlight_spec.lua | 63 +++++++++++++++------------ 1 file changed, 36 insertions(+), 27 deletions(-) (limited to 'test/functional') diff --git a/test/functional/treesitter/highlight_spec.lua b/test/functional/treesitter/highlight_spec.lua index 69984b3233..05c0cdc01e 100644 --- a/test/functional/treesitter/highlight_spec.lua +++ b/test/functional/treesitter/highlight_spec.lua @@ -1008,39 +1008,48 @@ describe('treesitter highlighting (markdown)', function() before_each(function() screen = Screen.new(40, 6) screen:attach() - screen:set_default_attr_ids { - [1] = { foreground = Screen.colors.Blue1 }, - [2] = { bold = true, foreground = Screen.colors.Blue1 }, - [3] = { bold = true, foreground = Screen.colors.Brown }, - [4] = { foreground = Screen.colors.Cyan4 }, - [5] = { foreground = Screen.colors.Magenta1 }, - } + exec_lua([[ + vim.bo.filetype = 'markdown' + vim.treesitter.start() + ]]) end) it('supports hyperlinks', function() local url = 'https://example.com' insert(string.format('[This link text](%s) is a hyperlink.', url)) - exec_lua([[ - vim.bo.filetype = 'markdown' - vim.treesitter.start() - ]]) + screen:add_extra_attr_ids({ + [100] = { foreground = Screen.colors.DarkCyan, url = 'https://example.com' }, + }) + screen:expect({ + grid = [[ + {25:[}{100:This link text}{25:](}{28:https://example.com}{25:)} is| + a hyperlink^. | + {1:~ }|*3 + | + ]], + }) + end) - screen:expect { + it('works with spellchecked and smoothscrolled topline', function() + insert([[ +- $f(0)=\sum_{k=1}^{\infty}\frac{2}{\pi^{2}k^{2}}+\lim_{w \to 0}x$. + +```c +printf('Hello World!'); +``` + ]]) + command('set spell smoothscroll') + feed('gg') + screen:add_extra_attr_ids({ [100] = { undercurl = true, special = Screen.colors.Red } }) + screen:expect({ grid = [[ - {4:[}{6:This link text}{4:](}{7:https://example.com}{4:)} is| - a hyperlink^. | - {2:~ }|*3 - | - ]], - attr_ids = { - [1] = { foreground = Screen.colors.Blue1 }, - [2] = { bold = true, foreground = Screen.colors.Blue1 }, - [3] = { bold = true, foreground = Screen.colors.Brown }, - [4] = { foreground = Screen.colors.Cyan4 }, - [5] = { foreground = Screen.colors.Magenta }, - [6] = { foreground = Screen.colors.Cyan4, url = url }, - [7] = { underline = true, foreground = Screen.colors.SlateBlue }, - }, - } + {1:<<<}k^{2}}+\{100:lim}_{w \to 0}x$^. | + | + {18:```}{15:c} | + {25:printf}{16:(}{26:'Hello World!'}{16:);} | + {18:```} | + | + ]], + }) end) end) -- cgit From c57a85e0eda067ea28ca5853358947332aceecfd Mon Sep 17 00:00:00 2001 From: Riley Bruins Date: Fri, 14 Jun 2024 17:54:10 -0700 Subject: perf(treesitter): remove unnecessary foldexpr loop Instead of looping over all captured nodes, just take the end range from the last node in the list. This uses the fact that nodes returned by iter_matches are ordered by their range (earlier to later). --- test/functional/treesitter/query_spec.lua | 55 +++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) (limited to 'test/functional') diff --git a/test/functional/treesitter/query_spec.lua b/test/functional/treesitter/query_spec.lua index c3a376cd71..2212f787af 100644 --- a/test/functional/treesitter/query_spec.lua +++ b/test/functional/treesitter/query_spec.lua @@ -249,6 +249,61 @@ void ui_refresh(void) }, res) end) + it('returns quantified matches in order of range #29344', function() + insert([[ + int main() { + int a, b, c, d, e, f, g, h, i; + a = MIN(0, 1); + b = MIN(0, 1); + c = MIN(0, 1); + d = MIN(0, 1); + e = MIN(0, 1); + f = MIN(0, 1); + g = MIN(0, 1); + h = MIN(0, 1); + i = MIN(0, 1); + } + ]]) + + local res = exec_lua( + [[ + cquery = vim.treesitter.query.parse("c", ...) + parser = vim.treesitter.get_parser(0, "c") + tree = parser:parse()[1] + res = {} + for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14, { all = true }) do + -- can't transmit node over RPC. just check the name and range + local mrepr = {} + for cid, nodes in pairs(match) do + for _, node in ipairs(nodes) do + table.insert(mrepr, { '@' .. cquery.captures[cid], node:type(), node:range() }) + end + end + table.insert(res, {pattern, mrepr}) + end + return res + ]], + '(expression_statement (assignment_expression (call_expression)))+ @funccall' + ) + + eq({ + { + 1, + { + { '@funccall', 'expression_statement', 2, 2, 2, 16 }, + { '@funccall', 'expression_statement', 3, 2, 3, 16 }, + { '@funccall', 'expression_statement', 4, 2, 4, 16 }, + { '@funccall', 'expression_statement', 5, 2, 5, 16 }, + { '@funccall', 'expression_statement', 6, 2, 6, 16 }, + { '@funccall', 'expression_statement', 7, 2, 7, 16 }, + { '@funccall', 'expression_statement', 8, 2, 8, 16 }, + { '@funccall', 'expression_statement', 9, 2, 9, 16 }, + { '@funccall', 'expression_statement', 10, 2, 10, 16 }, + }, + }, + }, res) + end) + it('can match special regex characters like \\ * + ( with `vim-match?`', function() insert('char* astring = "\\n"; (1 + 1) * 2 != 2;') -- cgit From 5581a95534e44b8714e715c925c9de2d95ae1c21 Mon Sep 17 00:00:00 2001 From: Tom Praschan <13141438+tom-anders@users.noreply.github.com> Date: Mon, 24 Jun 2024 16:54:56 +0200 Subject: feat(lsp): vim.lsp.buf.format() supports textDocument/rangesFormatting #27323 While this relies on a proposed LSP 3.18 feature, it's fully backwards compatible, so IMO there's no harm in adding this already. Looks like some servers already support for this e.g. - gopls: https://go-review.googlesource.com/c/tools/+/510235 - clangd: https://github.com/llvm/llvm-project/pull/80180 Fixes #27293 --- test/functional/fixtures/fake-lsp-server.lua | 42 +++++++++++++++ test/functional/plugin/lsp_spec.lua | 80 ++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+) (limited to 'test/functional') diff --git a/test/functional/fixtures/fake-lsp-server.lua b/test/functional/fixtures/fake-lsp-server.lua index f806869b40..f813927f77 100644 --- a/test/functional/fixtures/fake-lsp-server.lua +++ b/test/functional/fixtures/fake-lsp-server.lua @@ -939,6 +939,48 @@ function tests.basic_formatting() } end +function tests.range_formatting() + skeleton { + on_init = function() + return { + capabilities = { + documentFormattingProvider = true, + documentRangeFormattingProvider = true, + }, + } + end, + body = function() + notify('start') + expect_request('textDocument/rangeFormatting', function() + return nil, {} + end) + notify('shutdown') + end, + } +end + +function tests.ranges_formatting() + skeleton { + on_init = function() + return { + capabilities = { + documentFormattingProvider = true, + documentRangeFormattingProvider = { + rangesSupport = true, + }, + }, + } + end, + body = function() + notify('start') + expect_request('textDocument/rangesFormatting', function() + return nil, {} + end) + notify('shutdown') + end, + } +end + function tests.set_defaults_all_capabilities() skeleton { on_init = function(_) diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index b345a3288c..be303f21ce 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -4537,6 +4537,86 @@ describe('LSP', function() end, } end) + it('Sends textDocument/rangeFormatting request to format a range', function() + local expected_handlers = { + { NIL, {}, { method = 'shutdown', client_id = 1 } }, + { NIL, {}, { method = 'start', client_id = 1 } }, + } + local client + test_rpc_server { + test_name = 'range_formatting', + on_init = function(c) + client = c + end, + on_handler = function(_, _, ctx) + table.remove(expected_handlers) + if ctx.method == 'start' then + local notify_msg = exec_lua([[ + local bufnr = vim.api.nvim_get_current_buf() + vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, {'foo', 'bar'}) + vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID) + local notify_msg + local notify = vim.notify + vim.notify = function(msg, log_level) + notify_msg = msg + end + vim.lsp.buf.format({ bufnr = bufnr, range = { + start = {1, 1}, + ['end'] = {1, 1}, + }}) + vim.notify = notify + return notify_msg + ]]) + eq(NIL, notify_msg) + elseif ctx.method == 'shutdown' then + client.stop() + end + end, + } + end) + it('Sends textDocument/rangesFormatting request to format multiple ranges', function() + local expected_handlers = { + { NIL, {}, { method = 'shutdown', client_id = 1 } }, + { NIL, {}, { method = 'start', client_id = 1 } }, + } + local client + test_rpc_server { + test_name = 'ranges_formatting', + on_init = function(c) + client = c + end, + on_handler = function(_, _, ctx) + table.remove(expected_handlers) + if ctx.method == 'start' then + local notify_msg = exec_lua([[ + local bufnr = vim.api.nvim_get_current_buf() + vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, {'foo', 'bar', 'baz'}) + vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID) + local notify_msg + local notify = vim.notify + vim.notify = function(msg, log_level) + notify_msg = msg + end + vim.lsp.buf.format({ bufnr = bufnr, range = { + { + start = {1, 1}, + ['end'] = {1, 1}, + }, + { + start = {2, 2}, + ['end'] = {2, 2}, + } + }}) + vim.notify = notify + return notify_msg + ]]) + eq(NIL, notify_msg) + elseif ctx.method == 'shutdown' then + client.stop() + end + end, + } + end) it('Can format async', function() local expected_handlers = { { NIL, {}, { method = 'shutdown', client_id = 1 } }, -- cgit From f8795365deb88ab4e108858c563284b1082d06d4 Mon Sep 17 00:00:00 2001 From: Evgeni Chasnovski Date: Fri, 21 Jun 2024 16:23:02 +0300 Subject: test(lua): cover `vim._with()` with tests Problem: `vim._with()` has many different use cases which are not covered with tests. Solution: cover with tests. Some (many) test cases are intentionally marked as "pending" because they cover cases which don't work as expected at the moment (and fixing them requires specific knowledge of C codebase). Use them as a reference for future fixes. Also some of "can be nested" tests currently might pass only because the tested context doesn't work. --- test/functional/lua/with_spec.lua | 1044 +++++++++++++++++++++++++++++-------- 1 file changed, 814 insertions(+), 230 deletions(-) (limited to 'test/functional') diff --git a/test/functional/lua/with_spec.lua b/test/functional/lua/with_spec.lua index 36dee9630a..f93ef6f26b 100644 --- a/test/functional/lua/with_spec.lua +++ b/test/functional/lua/with_spec.lua @@ -7,286 +7,870 @@ local api = n.api local command = n.command local eq = t.eq local exec_lua = n.exec_lua +local exec_capture = n.exec_capture local matches = t.matches local pcall_err = t.pcall_err -before_each(function() - n.clear() -end) +describe('vim._with', function() + before_each(function() + n.clear() + exec_lua([[ + _G.fn = vim.fn + _G.api = vim.api -describe('vim._with {buf = }', function() - it('does not trigger autocmd', function() - exec_lua [[ - local new = vim.api.nvim_create_buf(false, true) - vim.api.nvim_create_autocmd( { 'BufEnter', 'BufLeave', 'BufWinEnter', 'BufWinLeave' }, { - callback = function() _G.n = (_G.n or 0) + 1 end - }) - vim._with({buf = new}, function() - end) - assert(_G.n == nil) - ]] + _G.setup_buffers = function() + return api.nvim_create_buf(false, true), api.nvim_get_current_buf() + end + + _G.setup_windows = function() + local other_win = api.nvim_get_current_win() + vim.cmd.new() + return other_win, api.nvim_get_current_win() + end + ]]) end) - it('trigger autocmd if changed within context', function() - exec_lua [[ - local new = vim.api.nvim_create_buf(false, true) - vim.api.nvim_create_autocmd( { 'BufEnter', 'BufLeave', 'BufWinEnter', 'BufWinLeave' }, { - callback = function() _G.n = (_G.n or 0) + 1 end - }) - vim._with({}, function() - vim.api.nvim_set_current_buf(new) - assert(_G.n ~= nil) + local validate_events_trigger = function() + local out = exec_lua [[ + -- Needs three global values defined: + -- - `test_events` - array of events which are tested. + -- - `test_context` - context to be tested. + -- - `test_trig_event` - callable triggering at least one tested event. + _G.n_events = 0 + local opts = { callback = function() _G.n_events = _G.n_events + 1 end } + api.nvim_create_autocmd(_G.test_events, opts) + + local context = { bo = { commentstring = '-- %s' } } + + -- Should not trigger events on its own + vim._with(_G.test_context, function() end) + local is_no_events = _G.n_events == 0 + + -- Should trigger events if specifically asked inside callback + local is_events = vim._with(_G.test_context, function() + _G.test_trig_event() + return _G.n_events > 0 end) + return { is_no_events, is_events } ]] - end) + eq({ true, true }, out) + end - it('can access buf options', function() - local buf1 = api.nvim_get_current_buf() - local buf2 = exec_lua [[ - buf2 = vim.api.nvim_create_buf(false, true) - return buf2 - ]] + describe('`buf` context', function() + it('works', function() + local out = exec_lua [[ + local other_buf, cur_buf = setup_buffers() + local inner = vim._with({ buf = other_buf }, function() + return api.nvim_get_current_buf() + end) + return { inner == other_buf, api.nvim_get_current_buf() == cur_buf } + ]] + eq({ true, true }, out) + end) + + it('does not trigger events', function() + exec_lua [[ + _G.test_events = { 'BufEnter', 'BufLeave', 'BufWinEnter', 'BufWinLeave' } + _G.test_context = { buf = other_buf } + _G.test_trig_event = function() vim.cmd.new() end + ]] + validate_events_trigger() + end) - eq(false, api.nvim_get_option_value('autoindent', { buf = buf1 })) - eq(false, api.nvim_get_option_value('autoindent', { buf = buf2 })) + it('can access buffer options', function() + local out = exec_lua [[ + other_buf, cur_buf = setup_buffers() + vim.bo[other_buf].commentstring = '## %s' + vim.bo[cur_buf].commentstring = '// %s' - local val = exec_lua [[ - return vim._with({buf = buf2}, function() - vim.cmd "set autoindent" - return vim.api.nvim_get_current_buf() + vim._with({ buf = other_buf }, function() + vim.cmd.set('commentstring=--\\ %s') + end) + + return vim.bo[other_buf].commentstring == '-- %s' and + vim.bo[cur_buf].commentstring == '// %s' + ]] + eq(true, out) end) - ]] - eq(false, api.nvim_get_option_value('autoindent', { buf = buf1 })) - eq(true, api.nvim_get_option_value('autoindent', { buf = buf2 })) - eq(buf1, api.nvim_get_current_buf()) - eq(buf2, val) + it('works with different kinds of buffers', function() + exec_lua [[ + local validate = function(buf) + vim._with({ buf = buf }, function() + assert(api.nvim_get_current_buf() == buf) + end) + end + + -- Current + validate(api.nvim_get_current_buf()) + + -- Hidden listed + local listed = api.nvim_create_buf(true, true) + validate(listed) + + -- Visible + local other_win, cur_win = setup_windows() + api.nvim_win_set_buf(other_win, listed) + validate(listed) + + -- Shown but not visible + vim.cmd.tabnew() + validate(listed) + + -- Shown in several windows + api.nvim_win_set_buf(0, listed) + validate(listed) + + -- Shown in floating window + local float_buf = api.nvim_create_buf(false, true) + local config = { relative = 'editor', row = 1, col = 1, width = 5, height = 5 } + api.nvim_open_win(float_buf, false, config) + validate(float_buf) + ]] + end) + + it('does not cause ml_get errors with invalid visual selection', function() + exec_lua [[ + api.nvim_buf_set_lines(0, 0, -1, true, { 'a', 'b', 'c' }) + api.nvim_feedkeys(vim.keycode('G'), 'txn', false) + local other_buf, _ = setup_buffers() + vim._with({ buf = buf }, function() vim.cmd.redraw() end) + ]] + end) + + it('can be nested', function() + exec_lua [[ + local other_buf, cur_buf = setup_buffers() + vim._with({ buf = other_buf }, function() + assert(api.nvim_get_current_buf() == other_buf) + inner = vim._with({ buf = cur_buf }, function() + assert(api.nvim_get_current_buf() == cur_buf) + end) + assert(api.nvim_get_current_buf() == other_buf) + end) + assert(api.nvim_get_current_buf() == cur_buf) + ]] + end) + + it('can be nested crazily with hidden buffers', function() + local out = exec_lua([[ + local n = 0 + local function with_recursive_nested_bufs() + n = n + 1 + if n > 20 then return true end + + local other_buf, _ = setup_buffers() + vim.bo[other_buf].commentstring = '## %s' + local callback = function() + return api.nvim_get_current_buf() == other_buf + and vim.bo[other_buf].commentstring == '## %s' + and with_recursive_nested_bufs() + end + return vim._with({ buf = other_buf }, callback) and + api.nvim_buf_delete(other_buf, {}) == nil + end + + return with_recursive_nested_bufs() + ]]) + eq(true, out) + end) end) - it('does not cause ml_get errors with invalid visual selection', function() - exec_lua [[ - local api = vim.api - local t = function(s) return api.nvim_replace_termcodes(s, true, true, true) end - api.nvim_buf_set_lines(0, 0, -1, true, {"a", "b", "c"}) - api.nvim_feedkeys(t "G", "txn", false) - vim._with({buf = api.nvim_create_buf(false, true)}, function() vim.cmd "redraw" end) - ]] + describe('`emsg_silent` context', function() + pending('works', function() + local ok = pcall( + exec_lua, + [[ + _G.f = function() + error('This error should not interfer with execution', 0) + end + -- Should not produce error same as `vim.cmd('silent! lua _G.f()')` + vim._with({ emsg_silent = true }, f) + ]] + ) + eq(true, ok) + + -- Should properly report errors afterwards + ok = pcall(exec_lua, 'lua _G.f()') + eq(false, ok) + end) + + it('can be nested', function() + local ok = pcall( + exec_lua, + [[ + _G.f = function() + error('This error should not interfer with execution', 0) + end + -- Should produce error same as `_G.f()` + vim._with({ emsg_silent = true }, function() + vim._with( { emsg_silent = false }, f) + end) + ]] + ) + eq(false, ok) + end) end) - it('can be nested crazily with hidden buffers', function() - eq( - true, - exec_lua([[ - local function scratch_buf_call(fn) - local buf = vim.api.nvim_create_buf(false, true) - vim.api.nvim_set_option_value('cindent', true, {buf = buf}) - return vim._with({buf = buf}, function() - return vim.api.nvim_get_current_buf() == buf - and vim.api.nvim_get_option_value('cindent', {buf = buf}) - and fn() - end) and vim.api.nvim_buf_delete(buf, {}) == nil - end + describe('`hide` context', function() + pending('works', function() + local ok = pcall( + exec_lua, + [[ + vim.o.hidden = false + vim.bo.modified = true + local init_buf = api.nvim_get_current_buf() + -- Should not produce error same as `vim.cmd('hide enew')` + vim._with({ hide = true }, function() + vim.cmd.enew() + end) + assert(api.nvim_get_current_buf() ~= init_buf) + ]] + ) + eq(true, ok) + end) - return scratch_buf_call(function() - return scratch_buf_call(function() - return scratch_buf_call(function() - return scratch_buf_call(function() - return scratch_buf_call(function() - return scratch_buf_call(function() - return scratch_buf_call(function() - return scratch_buf_call(function() - return scratch_buf_call(function() - return scratch_buf_call(function() - return scratch_buf_call(function() - return scratch_buf_call(function() - return true - end) - end) - end) - end) - end) - end) - end) + it('can be nested', function() + local ok = pcall( + exec_lua, + [[ + vim.o.hidden = false + vim.bo.modified = true + -- Should produce error same as `vim.cmd.enew()` + vim._with({ hide = true }, function() + vim._with({ hide = false }, function() + vim.cmd.enew() end) end) - end) - end) + ]] + ) + eq(false, ok) end) - ]]) - ) end) - it('can return values by reference', function() - eq( - { 4, 7 }, + describe('`horizontal` context', function() + local is_approx_eq = function(dim, id_1, id_2) + local f = dim == 'height' and api.nvim_win_get_height or api.nvim_win_get_width + return math.abs(f(id_1) - f(id_2)) <= 1 + end + + local win_id_1, win_id_2, win_id_3 + before_each(function() + win_id_1 = api.nvim_get_current_win() + command('wincmd v | wincmd 5>') + win_id_2 = api.nvim_get_current_win() + command('wincmd s | wincmd 5+') + win_id_3 = api.nvim_get_current_win() + + eq(is_approx_eq('width', win_id_1, win_id_2), false) + eq(is_approx_eq('height', win_id_3, win_id_2), false) + end) + + pending('works', function() exec_lua [[ - local val = {4, 10} - local ref = vim._with({ buf = 0}, function() return val end) - ref[2] = 7 - return val - ]] - ) + -- Should be same as `vim.cmd('horizontal wincmd =')` + vim._with({ horizontal = true }, function() + vim.cmd.wincmd('=') + end) + ]] + eq(is_approx_eq('width', win_id_1, win_id_2), true) + eq(is_approx_eq('height', win_id_3, win_id_2), false) + end) + + pending('can be nested', function() + exec_lua [[ + -- Should be same as `vim.cmd.wincmd('=')` + vim._with({ horizontal = true }, function() + vim._with({ horizontal = false }, function() + vim.cmd.wincmd('=') + end) + end) + ]] + eq(is_approx_eq('width', win_id_1, win_id_2), true) + eq(is_approx_eq('height', win_id_3, win_id_2), true) + end) end) -end) -describe('vim._with {win = }', function() - it('does not trigger autocmd', function() - exec_lua [[ - local old = vim.api.nvim_get_current_win() - vim.cmd("new") - local new = vim.api.nvim_get_current_win() - vim.api.nvim_create_autocmd( { 'WinEnter', 'WinLeave' }, { - callback = function() _G.n = (_G.n or 0) + 1 end - }) - vim._with({win = old}, function() - end) - assert(_G.n == nil) - ]] + describe('`keepalt` context', function() + pending('works', function() + local out = exec_lua [[ + vim.cmd('edit alt') + vim.cmd('edit new') + assert(fn.bufname('#') == 'alt') + + -- Should work as `vim.cmd('keepalt edit very-new')` + vim._with({ keepalt = true }, function() + vim.cmd.edit('very-new') + end) + return fn.bufname('#') == 'alt' + ]] + eq(true, out) + end) + + it('can be nested', function() + local out = exec_lua [[ + vim.cmd('edit alt') + vim.cmd('edit new') + assert(fn.bufname('#') == 'alt') + + -- Should work as `vim.cmd.edit('very-new')` + vim._with({ keepalt = true }, function() + vim._with({ keepalt = false }, function() + vim.cmd.edit('very-new') + end) + end) + return fn.bufname('#') == 'alt' + ]] + eq(false, out) + end) end) - it('trigger autocmd if changed within context', function() - exec_lua [[ - local old = vim.api.nvim_get_current_win() - vim.cmd("new") - local new = vim.api.nvim_get_current_win() - vim.api.nvim_create_autocmd( { 'WinEnter', 'WinLeave' }, { - callback = function() _G.n = (_G.n or 0) + 1 end - }) - vim._with({}, function() - vim.api.nvim_set_current_win(old) - assert(_G.n ~= nil) - end) - ]] + describe('`keepjumps` context', function() + pending('works', function() + local out = exec_lua [[ + api.nvim_buf_set_lines(0, 0, -1, false, { 'aaa', 'bbb', 'ccc' }) + local jumplist_before = fn.getjumplist() + -- Should work as `vim.cmd('keepjumps normal! Ggg')` + vim._with({ keepjumps = true }, function() + vim.cmd('normal! Ggg') + end) + return vim.deep_equal(jumplist_before, fn.getjumplist()) + ]] + eq(true, out) + end) + + it('can be nested', function() + local out = exec_lua [[ + api.nvim_buf_set_lines(0, 0, -1, false, { 'aaa', 'bbb', 'ccc' }) + local jumplist_before = fn.getjumplist() + vim._with({ keepjumps = true }, function() + vim._with({ keepjumps = false }, function() + vim.cmd('normal! Ggg') + end) + end) + return vim.deep_equal(jumplist_before, fn.getjumplist()) + ]] + eq(false, out) + end) end) - it('can access window options', function() - command('vsplit') - local win1 = api.nvim_get_current_win() - command('wincmd w') - local win2 = exec_lua [[ - win2 = vim.api.nvim_get_current_win() - return win2 - ]] - command('wincmd p') + describe('`keepmarks` context', function() + pending('works', function() + local out = exec_lua [[ + vim.cmd('set cpoptions+=R') + api.nvim_buf_set_lines(0, 0, -1, false, { 'bbb', 'ccc', 'aaa' }) + api.nvim_buf_set_mark(0, 'm', 2, 2, {}) - eq('', api.nvim_get_option_value('winhighlight', { win = win1 })) - eq('', api.nvim_get_option_value('winhighlight', { win = win2 })) + -- Should be the same as `vim.cmd('keepmarks %!sort')` + vim._with({ keepmarks = true }, function() + vim.cmd('%!sort') + end) + return api.nvim_buf_get_mark(0, 'm') + ]] + eq({ 2, 2 }, out) + end) - local val = exec_lua [[ - return vim._with({win = win2}, function() - vim.cmd "setlocal winhighlight=Normal:Normal" - return vim.api.nvim_get_current_win() - end) - ]] + it('can be nested', function() + local out = exec_lua [[ + vim.cmd('set cpoptions+=R') + api.nvim_buf_set_lines(0, 0, -1, false, { 'bbb', 'ccc', 'aaa' }) + api.nvim_buf_set_mark(0, 'm', 2, 2, {}) - eq('', api.nvim_get_option_value('winhighlight', { win = win1 })) - eq('Normal:Normal', api.nvim_get_option_value('winhighlight', { win = win2 })) - eq(win1, api.nvim_get_current_win()) - eq(win2, val) + vim._with({ keepmarks = true }, function() + vim._with({ keepmarks = false }, function() + vim.cmd('%!sort') + end) + end) + return api.nvim_buf_get_mark(0, 'm') + ]] + eq({ 0, 2 }, out) + end) end) - it('does not cause ml_get errors with invalid visual selection', function() - -- Add lines to the current buffer and make another window looking into an empty buffer. - exec_lua [[ - _G.api = vim.api - _G.t = function(s) return api.nvim_replace_termcodes(s, true, true, true) end - _G.win_lines = api.nvim_get_current_win() - vim.cmd "new" - _G.win_empty = api.nvim_get_current_win() - api.nvim_set_current_win(win_lines) - api.nvim_buf_set_lines(0, 0, -1, true, {"a", "b", "c"}) - ]] + describe('`keepatterns` context', function() + pending('works', function() + local out = exec_lua [[ + api.nvim_buf_set_lines(0, 0, -1, false, { 'aaa', 'bbb' }) + vim.cmd('/aaa') + -- Should be the same as `vim.cmd('keeppatterns /bbb')` + vim._with({ keeppatterns = true }, function() + vim.cmd('/bbb') + end) + return fn.getreg('/') + ]] + eq('aaa', out) + end) - -- Start Visual in current window, redraw in other window with fewer lines. - exec_lua [[ - api.nvim_feedkeys(t "G", "txn", false) - vim._with({win = win_empty}, function() vim.cmd "redraw" end) - ]] + it('can be nested', function() + local out = exec_lua [[ + api.nvim_buf_set_lines(0, 0, -1, false, { 'aaa', 'bbb' }) + vim.cmd('/aaa') + vim._with({ keeppatterns = true }, function() + vim._with({ keeppatterns = false }, function() + vim.cmd('/bbb') + end) + end) + return fn.getreg('/') + ]] + eq('bbb', out) + end) + end) - -- Start Visual in current window, extend it in other window with more lines. - exec_lua [[ - api.nvim_feedkeys(t "gg", "txn", false) - api.nvim_set_current_win(win_empty) - api.nvim_feedkeys(t "gg", "txn", false) - vim._with({win = win_lines}, function() api.nvim_feedkeys(t "G", "txn", false) end) - vim.cmd "redraw" - ]] + describe('`lockmarks` context', function() + it('works', function() + local mark = exec_lua [[ + api.nvim_buf_set_lines(0, 0, 0, false, { 'aaa', 'bbb', 'ccc' }) + api.nvim_buf_set_mark(0, 'm', 2, 2, {}) + -- Should be same as `:lockmarks lua api.nvim_buf_set_lines(...)` + vim._with({ lockmarks = true }, function() + api.nvim_buf_set_lines(0, 0, 2, false, { 'uuu', 'vvv', 'www' }) + end) + return api.nvim_buf_get_mark(0, 'm') + ]] + eq({ 2, 2 }, mark) + end) + + it('can be nested', function() + local mark = exec_lua [[ + api.nvim_buf_set_lines(0, 0, 0, false, { 'aaa', 'bbb', 'ccc' }) + api.nvim_buf_set_mark(0, 'm', 2, 2, {}) + vim._with({ lockmarks = true }, function() + vim._with({ lockmarks = false }, function() + api.nvim_buf_set_lines(0, 0, 2, false, { 'uuu', 'vvv', 'www' }) + end) + end) + return api.nvim_buf_get_mark(0, 'm') + ]] + eq({ 0, 2 }, mark) + end) end) - it('updates ruler if cursor moved', function() - local screen = Screen.new(30, 5) - screen:set_default_attr_ids { - [1] = { reverse = true }, - [2] = { bold = true, reverse = true }, - } - screen:attach() - exec_lua [[ - _G.api = vim.api - vim.opt.ruler = true - local lines = {} - for i = 0, 499 do lines[#lines + 1] = tostring(i) end - api.nvim_buf_set_lines(0, 0, -1, true, lines) - api.nvim_win_set_cursor(0, {20, 0}) - vim.cmd "split" - _G.win = api.nvim_get_current_win() - vim.cmd "wincmd w | redraw" - ]] - screen:expect [[ - 19 | - {1:[No Name] [+] 20,1 3%}| - ^19 | - {2:[No Name] [+] 20,1 3%}| - | - ]] - exec_lua [[ - vim._with({win = win}, function() api.nvim_win_set_cursor(0, {100, 0}) end) - vim.cmd "redraw" - ]] - screen:expect [[ - 99 | - {1:[No Name] [+] 100,1 19%}| - ^19 | - {2:[No Name] [+] 20,1 3%}| - | + describe('`noautocmd` context', function() + it('works', function() + local out = exec_lua [[ + _G.n_events = 0 + vim.cmd('au ModeChanged * lua _G.n_events = _G.n_events + 1') + -- Should be the same as `vim.cmd('noautocmd normal! vv')` + vim._with({ noautocmd = true }, function() + vim.cmd('normal! vv') + end) + return _G.n_events + ]] + eq(0, out) + end) + + it('works with User events', function() + local out = exec_lua [[ + _G.n_events = 0 + vim.cmd('au User MyEvent lua _G.n_events = _G.n_events + 1') + -- Should be the same as `vim.cmd('noautocmd doautocmd User MyEvent')` + vim._with({ noautocmd = true }, function() + api.nvim_exec_autocmds('User', { pattern = 'MyEvent' }) + end) + return _G.n_events + ]] + eq(0, out) + end) + + pending('can be nested', function() + local out = exec_lua [[ + _G.n_events = 0 + vim.cmd('au ModeChanged * lua _G.n_events = _G.n_events + 1') + vim._with({ noautocmd = true }, function() + vim._with({ noautocmd = false }, function() + vim.cmd('normal! vv') + end) + end) + return _G.n_events + ]] + eq(2, out) + end) + end) + + describe('`sandbox` context', function() + it('works', function() + local ok, err = pcall( + exec_lua, + [[ + -- Should work as `vim.cmd('sandbox call append(0, "aaa")')` + vim._with({ sandbox = true }, function() + fn.append(0, 'aaa') + end) + ]] + ) + eq(false, ok) + matches('Not allowed in sandbox', err) + end) + + it('can NOT be nested', function() + -- This behavior is intentionally different from other flags as allowing + -- disabling `sandbox` from nested function seems to be against the point + -- of using `sandbox` context in the first place + local ok, err = pcall( + exec_lua, + [[ + vim._with({ sandbox = true }, function() + vim._with({ sandbox = false }, function() + fn.append(0, 'aaa') + end) + end) + ]] + ) + eq(false, ok) + matches('Not allowed in sandbox', err) + end) + end) + + describe('`silent` context', function() + it('works', function() + exec_lua [[ + -- Should be same as `vim.cmd('silent lua print("aaa")')` + vim._with({ silent = true }, function() print('aaa') end) + ]] + eq('', exec_capture('messages')) + + exec_lua [[ vim._with({ silent = true }, function() vim.cmd.echomsg('"bbb"') end) ]] + eq('', exec_capture('messages')) + + local screen = Screen.new(20, 5) + screen:set_default_attr_ids { + [1] = { bold = true, reverse = true }, + [2] = { bold = true, foreground = Screen.colors.Blue }, + } + screen:attach() + exec_lua [[ vim._with({ silent = true }, function() vim.cmd.echo('"ccc"') end) ]] + screen:expect [[ + ^ | + {2:~ }|*3 + | + ]] + end) + + pending('can be nested', function() + exec_lua [[ vim._with({ silent = true }, function() + vim._with({ silent = false }, function() + print('aaa') + end) + end)]] + eq('aaa', exec_capture('messages')) + end) + end) + + describe('`unsilent` context', function() + it('works', function() + exec_lua [[ + _G.f = function() + -- Should be same as `vim.cmd('unsilent lua print("aaa")')` + vim._with({ unsilent = true }, function() print('aaa') end) + end + ]] + command('silent lua f()') + eq('aaa', exec_capture('messages')) + end) + + pending('can be nested', function() + exec_lua [[ + _G.f = function() + vim._with({ unsilent = true }, function() + vim._with({ unsilent = false }, function() print('aaa') end) + end) + end + ]] + command('silent lua f()') + eq('', exec_capture('messages')) + end) + end) + + describe('`win` context', function() + it('works', function() + local out = exec_lua [[ + local other_win, cur_win = setup_windows() + local inner = vim._with({ win = other_win }, function() + return api.nvim_get_current_win() + end) + return { inner == other_win, api.nvim_get_current_win() == cur_win } + ]] + eq({ true, true }, out) + end) + + it('does not trigger events', function() + exec_lua [[ + _G.test_events = { 'WinEnter', 'WinLeave', 'BufWinEnter', 'BufWinLeave' } + _G.test_context = { win = other_win } + _G.test_trig_event = function() vim.cmd.new() end + ]] + validate_events_trigger() + end) + + it('can access window options', function() + local out = exec_lua [[ + local other_win, cur_win = setup_windows() + vim.wo[other_win].winblend = 10 + vim.wo[cur_win].winblend = 25 + + vim._with({ win = other_win }, function() + vim.cmd.setlocal('winblend=0') + end) + + return vim.wo[other_win].winblend == 0 and vim.wo[cur_win].winblend == 25 + ]] + eq(true, out) + end) + + it('works with different kinds of windows', function() + exec_lua [[ + local validate = function(win) + vim._with({ win = win }, function() + assert(api.nvim_get_current_win() == win) + end) + end + + -- Current + validate(api.nvim_get_current_win()) + + -- Not visible + local other_win, cur_win = setup_windows() + vim.cmd.tabnew() + validate(other_win) + + -- Floating + local float_win = api.nvim_open_win( + api.nvim_create_buf(false, true), + false, + { relative = 'editor', row = 1, col = 1, height = 5, width = 5} + ) + validate(float_win) + ]] + end) + + it('does not cause ml_get errors with invalid visual selection', function() + exec_lua [[ + local feedkeys = function(keys) api.nvim_feedkeys(vim.keycode(keys), 'txn', false) end + + -- Add lines to the current buffer and make another window looking into an empty buffer. + local win_empty, win_lines = setup_windows() + api.nvim_buf_set_lines(0, 0, -1, true, { 'a', 'b', 'c' }) + + -- Start Visual in current window, redraw in other window with fewer lines. + -- Should be fixed by vim-patch:8.2.4018. + feedkeys('G') + vim._with({ win = win_empty }, function() vim.cmd.redraw() end) + + -- Start Visual in current window, extend it in other window with more lines. + -- Fixed for win_execute by vim-patch:8.2.4026, but nvim_win_call should also not be affected. + feedkeys('gg') + api.nvim_set_current_win(win_empty) + feedkeys('gg') + vim._with({ win = win_lines }, function() feedkeys('G') end) + vim.cmd.redraw() + ]] + end) + + it('can be nested', function() + exec_lua [[ + local other_win, cur_win = setup_windows() + vim._with({ win = other_win }, function() + assert(api.nvim_get_current_win() == other_win) + inner = vim._with({ win = cur_win }, function() + assert(api.nvim_get_current_win() == cur_win) + end) + assert(api.nvim_get_current_win() == other_win) + end) + assert(api.nvim_get_current_win() == cur_win) + ]] + end) + + it('updates ruler if cursor moved', function() + local screen = Screen.new(30, 5) + screen:set_default_attr_ids { + [1] = { reverse = true }, + [2] = { bold = true, reverse = true }, + } + screen:attach() + exec_lua [[ + vim.opt.ruler = true + local lines = {} + for i = 0, 499 do lines[#lines + 1] = tostring(i) end + api.nvim_buf_set_lines(0, 0, -1, true, lines) + api.nvim_win_set_cursor(0, { 20, 0 }) + vim.cmd 'split' + _G.win = api.nvim_get_current_win() + vim.cmd "wincmd w | redraw" + ]] + screen:expect [[ + 19 | + {1:[No Name] [+] 20,1 3%}| + ^19 | + {2:[No Name] [+] 20,1 3%}| + | + ]] + exec_lua [[ + vim._with({ win = win }, function() api.nvim_win_set_cursor(0, { 100, 0 }) end) + vim.cmd "redraw" + ]] + screen:expect [[ + 99 | + {1:[No Name] [+] 100,1 19%}| + ^19 | + {2:[No Name] [+] 20,1 3%}| + | + ]] + end) + + it('layout in current tabpage does not affect windows in others', function() + command('tab split') + local t2_move_win = api.nvim_get_current_win() + command('vsplit') + local t2_other_win = api.nvim_get_current_win() + command('tabprevious') + matches('E36: Not enough room$', pcall_err(command, 'execute "split|"->repeat(&lines)')) + command('vsplit') + + exec_lua('vim._with({ win = ... }, function() vim.cmd.wincmd "J" end)', t2_move_win) + eq({ 'col', { { 'leaf', t2_other_win }, { 'leaf', t2_move_win } } }, fn.winlayout(2)) + end) + end) + + it('returns what callback returns', function() + local out_verify = exec_lua [[ + out = { vim._with({}, function() + return 'a', 2, nil, { 4 }, function() end + end) } + return { + out[1] == 'a', out[2] == 2, out[3] == nil, + vim.deep_equal(out[4], { 4 }), + type(out[5]) == 'function', + vim.tbl_count(out), + } ]] + eq({ true, true, true, true, true, 4 }, out_verify) end) it('can return values by reference', function() - eq( - { 7, 10 }, - exec_lua [[ - local val = {4, 10} - local ref = vim._with({win = 0}, function() return val end) + local out = exec_lua [[ + local val = { 4, 10 } + local ref = vim._with({}, function() return val end) ref[1] = 7 return val ]] - ) + eq({ 7, 10 }, out) end) - it('layout in current tabpage does not affect windows in others', function() - command('tab split') - local t2_move_win = api.nvim_get_current_win() - command('vsplit') - local t2_other_win = api.nvim_get_current_win() - command('tabprevious') - matches('E36: Not enough room$', pcall_err(command, 'execute "split|"->repeat(&lines)')) - command('vsplit') - - exec_lua('vim._with({win = ...}, function() vim.cmd.wincmd "J" end)', t2_move_win) - eq({ 'col', { { 'leaf', t2_other_win }, { 'leaf', t2_move_win } } }, fn.winlayout(2)) + it('can not work with conflicting `buf` and `win`', function() + local out = exec_lua [[ + local other_buf, cur_buf = setup_buffers() + local other_win, cur_win = setup_windows() + assert(api.nvim_win_get_buf(other_win) ~= other_buf) + local _, err = pcall(vim._with, { buf = other_buf, win = other_win }, function() end) + return err + ]] + matches('Can not set both `buf` and `win`', out) end) -end) -describe('vim._with {lockmarks = true}', function() - it('is reset', function() - local mark = exec_lua [[ - vim.api.nvim_buf_set_lines(0, 0, 0, false, {"marky", "snarky", "malarkey"}) - vim.api.nvim_buf_set_mark(0,"m",1,0, {}) - vim._with({lockmarks = true}, function() - vim.api.nvim_buf_set_lines(0, 0, 2, false, {"mass", "mess", "moss"}) - end) - return vim.api.nvim_buf_get_mark(0,"m") + pending('can forward command modifiers to user command', function() + local out = exec_lua [[ + local test_flags = { + 'emsg_silent', + 'hide', + 'keepalt', + 'keepjumps', + 'keepmarks', + 'keeppatterns', + 'lockmarks', + 'noautocmd', + 'silent', + 'unsilent', + } + + local used_smods + local command = function(data) + used_smods = data.smods + end + api.nvim_create_user_command('DummyLog', command, {}) + + local res = {} + for _, flag in ipairs(test_flags) do + used_smods = nil + vim._with({ [flag] = true }, function() vim.cmd('DummyLog') end) + res[flag] = used_smods[flag] + end + return res ]] - t.eq(mark, { 1, 0 }) + for k, v in pairs(out) do + eq({ k, true }, { k, v }) + end + end) + + it('handles error in callback', function() + -- Should still restore initial context + local out_buf = exec_lua [[ + local other_buf, cur_buf = setup_buffers() + + local context = { buf = other_buf } + local ok, err = pcall(vim._with, context, function() error('Oops buf', 0) end) + + return { + ok, + err, + api.nvim_get_current_buf() == cur_buf, + } + ]] + eq({ false, 'Oops buf', true }, out_buf) + + local out_win = exec_lua [[ + local other_win, cur_win = setup_windows() + vim.wo[other_win].winblend = 25 + + local context = { win = other_win, wo = { winblend = 50 } } + local ok, err = pcall(vim._with, context, function() error('Oops win', 0) end) + + return { + ok, + err, + api.nvim_get_current_win() == cur_win, + vim.wo[other_win].winblend, + } + ]] + eq({ false, 'Oops win', true, 25 }, out_win) + end) + + it('validates arguments', function() + exec_lua [[ + _G.get_error = function(...) + local _, err = pcall(vim._with, ...) + return err or '' + end + ]] + local get_error = function(string_args) + return exec_lua('return get_error(' .. string_args .. ')') + end + + matches('context.*table', get_error("'a', function() end")) + matches('f.*function', get_error('{}, 1')) + + local validate_context = function(bad_context, expected_type) + local bad_field = vim.tbl_keys(bad_context)[1] + matches( + 'context%.' .. bad_field .. '.*' .. expected_type, + get_error(vim.inspect(bad_context) .. ', function() end') + ) + end + + validate_context({ buf = 'a' }, 'number') + validate_context({ emsg_silent = 1 }, 'boolean') + validate_context({ hide = 1 }, 'boolean') + validate_context({ keepalt = 1 }, 'boolean') + validate_context({ keepjumps = 1 }, 'boolean') + validate_context({ keepmarks = 1 }, 'boolean') + validate_context({ keeppatterns = 1 }, 'boolean') + validate_context({ lockmarks = 1 }, 'boolean') + validate_context({ noautocmd = 1 }, 'boolean') + validate_context({ sandbox = 1 }, 'boolean') + validate_context({ silent = 1 }, 'boolean') + validate_context({ unsilent = 1 }, 'boolean') + validate_context({ win = 'a' }, 'number') + + matches('Invalid buffer', get_error('{ buf = -1 }, function() end')) + matches('Invalid window', get_error('{ win = -1 }, function() end')) end) end) -- cgit From 07cc559cdf11acb3031b6b7ba53e65285a6f4b3f Mon Sep 17 00:00:00 2001 From: Evgeni Chasnovski Date: Fri, 21 Jun 2024 16:23:05 +0300 Subject: feat(lua): update `vim._with` to allow more granular option contexts Problem: with a single `context.options` there is no way for user to force which scope (local, global, both) is being temporarily set and later restored. Solution: replace single `options` context with `bo`, `go`, `wo`, and `o`. Naming and implementation follows how options can be set directly with `vim.*` (like `vim.bo`, etc.). Options are set for possible target `win` or `buf` context. --- test/functional/lua/with_spec.lua | 751 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 721 insertions(+), 30 deletions(-) (limited to 'test/functional') diff --git a/test/functional/lua/with_spec.lua b/test/functional/lua/with_spec.lua index f93ef6f26b..aa2f4bb7f5 100644 --- a/test/functional/lua/with_spec.lua +++ b/test/functional/lua/with_spec.lua @@ -30,7 +30,7 @@ describe('vim._with', function() ]]) end) - local validate_events_trigger = function() + local assert_events_trigger = function() local out = exec_lua [[ -- Needs three global values defined: -- - `test_events` - array of events which are tested. @@ -56,6 +56,132 @@ describe('vim._with', function() eq({ true, true }, out) end + describe('`bo` context', function() + before_each(function() + exec_lua [[ + _G.other_buf, _G.cur_buf = setup_buffers() + + -- 'commentstring' is local to buffer and string + vim.bo[other_buf].commentstring = '## %s' + vim.bo[cur_buf].commentstring = '// %s' + vim.go.commentstring = '$$ %s' + + -- 'undolevels' is global or local to buffer (global-local) and number + vim.bo[other_buf].undolevels = 100 + vim.bo[cur_buf].undolevels = 250 + vim.go.undolevels = 500 + + _G.get_state = function() + return { + bo = { + cms_cur = vim.bo[cur_buf].commentstring, + cms_other = vim.bo[other_buf].commentstring, + ul_cur = vim.bo[cur_buf].undolevels, + ul_other = vim.bo[other_buf].undolevels, + }, + go = { + cms = vim.go.commentstring, + ul = vim.go.undolevels, + }, + } + end + ]] + end) + + it('works', function() + local out = exec_lua [[ + local context = { bo = { commentstring = '-- %s', undolevels = 0 } } + + local before = get_state() + local inner = vim._with(context, function() + assert(api.nvim_get_current_buf() == cur_buf) + return get_state() + end) + + return { before = before, inner = inner, after = get_state() } + ]] + + eq({ + bo = { cms_cur = '-- %s', cms_other = '## %s', ul_cur = 0, ul_other = 100 }, + go = { cms = '$$ %s', ul = 500 }, + }, out.inner) + eq(out.before, out.after) + end) + + it('sets options in `buf` context', function() + local out = exec_lua [[ + local context = { buf = other_buf, bo = { commentstring = '-- %s', undolevels = 0 } } + + local before = get_state() + local inner = vim._with(context, function() + assert(api.nvim_get_current_buf() == other_buf) + return get_state() + end) + + return { before = before, inner = inner, after = get_state() } + ]] + + eq({ + bo = { cms_cur = '// %s', cms_other = '-- %s', ul_cur = 250, ul_other = 0 }, + go = { cms = '$$ %s', ul = 500 }, + }, out.inner) + eq(out.before, out.after) + end) + + it('restores only options from context', function() + local out = exec_lua [[ + local context = { bo = { commentstring = '-- %s' } } + + local inner = vim._with(context, function() + assert(api.nvim_get_current_buf() == cur_buf) + vim.bo[cur_buf].undolevels = 750 + vim.bo[cur_buf].commentstring = '!! %s' + return get_state() + end) + + return { inner = inner, after = get_state() } + ]] + + eq({ + bo = { cms_cur = '!! %s', cms_other = '## %s', ul_cur = 750, ul_other = 100 }, + go = { cms = '$$ %s', ul = 500 }, + }, out.inner) + eq({ + bo = { cms_cur = '// %s', cms_other = '## %s', ul_cur = 750, ul_other = 100 }, + go = { cms = '$$ %s', ul = 500 }, + }, out.after) + end) + + it('does not trigger events', function() + exec_lua [[ + _G.test_events = { 'BufEnter', 'BufLeave', 'BufWinEnter', 'BufWinLeave' } + _G.test_context = { bo = { commentstring = '-- %s' } } + _G.test_trig_event = function() vim.cmd.new() end + ]] + assert_events_trigger() + end) + + it('can be nested', function() + local out = exec_lua [[ + local before, before_inner, after_inner = get_state(), nil, nil + vim._with({ bo = { commentstring = '-- %s', undolevels = 0 } }, function() + before_inner = get_state() + inner = vim._with({ bo = { commentstring = '!! %s' } }, get_state) + after_inner = get_state() + end) + return { + before = before, before_inner = before_inner, + inner = inner, + after_inner = after_inner, after = get_state(), + } + ]] + eq('!! %s', out.inner.bo.cms_cur) + eq(0, out.inner.bo.ul_cur) + eq(out.before_inner, out.after_inner) + eq(out.before, out.after) + end) + end) + describe('`buf` context', function() it('works', function() local out = exec_lua [[ @@ -74,7 +200,7 @@ describe('vim._with', function() _G.test_context = { buf = other_buf } _G.test_trig_event = function() vim.cmd.new() end ]] - validate_events_trigger() + assert_events_trigger() end) it('can access buffer options', function() @@ -95,37 +221,37 @@ describe('vim._with', function() it('works with different kinds of buffers', function() exec_lua [[ - local validate = function(buf) + local assert_buf = function(buf) vim._with({ buf = buf }, function() assert(api.nvim_get_current_buf() == buf) end) end -- Current - validate(api.nvim_get_current_buf()) + assert_buf(api.nvim_get_current_buf()) -- Hidden listed local listed = api.nvim_create_buf(true, true) - validate(listed) + assert_buf(listed) -- Visible local other_win, cur_win = setup_windows() api.nvim_win_set_buf(other_win, listed) - validate(listed) + assert_buf(listed) -- Shown but not visible vim.cmd.tabnew() - validate(listed) + assert_buf(listed) -- Shown in several windows api.nvim_win_set_buf(0, listed) - validate(listed) + assert_buf(listed) -- Shown in floating window local float_buf = api.nvim_create_buf(false, true) local config = { relative = 'editor', row = 1, col = 1, width = 5, height = 5 } api.nvim_open_win(float_buf, false, config) - validate(float_buf) + assert_buf(float_buf) ]] end) @@ -212,6 +338,118 @@ describe('vim._with', function() end) end) + describe('`go` context', function() + before_each(function() + exec_lua [[ + vim.bo.commentstring = '## %s' + vim.go.commentstring = '$$ %s' + vim.wo.winblend = 25 + vim.go.winblend = 50 + vim.go.langmap = 'xy,yx' + + _G.get_state = function() + return { + bo = { cms = vim.bo.commentstring }, + wo = { winbl = vim.wo.winblend }, + go = { + cms = vim.go.commentstring, + winbl = vim.go.winblend, + lmap = vim.go.langmap, + }, + } + end + ]] + end) + + it('works', function() + local out = exec_lua [[ + local context = { + go = { commentstring = '-- %s', winblend = 75, langmap = 'ab,ba' }, + } + local before = get_state() + local inner = vim._with(context, get_state) + return { before = before, inner = inner, after = get_state() } + ]] + + eq({ + bo = { cms = '## %s' }, + wo = { winbl = 25 }, + go = { cms = '-- %s', winbl = 75, lmap = 'ab,ba' }, + }, out.inner) + eq(out.before, out.after) + end) + + it('works with `eventignore`', function() + -- This might be an issue if saving and restoring option context is done + -- to account for triggering `OptionSet`, but in not a good way + local out = exec_lua [[ + vim.go.eventignore = 'ModeChanged' + local inner = vim._with({ go = { eventignore = 'CursorMoved' } }, function() + return vim.go.eventignore + end) + return { inner = inner, after = vim.go.eventignore } + ]] + eq({ inner = 'CursorMoved', after = 'ModeChanged' }, out) + end) + + it('restores only options from context', function() + local out = exec_lua [[ + local context = { go = { langmap = 'ab,ba' } } + + local inner = vim._with(context, function() + vim.go.commentstring = '!! %s' + vim.go.winblend = 75 + vim.go.langmap = 'uv,vu' + return get_state() + end) + + return { inner = inner, after = get_state() } + ]] + + eq({ + bo = { cms = '## %s' }, + wo = { winbl = 25 }, + go = { cms = '!! %s', winbl = 75, lmap = 'uv,vu' }, + }, out.inner) + eq({ + bo = { cms = '## %s' }, + wo = { winbl = 25 }, + go = { cms = '!! %s', winbl = 75, lmap = 'xy,yx' }, + }, out.after) + end) + + it('does not trigger events', function() + exec_lua [[ + _G.test_events = { + 'BufEnter', 'BufLeave', 'BufWinEnter', 'BufWinLeave', 'WinEnter', 'WinLeave' + } + _G.test_context = { go = { commentstring = '-- %s', winblend = 75, langmap = 'ab,ba' } } + _G.test_trig_event = function() vim.cmd.new() end + ]] + assert_events_trigger() + end) + + it('can be nested', function() + local out = exec_lua [[ + local before, before_inner, after_inner = get_state(), nil, nil + vim._with({ go = { langmap = 'ab,ba', commentstring = '-- %s' } }, function() + before_inner = get_state() + inner = vim._with({ go = { langmap = 'uv,vu' } }, get_state) + after_inner = get_state() + end) + return { + before = before, before_inner = before_inner, + inner = inner, + after_inner = after_inner, after = get_state(), + } + ]] + eq('uv,vu', out.inner.go.lmap) + eq('-- %s', out.inner.go.cms) + eq(out.before_inner, out.after_inner) + eq(out.before, out.after) + end) + end) + describe('`hide` context', function() pending('works', function() local ok = pcall( @@ -487,6 +725,202 @@ describe('vim._with', function() end) end) + describe('`o` context', function() + before_each(function() + exec_lua [[ + _G.other_win, _G.cur_win = setup_windows() + _G.other_buf, _G.cur_buf = setup_buffers() + + vim.bo[other_buf].commentstring = '## %s' + vim.bo[cur_buf].commentstring = '// %s' + vim.go.commentstring = '$$ %s' + + vim.bo[other_buf].undolevels = 100 + vim.bo[cur_buf].undolevels = 250 + vim.go.undolevels = 500 + + vim.wo[other_win].virtualedit = 'block' + vim.wo[cur_win].virtualedit = 'insert' + vim.go.virtualedit = 'none' + + vim.wo[other_win].winblend = 10 + vim.wo[cur_win].winblend = 25 + vim.go.winblend = 50 + + vim.go.langmap = 'xy,yx' + + _G.get_state = function() + return { + bo = { + cms_cur = vim.bo[cur_buf].commentstring, + cms_other = vim.bo[other_buf].commentstring, + ul_cur = vim.bo[cur_buf].undolevels, + ul_other = vim.bo[other_buf].undolevels, + }, + wo = { + ve_cur = vim.wo[cur_win].virtualedit, + ve_other = vim.wo[other_win].virtualedit, + winbl_cur = vim.wo[cur_win].winblend, + winbl_other = vim.wo[other_win].winblend, + }, + go = { + cms = vim.go.commentstring, + ul = vim.go.undolevels, + ve = vim.go.virtualedit, + winbl = vim.go.winblend, + lmap = vim.go.langmap, + }, + } + end + ]] + end) + + it('works', function() + local out = exec_lua [[ + local context = { + o = { + commentstring = '-- %s', + undolevels = 0, + virtualedit = 'all', + winblend = 75, + langmap = 'ab,ba', + }, + } + + local before = get_state() + local inner = vim._with(context, function() + assert(api.nvim_get_current_buf() == cur_buf) + assert(api.nvim_get_current_win() == cur_win) + return get_state() + end) + + return { before = before, inner = inner, after = get_state() } + ]] + + -- Options in context are set with `vim.o`, so usually both local + -- and global values are affected. Yet all of them should be later + -- restored to pre-context values. + eq({ + bo = { cms_cur = '-- %s', cms_other = '## %s', ul_cur = -123456, ul_other = 100 }, + wo = { ve_cur = 'all', ve_other = 'block', winbl_cur = 75, winbl_other = 10 }, + go = { cms = '-- %s', ul = 0, ve = 'all', winbl = 75, lmap = 'ab,ba' }, + }, out.inner) + eq(out.before, out.after) + end) + + it('sets options in `buf` context', function() + local out = exec_lua [[ + local context = { buf = other_buf, o = { commentstring = '-- %s', undolevels = 0 } } + + local before = get_state() + local inner = vim._with(context, function() + assert(api.nvim_get_current_buf() == other_buf) + return get_state() + end) + + return { before = before, inner = inner, after = get_state() } + ]] + + eq({ + bo = { cms_cur = '// %s', cms_other = '-- %s', ul_cur = 250, ul_other = -123456 }, + wo = { ve_cur = 'insert', ve_other = 'block', winbl_cur = 25, winbl_other = 10 }, + -- Global `winbl` inside context ideally should be untouched and equal + -- to 50. It seems to be equal to 0 because `context.buf` uses + -- `aucmd_prepbuf` C approach which has no guarantees about window or + -- window option values inside context. + go = { cms = '-- %s', ul = 0, ve = 'none', winbl = 0, lmap = 'xy,yx' }, + }, out.inner) + eq(out.before, out.after) + end) + + it('sets options in `win` context', function() + local out = exec_lua [[ + local context = { win = other_win, o = { winblend = 75, virtualedit = 'all' } } + + local before = get_state() + local inner = vim._with(context, function() + assert(api.nvim_get_current_win() == other_win) + return get_state() + end) + + return { before = before, inner = inner, after = get_state() } + ]] + + eq({ + bo = { cms_cur = '// %s', cms_other = '## %s', ul_cur = 250, ul_other = 100 }, + wo = { winbl_cur = 25, winbl_other = 75, ve_cur = 'insert', ve_other = 'all' }, + go = { cms = '$$ %s', ul = 500, winbl = 75, ve = 'all', lmap = 'xy,yx' }, + }, out.inner) + eq(out.before, out.after) + end) + + it('restores only options from context', function() + local out = exec_lua [[ + local context = { o = { undolevels = 0, winblend = 75, langmap = 'ab,ba' } } + + local inner = vim._with(context, function() + assert(api.nvim_get_current_buf() == cur_buf) + assert(api.nvim_get_current_win() == cur_win) + + vim.o.commentstring = '!! %s' + vim.o.undolevels = 750 + vim.o.virtualedit = 'onemore' + vim.o.winblend = 99 + vim.o.langmap = 'uv,vu' + return get_state() + end) + + return { inner = inner, after = get_state() } + ]] + + eq({ + bo = { cms_cur = '!! %s', cms_other = '## %s', ul_cur = -123456, ul_other = 100 }, + wo = { ve_cur = 'onemore', ve_other = 'block', winbl_cur = 99, winbl_other = 10 }, + go = { cms = '!! %s', ul = 750, ve = 'onemore', winbl = 99, lmap = 'uv,vu' }, + }, out.inner) + eq({ + bo = { cms_cur = '!! %s', cms_other = '## %s', ul_cur = 250, ul_other = 100 }, + wo = { ve_cur = 'onemore', ve_other = 'block', winbl_cur = 25, winbl_other = 10 }, + go = { cms = '!! %s', ul = 500, ve = 'onemore', winbl = 50, lmap = 'xy,yx' }, + }, out.after) + end) + + it('does not trigger events', function() + exec_lua [[ + _G.test_events = { + 'BufEnter', 'BufLeave', 'WinEnter', 'WinLeave', 'BufWinEnter', 'BufWinLeave' + } + _G.test_context = { o = { undolevels = 0, winblend = 75, langmap = 'ab,ba' } } + _G.test_trig_event = function() vim.cmd.new() end + ]] + assert_events_trigger() + end) + + it('can be nested', function() + local out = exec_lua [[ + local before, before_inner, after_inner = get_state(), nil, nil + local cxt_o = { commentstring = '-- %s', winblend = 75, langmap = 'ab,ba', undolevels = 0 } + vim._with({ o = cxt_o }, function() + before_inner = get_state() + local inner_cxt_o = { commentstring = '!! %s', winblend = 99, langmap = 'uv,vu' } + inner = vim._with({ o = inner_cxt_o }, get_state) + after_inner = get_state() + end) + return { + before = before, before_inner = before_inner, + inner = inner, + after_inner = after_inner, after = get_state(), + } + ]] + eq('!! %s', out.inner.bo.cms_cur) + eq(99, out.inner.wo.winbl_cur) + eq('uv,vu', out.inner.go.lmap) + eq(0, out.inner.go.ul) + eq(out.before_inner, out.after_inner) + eq(out.before, out.after) + end) + end) + describe('`sandbox` context', function() it('works', function() local ok, err = pcall( @@ -599,7 +1033,7 @@ describe('vim._with', function() _G.test_context = { win = other_win } _G.test_trig_event = function() vim.cmd.new() end ]] - validate_events_trigger() + assert_events_trigger() end) it('can access window options', function() @@ -619,19 +1053,19 @@ describe('vim._with', function() it('works with different kinds of windows', function() exec_lua [[ - local validate = function(win) + local assert_win = function(win) vim._with({ win = win }, function() assert(api.nvim_get_current_win() == win) end) end -- Current - validate(api.nvim_get_current_win()) + assert_win(api.nvim_get_current_win()) -- Not visible local other_win, cur_win = setup_windows() vim.cmd.tabnew() - validate(other_win) + assert_win(other_win) -- Floating local float_win = api.nvim_open_win( @@ -639,7 +1073,7 @@ describe('vim._with', function() false, { relative = 'editor', row = 1, col = 1, height = 5, width = 5} ) - validate(float_win) + assert_win(float_win) ]] end) @@ -731,6 +1165,132 @@ describe('vim._with', function() end) end) + describe('`wo` context', function() + before_each(function() + exec_lua [[ + _G.other_win, _G.cur_win = setup_windows() + + -- 'virtualedit' is global or local to window (global-local) and string + vim.wo[other_win].virtualedit = 'block' + vim.wo[cur_win].virtualedit = 'insert' + vim.go.virtualedit = 'none' + + -- 'winblend' is local to window and number + vim.wo[other_win].winblend = 10 + vim.wo[cur_win].winblend = 25 + vim.go.winblend = 50 + + _G.get_state = function() + return { + wo = { + ve_cur = vim.wo[cur_win].virtualedit, + ve_other = vim.wo[other_win].virtualedit, + winbl_cur = vim.wo[cur_win].winblend, + winbl_other = vim.wo[other_win].winblend, + }, + go = { + ve = vim.go.virtualedit, + winbl = vim.go.winblend, + }, + } + end + ]] + end) + + it('works', function() + local out = exec_lua [[ + local context = { wo = { virtualedit = 'all', winblend = 75 } } + + local before = get_state() + local inner = vim._with(context, function() + assert(api.nvim_get_current_win() == cur_win) + return get_state() + end) + + return { before = before, inner = inner, after = get_state() } + ]] + + eq({ + wo = { ve_cur = 'all', ve_other = 'block', winbl_cur = 75, winbl_other = 10 }, + go = { ve = 'none', winbl = 75 }, + }, out.inner) + eq(out.before, out.after) + end) + + it('sets options in `win` context', function() + local out = exec_lua [[ + local context = { win = other_win, wo = { virtualedit = 'all', winblend = 75 } } + + local before = get_state() + local inner = vim._with(context, function() + assert(api.nvim_get_current_win() == other_win) + return get_state() + end) + + return { before = before, inner = inner, after = get_state() } + ]] + + eq({ + wo = { ve_cur = 'insert', ve_other = 'all', winbl_cur = 25, winbl_other = 75 }, + go = { ve = 'none', winbl = 75 }, + }, out.inner) + eq(out.before, out.after) + end) + + it('restores only options from context', function() + local out = exec_lua [[ + local context = { wo = { winblend = 75 } } + + local inner = vim._with(context, function() + assert(api.nvim_get_current_win() == cur_win) + vim.wo[cur_win].virtualedit = 'onemore' + vim.wo[cur_win].winblend = 99 + return get_state() + end) + + return { inner = inner, after = get_state() } + ]] + + eq({ + wo = { ve_cur = 'onemore', ve_other = 'block', winbl_cur = 99, winbl_other = 10 }, + go = { ve = 'none', winbl = 99 }, + }, out.inner) + eq({ + wo = { ve_cur = 'onemore', ve_other = 'block', winbl_cur = 25, winbl_other = 10 }, + go = { ve = 'none', winbl = 50 }, + }, out.after) + end) + + it('does not trigger events', function() + exec_lua [[ + _G.test_events = { 'WinEnter', 'WinLeave', 'BufWinEnter', 'BufWinLeave' } + _G.test_context = { wo = { winblend = 75 } } + _G.test_trig_event = function() vim.cmd.new() end + ]] + assert_events_trigger() + end) + + it('can be nested', function() + local out = exec_lua [[ + local before, before_inner, after_inner = get_state(), nil, nil + vim._with({ wo = { winblend = 75, virtualedit = 'all' } }, function() + before_inner = get_state() + inner = vim._with({ wo = { winblend = 99 } }, get_state) + after_inner = get_state() + end) + return { + before = before, before_inner = before_inner, + inner = inner, + after_inner = after_inner, after = get_state(), + } + ]] + eq(99, out.inner.wo.winbl_cur) + eq('all', out.inner.wo.ve_cur) + eq(out.before_inner, out.after_inner) + eq(out.before, out.after) + end) + end) + it('returns what callback returns', function() local out_verify = exec_lua [[ out = { vim._with({}, function() @@ -767,6 +1327,116 @@ describe('vim._with', function() matches('Can not set both `buf` and `win`', out) end) + it('works with several contexts at once', function() + local out = exec_lua [[ + local other_buf, cur_buf = setup_buffers() + vim.bo[other_buf].commentstring = '## %s' + api.nvim_buf_set_lines(other_buf, 0, -1, false, { 'aaa', 'bbb', 'ccc' }) + api.nvim_buf_set_mark(other_buf, 'm', 2, 2, {}) + + vim.go.commentstring = '// %s' + vim.go.langmap = 'xy,yx' + + local context = { + buf = other_buf, + bo = { commentstring = '-- %s' }, + go = { langmap = 'ab,ba' }, + lockmarks = true, + } + + local inner = vim._with(context, function() + api.nvim_buf_set_lines(0, 0, -1, false, { 'uuu', 'vvv', 'www' }) + return { + buf = api.nvim_get_current_buf(), + bo = { cms = vim.bo.commentstring }, + go = { cms = vim.go.commentstring, lmap = vim.go.langmap }, + mark = api.nvim_buf_get_mark(0, 'm') + } + end) + + local after = { + buf = api.nvim_get_current_buf(), + bo = { cms = vim.bo[other_buf].commentstring }, + go = { cms = vim.go.commentstring, lmap = vim.go.langmap }, + mark = api.nvim_buf_get_mark(other_buf, 'm') + } + + return { + context_buf = other_buf, cur_buf = cur_buf, + inner = inner, after = after + } + ]] + + eq({ + buf = out.context_buf, + bo = { cms = '-- %s' }, + go = { cms = '// %s', lmap = 'ab,ba' }, + mark = { 2, 2 }, + }, out.inner) + eq({ + buf = out.cur_buf, + bo = { cms = '## %s' }, + go = { cms = '// %s', lmap = 'xy,yx' }, + mark = { 2, 2 }, + }, out.after) + end) + + it('works with same option set in different contexts', function() + local out = exec_lua [[ + local get_state = function() + return { + bo = { cms = vim.bo.commentstring }, + wo = { ve = vim.wo.virtualedit }, + go = { cms = vim.go.commentstring, ve = vim.go.virtualedit }, + } + end + + vim.bo.commentstring = '// %s' + vim.go.commentstring = '$$ %s' + vim.wo.virtualedit = 'insert' + vim.go.virtualedit = 'none' + + local before = get_state() + local context_no_go = { + o = { commentstring = '-- %s', virtualedit = 'all' }, + bo = { commentstring = '!! %s' }, + wo = { virtualedit = 'onemore' }, + } + local inner_no_go = vim._with(context_no_go, get_state) + local middle = get_state() + local context_with_go = { + o = { commentstring = '-- %s', virtualedit = 'all' }, + bo = { commentstring = '!! %s' }, + wo = { virtualedit = 'onemore' }, + go = { commentstring = '@@ %s', virtualedit = 'block' }, + } + local inner_with_go = vim._with(context_with_go, get_state) + return { + before = before, + inner_no_go = inner_no_go, + middle = middle, + inner_with_go = inner_with_go, + after = get_state(), + } + ]] + + -- Should prefer explicit local scopes instead of `o` + eq({ + bo = { cms = '!! %s' }, + wo = { ve = 'onemore' }, + go = { cms = '-- %s', ve = 'all' }, + }, out.inner_no_go) + eq(out.before, out.middle) + + -- Should prefer explicit global scopes instead of `o` + eq({ + bo = { cms = '!! %s' }, + wo = { ve = 'onemore' }, + go = { cms = '@@ %s', ve = 'block' }, + }, out.inner_with_go) + eq(out.middle, out.after) + end) + pending('can forward command modifiers to user command', function() local out = exec_lua [[ local test_flags = { @@ -805,17 +1475,19 @@ describe('vim._with', function() -- Should still restore initial context local out_buf = exec_lua [[ local other_buf, cur_buf = setup_buffers() + vim.bo[other_buf].commentstring = '## %s' - local context = { buf = other_buf } + local context = { buf = other_buf, bo = { commentstring = '-- %s' } } local ok, err = pcall(vim._with, context, function() error('Oops buf', 0) end) return { ok, err, api.nvim_get_current_buf() == cur_buf, + vim.bo[other_buf].commentstring, } ]] - eq({ false, 'Oops buf', true }, out_buf) + eq({ false, 'Oops buf', true, '## %s' }, out_buf) local out_win = exec_lua [[ local other_win, cur_win = setup_windows() @@ -834,6 +1506,21 @@ describe('vim._with', function() eq({ false, 'Oops win', true, 25 }, out_win) end) + it('handles not supported option', function() + local out = exec_lua [[ + -- Should still restore initial state + vim.bo.commentstring = '## %s' + + local context = { o = { commentstring = '-- %s' }, bo = { winblend = 10 } } + local ok, err = pcall(vim._with, context, function() end) + + return { ok = ok, err = err, cms = vim.bo.commentstring } + ]] + eq(false, out.ok) + matches('window.*option.*winblend', out.err) + eq('## %s', out.cms) + end) + it('validates arguments', function() exec_lua [[ _G.get_error = function(...) @@ -848,7 +1535,7 @@ describe('vim._with', function() matches('context.*table', get_error("'a', function() end")) matches('f.*function', get_error('{}, 1')) - local validate_context = function(bad_context, expected_type) + local assert_context = function(bad_context, expected_type) local bad_field = vim.tbl_keys(bad_context)[1] matches( 'context%.' .. bad_field .. '.*' .. expected_type, @@ -856,19 +1543,23 @@ describe('vim._with', function() ) end - validate_context({ buf = 'a' }, 'number') - validate_context({ emsg_silent = 1 }, 'boolean') - validate_context({ hide = 1 }, 'boolean') - validate_context({ keepalt = 1 }, 'boolean') - validate_context({ keepjumps = 1 }, 'boolean') - validate_context({ keepmarks = 1 }, 'boolean') - validate_context({ keeppatterns = 1 }, 'boolean') - validate_context({ lockmarks = 1 }, 'boolean') - validate_context({ noautocmd = 1 }, 'boolean') - validate_context({ sandbox = 1 }, 'boolean') - validate_context({ silent = 1 }, 'boolean') - validate_context({ unsilent = 1 }, 'boolean') - validate_context({ win = 'a' }, 'number') + assert_context({ bo = 1 }, 'table') + assert_context({ buf = 'a' }, 'number') + assert_context({ emsg_silent = 1 }, 'boolean') + assert_context({ go = 1 }, 'table') + assert_context({ hide = 1 }, 'boolean') + assert_context({ keepalt = 1 }, 'boolean') + assert_context({ keepjumps = 1 }, 'boolean') + assert_context({ keepmarks = 1 }, 'boolean') + assert_context({ keeppatterns = 1 }, 'boolean') + assert_context({ lockmarks = 1 }, 'boolean') + assert_context({ noautocmd = 1 }, 'boolean') + assert_context({ o = 1 }, 'table') + assert_context({ sandbox = 1 }, 'boolean') + assert_context({ silent = 1 }, 'boolean') + assert_context({ unsilent = 1 }, 'boolean') + assert_context({ win = 'a' }, 'number') + assert_context({ wo = 1 }, 'table') matches('Invalid buffer', get_error('{ buf = -1 }, function() end')) matches('Invalid window', get_error('{ win = -1 }, function() end')) -- cgit From cd53db2157f0cd27877451a6b00d66e9bed74e73 Mon Sep 17 00:00:00 2001 From: Evgeni Chasnovski Date: Sun, 23 Jun 2024 17:13:06 +0300 Subject: feat(lua): add `context.env` (environment variables) to `vim._with()` --- test/functional/lua/with_spec.lua | 59 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) (limited to 'test/functional') diff --git a/test/functional/lua/with_spec.lua b/test/functional/lua/with_spec.lua index aa2f4bb7f5..99b80ef749 100644 --- a/test/functional/lua/with_spec.lua +++ b/test/functional/lua/with_spec.lua @@ -338,6 +338,64 @@ describe('vim._with', function() end) end) + describe('`env` context', function() + before_each(function() + exec_lua [[ + vim.fn.setenv('aaa', 'hello') + _G.get_state = function() + return { aaa = vim.fn.getenv('aaa'), bbb = vim.fn.getenv('bbb') } + end + ]] + end) + + it('works', function() + local out = exec_lua [[ + local context = { env = { aaa = 'inside', bbb = 'wow' } } + local before = get_state() + local inner = vim._with(context, get_state) + return { before = before, inner = inner, after = get_state() } + ]] + + eq({ aaa = 'inside', bbb = 'wow' }, out.inner) + eq(out.before, out.after) + end) + + it('restores only variables from context', function() + local out = exec_lua [[ + local context = { env = { bbb = 'wow' } } + local before = get_state() + local inner = vim._with(context, function() + vim.env.aaa = 'inside' + return get_state() + end) + return { before = before, inner = inner, after = get_state() } + ]] + + eq({ aaa = 'inside', bbb = 'wow' }, out.inner) + eq({ aaa = 'inside', bbb = vim.NIL }, out.after) + end) + + it('can be nested', function() + local out = exec_lua [[ + local before, before_inner, after_inner = get_state(), nil, nil + vim._with({ env = { aaa = 'inside', bbb = 'wow' } }, function() + before_inner = get_state() + inner = vim._with({ env = { aaa = 'more inside' } }, get_state) + after_inner = get_state() + end) + return { + before = before, before_inner = before_inner, + inner = inner, + after_inner = after_inner, after = get_state(), + } + ]] + eq('more inside', out.inner.aaa) + eq('wow', out.inner.bbb) + eq(out.before_inner, out.after_inner) + eq(out.before, out.after) + end) + end) + describe('`go` context', function() before_each(function() exec_lua [[ @@ -1546,6 +1604,7 @@ describe('vim._with', function() assert_context({ bo = 1 }, 'table') assert_context({ buf = 'a' }, 'number') assert_context({ emsg_silent = 1 }, 'boolean') + assert_context({ env = 1 }, 'table') assert_context({ go = 1 }, 'table') assert_context({ hide = 1 }, 'boolean') assert_context({ keepalt = 1 }, 'boolean') -- cgit From bda63d5b97dfb333de6f4bd757dbb978906062a2 Mon Sep 17 00:00:00 2001 From: bfredl Date: Tue, 25 Jun 2024 15:33:47 +0200 Subject: refactor(typval)!: remove distinction of binary and nonbinary strings This is a breaking change which will make refactor of typval and shada code a lot easier. In particular, code that would use or check for v:msgpack_types.binary in the wild would be broken. This appears to be rarely used in existing plugins. Also some cases where v:msgpack_type.string would be used to represent a binary string of "string" type, we use a BLOB instead, which is vimscripts native type for binary blobs, and already was used for BIN formats when necessary. msgpackdump(msgpackparse(data)) no longer preserves the distinction of BIN and STR strings. This is very common behavior for language-specific msgpack bindings. Nvim uses msgpack as a tool to serialize its data. Nvim is not a tool to bit-perfectly manipulate arbitrary msgpack data out in the wild. The changed tests should indicate how behavior changes in various edge cases. --- test/functional/api/vim_spec.lua | 4 +- test/functional/lua/luaeval_spec.lua | 12 ++-- test/functional/plugin/msgpack_spec.lua | 65 ++++-------------- test/functional/plugin/shada_spec.lua | 77 +++++++++++----------- test/functional/vimscript/json_functions_spec.lua | 32 ++------- .../vimscript/msgpack_functions_spec.lua | 29 ++++---- 6 files changed, 75 insertions(+), 144 deletions(-) (limited to 'test/functional') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index d28064447c..86ea8679b5 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -1571,9 +1571,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) diff --git a/test/functional/lua/luaeval_spec.lua b/test/functional/lua/luaeval_spec.lua index 3f62cd8325..2f137e280c 100644 --- a/test/functional/lua/luaeval_spec.lua +++ b/test/functional/lua/luaeval_spec.lua @@ -72,9 +72,9 @@ describe('luaeval()', function() end) it('are successfully converted to special dictionaries in table keys', function() command([[let d = luaeval('{["\0"]=1}')]]) - eq({_TYPE={}, _VAL={{{_TYPE={}, _VAL={'\n'}}, 1}}}, api.nvim_get_var('d')) + eq({_TYPE={}, _VAL={{'\000', 1}}}, api.nvim_get_var('d')) eq(1, fn.eval('d._TYPE is v:msgpack_types.map')) - eq(1, fn.eval('d._VAL[0][0]._TYPE is v:msgpack_types.string')) + eq(eval('v:t_blob'), fn.eval('type(d._VAL[0][0])')) end) it('are successfully converted to blobs from a list', function() command([[let l = luaeval('{"abc", "a\0b", "c\0d", "def"}')]]) @@ -125,11 +125,11 @@ describe('luaeval()', function() local level = 30 eq(nested_by_level[level].o, fn.luaeval(nested_by_level[level].s)) - eq({_TYPE={}, _VAL={{{_TYPE={}, _VAL={'\n', '\n'}}, '\000\n\000\000'}}}, + eq({_TYPE={}, _VAL={{'\000\n\000', '\000\n\000\000'}}}, fn.luaeval([[{['\0\n\0']='\0\n\0\0'}]])) eq(1, eval([[luaeval('{["\0\n\0"]="\0\n\0\0"}')._TYPE is v:msgpack_types.map]])) - eq(1, eval([[luaeval('{["\0\n\0"]="\0\n\0\0"}')._VAL[0][0]._TYPE is v:msgpack_types.string]])) - eq({nested={{_TYPE={}, _VAL={{{_TYPE={}, _VAL={'\n', '\n'}}, '\000\n\000\000'}}}}}, + eq(eval("v:t_blob"), eval([[type(luaeval('{["\0\n\0"]="\0\n\0\0"}')._VAL[0][0])]])) + eq({nested={{_TYPE={}, _VAL={{'\000\n\000', '\000\n\000\000'}}}}}, fn.luaeval([[{nested={{['\0\n\0']='\0\n\0\0'}}}]])) end) @@ -177,12 +177,10 @@ describe('luaeval()', function() end it('correctly passes special dictionaries', function() - eq({0, '\000\n\000'}, luaevalarg(sp('binary', '["\\n", "\\n"]'))) eq({0, '\000\n\000'}, luaevalarg(sp('string', '["\\n", "\\n"]'))) eq({0, true}, luaevalarg(sp('boolean', 1))) eq({0, false}, luaevalarg(sp('boolean', 0))) eq({0, NIL}, luaevalarg(sp('nil', 0))) - eq({0, {[""]=""}}, luaevalarg(mapsp(sp('binary', '[""]'), '""'))) eq({0, {[""]=""}}, luaevalarg(mapsp(sp('string', '[""]'), '""'))) end) diff --git a/test/functional/plugin/msgpack_spec.lua b/test/functional/plugin/msgpack_spec.lua index 1d5d20ec02..61ab730da8 100644 --- a/test/functional/plugin/msgpack_spec.lua +++ b/test/functional/plugin/msgpack_spec.lua @@ -58,23 +58,11 @@ describe('autoload/msgpack.vim', function() msgpack_eq(1, '"abc\\ndef"', '"abc\\ndef"') msgpack_eq(0, '"abc\\ndef"', '"abc\\nghi"') end) - it('compares binary specials correctly', function() - msgpack_eq(1, sp('binary', '["abc\\n", "def"]'), sp('binary', '["abc\\n", "def"]')) - msgpack_eq(0, sp('binary', '["abc", "def"]'), sp('binary', '["abc\\n", "def"]')) - end) - it('compares binary specials with raw binaries correctly', function() - msgpack_eq(1, sp('binary', '["abc", "def"]'), '"abc\\ndef"') - msgpack_eq(0, sp('binary', '["abc", "def"]'), '"abcdef"') - end) it('compares string specials correctly', function() msgpack_eq(1, sp('string', '["abc\\n", "def"]'), sp('string', '["abc\\n", "def"]')) msgpack_eq(0, sp('string', '["abc", "def"]'), sp('string', '["abc\\n", "def"]')) - end) - it('compares string specials with binary correctly', function() - msgpack_eq(0, sp('string', '["abc\\n", "def"]'), sp('binary', '["abc\\n", "def"]')) - msgpack_eq(0, sp('string', '["abc", "def"]'), '"abc\\ndef"') - msgpack_eq(0, sp('binary', '["abc\\n", "def"]'), sp('string', '["abc\\n", "def"]')) - msgpack_eq(0, '"abc\\ndef"', sp('string', '["abc", "def"]')) + msgpack_eq(1, sp('string', '["abc", "def"]'), '"abc\\ndef"') + msgpack_eq(1, '"abc\\ndef"', sp('string', '["abc", "def"]')) end) it('compares ext specials correctly', function() msgpack_eq(1, sp('ext', '[1, ["", "ac"]]'), sp('ext', '[1, ["", "ac"]]')) @@ -92,20 +80,16 @@ describe('autoload/msgpack.vim', function() end) it('compares map specials correctly', function() msgpack_eq(1, mapsp(), mapsp()) - msgpack_eq(1, mapsp(sp('binary', '[""]'), '""'), mapsp(sp('binary', '[""]'), '""')) msgpack_eq( 1, mapsp(mapsp('1', '1'), mapsp('1', '1')), mapsp(mapsp('1', '1'), mapsp('1', '1')) ) msgpack_eq(0, mapsp(), mapsp('1', '1')) - msgpack_eq(0, mapsp(sp('binary', '["a"]'), '""'), mapsp(sp('binary', '[""]'), '""')) - msgpack_eq(0, mapsp(sp('binary', '[""]'), '"a"'), mapsp(sp('binary', '[""]'), '""')) - msgpack_eq(0, mapsp(sp('binary', '["a"]'), '"a"'), mapsp(sp('binary', '[""]'), '""')) msgpack_eq( 0, mapsp(mapsp('1', '1'), mapsp('1', '1')), - mapsp(sp('binary', '[""]'), mapsp('1', '1')) + mapsp(sp('string', '[""]'), mapsp('1', '1')) ) msgpack_eq( 0, @@ -138,7 +122,7 @@ describe('autoload/msgpack.vim', function() msgpack_eq(1, mapsp(sp('string', '["1"]'), '1'), '{"1": 1}') msgpack_eq(1, mapsp(sp('string', '["1"]'), sp('integer', '[1, 0, 0, 1]')), '{"1": 1}') msgpack_eq(0, mapsp(sp('integer', '[1, 0, 0, 1]'), sp('string', '["1"]')), '{1: "1"}') - msgpack_eq(0, mapsp('"1"', sp('integer', '[1, 0, 0, 1]')), '{"1": 1}') + msgpack_eq(1, mapsp('"1"', sp('integer', '[1, 0, 0, 1]')), '{"1": 1}') msgpack_eq(0, mapsp(sp('string', '["1"]'), '1', sp('string', '["2"]'), '2'), '{"1": 1}') msgpack_eq(0, mapsp(sp('string', '["1"]'), '1'), '{"1": 1, "2": 2}') end) @@ -290,7 +274,6 @@ describe('autoload/msgpack.vim', function() it('works for special dictionaries', function() type_eq('string', sp('string', '[""]')) - type_eq('binary', sp('binary', '[""]')) type_eq('ext', sp('ext', '[1, [""]]')) type_eq('array', sp('array', '[]')) type_eq('map', sp('map', '[]')) @@ -301,7 +284,7 @@ describe('autoload/msgpack.vim', function() end) it('works for regular values', function() - type_eq('binary', '""') + type_eq('string', '""') type_eq('array', '[]') type_eq('map', '{}') type_eq('integer', '1') @@ -319,7 +302,6 @@ describe('autoload/msgpack.vim', function() it('works for special dictionaries', function() sp_type_eq('string', sp('string', '[""]')) - sp_type_eq('binary', sp('binary', '[""]')) sp_type_eq('ext', sp('ext', '[1, [""]]')) sp_type_eq('array', sp('array', '[]')) sp_type_eq('map', sp('map', '[]')) @@ -347,12 +329,9 @@ describe('autoload/msgpack.vim', function() end it('works for special dictionaries', function() - string_eq('=""', sp('string', '[""]')) - string_eq('="\\n"', sp('string', '["", ""]')) - string_eq('="ab\\0c\\nde"', sp('string', '["ab\\nc", "de"]')) - string_eq('""', sp('binary', '[""]')) - string_eq('"\\n"', sp('binary', '["", ""]')) - string_eq('"ab\\0c\\nde"', sp('binary', '["ab\\nc", "de"]')) + string_eq('""', sp('string', '[""]')) + string_eq('"\\n"', sp('string', '["", ""]')) + string_eq('"ab\\0c\\nde"', sp('string', '["ab\\nc", "de"]')) string_eq('+(2)""', sp('ext', '[2, [""]]')) string_eq('+(2)"\\n"', sp('ext', '[2, ["", ""]]')) string_eq('+(2)"ab\\0c\\nde"', sp('ext', '[2, ["ab\\nc", "de"]]')) @@ -397,8 +376,8 @@ describe('autoload/msgpack.vim', function() string_eq('[]', '[]') string_eq('[[[{}]]]', '[[[{}]]]') string_eq('{}', '{}') - string_eq('{="2": 10}', '{2: 10}') - string_eq('{="2": [{}]}', '{2: [{}]}') + string_eq('{"2": 10}', '{2: 10}') + string_eq('{"2": [{}]}', '{2: [{}]}') string_eq('1', '1') string_eq('0.0', '0.0') string_eq('inf', '(1.0/0.0)') @@ -422,7 +401,6 @@ describe('autoload/msgpack.vim', function() nvim_command('let spflt = ' .. sp('float', '1.0')) nvim_command('let spext = ' .. sp('ext', '[2, ["abc", "def"]]')) nvim_command('let spstr = ' .. sp('string', '["abc", "def"]')) - nvim_command('let spbin = ' .. sp('binary', '["abc", "def"]')) nvim_command('let spbln = ' .. sp('boolean', '0')) nvim_command('let spnil = ' .. sp('nil', '0')) @@ -432,7 +410,6 @@ describe('autoload/msgpack.vim', function() nvim_command('let spflt2 = msgpack#deepcopy(spflt)') nvim_command('let spext2 = msgpack#deepcopy(spext)') nvim_command('let spstr2 = msgpack#deepcopy(spstr)') - nvim_command('let spbin2 = msgpack#deepcopy(spbin)') nvim_command('let spbln2 = msgpack#deepcopy(spbln)') nvim_command('let spnil2 = msgpack#deepcopy(spnil)') @@ -442,7 +419,6 @@ describe('autoload/msgpack.vim', function() eq('float', nvim_eval('msgpack#type(spflt2)')) eq('ext', nvim_eval('msgpack#type(spext2)')) eq('string', nvim_eval('msgpack#type(spstr2)')) - eq('binary', nvim_eval('msgpack#type(spbin2)')) eq('boolean', nvim_eval('msgpack#type(spbln2)')) eq('nil', nvim_eval('msgpack#type(spnil2)')) @@ -457,7 +433,6 @@ describe('autoload/msgpack.vim', function() nvim_command('let spext._VAL[0] = 3') nvim_command('let spext._VAL[1][0] = "gh"') nvim_command('let spstr._VAL[0] = "gh"') - nvim_command('let spbin._VAL[0] = "gh"') nvim_command('let spbln._VAL = 1') nvim_command('let spnil._VAL = 1') @@ -467,7 +442,6 @@ describe('autoload/msgpack.vim', function() eq({ _TYPE = {}, _VAL = 1.0 }, nvim_eval('spflt2')) eq({ _TYPE = {}, _VAL = { 2, { 'abc', 'def' } } }, nvim_eval('spext2')) eq({ _TYPE = {}, _VAL = { 'abc', 'def' } }, nvim_eval('spstr2')) - eq({ _TYPE = {}, _VAL = { 'abc', 'def' } }, nvim_eval('spbin2')) eq({ _TYPE = {}, _VAL = 0 }, nvim_eval('spbln2')) eq({ _TYPE = {}, _VAL = 0 }, nvim_eval('spnil2')) @@ -477,7 +451,6 @@ describe('autoload/msgpack.vim', function() nvim_command('let spflt._TYPE = []') nvim_command('let spext._TYPE = []') nvim_command('let spstr._TYPE = []') - nvim_command('let spbin._TYPE = []') nvim_command('let spbln._TYPE = []') nvim_command('let spnil._TYPE = []') @@ -487,7 +460,6 @@ describe('autoload/msgpack.vim', function() eq('float', nvim_eval('msgpack#special_type(spflt2)')) eq('ext', nvim_eval('msgpack#special_type(spext2)')) eq('string', nvim_eval('msgpack#special_type(spstr2)')) - eq('binary', nvim_eval('msgpack#special_type(spbin2)')) eq('boolean', nvim_eval('msgpack#special_type(spbln2)')) eq('nil', nvim_eval('msgpack#special_type(spnil2)')) end) @@ -509,7 +481,7 @@ describe('autoload/msgpack.vim', function() eq('map', nvim_eval('msgpack#type(map2)')) eq('integer', nvim_eval('msgpack#type(int2)')) eq('float', nvim_eval('msgpack#type(flt2)')) - eq('binary', nvim_eval('msgpack#type(bin2)')) + eq('string', nvim_eval('msgpack#type(bin2)')) nvim_command('call add(arr, 0)') nvim_command('call add(arr[0], 0)') @@ -566,21 +538,6 @@ describe('autoload/msgpack.vim', function() nvim_command('unlet g:__val') end - it('correctly loads binary strings', function() - eval_eq('binary', { 'abcdef' }, '"abcdef"') - eval_eq('binary', { 'abc', 'def' }, '"abc\\ndef"') - eval_eq('binary', { 'abc\ndef' }, '"abc\\0def"') - eval_eq('binary', { '\nabc\ndef\n' }, '"\\0abc\\0def\\0"') - eval_eq('binary', { 'abc\n\n\ndef' }, '"abc\\0\\0\\0def"') - eval_eq('binary', { 'abc\n', '\ndef' }, '"abc\\0\\n\\0def"') - eval_eq('binary', { 'abc', '', '', 'def' }, '"abc\\n\\n\\ndef"') - eval_eq('binary', { 'abc', '', '', 'def', '' }, '"abc\\n\\n\\ndef\\n"') - eval_eq('binary', { '', 'abc', '', '', 'def' }, '"\\nabc\\n\\n\\ndef"') - eval_eq('binary', { '' }, '""') - eval_eq('binary', { '"' }, '"\\""') - eval_eq('binary', { 'py3 print(sys.version_info)' }, '"py3 print(sys.version_info)"') - end) - it('correctly loads strings', function() eval_eq('string', { 'abcdef' }, '="abcdef"') eval_eq('string', { 'abc', 'def' }, '="abc\\ndef"') diff --git a/test/functional/plugin/shada_spec.lua b/test/functional/plugin/shada_spec.lua index 1c2bcbd497..c9d49f7d01 100644 --- a/test/functional/plugin/shada_spec.lua +++ b/test/functional/plugin/shada_spec.lua @@ -68,7 +68,7 @@ describe('autoload/shada.vim', function() endfor return ret elseif type(a:val) == type('') - return {'_TYPE': v:msgpack_types.binary, '_VAL': split(a:val, "\n", 1)} + return {'_TYPE': v:msgpack_types.string, '_VAL': split(a:val, "\n", 1)} else return a:val endif @@ -253,8 +253,7 @@ describe('autoload/shada.vim', function() ' + sm magic value "TRUE"', ' # Expected integer', ' + so offset value "TRUE"', - ' # Expected binary string', - ' + sp pattern ="abc"', + ' + sp pattern "abc"', }, ([[ [{'type': 1, 'timestamp': 0, 'data': { 'sm': 'TRUE', @@ -267,7 +266,7 @@ describe('autoload/shada.vim', function() 'n': -0x40, 'l': -10, 'c': 'abc', - 'f': {'_TYPE': v:msgpack_types.binary, '_VAL': ["abc\ndef"]}, + 'f': {'_TYPE': v:msgpack_types.string, '_VAL': ["abc\ndef"]}, }}] ]]):gsub('\n', '') ) sd2strings_eq( @@ -276,15 +275,14 @@ describe('autoload/shada.vim', function() ' % Key Description Value', ' # Expected no NUL bytes', ' + f file name "abc\\0def"', - ' # Expected array of binary strings', - ' + rc contents ["abc", ="abc"]', + ' + rc contents ["abc", "abc"]', ' # Expected integer', ' + rt type "ABC"', }, ([[ [{'type': 1, 'timestamp': 0, 'data': { 'rt': 'ABC', 'rc': ["abc", {'_TYPE': v:msgpack_types.string, '_VAL': ["abc"]}], - 'f': {'_TYPE': v:msgpack_types.binary, '_VAL': ["abc\ndef"]}, + 'f': {'_TYPE': v:msgpack_types.string, '_VAL': ["abc\ndef"]}, }}] ]]):gsub('\n', '') ) sd2strings_eq( @@ -295,7 +293,7 @@ describe('autoload/shada.vim', function() ' + rc contents ["abc", "a\\nd\\0"]', }, ([[ [{'type': 1, 'timestamp': 0, 'data': { - 'rc': ["abc", {'_TYPE': v:msgpack_types.binary, '_VAL': ["a", "d\n"]}], + 'rc': ["abc", {'_TYPE': v:msgpack_types.string, '_VAL': ["a", "d\n"]}], }}] ]]):gsub('\n', '') ) end) @@ -468,7 +466,7 @@ describe('autoload/shada.vim', function() sd2strings_eq({ 'Replacement string with timestamp ' .. epoch .. ':', ' # Unexpected type: map instead of array', - ' = {="a": [10]}', + ' = {"a": [10]}', }, { { type = 3, timestamp = 0, data = { a = { 10 } } } }) sd2strings_eq( { @@ -498,7 +496,7 @@ describe('autoload/shada.vim', function() ' - :s replacement string "abc\\0def"', }, ([[ [{'type': 3, 'timestamp': 0, 'data': [ - {'_TYPE': v:msgpack_types.binary, '_VAL': ["abc\ndef"]}, + {'_TYPE': v:msgpack_types.string, '_VAL': ["abc\ndef"]}, ]}] ]]):gsub('\n', '') ) sd2strings_eq( @@ -508,7 +506,7 @@ describe('autoload/shada.vim', function() ' - :s replacement string "abc\\ndef"', }, ([[ [{'type': 3, 'timestamp': 0, 'data': [ - {'_TYPE': v:msgpack_types.binary, '_VAL': ["abc", "def"]}, + {'_TYPE': v:msgpack_types.string, '_VAL': ["abc", "def"]}, ]}] ]]):gsub('\n', '') ) sd2strings_eq( @@ -519,7 +517,7 @@ describe('autoload/shada.vim', function() ' - 0', }, ([[ [{'type': 3, 'timestamp': 0, 'data': [ - {'_TYPE': v:msgpack_types.binary, '_VAL': ["abc", "def"]}, + {'_TYPE': v:msgpack_types.string, '_VAL': ["abc", "def"]}, 0, ]}] ]]):gsub('\n', '') ) @@ -529,7 +527,7 @@ describe('autoload/shada.vim', function() sd2strings_eq({ 'History entry with timestamp ' .. epoch .. ':', ' # Unexpected type: map instead of array', - ' = {="a": [10]}', + ' = {"a": [10]}', }, { { type = 4, timestamp = 0, data = { a = { 10 } } } }) sd2strings_eq( { @@ -682,7 +680,7 @@ describe('autoload/shada.vim', function() }, ([[ [{'type': 4, 'timestamp': 0, 'data': [ 4, - {'_TYPE': v:msgpack_types.binary, '_VAL': ["abc\ndef"]}, + {'_TYPE': v:msgpack_types.string, '_VAL': ["abc\ndef"]}, ]}] ]]):gsub('\n', '') ) sd2strings_eq( @@ -909,7 +907,7 @@ describe('autoload/shada.vim', function() sd2strings_eq({ 'Variable with timestamp ' .. epoch .. ':', ' # Unexpected type: map instead of array', - ' = {="a": [10]}', + ' = {"a": [10]}', }, { { type = 6, timestamp = 0, data = { a = { 10 } } } }) sd2strings_eq( { @@ -941,7 +939,7 @@ describe('autoload/shada.vim', function() ' # Expected more elements in list', }, ([[ [{'type': 6, 'timestamp': 0, 'data': [ - {'_TYPE': v:msgpack_types.binary, '_VAL': ["\n"]}, + {'_TYPE': v:msgpack_types.string, '_VAL': ["\n"]}, ]}] ]]):gsub('\n', '') ) sd2strings_eq( @@ -952,7 +950,7 @@ describe('autoload/shada.vim', function() ' # Expected more elements in list', }, ([[ [{'type': 6, 'timestamp': 0, 'data': [ - {'_TYPE': v:msgpack_types.binary, '_VAL': ["foo"]}, + {'_TYPE': v:msgpack_types.string, '_VAL': ["foo"]}, ]}] ]]):gsub('\n', '') ) sd2strings_eq( @@ -963,7 +961,7 @@ describe('autoload/shada.vim', function() ' - value NIL', }, ([[ [{'type': 6, 'timestamp': 0, 'data': [ - {'_TYPE': v:msgpack_types.binary, '_VAL': ["foo"]}, + {'_TYPE': v:msgpack_types.string, '_VAL': ["foo"]}, {'_TYPE': v:msgpack_types.nil, '_VAL': ["foo"]}, ]}] ]]):gsub('\n', '') ) @@ -976,7 +974,7 @@ describe('autoload/shada.vim', function() ' - NIL', }, ([[ [{'type': 6, 'timestamp': 0, 'data': [ - {'_TYPE': v:msgpack_types.binary, '_VAL': ["foo"]}, + {'_TYPE': v:msgpack_types.string, '_VAL': ["foo"]}, {'_TYPE': v:msgpack_types.nil, '_VAL': ["foo"]}, {'_TYPE': v:msgpack_types.nil, '_VAL': ["foo"]}, ]}] ]]):gsub('\n', '') @@ -1041,7 +1039,7 @@ describe('autoload/shada.vim', function() }, ([[ [{'type': 7, 'timestamp': 0, 'data': { 'n': -10, - 'f': {'_TYPE': v:msgpack_types.binary, '_VAL': ["\n"]}, + 'f': {'_TYPE': v:msgpack_types.string, '_VAL': ["\n"]}, }}] ]]):gsub('\n', '') ) sd2strings_eq( @@ -1174,7 +1172,7 @@ describe('autoload/shada.vim', function() }, ([[ [{'type': 8, 'timestamp': 0, 'data': { 'n': -10, - 'f': {'_TYPE': v:msgpack_types.binary, '_VAL': ["\n"]}, + 'f': {'_TYPE': v:msgpack_types.string, '_VAL': ["\n"]}, }}] ]]):gsub('\n', '') ) sd2strings_eq( @@ -1237,7 +1235,7 @@ describe('autoload/shada.vim', function() sd2strings_eq({ 'Buffer list with timestamp ' .. epoch .. ':', ' # Unexpected type: map instead of array', - ' = {="a": [10]}', + ' = {"a": [10]}', }, { { type = 9, timestamp = 0, data = { a = { 10 } } } }) sd2strings_eq({ 'Buffer list with timestamp ' .. epoch .. ':', @@ -1247,7 +1245,7 @@ describe('autoload/shada.vim', function() sd2strings_eq({ 'Buffer list with timestamp ' .. epoch .. ':', ' # Expected array of maps', - ' = [{="a": 10}, []]', + ' = [{"a": 10}, []]', }, { { type = 9, timestamp = 0, data = { { a = 10 }, {} } } }) sd2strings_eq({ 'Buffer list with timestamp ' .. epoch .. ':', @@ -1322,7 +1320,7 @@ describe('autoload/shada.vim', function() }, ([[ [{'type': 9, 'timestamp': 0, 'data': [ {'f': 10}, - {'f': {'_TYPE': v:msgpack_types.binary, '_VAL': ["\n"]}}, + {'f': {'_TYPE': v:msgpack_types.string, '_VAL': ["\n"]}}, ]}] ]]):gsub('\n', '') ) end) @@ -1385,7 +1383,7 @@ describe('autoload/shada.vim', function() }, ([[ [{'type': 10, 'timestamp': 0, 'data': { 'n': -10, - 'f': {'_TYPE': v:msgpack_types.binary, '_VAL': ["\n"]}, + 'f': {'_TYPE': v:msgpack_types.string, '_VAL': ["\n"]}, }}] ]]):gsub('\n', '') ) sd2strings_eq( @@ -1504,7 +1502,7 @@ describe('autoload/shada.vim', function() }, ([[ [{'type': 11, 'timestamp': 0, 'data': { 'n': -10, - 'f': {'_TYPE': v:msgpack_types.binary, '_VAL': ["\n"]}, + 'f': {'_TYPE': v:msgpack_types.string, '_VAL': ["\n"]}, }}] ]]):gsub('\n', '') ) sd2strings_eq( @@ -1616,7 +1614,7 @@ describe('autoload/shada.vim', function() timestamp = 0, data = { c = 'abc', - f = { '!binary', { 'abc\ndef' } }, + f = { '!string', { 'abc\ndef' } }, l = -10, n = -64, rc = '10', @@ -1711,7 +1709,7 @@ describe('autoload/shada.vim', function() timestamp = 0, data = { c = 'abc', - f = { '!binary', { 'abc\ndef' } }, + f = { '!string', { 'abc\ndef' } }, l = -10, n = -64, rc = '10', @@ -1892,7 +1890,7 @@ describe('autoload/shada.vim', function() } } }, { 'Replacement string with timestamp ' .. epoch .. ':', ' # Unexpected type: map instead of array', - ' = {="a": [10]}', + ' = {"a": [10]}', }) strings2sd_eq({ { type = 3, timestamp = 0, data = {} } }, { 'Replacement string with timestamp ' .. epoch .. ':', @@ -1934,7 +1932,7 @@ describe('autoload/shada.vim', function() } } }, { 'History entry with timestamp ' .. epoch .. ':', ' # Unexpected type: map instead of array', - ' = {="a": [10]}', + ' = {"a": [10]}', }) strings2sd_eq({ { type = 4, timestamp = 0, data = {} } }, { 'History entry with timestamp ' .. epoch .. ':', @@ -2184,7 +2182,7 @@ describe('autoload/shada.vim', function() } } }, { 'Variable with timestamp ' .. epoch .. ':', ' # Unexpected type: map instead of array', - ' = {="a": [10]}', + ' = {"a": [10]}', }) strings2sd_eq({ { type = 6, timestamp = 0, data = {} } }, { 'Variable with timestamp ' .. epoch .. ':', @@ -2315,7 +2313,7 @@ describe('autoload/shada.vim', function() } } }, { 'Buffer list with timestamp ' .. epoch .. ':', ' # Unexpected type: map instead of array', - ' = {="a": [10]}', + ' = {"a": [10]}', }) strings2sd_eq( { { type = 9, timestamp = 0, data = { @@ -2325,7 +2323,7 @@ describe('autoload/shada.vim', function() { 'Buffer list with timestamp ' .. epoch .. ':', ' # Expected array of maps', - ' = [{="a": 10}, []]', + ' = [{"a": 10}, []]', } ) strings2sd_eq({ { type = 9, timestamp = 0, data = { @@ -2421,7 +2419,7 @@ describe('autoload/shada.vim', function() timestamp = 0, data = { { f = 10 }, - { f = { '!binary', { '\n' } } }, + { f = { '!string', { '\n' } } }, }, }, }, { @@ -2955,7 +2953,7 @@ describe('ftplugin/shada.vim', function() ' - :s replacement string "abc\\ndef"', ' Buffer list with timestamp ' .. epoch .. ':', ' # Expected array of maps', - '= [{="a": 10}, []]', + '= [{"a": 10}, []]', ' Buffer list with timestamp ' .. epoch .. ':', ' % Key Description Value', ' # Expected binary string', @@ -2992,7 +2990,7 @@ describe('ftplugin/shada.vim', function() ' - :s replacement string "abc\\ndef"', 'Buffer list with timestamp ' .. epoch .. ':', ' # Expected array of maps', - ' = [{="a": 10}, []]', + ' = [{"a": 10}, []]', 'Buffer list with timestamp ' .. epoch .. ':', ' % Key Description Value', ' # Expected binary string', @@ -3083,7 +3081,7 @@ describe('syntax/shada.vim', function() ' - :s replacement string DEBUG', 'Buffer list with timestamp ' .. epoch .. ':', ' # Expected array of maps', - ' = [{="a": +(10)"ac\\0df\\ngi\\"tt\\.", TRUE: FALSE}, [NIL, +(-10)""]]', + ' = [{"a": +(10)"ac\\0df\\ngi\\"tt\\.", TRUE: FALSE}, [NIL, +(-10)""]]', 'Buffer list with timestamp ' .. epoch .. ':', ' % Key Description Value', '', @@ -3119,8 +3117,8 @@ describe('syntax/shada.vim', function() {1: -} {4::s replacement string} {1:DEBUG} | {1:Buffer list} with timestamp 1970{1:-}01{1:-}01{1:T}00{1::}00{1::}00: | {4: # Expected array of maps} | - = {1:[{="}{3:a}{1:":} {1:+(}{5:10}{1:)"}{3:ac}{6:\0}{3:df}{6:\n}{3:gi}{6:\"}{3:tt\.}{1:",} {1:TRUE:} {1:FALSE},} {1:[NIL,} {1:+(}{5:-}| - {5:10}{1:)""]]} | + = {1:[{"}{3:a}{1:":} {1:+(}{5:10}{1:)"}{3:ac}{6:\0}{3:df}{6:\n}{3:gi}{6:\"}{3:tt\.}{1:",} {1:TRUE:} {1:FALSE},} {1:[NIL,} {1:+(}{5:-1}| + {5:0}{1:)""]]} | {1:Buffer list} with timestamp 1970{1:-}01{1:-}01{1:T}00{1::}00{1::}00: | {2: % Key Description Value} | | @@ -3464,7 +3462,6 @@ describe('syntax/shada.vim', function() { { 'ShaDaEntryRawMsgpack' }, ' = ' }, { { 'ShaDaMsgpackArray', 'ShaDaMsgpackArrayBraces' }, '[' }, { { 'ShaDaMsgpackArray', 'ShaDaMsgpackMap', 'ShaDaMsgpackMapBraces' }, '{' }, - { { 'ShaDaMsgpackArray', 'ShaDaMsgpackMap', 'ShaDaMsgpackString' }, '=' }, { { 'ShaDaMsgpackArray', diff --git a/test/functional/vimscript/json_functions_spec.lua b/test/functional/vimscript/json_functions_spec.lua index ae56e8873d..c6e0e75bdc 100644 --- a/test/functional/vimscript/json_functions_spec.lua +++ b/test/functional/vimscript/json_functions_spec.lua @@ -502,9 +502,9 @@ describe('json_decode() function', function() end it('parses strings with NUL properly', function() - sp_decode_eq({ _TYPE = 'string', _VAL = { '\n' } }, '"\\u0000"') - sp_decode_eq({ _TYPE = 'string', _VAL = { '\n', '\n' } }, '"\\u0000\\n\\u0000"') - sp_decode_eq({ _TYPE = 'string', _VAL = { '\n«\n' } }, '"\\u0000\\u00AB\\u0000"') + sp_decode_eq('\000', '"\\u0000"') + sp_decode_eq('\000\n\000', '"\\u0000\\n\\u0000"') + sp_decode_eq('\000«\000', '"\\u0000\\u00AB\\u0000"') end) it('parses dictionaries with duplicate keys to special maps', function() @@ -580,14 +580,8 @@ describe('json_decode() function', function() end) it('parses dictionaries with keys with NUL bytes to special maps', function() - sp_decode_eq( - { _TYPE = 'map', _VAL = { { { _TYPE = 'string', _VAL = { 'a\n', 'b' } }, 4 } } }, - '{"a\\u0000\\nb": 4}' - ) - sp_decode_eq( - { _TYPE = 'map', _VAL = { { { _TYPE = 'string', _VAL = { 'a\n', 'b', '' } }, 4 } } }, - '{"a\\u0000\\nb\\n": 4}' - ) + sp_decode_eq({ _TYPE = 'map', _VAL = { { 'a\000\nb', 4 } } }, '{"a\\u0000\\nb": 4}') + sp_decode_eq({ _TYPE = 'map', _VAL = { { 'a\000\nb\n', 4 } } }, '{"a\\u0000\\nb\\n": 4}') sp_decode_eq({ _TYPE = 'map', _VAL = { @@ -595,10 +589,7 @@ describe('json_decode() function', function() { 'a', 1 }, { 'c', 4 }, { 'd', 2 }, - { - { _TYPE = 'string', _VAL = { '\n' } }, - 4, - }, + { '\000', 4 }, }, }, '{"b": 3, "a": 1, "c": 4, "d": 2, "\\u0000": 4}') end) @@ -738,22 +729,11 @@ describe('json_encode() function', function() eq('{"\\u0000": 1}', eval('json_encode(todump)')) end) - it('can dump generic mapping with BIN special key and NUL', function() - command('let todump = {"_TYPE": v:msgpack_types.binary, "_VAL": ["\\n"]}') - command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[todump, 1]]}') - eq('{"\\u0000": 1}', eval('json_encode(todump)')) - end) - it('can dump STR special mapping with NUL and NL', function() command('let todump = {"_TYPE": v:msgpack_types.string, "_VAL": ["\\n", ""]}') eq('"\\u0000\\n"', eval('json_encode(todump)')) end) - it('can dump BIN special mapping with NUL and NL', function() - command('let todump = {"_TYPE": v:msgpack_types.binary, "_VAL": ["\\n", ""]}') - eq('"\\u0000\\n"', eval('json_encode(todump)')) - end) - it('cannot dump special ext mapping', function() command('let todump = {"_TYPE": v:msgpack_types.ext, "_VAL": [5, ["",""]]}') eq('Vim(call):E474: Unable to convert EXT string to JSON', exc_exec('call json_encode(todump)')) diff --git a/test/functional/vimscript/msgpack_functions_spec.lua b/test/functional/vimscript/msgpack_functions_spec.lua index d59dceef31..6b77811e35 100644 --- a/test/functional/vimscript/msgpack_functions_spec.lua +++ b/test/functional/vimscript/msgpack_functions_spec.lua @@ -371,13 +371,14 @@ describe('msgpack*() functions', function() eq(1, eval('dumped ==# dumped2')) end) - it('can restore and dump STR string with zero byte', function() + it('can restore and dump STR string contents with zero byte', function() command('let dumped = ["\\xA1\\n"]') command('let parsed = msgpackparse(dumped)') command('let dumped2 = msgpackdump(parsed)') - eq({ { _TYPE = {}, _VAL = { '\n' } } }, eval('parsed')) - eq(1, eval('parsed[0]._TYPE is v:msgpack_types.string')) - eq(1, eval('dumped ==# dumped2')) + eq({ '\000' }, eval('parsed')) + eq(eval('v:t_blob'), eval('type(parsed[0])')) + -- type is not preserved: prefer BIN for binary contents + eq(0, eval('dumped ==# dumped2')) end) it('can restore and dump BIN string with NL', function() @@ -428,9 +429,8 @@ describe('msgpackparse() function', function() parse_eq({ true }, { '\195' }) end) - it('restores FIXSTR as special dict', function() - parse_eq({ { _TYPE = {}, _VAL = { 'ab' } } }, { '\162ab' }) - eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.string')) + it('restores FIXSTR as string', function() + parse_eq({ 'ab' }, { '\162ab' }) end) it('restores BIN 8 as string', function() @@ -442,9 +442,8 @@ describe('msgpackparse() function', function() eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.ext')) end) - it('restores MAP with BIN key as special dictionary', function() - parse_eq({ { _TYPE = {}, _VAL = { { 'a', '' } } } }, { '\129\196\001a\196\n' }) - eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.map')) + it('restores MAP with BIN key as ordinary dictionary', function() + parse_eq({ { a = '' } }, { '\129\196\001a\196\n' }) end) it('restores MAP with duplicate STR keys as special dictionary', function() @@ -455,14 +454,14 @@ describe('msgpackparse() function', function() { _TYPE = {}, _VAL = { - { { _TYPE = {}, _VAL = { 'a' } }, '' }, - { { _TYPE = {}, _VAL = { 'a' } }, '' }, + { 'a', '' }, + { 'a', '' }, }, }, }, eval('parsed')) eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.map')) - eq(1, eval('g:parsed[0]._VAL[0][0]._TYPE is v:msgpack_types.string')) - eq(1, eval('g:parsed[0]._VAL[1][0]._TYPE is v:msgpack_types.string')) + eq(eval('v:t_string'), eval('type(g:parsed[0]._VAL[0][0])')) + eq(eval('v:t_string'), eval('type(g:parsed[0]._VAL[1][0])')) end) it('restores MAP with MAP key as special dictionary', function() @@ -802,7 +801,7 @@ describe('msgpackdump() function', function() it('can dump NULL string', function() dump_eq({ '\196\n' }, '[$XXX_UNEXISTENT_VAR_XXX]') - dump_eq({ '\196\n' }, '[{"_TYPE": v:msgpack_types.binary, "_VAL": [$XXX_UNEXISTENT_VAR_XXX]}]') + dump_eq({ '\196\n' }, '[v:_null_blob]') dump_eq({ '\160' }, '[{"_TYPE": v:msgpack_types.string, "_VAL": [$XXX_UNEXISTENT_VAR_XXX]}]') end) -- cgit From 724d1110b1e4699a34f489e9cdb2d25098746499 Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Thu, 27 Jun 2024 12:20:00 +0200 Subject: fix(lsp): pre-filter matches on label if filterText is missing (#29491) Although the built-in pum completion mechanism will filter anyway on the next input it is odd if the initial popup shows entries which don't match the current prefix. Using fuzzy match on the label/prefix is compatible with `completeopt+=fuzzy` and also doesn't seem to break postfix snippet cases Closes https://github.com/neovim/neovim/issues/29287 --- test/functional/plugin/lsp/completion_spec.lua | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'test/functional') diff --git a/test/functional/plugin/lsp/completion_spec.lua b/test/functional/plugin/lsp/completion_spec.lua index 1b56d1740a..bc10c0c937 100644 --- a/test/functional/plugin/lsp/completion_spec.lua +++ b/test/functional/plugin/lsp/completion_spec.lua @@ -141,6 +141,27 @@ describe('vim.lsp.completion: item conversion', function() eq(expected, result) end) + it('filters on label if filterText is missing', function() + local completion_list = { + { label = 'foo' }, + { label = 'bar' }, + } + local result = complete('fo|', completion_list) + local expected = { + { + abbr = 'foo', + word = 'foo', + }, + } + result = vim.tbl_map(function(x) + return { + abbr = x.abbr, + word = x.word, + } + end, result.items) + eq(expected, result) + end) + it('trims trailing newline or tab from textEdit', function() local range0 = { start = { line = 0, character = 0 }, -- cgit From aa6b9c677d83d76d448c3bb0973bf8d14bfdf922 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Sat, 8 Jun 2024 21:40:18 +0200 Subject: refactor: use `vim._with` where possible This mostly means replacing `nvim_buf_call` and `nvim_win_call` with `vim._with`. --- test/functional/api/window_spec.lua | 14 +++++++------- test/functional/autocmd/autocmd_spec.lua | 24 ++++++++++++------------ test/functional/plugin/lsp_spec.lua | 6 +++--- test/functional/ui/title_spec.lua | 4 ++-- test/functional/vimscript/api_functions_spec.lua | 2 +- 5 files changed, 25 insertions(+), 25 deletions(-) (limited to 'test/functional') diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua index 77611cc750..046e7107c0 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) ]], @@ -638,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) ]], @@ -657,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) ]], @@ -771,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) ]], @@ -790,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) ]], @@ -1178,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, }) diff --git a/test/functional/autocmd/autocmd_spec.lua b/test/functional/autocmd/autocmd_spec.lua index 5e407a9986..fbaf0c0dbf 100644 --- a/test/functional/autocmd/autocmd_spec.lua +++ b/test/functional/autocmd/autocmd_spec.lua @@ -350,11 +350,11 @@ describe('autocmd', function() } -- Create specific layout and ensure it's left unchanged. - -- Use nvim_buf_call on a hidden buffer so aucmd_win is used. + -- Use vim._with on a hidden buffer so aucmd_win is used. exec_lua [[ vim.cmd "wincmd s | wincmd _" _G.buf = vim.api.nvim_create_buf(true, true) - vim.api.nvim_buf_call(_G.buf, function() vim.cmd "wincmd J" end) + vim._with({buf = _G.buf}, function() vim.cmd "wincmd J" end) ]] screen:expect [[ ^ | @@ -367,14 +367,14 @@ describe('autocmd', function() -- This used to crash after making aucmd_win a normal window via the above. exec_lua [[ vim.cmd "tabnew | tabclose # | wincmd s | wincmd _" - vim.api.nvim_buf_call(_G.buf, function() vim.cmd "wincmd K" end) + vim._with({buf = _G.buf}, function() vim.cmd "wincmd K" end) ]] assert_alive() screen:expect_unchanged() -- Also check with win_splitmove(). exec_lua [[ - vim.api.nvim_buf_call(_G.buf, function() + vim._with({buf = _G.buf}, function() vim.fn.win_splitmove(vim.fn.winnr(), vim.fn.win_getid(1)) end) ]] @@ -382,11 +382,11 @@ describe('autocmd', function() -- Also check with nvim_win_set_config(). matches( - ': Failed to move window %d+ into split$', + '^Failed to move window %d+ into split$', pcall_err( exec_lua, [[ - vim.api.nvim_buf_call(_G.buf, function() + vim._with({buf = _G.buf}, function() vim.api.nvim_win_set_config(0, { vertical = true, win = vim.fn.win_getid(1) @@ -398,7 +398,7 @@ describe('autocmd', function() screen:expect_unchanged() -- Ensure splitting still works from inside the aucmd_win. - exec_lua [[vim.api.nvim_buf_call(_G.buf, function() vim.cmd "split" end)]] + exec_lua [[vim._with({buf = _G.buf}, function() vim.cmd "split" end)]] screen:expect [[ ^ | {1:~ }| @@ -418,7 +418,7 @@ describe('autocmd', function() 'editor', exec_lua [[ vim.cmd "only" - vim.api.nvim_buf_call(_G.buf, function() + vim._with({buf = _G.buf}, function() _G.config = vim.api.nvim_win_get_config(0) end) return _G.config.relative @@ -463,7 +463,7 @@ describe('autocmd', function() pcall_err( exec_lua, [[ - vim.api.nvim_buf_call(_G.buf, function() + vim._with({buf = _G.buf}, function() local win = vim.api.nvim_get_current_win() vim.api.nvim_win_close(win, true) end) @@ -475,7 +475,7 @@ describe('autocmd', function() pcall_err( exec_lua, [[ - vim.api.nvim_buf_call(_G.buf, function() + vim._with({buf = _G.buf}, function() local win = vim.api.nvim_get_current_win() vim.cmd('tabnext') vim.api.nvim_win_close(win, true) @@ -488,7 +488,7 @@ describe('autocmd', function() pcall_err( exec_lua, [[ - vim.api.nvim_buf_call(_G.buf, function() + vim._with({buf = _G.buf}, function() local win = vim.api.nvim_get_current_win() vim.api.nvim_win_hide(win) end) @@ -500,7 +500,7 @@ describe('autocmd', function() pcall_err( exec_lua, [[ - vim.api.nvim_buf_call(_G.buf, function() + vim._with({buf = _G.buf}, function() local win = vim.api.nvim_get_current_win() vim.cmd('tabnext') vim.api.nvim_win_hide(win) diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index be303f21ce..0630df65d5 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -371,7 +371,7 @@ describe('LSP', function() true, exec_lua [[ local keymap - vim.api.nvim_buf_call(BUFFER, function() + vim._with({buf = BUFFER}, function() keymap = vim.fn.maparg("K", "n", false, true) end) return keymap.callback == vim.lsp.buf.hover @@ -388,7 +388,7 @@ describe('LSP', function() '', exec_lua [[ local keymap - vim.api.nvim_buf_call(BUFFER, function() + vim._with({buf = BUFFER}, function() keymap = vim.fn.maparg("K", "n", false, false) end) return keymap @@ -782,7 +782,7 @@ describe('LSP', function() vim.api.nvim_buf_set_name(BUFFER, oldname) vim.api.nvim_buf_set_lines(BUFFER, 0, -1, true, {"help me"}) lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID) - vim.api.nvim_buf_call(BUFFER, function() vim.cmd('saveas ' .. newname) end) + vim._with({buf = BUFFER}, function() vim.cmd('saveas ' .. newname) end) ]=], tmpfile_old, tmpfile_new diff --git a/test/functional/ui/title_spec.lua b/test/functional/ui/title_spec.lua index e86fdbe5a3..fddda2c07a 100644 --- a/test/functional/ui/title_spec.lua +++ b/test/functional/ui/title_spec.lua @@ -82,11 +82,11 @@ describe('title', function() end) end) - it('a Lua callback calling nvim_buf_call in a hidden buffer', function() + it('a Lua callback calling vim._with in a hidden buffer', function() exec_lua(string.format( [[ vim.schedule(function() - vim.api.nvim_buf_call(%d, function() end) + vim._with({buf = %d}, function() end) end) ]], buf2 diff --git a/test/functional/vimscript/api_functions_spec.lua b/test/functional/vimscript/api_functions_spec.lua index b2865d2b4c..30d6c969ca 100644 --- a/test/functional/vimscript/api_functions_spec.lua +++ b/test/functional/vimscript/api_functions_spec.lua @@ -115,7 +115,7 @@ describe('eval-API', 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_term(cmdwin_buf, {}) end) ]] -- cgit From e7020306a19a5211c834966ec067fff3b981bdb9 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 30 Jun 2024 06:40:31 +0800 Subject: feat(jumplist): allow opting out of removing unloaded buffers (#29347) Problem: Cannot opt out of removing unloaded buffers from the jumplist. Solution: Only enable that with "unload" flag in 'jumpoptions'. --- test/functional/editor/jump_spec.lua | 46 +++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/editor/jump_spec.lua b/test/functional/editor/jump_spec.lua index 880831d9f8..6d2f75e7c5 100644 --- a/test/functional/editor/jump_spec.lua +++ b/test/functional/editor/jump_spec.lua @@ -194,7 +194,7 @@ describe("jumpoptions=stack behaves like 'tagstack'", function() end) end) -describe('buffer deletion', function() +describe('buffer deletion with jumpoptions+=unload', function() local base_file = 'Xtest-functional-buffer-deletion' local file1 = base_file .. '1' local file2 = base_file .. '2' @@ -227,6 +227,12 @@ describe('buffer deletion', function() command('edit ' .. file3) end) + after_each(function() + os.remove(file1) + os.remove(file2) + os.remove(file3) + end) + it('deletes jump list entries when the current buffer is deleted', function() command('edit ' .. file1) @@ -319,6 +325,44 @@ describe('buffer deletion', function() end) end) +describe('buffer deletion with jumpoptions-=unload', function() + local base_file = 'Xtest-functional-buffer-deletion' + local file1 = base_file .. '1' + local file2 = base_file .. '2' + local base_content = 'text' + local content1 = base_content .. '1' + local content2 = base_content .. '2' + + before_each(function() + clear() + command('clearjumps') + command('set jumpoptions-=unload') + + write_file(file1, content1, false, false) + write_file(file2, content2, false, false) + + command('edit ' .. file1) + command('edit ' .. file2) + end) + + after_each(function() + os.remove(file1) + os.remove(file2) + end) + + it('Ctrl-O reopens previous buffer with :bunload or :bdelete #28968', function() + eq(file2, fn.bufname('')) + command('bunload') + eq(file1, fn.bufname('')) + feed('') + eq(file2, fn.bufname('')) + command('bdelete') + eq(file1, fn.bufname('')) + feed('') + eq(file2, fn.bufname('')) + end) +end) + describe('jumpoptions=view', function() local file1 = 'Xtestfile-functional-editor-jumps' local file2 = 'Xtestfile-functional-editor-jumps-2' -- cgit From aec7f1979ada1b34cfb3d8fd33769232d0323ea8 Mon Sep 17 00:00:00 2001 From: Sebastian Lyng Johansen Date: Tue, 2 Jul 2024 18:27:51 +0200 Subject: fix(lsp): fallback to `label` for completion items if all others are missing (#29522) --- test/functional/plugin/lsp/completion_spec.lua | 27 ++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'test/functional') diff --git a/test/functional/plugin/lsp/completion_spec.lua b/test/functional/plugin/lsp/completion_spec.lua index bc10c0c937..5c2933c610 100644 --- a/test/functional/plugin/lsp/completion_spec.lua +++ b/test/functional/plugin/lsp/completion_spec.lua @@ -427,6 +427,33 @@ describe('vim.lsp.completion: item conversion', function() eq('the-insertText', text) end ) + + it( + 'defaults to label as textEdit.newText if insertText or textEditText are not present', + function() + local completion_list = { + isIncomplete = false, + itemDefaults = { + editRange = { + start = { line = 1, character = 1 }, + ['end'] = { line = 1, character = 4 }, + }, + insertTextFormat = 2, + data = 'foobar', + }, + items = { + { + label = 'hello', + data = 'item-property-has-priority', + }, + }, + } + local result = complete('|', completion_list) + eq(1, #result.items) + local text = result.items[1].user_data.nvim.lsp.completion_item.textEdit.newText + eq('hello', text) + end + ) end) describe('vim.lsp.completion: protocol', function() -- cgit From d413038b4fd71b7a335b6653aa64d2cb6daeac7b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 3 Jul 2024 07:40:42 +0800 Subject: fix(treesitter): ensure syntaxset augroup exists (#29542) Problem: Error when calling vim.treesitter.start() and vim.treesitter.stop() in init.lua. Solution: Ensure syntaxset augroup exists after loading synload.vim. --- test/functional/treesitter/highlight_spec.lua | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) (limited to 'test/functional') diff --git a/test/functional/treesitter/highlight_spec.lua b/test/functional/treesitter/highlight_spec.lua index 05c0cdc01e..6eadb3110f 100644 --- a/test/functional/treesitter/highlight_spec.lua +++ b/test/functional/treesitter/highlight_spec.lua @@ -10,8 +10,6 @@ local command = n.command local api = n.api local eq = t.eq -before_each(clear) - local hl_query_c = [[ (ERROR) @error @@ -120,6 +118,7 @@ describe('treesitter highlighting (C)', function() local screen before_each(function() + clear() screen = Screen.new(65, 18) screen:attach() screen:set_default_attr_ids { @@ -800,6 +799,7 @@ describe('treesitter highlighting (lua)', function() local screen before_each(function() + clear() screen = Screen.new(65, 18) screen:attach() screen:set_default_attr_ids { @@ -838,6 +838,7 @@ describe('treesitter highlighting (help)', function() local screen before_each(function() + clear() screen = Screen.new(40, 6) screen:attach() screen:set_default_attr_ids { @@ -939,6 +940,7 @@ describe('treesitter highlighting (nested injections)', function() local screen before_each(function() + clear() screen = Screen.new(80, 7) screen:attach() screen:set_default_attr_ids { @@ -1006,6 +1008,7 @@ describe('treesitter highlighting (markdown)', function() local screen before_each(function() + clear() screen = Screen.new(40, 6) screen:attach() exec_lua([[ @@ -1053,3 +1056,19 @@ printf('Hello World!'); }) end) end) + +it('starting and stopping treesitter highlight in init.lua works #29541', function() + t.write_file( + 'Xinit.lua', + [[ + vim.bo.ft = 'c' + vim.treesitter.start() + vim.treesitter.stop() + ]] + ) + finally(function() + os.remove('Xinit.lua') + end) + clear({ args = { '-u', 'Xinit.lua' } }) + eq('', api.nvim_get_vvar('errmsg')) +end) -- cgit From 599fc7cee4441cf3beacd47f388aa36194091422 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 3 Jul 2024 08:40:55 +0800 Subject: test: starting and stopping treesitter highlight (#29546) --- test/functional/treesitter/highlight_spec.lua | 143 +++++++++++++++++--------- 1 file changed, 97 insertions(+), 46 deletions(-) (limited to 'test/functional') diff --git a/test/functional/treesitter/highlight_spec.lua b/test/functional/treesitter/highlight_spec.lua index 6eadb3110f..3774ff8d54 100644 --- a/test/functional/treesitter/highlight_spec.lua +++ b/test/functional/treesitter/highlight_spec.lua @@ -8,6 +8,7 @@ local exec_lua = n.exec_lua local feed = n.feed local command = n.command local api = n.api +local fn = n.fn local eq = t.eq local hl_query_c = [[ @@ -63,6 +64,46 @@ static int nlua_schedule(lua_State *const lstate) return 0; }]] +local hl_grid_legacy_c = [[ + {2:^/// Schedule Lua callback on main loop's event queue} | + {3:static} {3:int} nlua_schedule(lua_State *{3:const} lstate) | + { | + {4:if} (lua_type(lstate, {5:1}) != LUA_TFUNCTION | + || lstate != lstate) { | + lua_pushliteral(lstate, {5:"vim.schedule: expected function"}); | + {4:return} lua_error(lstate); | + } | + | + LuaRef cb = nlua_ref(lstate, {5:1}); | + | + multiqueue_put(main_loop.events, nlua_schedule_event, | + {5:1}, ({3:void} *)({3:ptrdiff_t})cb); | + {4:return} {5:0}; | + } | + {1:~ }|*2 + | +]] + +local hl_grid_ts_c = [[ + {2:^/// Schedule Lua callback on main loop's event queue} | + {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) | + { | + {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} | + || {6:lstate} != {6:lstate}) { | + {11:lua_pushliteral}(lstate, {5:"vim.schedule: expected function"}); | + {4:return} {11:lua_error}(lstate); | + } | + | + {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); | + | + multiqueue_put(main_loop.events, {11:nlua_schedule_event}, | + {5:1}, ({3:void} *)({3:ptrdiff_t})cb); | + {4:return} {5:0}; | + } | + {1:~ }|*2 + | +]] + local test_text_c = [[ void ui_refresh(void) { @@ -140,11 +181,39 @@ describe('treesitter highlighting (C)', function() command [[ hi link @warning WarningMsg ]] end) + it('starting and stopping treesitter highlight works', function() + command('setfiletype c | syntax on') + fn.setreg('r', hl_text_c) + feed('irgg') + -- legacy syntax highlighting is used by default + screen:expect(hl_grid_legacy_c) + + exec_lua([[ + vim.treesitter.query.set('c', 'highlights', hl_query) + vim.treesitter.start() + ]]) + -- treesitter highlighting is used + screen:expect(hl_grid_ts_c) + + exec_lua('vim.treesitter.stop()') + -- legacy syntax highlighting is used + screen:expect(hl_grid_legacy_c) + + exec_lua('vim.treesitter.start()') + -- treesitter highlighting is used + screen:expect(hl_grid_ts_c) + + exec_lua('vim.treesitter.stop()') + -- legacy syntax highlighting is used + screen:expect(hl_grid_legacy_c) + end) + it('is updated with edits', function() insert(hl_text_c) + feed('gg') screen:expect { grid = [[ - /// Schedule Lua callback on main loop's event queue | + ^/// Schedule Lua callback on main loop's event queue | static int nlua_schedule(lua_State *const lstate) | { | if (lua_type(lstate, 1) != LUA_TFUNCTION | @@ -158,7 +227,7 @@ describe('treesitter highlighting (C)', function() multiqueue_put(main_loop.events, nlua_schedule_event, | 1, (void *)(ptrdiff_t)cb); | return 0; | - ^} | + } | {1:~ }|*2 | ]], @@ -169,27 +238,7 @@ describe('treesitter highlighting (C)', function() local highlighter = vim.treesitter.highlighter test_hl = highlighter.new(parser, {queries = {c = hl_query}}) ]] - screen:expect { - grid = [[ - {2:/// Schedule Lua callback on main loop's event queue} | - {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) | - { | - {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} | - || {6:lstate} != {6:lstate}) { | - {11:lua_pushliteral}(lstate, {5:"vim.schedule: expected function"}); | - {4:return} {11:lua_error}(lstate); | - } | - | - {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); | - | - multiqueue_put(main_loop.events, {11:nlua_schedule_event}, | - {5:1}, ({3:void} *)({3:ptrdiff_t})cb); | - {4:return} {5:0}; | - ^} | - {1:~ }|*2 - | - ]], - } + screen:expect(hl_grid_ts_c) feed('5Gocdd') @@ -525,40 +574,21 @@ describe('treesitter highlighting (C)', function() it('supports highlighting with custom highlight groups', function() insert(hl_text_c) + feed('gg') exec_lua [[ local parser = vim.treesitter.get_parser(0, "c") test_hl = vim.treesitter.highlighter.new(parser, {queries = {c = hl_query}}) ]] - screen:expect { - grid = [[ - {2:/// Schedule Lua callback on main loop's event queue} | - {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) | - { | - {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} | - || {6:lstate} != {6:lstate}) { | - {11:lua_pushliteral}(lstate, {5:"vim.schedule: expected function"}); | - {4:return} {11:lua_error}(lstate); | - } | - | - {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); | - | - multiqueue_put(main_loop.events, {11:nlua_schedule_event}, | - {5:1}, ({3:void} *)({3:ptrdiff_t})cb); | - {4:return} {5:0}; | - ^} | - {1:~ }|*2 - | - ]], - } + screen:expect(hl_grid_ts_c) -- This will change ONLY the literal strings to look like comments -- The only literal string is the "vim.schedule: expected function" in this test. exec_lua [[vim.cmd("highlight link @string.nonexistent_specializer comment")]] screen:expect { grid = [[ - {2:/// Schedule Lua callback on main loop's event queue} | + {2:^/// Schedule Lua callback on main loop's event queue} | {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) | { | {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} | @@ -572,7 +602,7 @@ describe('treesitter highlighting (C)', function() multiqueue_put(main_loop.events, {11:nlua_schedule_event}, | {5:1}, ({3:void} *)({3:ptrdiff_t})cb); | {4:return} {5:0}; | - ^} | + } | {1:~ }|*2 | ]], @@ -1071,4 +1101,25 @@ it('starting and stopping treesitter highlight in init.lua works #29541', functi end) clear({ args = { '-u', 'Xinit.lua' } }) eq('', api.nvim_get_vvar('errmsg')) + + local screen = Screen.new(65, 18) + screen:attach() + screen:set_default_attr_ids { + [1] = { bold = true, foreground = Screen.colors.Blue1 }, + [2] = { foreground = Screen.colors.Blue1 }, + [3] = { bold = true, foreground = Screen.colors.SeaGreen4 }, + [4] = { bold = true, foreground = Screen.colors.Brown }, + [5] = { foreground = Screen.colors.Magenta }, + [6] = { foreground = Screen.colors.Red }, + [7] = { bold = true, foreground = Screen.colors.SlateBlue }, + [8] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, + [9] = { foreground = Screen.colors.Magenta, background = Screen.colors.Red }, + [10] = { foreground = Screen.colors.Red, background = Screen.colors.Red }, + [11] = { foreground = Screen.colors.Cyan4 }, + } + + fn.setreg('r', hl_text_c) + feed('irgg') + -- legacy syntax highlighting is used + screen:expect(hl_grid_legacy_c) end) -- cgit From 7f33c1967b78ca8fda11fb0ad4c7f57d563e6ede Mon Sep 17 00:00:00 2001 From: Tyler Miller Date: Wed, 3 Jul 2024 15:36:00 -0700 Subject: fix(lua): use rawget() to get __call in vim.is_callable() (#29536) Lua 5.1 uses a "raw get" to retrieve `__call` from a metatable to determine if a table is callable. Mirror this behavior in `vim.is_callable()`. --- test/functional/lua/vim_spec.lua | 54 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) (limited to 'test/functional') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 23bb9f0a2e..03c743c9ae 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -1495,6 +1495,60 @@ describe('lua stdlib', function() ]]) ) + eq( + { false, false }, + exec_lua([[ + local meta = { __call = {} } + assert(meta.__call) + local function new() + return setmetatable({}, meta) + end + local not_callable = new() + return { pcall(function() not_callable() end), vim.is_callable(not_callable) } + ]]) + ) + eq( + { false, false }, + exec_lua([[ + local function new() + return { __call = function()end } + end + local not_callable = new() + assert(not_callable.__call) + return { pcall(function() not_callable() end), vim.is_callable(not_callable) } + ]]) + ) + eq( + { false, false }, + exec_lua([[ + local meta = setmetatable( + { __index = { __call = function() end } }, + { __index = { __call = function() end } } + ) + assert(meta.__call) + local not_callable = setmetatable({}, meta) + assert(not_callable.__call) + return { pcall(function() not_callable() end), vim.is_callable(not_callable) } + ]]) + ) + eq( + { false, false }, + exec_lua([[ + local meta = setmetatable({ + __index = function() + return function() end + end, + }, { + __index = function() + return function() end + end, + }) + assert(meta.__call) + local not_callable = setmetatable({}, meta) + assert(not_callable.__call) + return { pcall(function() not_callable() end), vim.is_callable(not_callable) } + ]]) + ) eq(false, exec_lua('return vim.is_callable(1)')) eq(false, exec_lua("return vim.is_callable('foo')")) eq(false, exec_lua('return vim.is_callable({})')) -- cgit From 033ea63b2fa2c0ce1a47bafd97df482871aafef5 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 4 Jul 2024 09:54:51 +0800 Subject: refactor: add assertion for v_blob in tv_ptr() (#29554) Also add test for using printf() and id() with a Blob. --- test/functional/vimscript/printf_spec.lua | 3 +++ 1 file changed, 3 insertions(+) (limited to 'test/functional') diff --git a/test/functional/vimscript/printf_spec.lua b/test/functional/vimscript/printf_spec.lua index 3c66e07618..1fd5c3c9b6 100644 --- a/test/functional/vimscript/printf_spec.lua +++ b/test/functional/vimscript/printf_spec.lua @@ -84,10 +84,13 @@ describe('printf()', function() end api.nvim_del_var('__result') end + check_printf('v:_null_string', true) check_printf('v:_null_list', true) check_printf('v:_null_dict', true) + check_printf('v:_null_blob', true) check_printf('[]') check_printf('{}') + check_printf('0z') check_printf('function("tr", ["a"])') end) end) -- cgit From 81d4e96bc8685876943d8a7549004f128501da17 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 5 Jul 2024 07:24:45 +0800 Subject: fix(mouse): don't treat click on hsep as click on statusline (#29565) This allows showing popup menu when right-clicking on hsep or cmdline. --- test/functional/ui/mouse_spec.lua | 19 +++++++++++++++++++ test/functional/ui/statuscolumn_spec.lua | 3 --- 2 files changed, 19 insertions(+), 3 deletions(-) (limited to 'test/functional') diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua index 42c877fd92..0228708958 100644 --- a/test/functional/ui/mouse_spec.lua +++ b/test/functional/ui/mouse_spec.lua @@ -2002,5 +2002,24 @@ describe('ui/mouse/input', function() feed('') eq({ 4, 20 }, api.nvim_win_get_cursor(0)) eq('the moon', fn.getreg('"')) + + -- Try clicking in the cmdline + api.nvim_input_mouse('right', 'press', '', 0, 23, 0) + api.nvim_input_mouse('right', 'release', '', 0, 23, 0) + feed('') + eq('baz', api.nvim_get_var('menustr')) + + -- Try clicking in horizontal separator with global statusline + command('set laststatus=3') + api.nvim_input_mouse('right', 'press', '', 0, 5, 0) + api.nvim_input_mouse('right', 'release', '', 0, 5, 0) + feed('') + eq('foo', api.nvim_get_var('menustr')) + + -- Try clicking in the cmdline with global statusline + api.nvim_input_mouse('right', 'press', '', 0, 23, 0) + api.nvim_input_mouse('right', 'release', '', 0, 23, 0) + feed('') + eq('bar', api.nvim_get_var('menustr')) end) end) diff --git a/test/functional/ui/statuscolumn_spec.lua b/test/functional/ui/statuscolumn_spec.lua index 7ee7f38d07..b4d4c94a5e 100644 --- a/test/functional/ui/statuscolumn_spec.lua +++ b/test/functional/ui/statuscolumn_spec.lua @@ -652,9 +652,6 @@ describe('statuscolumn', function() -- Check that statusline click doesn't register as statuscolumn click api.nvim_input_mouse('right', 'press', '', 0, 12, 0) eq('', eval('g:testvar')) - -- Check that cmdline click doesn't register as statuscolumn click - api.nvim_input_mouse('right', 'press', '', 0, 13, 0) - eq('', eval('g:testvar')) end) it('clicks and highlights work with control characters', function() -- cgit From 9217e0d671b790d39192181cb894cfec012f06a6 Mon Sep 17 00:00:00 2001 From: Riley Bruins Date: Thu, 4 Jul 2024 10:09:19 -0700 Subject: fix(treesitter): display fields for anonymous nodes in :InspectTree --- test/functional/treesitter/inspect_tree_spec.lua | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'test/functional') diff --git a/test/functional/treesitter/inspect_tree_spec.lua b/test/functional/treesitter/inspect_tree_spec.lua index b403cca735..ef2ed8d970 100644 --- a/test/functional/treesitter/inspect_tree_spec.lua +++ b/test/functional/treesitter/inspect_tree_spec.lua @@ -37,7 +37,7 @@ describe('vim.treesitter.inspect_tree', function() it('can toggle to show anonymous nodes', function() insert([[ - print() + print('hello') ]]) exec_lua([[ @@ -48,11 +48,15 @@ describe('vim.treesitter.inspect_tree', function() expect_tree [[ (chunk ; [0, 0] - [2, 0] - (function_call ; [0, 0] - [0, 7] + (function_call ; [0, 0] - [0, 14] name: (identifier) ; [0, 0] - [0, 5] - arguments: (arguments ; [0, 5] - [0, 7] + arguments: (arguments ; [0, 5] - [0, 14] "(" ; [0, 5] - [0, 6] - ")"))) ; [0, 6] - [0, 7] + (string ; [0, 6] - [0, 13] + start: "'" ; [0, 6] - [0, 7] + content: (string_content) ; [0, 7] - [0, 12] + end: "'") ; [0, 12] - [0, 13] + ")"))) ; [0, 13] - [0, 14] ]] end) -- cgit From b109b1abce8c86f80aea06948b32e35a70daa0b0 Mon Sep 17 00:00:00 2001 From: Zoltán Nyikos Date: Sat, 6 Jul 2024 11:40:08 +0200 Subject: fix(glob): avoid `subcapture nesting too deep` error (#29520) Use Cmt to evaluate Cond and Elem during match to avoid building the nested capture structure later. --- test/functional/lua/glob_spec.lua | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'test/functional') diff --git a/test/functional/lua/glob_spec.lua b/test/functional/lua/glob_spec.lua index b3e1b79ee7..b95d874bb5 100644 --- a/test/functional/lua/glob_spec.lua +++ b/test/functional/lua/glob_spec.lua @@ -205,6 +205,19 @@ describe('glob', function() eq(true, match('[!a-zA-Z0-9]', '!')) end) + it('should handle long patterns', function() + -- lpeg has a recursion limit of 200 by default, make sure the grammar does trigger it on + -- strings longer than that + local fill_200 = + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + eq(200, fill_200:len()) + local long_lit = fill_200 .. 'a' + eq(false, match(long_lit, 'b')) + eq(true, match(long_lit, long_lit)) + local long_pat = fill_200 .. 'a/**/*.c' + eq(true, match(long_pat, fill_200 .. 'a/b/c/d.c')) + end) + it('should match complex patterns', function() eq(false, match('**/*.{c,h}', '')) eq(false, match('**/*.{c,h}', 'c')) -- cgit From 55e4301036bb938474fc9768c41e28df867d9286 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Sat, 6 Jul 2024 11:44:19 +0200 Subject: feat(lsp): drop fswatch, use inotifywait (#29374) This patch replaces fswatch with inotifywait from inotify-toools: https://github.com/inotify-tools/inotify-tools fswatch takes ~1min to set up recursively for the Samba source code directory. inotifywait needs less than a second to do the same thing. https://github.com/emcrisostomo/fswatch/issues/321 Also it fswatch seems to be unmaintained in the meantime. Signed-off-by: Andreas Schneider --- test/functional/lua/watch_spec.lua | 9 ++++++--- test/functional/plugin/lsp_spec.lua | 8 ++++---- 2 files changed, 10 insertions(+), 7 deletions(-) (limited to 'test/functional') diff --git a/test/functional/lua/watch_spec.lua b/test/functional/lua/watch_spec.lua index bd8faadf5b..3d2dda716e 100644 --- a/test/functional/lua/watch_spec.lua +++ b/test/functional/lua/watch_spec.lua @@ -23,10 +23,13 @@ describe('vim._watch', function() local function run(watchfunc) it('detects file changes (watchfunc=' .. watchfunc .. '())', function() - if watchfunc == 'fswatch' then + if watchfunc == 'inotify' then skip(is_os('win'), 'not supported on windows') skip(is_os('mac'), 'flaky test on mac') - skip(not is_ci() and n.fn.executable('fswatch') == 0, 'fswatch not installed and not on CI') + skip( + not is_ci() and n.fn.executable('inotifywait') == 0, + 'inotify-tools not installed and not on CI' + ) end if watchfunc == 'watch' then @@ -123,5 +126,5 @@ describe('vim._watch', function() run('watch') run('watchdirs') - run('fswatch') + run('inotify') end) diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 0630df65d5..2b8a7aed9e 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -5128,12 +5128,12 @@ describe('LSP', function() it( string.format('sends notifications when files change (watchfunc=%s)', watchfunc), function() - if watchfunc == 'fswatch' then + if watchfunc == 'inotify' then skip(is_os('win'), 'not supported on windows') skip(is_os('mac'), 'flaky test on mac') skip( - not is_ci() and fn.executable('fswatch') == 0, - 'fswatch not installed and not on CI' + not is_ci() and fn.executable('inotifywait') == 0, + 'inotify-tools not installed and not on CI' ) end @@ -5265,7 +5265,7 @@ describe('LSP', function() test_filechanges('watch') test_filechanges('watchdirs') - test_filechanges('fswatch') + test_filechanges('inotify') it('correctly registers and unregisters', function() local root_dir = '/some_dir' -- cgit From bdc6e38781321895331057cbcfb099f8ad31e6db Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 6 Jul 2024 22:25:35 +0800 Subject: fix(lua): don't include text after cursor in completion pattern (#29587) --- test/functional/editor/completion_spec.lua | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'test/functional') diff --git a/test/functional/editor/completion_spec.lua b/test/functional/editor/completion_spec.lua index 405af5fcfd..9d5bda0acc 100644 --- a/test/functional/editor/completion_spec.lua +++ b/test/functional/editor/completion_spec.lua @@ -854,6 +854,16 @@ describe('completion', function() ]]) end) + it('works when cursor is in the middle of cmdline #29586', function() + feed(':lua math.a(); 1') + screen:expect([[ + | + {1:~ }|*5 + {100:abs}{3: acos asin atan atan2 }| + :lua math.abs^(); 1 | + ]]) + end) + it('provides completion from `getcompletion()`', function() eq({ 'vim' }, fn.getcompletion('vi', 'lua')) eq({ 'api' }, fn.getcompletion('vim.ap', 'lua')) -- cgit From 7a54d707fa6f32822b241140b31a348ad5ad0e6b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 6 Jul 2024 22:44:37 +0800 Subject: vim-patch:9.1.0534: completion wrong with fuzzy when cycling back to original (#29588) Problem: completion wrong with fuzzy when cycling back to original (Quan Nguyen) Solution: reset show_match_ok when cp_score is zero (glepnir) fixes: vim/vim#15095 closes: vim/vim#15105 https://github.com/vim/vim/commit/65407ce1d2963e7a758af8fecdcbd67b9a90bdb9 Co-authored-by: glepnir --- test/functional/ui/popupmenu_spec.lua | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'test/functional') diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index a1a21eb317..db2ee7ff29 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -4905,6 +4905,28 @@ describe('builtin popupmenu', function() feed('o=Comp()') screen:expect_unchanged(true) + feed('') + command('set completeopt+=fuzzy,menu') + feed('S hello helio hero h') + screen:expect([[ + hello helio hero h^ | + {1:~ }{n: }{mn:h}{n:ello }{1: }| + {1:~ }{n: }{mn:h}{n:elio }{1: }| + {1:~ }{s: }{ms:h}{s:ero }{1: }| + {1:~ }|*15 + {2:-- }{5:match 1 of 3} | + ]]) + + feed('S hello helio hero h') + screen:expect([[ + hello helio hero h^ | + {1:~ }{n: }{mn:h}{n:ello }{1: }| + {1:~ }{s: }{ms:h}{s:elio }{1: }| + {1:~ }{n: }{mn:h}{n:ero }{1: }| + {1:~ }|*15 + {2:-- }{5:match 2 of 3} | + ]]) + feed('') end) end -- cgit From 6a886a2511bbfd24a4d6ecc3f3a75f08a6df9de9 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 7 Jul 2024 07:21:14 +0800 Subject: vim-patch:9.1.0538: not possible to assign priority when defining a sign (#29592) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: not possible to assign priority when defining a sign (Mathias Fußenegger) Solution: Add the priority argument for the :sign-define ex command and the sign_define() function (LemonBoy) Use the specified value instead of the default one (SIGN_DEF_PRIO) when no priority is explicitly specified in sign_place or :sign place. fixes: vim/vim#8334 closes: vim/vim#15124 https://github.com/vim/vim/commit/b975ddfdf96644b8df808415dee36f99abd48753 Co-authored-by: LemonBoy --- test/functional/ui/popupmenu_spec.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'test/functional') diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index db2ee7ff29..e005cfd2e6 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -2920,11 +2920,12 @@ describe('builtin popupmenu', function() feed('sign define ') screen:expect([[ | - {1:~ }|*2 + {1:~ }| {1:~ }{s: culhl= }{1: }| {1:~ }{n: icon= }{1: }| {1:~ }{n: linehl= }{1: }| {1:~ }{n: numhl= }{1: }| + {1:~ }{n: priority= }{1: }| {1:~ }{n: text= }{1: }| {1:~ }{n: texthl= }{1: }| :sign define culhl=^ | @@ -2933,11 +2934,12 @@ describe('builtin popupmenu', function() feed('') screen:expect([[ | - {1:~ }|*2 + {1:~ }| {1:~ }{s: culhl= }{1: }| {1:~ }{n: icon= }{1: }| {1:~ }{n: linehl= }{1: }| {1:~ }{n: numhl= }{1: }| + {1:~ }{n: priority= }{1: }| {1:~ }{n: text= }{1: }| {1:~ }{n: texthl= }{1: }| :sign define culhl= culhl=^ | -- cgit From 73ae7d44a281a543f902f0dea111713c06490079 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 8 Jul 2024 10:36:41 +0800 Subject: fix(quickfix): make shortmess+=O work with cmdheight=0 (#29609) --- test/functional/ex_cmds/quickfix_commands_spec.lua | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/ex_cmds/quickfix_commands_spec.lua b/test/functional/ex_cmds/quickfix_commands_spec.lua index 3df41b015e..9c47b1f05f 100644 --- a/test/functional/ex_cmds/quickfix_commands_spec.lua +++ b/test/functional/ex_cmds/quickfix_commands_spec.lua @@ -185,6 +185,9 @@ describe('quickfix', function() it('BufAdd does not cause E16 when reusing quickfix buffer #18135', function() local file = file_base .. '_reuse_qfbuf_BufAdd' write_file(file, ('\n'):rep(100) .. 'foo') + finally(function() + os.remove(file) + end) source([[ set grepprg=internal autocmd BufAdd * call and(0, 0) @@ -192,7 +195,24 @@ describe('quickfix', function() ]]) command('grep foo ' .. file) command('grep foo ' .. file) - os.remove(file) + end) + + it('jump message does not scroll with cmdheight=0 and shm+=O #29597', function() + local screen = Screen.new(40, 6) + screen:attach() + command('set cmdheight=0') + local file = file_base .. '_reuse_qfbuf_BufAdd' + write_file(file, 'foobar') + finally(function() + os.remove(file) + end) + command('vimgrep /foo/gj ' .. file) + feed(':cc') + screen:expect([[ + ^foobar | + {1:~ }|*4 + (1 of 1): foobar | + ]]) end) end) -- cgit From 51d85f7ea58bd715cec1fdfa8d19826cafe7185d Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Tue, 9 Jul 2024 15:26:48 +0200 Subject: build(deps): drop unused bundled bash, python parsers and queries Problem: Neovim bundles treesitter parsers for bash and python but does not use them by default. This dilutes the messaging about the bundled parsers being required for functionality or reasonable out-of-the-box experience. It also increases the risk of query incompatibilities for no gain. Solution: Stop bundling bash and python parser and queries. --- test/functional/treesitter/fold_spec.lua | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'test/functional') diff --git a/test/functional/treesitter/fold_spec.lua b/test/functional/treesitter/fold_spec.lua index 6d33544cd4..3e81cebe71 100644 --- a/test/functional/treesitter/fold_spec.lua +++ b/test/functional/treesitter/fold_spec.lua @@ -408,15 +408,15 @@ t3]]) it('handles quantified patterns', function() insert([[ -import hello -import hello -import hello -import hello -import hello -import hello]]) - - exec_lua([[vim.treesitter.query.set('python', 'folds', '(import_statement)+ @fold')]]) - parse('python') +-- hello +-- hello +-- hello +-- hello +-- hello +-- hello]]) + + exec_lua([[vim.treesitter.query.set('lua', 'folds', '(comment)+ @fold')]]) + parse('lua') eq({ [1] = '>1', -- cgit From 16f63b964fc4a7842fd9a2fd5e0ba8c997d549c9 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 13 Jul 2024 04:14:29 +0800 Subject: fix(input): handle vim.on_key() properly with ALT and K_SPECIAL (#29677) --- test/functional/editor/meta_key_spec.lua | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'test/functional') diff --git a/test/functional/editor/meta_key_spec.lua b/test/functional/editor/meta_key_spec.lua index 87fe395608..30027e2fd6 100644 --- a/test/functional/editor/meta_key_spec.lua +++ b/test/functional/editor/meta_key_spec.lua @@ -145,7 +145,8 @@ describe('meta-keys #8226 #13042', function() end) it('ALT/META with vim.on_key()', function() - feed('ifoobarbazgg0') + feed('ifoobarbazgg0viw"ay') + command('nnoremap … "') exec_lua [[ keys = {} @@ -157,15 +158,15 @@ describe('meta-keys #8226 #13042', function() end) ]] - -- is reinterpreted as " - feed('qrviw"ayc$FOO.apq') + -- and are reinterpreted as " and … + feed('c$FOO.apA.ap') expect([[ - FOO.foo + FOO.foo.foo bar baz]]) - -- vim.on_key() callback should only receive " - eq('qrviw"ayc$FOO."apq', exec_lua [[return table.concat(keys, '')]]) - eq('qrviw"ayc$FOO."apq', exec_lua [[return table.concat(typed, '')]]) + -- vim.on_key() callback should only receive " and … + eq('c$FOO."apA."ap', exec_lua [[return table.concat(keys, '')]]) + eq('c$FOO."apA.…ap', exec_lua [[return table.concat(typed, '')]]) end) end) -- cgit From 970a27927eb31bdc735f0d7d5e3d07784486c6de Mon Sep 17 00:00:00 2001 From: Amit Singh Date: Thu, 11 Jul 2024 15:56:52 +0530 Subject: fix(lua)!: do not use typed table for empty dict Problem: Empty dictionaries are converted into typed tables of the form `{ [true] = 6}` instead of an empty dictionary representation `{}`. This leads to incorrect table representation, along with failure in JSON encoding of such tables as currently tables with only string and number type keys can be encoded. Solution: The typed table logic has been removed from `nlua_push_Dictionary`. The typed table logic is required only for float value conversions which is already handled in `nlua_push_Float`. So, it is(was) no longer required here. Fixes neovim/neovim#29218 --- test/functional/api/vim_spec.lua | 2 ++ test/functional/lua/vim_spec.lua | 3 +-- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'test/functional') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 86ea8679b5..bd16f0785b 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -1500,6 +1500,8 @@ describe('API', function() eq('Dictionary 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' }) diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 03c743c9ae..b0720e6a94 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -1205,8 +1205,7 @@ describe('lua stdlib', function() ]]) eq(true, exec_lua([[return next(vim.fn.FooFunc(3)) == nil ]])) eq(3, eval('g:test')) - -- compat: nvim_call_function uses "special" value for empty dict - eq(true, exec_lua([[return next(vim.api.nvim_call_function("FooFunc", {5})) == true ]])) + eq(true, exec_lua([[return vim.tbl_isempty(vim.api.nvim_call_function("FooFunc", {5}))]])) eq(5, eval('g:test')) eq({ 2, 'foo', true }, exec_lua([[return vim.fn.VarArg(2, "foo", true)]])) -- cgit From c31f64dd4d1aa0b89ed76c4e808d664b4f349f50 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 14 Jul 2024 05:54:31 +0800 Subject: vim-patch:9.1.0577: Unnecessary checks for v:sizeoflong in test_put.vim Problem: Unnecessary checks for v:sizeoflong in test_put.vim. They are no longer necessary as patch 8.2.3661 has changed the count to be within 32-bit integer limit. Solution: Remove the checks (zeertzjq). closes: vim/vim#15239 https://github.com/vim/vim/commit/69a28f6c0861523b1a9c565b3c882f439ae73ef4 --- test/functional/legacy/put_spec.lua | 41 ------------------------------------- 1 file changed, 41 deletions(-) (limited to 'test/functional') diff --git a/test/functional/legacy/put_spec.lua b/test/functional/legacy/put_spec.lua index 587424da10..8b9b495679 100644 --- a/test/functional/legacy/put_spec.lua +++ b/test/functional/legacy/put_spec.lua @@ -1,52 +1,11 @@ -local t = require('test.testutil') local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') local clear = n.clear -local exec_lua = n.exec_lua -local api = n.api local source = n.source -local eq = t.eq - -local function sizeoflong() - if not exec_lua('return pcall(require, "ffi")') then - pending('missing LuaJIT FFI') - end - return exec_lua('return require("ffi").sizeof(require("ffi").typeof("long"))') -end describe('put', function() before_each(clear) - after_each(function() - eq({}, api.nvim_get_vvar('errors')) - end) - - it('very large count 64-bit', function() - if sizeoflong() < 8 then - pending('Skipped: only works with 64 bit long ints') - end - - source [[ - new - let @" = repeat('x', 100) - call assert_fails('norm 999999999p', 'E1240:') - bwipe! - ]] - end) - - it('very large count (visual block) 64-bit', function() - if sizeoflong() < 8 then - pending('Skipped: only works with 64 bit long ints') - end - - source [[ - new - call setline(1, repeat('x', 100)) - exe "norm \$y" - call assert_fails('norm 999999999p', 'E1240:') - bwipe! - ]] - end) -- oldtest: Test_put_other_window() it('above topline in buffer in two splits', function() -- cgit From 6276fce11e1d1d344f988ebfc8857df7d4f1a8bd Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 13 Jul 2024 09:58:54 +0800 Subject: test(old): enable Test_address_line_overflow() Nvim doesn't use atol() in getdigits() and doesn't need to check for size of long. --- test/functional/legacy/excmd_spec.lua | 31 ------------------------------- 1 file changed, 31 deletions(-) (limited to 'test/functional') diff --git a/test/functional/legacy/excmd_spec.lua b/test/functional/legacy/excmd_spec.lua index de3d498f27..753a45ee05 100644 --- a/test/functional/legacy/excmd_spec.lua +++ b/test/functional/legacy/excmd_spec.lua @@ -5,45 +5,14 @@ local Screen = require('test.functional.ui.screen') local clear = n.clear local command = n.command local exec = n.exec -local exec_lua = n.exec_lua local expect_exit = n.expect_exit local feed = n.feed local fn = n.fn -local api = n.api local read_file = t.read_file -local source = n.source local eq = t.eq local write_file = t.write_file local is_os = t.is_os -local function sizeoflong() - if not exec_lua('return pcall(require, "ffi")') then - pending('missing LuaJIT FFI') - end - return exec_lua('return require("ffi").sizeof(require("ffi").typeof("long"))') -end - -describe('Ex command', function() - before_each(clear) - after_each(function() - eq({}, api.nvim_get_vvar('errors')) - end) - - it('checks for address line overflow', function() - if sizeoflong() < 8 then - pending('Skipped: only works with 64 bit long ints') - end - - source [[ - new - call setline(1, 'text') - call assert_fails('|.44444444444444444444444', 'E1247:') - call assert_fails('|.9223372036854775806', 'E1247:') - bwipe! - ]] - end) -end) - describe(':confirm command dialog', function() local screen -- cgit From 5531c95101b7656416c97acdd4acb3173d09f64c Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 14 Jul 2024 05:58:32 +0800 Subject: vim-patch:8.2.4065: computation overflow with large cound for :yank Problem: Computation overflow with large cound for :yank. Solution: Avoid an overflow. https://github.com/vim/vim/commit/3cf21b305104e91a28e4ce3a473672b2e88a9469 Co-authored-by: Bram Moolenaar --- test/functional/ex_cmds/excmd_spec.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'test/functional') diff --git a/test/functional/ex_cmds/excmd_spec.lua b/test/functional/ex_cmds/excmd_spec.lua index 20ebb2dedb..923bb99eeb 100644 --- a/test/functional/ex_cmds/excmd_spec.lua +++ b/test/functional/ex_cmds/excmd_spec.lua @@ -29,13 +29,13 @@ describe('Ex cmds', function() ':tabnext 9999999999999999999999999999999999999999', 'Vim(tabnext):E475: Invalid argument: 9999999999999999999999999999999999999999' ) - check_excmd_err( - ':N 9999999999999999999999999999999999999999', - 'Vim(Next):E939: Positive count required' + eq( + 'Vim(Next):E163: There is only one file to edit', + pcall_err(command, ':N 9999999999999999999999999999999999999999') ) check_excmd_err( ':bdelete 9999999999999999999999999999999999999999', - 'Vim(bdelete):E939: Positive count required' + 'Vim(bdelete):E516: No buffers were deleted' ) eq( 'Vim(menu):E329: No menu "9999999999999999999999999999999999999999"', -- cgit From c8401515cdaad20220e30f5a0c39ddb7bae77f5e Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 14 Jul 2024 16:28:05 +0800 Subject: vim-patch:9.1.0582: Printed line doesn't overwrite colon when pressing Enter in Ex mode Problem: Printed line no longer overwrites colon when pressing Enter in Ex mode (after 9.1.0573). Solution: Restore the behavior of pressing Enter in Ex mode. (zeertzjq) closes: vim/vim#15258 https://github.com/vim/vim/commit/7d664bf0eb2cb25cb77933c8b7f11ca09929e7b8 --- test/functional/legacy/ex_mode_spec.lua | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'test/functional') diff --git a/test/functional/legacy/ex_mode_spec.lua b/test/functional/legacy/ex_mode_spec.lua index 574c3e4069..e033898d7a 100644 --- a/test/functional/legacy/ex_mode_spec.lua +++ b/test/functional/legacy/ex_mode_spec.lua @@ -48,7 +48,7 @@ describe('Ex mode', function() command('set noincsearch nohlsearch inccommand=') local screen = Screen.new(60, 6) screen:attach() - command([[call setline(1, ['foo foo', 'foo foo', 'foo foo'])]]) + command([[call setline(1, repeat(['foo foo'], 4))]]) command([[set number]]) feed('gQ') screen:expect([[ @@ -110,12 +110,24 @@ describe('Ex mode', function() :^ | ]]) + -- The printed line should overwrite the colon + feed('') + screen:expect([[ + {8: 2 }foo foo | + ^^^q | + {8: 2 }foo foo | + {8: 3 }foo foo | + {8: 4 }foo foo | + :^ | + ]]) + feed(':vi') screen:expect([[ {8: 1 }foo bar | {8: 2 }foo foo | - {8: 3 }^foo foo | - {1:~ }|*2 + {8: 3 }foo foo | + {8: 4 }^foo foo | + {1:~ }| | ]]) end) -- cgit From 594c7f3d77262a1222c9786d86353a0595f2894c Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 15 Jul 2024 18:35:20 +0800 Subject: fix(ui): avoid ambiguity about last chunk when flushing halfway (#29718) --- test/functional/terminal/testutil.lua | 2 +- test/functional/terminal/tui_spec.lua | 41 +++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/terminal/testutil.lua b/test/functional/terminal/testutil.lua index 45c73b1dc6..7eb4af4940 100644 --- a/test/functional/terminal/testutil.lua +++ b/test/functional/terminal/testutil.lua @@ -169,7 +169,7 @@ local function setup_child_nvim(args, opts) env.VIMRUNTIME = os.getenv('VIMRUNTIME') end - return screen_setup(0, argv, opts.cols, env) + return screen_setup(opts.extra_rows, argv, opts.cols, env) end return { diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 5269af760a..3e0b907ea2 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -2199,6 +2199,47 @@ describe('TUI', function() } end) + it('draws screen lines with leading spaces correctly #29711', function() + local screen = tt.setup_child_nvim({ + '-u', + 'NONE', + '-i', + 'NONE', + '--cmd', + 'set foldcolumn=6 | call setline(1, ["", repeat("aabb", 1000)]) | echo 42', + }, { extra_rows = 10, cols = 66 }) + screen:expect { + grid = [[ + | + aabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabb|*12 + aabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabba@@@| + [No Name] [+] 1,0-1 Top| + 42 | + -- TERMINAL -- | + ]], + attr_ids = {}, + } + feed_data('\12') -- Ctrl-L + -- The first line counts as 3 cells. + -- For the second line, 6 repeated spaces at the start counts as 2 cells, + -- so each screen line of the second line counts as 62 cells. + -- After drawing the first line and 8 screen lines of the second line, + -- 3 + 8 * 62 = 499 cells have been counted. + -- The 6 repeated spaces at the start of the next screen line exceeds the + -- 500-cell limit, so the buffer is flushed after these spaces. + screen:expect { + grid = [[ + | + aabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabb|*12 + aabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabba@@@| + [No Name] [+] 1,0-1 Top| + | + -- TERMINAL -- | + ]], + attr_ids = {}, + } + end) + it('no heap-buffer-overflow when changing &columns', function() -- Set a different bg colour and change $TERM to something dumber so the `print_spaces()` -- codepath in `clear_region()` is hit. -- cgit From 118ae7e5ed6cfab6a49ec70c21da2b850161289c Mon Sep 17 00:00:00 2001 From: altermo <107814000+altermo@users.noreply.github.com> Date: Thu, 11 Jul 2024 18:16:51 +0200 Subject: fix(tohtml): support ranges again --- test/functional/plugin/tohtml_spec.lua | 38 ++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'test/functional') diff --git a/test/functional/plugin/tohtml_spec.lua b/test/functional/plugin/tohtml_spec.lua index be5bada901..827db8c0f3 100644 --- a/test/functional/plugin/tohtml_spec.lua +++ b/test/functional/plugin/tohtml_spec.lua @@ -176,6 +176,44 @@ describe(':TOhtml', function() }, fn.readfile(out_file)) end) + it('expected internal html generated from range', function() + insert([[ + line1 + line2 + line3 + ]]) + local ns = api.nvim_create_namespace '' + api.nvim_buf_set_extmark(0, ns, 0, 0, { end_col = 1, end_row = 1, hl_group = 'Visual' }) + exec('set termguicolors') + local bg = fn.synIDattr(fn.hlID('Normal'), 'bg#', 'gui') + local fg = fn.synIDattr(fn.hlID('Normal'), 'fg#', 'gui') + exec_lua [[ + local html = vim.cmd'2,2TOhtml' + ]] + local out_file = api.nvim_buf_get_name(api.nvim_get_current_buf()) + eq({ + '', + '', + '', + '', + '', + (''):format(api.nvim_get_var('colors_name')), + '', + '', + '', + '
',
+      'line2',
+      '',
+      '
', + '', + '', + }, fn.readfile(out_file)) + end) + it('highlight attributes generated', function() --Make sure to uncomment the attribute in `html_syntax_match()` exec('hi LINE gui=' .. table.concat({ -- cgit From 5fe4ce6678c0b531487e4d9836774464b5ec56ed Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Tue, 16 Jul 2024 10:30:22 -0700 Subject: fix(snippet): modify base indentation when there's actually whitespace (#29670) --- test/functional/lua/snippet_spec.lua | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'test/functional') diff --git a/test/functional/lua/snippet_spec.lua b/test/functional/lua/snippet_spec.lua index bca0a59cb4..eb2f17216c 100644 --- a/test/functional/lua/snippet_spec.lua +++ b/test/functional/lua/snippet_spec.lua @@ -58,7 +58,13 @@ describe('vim.snippet', function() end) it('adds indentation based on the start of snippet lines', function() + local curbuf = api.nvim_get_current_buf() + test_expand_success({ 'if $1 then', ' $0', 'end' }, { 'if then', ' ', 'end' }) + + -- Regression test: #29658 + api.nvim_buf_set_lines(curbuf, 0, -1, false, {}) + test_expand_success({ '${1:foo^bar}\n' }, { 'foo^bar', '' }) end) it('replaces tabs with spaces when expandtab is set', function() -- cgit From f9a49fab0c9062cb0e5ed8fbb26579efda0e7a30 Mon Sep 17 00:00:00 2001 From: luukvbaal Date: Wed, 17 Jul 2024 02:53:10 +0200 Subject: fix(column): modifying a sign should update placed signs (#29750) Problem: Modifying a sign no longer updates already placed signs. Solution: Loop over (newly-exposed) placed decorations when modifying a sign definition. Update placed decor if it belongs to the sign that is modified. --- test/functional/legacy/signs_spec.lua | 50 ++++++++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 3 deletions(-) (limited to 'test/functional') diff --git a/test/functional/legacy/signs_spec.lua b/test/functional/legacy/signs_spec.lua index 614673ee3c..61eba1e559 100644 --- a/test/functional/legacy/signs_spec.lua +++ b/test/functional/legacy/signs_spec.lua @@ -1,13 +1,14 @@ -- Tests for signs local n = require('test.functional.testnvim')() +local Screen = require('test.functional.ui.screen') -local clear, command, expect = n.clear, n.command, n.expect +local clear, command, exec, expect, feed = n.clear, n.command, n.exec, n.expect, n.feed describe('signs', function() - setup(clear) + before_each(clear) - it('is working', function() + it('are working', function() command('sign define JumpSign text=x') command([[exe 'sign place 42 line=2 name=JumpSign buffer=' . bufnr('')]]) -- Split the window to the bottom to verify :sign-jump will stay in the current @@ -21,4 +22,47 @@ describe('signs', function() 2]]) end) + + -- oldtest: Test_sign_cursor_position() + it('are drawn correctly', function() + local screen = Screen.new(75, 6) + screen:attach() + exec([[ + call setline(1, [repeat('x', 75), 'mmmm', 'yyyy']) + call cursor(2,1) + sign define s1 texthl=Search text==> + redraw + sign place 10 line=2 name=s1 + ]]) + screen:expect([[ + {7: }xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + {7: }xx | + {10:=>}^mmmm | + {7: }yyyy | + {1:~ }| + | + ]]) + + -- Change the sign text + command('sign define s1 text=-)') + screen:expect([[ + {7: }xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + {7: }xx | + {10:-)}^mmmm | + {7: }yyyy | + {1:~ }| + | + ]]) + + -- update cursor position calculation + feed('lh') + command('sign unplace 10') + screen:expect([[ + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + ^mmmm | + yyyy | + {1:~ }|*2 + | + ]]) + end) end) -- cgit From 4025c2aa5f788ba2772d8f0dd3f7add499333878 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 17 Jul 2024 09:20:41 +0800 Subject: vim-patch:8.2.0281: two placed signs in the same line are not combined (#29757) Problem: Two placed signs in the same line are not combined. E.g. in the terminal debugger a breakpoint and the PC cannot be both be displayed. Solution: Combine the sign column and line highlight attributes. https://github.com/vim/vim/commit/a2f6e42ded067df8ee682c15aa246491a389b1a0 Nvim already does this in decor_redraw_signs(). Co-authored-by: Bram Moolenaar --- test/functional/legacy/signs_spec.lua | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'test/functional') diff --git a/test/functional/legacy/signs_spec.lua b/test/functional/legacy/signs_spec.lua index 61eba1e559..27145f4c91 100644 --- a/test/functional/legacy/signs_spec.lua +++ b/test/functional/legacy/signs_spec.lua @@ -31,6 +31,7 @@ describe('signs', function() call setline(1, [repeat('x', 75), 'mmmm', 'yyyy']) call cursor(2,1) sign define s1 texthl=Search text==> + sign define s2 linehl=Pmenu redraw sign place 10 line=2 name=s1 ]]) @@ -54,8 +55,20 @@ describe('signs', function() | ]]) + -- Also place a line HL sign + command('sign place 11 line=2 name=s2') + screen:expect([[ + {7: }xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + {7: }xx | + {10:-)}{4:^mmmm }| + {7: }yyyy | + {1:~ }| + | + ]]) + -- update cursor position calculation feed('lh') + command('sign unplace 11') command('sign unplace 10') screen:expect([[ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| -- cgit From bc2bd25f8e7123c335806832f29903f0e18d6914 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 17 Jul 2024 22:39:25 +0800 Subject: test: fix reporting "no flush received" too early (#29735) --- test/functional/ui/screen.lua | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index 932ddb070a..f1891b608e 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -788,7 +788,9 @@ function Screen:_wait(check, flags) end local eof = run_session(self._session, flags.request_cb, notification_cb, nil, minimal_timeout) if not did_flush then - err = 'no flush received' + if eof then + err = 'no flush received' + end elseif not checked then err = check() if not err and flags.unchanged then @@ -801,6 +803,9 @@ function Screen:_wait(check, flags) did_minimal_timeout = true eof = run_session(self._session, flags.request_cb, notification_cb, nil, timeout - minimal_timeout) + if not did_flush then + err = 'no flush received' + end end local did_warn = false -- cgit From e29f245a10821fcce454f7ede684aa0dd64efc33 Mon Sep 17 00:00:00 2001 From: Amit Singh <29333147+amitds1997@users.noreply.github.com> Date: Wed, 17 Jul 2024 20:14:53 +0530 Subject: fix(lsp): inlay hints are rendered in the correct order (#29707) Problem: When there are multiple inlay hints present at the same position, they should be rendered in the order they are received in the response from LSP as per the LSP spec. Currently, this is not respected. Solution: Gather all hints for a given position, and then set it in a single extmark call instead of multiple set_extmark calls. This leads to fewer extmark calls and correct inlay hints being rendered. --- test/functional/plugin/lsp/inlay_hint_spec.lua | 117 ++++++++++++++++++++----- 1 file changed, 94 insertions(+), 23 deletions(-) (limited to 'test/functional') diff --git a/test/functional/plugin/lsp/inlay_hint_spec.lua b/test/functional/plugin/lsp/inlay_hint_spec.lua index d3b5ae0e4e..00f79b9963 100644 --- a/test/functional/plugin/lsp/inlay_hint_spec.lua +++ b/test/functional/plugin/lsp/inlay_hint_spec.lua @@ -12,7 +12,8 @@ local api = n.api local clear_notrace = t_lsp.clear_notrace local create_server_definition = t_lsp.create_server_definition -local text = dedent([[ +describe('vim.lsp.inlay_hint', function() + local text = dedent([[ auto add(int a, int b) { return a + b; } int main() { @@ -22,7 +23,7 @@ int main() { } }]]) -local response = [==[ + local response = [==[ [ {"kind":1,"paddingLeft":false,"label":"-> int","position":{"character":22,"line":0},"paddingRight":false}, {"kind":2,"paddingLeft":false,"label":"a:","position":{"character":15,"line":5},"paddingRight":true}, @@ -30,7 +31,7 @@ local response = [==[ ] ]==] -local grid_without_inlay_hints = [[ + local grid_without_inlay_hints = [[ auto add(int a, int b) { return a + b; } | | int main() { | @@ -42,7 +43,7 @@ local grid_without_inlay_hints = [[ | ]] -local grid_with_inlay_hints = [[ + local grid_with_inlay_hints = [[ auto add(int a, int b){1:-> int} { return a + b; } | | int main() { | @@ -54,16 +55,16 @@ local grid_with_inlay_hints = [[ | ]] ---- @type test.functional.ui.screen -local screen -before_each(function() - clear_notrace() - screen = Screen.new(50, 9) - screen:attach() + --- @type test.functional.ui.screen + local screen + before_each(function() + clear_notrace() + screen = Screen.new(50, 9) + screen:attach() - exec_lua(create_server_definition) - exec_lua( - [[ + exec_lua(create_server_definition) + exec_lua( + [[ local response = ... server = _create_server({ capabilities = { @@ -81,19 +82,18 @@ before_each(function() client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) ]], - response - ) + response + ) - insert(text) - exec_lua([[vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })]]) - screen:expect({ grid = grid_with_inlay_hints }) -end) + insert(text) + exec_lua([[vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })]]) + screen:expect({ grid = grid_with_inlay_hints }) + end) -after_each(function() - api.nvim_exec_autocmds('VimLeavePre', { modeline = false }) -end) + after_each(function() + api.nvim_exec_autocmds('VimLeavePre', { modeline = false }) + end) -describe('vim.lsp.inlay_hint', function() it('clears inlay hints when sole client detaches', function() exec_lua([[vim.lsp.stop_client(client_id)]]) screen:expect({ grid = grid_without_inlay_hints, unchanged = true }) @@ -258,3 +258,74 @@ describe('vim.lsp.inlay_hint', function() end) end) end) + +describe('Inlay hints handler', function() + local text = dedent([[ +test text + ]]) + + local response = [==[ + [ + { "position": { "line": 0, "character": 0 }, "label": "0" }, + { "position": { "line": 0, "character": 0 }, "label": "1" }, + { "position": { "line": 0, "character": 0 }, "label": "2" }, + { "position": { "line": 0, "character": 0 }, "label": "3" }, + { "position": { "line": 0, "character": 0 }, "label": "4" } + ] + ]==] + + local grid_without_inlay_hints = [[ + test text | + ^ | + | +]] + + local grid_with_inlay_hints = [[ + {1:01234}test text | + ^ | + | +]] + + --- @type test.functional.ui.screen + local screen + before_each(function() + clear_notrace() + screen = Screen.new(50, 3) + screen:attach() + + exec_lua(create_server_definition) + exec_lua( + [[ + local response = ... + server = _create_server({ + capabilities = { + inlayHintProvider = true, + }, + handlers = { + ['textDocument/inlayHint'] = function(_, _, callback) + callback(nil, vim.json.decode(response)) + end, + } + }) + + bufnr = vim.api.nvim_get_current_buf() + vim.api.nvim_win_set_buf(0, bufnr) + + client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) + ]], + response + ) + insert(text) + end) + + it('renders hints with same position in received order', function() + exec_lua([[vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })]]) + screen:expect({ grid = grid_with_inlay_hints }) + exec_lua([[vim.lsp.stop_client(client_id)]]) + screen:expect({ grid = grid_without_inlay_hints, unchanged = true }) + end) + + after_each(function() + api.nvim_exec_autocmds('VimLeavePre', { modeline = false }) + end) +end) -- cgit From 6720bd440f19747585713924de77e6231bdc3e42 Mon Sep 17 00:00:00 2001 From: Rustum Zia Date: Wed, 10 Jul 2024 17:42:37 -0400 Subject: fix: assert failure in VimL expression parser --- test/functional/api/vim_spec.lua | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'test/functional') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index bd16f0785b..17be8098aa 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -2938,6 +2938,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(':=') + api.nvim_input('1bork/') + assert_alive() + end) + require('test.unit.viml.expressions.parser_tests')(it, _check_parsing, hl, fmtn) end) -- cgit From 35b35cb93cb54d2a9b7f881b930ba42186e57d23 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 19 Jul 2024 11:54:42 +0800 Subject: vim-patch:9.1.0601: Wrong cursor position with 'breakindent' when wide char doesn't fit (#29793) Problem: Wrong cursor position with 'breakindent' when a double-width character doesn't fit in a screen line (mikoto2000) Solution: Include the width of the 'breakindent' properly. (zeertzjq) fixes: vim/vim#15289 closes: vim/vim#15290 https://github.com/vim/vim/commit/b5d6b5caac752fe15856e37fd3abc5459292d4b8 --- test/functional/ui/decorations_spec.lua | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'test/functional') diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua index 318dc8c197..eda95b8991 100644 --- a/test/functional/ui/decorations_spec.lua +++ b/test/functional/ui/decorations_spec.lua @@ -4027,11 +4027,23 @@ describe('decorations: inline virtual text', function() normal! $ ]]) api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { ('b'):rep(9) } }, virt_text_pos = 'inline' }) - screen:expect{grid=[[ + screen:expect([[ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbb{1:>}| 口1234^5 | | - ]]} + ]]) + feed('g0') + screen:expect([[ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbb{1:>}| + ^口12345 | + | + ]]) + command('set showbreak=+++') + screen:expect([[ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbb{1:>}| + {1:+++}^口12345 | + | + ]]) end) end) -- cgit From 012db2b0f5099909a62c56651acb4dcf62328fc9 Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Sun, 30 Jun 2024 02:23:09 +0200 Subject: fix(marks): revalidate marks whose position did not change Problem: Marks whose position did not change with the action that invalidated them (right_gravity = false) are not revalidated upon undo. Solution: Remove early return when restoring a marks saved position so that it is still revalidated. Add "move" guards instead. --- test/functional/api/extmark_spec.lua | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) (limited to 'test/functional') diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index 7b2fe209ba..a7f4ba25e0 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 -- cgit From 89f9f168a5c4317bcc71cb61e64a1dd63d17a377 Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Mon, 20 May 2024 20:21:11 +0200 Subject: fix(api): alloc and draw cursor window in nvim__redraw Problem: Unable to move cursor to recently opened window. Solution: Make sure uninitialized window is drawn before trying to move the cursor to it. --- test/functional/api/vim_spec.lua | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) (limited to 'test/functional') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index bd16f0785b..035c8f70de 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -4969,12 +4969,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()') + 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') @@ -4983,11 +5000,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({ -- cgit From 862338255da6dc08ae4f4f78db0034c81e3cdf38 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Wed, 24 Jul 2024 15:06:01 +0200 Subject: fix(runtime): sync bundled treesitter queries --- test/functional/treesitter/highlight_spec.lua | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/treesitter/highlight_spec.lua b/test/functional/treesitter/highlight_spec.lua index 3774ff8d54..b0ac180738 100644 --- a/test/functional/treesitter/highlight_spec.lua +++ b/test/functional/treesitter/highlight_spec.lua @@ -1052,10 +1052,15 @@ describe('treesitter highlighting (markdown)', function() insert(string.format('[This link text](%s) is a hyperlink.', url)) screen:add_extra_attr_ids({ [100] = { foreground = Screen.colors.DarkCyan, url = 'https://example.com' }, + [101] = { + foreground = Screen.colors.SlateBlue, + url = 'https://example.com', + underline = true, + }, }) screen:expect({ grid = [[ - {25:[}{100:This link text}{25:](}{28:https://example.com}{25:)} is| + {25:[}{100:This link text}{25:](}{101:https://example.com}{25:)} is| a hyperlink^. | {1:~ }|*3 | -- cgit From b02c83941493db79e4ab7ba23adb665d4528f791 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Wed, 24 Jul 2024 09:04:09 -0500 Subject: fix(tui): set id parameter in OSC 8 sequences (#29840) The id parameter is used to communicate to the terminal that two URLs are the same. Without an id, the terminal must rely on heuristics to determine which cells belong together to make a single hyperlink. See the relevant section in the spec [1] for more details. [1]: https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda#hover-underlining-and-the-id-parameter --- test/functional/terminal/tui_spec.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'test/functional') diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 3e0b907ea2..50199bd83d 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -1968,9 +1968,9 @@ describe('TUI', function() if not req then return end - local url = req:match('\027]8;;(.*)$') - if url ~= nil then - table.insert(_G.urls, url) + local id, url = req:match('\027]8;id=(%d+);(.*)$') + if id ~= nil and url ~= nil then + table.insert(_G.urls, { id = tonumber(id), url = url }) end end, }) @@ -1984,7 +1984,7 @@ describe('TUI', function() }) ]]) retry(nil, 1000, function() - eq({ 'https://example.com', '' }, exec_lua([[return _G.urls]])) + eq({ { id = 0xE1EA0000, url = 'https://example.com' } }, exec_lua([[return _G.urls]])) end) end) end) -- cgit From 5af9c065ada5600a076e24ca899da38b299c81e6 Mon Sep 17 00:00:00 2001 From: luukvbaal Date: Fri, 26 Jul 2024 03:04:17 +0200 Subject: fix(decor): don't draw invalidated virtual lines (#29858) --- test/functional/ui/decorations_spec.lua | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'test/functional') diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua index eda95b8991..c86b68994d 100644 --- a/test/functional/ui/decorations_spec.lua +++ b/test/functional/ui/decorations_spec.lua @@ -4948,6 +4948,28 @@ if (h->n_buckets < new_n_buckets) { // expand | ]]) end) + + it('not drawn when invalid', function() + api.nvim_buf_set_lines(0, 0, -1, false, { 'foo', 'bar' }) + api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_lines = {{{'VIRT1'}}}, invalidate = true }) + screen:expect({ + grid = [[ + ^foo | + VIRT1 | + bar | + {1:~ }|*8 + | + ]] + }) + feed('dd') + screen:expect({ + grid = [[ + ^bar | + {1:~ }|*10 + | + ]] + }) + end) end) describe('decorations: signs', function() -- cgit From 0dfcf3fe12ace3116bdffbbfc6875c67023eb8f2 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 26 Jul 2024 10:01:12 +0800 Subject: fix(plines): don't count invalidated virt text in char size (#29863) Also: - Remove mt_end() and MT_FLAG_DECOR_VIRT_TEXT_INLINE checks, as they are already checked by marktree_itr_check_filter(). - Move ns_in_win() to the last check in decor_redraw_col(). --- test/functional/ui/decorations_spec.lua | 62 +++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) (limited to 'test/functional') diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua index c86b68994d..49ba4a7096 100644 --- a/test/functional/ui/decorations_spec.lua +++ b/test/functional/ui/decorations_spec.lua @@ -4045,6 +4045,68 @@ describe('decorations: inline virtual text', function() | ]]) end) + + it('cursor position is correct if end_row or end_col is specified', function() + screen:try_resize(50, 8) + api.nvim_buf_set_lines(0, 0, -1, false, { ('a'):rep(48), ('b'):rep(48), ('c'):rep(48), ('d'):rep(48) }) + api.nvim_buf_set_extmark(0, ns, 0, 0, {end_row = 2, virt_text_pos = 'inline', virt_text = {{'I1', 'NonText'}}}) + api.nvim_buf_set_extmark(0, ns, 3, 0, {end_col = 2, virt_text_pos = 'inline', virt_text = {{'I2', 'NonText'}}}) + feed('$') + screen:expect([[ + {1:I1}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa^a| + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb | + cccccccccccccccccccccccccccccccccccccccccccccccc | + {1:I2}dddddddddddddddddddddddddddddddddddddddddddddddd| + {1:~ }|*3 + | + ]]) + feed('j') + screen:expect([[ + {1:I1}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb^b | + cccccccccccccccccccccccccccccccccccccccccccccccc | + {1:I2}dddddddddddddddddddddddddddddddddddddddddddddddd| + {1:~ }|*3 + | + ]]) + feed('j') + screen:expect([[ + {1:I1}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb | + ccccccccccccccccccccccccccccccccccccccccccccccc^c | + {1:I2}dddddddddddddddddddddddddddddddddddddddddddddddd| + {1:~ }|*3 + | + ]]) + feed('j') + screen:expect([[ + {1:I1}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb | + cccccccccccccccccccccccccccccccccccccccccccccccc | + {1:I2}ddddddddddddddddddddddddddddddddddddddddddddddd^d| + {1:~ }|*3 + | + ]]) + end) + + it('cursor position is correct with invalidated inline virt text', function() + screen:try_resize(50, 8) + api.nvim_buf_set_lines(0, 0, -1, false, { ('a'):rep(48), ('b'):rep(48) }) + api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text_pos = 'inline', virt_text = {{'INLINE', 'NonText'}}, invalidate = true }) + screen:expect([[ + {1:INLINE}^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + aaaa | + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb | + {1:~ }|*4 + | + ]]) + feed('dd$') + screen:expect([[ + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb^b | + {1:~ }|*6 + | + ]]) + end) end) describe('decorations: virtual lines', function() -- cgit From 8bdfc2ab2b2565f06d41921d57a0c6184a097271 Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Fri, 26 Jul 2024 19:19:39 -0700 Subject: fix(version): return nil with empty string --- test/functional/lua/version_spec.lua | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'test/functional') diff --git a/test/functional/lua/version_spec.lua b/test/functional/lua/version_spec.lua index 4ce8fb8dfe..c172555091 100644 --- a/test/functional/lua/version_spec.lua +++ b/test/functional/lua/version_spec.lua @@ -112,6 +112,10 @@ describe('version', function() assert(vim.version.range('1.2.3-alpha'):has('1.2.3-alpha')) assert(not vim.version.range('1.2.3-alpha'):has('1.2.3-beta')) end) + + it('returns nil with empty version', function() + eq(vim.version.parse(''), nil) + end) end) describe('cmp()', function() -- cgit From 5be5928771fa4423cd6468914aa698085f5f4656 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 27 Jul 2024 21:42:12 +0800 Subject: test(ui/popupmenu_spec): make highlights more consistent --- test/functional/ui/popupmenu_spec.lua | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'test/functional') diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index e005cfd2e6..02ac0ada22 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -1160,25 +1160,25 @@ describe('builtin popupmenu', function() screen = Screen.new(32, 20) screen:set_default_attr_ids({ -- popup selected item / scrollbar track - ['s'] = { background = Screen.colors.WebGray }, + s = { background = Screen.colors.Grey }, -- popup non-selected item - ['n'] = { background = Screen.colors.LightMagenta }, + n = { background = Screen.colors.Plum1 }, -- popup scrollbar knob - ['c'] = { background = Screen.colors.Grey0 }, + c = { background = Screen.colors.Black }, [1] = { bold = true, foreground = Screen.colors.Blue }, [2] = { bold = true }, [3] = { reverse = true }, [4] = { bold = true, reverse = true }, [5] = { bold = true, foreground = Screen.colors.SeaGreen }, - [6] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, + [6] = { foreground = Screen.colors.White, background = Screen.colors.Red }, [7] = { background = Screen.colors.Yellow }, -- Search [8] = { foreground = Screen.colors.Red }, - kn = { foreground = Screen.colors.Red, background = Screen.colors.Magenta }, ks = { foreground = Screen.colors.Red, background = Screen.colors.Grey }, - xn = { foreground = Screen.colors.White, background = Screen.colors.Magenta }, + kn = { foreground = Screen.colors.Red, background = Screen.colors.Plum1 }, xs = { foreground = Screen.colors.Black, background = Screen.colors.Grey }, - mn = { foreground = Screen.colors.Blue, background = Screen.colors.Magenta }, + xn = { foreground = Screen.colors.White, background = Screen.colors.Plum1 }, ms = { foreground = Screen.colors.Blue, background = Screen.colors.Grey }, + mn = { foreground = Screen.colors.Blue, background = Screen.colors.Plum1 }, }) screen:attach({ ext_multigrid = multigrid }) end) @@ -3558,7 +3558,7 @@ describe('builtin popupmenu', function() exec([[ set wildoptions=pum,fuzzy hi PmenuMatchSel guifg=Blue guibg=Grey - hi PmenuMatch guifg=Blue guibg=Magenta + hi PmenuMatch guifg=Blue guibg=Plum1 ]]) feed(':sign plc') @@ -4704,9 +4704,9 @@ describe('builtin popupmenu', function() -- oldtest: Test_pum_highlights_custom() it('custom highlight groups', function() exec([[ - hi PmenuKind guifg=Red guibg=Magenta + hi PmenuKind guifg=Red guibg=Plum1 hi PmenuKindSel guifg=Red guibg=Grey - hi PmenuExtra guifg=White guibg=Magenta + hi PmenuExtra guifg=White guibg=Plum1 hi PmenuExtraSel guifg=Black guibg=Grey ]]) feed('iaw') @@ -4758,7 +4758,7 @@ describe('builtin popupmenu', function() set omnifunc=Omni_test set completeopt=menu,noinsert,fuzzy hi PmenuMatchSel guifg=Blue guibg=Grey - hi PmenuMatch guifg=Blue guibg=Magenta + hi PmenuMatch guifg=Blue guibg=Plum1 ]]) feed('i') local pum_start = [[ -- cgit From 985c636aa6dfcec2a1b788549c3f3ac058c8d141 Mon Sep 17 00:00:00 2001 From: glepnir Date: Sat, 27 Jul 2024 18:14:22 +0800 Subject: test(ui/popupmenu_spec): add case of hl_group field in complete items Problem: Missing test case for hl_group field in complete items. Solution: Add a test case for hl_group field. --- test/functional/ui/popupmenu_spec.lua | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'test/functional') diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index 02ac0ada22..26110b559d 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -1179,6 +1179,8 @@ describe('builtin popupmenu', function() xn = { foreground = Screen.colors.White, background = Screen.colors.Plum1 }, ms = { foreground = Screen.colors.Blue, background = Screen.colors.Grey }, mn = { foreground = Screen.colors.Blue, background = Screen.colors.Plum1 }, + ds = { foreground = Screen.colors.DarkRed, background = Screen.colors.Grey }, + dn = { foreground = Screen.colors.DarkRed, background = Screen.colors.Plum1 }, }) screen:attach({ ext_multigrid = multigrid }) end) @@ -4931,6 +4933,35 @@ describe('builtin popupmenu', function() feed('') end) + + -- oldtest: Test_pum_extrahl() + it('custom hl_group override', function() + exec([[ + hi StrikeFake guifg=DarkRed + func CompleteFunc( findstart, base ) + if a:findstart + return 0 + endif + return { + \ 'words': [ + \ { 'word': 'aword1', 'menu': 'extra text 1', 'kind': 'W', 'hl_group': 'StrikeFake' }, + \ { 'word': 'aword2', 'menu': 'extra text 2', 'kind': 'W', }, + \ { 'word': '你好', 'menu': 'extra text 3', 'kind': 'W', 'hl_group': 'StrikeFake' }, + \]} + endfunc + set completeopt=menu + set completefunc=CompleteFunc + ]]) + feed('iaw') + screen:expect([[ + aword1^ | + {ds:aword1 W extra text 1 }{1: }| + {n:aword2 W extra text 2 }{1: }| + {dn:你好 W extra text 3 }{1: }| + {1:~ }|*15 + {2:-- }{5:match 1 of 3} | + ]]) + end) end end -- cgit From b8b0e9db3f91fbaa8835b90c683c33310064c8c8 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 27 Jul 2024 21:44:05 +0800 Subject: vim-patch:9.1.0629: Rename of pum hl_group is incomplete Problem: Rename of pum hl_group is incomplete in source. Solution: Also rename the test function. Rename to user_hlattr in code to avoid confusion with pum_extra. Add test with matched text highlighting (zeertzjq). closes: vim/vim#15348 https://github.com/vim/vim/commit/4100852e099133a0c9603e1087e5dc6d82001ce7 --- test/functional/ui/popupmenu_spec.lua | 55 +++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 3 deletions(-) (limited to 'test/functional') diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index 26110b559d..c73d5bf97a 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -1181,6 +1181,26 @@ describe('builtin popupmenu', function() mn = { foreground = Screen.colors.Blue, background = Screen.colors.Plum1 }, ds = { foreground = Screen.colors.DarkRed, background = Screen.colors.Grey }, dn = { foreground = Screen.colors.DarkRed, background = Screen.colors.Plum1 }, + ums = { + foreground = Screen.colors.Blue, + background = Screen.colors.Grey, + underline = true, + }, + umn = { + foreground = Screen.colors.Blue, + background = Screen.colors.Plum1, + underline = true, + }, + uds = { + foreground = Screen.colors.DarkRed, + background = Screen.colors.Grey, + underline = true, + }, + udn = { + foreground = Screen.colors.DarkRed, + background = Screen.colors.Plum1, + underline = true, + }, }) screen:attach({ ext_multigrid = multigrid }) end) @@ -4934,10 +4954,9 @@ describe('builtin popupmenu', function() feed('') end) - -- oldtest: Test_pum_extrahl() + -- oldtest: Test_pum_user_hl_group() it('custom hl_group override', function() exec([[ - hi StrikeFake guifg=DarkRed func CompleteFunc( findstart, base ) if a:findstart return 0 @@ -4951,8 +4970,15 @@ describe('builtin popupmenu', function() endfunc set completeopt=menu set completefunc=CompleteFunc + + hi StrikeFake guifg=DarkRed + func HlMatch() + hi PmenuMatchSel guifg=Blue guibg=Grey gui=underline + hi PmenuMatch guifg=Blue guibg=Plum1 gui=underline + endfunc ]]) - feed('iaw') + + feed('Saw') screen:expect([[ aword1^ | {ds:aword1 W extra text 1 }{1: }| @@ -4961,6 +4987,29 @@ describe('builtin popupmenu', function() {1:~ }|*15 {2:-- }{5:match 1 of 3} | ]]) + feed('') + + command('call HlMatch()') + + feed('Saw') + screen:expect([[ + aword1^ | + {uds:aw}{ds:ord1 W extra text 1 }{1: }| + {umn:aw}{n:ord2 W extra text 2 }{1: }| + {dn:你好 W extra text 3 }{1: }| + {1:~ }|*15 + {2:-- }{5:match 1 of 3} | + ]]) + feed('') + screen:expect([[ + aword2^ | + {udn:aw}{dn:ord1 W extra text 1 }{1: }| + {ums:aw}{s:ord2 W extra text 2 }{1: }| + {dn:你好 W extra text 3 }{1: }| + {1:~ }|*15 + {2:-- }{5:match 2 of 3} | + ]]) + feed('') end) end end -- cgit From bdff50dee56ebf6de58d58315920abf2f8e262f7 Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Sat, 27 Jul 2024 22:30:14 +0200 Subject: fix(lsp): revert text edit application order change (#29877) Reverts https://github.com/neovim/neovim/pull/29212 and adds a few additional test cases From the spec > All text edits ranges refer to positions in the document they are > computed on. They therefore move a document from state S1 to S2 without > describing any intermediate state. Text edits ranges must never overlap, > that means no part of the original document must be manipulated by more > than one edit. However, it is possible that multiple edits have the same > start position: multiple inserts, or any number of inserts followed by a > single remove or replace edit. If multiple inserts have the same > position, the order in the array defines the order in which the inserted > strings appear in the resulting text. The previous fix seems wrong. The important part: > If multiple inserts have the same position, the order in the array > defines the order in which the inserted strings appear in the > resulting text. Emphasis on _appear in the resulting text_ Which means that in: local edits1 = { make_edit(0, 3, 0, 3, { 'World' }), make_edit(0, 3, 0, 3, { 'Hello' }), } `World` must appear before `Hello` in the final text. That means the old logic was correct, and the fix was wrong. --- test/functional/plugin/lsp_spec.lua | 64 +++++++++++++++++++++++++++++++++---- 1 file changed, 58 insertions(+), 6 deletions(-) (limited to 'test/functional') diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 2b8a7aed9e..a7ba851215 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -1756,6 +1756,58 @@ describe('LSP', function() } end + describe('apply vscode text_edits', function() + it('single replace', function() + insert('012345678901234567890123456789') + local edits = { + make_edit(0, 3, 0, 6, { 'Hello' }), + } + exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + eq({ '012Hello678901234567890123456789' }, buf_lines(1)) + end) + it('two replaces', function() + insert('012345678901234567890123456789') + local edits = { + make_edit(0, 3, 0, 6, { 'Hello' }), + make_edit(0, 6, 0, 9, { 'World' }), + } + exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + eq({ '012HelloWorld901234567890123456789' }, buf_lines(1)) + end) + it('same start pos insert are kept in order', function() + insert('012345678901234567890123456789') + local edits1 = { + make_edit(0, 3, 0, 3, { 'World' }), + make_edit(0, 3, 0, 3, { 'Hello' }), + } + exec_lua('vim.lsp.util.apply_text_edits(...)', edits1, 1, 'utf-16') + eq({ '012WorldHello345678901234567890123456789' }, buf_lines(1)) + end) + it('same start pos insert and replace are kept in order', function() + insert('012345678901234567890123456789') + local edits1 = { + make_edit(0, 3, 0, 3, { 'World' }), + make_edit(0, 3, 0, 3, { 'Hello' }), + make_edit(0, 3, 0, 8, { 'No' }), + } + exec_lua('vim.lsp.util.apply_text_edits(...)', edits1, 1, 'utf-16') + eq({ '012WorldHelloNo8901234567890123456789' }, buf_lines(1)) + end) + it('multiline', function() + exec_lua([[ + vim.api.nvim_buf_set_lines(1, 0, 0, true, {' {', ' "foo": "bar"', ' }'}) + ]]) + eq({ ' {', ' "foo": "bar"', ' }', '' }, buf_lines(1)) + local edits = { + make_edit(0, 0, 3, 0, { '' }), + make_edit(3, 0, 3, 0, { '{\n' }), + make_edit(3, 0, 3, 0, { ' "foo": "bar"\n' }), + make_edit(3, 0, 3, 0, { '}\n' }), + } + exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + eq({ '{', ' "foo": "bar"', '}', '' }, buf_lines(1)) + end) + end) describe('apply_text_edits', function() before_each(function() insert(dedent([[ @@ -1794,9 +1846,9 @@ describe('LSP', function() } exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') eq({ - '3', - 'foo', - '12Fbar', + '', + '123', + 'fooFbar', '123irst guy', 'baz line of text', 'The next line of text', @@ -1818,9 +1870,9 @@ describe('LSP', function() } exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') eq({ - '3', - 'foo', - '12Fbar', + '', + '123', + 'fooFbar', '123irst guy', 'baz line of text', 'The next line of text', -- cgit From bd3b6ec8360e0dd6edfe74c3d0013fd2b98b989e Mon Sep 17 00:00:00 2001 From: Riley Bruins Date: Sun, 28 Jul 2024 13:23:40 -0700 Subject: feat(treesitter): add node_for_range function This is identical to `named_node_for_range` except that it includes anonymous nodes. This maintains consistency in the API because we already have `descendant_for_range` and `named_descendant_for_range`. --- test/functional/treesitter/language_spec.lua | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'test/functional') diff --git a/test/functional/treesitter/language_spec.lua b/test/functional/treesitter/language_spec.lua index 40c974beee..e71c39244f 100644 --- a/test/functional/treesitter/language_spec.lua +++ b/test/functional/treesitter/language_spec.lua @@ -148,4 +148,15 @@ describe('treesitter language API', function() eq('', exec_lua('return tostring(node)')) end) + + it('retrieve an anonymous node given a range', function() + insert([[vim.fn.input()]]) + + exec_lua([[ + langtree = vim.treesitter.get_parser(0, "lua") + node = langtree:node_for_range({0, 3, 0, 3}) + ]]) + + eq('.', exec_lua('return node:type()')) + end) end) -- cgit From 1af55bfcf21b9bc7594b9c5ee0c2f60cbb887654 Mon Sep 17 00:00:00 2001 From: Riley Bruins Date: Sun, 28 Jul 2024 13:30:33 -0700 Subject: feat(treesitter): allow get_node to return anonymous nodes Adds a new field `include_anonymous` to the `get_node` options to allow anonymous nodes to be returned. --- test/functional/treesitter/node_spec.lua | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'test/functional') diff --git a/test/functional/treesitter/node_spec.lua b/test/functional/treesitter/node_spec.lua index 96579f296b..6270ea3aa1 100644 --- a/test/functional/treesitter/node_spec.lua +++ b/test/functional/treesitter/node_spec.lua @@ -55,6 +55,23 @@ describe('treesitter node API', function() eq('identifier', lua_eval('node:type()')) end) + it('get_node() with anonymous nodes included', function() + insert([[print('test')]]) + + exec_lua([[ + parser = vim.treesitter.get_parser(0, 'lua') + tree = parser:parse()[1] + node = vim.treesitter.get_node({ + bufnr = 0, + pos = { 0, 6 }, -- on the first apostrophe + include_anonymous = true, + }) + ]]) + + eq("'", lua_eval('node:type()')) + eq(false, lua_eval('node:named()')) + end) + it('can move between siblings', function() insert([[ int main(int x, int y, int z) { -- cgit From 619cb143f93fbf75adde9710415a74d36c8eb63d Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 30 Jul 2024 13:38:13 +0800 Subject: vim-patch:9.1.0415: Some functions are not tested Problem: Some functions are not tested Solution: Add a few more tests, fix a few minor problems (Yegappan Lakshmanan) closes: vim/vim#14789 https://github.com/vim/vim/commit/fe424d13ef6e5486923f23f15bb6951e3079412e Co-authored-by: Yegappan Lakshmanan --- test/functional/legacy/edit_spec.lua | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'test/functional') diff --git a/test/functional/legacy/edit_spec.lua b/test/functional/legacy/edit_spec.lua index f3d18a2541..2d98188f9b 100644 --- a/test/functional/legacy/edit_spec.lua +++ b/test/functional/legacy/edit_spec.lua @@ -44,6 +44,12 @@ describe('edit', function() {1:~ }|*4 =^ | ]]) + feed([['r']]) + expect('r') + -- Test for inserting null and empty list + feed('a=v:_null_list') + feed('a=[]') + expect('r') end) -- oldtest: Test_edit_ctrl_r_failed() -- cgit From 573a71469d37cc35f72bfc929f4ce1156833df9f Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 17 Jul 2024 12:23:15 +0100 Subject: fix(scrollbind): properly take filler/virtual lines into account Problem: `'scrollbind'` does not work properly if the window being scrolled automatically contains any filler/virtual lines (except for diff filler lines). This is because when the scrollbind check is done, the logic only considers changes to topline which are represented as line numbers. Solution: Write the logic for determine the scroll amount to take into account filler/virtual lines. Fixes #29751 --- test/functional/testnvim.lua | 11 +- test/functional/ui/scrollbind_spec.lua | 442 +++++++++++++++++++++++++++++++++ 2 files changed, 452 insertions(+), 1 deletion(-) create mode 100644 test/functional/ui/scrollbind_spec.lua (limited to 'test/functional') diff --git a/test/functional/testnvim.lua b/test/functional/testnvim.lua index 5a9e7f8c29..66ce6daacb 100644 --- a/test/functional/testnvim.lua +++ b/test/functional/testnvim.lua @@ -835,9 +835,18 @@ function M.exec_capture(code) return M.api.nvim_exec2(code, { output = true }).output end ---- @param code string +--- @param code string|function --- @return any function M.exec_lua(code, ...) + if type(code) == 'function' then + return M.api.nvim_exec_lua( + [[ + local code = ... + return loadstring(code)(select(2, ...)) + ]], + { string.dump(code), ... } + ) + end return M.api.nvim_exec_lua(code, { ... }) end diff --git a/test/functional/ui/scrollbind_spec.lua b/test/functional/ui/scrollbind_spec.lua new file mode 100644 index 0000000000..9e70b25efa --- /dev/null +++ b/test/functional/ui/scrollbind_spec.lua @@ -0,0 +1,442 @@ +local t = require('test.testutil') +local n = require('test.functional.testnvim')() +local clear = n.clear +local Screen = require('test.functional.ui.screen') + +before_each(clear) + +describe('Scrollbind', function() + local screen --- @type test.functional.ui.screen + + before_each(function() + screen = Screen.new(40, 12) + screen:attach() + end) + + it('works with one buffer with virtual lines', function() + n.exec_lua(function() + local lines = {} --- @type string[] + + for i = 1, 20 do + lines[i] = tostring(i * 2 - 1) + end + + local ns = vim.api.nvim_create_namespace('test') + + vim.api.nvim_buf_set_lines(0, 0, -1, false, lines) + vim.bo.buftype = 'nofile' + + for i in ipairs(lines) do + vim.api.nvim_buf_set_extmark(0, ns, i - 1, 0, { + virt_lines = { { { tostring(2 * i) .. ' v' } } }, + }) + end + + vim.wo.scrollbind = true + vim.cmd.vsplit() + vim.wo.scrollbind = true + end) + + n.feed('') + + t.eq(5, n.api.nvim_get_option_value('scroll', {})) + + screen:expect({ + grid = [[ + 6 v │6 v | + 7 │7 | + 8 v │8 v | + 9 │9 | + 10 v │10 v | + ^11 │11 | + 12 v │12 v | + 13 │13 | + 14 v │14 v | + 15 │15 | + {3:[Scratch] }{2:[Scratch] }| + | + ]], + }) + + n.feed('') + + local line1_grid = [[ + ^1 │1 | + 2 v │2 v | + 3 │3 | + 4 v │4 v | + 5 │5 | + 6 v │6 v | + 7 │7 | + 8 v │8 v | + 9 │9 | + 10 v │10 v | + {3:[Scratch] }{2:[Scratch] }| + | + ]] + + screen:expect({ grid = line1_grid }) + + n.api.nvim_set_option_value('scroll', 6, {}) + + n.feed('') + + screen:expect({ + grid = [[ + 7 │7 | + 8 v │8 v | + 9 │9 | + 10 v │10 v | + 11 │11 | + 12 v │12 v | + ^13 │13 | + 14 v │14 v | + 15 │15 | + 16 v │16 v | + {3:[Scratch] }{2:[Scratch] }| + | + ]], + }) + + n.feed('') + + screen:expect({ grid = line1_grid }) + end) + + it('works with two buffers with virtual lines on one side', function() + n.exec_lua(function() + local lines = {} --- @type string[] + + for i = 1, 20 do + lines[i] = tostring(i) + end + + local ns = vim.api.nvim_create_namespace('test') + + vim.api.nvim_buf_set_lines(0, 0, -1, false, lines) + vim.bo.buftype = 'nofile' + + vim.wo.scrollbind = true + vim.cmd.vnew() + + lines = {} --- @type string[] + + for i = 1, 20 do + lines[i] = tostring(i + (i > 3 and 4 or 0)) + end + vim.api.nvim_buf_set_lines(0, 0, -1, false, lines) + vim.bo.buftype = 'nofile' + + vim.api.nvim_buf_set_extmark(0, ns, 2, 0, { + virt_lines = { + { { '4 v' } }, + { { '5 v' } }, + { { '6 v' } }, + { { '7 v' } }, + }, + }) + + vim.wo.scrollbind = true + end) + + n.feed('') + + t.eq(5, n.api.nvim_get_option_value('scroll', {})) + + screen:expect({ + grid = [[ + 6 v │6 | + 7 v │7 | + 8 │8 | + 9 │9 | + ^10 │10 | + 11 │11 | + 12 │12 | + 13 │13 | + 14 │14 | + 15 │15 | + {3:[Scratch] }{2:[Scratch] }| + | + ]], + }) + + n.feed('') + + local line1_grid = [[ + ^1 │1 | + 2 │2 | + 3 │3 | + 4 v │4 | + 5 v │5 | + 6 v │6 | + 7 v │7 | + 8 │8 | + 9 │9 | + 10 │10 | + {3:[Scratch] }{2:[Scratch] }| + | + ]] + + screen:expect({ grid = line1_grid }) + + n.api.nvim_set_option_value('scroll', 6, {}) + + n.feed('') + + screen:expect({ + grid = [[ + 7 v │7 | + 8 │8 | + 9 │9 | + 10 │10 | + ^11 │11 | + 12 │12 | + 13 │13 | + 14 │14 | + 15 │15 | + 16 │16 | + {3:[Scratch] }{2:[Scratch] }| + | + ]], + }) + + n.feed('') + + screen:expect({ grid = line1_grid }) + + -- Note: not the same as n.feed('4') + n.feed('') + n.feed('') + n.feed('') + n.feed('') + + screen:expect({ + grid = [[ + 5 v │5 | + 6 v │6 | + 7 v │7 | + ^8 │8 | + 9 │9 | + 10 │10 | + 11 │11 | + 12 │12 | + 13 │13 | + 14 │14 | + {3:[Scratch] }{2:[Scratch] }| + | + ]], + }) + + n.feed('') + + screen:expect({ + grid = [[ + 6 v │6 | + 7 v │7 | + ^8 │8 | + 9 │9 | + 10 │10 | + 11 │11 | + 12 │12 | + 13 │13 | + 14 │14 | + 15 │15 | + {3:[Scratch] }{2:[Scratch] }| + | + ]], + }) + + n.feed('') + n.feed('') + + screen:expect({ + grid = [[ + 4 v │4 | + 5 v │5 | + 6 v │6 | + 7 v │7 | + ^8 │8 | + 9 │9 | + 10 │10 | + 11 │11 | + 12 │12 | + 13 │13 | + {3:[Scratch] }{2:[Scratch] }| + | + ]], + }) + end) + + it('works with buffers of different lengths', function() + n.exec_lua(function() + vim.api.nvim_buf_set_lines(0, 0, -1, false, { '1', '2', '3' }) + vim.bo.buftype = 'nofile' + + vim.wo.scrollbind = true + vim.cmd.vnew() + + local lines = {} --- @type string[] + + for i = 1, 50 do + lines[i] = tostring(i) + end + + vim.api.nvim_buf_set_lines(0, 0, -1, false, lines) + vim.bo.buftype = 'nofile' + vim.wo.scrollbind = true + end) + + n.feed('10') + + screen:expect({ + grid = [[ + ^11 │3 | + 12 │{1:~ }| + 13 │{1:~ }| + 14 │{1:~ }| + 15 │{1:~ }| + 16 │{1:~ }| + 17 │{1:~ }| + 18 │{1:~ }| + 19 │{1:~ }| + 20 │{1:~ }| + {3:[Scratch] }{2:[Scratch] }| + | + ]], + }) + + n.feed('') + + screen:expect({ + grid = [[ + 10 │3 | + ^11 │{1:~ }| + 12 │{1:~ }| + 13 │{1:~ }| + 14 │{1:~ }| + 15 │{1:~ }| + 16 │{1:~ }| + 17 │{1:~ }| + 18 │{1:~ }| + 19 │{1:~ }| + {3:[Scratch] }{2:[Scratch] }| + | + ]], + }) + end) + + it('works with buffers of different lengths and virtual lines', function() + n.exec_lua(function() + vim.api.nvim_buf_set_lines(0, 0, -1, false, { '1', '5', '6' }) + + local ns = vim.api.nvim_create_namespace('test') + vim.api.nvim_buf_set_extmark(0, ns, 0, 0, { + virt_lines = { + { { '2 v' } }, + { { '3 v' } }, + { { '4 v' } }, + }, + }) + + vim.bo.buftype = 'nofile' + + vim.wo.scrollbind = true + vim.cmd.vnew() + + local lines = {} --- @type string[] + + for i = 1, 50 do + lines[i] = tostring(i) + end + + vim.api.nvim_buf_set_lines(0, 0, -1, false, lines) + vim.bo.buftype = 'nofile' + vim.wo.scrollbind = true + end) + + n.feed('') + n.feed('') + screen:expect({ + grid = [[ + ^3 │3 v | + 4 │4 v | + 5 │5 | + 6 │6 | + 7 │{1:~ }| + 8 │{1:~ }| + 9 │{1:~ }| + 10 │{1:~ }| + 11 │{1:~ }| + 12 │{1:~ }| + {3:[Scratch] }{2:[Scratch] }| + | + ]], + }) + + n.feed('8') + + screen:expect({ + grid = [[ + ^11 │6 | + 12 │{1:~ }| + 13 │{1:~ }| + 14 │{1:~ }| + 15 │{1:~ }| + 16 │{1:~ }| + 17 │{1:~ }| + 18 │{1:~ }| + 19 │{1:~ }| + 20 │{1:~ }| + {3:[Scratch] }{2:[Scratch] }| + | + ]], + }) + + n.feed('') + n.feed('') + n.feed('') + n.feed('') + n.feed('') + + t.eq(n.exec_lua [[return vim.fn.line('w0', 1001)]], 6) + t.eq(n.exec_lua [[return vim.fn.line('w0', 1000)]], 3) + + screen:expect({ + grid = [[ + 6 │6 | + 7 │{1:~ }| + 8 │{1:~ }| + 9 │{1:~ }| + 10 │{1:~ }| + ^11 │{1:~ }| + 12 │{1:~ }| + 13 │{1:~ }| + 14 │{1:~ }| + 15 │{1:~ }| + {3:[Scratch] }{2:[Scratch] }| + | + ]], + }) + + n.feed('') + n.feed('') + n.feed('') + + screen:expect({ + grid = [[ + 3 │3 v | + 4 │4 v | + 5 │5 | + 6 │6 | + 7 │{1:~ }| + 8 │{1:~ }| + 9 │{1:~ }| + 10 │{1:~ }| + ^11 │{1:~ }| + 12 │{1:~ }| + {3:[Scratch] }{2:[Scratch] }| + | + ]], + }) + end) +end) -- cgit From 4e90bc30237ae81bf15e77c17ac8089a2cc74046 Mon Sep 17 00:00:00 2001 From: glepnir Date: Wed, 31 Jul 2024 22:15:34 +0800 Subject: feat(lsp): lsp.completion support set deprecated (#29882) Problem: CompletionItem in lsp spec mentioned the deprecated attribute Solution: when item has deprecated attribute set hl_group to DiagnosticDeprecated in complete function --- test/functional/plugin/lsp/completion_spec.lua | 55 ++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) (limited to 'test/functional') diff --git a/test/functional/plugin/lsp/completion_spec.lua b/test/functional/plugin/lsp/completion_spec.lua index 5c2933c610..aad7e350ee 100644 --- a/test/functional/plugin/lsp/completion_spec.lua +++ b/test/functional/plugin/lsp/completion_spec.lua @@ -307,6 +307,7 @@ describe('vim.lsp.completion: item conversion', function() info = '', kind = 'Module', menu = '', + hl_group = '', word = 'this_thread', } local result = complete(' std::this|', completion_list) @@ -362,6 +363,7 @@ describe('vim.lsp.completion: item conversion', function() info = '', kind = 'Module', menu = '', + hl_group = '', word = 'this_thread', } local result = complete(' std::this|is', completion_list) @@ -529,6 +531,14 @@ describe('vim.lsp.completion: protocol', function() { label = 'hello', }, + { + label = 'hercules', + tags = { 1 }, -- 1 represents Deprecated tag + }, + { + label = 'hero', + deprecated = true, + }, }, }) @@ -545,6 +555,7 @@ describe('vim.lsp.completion: protocol', function() info = '', kind = 'Unknown', menu = '', + hl_group = '', user_data = { nvim = { lsp = { @@ -557,6 +568,50 @@ describe('vim.lsp.completion: protocol', function() }, word = 'hello', }, + { + abbr = 'hercules', + dup = 1, + empty = 1, + icase = 1, + info = '', + kind = 'Unknown', + menu = '', + hl_group = 'DiagnosticDeprecated', + user_data = { + nvim = { + lsp = { + client_id = 1, + completion_item = { + label = 'hercules', + tags = { 1 }, + }, + }, + }, + }, + word = 'hercules', + }, + { + abbr = 'hero', + dup = 1, + empty = 1, + icase = 1, + info = '', + kind = 'Unknown', + menu = '', + hl_group = 'DiagnosticDeprecated', + user_data = { + nvim = { + lsp = { + client_id = 1, + completion_item = { + label = 'hero', + deprecated = true, + }, + }, + }, + }, + word = 'hero', + }, }, matches) end) end) -- cgit From 6bb40f3dbffb4b9858d9b13486d1832db8f51755 Mon Sep 17 00:00:00 2001 From: Jaehwang Jung Date: Wed, 31 Jul 2024 23:18:24 +0900 Subject: fix(lsp): prevent desync due to empty buffer (#29904) Problem: Some language servers (e.g., rust-analyzer, texlab) are desynced when the user deletes the entire contents of the buffer. This is due to the discrepancy between how nvim computes diff and how nvim treats empty buffer. * diff: If the buffer became empty, then the diff includes the last line's eol. * empty buffer: Even if the buffer is empty, nvim regards it as having a single empty line with eol. Solution: Add special case for diff computation when the buffer becomes empty so that it does not include the eol of the last line. --- .../plugin/lsp/incremental_sync_spec.lua | 44 ++++++++++++++++++++-- 1 file changed, 41 insertions(+), 3 deletions(-) (limited to 'test/functional') diff --git a/test/functional/plugin/lsp/incremental_sync_spec.lua b/test/functional/plugin/lsp/incremental_sync_spec.lua index 238b90b57d..1e463d5117 100644 --- a/test/functional/plugin/lsp/incremental_sync_spec.lua +++ b/test/functional/plugin/lsp/incremental_sync_spec.lua @@ -170,7 +170,7 @@ describe('incremental synchronization', function() } test_edit({ 'a' }, { 'rb' }, expected_text_changes, 'utf-16', '\n') end) - it('deleting a line', function() + it('deleting the first line', function() local expected_text_changes = { { range = { @@ -183,11 +183,49 @@ describe('incremental synchronization', function() line = 1, }, }, - rangeLength = 12, + rangeLength = 6, + text = '', + }, + } + test_edit({ 'hello', 'world' }, { 'ggdd' }, expected_text_changes, 'utf-16', '\n') + end) + it('deleting the last line', function() + local expected_text_changes = { + { + range = { + ['start'] = { + character = 0, + line = 1, + }, + ['end'] = { + character = 0, + line = 2, + }, + }, + rangeLength = 6, + text = '', + }, + } + test_edit({ 'hello', 'world' }, { '2ggdd' }, expected_text_changes, 'utf-16', '\n') + end) + it('deleting all lines', function() + local expected_text_changes = { + { + range = { + ['start'] = { + character = 0, + line = 0, + }, + ['end'] = { + character = 5, + line = 1, + }, + }, + rangeLength = 11, text = '', }, } - test_edit({ 'hello world' }, { 'dd' }, expected_text_changes, 'utf-16', '\n') + test_edit({ 'hello', 'world' }, { 'ggdG' }, expected_text_changes, 'utf-16', '\n') end) it('deleting an empty line', function() local expected_text_changes = { -- cgit From 720b309c786c4a258adccc9c468d433fb0f755b9 Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Thu, 1 Aug 2024 16:01:15 +0200 Subject: fix(lsp): don't send foreign diagnostics to servers in buf.code_action (#29501) `buf.code_action` always included diagnostics on a given line from all clients. Servers should only receive diagnostics they published, and in the exact same format they sent it. Should fix https://github.com/neovim/neovim/issues/29500 --- test/functional/plugin/lsp/diagnostic_spec.lua | 27 -------------------------- 1 file changed, 27 deletions(-) (limited to 'test/functional') diff --git a/test/functional/plugin/lsp/diagnostic_spec.lua b/test/functional/plugin/lsp/diagnostic_spec.lua index c5e14ffdc2..779c4641b9 100644 --- a/test/functional/plugin/lsp/diagnostic_spec.lua +++ b/test/functional/plugin/lsp/diagnostic_spec.lua @@ -98,33 +98,6 @@ describe('vim.lsp.diagnostic', function() clear() end) - describe('vim.lsp.diagnostic', function() - it('maintains LSP information when translating diagnostics', function() - local result = exec_lua [[ - local diagnostics = { - make_error("Error 1", 1, 1, 1, 5), - } - - diagnostics[1].code = 42 - diagnostics[1].data = "Hello world" - - vim.lsp.diagnostic.on_publish_diagnostics(nil, { - uri = fake_uri, - diagnostics = diagnostics, - }, {client_id=client_id}) - - return { - vim.diagnostic.get(diagnostic_bufnr, {lnum=1})[1], - vim.lsp.diagnostic.get_line_diagnostics(diagnostic_bufnr, 1)[1], - } - ]] - eq({ code = 42, data = 'Hello world' }, result[1].user_data.lsp) - eq(42, result[1].code) - eq(42, result[2].code) - eq('Hello world', result[2].data) - end) - end) - describe('vim.lsp.diagnostic.on_publish_diagnostics', function() it('allows configuring the virtual text via vim.lsp.with', function() local expected_spacing = 10 -- cgit From 6af359ef4cc3c221e0e3102ab2b54cf64d7c9835 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 2 Aug 2024 06:00:02 +0800 Subject: vim-patch:9.1.0647: [security] use-after-free in tagstack_clear_entry Problem: [security] use-after-free in tagstack_clear_entry (Suyue Guo ) Solution: Instead of manually calling vim_free() on each of the tagstack entries, let's use tagstack_clear_entry(), which will also free the stack, but using the VIM_CLEAR macro, which prevents a use-after-free by setting those pointers to NULL This addresses CVE-2024-41957 Github advisory: https://github.com/vim/vim/security/advisories/GHSA-f9cr-gv85-hcr4 https://github.com/vim/vim/commit/8a0bbe7b8aad6f8da28dee218c01bc8a0185a2d5 Co-authored-by: Christian Brabandt --- test/functional/legacy/crash_spec.lua | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'test/functional') diff --git a/test/functional/legacy/crash_spec.lua b/test/functional/legacy/crash_spec.lua index 04f77c7d4f..e72c3a512a 100644 --- a/test/functional/legacy/crash_spec.lua +++ b/test/functional/legacy/crash_spec.lua @@ -1,8 +1,12 @@ +local t = require('test.testutil') local n = require('test.functional.testnvim')() local assert_alive = n.assert_alive local clear = n.clear local command = n.command +local eq = t.eq +local eval = n.eval +local exec = n.exec local feed = n.feed before_each(clear) @@ -32,3 +36,18 @@ it('no crash with very long option error message', function() pcall(command, 'source test/old/testdir/crash/poc_did_set_langmap') assert_alive() end) + +it('no crash when closing window with tag in loclist', function() + exec([[ + new + lexpr ['foo'] + lopen + let g:qf_bufnr = bufnr() + lclose + call settagstack(1, #{items: [#{tagname: 'foo', from: [g:qf_bufnr, 1, 1, 0]}]}) + ]]) + eq(1, eval('bufexists(g:qf_bufnr)')) + command('1close') + eq(0, eval('bufexists(g:qf_bufnr)')) + assert_alive() +end) -- cgit From b782a37cf58b5ae5e47fd15fb2a5096639c64a23 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 2 Aug 2024 07:52:09 +0800 Subject: vim-patch:9.1.0651: ex: trailing dot is optional for :g and :insert/:append (#29946) Problem: ex: trailing dot is optional for :g and :insert/:append Solution: don't break out early, when the next command is empty. (Mohamed Akram) The terminating period is optional for the last command in a global command list. closes: vim/vim#15407 https://github.com/vim/vim/commit/0214680a8ec5f7f656cb42e5db19243709202ed2 Co-authored-by: Mohamed Akram --- test/functional/ex_cmds/append_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/ex_cmds/append_spec.lua b/test/functional/ex_cmds/append_spec.lua index 80fdcb3134..df62aecc7f 100644 --- a/test/functional/ex_cmds/append_spec.lua +++ b/test/functional/ex_cmds/append_spec.lua @@ -23,7 +23,7 @@ local cmdtest = function(cmd, prep, ret1) end it(cmd .. 's' .. prep .. ' the current line by default', function() - command(cmd .. '\nabc\ndef\n') + command(cmd .. '\nabc\ndef') eq(ret1, buffer_contents()) end) -- Used to crash because this invokes history processing which uses -- cgit From 2a3561819e0e80150986779cee87659b7c92d0c1 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 2 Aug 2024 16:00:27 +0800 Subject: fix(eval): handle wrong v:lua in expr option properly (#29953) --- test/functional/lua/luaeval_spec.lua | 37 ++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'test/functional') diff --git a/test/functional/lua/luaeval_spec.lua b/test/functional/lua/luaeval_spec.lua index 2f137e280c..f3db729c09 100644 --- a/test/functional/lua/luaeval_spec.lua +++ b/test/functional/lua/luaeval_spec.lua @@ -13,6 +13,7 @@ local fn = n.fn local clear = n.clear local eval = n.eval local feed = n.feed +local assert_alive = n.assert_alive local NIL = vim.NIL local eq = t.eq @@ -558,5 +559,41 @@ describe('v:lua', function() eq("Vim:E107: Missing parentheses: v:lua", pcall_err(eval, "'bad'->v:lua")) eq("Vim:E1085: Not a callable type: v:lua", pcall_err(eval, "'bad'->v:lua()")) eq([[Vim:E15: Invalid expression: "v:lua.()"]], pcall_err(eval, "'bad'->v:lua.()")) + + eq("Vim:E1085: Not a callable type: v:lua", pcall_err(eval, "v:lua()")) + eq([[Vim:E15: Invalid expression: "v:lua.()"]], pcall_err(eval, "v:lua.()")) + end) + + describe('invalid use in fold text', function() + before_each(function() + feed('ifoobar') + command('1,2fold') + end) + + it('with missing function name when used as simple function', function() + api.nvim_set_option_value('debug', 'throw', {}) + eq( + [[Vim(eval):E15: Invalid expression: "v:lua.()"]], + pcall_err(command, 'set foldtext=v:lua.() | eval foldtextresult(1)') + ) + end) + + it('with missing function name when used in expression', function() + api.nvim_set_option_value('debug', 'throw', {}) + eq( + [[Vim(eval):E15: Invalid expression: "+v:lua.()"]], + pcall_err(command, 'set foldtext=+v:lua.() | eval foldtextresult(1)') + ) + end) + + it('with non-existent function when used as simple function', function() + command('set foldtext=v:lua.NoSuchFunc() | eval foldtextresult(1)') + assert_alive() + end) + + it('with non-existent function when used in expression', function() + command('set foldtext=+v:lua.NoSuchFunc() | eval foldtextresult(1)') + assert_alive() + end) end) end) -- cgit From 5de2ae2bced9732904801b37eb46c4b8e6484b81 Mon Sep 17 00:00:00 2001 From: Mathias Fussenegger Date: Fri, 2 Aug 2024 10:36:17 +0200 Subject: refactor(lsp): add test case for default diagnostic severity See https://github.com/microsoft/language-server-protocol/pull/1978 If the severity is not specified by the server, error should be used. This was already the case because it matches the vim.diagnostic default. This only adds a test case for it. --- test/functional/plugin/lsp/diagnostic_spec.lua | 28 ++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'test/functional') diff --git a/test/functional/plugin/lsp/diagnostic_spec.lua b/test/functional/plugin/lsp/diagnostic_spec.lua index 779c4641b9..76b1808883 100644 --- a/test/functional/plugin/lsp/diagnostic_spec.lua +++ b/test/functional/plugin/lsp/diagnostic_spec.lua @@ -317,6 +317,34 @@ describe('vim.lsp.diagnostic', function() eq('Pull Diagnostic', diags[1].message) end) + it('severity defaults to error if missing', function() + ---@type vim.Diagnostic[] + local diagnostics = exec_lua([[ + vim.lsp.diagnostic.on_diagnostic(nil, + { + kind = 'full', + items = { + { + range = make_range(4, 4, 4, 4), + message = "bad!", + } + } + }, + { + params = { + textDocument = { uri = fake_uri }, + }, + uri = fake_uri, + client_id = client_id, + }, + {} + ) + return vim.diagnostic.get(diagnostic_bufnr) + ]]) + eq(1, #diagnostics) + eq(1, diagnostics[1].severity) + end) + it('allows configuring the virtual text via vim.lsp.with', function() local expected_spacing = 10 local extmarks = exec_lua( -- cgit From 7d24c4d6b0413cd5af8d0579f0a9a694db7f775e Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Mon, 29 Jul 2024 11:20:15 +0100 Subject: test: allow exec_lua to handle functions Problem: Tests have lots of exec_lua calls which input blocks of code provided as unformatted strings. Solution: Teach exec_lua how to handle functions. --- test/functional/lua/api_spec.lua | 8 +- test/functional/lua/buffer_updates_spec.lua | 49 +- test/functional/lua/commands_spec.lua | 14 +- test/functional/lua/diagnostic_spec.lua | 3476 ++++++++++++---------- test/functional/lua/filetype_spec.lua | 152 +- test/functional/lua/fs_spec.lua | 64 +- test/functional/lua/glob_spec.lua | 11 +- test/functional/plugin/lsp_spec.lua | 2841 +++++++++--------- test/functional/treesitter/fold_spec.lua | 44 +- test/functional/treesitter/highlight_spec.lua | 175 +- test/functional/treesitter/inspect_tree_spec.lua | 38 +- test/functional/treesitter/language_spec.lua | 50 +- test/functional/treesitter/node_spec.lua | 86 +- test/functional/treesitter/parser_spec.lua | 486 ++- test/functional/treesitter/query_spec.lua | 505 ++-- test/functional/treesitter/utils_spec.lua | 26 +- 16 files changed, 4128 insertions(+), 3897 deletions(-) (limited to 'test/functional') diff --git a/test/functional/lua/api_spec.lua b/test/functional/lua/api_spec.lua index 56969150bd..4bbb57c3a8 100644 --- a/test/functional/lua/api_spec.lua +++ b/test/functional/lua/api_spec.lua @@ -145,10 +145,10 @@ describe('luaeval(vim.api.…)', function() eq(true, fn.luaeval('vim.api.nvim__id(vim.api.nvim__id)(true)')) eq( 42, - exec_lua [[ - local f = vim.api.nvim__id({42, vim.api.nvim__id}) - return f[2](f[1]) - ]] + exec_lua(function() + local f = vim.api.nvim__id({ 42, vim.api.nvim__id }) + return f[2](f[1]) + end) ) end) diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua index 6b575ad0ef..8ca97c8e5e 100644 --- a/test/functional/lua/buffer_updates_spec.lua +++ b/test/functional/lua/buffer_updates_spec.lua @@ -27,30 +27,35 @@ local origlines = { before_each(function() clear() - exec_lua [[ - local evname = ... + exec_lua(function() local events = {} - function test_register(bufnr, evname, id, changedtick, utf_sizes, preview) + function _G.test_register(bufnr, evname, id, changedtick, utf_sizes, preview) local function callback(...) - table.insert(events, {id, ...}) - if test_unreg == id then + table.insert(events, { id, ... }) + if _G.test_unreg == id then return true end end - local opts = {[evname]=callback, on_detach=callback, on_reload=callback, utf_sizes=utf_sizes, preview=preview} + local opts = { + [evname] = callback, + on_detach = callback, + on_reload = callback, + utf_sizes = utf_sizes, + preview = preview, + } if changedtick then opts.on_changedtick = callback end vim.api.nvim_buf_attach(bufnr, false, opts) end - function get_events() + function _G.get_events() local ret_events = events events = {} return ret_events end - ]] + end) end) describe('lua buffer event callbacks: on_lines', function() @@ -257,13 +262,13 @@ describe('lua buffer event callbacks: on_lines', function() it('has valid cursor position while shifting', function() api.nvim_buf_set_lines(0, 0, -1, true, { 'line1' }) - exec_lua([[ + exec_lua(function() vim.api.nvim_buf_attach(0, false, { on_lines = function() vim.api.nvim_set_var('listener_cursor_line', vim.api.nvim_win_get_cursor(0)[1]) end, }) - ]]) + end) feed('>>') eq(1, api.nvim_get_var('listener_cursor_line')) end) @@ -302,13 +307,13 @@ describe('lua buffer event callbacks: on_lines', function() it('#12718 lnume', function() api.nvim_buf_set_lines(0, 0, -1, true, { '1', '2', '3' }) - exec_lua([[ + exec_lua(function() vim.api.nvim_buf_attach(0, false, { on_lines = function(...) vim.api.nvim_set_var('linesev', { ... }) end, }) - ]]) + end) feed('1G0') feed('y2j') feed('G0') @@ -326,13 +331,13 @@ describe('lua buffer event callbacks: on_lines', function() end) it('nvim_buf_call() from callback does not cause wrong Normal mode CTRL-A #16729', function() - exec_lua([[ + exec_lua(function() vim.api.nvim_buf_attach(0, false, { - on_lines = function(...) + on_lines = function() vim.api.nvim_buf_call(0, function() end) end, }) - ]]) + end) feed('itest123') eq('test124', api.nvim_get_current_line()) end) @@ -342,19 +347,19 @@ describe('lua buffer event callbacks: on_lines', function() screen:attach() api.nvim_buf_set_lines(0, 0, -1, true, { 'aaa', 'bbb', 'ccc' }) - exec_lua([[ + exec_lua(function() local ns = vim.api.nvim_create_namespace('') vim.api.nvim_buf_attach(0, false, { on_lines = function(_, _, _, row, _, end_row) vim.api.nvim_buf_clear_namespace(0, ns, row, end_row) for i = row, end_row - 1 do - local id = vim.api.nvim_buf_set_extmark(0, ns, i, 0, { - virt_text = {{ 'NEW' .. tostring(i), 'WarningMsg' }}, + vim.api.nvim_buf_set_extmark(0, ns, i, 0, { + virt_text = { { 'NEW' .. tostring(i), 'WarningMsg' } }, }) end end, }) - ]]) + end) feed('o') screen:expect({ @@ -383,7 +388,7 @@ describe('lua buffer event callbacks: on_lines', function() it('line lengths are correct when pressing TAB with folding #29119', function() api.nvim_buf_set_lines(0, 0, -1, true, { 'a', 'b' }) - exec_lua([[ + exec_lua(function() _G.res = {} vim.o.foldmethod = 'indent' vim.o.softtabstop = -1 @@ -391,9 +396,9 @@ describe('lua buffer event callbacks: on_lines', function() on_lines = function(_, bufnr, _, row, _, end_row) local lines = vim.api.nvim_buf_get_lines(bufnr, row, end_row, true) table.insert(_G.res, lines) - end + end, }) - ]]) + end) feed('i') eq({ '\ta' }, exec_lua('return _G.res[#_G.res]')) diff --git a/test/functional/lua/commands_spec.lua b/test/functional/lua/commands_spec.lua index 57b084d3d6..456ee13da2 100644 --- a/test/functional/lua/commands_spec.lua +++ b/test/functional/lua/commands_spec.lua @@ -178,13 +178,15 @@ describe(':lua', function() eq('hello', exec_capture(':lua = x()')) exec_lua('x = {a = 1, b = 2}') eq('{\n a = 1,\n b = 2\n}', exec_capture(':lua =x')) - exec_lua([[function x(success) - if success then - return true, "Return value" - else - return false, nil, "Error message" + exec_lua(function() + function _G.x(success) + if success then + return true, 'Return value' + else + return false, nil, 'Error message' + end end - end]]) + end) eq( dedent [[ true diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua index decb58dc4d..718b9469a3 100644 --- a/test/functional/lua/diagnostic_spec.lua +++ b/test/functional/lua/diagnostic_spec.lua @@ -15,10 +15,10 @@ describe('vim.diagnostic', function() before_each(function() clear() - exec_lua [[ + exec_lua(function() require('vim.diagnostic') - function make_diagnostic(msg, lnum, col, end_lnum, end_col, severity, source, code) + local function make_diagnostic(msg, lnum, col, end_lnum, end_col, severity, source, code) return { lnum = lnum, col = col, @@ -31,54 +31,97 @@ describe('vim.diagnostic', function() } end - function make_error(msg, lnum, col, end_lnum, end_col, source, code) - return make_diagnostic(msg, lnum, col, end_lnum, end_col, vim.diagnostic.severity.ERROR, source, code) + function _G.make_error(msg, lnum, col, end_lnum, end_col, source, code) + return make_diagnostic( + msg, + lnum, + col, + end_lnum, + end_col, + vim.diagnostic.severity.ERROR, + source, + code + ) end - function make_warning(msg, lnum, col, end_lnum, end_col, source, code) - return make_diagnostic(msg, lnum, col, end_lnum, end_col, vim.diagnostic.severity.WARN, source, code) + function _G.make_warning(msg, lnum, col, end_lnum, end_col, source, code) + return make_diagnostic( + msg, + lnum, + col, + end_lnum, + end_col, + vim.diagnostic.severity.WARN, + source, + code + ) end - function make_info(msg, lnum, col, end_lnum, end_col, source, code) - return make_diagnostic(msg, lnum, col, end_lnum, end_col, vim.diagnostic.severity.INFO, source, code) + function _G.make_info(msg, lnum, col, end_lnum, end_col, source, code) + return make_diagnostic( + msg, + lnum, + col, + end_lnum, + end_col, + vim.diagnostic.severity.INFO, + source, + code + ) end - function make_hint(msg, lnum, col, end_lnum, end_col, source, code) - return make_diagnostic(msg, lnum, col, end_lnum, end_col, vim.diagnostic.severity.HINT, source, code) + function _G.make_hint(msg, lnum, col, end_lnum, end_col, source, code) + return make_diagnostic( + msg, + lnum, + col, + end_lnum, + end_col, + vim.diagnostic.severity.HINT, + source, + code + ) end - function count_diagnostics(bufnr, severity, namespace) - return #vim.diagnostic.get(bufnr, {severity = severity, namespace = namespace}) + function _G.count_diagnostics(bufnr, severity, namespace) + return #vim.diagnostic.get(bufnr, { severity = severity, namespace = namespace }) end - function count_extmarks(bufnr, namespace) + function _G.count_extmarks(bufnr, namespace) local ns = vim.diagnostic.get_namespace(namespace) local extmarks = 0 if ns.user_data.virt_text_ns then - extmarks = extmarks + #vim.api.nvim_buf_get_extmarks(bufnr, ns.user_data.virt_text_ns, 0, -1, {}) + extmarks = extmarks + + #vim.api.nvim_buf_get_extmarks(bufnr, ns.user_data.virt_text_ns, 0, -1, {}) end if ns.user_data.underline_ns then - extmarks = extmarks + #vim.api.nvim_buf_get_extmarks(bufnr, ns.user_data.underline_ns, 0, -1, {}) + extmarks = extmarks + + #vim.api.nvim_buf_get_extmarks(bufnr, ns.user_data.underline_ns, 0, -1, {}) end return extmarks end - function get_virt_text_extmarks(ns) - local ns = vim.diagnostic.get_namespace(ns) + function _G.get_virt_text_extmarks(ns) + ns = vim.diagnostic.get_namespace(ns) local virt_text_ns = ns.user_data.virt_text_ns - return vim.api.nvim_buf_get_extmarks(diagnostic_bufnr, virt_text_ns, 0, -1, {details = true}) + return vim.api.nvim_buf_get_extmarks( + _G.diagnostic_bufnr, + virt_text_ns, + 0, + -1, + { details = true } + ) end - ]] - - exec_lua([[ - diagnostic_ns = vim.api.nvim_create_namespace("diagnostic_spec") - other_ns = vim.api.nvim_create_namespace("other_namespace") - diagnostic_bufnr = vim.api.nvim_create_buf(true, false) - local lines = {"1st line of text", "2nd line of text", "wow", "cool", "more", "lines"} - vim.fn.bufload(diagnostic_bufnr) - vim.api.nvim_buf_set_lines(diagnostic_bufnr, 0, 1, false, lines) - return diagnostic_bufnr - ]]) + end) + + exec_lua(function() + _G.diagnostic_ns = vim.api.nvim_create_namespace('diagnostic_spec') + _G.other_ns = vim.api.nvim_create_namespace('other_namespace') + _G.diagnostic_bufnr = vim.api.nvim_create_buf(true, false) + local lines = { '1st line of text', '2nd line of text', 'wow', 'cool', 'more', 'lines' } + vim.fn.bufload(_G.diagnostic_bufnr) + vim.api.nvim_buf_set_lines(_G.diagnostic_bufnr, 0, 1, false, lines) + end) end) it('creates highlight groups', function() @@ -115,27 +158,28 @@ describe('vim.diagnostic', function() end) it('retrieves diagnostics from all buffers and namespaces', function() - local result = exec_lua [[ + local result = exec_lua(function() local other_bufnr = vim.api.nvim_create_buf(true, false) - local lines = vim.api.nvim_buf_get_lines(diagnostic_bufnr, 0, -1, true) + local lines = vim.api.nvim_buf_get_lines(_G.diagnostic_bufnr, 0, -1, true) vim.api.nvim_buf_set_lines(other_bufnr, 0, 1, false, lines) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), - make_error('Diagnostic #2', 2, 1, 2, 1), + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #1', 1, 1, 1, 1), + _G.make_error('Diagnostic #2', 2, 1, 2, 1), }) - vim.diagnostic.set(other_ns, other_bufnr, { - make_error('Diagnostic #3', 3, 1, 3, 1), + vim.diagnostic.set(_G.other_ns, other_bufnr, { + _G.make_error('Diagnostic #3', 3, 1, 3, 1), }) return vim.diagnostic.get() - ]] + end) eq(3, #result) eq( 2, - exec_lua( - [[return #vim.tbl_filter(function(d) return d.bufnr == diagnostic_bufnr end, ...)]], - result - ) + exec_lua(function(result0) + return #vim.tbl_filter(function(d) + return d.bufnr == _G.diagnostic_bufnr + end, result0) + end, result) ) eq('Diagnostic #1', result[1].message) end) @@ -143,155 +187,171 @@ describe('vim.diagnostic', function() it('removes diagnostics from the cache when a buffer is removed', function() eq( 2, - exec_lua [[ - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - local other_bufnr = vim.fn.bufadd('test | test') - local lines = vim.api.nvim_buf_get_lines(diagnostic_bufnr, 0, -1, true) - vim.api.nvim_buf_set_lines(other_bufnr, 0, 1, false, lines) - vim.cmd('bunload! ' .. other_bufnr) - - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), - make_error('Diagnostic #2', 2, 1, 2, 1), - }) - vim.diagnostic.set(diagnostic_ns, other_bufnr, { - make_error('Diagnostic #3', 3, 1, 3, 1), - }) - vim.api.nvim_set_current_buf(other_bufnr) - vim.opt_local.buflisted = true - vim.cmd('bwipeout!') - return #vim.diagnostic.get() - ]] + exec_lua(function() + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + local other_bufnr = vim.fn.bufadd('test | test') + local lines = vim.api.nvim_buf_get_lines(_G.diagnostic_bufnr, 0, -1, true) + vim.api.nvim_buf_set_lines(other_bufnr, 0, 1, false, lines) + vim.cmd('bunload! ' .. other_bufnr) + + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #1', 1, 1, 1, 1), + _G.make_error('Diagnostic #2', 2, 1, 2, 1), + }) + vim.diagnostic.set(_G.diagnostic_ns, other_bufnr, { + _G.make_error('Diagnostic #3', 3, 1, 3, 1), + }) + vim.api.nvim_set_current_buf(other_bufnr) + vim.opt_local.buflisted = true + vim.cmd('bwipeout!') + return #vim.diagnostic.get() + end) ) eq( 2, - exec_lua [[ - vim.api.nvim_set_current_buf(diagnostic_bufnr) - vim.opt_local.buflisted = false - return #vim.diagnostic.get() - ]] + exec_lua(function() + vim.api.nvim_set_current_buf(_G.diagnostic_bufnr) + vim.opt_local.buflisted = false + return #vim.diagnostic.get() + end) ) eq( 0, - exec_lua [[ - vim.cmd('bwipeout!') - return #vim.diagnostic.get() - ]] + exec_lua(function() + vim.cmd('bwipeout!') + return #vim.diagnostic.get() + end) ) end) it('removes diagnostic from stale cache on reset', function() - local diagnostics = exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), - make_error('Diagnostic #2', 2, 1, 2, 1), + local diagnostics = exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #1', 1, 1, 1, 1), + _G.make_error('Diagnostic #2', 2, 1, 2, 1), }) - local other_bufnr = vim.fn.bufadd('test | test') - vim.cmd('noautocmd bwipeout! ' .. diagnostic_bufnr) - return vim.diagnostic.get(diagnostic_bufnr) - ]] + vim.fn.bufadd('test | test') + vim.cmd('noautocmd bwipeout! ' .. _G.diagnostic_bufnr) + return vim.diagnostic.get(_G.diagnostic_bufnr) + end) eq(2, #diagnostics) - diagnostics = exec_lua [[ + diagnostics = exec_lua(function() vim.diagnostic.reset() return vim.diagnostic.get() - ]] + end) eq(0, #diagnostics) end) it('always returns a copy of diagnostic tables', function() - local result = exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), + local result = exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #1', 1, 1, 1, 1), }) local diag = vim.diagnostic.get() diag[1].col = 10000 return vim.diagnostic.get()[1].col == 10000 - ]] + end) eq(false, result) end) it('resolves buffer number 0 to the current buffer', function() eq( 2, - exec_lua [[ - vim.api.nvim_set_current_buf(diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), - make_error('Diagnostic #2', 2, 1, 2, 1), - }) - return #vim.diagnostic.get(0) - ]] + exec_lua(function() + vim.api.nvim_set_current_buf(_G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #1', 1, 1, 1, 1), + _G.make_error('Diagnostic #2', 2, 1, 2, 1), + }) + return #vim.diagnostic.get(0) + end) ) end) it('saves and count a single error', function() eq( 1, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), - }) - return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns) - ]] + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #1', 1, 1, 1, 1), + }) + return _G.count_diagnostics( + _G.diagnostic_bufnr, + vim.diagnostic.severity.ERROR, + _G.diagnostic_ns + ) + end) ) end) it('saves and count multiple errors', function() eq( 2, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), - make_error('Diagnostic #2', 2, 1, 2, 1), - }) - return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns) - ]] + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #1', 1, 1, 1, 1), + _G.make_error('Diagnostic #2', 2, 1, 2, 1), + }) + return _G.count_diagnostics( + _G.diagnostic_bufnr, + vim.diagnostic.severity.ERROR, + _G.diagnostic_ns + ) + end) ) end) it('saves and count from multiple namespaces', function() eq( { 1, 1, 2 }, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic From Server 1', 1, 1, 1, 1), - }) - vim.diagnostic.set(other_ns, diagnostic_bufnr, { - make_error('Diagnostic From Server 2', 1, 1, 1, 1), - }) - return { - -- First namespace - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns), - -- Second namespace - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, other_ns), - -- All namespaces - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR), - } - ]] + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic From Server 1', 1, 1, 1, 1), + }) + vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic From Server 2', 1, 1, 1, 1), + }) + return { + -- First namespace + _G.count_diagnostics( + _G.diagnostic_bufnr, + vim.diagnostic.severity.ERROR, + _G.diagnostic_ns + ), + -- Second namespace + _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.other_ns), + -- All namespaces + _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.ERROR), + } + end) ) end) it('saves and count from multiple namespaces with respect to severity', function() eq( { 3, 0, 3 }, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic From Server 1:1', 1, 1, 1, 1), - make_error('Diagnostic From Server 1:2', 2, 2, 2, 2), - make_error('Diagnostic From Server 1:3', 2, 3, 3, 2), - }) - vim.diagnostic.set(other_ns, diagnostic_bufnr, { - make_warning('Warning From Server 2', 3, 3, 3, 3), - }) - return { - -- Namespace 1 - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns), - -- Namespace 2 - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, other_ns), - -- All namespaces - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR), - } - ]] + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic From Server 1:1', 1, 1, 1, 1), + _G.make_error('Diagnostic From Server 1:2', 2, 2, 2, 2), + _G.make_error('Diagnostic From Server 1:3', 2, 3, 3, 2), + }) + vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, { + _G.make_warning('Warning From Server 2', 3, 3, 3, 3), + }) + return { + -- Namespace 1 + _G.count_diagnostics( + _G.diagnostic_bufnr, + vim.diagnostic.severity.ERROR, + _G.diagnostic_ns + ), + -- Namespace 2 + _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.other_ns), + -- All namespaces + _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.ERROR), + } + end) ) end) @@ -304,160 +364,190 @@ describe('vim.diagnostic', function() local all_highlights = { 1, 1, 2, 4, 2 } eq( all_highlights, - exec_lua [[ - local ns_1_diags = { - make_error("Error 1", 1, 1, 1, 5), - make_warning("Warning on Server 1", 2, 1, 2, 3), - } - local ns_2_diags = { - make_warning("Warning 1", 2, 1, 2, 3), - } + exec_lua(function() + local ns_1_diags = { + _G.make_error('Error 1', 1, 1, 1, 5), + _G.make_warning('Warning on Server 1', 2, 1, 2, 3), + } + local ns_2_diags = { + _G.make_warning('Warning 1', 2, 1, 2, 3), + } - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, ns_1_diags) - vim.diagnostic.set(other_ns, diagnostic_bufnr, ns_2_diags) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diags) + vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diags) - return { - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns), - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN, other_ns), - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN), - count_extmarks(diagnostic_bufnr, diagnostic_ns), - count_extmarks(diagnostic_bufnr, other_ns), - } - ]] + return { + _G.count_diagnostics( + _G.diagnostic_bufnr, + vim.diagnostic.severity.ERROR, + _G.diagnostic_ns + ), + _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN, _G.other_ns), + _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN), + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns), + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns), + } + end) ) -- Clear diagnostics from namespace 1, and make sure we have the right amount of stuff for namespace 2 eq( { 1, 1, 2, 0, 2 }, - exec_lua [[ - vim.diagnostic.enable(false, { bufnr = diagnostic_bufnr, ns_id = diagnostic_ns }) - return { - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns), - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN, other_ns), - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN), - count_extmarks(diagnostic_bufnr, diagnostic_ns), - count_extmarks(diagnostic_bufnr, other_ns), - } - ]] + exec_lua(function() + vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns }) + return { + _G.count_diagnostics( + _G.diagnostic_bufnr, + vim.diagnostic.severity.ERROR, + _G.diagnostic_ns + ), + _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN, _G.other_ns), + _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN), + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns), + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns), + } + end) ) -- Show diagnostics from namespace 1 again eq( all_highlights, - exec_lua([[ - vim.diagnostic.enable(true, { bufnr = diagnostic_bufnr, ns_id = diagnostic_ns }) - return { - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns), - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN, other_ns), - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN), - count_extmarks(diagnostic_bufnr, diagnostic_ns), - count_extmarks(diagnostic_bufnr, other_ns), - } - ]]) + exec_lua(function() + vim.diagnostic.enable(true, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns }) + return { + _G.count_diagnostics( + _G.diagnostic_bufnr, + vim.diagnostic.severity.ERROR, + _G.diagnostic_ns + ), + _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN, _G.other_ns), + _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN), + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns), + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns), + } + end) ) end) it('does not display diagnostics when disabled', function() eq( { 0, 2 }, - exec_lua [[ - local ns_1_diags = { - make_error("Error 1", 1, 1, 1, 5), - make_warning("Warning on Server 1", 2, 1, 2, 3), - } - local ns_2_diags = { - make_warning("Warning 1", 2, 1, 2, 3), - } + exec_lua(function() + local ns_1_diags = { + _G.make_error('Error 1', 1, 1, 1, 5), + _G.make_warning('Warning on Server 1', 2, 1, 2, 3), + } + local ns_2_diags = { + _G.make_warning('Warning 1', 2, 1, 2, 3), + } - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, ns_1_diags) - vim.diagnostic.set(other_ns, diagnostic_bufnr, ns_2_diags) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diags) + vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diags) - vim.diagnostic.enable(false, { bufnr = diagnostic_bufnr, ns_id = diagnostic_ns }) + vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns }) - return { - count_extmarks(diagnostic_bufnr, diagnostic_ns), - count_extmarks(diagnostic_bufnr, other_ns), - } - ]] + return { + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns), + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns), + } + end) ) eq( { 4, 0 }, - exec_lua [[ - vim.diagnostic.enable(true, { bufnr = diagnostic_bufnr, ns_id = diagnostic_ns }) - vim.diagnostic.enable(false, { bufnr = diagnostic_bufnr, ns_id = other_ns }) + exec_lua(function() + vim.diagnostic.enable(true, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns }) + vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr, ns_id = _G.other_ns }) - return { - count_extmarks(diagnostic_bufnr, diagnostic_ns), - count_extmarks(diagnostic_bufnr, other_ns), - } - ]] + return { + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns), + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns), + } + end) ) end) describe('show() and hide()', function() it('works', function() - local result = exec_lua [[ + local result = exec_lua(function() local other_bufnr = vim.api.nvim_create_buf(true, false) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) local result = {} vim.diagnostic.config({ underline = false, virtual_text = true }) local ns_1_diags = { - make_error("Error 1", 1, 1, 1, 5), - make_warning("Warning on Server 1", 2, 1, 2, 5), + _G.make_error('Error 1', 1, 1, 1, 5), + _G.make_warning('Warning on Server 1', 2, 1, 2, 5), } local ns_2_diags = { - make_warning("Warning 1", 2, 1, 2, 5), + _G.make_warning('Warning 1', 2, 1, 2, 5), } local other_buffer_diags = { - make_info("This is interesting", 0, 0, 0, 0) + _G.make_info('This is interesting', 0, 0, 0, 0), } - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, ns_1_diags) - vim.diagnostic.set(other_ns, diagnostic_bufnr, ns_2_diags) - vim.diagnostic.set(diagnostic_ns, other_bufnr, other_buffer_diags) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diags) + vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diags) + vim.diagnostic.set(_G.diagnostic_ns, other_bufnr, other_buffer_diags) -- All buffers and namespaces - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns) + - count_extmarks(other_bufnr, diagnostic_ns)) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) + ) -- Hide one namespace - vim.diagnostic.hide(diagnostic_ns) - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns) + - count_extmarks(other_bufnr, diagnostic_ns)) + vim.diagnostic.hide(_G.diagnostic_ns) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) + ) -- Show one namespace - vim.diagnostic.show(diagnostic_ns) - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns) + - count_extmarks(other_bufnr, diagnostic_ns)) + vim.diagnostic.show(_G.diagnostic_ns) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) + ) -- Hide one buffer vim.diagnostic.hide(nil, other_bufnr) - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns) + - count_extmarks(other_bufnr, diagnostic_ns)) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) + ) -- Hide everything vim.diagnostic.hide() - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns) + - count_extmarks(other_bufnr, diagnostic_ns)) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) + ) -- Show one buffer - vim.diagnostic.show(nil, diagnostic_bufnr) - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns) + - count_extmarks(other_bufnr, diagnostic_ns)) + vim.diagnostic.show(nil, _G.diagnostic_bufnr) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) + ) return result - ]] + end) eq(4, result[1]) eq(1, result[2]) @@ -468,13 +558,17 @@ describe('vim.diagnostic', function() end) it("doesn't error after bwipeout on buffer", function() - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {{ lnum = 0, end_lnum = 0, col = 0, end_col = 0 }}) - vim.cmd("bwipeout! " .. diagnostic_bufnr) + exec_lua(function() + vim.diagnostic.set( + _G.diagnostic_ns, + _G.diagnostic_bufnr, + { { lnum = 0, end_lnum = 0, col = 0, end_col = 0 } } + ) + vim.cmd('bwipeout! ' .. _G.diagnostic_bufnr) - vim.diagnostic.show(diagnostic_ns) - vim.diagnostic.hide(diagnostic_ns) - ]] + vim.diagnostic.show(_G.diagnostic_ns) + vim.diagnostic.hide(_G.diagnostic_ns) + end) end) end) @@ -505,52 +599,64 @@ describe('vim.diagnostic', function() end) it('without arguments', function() - local result = exec_lua [[ - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + local result = exec_lua(function() + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) local result = {} vim.diagnostic.config({ underline = false, virtual_text = true }) local ns_1_diags = { - make_error("Error 1", 1, 1, 1, 5), - make_warning("Warning on Server 1", 2, 1, 2, 5), + _G.make_error('Error 1', 1, 1, 1, 5), + _G.make_warning('Warning on Server 1', 2, 1, 2, 5), } local ns_2_diags = { - make_warning("Warning 1", 2, 1, 2, 5), + _G.make_warning('Warning 1', 2, 1, 2, 5), } - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, ns_1_diags) - vim.diagnostic.set(other_ns, diagnostic_bufnr, ns_2_diags) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diags) + vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diags) - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns)) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + ) vim.diagnostic.enable(false) - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns)) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + ) -- Create a new buffer local other_bufnr = vim.api.nvim_create_buf(true, false) local other_buffer_diags = { - make_info("This is interesting", 0, 0, 0, 0) + _G.make_info('This is interesting', 0, 0, 0, 0), } - vim.diagnostic.set(diagnostic_ns, other_bufnr, other_buffer_diags) + vim.diagnostic.set(_G.diagnostic_ns, other_bufnr, other_buffer_diags) - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns) + - count_extmarks(other_bufnr, diagnostic_ns)) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) + ) vim.diagnostic.enable() - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns) + - count_extmarks(other_bufnr, diagnostic_ns)) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) + ) return result - ]] + end) eq(3, result[1]) eq(0, result[2]) @@ -559,54 +665,66 @@ describe('vim.diagnostic', function() end) it('with buffer argument', function() - local result = exec_lua [[ + local result = exec_lua(function() local other_bufnr = vim.api.nvim_create_buf(true, false) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) local result = {} vim.diagnostic.config({ underline = false, virtual_text = true }) local ns_1_diags = { - make_error("Error 1", 1, 1, 1, 5), - make_warning("Warning on Server 1", 2, 1, 2, 5), + _G.make_error('Error 1', 1, 1, 1, 5), + _G.make_warning('Warning on Server 1', 2, 1, 2, 5), } local ns_2_diags = { - make_warning("Warning 1", 2, 1, 2, 5), + _G.make_warning('Warning 1', 2, 1, 2, 5), } local other_buffer_diags = { - make_info("This is interesting", 0, 0, 0, 0) + _G.make_info('This is interesting', 0, 0, 0, 0), } - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, ns_1_diags) - vim.diagnostic.set(other_ns, diagnostic_bufnr, ns_2_diags) - vim.diagnostic.set(diagnostic_ns, other_bufnr, other_buffer_diags) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diags) + vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diags) + vim.diagnostic.set(_G.diagnostic_ns, other_bufnr, other_buffer_diags) - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns) + - count_extmarks(other_bufnr, diagnostic_ns)) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) + ) - vim.diagnostic.enable(false, { bufnr = diagnostic_bufnr }) + vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr }) - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns) + - count_extmarks(other_bufnr, diagnostic_ns)) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) + ) - vim.diagnostic.enable(true, { bufnr = diagnostic_bufnr }) + vim.diagnostic.enable(true, { bufnr = _G.diagnostic_bufnr }) - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns) + - count_extmarks(other_bufnr, diagnostic_ns)) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) + ) vim.diagnostic.enable(false, { bufnr = other_bufnr }) - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns) + - count_extmarks(other_bufnr, diagnostic_ns)) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) + ) return result - ]] + end) eq(4, result[1]) eq(1, result[2]) @@ -615,44 +733,56 @@ describe('vim.diagnostic', function() end) it('with a namespace argument', function() - local result = exec_lua [[ - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + local result = exec_lua(function() + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) local result = {} vim.diagnostic.config({ underline = false, virtual_text = true }) local ns_1_diags = { - make_error("Error 1", 1, 1, 1, 5), - make_warning("Warning on Server 1", 2, 1, 2, 5), + _G.make_error('Error 1', 1, 1, 1, 5), + _G.make_warning('Warning on Server 1', 2, 1, 2, 5), } local ns_2_diags = { - make_warning("Warning 1", 2, 1, 2, 5), + _G.make_warning('Warning 1', 2, 1, 2, 5), } - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, ns_1_diags) - vim.diagnostic.set(other_ns, diagnostic_bufnr, ns_2_diags) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diags) + vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diags) - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns)) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + ) - vim.diagnostic.enable(false, { ns_id = diagnostic_ns }) + vim.diagnostic.enable(false, { ns_id = _G.diagnostic_ns }) - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns)) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + ) - vim.diagnostic.enable(true, { ns_id = diagnostic_ns }) + vim.diagnostic.enable(true, { ns_id = _G.diagnostic_ns }) - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns)) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + ) - vim.diagnostic.enable(false, { ns_id = other_ns }) + vim.diagnostic.enable(false, { ns_id = _G.other_ns }) - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns)) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + ) return result - ]] + end) eq(3, result[1]) eq(1, result[2]) @@ -662,82 +792,93 @@ describe('vim.diagnostic', function() --- @return table local function test_enable(legacy) - local result = exec_lua( - [[ - local legacy = ... + local result = exec_lua(function(legacy0) local other_bufnr = vim.api.nvim_create_buf(true, false) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) local result = {} vim.diagnostic.config({ underline = false, virtual_text = true }) local ns_1_diags = { - make_error("Error 1", 1, 1, 1, 5), - make_warning("Warning on Server 1", 2, 1, 2, 5), + _G.make_error('Error 1', 1, 1, 1, 5), + _G.make_warning('Warning on Server 1', 2, 1, 2, 5), } local ns_2_diags = { - make_warning("Warning 1", 2, 1, 2, 5), + _G.make_warning('Warning 1', 2, 1, 2, 5), } local other_buffer_diags = { - make_info("This is interesting", 0, 0, 0, 0) + _G.make_info('This is interesting', 0, 0, 0, 0), } - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, ns_1_diags) - vim.diagnostic.set(other_ns, diagnostic_bufnr, ns_2_diags) - vim.diagnostic.set(diagnostic_ns, other_bufnr, other_buffer_diags) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diags) + vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diags) + vim.diagnostic.set(_G.diagnostic_ns, other_bufnr, other_buffer_diags) - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns) + - count_extmarks(other_bufnr, diagnostic_ns)) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) + ) - if legacy then - vim.diagnostic.disable(diagnostic_bufnr, diagnostic_ns) + if legacy0 then + vim.diagnostic.disable(_G.diagnostic_bufnr, _G.diagnostic_ns) else - vim.diagnostic.enable(false, { bufnr = diagnostic_bufnr, ns_id = diagnostic_ns }) + vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns }) end - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns) + - count_extmarks(other_bufnr, diagnostic_ns)) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) + ) - if legacy then - vim.diagnostic.disable(diagnostic_bufnr, other_ns) + if legacy0 then + vim.diagnostic.disable(_G.diagnostic_bufnr, _G.other_ns) else - vim.diagnostic.enable(false, { bufnr = diagnostic_bufnr, ns_id = other_ns }) + vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr, ns_id = _G.other_ns }) end - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns) + - count_extmarks(other_bufnr, diagnostic_ns)) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) + ) - if legacy then - vim.diagnostic.enable(diagnostic_bufnr, diagnostic_ns) + if legacy0 then + vim.diagnostic.enable(_G.diagnostic_bufnr, _G.diagnostic_ns) else - vim.diagnostic.enable(true, { bufnr = diagnostic_bufnr, ns_id = diagnostic_ns }) + vim.diagnostic.enable(true, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns }) end - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns) + - count_extmarks(other_bufnr, diagnostic_ns)) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) + ) - if legacy then + if legacy0 then -- Should have no effect - vim.diagnostic.disable(other_bufnr, other_ns) + vim.diagnostic.disable(other_bufnr, _G.other_ns) else -- Should have no effect - vim.diagnostic.enable(false, { bufnr = other_bufnr, ns_id = other_ns }) + vim.diagnostic.enable(false, { bufnr = other_bufnr, ns_id = _G.other_ns }) end - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns) + - count_extmarks(other_bufnr, diagnostic_ns)) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) + ) return result - ]], - legacy - ) + end, legacy) return result end @@ -772,74 +913,94 @@ describe('vim.diagnostic', function() local all_highlights = { 1, 1, 2, 4, 2 } eq( all_highlights, - exec_lua [[ - local ns_1_diags = { - make_error("Error 1", 1, 1, 1, 5), - make_warning("Warning on Server 1", 2, 1, 2, 3), - } - local ns_2_diags = { - make_warning("Warning 1", 2, 1, 2, 3), - } + exec_lua(function() + local ns_1_diags = { + _G.make_error('Error 1', 1, 1, 1, 5), + _G.make_warning('Warning on Server 1', 2, 1, 2, 3), + } + local ns_2_diags = { + _G.make_warning('Warning 1', 2, 1, 2, 3), + } - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, ns_1_diags) - vim.diagnostic.set(other_ns, diagnostic_bufnr, ns_2_diags) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diags) + vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diags) - return { - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns), - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN, other_ns), - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN), - count_extmarks(diagnostic_bufnr, diagnostic_ns), - count_extmarks(diagnostic_bufnr, other_ns), - } - ]] + return { + _G.count_diagnostics( + _G.diagnostic_bufnr, + vim.diagnostic.severity.ERROR, + _G.diagnostic_ns + ), + _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN, _G.other_ns), + _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN), + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns), + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns), + } + end) ) -- Reset diagnostics from namespace 1 - exec_lua([[ vim.diagnostic.reset(diagnostic_ns) ]]) + exec_lua([[ vim.diagnostic.reset( _G.diagnostic_ns) ]]) -- Make sure we have the right diagnostic count eq( { 0, 1, 1, 0, 2 }, - exec_lua [[ - local diagnostic_count = {} - vim.wait(100, function () diagnostic_count = { - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns), - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN, other_ns), - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN), - count_extmarks(diagnostic_bufnr, diagnostic_ns), - count_extmarks(diagnostic_bufnr, other_ns), - } end ) - return diagnostic_count - ]] + exec_lua(function() + local diagnostic_count = {} + vim.wait(100, function() + diagnostic_count = { + _G.count_diagnostics( + _G.diagnostic_bufnr, + vim.diagnostic.severity.ERROR, + _G.diagnostic_ns + ), + _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN, _G.other_ns), + _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN), + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns), + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns), + } + end) + return diagnostic_count + end) ) -- Reset diagnostics from namespace 2 - exec_lua([[ vim.diagnostic.reset(other_ns) ]]) + exec_lua([[ vim.diagnostic.reset(_G.other_ns) ]]) -- Make sure we have the right diagnostic count eq( { 0, 0, 0, 0, 0 }, - exec_lua [[ - local diagnostic_count = {} - vim.wait(100, function () diagnostic_count = { - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns), - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN, other_ns), - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN), - count_extmarks(diagnostic_bufnr, diagnostic_ns), - count_extmarks(diagnostic_bufnr, other_ns), - } end ) - return diagnostic_count - ]] + exec_lua(function() + local diagnostic_count = {} + vim.wait(100, function() + diagnostic_count = { + _G.count_diagnostics( + _G.diagnostic_bufnr, + vim.diagnostic.severity.ERROR, + _G.diagnostic_ns + ), + _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN, _G.other_ns), + _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN), + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns), + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns), + } + end) + return diagnostic_count + end) ) end) it("doesn't error after bwipeout called on buffer", function() - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {{ lnum = 0, end_lnum = 0, col = 0, end_col = 0 }}) - vim.cmd("bwipeout! " .. diagnostic_bufnr) + exec_lua(function() + vim.diagnostic.set( + _G.diagnostic_ns, + _G.diagnostic_bufnr, + { { lnum = 0, end_lnum = 0, col = 0, end_col = 0 } } + ) + vim.cmd('bwipeout! ' .. _G.diagnostic_bufnr) - vim.diagnostic.reset(diagnostic_ns) - ]] + vim.diagnostic.reset(_G.diagnostic_ns) + end) end) end) @@ -847,206 +1008,206 @@ describe('vim.diagnostic', function() it('can find the next pos with only one namespace', function() eq( { 1, 1 }, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #1', 1, 1, 1, 1), }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) local next = vim.diagnostic.get_next() return { next.lnum, next.col } - ]] + end) ) end) it('can find next pos with two errors', function() eq( { 4, 4 }, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), - make_error('Diagnostic #2', 4, 4, 4, 4), + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #1', 1, 1, 1, 1), + _G.make_error('Diagnostic #2', 4, 4, 4, 4), }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {3, 1}) - local next = vim.diagnostic.get_next({ namespace = diagnostic_ns }) + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, { 3, 1 }) + local next = vim.diagnostic.get_next({ namespace = _G.diagnostic_ns }) return { next.lnum, next.col } - ]] + end) ) end) it('can cycle when position is past error', function() eq( { 1, 1 }, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #1', 1, 1, 1, 1), }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {3, 1}) - local next = vim.diagnostic.get_next({ namespace = diagnostic_ns }) + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, { 3, 1 }) + local next = vim.diagnostic.get_next({ namespace = _G.diagnostic_ns }) return { next.lnum, next.col } - ]] + end) ) end) it('will not cycle when wrap is off', function() eq( vim.NIL, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #1', 1, 1, 1, 1), }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {3, 1}) - local next = vim.diagnostic.get_next({ namespace = diagnostic_ns, wrap = false }) + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, { 3, 1 }) + local next = vim.diagnostic.get_next({ namespace = _G.diagnostic_ns, wrap = false }) return next - ]] + end) ) end) it('can cycle even from the last line', function() eq( { 4, 4 }, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #2', 4, 4, 4, 4), + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #2', 4, 4, 4, 4), }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {vim.api.nvim_buf_line_count(0), 1}) - local prev = vim.diagnostic.get_prev({ namespace = diagnostic_ns }) + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, { vim.api.nvim_buf_line_count(0), 1 }) + local prev = vim.diagnostic.get_prev({ namespace = _G.diagnostic_ns }) return { prev.lnum, prev.col } - ]] + end) ) end) it('works with diagnostics past the end of the line #16349', function() eq( { 4, 0 }, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 3, 9001, 3, 9001), - make_error('Diagnostic #2', 4, 0, 4, 0), + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #1', 3, 9001, 3, 9001), + _G.make_error('Diagnostic #2', 4, 0, 4, 0), }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {1, 1}) + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, { 1, 1 }) vim.diagnostic.jump({ count = 1, float = false }) - local next = vim.diagnostic.get_next({ namespace = diagnostic_ns }) + local next = vim.diagnostic.get_next({ namespace = _G.diagnostic_ns }) return { next.lnum, next.col } - ]] + end) ) end) it('works with diagnostics before the start of the line', function() eq( { 4, 0 }, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 3, 9001, 3, 9001), - make_error('Diagnostic #2', 4, -1, 4, -1), + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #1', 3, 9001, 3, 9001), + _G.make_error('Diagnostic #2', 4, -1, 4, -1), }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {1, 1}) + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, { 1, 1 }) vim.diagnostic.jump({ count = 1, float = false }) - local next = vim.diagnostic.get_next({ namespace = diagnostic_ns }) + local next = vim.diagnostic.get_next({ namespace = _G.diagnostic_ns }) return { next.lnum, next.col } - ]] + end) ) end) it('jumps to diagnostic with highest severity', function() - exec_lua([[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_info('Info', 1, 0, 1, 1), - make_error('Error', 2, 0, 2, 1), - make_warning('Warning', 3, 0, 3, 1), - make_error('Error', 4, 0, 4, 1), + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_info('Info', 1, 0, 1, 1), + _G.make_error('Error', 2, 0, 2, 1), + _G.make_warning('Warning', 3, 0, 3, 1), + _G.make_error('Error', 4, 0, 4, 1), }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {1, 0}) - ]]) + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, { 1, 0 }) + end) eq( { 3, 0 }, - exec_lua([[ - vim.diagnostic.jump({ count = 1, _highest = true }) - return vim.api.nvim_win_get_cursor(0) - ]]) + exec_lua(function() + vim.diagnostic.jump({ count = 1, _highest = true }) + return vim.api.nvim_win_get_cursor(0) + end) ) eq( { 5, 0 }, - exec_lua([[ - vim.diagnostic.jump({ count = 1, _highest = true }) - return vim.api.nvim_win_get_cursor(0) - ]]) - ) - - exec_lua([[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_info('Info', 1, 0, 1, 1), - make_hint('Hint', 2, 0, 2, 1), - make_warning('Warning', 3, 0, 3, 1), - make_hint('Hint', 4, 0, 4, 1), - make_warning('Warning', 5, 0, 5, 1), + exec_lua(function() + vim.diagnostic.jump({ count = 1, _highest = true }) + return vim.api.nvim_win_get_cursor(0) + end) + ) + + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_info('Info', 1, 0, 1, 1), + _G.make_hint('Hint', 2, 0, 2, 1), + _G.make_warning('Warning', 3, 0, 3, 1), + _G.make_hint('Hint', 4, 0, 4, 1), + _G.make_warning('Warning', 5, 0, 5, 1), }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {1, 0}) - ]]) + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, { 1, 0 }) + end) eq( { 4, 0 }, - exec_lua([[ - vim.diagnostic.jump({ count = 1, _highest = true }) - return vim.api.nvim_win_get_cursor(0) - ]]) + exec_lua(function() + vim.diagnostic.jump({ count = 1, _highest = true }) + return vim.api.nvim_win_get_cursor(0) + end) ) eq( { 6, 0 }, - exec_lua([[ - vim.diagnostic.jump({ count = 1, _highest = true }) - return vim.api.nvim_win_get_cursor(0) - ]]) + exec_lua(function() + vim.diagnostic.jump({ count = 1, _highest = true }) + return vim.api.nvim_win_get_cursor(0) + end) ) end) it('jumps to next diagnostic if severity is non-nil', function() - exec_lua([[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_info('Info', 1, 0, 1, 1), - make_error('Error', 2, 0, 2, 1), - make_warning('Warning', 3, 0, 3, 1), - make_error('Error', 4, 0, 4, 1), + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_info('Info', 1, 0, 1, 1), + _G.make_error('Error', 2, 0, 2, 1), + _G.make_warning('Warning', 3, 0, 3, 1), + _G.make_error('Error', 4, 0, 4, 1), }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {1, 0}) - ]]) + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, { 1, 0 }) + end) eq( { 2, 0 }, - exec_lua([[ - vim.diagnostic.jump({ count = 1 }) - return vim.api.nvim_win_get_cursor(0) - ]]) + exec_lua(function() + vim.diagnostic.jump({ count = 1 }) + return vim.api.nvim_win_get_cursor(0) + end) ) eq( { 3, 0 }, - exec_lua([[ - vim.diagnostic.jump({ count = 1 }) - return vim.api.nvim_win_get_cursor(0) - ]]) + exec_lua(function() + vim.diagnostic.jump({ count = 1 }) + return vim.api.nvim_win_get_cursor(0) + end) ) eq( { 4, 0 }, - exec_lua([[ - vim.diagnostic.jump({ count = 1 }) - return vim.api.nvim_win_get_cursor(0) - ]]) + exec_lua(function() + vim.diagnostic.jump({ count = 1 }) + return vim.api.nvim_win_get_cursor(0) + end) ) end) end) @@ -1055,282 +1216,297 @@ describe('vim.diagnostic', function() it('can find the previous diagnostic with only one namespace', function() eq( { 1, 1 }, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #1', 1, 1, 1, 1), }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {3, 1}) + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, { 3, 1 }) local prev = vim.diagnostic.get_prev() return { prev.lnum, prev.col } - ]] + end) ) end) it('can find the previous diagnostic with two errors', function() eq( { 1, 1 }, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), - make_error('Diagnostic #2', 4, 4, 4, 4), + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #1', 1, 1, 1, 1), + _G.make_error('Diagnostic #2', 4, 4, 4, 4), }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {3, 1}) - local prev = vim.diagnostic.get_prev({ namespace = diagnostic_ns }) + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, { 3, 1 }) + local prev = vim.diagnostic.get_prev({ namespace = _G.diagnostic_ns }) return { prev.lnum, prev.col } - ]] + end) ) end) it('can cycle when position is past error', function() eq( { 4, 4 }, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #2', 4, 4, 4, 4), + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #2', 4, 4, 4, 4), }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {3, 1}) - local prev = vim.diagnostic.get_prev({ namespace = diagnostic_ns }) + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, { 3, 1 }) + local prev = vim.diagnostic.get_prev({ namespace = _G.diagnostic_ns }) return { prev.lnum, prev.col } - ]] + end) ) end) it('respects wrap parameter', function() eq( vim.NIL, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #2', 4, 4, 4, 4), + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #2', 4, 4, 4, 4), }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {3, 1}) - local prev = vim.diagnostic.get_prev({ namespace = diagnostic_ns, wrap = false }) + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, { 3, 1 }) + local prev = vim.diagnostic.get_prev({ namespace = _G.diagnostic_ns, wrap = false }) return prev - ]] + end) ) end) it('works on blank line #28397', function() eq( { 0, 2 }, - exec_lua [[ - local test_bufnr = vim.api.nvim_create_buf(true, false) - vim.api.nvim_buf_set_lines(test_bufnr, 0, -1, false, { - 'first line', - '', - '', - 'end line', - }) - vim.diagnostic.set(diagnostic_ns, test_bufnr, { - make_info('Diagnostic #1', 0, 2, 0, 2), - make_info('Diagnostic #2', 2, 0, 2, 0), - make_info('Diagnostic #3', 2, 0, 2, 0), - }) - vim.api.nvim_win_set_buf(0, test_bufnr) - vim.api.nvim_win_set_cursor(0, {3, 0}) - return vim.diagnostic.get_prev_pos { namespace = diagnostic_ns} - ]] + exec_lua(function() + local test_bufnr = vim.api.nvim_create_buf(true, false) + vim.api.nvim_buf_set_lines(test_bufnr, 0, -1, false, { + 'first line', + '', + '', + 'end line', + }) + vim.diagnostic.set(_G.diagnostic_ns, test_bufnr, { + _G.make_info('Diagnostic #1', 0, 2, 0, 2), + _G.make_info('Diagnostic #2', 2, 0, 2, 0), + _G.make_info('Diagnostic #3', 2, 0, 2, 0), + }) + vim.api.nvim_win_set_buf(0, test_bufnr) + vim.api.nvim_win_set_cursor(0, { 3, 0 }) + return vim.diagnostic.get_prev_pos { namespace = _G.diagnostic_ns } + end) ) end) end) describe('jump()', function() before_each(function() - exec_lua([[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 0, 0, 0, 2), - make_error('Diagnostic #2', 1, 1, 1, 4), - make_warning('Diagnostic #3', 2, -1, 2, -1), - make_info('Diagnostic #4', 3, 0, 3, 3), + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #1', 0, 0, 0, 2), + _G.make_error('Diagnostic #2', 1, 1, 1, 4), + _G.make_warning('Diagnostic #3', 2, -1, 2, -1), + _G.make_info('Diagnostic #4', 3, 0, 3, 3), }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - ]]) + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + end) end) it('can move forward', function() eq( { 2, 1 }, - exec_lua([[ - vim.api.nvim_win_set_cursor(0, { 1, 0 }) - vim.diagnostic.jump({ count = 1 }) - return vim.api.nvim_win_get_cursor(0) - ]]) + exec_lua(function() + vim.api.nvim_win_set_cursor(0, { 1, 0 }) + vim.diagnostic.jump({ count = 1 }) + return vim.api.nvim_win_get_cursor(0) + end) ) eq( { 4, 0 }, - exec_lua([[ - vim.api.nvim_win_set_cursor(0, { 1, 0 }) - vim.diagnostic.jump({ count = 3 }) - return vim.api.nvim_win_get_cursor(0) - ]]) + exec_lua(function() + vim.api.nvim_win_set_cursor(0, { 1, 0 }) + vim.diagnostic.jump({ count = 3 }) + return vim.api.nvim_win_get_cursor(0) + end) ) eq( { 4, 0 }, - exec_lua([[ - vim.api.nvim_win_set_cursor(0, { 1, 0 }) - vim.diagnostic.jump({ count = math.huge, wrap = false }) - return vim.api.nvim_win_get_cursor(0) - ]]) + exec_lua(function() + vim.api.nvim_win_set_cursor(0, { 1, 0 }) + vim.diagnostic.jump({ count = math.huge, wrap = false }) + return vim.api.nvim_win_get_cursor(0) + end) ) end) it('can move backward', function() eq( { 3, 0 }, - exec_lua([[ - vim.api.nvim_win_set_cursor(0, { 4, 0 }) - vim.diagnostic.jump({ count = -1 }) - return vim.api.nvim_win_get_cursor(0) - ]]) + exec_lua(function() + vim.api.nvim_win_set_cursor(0, { 4, 0 }) + vim.diagnostic.jump({ count = -1 }) + return vim.api.nvim_win_get_cursor(0) + end) ) eq( { 1, 0 }, - exec_lua([[ - vim.api.nvim_win_set_cursor(0, { 4, 0 }) - vim.diagnostic.jump({ count = -3 }) - return vim.api.nvim_win_get_cursor(0) - ]]) + exec_lua(function() + vim.api.nvim_win_set_cursor(0, { 4, 0 }) + vim.diagnostic.jump({ count = -3 }) + return vim.api.nvim_win_get_cursor(0) + end) ) eq( { 1, 0 }, - exec_lua([[ - vim.api.nvim_win_set_cursor(0, { 4, 0 }) - vim.diagnostic.jump({ count = -math.huge, wrap = false }) - return vim.api.nvim_win_get_cursor(0) - ]]) + exec_lua(function() + vim.api.nvim_win_set_cursor(0, { 4, 0 }) + vim.diagnostic.jump({ count = -math.huge, wrap = false }) + return vim.api.nvim_win_get_cursor(0) + end) ) end) it('can filter by severity', function() eq( { 3, 0 }, - exec_lua([[ - vim.api.nvim_win_set_cursor(0, { 1, 0 }) - vim.diagnostic.jump({ count = 1, severity = vim.diagnostic.severity.WARN }) - return vim.api.nvim_win_get_cursor(0) - ]]) + exec_lua(function() + vim.api.nvim_win_set_cursor(0, { 1, 0 }) + vim.diagnostic.jump({ count = 1, severity = vim.diagnostic.severity.WARN }) + return vim.api.nvim_win_get_cursor(0) + end) ) eq( { 3, 0 }, - exec_lua([[ - vim.api.nvim_win_set_cursor(0, { 1, 0 }) - vim.diagnostic.jump({ count = 9999, severity = vim.diagnostic.severity.WARN }) - return vim.api.nvim_win_get_cursor(0) - ]]) + exec_lua(function() + vim.api.nvim_win_set_cursor(0, { 1, 0 }) + vim.diagnostic.jump({ count = 9999, severity = vim.diagnostic.severity.WARN }) + return vim.api.nvim_win_get_cursor(0) + end) ) end) it('can wrap', function() eq( { 1, 0 }, - exec_lua([[ - vim.api.nvim_win_set_cursor(0, { 4, 0 }) - vim.diagnostic.jump({ count = 1, wrap = true }) - return vim.api.nvim_win_get_cursor(0) - ]]) + exec_lua(function() + vim.api.nvim_win_set_cursor(0, { 4, 0 }) + vim.diagnostic.jump({ count = 1, wrap = true }) + return vim.api.nvim_win_get_cursor(0) + end) ) eq( { 4, 0 }, - exec_lua([[ - vim.api.nvim_win_set_cursor(0, { 1, 0 }) - vim.diagnostic.jump({ count = -1, wrap = true }) - return vim.api.nvim_win_get_cursor(0) - ]]) + exec_lua(function() + vim.api.nvim_win_set_cursor(0, { 1, 0 }) + vim.diagnostic.jump({ count = -1, wrap = true }) + return vim.api.nvim_win_get_cursor(0) + end) ) end) end) describe('get()', function() it('returns an empty table when no diagnostics are present', function() - eq({}, exec_lua [[return vim.diagnostic.get(diagnostic_bufnr, {namespace=diagnostic_ns})]]) + eq( + {}, + exec_lua [[return vim.diagnostic.get( _G.diagnostic_bufnr, {namespace=diagnostic_ns})]] + ) end) it('returns all diagnostics when no severity is supplied', function() eq( 2, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error("Error 1", 1, 1, 1, 5), - make_warning("Warning on Server 1", 1, 1, 2, 3), - }) + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Error 1', 1, 1, 1, 5), + _G.make_warning('Warning on Server 1', 1, 1, 2, 3), + }) - return #vim.diagnostic.get(diagnostic_bufnr) - ]] + return #vim.diagnostic.get(_G.diagnostic_bufnr) + end) ) end) it('returns only requested diagnostics when severity range is supplied', function() eq( { 2, 3, 2 }, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error("Error 1", 1, 1, 1, 5), - make_warning("Warning on Server 1", 1, 1, 2, 3), - make_info("Ignored information", 1, 1, 2, 3), - make_hint("Here's a hint", 1, 1, 2, 3), - }) + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Error 1', 1, 1, 1, 5), + _G.make_warning('Warning on Server 1', 1, 1, 2, 3), + _G.make_info('Ignored information', 1, 1, 2, 3), + _G.make_hint("Here's a hint", 1, 1, 2, 3), + }) - return { - #vim.diagnostic.get(diagnostic_bufnr, { severity = {min=vim.diagnostic.severity.WARN} }), - #vim.diagnostic.get(diagnostic_bufnr, { severity = {max=vim.diagnostic.severity.WARN} }), - #vim.diagnostic.get(diagnostic_bufnr, { - severity = { - min=vim.diagnostic.severity.INFO, - max=vim.diagnostic.severity.WARN, - } - }), - } - ]] + return { + #vim.diagnostic.get( + _G.diagnostic_bufnr, + { severity = { min = vim.diagnostic.severity.WARN } } + ), + #vim.diagnostic.get( + _G.diagnostic_bufnr, + { severity = { max = vim.diagnostic.severity.WARN } } + ), + #vim.diagnostic.get(_G.diagnostic_bufnr, { + severity = { + min = vim.diagnostic.severity.INFO, + max = vim.diagnostic.severity.WARN, + }, + }), + } + end) ) end) it('returns only requested diagnostics when severities are supplied', function() eq( { 1, 1, 2 }, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error("Error 1", 1, 1, 1, 5), - make_warning("Warning on Server 1", 1, 1, 2, 3), - make_info("Ignored information", 1, 1, 2, 3), - make_hint("Here's a hint", 1, 1, 2, 3), - }) + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Error 1', 1, 1, 1, 5), + _G.make_warning('Warning on Server 1', 1, 1, 2, 3), + _G.make_info('Ignored information', 1, 1, 2, 3), + _G.make_hint("Here's a hint", 1, 1, 2, 3), + }) - return { - #vim.diagnostic.get(diagnostic_bufnr, { severity = {vim.diagnostic.severity.WARN} }), - #vim.diagnostic.get(diagnostic_bufnr, { severity = {vim.diagnostic.severity.ERROR} }), - #vim.diagnostic.get(diagnostic_bufnr, { - severity = { - vim.diagnostic.severity.INFO, - vim.diagnostic.severity.WARN, - } - }), - } - ]] + return { + #vim.diagnostic.get( + _G.diagnostic_bufnr, + { severity = { vim.diagnostic.severity.WARN } } + ), + #vim.diagnostic.get( + _G.diagnostic_bufnr, + { severity = { vim.diagnostic.severity.ERROR } } + ), + #vim.diagnostic.get(_G.diagnostic_bufnr, { + severity = { + vim.diagnostic.severity.INFO, + vim.diagnostic.severity.WARN, + }, + }), + } + end) ) end) it('allows filtering by line', function() eq( 2, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error("Error 1", 1, 1, 1, 5), - make_warning("Warning on Server 1", 1, 1, 2, 3), - make_info("Ignored information", 1, 1, 2, 3), - make_error("Error On Other Line", 3, 1, 3, 5), - }) + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Error 1', 1, 1, 1, 5), + _G.make_warning('Warning on Server 1', 1, 1, 2, 3), + _G.make_info('Ignored information', 1, 1, 2, 3), + _G.make_error('Error On Other Line', 3, 1, 3, 5), + }) - return #vim.diagnostic.get(diagnostic_bufnr, {lnum = 2}) - ]] + return #vim.diagnostic.get(_G.diagnostic_bufnr, { lnum = 2 }) + end) ) end) end) @@ -1344,35 +1520,35 @@ describe('vim.diagnostic', function() [vim.diagnostic.severity.INFO] = 2, [vim.diagnostic.severity.HINT] = 1, }]], - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error("Error 1", 1, 1, 1, 2), - make_error("Error 2", 1, 3, 1, 4), - make_error("Error 3", 1, 5, 1, 6), - make_error("Error 4", 1, 7, 1, 8), - make_warning("Warning 1", 2, 1, 2, 2), - make_warning("Warning 2", 2, 3, 2, 4), - make_warning("Warning 3", 2, 5, 2, 6), - make_info("Info 1", 3, 1, 3, 2), - make_info("Info 2", 3, 3, 3, 4), - make_hint("Hint 1", 4, 1, 4, 2), + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Error 1', 1, 1, 1, 2), + _G.make_error('Error 2', 1, 3, 1, 4), + _G.make_error('Error 3', 1, 5, 1, 6), + _G.make_error('Error 4', 1, 7, 1, 8), + _G.make_warning('Warning 1', 2, 1, 2, 2), + _G.make_warning('Warning 2', 2, 3, 2, 4), + _G.make_warning('Warning 3', 2, 5, 2, 6), + _G.make_info('Info 1', 3, 1, 3, 2), + _G.make_info('Info 2', 3, 3, 3, 4), + _G.make_hint('Hint 1', 4, 1, 4, 2), }) - return vim.diagnostic.count(diagnostic_bufnr) - ]] + return vim.diagnostic.count(_G.diagnostic_bufnr) + end) ) eq( exec_lua [[return { [vim.diagnostic.severity.ERROR] = 2, [vim.diagnostic.severity.INFO] = 1, }]], - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error("Error 1", 1, 1, 1, 2), - make_error("Error 2", 1, 3, 1, 4), - make_info("Info 1", 3, 1, 3, 2), + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Error 1', 1, 1, 1, 2), + _G.make_error('Error 2', 1, 3, 1, 4), + _G.make_info('Info 1', 3, 1, 3, 2), }) - return vim.diagnostic.count(diagnostic_bufnr) - ]] + return vim.diagnostic.count(_G.diagnostic_bufnr) + end) ) end) @@ -1383,25 +1559,31 @@ describe('vim.diagnostic', function() { [vim.diagnostic.severity.WARN] = 1, [vim.diagnostic.severity.INFO] = 1, [vim.diagnostic.severity.HINT] = 1 }, { [vim.diagnostic.severity.WARN] = 1, [vim.diagnostic.severity.INFO] = 1 }, }]], - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error("Error 1", 1, 1, 1, 5), - make_warning("Warning on Server 1", 1, 1, 2, 3), - make_info("Ignored information", 1, 1, 2, 3), - make_hint("Here's a hint", 1, 1, 2, 3), + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Error 1', 1, 1, 1, 5), + _G.make_warning('Warning on Server 1', 1, 1, 2, 3), + _G.make_info('Ignored information', 1, 1, 2, 3), + _G.make_hint("Here's a hint", 1, 1, 2, 3), }) return { - vim.diagnostic.count(diagnostic_bufnr, { severity = {min=vim.diagnostic.severity.WARN} }), - vim.diagnostic.count(diagnostic_bufnr, { severity = {max=vim.diagnostic.severity.WARN} }), - vim.diagnostic.count(diagnostic_bufnr, { + vim.diagnostic.count( + _G.diagnostic_bufnr, + { severity = { min = vim.diagnostic.severity.WARN } } + ), + vim.diagnostic.count( + _G.diagnostic_bufnr, + { severity = { max = vim.diagnostic.severity.WARN } } + ), + vim.diagnostic.count(_G.diagnostic_bufnr, { severity = { - min=vim.diagnostic.severity.INFO, - max=vim.diagnostic.severity.WARN, - } + min = vim.diagnostic.severity.INFO, + max = vim.diagnostic.severity.WARN, + }, }), } - ]] + end) ) end) @@ -1412,25 +1594,31 @@ describe('vim.diagnostic', function() { [vim.diagnostic.severity.ERROR] = 1 }, { [vim.diagnostic.severity.WARN] = 1, [vim.diagnostic.severity.INFO] = 1 }, }]], - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error("Error 1", 1, 1, 1, 5), - make_warning("Warning on Server 1", 1, 1, 2, 3), - make_info("Ignored information", 1, 1, 2, 3), - make_hint("Here's a hint", 1, 1, 2, 3), + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Error 1', 1, 1, 1, 5), + _G.make_warning('Warning on Server 1', 1, 1, 2, 3), + _G.make_info('Ignored information', 1, 1, 2, 3), + _G.make_hint("Here's a hint", 1, 1, 2, 3), }) return { - vim.diagnostic.count(diagnostic_bufnr, { severity = {vim.diagnostic.severity.WARN} }), - vim.diagnostic.count(diagnostic_bufnr, { severity = {vim.diagnostic.severity.ERROR} }), - vim.diagnostic.count(diagnostic_bufnr, { + vim.diagnostic.count( + _G.diagnostic_bufnr, + { severity = { vim.diagnostic.severity.WARN } } + ), + vim.diagnostic.count( + _G.diagnostic_bufnr, + { severity = { vim.diagnostic.severity.ERROR } } + ), + vim.diagnostic.count(_G.diagnostic_bufnr, { severity = { vim.diagnostic.severity.INFO, vim.diagnostic.severity.WARN, - } + }, }), } - ]] + end) ) end) @@ -1440,16 +1628,16 @@ describe('vim.diagnostic', function() [vim.diagnostic.severity.WARN] = 1, [vim.diagnostic.severity.INFO] = 1, }]], - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error("Error 1", 1, 1, 1, 5), - make_warning("Warning on Server 1", 1, 1, 2, 3), - make_info("Ignored information", 1, 1, 2, 3), - make_error("Error On Other Line", 3, 1, 3, 5), + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Error 1', 1, 1, 1, 5), + _G.make_warning('Warning on Server 1', 1, 1, 2, 3), + _G.make_info('Ignored information', 1, 1, 2, 3), + _G.make_error('Error On Other Line', 3, 1, 3, 5), }) - return vim.diagnostic.count(diagnostic_bufnr, {lnum = 2}) - ]] + return vim.diagnostic.count(_G.diagnostic_bufnr, { lnum = 2 }) + end) ) end) end) @@ -1458,137 +1646,138 @@ describe('vim.diagnostic', function() it('works with global, namespace, and ephemeral options', function() eq( 1, - exec_lua [[ - vim.diagnostic.config({ - virtual_text = false, - }) + exec_lua(function() + vim.diagnostic.config({ + virtual_text = false, + }) - vim.diagnostic.config({ - virtual_text = true, - underline = false, - }, diagnostic_ns) + vim.diagnostic.config({ + virtual_text = true, + underline = false, + }, _G.diagnostic_ns) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Some Error', 4, 4, 4, 4), - }) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Some Error', 4, 4, 4, 4), + }) - return count_extmarks(diagnostic_bufnr, diagnostic_ns) - ]] + return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + end) ) eq( 1, - exec_lua [[ - vim.diagnostic.config({ - virtual_text = false, - }) + exec_lua(function() + vim.diagnostic.config({ + virtual_text = false, + }) - vim.diagnostic.config({ - virtual_text = false, - underline = false, - }, diagnostic_ns) + vim.diagnostic.config({ + virtual_text = false, + underline = false, + }, _G.diagnostic_ns) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Some Error', 4, 4, 4, 4), - }, {virtual_text = true}) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Some Error', 4, 4, 4, 4), + }, { virtual_text = true }) - return count_extmarks(diagnostic_bufnr, diagnostic_ns) - ]] + return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + end) ) eq( 0, - exec_lua [[ - vim.diagnostic.config({ - virtual_text = false, - }) + exec_lua(function() + vim.diagnostic.config({ + virtual_text = false, + }) - vim.diagnostic.config({ - virtual_text = {severity=vim.diagnostic.severity.ERROR}, - underline = false, - }, diagnostic_ns) + vim.diagnostic.config({ + virtual_text = { severity = vim.diagnostic.severity.ERROR }, + underline = false, + }, _G.diagnostic_ns) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_warning('Some Warning', 4, 4, 4, 4), - }, {virtual_text = true}) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_warning('Some Warning', 4, 4, 4, 4), + }, { virtual_text = true }) - return count_extmarks(diagnostic_bufnr, diagnostic_ns) - ]] + return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + end) ) eq( 1, - exec_lua [[ - vim.diagnostic.config({ - virtual_text = false, - }) + exec_lua(function() + vim.diagnostic.config({ + virtual_text = false, + }) - vim.diagnostic.config({ - virtual_text = {severity=vim.diagnostic.severity.ERROR}, - underline = false, - }, diagnostic_ns) + vim.diagnostic.config({ + virtual_text = { severity = vim.diagnostic.severity.ERROR }, + underline = false, + }, _G.diagnostic_ns) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_warning('Some Warning', 4, 4, 4, 4), - }, { - virtual_text = {} -- An empty table uses default values - }) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_warning('Some Warning', 4, 4, 4, 4), + }, { + virtual_text = {}, -- An empty table uses default values + }) - return count_extmarks(diagnostic_bufnr, diagnostic_ns) - ]] + return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + end) ) end) it('can use functions for config values', function() - exec_lua [[ + exec_lua(function() vim.diagnostic.config({ - virtual_text = function() return true end, - }, diagnostic_ns) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Delayed Diagnostic', 4, 4, 4, 4), + virtual_text = function() + return true + end, + }, _G.diagnostic_ns) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Delayed Diagnostic', 4, 4, 4, 4), }) - ]] + end) eq( 1, - exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]] + exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]] ) - eq(2, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]]) + eq(2, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]]) -- Now, don't enable virtual text. -- We should have one less extmark displayed. - exec_lua [[ + exec_lua(function() vim.diagnostic.config({ - virtual_text = function() return false end, - }, diagnostic_ns) - ]] + virtual_text = function() + return false + end, + }, _G.diagnostic_ns) + end) eq( 1, - exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]] + exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]] ) - eq(1, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]]) + eq(1, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]]) end) it('allows filtering by severity', function() local get_extmark_count_with_severity = function(min_severity) - return exec_lua( - [[ + return exec_lua(function(min_severity0) vim.diagnostic.config({ underline = false, virtual_text = { - severity = {min=...}, + severity = { min = min_severity0 }, }, }) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_warning('Delayed Diagnostic', 4, 4, 4, 4), + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_warning('Delayed Diagnostic', 4, 4, 4, 4), }) - return count_extmarks(diagnostic_bufnr, diagnostic_ns) - ]], - min_severity - ) + return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + end, min_severity) end -- No messages with Error or higher @@ -1600,152 +1789,158 @@ describe('vim.diagnostic', function() end) it('allows sorting by severity', function() - exec_lua [[ + exec_lua(function() vim.diagnostic.config({ underline = false, signs = true, virtual_text = true, }) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_warning('Warning', 4, 4, 4, 4), - make_error('Error', 4, 4, 4, 4), - make_info('Info', 4, 4, 4, 4), + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_warning('Warning', 4, 4, 4, 4), + _G.make_error('Error', 4, 4, 4, 4), + _G.make_info('Info', 4, 4, 4, 4), }) - function get_virt_text_and_signs(severity_sort) + function _G.get_virt_text_and_signs(severity_sort) vim.diagnostic.config({ severity_sort = severity_sort, }) - local virt_text = get_virt_text_extmarks(diagnostic_ns)[1][4].virt_text + local virt_text = _G.get_virt_text_extmarks(_G.diagnostic_ns)[1][4].virt_text local virt_texts = {} for i = 2, #virt_text - 1 do - table.insert(virt_texts, (string.gsub(virt_text[i][2], "DiagnosticVirtualText", ""))) + table.insert(virt_texts, (string.gsub(virt_text[i][2], 'DiagnosticVirtualText', ''))) end - local ns = vim.diagnostic.get_namespace(diagnostic_ns) + local ns = vim.diagnostic.get_namespace(_G.diagnostic_ns) local sign_ns = ns.user_data.sign_ns local signs = {} - local all_signs = vim.api.nvim_buf_get_extmarks(diagnostic_bufnr, sign_ns, 0, -1, {type = 'sign', details = true}) + local all_signs = vim.api.nvim_buf_get_extmarks( + _G.diagnostic_bufnr, + sign_ns, + 0, + -1, + { type = 'sign', details = true } + ) table.sort(all_signs, function(a, b) return a[1] > b[1] end) for _, v in ipairs(all_signs) do - local s = v[4].sign_hl_group:gsub('DiagnosticSign', "") + local s = v[4].sign_hl_group:gsub('DiagnosticSign', '') if not vim.tbl_contains(signs, s) then signs[#signs + 1] = s end end - return {virt_texts, signs} + return { virt_texts, signs } end - ]] + end) - local result = exec_lua [[return get_virt_text_and_signs(false)]] + local result = exec_lua [[return _G.get_virt_text_and_signs(false)]] -- Virt texts are defined lowest priority to highest, signs from -- highest to lowest eq({ 'Warn', 'Error', 'Info' }, result[1]) eq({ 'Info', 'Error', 'Warn' }, result[2]) - result = exec_lua [[return get_virt_text_and_signs(true)]] + result = exec_lua [[return _G.get_virt_text_and_signs(true)]] eq({ 'Info', 'Warn', 'Error' }, result[1]) eq({ 'Error', 'Warn', 'Info' }, result[2]) - result = exec_lua [[return get_virt_text_and_signs({ reverse = true })]] + result = exec_lua [[return _G.get_virt_text_and_signs({ reverse = true })]] eq({ 'Error', 'Warn', 'Info' }, result[1]) eq({ 'Info', 'Warn', 'Error' }, result[2]) end) it('can show diagnostic sources in virtual text', function() - local result = exec_lua [[ + local result = exec_lua(function() local diagnostics = { - make_error('Some error', 0, 0, 0, 0, 'source x'), + _G.make_error('Some error', 0, 0, 0, 0, 'source x'), } - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics, { + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics, { underline = false, virtual_text = { prefix = '', source = 'always', - } + }, }) - local extmarks = get_virt_text_extmarks(diagnostic_ns) + local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns) local virt_text = extmarks[1][4].virt_text[3][1] return virt_text - ]] + end) eq(' source x: Some error', result) - result = exec_lua [[ + result = exec_lua(function() vim.diagnostic.config({ underline = false, virtual_text = { prefix = '', source = 'if_many', - } - }, diagnostic_ns) + }, + }, _G.diagnostic_ns) - local extmarks = get_virt_text_extmarks(diagnostic_ns) + local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns) local virt_text = extmarks[1][4].virt_text[3][1] return virt_text - ]] + end) eq(' Some error', result) - result = exec_lua [[ + result = exec_lua(function() local diagnostics = { - make_error('Some error', 0, 0, 0, 0, 'source x'), - make_error('Another error', 1, 1, 1, 1, 'source y'), + _G.make_error('Some error', 0, 0, 0, 0, 'source x'), + _G.make_error('Another error', 1, 1, 1, 1, 'source y'), } - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics, { + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics, { underline = false, virtual_text = { prefix = '', source = 'if_many', - } + }, }) - local extmarks = get_virt_text_extmarks(diagnostic_ns) - local virt_text = {extmarks[1][4].virt_text[3][1], extmarks[2][4].virt_text[3][1]} + local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns) + local virt_text = { extmarks[1][4].virt_text[3][1], extmarks[2][4].virt_text[3][1] } return virt_text - ]] + end) eq(' source x: Some error', result[1]) eq(' source y: Another error', result[2]) end) it('supports a format function for diagnostic messages', function() - local result = exec_lua [[ + local result = exec_lua(function() vim.diagnostic.config({ underline = false, virtual_text = { prefix = '', format = function(diagnostic) if diagnostic.severity == vim.diagnostic.severity.ERROR then - return string.format("🔥 %s", diagnostic.message) + return string.format('🔥 %s', diagnostic.message) end - return string.format("👀 %s", diagnostic.message) + return string.format('👀 %s', diagnostic.message) end, - } + }, }) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_warning('Warning', 0, 0, 0, 0), - make_error('Error', 1, 0, 1, 0), + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_warning('Warning', 0, 0, 0, 0), + _G.make_error('Error', 1, 0, 1, 0), }) - local extmarks = get_virt_text_extmarks(diagnostic_ns) - return {extmarks[1][4].virt_text, extmarks[2][4].virt_text} - ]] + local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns) + return { extmarks[1][4].virt_text, extmarks[2][4].virt_text } + end) eq(' 👀 Warning', result[1][3][1]) eq(' 🔥 Error', result[2][3][1]) end) it('includes source for formatted diagnostics', function() - local result = exec_lua [[ + local result = exec_lua(function() vim.diagnostic.config({ underline = false, virtual_text = { @@ -1753,21 +1948,21 @@ describe('vim.diagnostic', function() source = 'always', format = function(diagnostic) if diagnostic.severity == vim.diagnostic.severity.ERROR then - return string.format("🔥 %s", diagnostic.message) + return string.format('🔥 %s', diagnostic.message) end - return string.format("👀 %s", diagnostic.message) + return string.format('👀 %s', diagnostic.message) end, - } + }, }) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_warning('Warning', 0, 0, 0, 0, 'some_linter'), - make_error('Error', 1, 0, 1, 0, 'another_linter'), + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_warning('Warning', 0, 0, 0, 0, 'some_linter'), + _G.make_error('Error', 1, 0, 1, 0, 'another_linter'), }) - local extmarks = get_virt_text_extmarks(diagnostic_ns) - return {extmarks[1][4].virt_text, extmarks[2][4].virt_text} - ]] + local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns) + return { extmarks[1][4].virt_text, extmarks[2][4].virt_text } + end) eq(' some_linter: 👀 Warning', result[1][3][1]) eq(' another_linter: 🔥 Error', result[2][3][1]) end) @@ -1775,90 +1970,94 @@ describe('vim.diagnostic', function() it('can add a prefix to virtual text', function() eq( 'E Some error', - exec_lua [[ - local diagnostics = { - make_error('Some error', 0, 0, 0, 0), - } - - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics, { - underline = false, - virtual_text = { - prefix = 'E', - suffix = '', + exec_lua(function() + local diagnostics = { + _G.make_error('Some error', 0, 0, 0, 0), } - }) - local extmarks = get_virt_text_extmarks(diagnostic_ns) - local prefix = extmarks[1][4].virt_text[2][1] - local message = extmarks[1][4].virt_text[3][1] - return prefix .. message - ]] + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics, { + underline = false, + virtual_text = { + prefix = 'E', + suffix = '', + }, + }) + + local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns) + local prefix = extmarks[1][4].virt_text[2][1] + local message = extmarks[1][4].virt_text[3][1] + return prefix .. message + end) ) eq( '[(1/1) err-code] Some error', - exec_lua [[ - local diagnostics = { - make_error('Some error', 0, 0, 0, 0, nil, 'err-code'), - } - - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics, { - underline = false, - virtual_text = { - prefix = function(diag, i, total) return string.format('[(%d/%d) %s]', i, total, diag.code) end, - suffix = '', + exec_lua(function() + local diagnostics = { + _G.make_error('Some error', 0, 0, 0, 0, nil, 'err-code'), } - }) - local extmarks = get_virt_text_extmarks(diagnostic_ns) - local prefix = extmarks[1][4].virt_text[2][1] - local message = extmarks[1][4].virt_text[3][1] - return prefix .. message - ]] + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics, { + underline = false, + virtual_text = { + prefix = function(diag, i, total) + return string.format('[(%d/%d) %s]', i, total, diag.code) + end, + suffix = '', + }, + }) + + local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns) + local prefix = extmarks[1][4].virt_text[2][1] + local message = extmarks[1][4].virt_text[3][1] + return prefix .. message + end) ) end) it('can add a suffix to virtual text', function() eq( ' Some error ✘', - exec_lua [[ - local diagnostics = { - make_error('Some error', 0, 0, 0, 0), - } - - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics, { - underline = false, - virtual_text = { - prefix = '', - suffix = ' ✘', + exec_lua(function() + local diagnostics = { + _G.make_error('Some error', 0, 0, 0, 0), } - }) - local extmarks = get_virt_text_extmarks(diagnostic_ns) - local virt_text = extmarks[1][4].virt_text[3][1] - return virt_text - ]] + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics, { + underline = false, + virtual_text = { + prefix = '', + suffix = ' ✘', + }, + }) + + local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns) + local virt_text = extmarks[1][4].virt_text[3][1] + return virt_text + end) ) eq( ' Some error [err-code]', - exec_lua [[ - local diagnostics = { - make_error('Some error', 0, 0, 0, 0, nil, 'err-code'), - } - - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics, { - underline = false, - virtual_text = { - prefix = '', - suffix = function(diag) return string.format(' [%s]', diag.code) end, + exec_lua(function() + local diagnostics = { + _G.make_error('Some error', 0, 0, 0, 0, nil, 'err-code'), } - }) - local extmarks = get_virt_text_extmarks(diagnostic_ns) - local virt_text = extmarks[1][4].virt_text[3][1] - return virt_text - ]] + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics, { + underline = false, + virtual_text = { + prefix = '', + suffix = function(diag) + return string.format(' [%s]', diag.code) + end, + }, + }) + + local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns) + local virt_text = extmarks[1][4].virt_text[3][1] + return virt_text + end) ) end) end) @@ -1872,80 +2071,80 @@ describe('vim.diagnostic', function() end) it('can perform updates after insert_leave', function() - exec_lua [[vim.api.nvim_set_current_buf(diagnostic_bufnr)]] + exec_lua [[vim.api.nvim_set_current_buf( _G.diagnostic_bufnr)]] api.nvim_input('o') eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) -- Save the diagnostics - exec_lua [[ + exec_lua(function() vim.diagnostic.config({ update_in_insert = false, }) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Delayed Diagnostic', 4, 4, 4, 4), + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Delayed Diagnostic', 4, 4, 4, 4), }) - ]] + end) -- No diagnostics displayed yet. eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) eq( 1, - exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]] + exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]] ) - eq(0, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]]) + eq(0, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]]) api.nvim_input('') eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) eq( 1, - exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]] + exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]] ) - eq(2, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]]) + eq(2, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]]) end) it('does not perform updates when not needed', function() - exec_lua [[vim.api.nvim_set_current_buf(diagnostic_bufnr)]] + exec_lua [[vim.api.nvim_set_current_buf( _G.diagnostic_bufnr)]] api.nvim_input('o') eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) -- Save the diagnostics - exec_lua [[ + exec_lua(function() vim.diagnostic.config({ update_in_insert = false, virtual_text = true, }) - DisplayCount = 0 + _G.DisplayCount = 0 local set_virtual_text = vim.diagnostic.handlers.virtual_text.show vim.diagnostic.handlers.virtual_text.show = function(...) - DisplayCount = DisplayCount + 1 + _G.DisplayCount = _G.DisplayCount + 1 return set_virtual_text(...) end - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Delayed Diagnostic', 4, 4, 4, 4), + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Delayed Diagnostic', 4, 4, 4, 4), }) - ]] + end) -- No diagnostics displayed yet. eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) eq( 1, - exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]] + exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]] ) - eq(0, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]]) - eq(0, exec_lua [[return DisplayCount]]) + eq(0, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]]) + eq(0, exec_lua [[return _G.DisplayCount]]) api.nvim_input('') eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) eq( 1, - exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]] + exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]] ) - eq(2, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]]) - eq(1, exec_lua [[return DisplayCount]]) + eq(2, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]]) + eq(1, exec_lua [[return _G.DisplayCount]]) -- Go in and out of insert mode one more time. api.nvim_input('o') @@ -1955,52 +2154,51 @@ describe('vim.diagnostic', function() eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) -- Should not have set the virtual text again. - eq(1, exec_lua [[return DisplayCount]]) + eq(1, exec_lua [[return _G.DisplayCount]]) end) it('never sets virtual text, in combination with insert leave', function() - exec_lua [[vim.api.nvim_set_current_buf(diagnostic_bufnr)]] + exec_lua [[vim.api.nvim_set_current_buf( _G.diagnostic_bufnr)]] api.nvim_input('o') eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) -- Save the diagnostics - exec_lua [[ + exec_lua(function() vim.diagnostic.config({ update_in_insert = false, virtual_text = false, }) - - DisplayCount = 0 + _G.DisplayCount = 0 local set_virtual_text = vim.diagnostic.handlers.virtual_text.show vim.diagnostic.handlers.virtual_text.show = function(...) - DisplayCount = DisplayCount + 1 + _G.DisplayCount = _G.DisplayCount + 1 return set_virtual_text(...) end - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Delayed Diagnostic', 4, 4, 4, 4), + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Delayed Diagnostic', 4, 4, 4, 4), }) - ]] + end) -- No diagnostics displayed yet. eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) eq( 1, - exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]] + exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]] ) - eq(0, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]]) - eq(0, exec_lua [[return DisplayCount]]) + eq(0, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]]) + eq(0, exec_lua [[return _G.DisplayCount]]) api.nvim_input('') eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) eq( 1, - exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]] + exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]] ) - eq(1, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]]) - eq(0, exec_lua [[return DisplayCount]]) + eq(1, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]]) + eq(0, exec_lua [[return _G.DisplayCount]]) -- Go in and out of insert mode one more time. api.nvim_input('o') @@ -2010,124 +2208,136 @@ describe('vim.diagnostic', function() eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) -- Should not have set the virtual text still. - eq(0, exec_lua [[return DisplayCount]]) + eq(0, exec_lua [[return _G.DisplayCount]]) end) it('can perform updates while in insert mode, if desired', function() - exec_lua [[vim.api.nvim_set_current_buf(diagnostic_bufnr)]] + exec_lua [[vim.api.nvim_set_current_buf( _G.diagnostic_bufnr)]] api.nvim_input('o') eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) -- Save the diagnostics - exec_lua [[ + exec_lua(function() vim.diagnostic.config({ update_in_insert = true, }) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Delayed Diagnostic', 4, 4, 4, 4), + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Delayed Diagnostic', 4, 4, 4, 4), }) - ]] + end) -- Diagnostics are displayed, because the user wanted them that way! eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) eq( 1, - exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]] + exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]] ) - eq(2, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]]) + eq(2, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]]) api.nvim_input('') eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) eq( 1, - exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]] + exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]] ) - eq(2, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]]) + eq(2, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]]) end) it('can set diagnostics without displaying them', function() eq( 0, - exec_lua [[ - vim.diagnostic.enable(false, { bufnr = diagnostic_bufnr, ns_id = diagnostic_ns }) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic From Server 1:1', 1, 1, 1, 1), - }) - return count_extmarks(diagnostic_bufnr, diagnostic_ns) - ]] + exec_lua(function() + vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns }) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic From Server 1:1', 1, 1, 1, 1), + }) + return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + end) ) eq( 2, - exec_lua [[ - vim.diagnostic.enable(true, { bufnr = diagnostic_bufnr, ns_id = diagnostic_ns }) - return count_extmarks(diagnostic_bufnr, diagnostic_ns) - ]] + exec_lua(function() + vim.diagnostic.enable(true, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns }) + return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + end) ) end) it('can set display options', function() eq( 0, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic From Server 1:1', 1, 1, 1, 1), - }, { virtual_text = false, underline = false }) - return count_extmarks(diagnostic_bufnr, diagnostic_ns) - ]] + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic From Server 1:1', 1, 1, 1, 1), + }, { virtual_text = false, underline = false }) + return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + end) ) eq( 1, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic From Server 1:1', 1, 1, 1, 1), - }, { virtual_text = true, underline = false }) - return count_extmarks(diagnostic_bufnr, diagnostic_ns) - ]] + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic From Server 1:1', 1, 1, 1, 1), + }, { virtual_text = true, underline = false }) + return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + end) ) end) it('sets and clears signs #26193 #26555', function() do - local result = exec_lua [[ + local result = exec_lua(function() vim.diagnostic.config({ signs = true, }) local diagnostics = { - make_error('Error', 1, 1, 1, 2), - make_warning('Warning', 3, 3, 3, 3), + _G.make_error('Error', 1, 1, 1, 2), + _G.make_warning('Warning', 3, 3, 3, 3), } - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) - local ns = vim.diagnostic.get_namespace(diagnostic_ns) + local ns = vim.diagnostic.get_namespace(_G.diagnostic_ns) local sign_ns = ns.user_data.sign_ns - local signs = vim.api.nvim_buf_get_extmarks(diagnostic_bufnr, sign_ns, 0, -1, {type ='sign', details = true}) + local signs = vim.api.nvim_buf_get_extmarks( + _G.diagnostic_bufnr, + sign_ns, + 0, + -1, + { type = 'sign', details = true } + ) local result = {} for _, s in ipairs(signs) do result[#result + 1] = { lnum = s[2] + 1, name = s[4].sign_hl_group } end return result - ]] + end) eq({ 2, 'DiagnosticSignError' }, { result[1].lnum, result[1].name }) eq({ 4, 'DiagnosticSignWarn' }, { result[2].lnum, result[2].name }) end do - local result = exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {}) + local result = exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {}) - local ns = vim.diagnostic.get_namespace(diagnostic_ns) + local ns = vim.diagnostic.get_namespace(_G.diagnostic_ns) local sign_ns = ns.user_data.sign_ns - return vim.api.nvim_buf_get_extmarks(diagnostic_bufnr, sign_ns, 0, -1, {type ='sign', details = true}) - ]] + return vim.api.nvim_buf_get_extmarks( + _G.diagnostic_bufnr, + sign_ns, + 0, + -1, + { type = 'sign', details = true } + ) + end) eq({}, result) end @@ -2142,22 +2352,28 @@ describe('vim.diagnostic', function() n.command('sign define DiagnosticSignInfo text= texthl= linehl=Underlined numhl=Underlined') n.command('sign define DiagnosticSignHint text= texthl= linehl=Underlined numhl=Underlined') - local result = exec_lua [[ + local result = exec_lua(function() vim.diagnostic.config({ signs = true, }) local diagnostics = { - make_error('Error', 1, 1, 1, 2), - make_warning('Warning', 3, 3, 3, 3), + _G.make_error('Error', 1, 1, 1, 2), + _G.make_warning('Warning', 3, 3, 3, 3), } - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) - local ns = vim.diagnostic.get_namespace(diagnostic_ns) + local ns = vim.diagnostic.get_namespace(_G.diagnostic_ns) local sign_ns = ns.user_data.sign_ns - local signs = vim.api.nvim_buf_get_extmarks(diagnostic_bufnr, sign_ns, 0, -1, {type ='sign', details = true}) + local signs = vim.api.nvim_buf_get_extmarks( + _G.diagnostic_bufnr, + sign_ns, + 0, + -1, + { type = 'sign', details = true } + ) local result = {} for _, s in ipairs(signs) do result[#result + 1] = { @@ -2169,7 +2385,7 @@ describe('vim.diagnostic', function() } end return result - ]] + end) eq({ lnum = 2, @@ -2193,65 +2409,67 @@ describe('vim.diagnostic', function() it('can display a header', function() eq( { 'Diagnostics:', '1. Syntax error' }, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 0, 1, 0, 3), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float() - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + local float_bufnr, winnr = vim.diagnostic.open_float() + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) eq( { "We're no strangers to love...", '1. Syntax error' }, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 0, 1, 0, 3), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float({header = "We're no strangers to love..."}) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + local float_bufnr, winnr = + vim.diagnostic.open_float({ header = "We're no strangers to love..." }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) eq( { 'You know the rules', '1. Syntax error' }, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 0, 1, 0, 3), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float({header = {'You know the rules', 'Search'}}) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + local float_bufnr, winnr = + vim.diagnostic.open_float({ header = { 'You know the rules', 'Search' } }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) end) it('can show diagnostics from the whole buffer', function() eq( { '1. Syntax error', '2. Some warning' }, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 0, 1, 0, 3), - make_warning("Some warning", 1, 1, 1, 3), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float({header = false, scope="buffer"}) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3), + _G.make_warning('Some warning', 1, 1, 1, 3), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + local float_bufnr, winnr = vim.diagnostic.open_float({ header = false, scope = 'buffer' }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) end) @@ -2259,69 +2477,70 @@ describe('vim.diagnostic', function() -- Using cursor position eq( { '1. Some warning' }, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 0, 1, 0, 3), - make_warning("Some warning", 1, 1, 1, 3), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - vim.api.nvim_win_set_cursor(0, {2, 1}) - local float_bufnr, winnr = vim.diagnostic.open_float({header=false}) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3), + _G.make_warning('Some warning', 1, 1, 1, 3), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + vim.api.nvim_win_set_cursor(0, { 2, 1 }) + local float_bufnr, winnr = vim.diagnostic.open_float({ header = false }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) -- With specified position eq( { '1. Some warning' }, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 0, 1, 0, 3), - make_warning("Some warning", 1, 1, 1, 3), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - vim.api.nvim_win_set_cursor(0, {1, 1}) - local float_bufnr, winnr = vim.diagnostic.open_float({header=false, pos=1}) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3), + _G.make_warning('Some warning', 1, 1, 1, 3), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + vim.api.nvim_win_set_cursor(0, { 1, 1 }) + local float_bufnr, winnr = vim.diagnostic.open_float({ header = false, pos = 1 }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) -- End position is exclusive eq( vim.NIL, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 1, 1, 2, 0), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - vim.api.nvim_win_set_cursor(0, {1, 1}) - local _, winnr = vim.diagnostic.open_float(0, {header=false, pos={2,0}}) - return winnr - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 1, 1, 2, 0), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + vim.api.nvim_win_set_cursor(0, { 1, 1 }) + local _, winnr = vim.diagnostic.open_float(0, { header = false, pos = { 2, 0 } }) + return winnr + end) ) -- Works when width == 0 eq( { '1. Syntax error' }, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 2, 0, 2, 0), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - vim.api.nvim_win_set_cursor(0, {1, 1}) - local float_bufnr, winnr = vim.diagnostic.open_float(0, {header=false, pos={2,1}}) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 2, 0, 2, 0), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + vim.api.nvim_win_set_cursor(0, { 1, 1 }) + local float_bufnr, winnr = + vim.diagnostic.open_float(0, { header = false, pos = { 2, 1 } }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) end) @@ -2329,87 +2548,94 @@ describe('vim.diagnostic', function() -- Using cursor position eq( { 'Syntax error' }, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 1, 1, 1, 3), - make_warning("Some warning", 1, 3, 1, 4), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - vim.api.nvim_win_set_cursor(0, {2, 2}) - local float_bufnr, winnr = vim.diagnostic.open_float({header=false, scope="cursor"}) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 1, 1, 1, 3), + _G.make_warning('Some warning', 1, 3, 1, 4), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + vim.api.nvim_win_set_cursor(0, { 2, 2 }) + local float_bufnr, winnr = vim.diagnostic.open_float({ header = false, scope = 'cursor' }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) -- With specified position eq( { 'Some warning' }, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 1, 1, 1, 3), - make_warning("Some warning", 1, 3, 1, 4), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - vim.api.nvim_win_set_cursor(0, {1, 1}) - local float_bufnr, winnr = vim.diagnostic.open_float({header=false, scope="cursor", pos={1,3}}) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 1, 1, 1, 3), + _G.make_warning('Some warning', 1, 3, 1, 4), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + vim.api.nvim_win_set_cursor(0, { 1, 1 }) + local float_bufnr, winnr = + vim.diagnostic.open_float({ header = false, scope = 'cursor', pos = { 1, 3 } }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) -- With column position past the end of the line. #16062 eq( { 'Syntax error' }, - exec_lua [[ - local first_line_len = #vim.api.nvim_buf_get_lines(diagnostic_bufnr, 0, 1, true)[1] - local diagnostics = { - make_error("Syntax error", 0, first_line_len + 1, 1, 0), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - vim.api.nvim_win_set_cursor(0, {1, 1}) - local float_bufnr, winnr = vim.diagnostic.open_float({header=false, scope="cursor", pos={0,first_line_len}}) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local first_line_len = #vim.api.nvim_buf_get_lines(_G.diagnostic_bufnr, 0, 1, true)[1] + local diagnostics = { + _G.make_error('Syntax error', 0, first_line_len + 1, 1, 0), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + vim.api.nvim_win_set_cursor(0, { 1, 1 }) + local float_bufnr, winnr = vim.diagnostic.open_float({ + header = false, + scope = 'cursor', + pos = { 0, first_line_len }, + }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) -- End position is exclusive eq( vim.NIL, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 1, 1, 1, 3), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - vim.api.nvim_win_set_cursor(0, {1, 1}) - local _, winnr = vim.diagnostic.open_float(0, {header=false, scope="cursor", pos={1,3}}) - return winnr - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 1, 1, 1, 3), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + vim.api.nvim_win_set_cursor(0, { 1, 1 }) + local _, winnr = + vim.diagnostic.open_float(0, { header = false, scope = 'cursor', pos = { 1, 3 } }) + return winnr + end) ) -- Works when width == 0 eq( { 'Syntax error' }, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 2, 0, 2, 0), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - vim.api.nvim_win_set_cursor(0, {1, 1}) - local float_bufnr, winnr = vim.diagnostic.open_float({header=false, scope="cursor", pos={2,1}}) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 2, 0, 2, 0), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + vim.api.nvim_win_set_cursor(0, { 1, 1 }) + local float_bufnr, winnr = + vim.diagnostic.open_float({ header = false, scope = 'cursor', pos = { 2, 1 } }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) end) @@ -2421,17 +2647,17 @@ describe('vim.diagnostic', function() -- 1. eq( 2, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 0, 1, 0, 3), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float(diagnostic_bufnr) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return #lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + local float_bufnr, winnr = vim.diagnostic.open_float(_G.diagnostic_bufnr) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return #lines + end) ) end ) @@ -2439,43 +2665,44 @@ describe('vim.diagnostic', function() it('only reports diagnostics from the current buffer when bufnr is omitted #15710', function() eq( 2, - exec_lua [[ - local other_bufnr = vim.api.nvim_create_buf(true, false) - local buf_1_diagnostics = { - make_error("Syntax error", 0, 1, 0, 3), - } - local buf_2_diagnostics = { - make_warning("Some warning", 0, 1, 0, 3), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, buf_1_diagnostics) - vim.diagnostic.set(other_ns, other_bufnr, buf_2_diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float() - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return #lines - ]] + exec_lua(function() + local other_bufnr = vim.api.nvim_create_buf(true, false) + local buf_1_diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3), + } + local buf_2_diagnostics = { + _G.make_warning('Some warning', 0, 1, 0, 3), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, buf_1_diagnostics) + vim.diagnostic.set(_G.other_ns, other_bufnr, buf_2_diagnostics) + local float_bufnr, winnr = vim.diagnostic.open_float() + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return #lines + end) ) end) it('allows filtering by namespace', function() eq( 2, - exec_lua [[ - local ns_1_diagnostics = { - make_error("Syntax error", 0, 1, 0, 3), - } - local ns_2_diagnostics = { - make_warning("Some warning", 0, 1, 0, 3), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, ns_1_diagnostics) - vim.diagnostic.set(other_ns, diagnostic_bufnr, ns_2_diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float(diagnostic_bufnr, {namespace = diagnostic_ns}) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return #lines - ]] + exec_lua(function() + local ns_1_diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3), + } + local ns_2_diagnostics = { + _G.make_warning('Some warning', 0, 1, 0, 3), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diagnostics) + vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diagnostics) + local float_bufnr, winnr = + vim.diagnostic.open_float(_G.diagnostic_bufnr, { namespace = _G.diagnostic_ns }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return #lines + end) ) end) @@ -2486,17 +2713,18 @@ describe('vim.diagnostic', function() -- 1. eq( 1, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 0, 1, 0, 3), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float(diagnostic_bufnr, {header = false}) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return #lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + local float_bufnr, winnr = + vim.diagnostic.open_float(_G.diagnostic_bufnr, { header = false }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return #lines + end) ) end ) @@ -2504,138 +2732,141 @@ describe('vim.diagnostic', function() it('clamps diagnostic line numbers within the valid range', function() eq( 1, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 6, 0, 6, 0), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float(diagnostic_bufnr, {header = false, pos = 5}) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return #lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 6, 0, 6, 0), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + local float_bufnr, winnr = + vim.diagnostic.open_float(_G.diagnostic_bufnr, { header = false, pos = 5 }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return #lines + end) ) end) it('can show diagnostic source', function() - exec_lua [[vim.api.nvim_win_set_buf(0, diagnostic_bufnr)]] + exec_lua [[vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)]] eq( { '1. Syntax error' }, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 0, 1, 0, 3, "source x"), - } - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float(diagnostic_bufnr, { - header = false, - source = "if_many", - }) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3, 'source x'), + } + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + local float_bufnr, winnr = vim.diagnostic.open_float(_G.diagnostic_bufnr, { + header = false, + source = 'if_many', + }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) eq( { '1. source x: Syntax error' }, - exec_lua [[ - local float_bufnr, winnr = vim.diagnostic.open_float(diagnostic_bufnr, { - header = false, - source = "always", - }) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local float_bufnr, winnr = vim.diagnostic.open_float(_G.diagnostic_bufnr, { + header = false, + source = 'always', + }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) eq( { '1. source x: Syntax error', '2. source y: Another error' }, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 0, 1, 0, 3, "source x"), - make_error("Another error", 0, 1, 0, 3, "source y"), - } - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float(diagnostic_bufnr, { - header = false, - source = "if_many", - }) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3, 'source x'), + _G.make_error('Another error', 0, 1, 0, 3, 'source y'), + } + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + local float_bufnr, winnr = vim.diagnostic.open_float(_G.diagnostic_bufnr, { + header = false, + source = 'if_many', + }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) end) it('respects severity_sort', function() - exec_lua [[vim.api.nvim_win_set_buf(0, diagnostic_bufnr)]] + exec_lua [[vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)]] eq( { '1. Syntax error', '2. Info', '3. Error', '4. Warning' }, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 0, 1, 0, 3), - make_info('Info', 0, 3, 0, 4), - make_error('Error', 0, 2, 0, 2), - make_warning('Warning', 0, 0, 0, 1), - } + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3), + _G.make_info('Info', 0, 3, 0, 4), + _G.make_error('Error', 0, 2, 0, 2), + _G.make_warning('Warning', 0, 0, 0, 1), + } - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) - vim.diagnostic.config({severity_sort = false}) + vim.diagnostic.config({ severity_sort = false }) - local float_bufnr, winnr = vim.diagnostic.open_float(diagnostic_bufnr, { header = false }) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + local float_bufnr, winnr = + vim.diagnostic.open_float(_G.diagnostic_bufnr, { header = false }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) eq( { '1. Syntax error', '2. Error', '3. Warning', '4. Info' }, - exec_lua [[ - vim.diagnostic.config({severity_sort = true}) - local float_bufnr, winnr = vim.diagnostic.open_float(diagnostic_bufnr, { header = false }) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + vim.diagnostic.config({ severity_sort = true }) + local float_bufnr, winnr = + vim.diagnostic.open_float(_G.diagnostic_bufnr, { header = false }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) eq( { '1. Info', '2. Warning', '3. Error', '4. Syntax error' }, - exec_lua [[ - vim.diagnostic.config({severity_sort = { reverse = true } }) - local float_bufnr, winnr = vim.diagnostic.open_float(diagnostic_bufnr, { header = false }) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + vim.diagnostic.config({ severity_sort = { reverse = true } }) + local float_bufnr, winnr = + vim.diagnostic.open_float(_G.diagnostic_bufnr, { header = false }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) end) it('can filter by severity', function() local count_diagnostics_with_severity = function(min_severity, max_severity) - return exec_lua( - [[ - local min_severity, max_severity = ... + return exec_lua(function(min_severity0, max_severity0) vim.diagnostic.config({ float = { - severity = {min=min_severity, max=max_severity}, + severity = { min = min_severity0, max = max_severity0 }, }, }) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error("Syntax error", 0, 1, 0, 3), - make_info('Info', 0, 3, 0, 4), - make_error('Error', 0, 2, 0, 2), - make_warning('Warning', 0, 0, 0, 1), + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Syntax error', 0, 1, 0, 3), + _G.make_info('Info', 0, 3, 0, 4), + _G.make_error('Error', 0, 2, 0, 2), + _G.make_warning('Warning', 0, 0, 0, 1), }) - local float_bufnr, winnr = vim.diagnostic.open_float(diagnostic_bufnr, { header = false }) + local float_bufnr, winnr = + vim.diagnostic.open_float(_G.diagnostic_bufnr, { header = false }) if not float_bufnr then return 0 end @@ -2643,10 +2874,7 @@ describe('vim.diagnostic', function() local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return #lines - ]], - min_severity, - max_severity - ) + end, min_severity, max_severity) end eq(2, count_diagnostics_with_severity('ERROR')) @@ -2660,83 +2888,84 @@ describe('vim.diagnostic', function() -- Default is to add a number eq( { '1. Syntax error', '2. Some warning' }, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 0, 1, 0, 3), - make_warning("Some warning", 1, 1, 1, 3), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float({header = false, scope = "buffer"}) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3), + _G.make_warning('Some warning', 1, 1, 1, 3), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + local float_bufnr, winnr = vim.diagnostic.open_float({ header = false, scope = 'buffer' }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) eq( { 'Syntax error', 'Some warning' }, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 0, 1, 0, 3), - make_warning("Some warning", 1, 1, 1, 3), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float({header = false, scope = "buffer", prefix = ""}) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3), + _G.make_warning('Some warning', 1, 1, 1, 3), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + local float_bufnr, winnr = + vim.diagnostic.open_float({ header = false, scope = 'buffer', prefix = '' }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) eq( { '1. Syntax error', '2. Some warning' }, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 0, 1, 0, 3), - make_warning("Some warning", 0, 1, 0, 3), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float({ - header = false, - prefix = function(_, i, total) - -- Only show a number if there is more than one diagnostic - if total > 1 then - return string.format("%d. ", i) - end - return "" - end, - }) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3), + _G.make_warning('Some warning', 0, 1, 0, 3), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + local float_bufnr, winnr = vim.diagnostic.open_float({ + header = false, + prefix = function(_, i, total) + -- Only show a number if there is more than one diagnostic + if total > 1 then + return string.format('%d. ', i) + end + return '' + end, + }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) eq( { 'Syntax error' }, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 0, 1, 0, 3), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float({ - header = false, - prefix = function(_, i, total) - -- Only show a number if there is more than one diagnostic - if total > 1 then - return string.format("%d. ", i) - end - return "" - end, - }) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + local float_bufnr, winnr = vim.diagnostic.open_float({ + header = false, + prefix = function(_, i, total) + -- Only show a number if there is more than one diagnostic + if total > 1 then + return string.format('%d. ', i) + end + return '' + end, + }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) eq( @@ -2749,50 +2978,51 @@ describe('vim.diagnostic', function() -- Default is to render the diagnostic error code eq( { '1. Syntax error [code-x]', '2. Some warning [code-y]' }, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 0, 1, 0, 3, nil, "code-x"), - make_warning("Some warning", 1, 1, 1, 3, nil, "code-y"), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float({header = false, scope = "buffer"}) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3, nil, 'code-x'), + _G.make_warning('Some warning', 1, 1, 1, 3, nil, 'code-y'), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + local float_bufnr, winnr = vim.diagnostic.open_float({ header = false, scope = 'buffer' }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) eq( { '1. Syntax error', '2. Some warning' }, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 0, 1, 0, 3, nil, "code-x"), - make_warning("Some warning", 1, 1, 1, 3, nil, "code-y"), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float({header = false, scope = "buffer", suffix = ""}) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3, nil, 'code-x'), + _G.make_warning('Some warning', 1, 1, 1, 3, nil, 'code-y'), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + local float_bufnr, winnr = + vim.diagnostic.open_float({ header = false, scope = 'buffer', suffix = '' }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) -- Suffix is rendered on the last line of a multiline diagnostic eq( { '1. Syntax error', ' More context [code-x]' }, - exec_lua [[ - local diagnostics = { - make_error("Syntax error\nMore context", 0, 1, 0, 3, nil, "code-x"), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float({header = false, scope = "buffer"}) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error\nMore context', 0, 1, 0, 3, nil, 'code-x'), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + local float_bufnr, winnr = vim.diagnostic.open_float({ header = false, scope = 'buffer' }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) eq( @@ -2804,132 +3034,134 @@ describe('vim.diagnostic', function() it('works with the old signature', function() eq( { '1. Syntax error' }, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 0, 1, 0, 3), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float(0, { header = false }) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + local float_bufnr, winnr = vim.diagnostic.open_float(0, { header = false }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) end) it('works for multi-line diagnostics #21949', function() -- create diagnostic - exec_lua [[ + exec_lua(function() local diagnostics = { - make_error("Error in two lines lnum is 1 and end_lnum is 2", 1, 1, 2, 3), + _G.make_error('Error in two lines lnum is 1 and end_lnum is 2', 1, 1, 2, 3), } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - ]] + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + end) -- open float failed non diagnostic lnum eq( vim.NIL, - exec_lua [[ - vim.api.nvim_win_set_cursor(0, {1, 0}) - local _, winnr = vim.diagnostic.open_float(0, { header = false }) - return winnr - ]] + exec_lua(function() + vim.api.nvim_win_set_cursor(0, { 1, 0 }) + local _, winnr = vim.diagnostic.open_float(0, { header = false }) + return winnr + end) ) eq( vim.NIL, - exec_lua [[ - vim.api.nvim_win_set_cursor(0, {1, 0}) - local _, winnr = vim.diagnostic.open_float(0, { header = false, scope = "cursor" }) - return winnr - ]] + exec_lua(function() + vim.api.nvim_win_set_cursor(0, { 1, 0 }) + local _, winnr = vim.diagnostic.open_float(0, { header = false, scope = 'cursor' }) + return winnr + end) ) -- can open a float window on lnum 1 eq( { '1. Error in two lines lnum is 1 and end_lnum is 2' }, - exec_lua [[ - vim.api.nvim_win_set_cursor(0, {2, 0}) - local float_bufnr, winnr = vim.diagnostic.open_float(0, { header = false }) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + vim.api.nvim_win_set_cursor(0, { 2, 0 }) + local float_bufnr, winnr = vim.diagnostic.open_float(0, { header = false }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) -- can open a cursor-scoped float window on lnum 1 eq( { 'Error in two lines lnum is 1 and end_lnum is 2' }, - exec_lua [[ - vim.api.nvim_win_set_cursor(0, {2, 1}) - local float_bufnr, winnr = vim.diagnostic.open_float(0, { header = false, scope = "cursor" }) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + vim.api.nvim_win_set_cursor(0, { 2, 1 }) + local float_bufnr, winnr = + vim.diagnostic.open_float(0, { header = false, scope = 'cursor' }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) -- can open a float window on end_lnum 2 eq( { '1. Error in two lines lnum is 1 and end_lnum is 2' }, - exec_lua [[ - vim.api.nvim_win_set_cursor(0, {3, 0}) - local float_bufnr, winnr = vim.diagnostic.open_float(0, { header = false }) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + vim.api.nvim_win_set_cursor(0, { 3, 0 }) + local float_bufnr, winnr = vim.diagnostic.open_float(0, { header = false }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) -- can open a cursor-scoped float window on end_lnum 2 eq( { 'Error in two lines lnum is 1 and end_lnum is 2' }, - exec_lua [[ - vim.api.nvim_win_set_cursor(0, {3, 2}) - local float_bufnr, winnr = vim.diagnostic.open_float(0, { header = false, scope = "cursor" }) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + vim.api.nvim_win_set_cursor(0, { 3, 2 }) + local float_bufnr, winnr = + vim.diagnostic.open_float(0, { header = false, scope = 'cursor' }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) end) end) describe('setloclist()', function() it('sets diagnostics in lnum order', function() - local loc_list = exec_lua [[ - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + local loc_list = exec_lua(function() + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Farther Diagnostic', 4, 4, 4, 4), - make_error('Lower Diagnostic', 1, 1, 1, 1), + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Farther Diagnostic', 4, 4, 4, 4), + _G.make_error('Lower Diagnostic', 1, 1, 1, 1), }) vim.diagnostic.setloclist() return vim.fn.getloclist(0) - ]] + end) assert(loc_list[1].lnum < loc_list[2].lnum) end) it('sets diagnostics in lnum order, regardless of namespace', function() - local loc_list = exec_lua [[ - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + local loc_list = exec_lua(function() + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Lower Diagnostic', 1, 1, 1, 1), + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Lower Diagnostic', 1, 1, 1, 1), }) - vim.diagnostic.set(other_ns, diagnostic_bufnr, { - make_warning('Farther Diagnostic', 4, 4, 4, 4), + vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, { + _G.make_warning('Farther Diagnostic', 4, 4, 4, 4), }) vim.diagnostic.setloclist() return vim.fn.getloclist(0) - ]] + end) assert(loc_list[1].lnum < loc_list[2].lnum) end) @@ -2948,22 +3180,23 @@ describe('vim.diagnostic', function() } eq( diagnostic, - exec_lua( - [[ - return vim.diagnostic.match(..., "^(%w+): [^:]+:(%d+):(%d+):(.+)$", {"severity", "lnum", "col", "message"}) - ]], - msg - ) + exec_lua(function(msg0) + return vim.diagnostic.match( + msg0, + '^(%w+): [^:]+:(%d+):(%d+):(.+)$', + { 'severity', 'lnum', 'col', 'message' } + ) + end, msg) ) end) it('returns nil if the pattern fails to match', function() eq( NIL, - exec_lua [[ - local msg = "The answer to life, the universe, and everything is" - return vim.diagnostic.match(msg, "This definitely will not match", {}) - ]] + exec_lua(function() + local msg = 'The answer to life, the universe, and everything is' + return vim.diagnostic.match(msg, 'This definitely will not match', {}) + end) ) end) @@ -2979,12 +3212,15 @@ describe('vim.diagnostic', function() } eq( diagnostic, - exec_lua( - [[ - return vim.diagnostic.match(..., "^[^:]+:(%d+):(.+)$", {"lnum", "message"}, nil, {severity = vim.diagnostic.severity.INFO}) - ]], - msg - ) + exec_lua(function(msg0) + return vim.diagnostic.match( + msg0, + '^[^:]+:(%d+):(.+)$', + { 'lnum', 'message' }, + nil, + { severity = vim.diagnostic.severity.INFO } + ) + end, msg) ) end) @@ -3000,38 +3236,40 @@ describe('vim.diagnostic', function() } eq( diagnostic, - exec_lua( - [[ - return vim.diagnostic.match(..., "^(%d+):(%w+):(.+)$", {"lnum", "severity", "message"}, {FATAL = vim.diagnostic.severity.ERROR}) - ]], - msg - ) + exec_lua(function(msg0) + return vim.diagnostic.match( + msg0, + '^(%d+):(%w+):(.+)$', + { 'lnum', 'severity', 'message' }, + { FATAL = vim.diagnostic.severity.ERROR } + ) + end, msg) ) end) end) describe('toqflist() and fromqflist()', function() it('works', function() - local result = exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Error 1', 0, 1, 0, 1), - make_error('Error 2', 1, 1, 1, 1), - make_warning('Warning', 2, 2, 2, 2), - }) + local result = exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Error 1', 0, 1, 0, 1), + _G.make_error('Error 2', 1, 1, 1, 1), + _G.make_warning('Warning', 2, 2, 2, 2), + }) - local diagnostics = vim.diagnostic.get(diagnostic_bufnr) - vim.fn.setqflist(vim.diagnostic.toqflist(diagnostics)) - local list = vim.fn.getqflist() - local new_diagnostics = vim.diagnostic.fromqflist(list) + local diagnostics = vim.diagnostic.get(_G.diagnostic_bufnr) + vim.fn.setqflist(vim.diagnostic.toqflist(diagnostics)) + local list = vim.fn.getqflist() + local new_diagnostics = vim.diagnostic.fromqflist(list) - -- Remove namespace since it isn't present in the return value of - -- fromlist() - for _, v in ipairs(diagnostics) do - v.namespace = nil - end + -- Remove namespace since it isn't present in the return value of + -- fromlist() + for _, v in ipairs(diagnostics) do + v.namespace = nil + end - return {diagnostics, new_diagnostics} - ]] + return { diagnostics, new_diagnostics } + end) eq(result[1], result[2]) end) end) @@ -3051,179 +3289,181 @@ describe('vim.diagnostic', function() it('can add new handlers', function() eq( true, - exec_lua [[ - local handler_called = false - vim.diagnostic.handlers.test = { - show = function(namespace, bufnr, diagnostics, opts) - assert(namespace == diagnostic_ns) - assert(bufnr == diagnostic_bufnr) - assert(#diagnostics == 1) - assert(opts.test.some_opt == 42) - handler_called = true - end, - } + exec_lua(function() + local handler_called = false + vim.diagnostic.handlers.test = { + show = function(namespace, bufnr, diagnostics, opts) + assert(namespace == _G.diagnostic_ns) + assert(bufnr == _G.diagnostic_bufnr) + assert(#diagnostics == 1) + assert(opts.test.some_opt == 42) + handler_called = true + end, + } - vim.diagnostic.config({test = {some_opt = 42}}) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_warning("Warning", 0, 0, 0, 0), - }) - return handler_called - ]] + vim.diagnostic.config({ test = { some_opt = 42 } }) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_warning('Warning', 0, 0, 0, 0), + }) + return handler_called + end) ) end) it('can disable handlers by setting the corresponding option to false', function() eq( false, - exec_lua [[ - local handler_called = false - vim.diagnostic.handlers.test = { - show = function(namespace, bufnr, diagnostics, opts) - handler_called = true - end, - } + exec_lua(function() + local handler_called = false + vim.diagnostic.handlers.test = { + show = function(_, _, _, _) + handler_called = true + end, + } - vim.diagnostic.config({test = false}) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_warning("Warning", 0, 0, 0, 0), - }) - return handler_called - ]] + vim.diagnostic.config({ test = false }) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_warning('Warning', 0, 0, 0, 0), + }) + return handler_called + end) ) end) it("always calls a handler's hide function if defined", function() eq( { false, true }, - exec_lua [[ - local hide_called = false - local show_called = false - vim.diagnostic.handlers.test = { - show = function(namespace, bufnr, diagnostics, opts) - show_called = true - end, - hide = function(namespace, bufnr) - assert(namespace == diagnostic_ns) - assert(bufnr == diagnostic_bufnr) - hide_called = true - end, - } + exec_lua(function() + local hide_called = false + local show_called = false + vim.diagnostic.handlers.test = { + show = function(_, _, _, _) + show_called = true + end, + hide = function(namespace, bufnr) + assert(namespace == _G.diagnostic_ns) + assert(bufnr == _G.diagnostic_bufnr) + hide_called = true + end, + } - vim.diagnostic.config({test = false}) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_warning("Warning", 0, 0, 0, 0), - }) - vim.diagnostic.hide(diagnostic_ns, diagnostic_bufnr) - return {show_called, hide_called} - ]] + vim.diagnostic.config({ test = false }) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_warning('Warning', 0, 0, 0, 0), + }) + vim.diagnostic.hide(_G.diagnostic_ns, _G.diagnostic_bufnr) + return { show_called, hide_called } + end) ) end) it('triggers the autocommand when diagnostics are set', function() eq( { true, true }, - exec_lua [[ - -- Set a different buffer as current to test that is being set properly in - -- DiagnosticChanged callbacks - local tmp = vim.api.nvim_create_buf(false, true) - vim.api.nvim_set_current_buf(tmp) - - local triggered = {} - vim.api.nvim_create_autocmd('DiagnosticChanged', { - callback = function(args) - triggered = {args.buf, #args.data.diagnostics} - end, - }) - vim.api.nvim_buf_set_name(diagnostic_bufnr, "test | test") - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic', 0, 0, 0, 0) - }) - return { - triggered[1] == diagnostic_bufnr, - triggered[2] == 1, - } - ]] + exec_lua(function() + -- Set a different buffer as current to test that is being set properly in + -- DiagnosticChanged callbacks + local tmp = vim.api.nvim_create_buf(false, true) + vim.api.nvim_set_current_buf(tmp) + + local triggered = {} + vim.api.nvim_create_autocmd('DiagnosticChanged', { + callback = function(args) + triggered = { args.buf, #args.data.diagnostics } + end, + }) + vim.api.nvim_buf_set_name(_G.diagnostic_bufnr, 'test | test') + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic', 0, 0, 0, 0), + }) + return { + triggered[1] == _G.diagnostic_bufnr, + triggered[2] == 1, + } + end) ) end) it('triggers the autocommand when diagnostics are cleared', function() eq( true, - exec_lua [[ - local tmp = vim.api.nvim_create_buf(false, true) - vim.api.nvim_set_current_buf(tmp) - vim.g.diagnostic_autocmd_triggered = 0 - vim.cmd('autocmd DiagnosticChanged * let g:diagnostic_autocmd_triggered = +expand("")') - vim.api.nvim_buf_set_name(diagnostic_bufnr, "test | test") - vim.diagnostic.reset(diagnostic_ns, diagnostic_bufnr) - return vim.g.diagnostic_autocmd_triggered == diagnostic_bufnr - ]] + exec_lua(function() + local tmp = vim.api.nvim_create_buf(false, true) + vim.api.nvim_set_current_buf(tmp) + vim.g.diagnostic_autocmd_triggered = 0 + vim.cmd( + 'autocmd DiagnosticChanged * let g:diagnostic_autocmd_triggered = +expand("")' + ) + vim.api.nvim_buf_set_name(_G.diagnostic_bufnr, 'test | test') + vim.diagnostic.reset(_G.diagnostic_ns, _G.diagnostic_bufnr) + return vim.g.diagnostic_autocmd_triggered == _G.diagnostic_bufnr + end) ) end) it('is_enabled', function() eq( { false, false, false, false, false }, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), - }) - vim.api.nvim_set_current_buf(diagnostic_bufnr) - vim.diagnostic.enable(false) - return { - vim.diagnostic.is_enabled(), - vim.diagnostic.is_enabled{ bufnr = 0 }, - vim.diagnostic.is_enabled{ bufnr = diagnostic_bufnr }, - vim.diagnostic.is_enabled{ bufnr = diagnostic_bufnr, ns_id = diagnostic_ns }, - vim.diagnostic.is_enabled{ bufnr = 0, ns_id = diagnostic_ns }, - } - ]] + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #1', 1, 1, 1, 1), + }) + vim.api.nvim_set_current_buf(_G.diagnostic_bufnr) + vim.diagnostic.enable(false) + return { + vim.diagnostic.is_enabled(), + vim.diagnostic.is_enabled { bufnr = 0 }, + vim.diagnostic.is_enabled { bufnr = _G.diagnostic_bufnr }, + vim.diagnostic.is_enabled { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns }, + vim.diagnostic.is_enabled { bufnr = 0, ns_id = _G.diagnostic_ns }, + } + end) ) eq( { true, true, true, true, true }, - exec_lua [[ - vim.diagnostic.enable() - return { - vim.diagnostic.is_enabled(), - vim.diagnostic.is_enabled{ bufnr = 0 }, - vim.diagnostic.is_enabled{ bufnr = diagnostic_bufnr }, - vim.diagnostic.is_enabled{ bufnr = diagnostic_bufnr, ns_id = diagnostic_ns }, - vim.diagnostic.is_enabled{ bufnr = 0, ns_id = diagnostic_ns }, - } - ]] + exec_lua(function() + vim.diagnostic.enable() + return { + vim.diagnostic.is_enabled(), + vim.diagnostic.is_enabled { bufnr = 0 }, + vim.diagnostic.is_enabled { bufnr = _G.diagnostic_bufnr }, + vim.diagnostic.is_enabled { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns }, + vim.diagnostic.is_enabled { bufnr = 0, ns_id = _G.diagnostic_ns }, + } + end) ) end) it('is_disabled (deprecated)', function() eq( { true, true, true, true }, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), - }) - vim.api.nvim_set_current_buf(diagnostic_bufnr) - vim.diagnostic.disable() - return { - vim.diagnostic.is_disabled(), - vim.diagnostic.is_disabled(diagnostic_bufnr), - vim.diagnostic.is_disabled(diagnostic_bufnr, diagnostic_ns), - vim.diagnostic.is_disabled(_, diagnostic_ns), - } - ]] + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #1', 1, 1, 1, 1), + }) + vim.api.nvim_set_current_buf(_G.diagnostic_bufnr) + vim.diagnostic.disable() + return { + vim.diagnostic.is_disabled(), + vim.diagnostic.is_disabled(_G.diagnostic_bufnr), + vim.diagnostic.is_disabled(_G.diagnostic_bufnr, _G.diagnostic_ns), + vim.diagnostic.is_disabled(0, _G.diagnostic_ns), + } + end) ) eq( { false, false, false, false }, - exec_lua [[ - vim.diagnostic.enable() - return { - vim.diagnostic.is_disabled(), - vim.diagnostic.is_disabled(diagnostic_bufnr), - vim.diagnostic.is_disabled(diagnostic_bufnr, diagnostic_ns), - vim.diagnostic.is_disabled(_, diagnostic_ns), - } - ]] + exec_lua(function() + vim.diagnostic.enable() + return { + vim.diagnostic.is_disabled(), + vim.diagnostic.is_disabled(_G.diagnostic_bufnr), + vim.diagnostic.is_disabled(_G.diagnostic_bufnr, _G.diagnostic_ns), + vim.diagnostic.is_disabled(0, _G.diagnostic_ns), + } + end) ) end) end) diff --git a/test/functional/lua/filetype_spec.lua b/test/functional/lua/filetype_spec.lua index 7db04e6f6b..b5eb9fab23 100644 --- a/test/functional/lua/filetype_spec.lua +++ b/test/functional/lua/filetype_spec.lua @@ -18,90 +18,82 @@ describe('vim.filetype', function() before_each(function() clear() - exec_lua [[ + exec_lua(function() local bufnr = vim.api.nvim_create_buf(true, false) vim.api.nvim_set_current_buf(bufnr) - ]] + end) end) it('works with extensions', function() eq( 'radicalscript', - exec_lua [[ - vim.filetype.add({ - extension = { - rs = 'radicalscript', - }, - }) - return vim.filetype.match({ filename = 'main.rs' }) - ]] + exec_lua(function() + vim.filetype.add({ + extension = { + rs = 'radicalscript', + }, + }) + return vim.filetype.match({ filename = 'main.rs' }) + end) ) end) it('prioritizes filenames over extensions', function() eq( 'somethingelse', - exec_lua [[ - vim.filetype.add({ - extension = { - rs = 'radicalscript', - }, - filename = { - ['main.rs'] = 'somethingelse', - }, - }) - return vim.filetype.match({ filename = 'main.rs' }) - ]] + exec_lua(function() + vim.filetype.add({ + extension = { + rs = 'radicalscript', + }, + filename = { + ['main.rs'] = 'somethingelse', + }, + }) + return vim.filetype.match({ filename = 'main.rs' }) + end) ) end) it('works with filenames', function() eq( 'nim', - exec_lua [[ - vim.filetype.add({ - filename = { - ['s_O_m_e_F_i_l_e'] = 'nim', - }, - }) - return vim.filetype.match({ filename = 's_O_m_e_F_i_l_e' }) - ]] + exec_lua(function() + vim.filetype.add({ + filename = { + ['s_O_m_e_F_i_l_e'] = 'nim', + }, + }) + return vim.filetype.match({ filename = 's_O_m_e_F_i_l_e' }) + end) ) eq( 'dosini', - exec_lua( - [[ - local root = ... - vim.filetype.add({ - filename = { - ['config'] = 'toml', - [root .. '/.config/fun/config'] = 'dosini', - }, - }) - return vim.filetype.match({ filename = root .. '/.config/fun/config' }) - ]], - root - ) + exec_lua(function(root0) + vim.filetype.add({ + filename = { + ['config'] = 'toml', + [root0 .. '/.config/fun/config'] = 'dosini', + }, + }) + return vim.filetype.match({ filename = root0 .. '/.config/fun/config' }) + end, root) ) end) it('works with patterns', function() eq( 'markdown', - exec_lua( - [[ - local root = ... - vim.env.HOME = '/a-funky+home%dir' - vim.filetype.add({ - pattern = { - ['~/blog/.*%.txt'] = 'markdown', - } - }) - return vim.filetype.match({ filename = '~/blog/why_neovim_is_awesome.txt' }) - ]], - root - ) + exec_lua(function() + vim.env.HOME = '/a-funky+home%dir' + vim.filetype.add({ + pattern = { + ['~/blog/.*%.txt'] = 'markdown', + }, + }) + return vim.filetype.match({ filename = '~/blog/why_neovim_is_awesome.txt' }) + end) ) end) @@ -110,43 +102,43 @@ describe('vim.filetype', function() command('file relevant_to_me') eq( 'foss', - exec_lua [[ - vim.filetype.add({ - pattern = { - ["relevant_to_(%a+)"] = function(path, bufnr, capture) - if capture == "me" then - return "foss" - end - end, - } - }) - return vim.filetype.match({ buf = 0 }) - ]] + exec_lua(function() + vim.filetype.add({ + pattern = { + ['relevant_to_(%a+)'] = function(_, _, capture) + if capture == 'me' then + return 'foss' + end + end, + }, + }) + return vim.filetype.match({ buf = 0 }) + end) ) end) it('works with contents #22180', function() eq( 'sh', - exec_lua [[ - -- Needs to be set so detect#sh doesn't fail - vim.g.ft_ignore_pat = '\\.\\(Z\\|gz\\|bz2\\|zip\\|tgz\\)$' - return vim.filetype.match({ contents = { '#!/usr/bin/env bash' } }) - ]] + exec_lua(function() + -- Needs to be set so detect#sh doesn't fail + vim.g.ft_ignore_pat = '\\.\\(Z\\|gz\\|bz2\\|zip\\|tgz\\)$' + return vim.filetype.match({ contents = { '#!/usr/bin/env bash' } }) + end) ) end) it('considers extension mappings when matching from hashbang', function() eq( 'fooscript', - exec_lua [[ - vim.filetype.add({ - extension = { - foo = 'fooscript', - } - }) - return vim.filetype.match({ contents = { '#!/usr/bin/env foo' } }) - ]] + exec_lua(function() + vim.filetype.add({ + extension = { + foo = 'fooscript', + }, + }) + return vim.filetype.match({ contents = { '#!/usr/bin/env foo' } }) + end) ) end) diff --git a/test/functional/lua/fs_spec.lua b/test/functional/lua/fs_spec.lua index aba02ab01b..4848787ed2 100644 --- a/test/functional/lua/fs_spec.lua +++ b/test/functional/lua/fs_spec.lua @@ -141,19 +141,14 @@ describe('vim.fs', function() it('works', function() eq( true, - exec_lua( - [[ - local dir, nvim = ... - for name, type in vim.fs.dir(dir) do - if name == nvim and type == 'file' then - return true + exec_lua(function(dir, nvim) + for name, type in vim.fs.dir(dir) do + if name == nvim and type == 'file' then + return true + end end - end - return false - ]], - nvim_dir, - nvim_prog_basename - ) + return false + end, nvim_dir, nvim_prog_basename) ) end) @@ -172,27 +167,21 @@ describe('vim.fs', function() io.open('testd/a/b/c/c4', 'w'):close() local function run(dir, depth, skip) - local r = exec_lua( - [[ - local dir, depth, skip = ... + local r = exec_lua(function(dir0, depth0, skip0) local r = {} local skip_f - if skip then - skip_f = function(n) - if vim.tbl_contains(skip or {}, n) then + if skip0 then + skip_f = function(n0) + if vim.tbl_contains(skip0 or {}, n0) then return false end end end - for name, type_ in vim.fs.dir(dir, { depth = depth, skip = skip_f }) do + for name, type_ in vim.fs.dir(dir0, { depth = depth0, skip = skip_f }) do r[name] = type_ end return r - ]], - dir, - depth, - skip - ) + end, dir, depth, skip) return r end @@ -263,13 +252,9 @@ describe('vim.fs', function() opts = { path = test_source_path .. '/contrib', limit = math.huge } eq( - exec_lua( - [[ - local dir = ... - return vim.tbl_map(vim.fs.basename, vim.fn.glob(dir..'/contrib/*', false, true)) - ]], - test_source_path - ), + exec_lua(function(dir) + return vim.tbl_map(vim.fs.basename, vim.fn.glob(dir .. '/contrib/*', false, true)) + end, test_source_path), vim.tbl_map( vim.fs.basename, vim.fs.find(function(_, d) @@ -299,11 +284,11 @@ describe('vim.fs', function() it('works with a function', function() ---@type string - local result = exec_lua([[ - return vim.fs.root(0, function(name, path) + local result = exec_lua(function() + return vim.fs.root(0, function(name, _) return name:match('%.txt$') end) - ]]) + end) eq(vim.fs.joinpath(test_source_path, 'test/functional/fixtures'), result) end) @@ -352,13 +337,10 @@ describe('vim.fs', function() local xdg_config_home = test_build_dir .. '/.config' eq( xdg_config_home .. '/nvim', - exec_lua( - [[ - vim.env.XDG_CONFIG_HOME = ... - return vim.fs.normalize('$XDG_CONFIG_HOME/nvim') - ]], - xdg_config_home - ) + exec_lua(function(...) + vim.env.XDG_CONFIG_HOME = ... + return vim.fs.normalize('$XDG_CONFIG_HOME/nvim') + end, xdg_config_home) ) end) diff --git a/test/functional/lua/glob_spec.lua b/test/functional/lua/glob_spec.lua index b95d874bb5..6f1e5be501 100644 --- a/test/functional/lua/glob_spec.lua +++ b/test/functional/lua/glob_spec.lua @@ -9,14 +9,9 @@ describe('glob', function() after_each(n.clear) local match = function(...) - return exec_lua( - [[ - local pattern = select(1, ...) - local str = select(2, ...) - return require("vim.glob").to_lpeg(pattern):match(str) ~= nil - ]], - ... - ) + return exec_lua(function(pattern, str) + return require('vim.glob').to_lpeg(pattern):match(str) ~= nil + end, ...) end describe('glob matching', function() diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index a7ba851215..83db4f303c 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -57,31 +57,30 @@ describe('LSP', function() -- Run an instance of nvim on the file which contains our "scripts". -- Pass TEST_NAME to pick the script. local test_name = 'basic_init' - exec_lua( - [=[ - lsp = require('vim.lsp') - local test_name, fake_lsp_code, fake_lsp_logfile = ... - function test__start_client() - return lsp.start_client { + exec_lua(function(test_name0, fake_lsp_code0, fake_lsp_logfile0) + _G.lsp = require('vim.lsp') + function _G.test__start_client() + return vim.lsp.start_client { cmd_env = { - NVIM_LOG_FILE = fake_lsp_logfile; - NVIM_APPNAME = "nvim_lsp_test"; - }; + NVIM_LOG_FILE = fake_lsp_logfile0, + NVIM_APPNAME = 'nvim_lsp_test', + }, cmd = { - vim.v.progpath, '-l', fake_lsp_code, test_name; - }; - workspace_folders = {{ + vim.v.progpath, + '-l', + fake_lsp_code0, + test_name0, + }, + workspace_folders = { + { uri = 'file://' .. vim.uv.cwd(), name = 'test_folder', - }}; + }, + }, } end - TEST_CLIENT1 = test__start_client() - ]=], - test_name, - fake_lsp_code, - fake_lsp_logfile - ) + _G.TEST_CLIENT1 = _G.test__start_client() + end, test_name, fake_lsp_code, fake_lsp_logfile) end) after_each(function() @@ -96,17 +95,17 @@ describe('LSP', function() end) eq( 2, - exec_lua([[ - TEST_CLIENT2 = test__start_client() - return TEST_CLIENT2 - ]]) + exec_lua(function() + _G.TEST_CLIENT2 = _G.test__start_client() + return _G.TEST_CLIENT2 + end) ) eq( 3, - exec_lua([[ - TEST_CLIENT3 = test__start_client() - return TEST_CLIENT3 - ]]) + exec_lua(function() + _G.TEST_CLIENT3 = _G.test__start_client() + return _G.TEST_CLIENT3 + end) ) retry(nil, 4000, function() eq(3, exec_lua('return #lsp.get_clients()')) @@ -127,10 +126,10 @@ describe('LSP', function() end) it('stop_client() also works on client objects', function() - exec_lua([[ - TEST_CLIENT2 = test__start_client() - TEST_CLIENT3 = test__start_client() - ]]) + exec_lua(function() + _G.TEST_CLIENT2 = _G.test__start_client() + _G.TEST_CLIENT3 = _G.test__start_client() + end) retry(nil, 4000, function() eq(3, exec_lua('return #lsp.get_clients()')) end) @@ -221,28 +220,28 @@ describe('LSP', function() function() clear() exec_lua(create_server_definition) - local result = exec_lua([[ - local server = _create_server({ - capabilities = { - positionEncoding = "utf-8" - }, - }) + local result = exec_lua(function() + local server = _G._create_server({ + capabilities = { + positionEncoding = 'utf-8', + }, + }) - local client_id = vim.lsp.start({ - name = 'dummy', - cmd = server.cmd, - }) + local client_id = vim.lsp.start({ + name = 'dummy', + cmd = server.cmd, + }) - if not client_id then - return 'vim.lsp.start did not return client_id' - end + if not client_id then + return 'vim.lsp.start did not return client_id' + end - local client = vim.lsp.get_client_by_id(client_id) - if not client then - return 'No client found with id ' .. client_id - end - return client.offset_encoding - ]]) + local client = vim.lsp.get_client_by_id(client_id) + if not client then + return 'No client found with id ' .. client_id + end + return client.offset_encoding + end) eq('utf-8', result) end ) @@ -285,14 +284,14 @@ describe('LSP', function() test_rpc_server { test_name = 'basic_finish', on_setup = function() - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) - ]] - eq(true, exec_lua('return lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)')) - eq(true, exec_lua('return lsp.buf_is_attached(BUFFER, TEST_RPC_CLIENT_ID)')) - exec_lua [[ - vim.api.nvim_command(BUFFER.."bwipeout") - ]] + exec_lua(function() + _G.BUFFER = vim.api.nvim_create_buf(false, true) + end) + eq(true, exec_lua('return lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)')) + eq(true, exec_lua('return lsp.buf_is_attached(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)')) + exec_lua(function() + vim.api.nvim_command(_G.BUFFER .. 'bwipeout') + end) end, on_init = function(_client) client = _client @@ -305,8 +304,8 @@ describe('LSP', function() on_handler = function(err, result, ctx) eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler') if ctx.method == 'finish' then - exec_lua('return lsp.buf_detach_client(BUFFER, TEST_RPC_CLIENT_ID)') - eq(false, exec_lua('return lsp.buf_is_attached(BUFFER, TEST_RPC_CLIENT_ID)')) + exec_lua('return vim.lsp.buf_detach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)') + eq(false, exec_lua('return vim.lsp.buf_is_attached(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)')) client.stop() end end, @@ -318,31 +317,31 @@ describe('LSP', function() test_rpc_server { test_name = 'basic_init', on_setup = function() - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) + exec_lua(function() + _G.BUFFER = vim.api.nvim_create_buf(false, true) vim.api.nvim_create_autocmd('LspAttach', { callback = function(args) - local client = vim.lsp.get_client_by_id(args.data.client_id) - vim.g.lsp_attached = client.name + local client0 = vim.lsp.get_client_by_id(args.data.client_id) + vim.g.lsp_attached = client0.name end, }) vim.api.nvim_create_autocmd('LspDetach', { callback = function(args) - local client = vim.lsp.get_client_by_id(args.data.client_id) - vim.g.lsp_detached = client.name + local client0 = vim.lsp.get_client_by_id(args.data.client_id) + vim.g.lsp_detached = client0.name end, }) - ]] + end) end, on_init = function(_client) client = _client - eq(true, exec_lua('return lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)')) + eq(true, exec_lua('return vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)')) client.notify('finish') end, on_handler = function(_, _, ctx) if ctx.method == 'finish' then eq('basic_init', api.nvim_get_var('lsp_attached')) - exec_lua('return lsp.buf_detach_client(BUFFER, TEST_RPC_CLIENT_ID)') + exec_lua('return vim.lsp.buf_detach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)') eq('basic_init', api.nvim_get_var('lsp_detached')) client.stop() end @@ -356,10 +355,10 @@ describe('LSP', function() test_name = 'set_defaults_all_capabilities', on_init = function(_client) client = _client - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) - lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID) - ]] + exec_lua(function() + _G.BUFFER = vim.api.nvim_create_buf(false, true) + vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID) + end) end, on_handler = function(_, _, ctx) if ctx.method == 'test' then @@ -369,13 +368,13 @@ describe('LSP', function() eq('', get_buf_option('keywordprg')) eq( true, - exec_lua [[ - local keymap - vim._with({buf = BUFFER}, function() - keymap = vim.fn.maparg("K", "n", false, true) + exec_lua(function() + local keymap + vim._with({ buf = _G.BUFFER }, function() + keymap = vim.fn.maparg('K', 'n', false, true) + end) + return keymap.callback == vim.lsp.buf.hover end) - return keymap.callback == vim.lsp.buf.hover - ]] ) client.stop() end @@ -386,13 +385,13 @@ describe('LSP', function() eq('', get_buf_option('formatexpr')) eq( '', - exec_lua [[ - local keymap - vim._with({buf = BUFFER}, function() - keymap = vim.fn.maparg("K", "n", false, false) + exec_lua(function() + local keymap + vim._with({ buf = _G.BUFFER }, function() + keymap = vim.fn.maparg('K', 'n', false, false) + end) + return keymap end) - return keymap - ]] ) end, } @@ -404,36 +403,36 @@ describe('LSP', function() test_name = 'set_defaults_all_capabilities', on_init = function(_client) client = _client - exec_lua [[ + exec_lua(function() vim.api.nvim_command('filetype plugin on') - BUFFER_1 = vim.api.nvim_create_buf(false, true) - BUFFER_2 = vim.api.nvim_create_buf(false, true) - vim.api.nvim_set_option_value('filetype', 'man', { buf = BUFFER_1 }) - vim.api.nvim_set_option_value('filetype', 'xml', { buf = BUFFER_2 }) - ]] + _G.BUFFER_1 = vim.api.nvim_create_buf(false, true) + _G.BUFFER_2 = vim.api.nvim_create_buf(false, true) + vim.api.nvim_set_option_value('filetype', 'man', { buf = _G.BUFFER_1 }) + vim.api.nvim_set_option_value('filetype', 'xml', { buf = _G.BUFFER_2 }) + end) -- Sanity check to ensure that some values are set after setting filetype. - eq("v:lua.require'man'.goto_tag", get_buf_option('tagfunc', 'BUFFER_1')) - eq('xmlcomplete#CompleteTags', get_buf_option('omnifunc', 'BUFFER_2')) - eq('xmlformat#Format()', get_buf_option('formatexpr', 'BUFFER_2')) + eq("v:lua.require'man'.goto_tag", get_buf_option('tagfunc', '_G.BUFFER_1')) + eq('xmlcomplete#CompleteTags', get_buf_option('omnifunc', '_G.BUFFER_2')) + eq('xmlformat#Format()', get_buf_option('formatexpr', '_G.BUFFER_2')) - exec_lua [[ - lsp.buf_attach_client(BUFFER_1, TEST_RPC_CLIENT_ID) - lsp.buf_attach_client(BUFFER_2, TEST_RPC_CLIENT_ID) - ]] + exec_lua(function() + vim.lsp.buf_attach_client(_G.BUFFER_1, _G.TEST_RPC_CLIENT_ID) + vim.lsp.buf_attach_client(_G.BUFFER_2, _G.TEST_RPC_CLIENT_ID) + end) end, on_handler = function(_, _, ctx) if ctx.method == 'test' then - eq('v:lua.vim.lsp.tagfunc', get_buf_option('tagfunc', 'BUFFER_1')) - eq('v:lua.vim.lsp.omnifunc', get_buf_option('omnifunc', 'BUFFER_2')) - eq('v:lua.vim.lsp.formatexpr()', get_buf_option('formatexpr', 'BUFFER_2')) + eq('v:lua.vim.lsp.tagfunc', get_buf_option('tagfunc', '_G.BUFFER_1')) + eq('v:lua.vim.lsp.omnifunc', get_buf_option('omnifunc', '_G.BUFFER_2')) + eq('v:lua.vim.lsp.formatexpr()', get_buf_option('formatexpr', '_G.BUFFER_2')) client.stop() end end, on_exit = function(_, _) - eq('', get_buf_option('tagfunc', 'BUFFER_1')) - eq('', get_buf_option('omnifunc', 'BUFFER_2')) - eq('', get_buf_option('formatexpr', 'BUFFER_2')) + eq('', get_buf_option('tagfunc', '_G.BUFFER_1')) + eq('', get_buf_option('omnifunc', '_G.BUFFER_2')) + eq('', get_buf_option('formatexpr', '_G.BUFFER_2')) end, } end) @@ -444,13 +443,13 @@ describe('LSP', function() test_name = 'set_defaults_all_capabilities', on_init = function(_client) client = _client - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) - vim.api.nvim_set_option_value('tagfunc', 'tfu', { buf = BUFFER }) - vim.api.nvim_set_option_value('omnifunc', 'ofu', { buf = BUFFER }) - vim.api.nvim_set_option_value('formatexpr', 'fex', { buf = BUFFER }) - lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID) - ]] + exec_lua(function() + _G.BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_set_option_value('tagfunc', 'tfu', { buf = _G.BUFFER }) + vim.api.nvim_set_option_value('omnifunc', 'ofu', { buf = _G.BUFFER }) + vim.api.nvim_set_option_value('formatexpr', 'fex', { buf = _G.BUFFER }) + vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID) + end) end, on_handler = function(_, _, ctx) if ctx.method == 'test' then @@ -471,18 +470,18 @@ describe('LSP', function() it('should detach buffer on bufwipe', function() clear() exec_lua(create_server_definition) - local result = exec_lua([[ - local server = _create_server() + local result = exec_lua(function() + local server = _G._create_server() local bufnr = vim.api.nvim_create_buf(false, true) vim.api.nvim_set_current_buf(bufnr) local detach_called = false - vim.api.nvim_create_autocmd("LspDetach", { + vim.api.nvim_create_autocmd('LspDetach', { callback = function() detach_called = true - end + end, }) local client_id = vim.lsp.start({ name = 'detach-dummy', cmd = server.cmd }) - assert(client_id, "lsp.start must return client_id") + assert(client_id, 'lsp.start must return client_id') local client = vim.lsp.get_client_by_id(client_id) local num_attached_before = vim.tbl_count(client.attached_buffers) vim.api.nvim_buf_delete(bufnr, { force = true }) @@ -494,7 +493,7 @@ describe('LSP', function() num_attached_after = num_attached_after, detach_called = detach_called, } - ]]) + end) eq(true, result ~= nil, 'exec_lua must return result') eq(1, result.num_attached_before) eq(0, result.num_attached_after) @@ -504,15 +503,15 @@ describe('LSP', function() it('should not re-attach buffer if it was deleted in on_init #28575', function() clear() exec_lua(create_server_definition) - exec_lua([[ - local server = _create_server({ + exec_lua(function() + local server = _G._create_server({ handlers = { - initialize = function(method, params, callback) + initialize = function(_, _, callback) vim.schedule(function() callback(nil, { capabilities = {} }) end) - end - } + end, + }, }) local bufnr = vim.api.nvim_create_buf(false, true) local on_init_called = false @@ -522,40 +521,44 @@ describe('LSP', function() on_init = function() vim.api.nvim_buf_delete(bufnr, {}) on_init_called = true - end + end, }) vim.lsp.buf_attach_client(bufnr, client_id) - local ok = vim.wait(1000, function() return on_init_called end) - assert(ok, "on_init was not called") - ]]) + local ok = vim.wait(1000, function() + return on_init_called + end) + assert(ok, 'on_init was not called') + end) end) it('should allow on_lines + nvim_buf_delete during LSP initialization #28575', function() clear() exec_lua(create_server_definition) - exec_lua([[ + exec_lua(function() local initialized = false - local server = _create_server({ + local server = _G._create_server({ handlers = { - initialize = function(method, params, callback) + initialize = function(_, _, callback) vim.schedule(function() callback(nil, { capabilities = {} }) initialized = true end) - end - } + end, + }, }) local bufnr = vim.api.nvim_create_buf(false, true) vim.api.nvim_set_current_buf(bufnr) - local client_id = vim.lsp.start({ + vim.lsp.start({ name = 'detach-dummy', cmd = server.cmd, }) - vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {"hello"}) + vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { 'hello' }) vim.api.nvim_buf_delete(bufnr, {}) - local ok = vim.wait(1000, function() return initialized end) - assert(ok, "lsp did not initialize") - ]]) + local ok = vim.wait(1000, function() + return initialized + end) + assert(ok, 'lsp did not initialize') + end) end) it('client should return settings via workspace/configuration handler', function() @@ -588,22 +591,23 @@ describe('LSP', function() on_handler = function(err, result, ctx) eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler') if ctx.method == 'start' then - exec_lua([=[ - local client = vim.lsp.get_client_by_id(TEST_RPC_CLIENT_ID) - client.settings = { - testSetting1 = true; - testSetting2 = false; - test = {Setting3 = 'nested' }; - }]=]) + exec_lua(function() + local client0 = vim.lsp.get_client_by_id(_G.TEST_RPC_CLIENT_ID) + client0.settings = { + testSetting1 = true, + testSetting2 = false, + test = { Setting3 = 'nested' }, + } + end) end if ctx.method == 'workspace/configuration' then - local server_result = exec_lua( - [=[ - local method, params = ... - return require'vim.lsp.handlers'['workspace/configuration'](err, params, {method=method, client_id=TEST_RPC_CLIENT_ID})]=], - ctx.method, - result - ) + local server_result = exec_lua(function(method, params) + return require 'vim.lsp.handlers'['workspace/configuration']( + err, + params, + { method = method, client_id = _G.TEST_RPC_CLIENT_ID } + ) + end, ctx.method, result) client.notify('workspace/configuration', server_result) end if ctx.method == 'shutdown' then @@ -622,15 +626,19 @@ describe('LSP', function() c.stop() end, on_setup = function() - result = exec_lua [[ - local result = { - items = { - {section = 'foo'}, - {section = 'bar'}, + result = exec_lua(function() + local result0 = { + items = { + { section = 'foo' }, + { section = 'bar' }, + }, } - } - return vim.lsp.handlers['workspace/configuration'](nil, result, {client_id=TEST_RPC_CLIENT_ID}) - ]] + return vim.lsp.handlers['workspace/configuration']( + nil, + result0, + { client_id = _G.TEST_RPC_CLIENT_ID } + ) + end) end, } eq({ NIL, NIL }, result) @@ -678,11 +686,11 @@ describe('LSP', function() on_handler = function(err, result, ctx) eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler') if ctx.method == 'start' then - exec_lua([=[ - BUFFER = vim.api.nvim_get_current_buf() - lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID) - vim.api.nvim_exec_autocmds('BufWritePost', { buffer = BUFFER, modeline = false }) - ]=]) + exec_lua(function() + _G.BUFFER = vim.api.nvim_get_current_buf() + vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID) + vim.api.nvim_exec_autocmds('BufWritePost', { buffer = _G.BUFFER, modeline = false }) + end) else client.stop() end @@ -693,13 +701,13 @@ describe('LSP', function() it('BufWritePre does not send notifications if server lacks willSave capabilities', function() clear() exec_lua(create_server_definition) - local messages = exec_lua([[ - local server = _create_server({ + local messages = exec_lua(function() + local server = _G._create_server({ capabilities = { textDocumentSync = { willSave = false, willSaveWaitUntil = false, - } + }, }, }) local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) @@ -707,7 +715,7 @@ describe('LSP', function() vim.api.nvim_exec_autocmds('BufWritePre', { buffer = buf, modeline = false }) vim.lsp.stop_client(client_id) return server.messages - ]]) + end) eq(4, #messages) eq('initialize', messages[1].method) eq('initialized', messages[2].method) @@ -718,13 +726,13 @@ describe('LSP', function() it('BufWritePre sends willSave / willSaveWaitUntil, applies textEdits', function() clear() exec_lua(create_server_definition) - local result = exec_lua([[ - local server = _create_server({ + local result = exec_lua(function() + local server = _G._create_server({ capabilities = { textDocumentSync = { willSave = true, willSaveWaitUntil = true, - } + }, }, handlers = { ['textDocument/willSaveWaitUntil'] = function(_, _, callback) @@ -733,10 +741,10 @@ describe('LSP', function() start = { line = 0, character = 0 }, ['end'] = { line = 0, character = 0 }, }, - newText = 'Hello' + newText = 'Hello', } - callback(nil, { text_edit, }) - end + callback(nil, { text_edit }) + end, }, }) local buf = vim.api.nvim_get_current_buf() @@ -745,9 +753,9 @@ describe('LSP', function() vim.lsp.stop_client(client_id) return { messages = server.messages, - lines = vim.api.nvim_buf_get_lines(buf, 0, -1, true) + lines = vim.api.nvim_buf_get_lines(buf, 0, -1, true), } - ]]) + end) local messages = result.messages eq('textDocument/willSave', messages[3].method) eq('textDocument/willSaveWaitUntil', messages[4].method) @@ -775,18 +783,15 @@ describe('LSP', function() local tmpfile_old = tmpname() local tmpfile_new = tmpname() os.remove(tmpfile_new) - exec_lua( - [=[ - local oldname, newname = ... - BUFFER = vim.api.nvim_get_current_buf() - vim.api.nvim_buf_set_name(BUFFER, oldname) - vim.api.nvim_buf_set_lines(BUFFER, 0, -1, true, {"help me"}) - lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID) - vim._with({buf = BUFFER}, function() vim.cmd('saveas ' .. newname) end) - ]=], - tmpfile_old, - tmpfile_new - ) + exec_lua(function(oldname, newname) + _G.BUFFER = vim.api.nvim_get_current_buf() + vim.api.nvim_buf_set_name(_G.BUFFER, oldname) + vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, true, { 'help me' }) + vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID) + vim._with({ buf = _G.BUFFER }, function() + vim.cmd('saveas ' .. newname) + end) + end, tmpfile_old, tmpfile_new) else client.stop() end @@ -812,12 +817,12 @@ describe('LSP', function() on_handler = function(err, result, ctx) eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler') if ctx.method == 'start' then - exec_lua([=[ - BUFFER = vim.api.nvim_get_current_buf() - vim.api.nvim_buf_set_lines(BUFFER, 0, -1, true, {"help me"}) - lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID) - vim.api.nvim_exec_autocmds('BufWritePost', { buffer = BUFFER, modeline = false }) - ]=]) + exec_lua(function() + _G.BUFFER = vim.api.nvim_get_current_buf() + vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, true, { 'help me' }) + vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID) + vim.api.nvim_exec_autocmds('BufWritePost', { buffer = _G.BUFFER, modeline = false }) + end) else client.stop() end @@ -871,12 +876,12 @@ describe('LSP', function() test_rpc_server { test_name = 'capabilities_for_client_supports_method', on_setup = function() - exec_lua([=[ - BUFFER = vim.api.nvim_get_current_buf() - lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID) - vim.lsp.handlers['textDocument/typeDefinition'] = function() end - vim.cmd(BUFFER.."bwipeout") - ]=]) + exec_lua(function() + _G.BUFFER = vim.api.nvim_get_current_buf() + vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID) + vim.lsp.handlers['textDocument/typeDefinition'] = function() end + vim.cmd(_G.BUFFER .. 'bwipeout') + end) end, on_init = function(client) client.stop() @@ -901,9 +906,9 @@ describe('LSP', function() test_rpc_server { test_name = 'capabilities_for_client_supports_method', on_setup = function() - exec_lua([=[ + exec_lua(function() vim.lsp.handlers['textDocument/typeDefinition'] = function() end - ]=]) + end) end, on_init = function(client) client.stop() @@ -990,7 +995,9 @@ describe('LSP', function() on_init = function(_client) client = _client client.request('slow_request') - local request = exec_lua([=[ return TEST_RPC_CLIENT.requests[2] ]=]) + local request = exec_lua(function() + return _G.TEST_RPC_CLIENT.requests[2] + end) eq('slow_request', request.method) eq('pending', request.type) client.notify('release') @@ -1003,7 +1010,9 @@ describe('LSP', function() on_handler = function(err, _, ctx) eq(table.remove(expected_handlers), { err, {}, ctx }, 'expected handler') if ctx.method == 'slow_request' then - local request = exec_lua([=[ return TEST_RPC_CLIENT.requests[2] ]=]) + local request = exec_lua(function() + return _G.TEST_RPC_CLIENT.requests[2] + end) eq(NIL, request) client.notify('finish') end @@ -1025,7 +1034,9 @@ describe('LSP', function() client = _client client.request('slow_request') client.cancel_request(2) - local request = exec_lua([=[ return TEST_RPC_CLIENT.requests[2] ]=]) + local request = exec_lua(function() + return _G.TEST_RPC_CLIENT.requests[2] + end) eq('slow_request', request.method) eq('cancel', request.type) client.notify('release') @@ -1037,7 +1048,9 @@ describe('LSP', function() end, on_handler = function(err, _, ctx) eq(table.remove(expected_handlers), { err, {}, ctx }, 'expected handler') - local request = exec_lua([=[ return TEST_RPC_CLIENT.requests[2] ]=]) + local request = exec_lua(function() + return _G.TEST_RPC_CLIENT.requests[2] + end) eq(NIL, request) if ctx.method == 'finish' then client.stop() @@ -1057,11 +1070,15 @@ describe('LSP', function() on_init = function(_client) client = _client client.request('slow_request') - local request = exec_lua([=[ return TEST_RPC_CLIENT.requests[2] ]=]) + local request = exec_lua(function() + return _G.TEST_RPC_CLIENT.requests[2] + end) eq('slow_request', request.method) eq('pending', request.type) client.cancel_request(2) - request = exec_lua([=[ return TEST_RPC_CLIENT.requests[2] ]=]) + request = exec_lua(function() + return _G.TEST_RPC_CLIENT.requests[2] + end) eq('slow_request', request.method) eq('cancel', request.type) client.notify('release') @@ -1074,7 +1091,9 @@ describe('LSP', function() on_handler = function(err, _, ctx) eq(table.remove(expected_handlers), { err, {}, ctx }, 'expected handler') if ctx.method == 'slow_request' then - local request = exec_lua([=[ return TEST_RPC_CLIENT.requests[2] ]=]) + local request = exec_lua(function() + return _G.TEST_RPC_CLIENT.requests[2] + end) eq(NIL, request) client.notify('finish') end @@ -1130,17 +1149,17 @@ describe('LSP', function() test_rpc_server { test_name = 'basic_finish', on_setup = function() - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { - "testing"; - "123"; + exec_lua(function() + _G.BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, { + 'testing', + '123', }) - assert(TEST_RPC_CLIENT_ID == 1) - assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) - assert(lsp.buf_is_attached(BUFFER, TEST_RPC_CLIENT_ID)) - vim.cmd(BUFFER.."bwipeout") - ]] + assert(_G.TEST_RPC_CLIENT_ID == 1) + assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)) + assert(vim.lsp.buf_is_attached(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)) + vim.cmd(_G.BUFFER .. 'bwipeout') + end) end, on_init = function(_client) client = _client @@ -1172,25 +1191,28 @@ describe('LSP', function() test_rpc_server { test_name = 'basic_check_buffer_open', on_setup = function() - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { - "testing"; - "123"; + exec_lua(function() + _G.BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, { + 'testing', + '123', }) - ]] - exec_lua [[ - assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) - ]] + end) + exec_lua(function() + assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)) + end) end, on_init = function(_client) client = _client local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") eq(full_kind, client.server_capabilities().textDocumentSync.change) eq(true, client.server_capabilities().textDocumentSync.openClose) - exec_lua [[ - assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID), "Already attached, returns true") - ]] + exec_lua(function() + assert( + vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID), + 'Already attached, returns true' + ) + end) end, on_exit = function(code, signal) eq(0, code, 'exit code') @@ -1218,22 +1240,22 @@ describe('LSP', function() test_rpc_server { test_name = 'basic_check_buffer_open', on_setup = function() - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { - "testing"; - "123"; + exec_lua(function() + _G.BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, { + 'testing', + '123', }) - ]] + end) end, on_init = function(_client) client = _client local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") eq(full_kind, client.server_capabilities().textDocumentSync.change) eq(true, client.server_capabilities().textDocumentSync.openClose) - exec_lua [[ - assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) - ]] + exec_lua(function() + assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)) + end) end, on_exit = function(code, signal) eq(0, code, 'exit code') @@ -1261,22 +1283,22 @@ describe('LSP', function() test_rpc_server { test_name = 'basic_check_buffer_open_and_change', on_setup = function() - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { - "testing"; - "123"; + exec_lua(function() + _G.BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, { + 'testing', + '123', }) - ]] + end) end, on_init = function(_client) client = _client local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") eq(full_kind, client.server_capabilities().textDocumentSync.change) eq(true, client.server_capabilities().textDocumentSync.openClose) - exec_lua [[ - assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) - ]] + exec_lua(function() + assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)) + end) end, on_exit = function(code, signal) eq(0, code, 'exit code') @@ -1284,11 +1306,11 @@ describe('LSP', function() end, on_handler = function(err, result, ctx) if ctx.method == 'start' then - exec_lua [[ - vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { - "boop"; + exec_lua(function() + vim.api.nvim_buf_set_lines(_G.BUFFER, 1, 2, false, { + 'boop', }) - ]] + end) client.notify('finish') end eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler') @@ -1309,23 +1331,23 @@ describe('LSP', function() test_rpc_server { test_name = 'basic_check_buffer_open_and_change_noeol', on_setup = function() - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { - "testing"; - "123"; + exec_lua(function() + _G.BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, { + 'testing', + '123', }) - vim.bo[BUFFER].eol = false - ]] + vim.bo[_G.BUFFER].eol = false + end) end, on_init = function(_client) client = _client local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") eq(full_kind, client.server_capabilities().textDocumentSync.change) eq(true, client.server_capabilities().textDocumentSync.openClose) - exec_lua [[ - assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) - ]] + exec_lua(function() + assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)) + end) end, on_exit = function(code, signal) eq(0, code, 'exit code') @@ -1333,11 +1355,11 @@ describe('LSP', function() end, on_handler = function(err, result, ctx) if ctx.method == 'start' then - exec_lua [[ - vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { - "boop"; + exec_lua(function() + vim.api.nvim_buf_set_lines(_G.BUFFER, 1, 2, false, { + 'boop', }) - ]] + end) client.notify('finish') end eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler') @@ -1377,21 +1399,21 @@ describe('LSP', function() test_rpc_server { test_name = 'inlay_hint', on_setup = function() - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { - "testing"; - "123"; + exec_lua(function() + _G.BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, { + 'testing', + '123', }) - vim.bo[BUFFER].eol = false - ]] + vim.bo[_G.BUFFER].eol = false + end) end, on_init = function(_client) client = _client eq(true, client.supports_method('textDocument/inlayHint')) - exec_lua [[ - assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) - ]] + exec_lua(function() + assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)) + end) end, on_exit = function(code, signal) eq(0, code, 'exit code') @@ -1399,9 +1421,9 @@ describe('LSP', function() end, on_handler = function(err, result, ctx) if ctx.method == 'start' then - exec_lua [[ - vim.lsp.inlay_hint.enable(true, { bufnr = BUFFER }) - ]] + exec_lua(function() + vim.lsp.inlay_hint.enable(true, { bufnr = _G.BUFFER }) + end) end if ctx.method == 'textDocument/inlayHint' then client.notify('finish') @@ -1427,13 +1449,13 @@ describe('LSP', function() allow_incremental_sync = true, }, on_setup = function() - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { - "testing"; - "123"; + exec_lua(function() + _G.BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, { + 'testing', + '123', }) - ]] + end) end, on_init = function(_client) client = _client @@ -1441,9 +1463,9 @@ describe('LSP', function() exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Incremental") eq(sync_kind, client.server_capabilities().textDocumentSync.change) eq(true, client.server_capabilities().textDocumentSync.openClose) - exec_lua [[ - assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) - ]] + exec_lua(function() + assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)) + end) end, on_exit = function(code, signal) eq(0, code, 'exit code') @@ -1451,11 +1473,11 @@ describe('LSP', function() end, on_handler = function(err, result, ctx) if ctx.method == 'start' then - exec_lua [[ - vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { - "123boop"; + exec_lua(function() + vim.api.nvim_buf_set_lines(_G.BUFFER, 1, 2, false, { + '123boop', }) - ]] + end) client.notify('finish') end eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler') @@ -1479,13 +1501,13 @@ describe('LSP', function() debounce_text_changes = 5, }, on_setup = function() - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { - "testing"; - "123"; + exec_lua(function() + _G.BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, { + 'testing', + '123', }) - ]] + end) end, on_init = function(_client) client = _client @@ -1493,9 +1515,9 @@ describe('LSP', function() exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Incremental") eq(sync_kind, client.server_capabilities().textDocumentSync.change) eq(true, client.server_capabilities().textDocumentSync.openClose) - exec_lua [[ - assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) - ]] + exec_lua(function() + assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)) + end) end, on_exit = function(code, signal) eq(0, code, 'exit code') @@ -1503,11 +1525,11 @@ describe('LSP', function() end, on_handler = function(err, result, ctx) if ctx.method == 'start' then - exec_lua [[ - vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { - "123boop"; + exec_lua(function() + vim.api.nvim_buf_set_lines(_G.BUFFER, 1, 2, false, { + '123boop', }) - ]] + end) client.notify('finish') end eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler') @@ -1529,13 +1551,13 @@ describe('LSP', function() test_rpc_server { test_name = 'basic_check_buffer_open_and_change_incremental_editing', on_setup = function() - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { - "testing"; - "123"; + exec_lua(function() + _G.BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, { + 'testing', + '123', }) - ]] + end) end, on_init = function(_client) client = _client @@ -1543,9 +1565,9 @@ describe('LSP', function() exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Incremental") eq(sync_kind, client.server_capabilities().textDocumentSync.change) eq(true, client.server_capabilities().textDocumentSync.openClose) - exec_lua [[ - assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) - ]] + exec_lua(function() + assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)) + end) end, on_exit = function(code, signal) eq(0, code, 'exit code') @@ -1574,22 +1596,22 @@ describe('LSP', function() test_rpc_server { test_name = 'basic_check_buffer_open_and_change_multi', on_setup = function() - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { - "testing"; - "123"; + exec_lua(function() + _G.BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, { + 'testing', + '123', }) - ]] + end) end, on_init = function(_client) client = _client local sync_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") eq(sync_kind, client.server_capabilities().textDocumentSync.change) eq(true, client.server_capabilities().textDocumentSync.openClose) - exec_lua [[ - assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) - ]] + exec_lua(function() + assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)) + end) end, on_exit = function(code, signal) eq(0, code, 'exit code') @@ -1597,14 +1619,14 @@ describe('LSP', function() end, on_handler = function(err, result, ctx) if ctx.method == 'start' then - exec_lua [[ - vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { - "321"; + exec_lua(function() + vim.api.nvim_buf_set_lines(_G.BUFFER, 1, 2, false, { + '321', }) - vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { - "boop"; + vim.api.nvim_buf_set_lines(_G.BUFFER, 1, 2, false, { + 'boop', }) - ]] + end) client.notify('finish') end eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler') @@ -1625,22 +1647,22 @@ describe('LSP', function() test_rpc_server { test_name = 'basic_check_buffer_open_and_change_multi_and_close', on_setup = function() - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { - "testing"; - "123"; + exec_lua(function() + _G.BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, { + 'testing', + '123', }) - ]] + end) end, on_init = function(_client) client = _client local sync_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") eq(sync_kind, client.server_capabilities().textDocumentSync.change) eq(true, client.server_capabilities().textDocumentSync.openClose) - exec_lua [[ - assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) - ]] + exec_lua(function() + assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)) + end) end, on_exit = function(code, signal) eq(0, code, 'exit code') @@ -1648,15 +1670,15 @@ describe('LSP', function() end, on_handler = function(err, result, ctx) if ctx.method == 'start' then - exec_lua [[ - vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { - "321"; + exec_lua(function() + vim.api.nvim_buf_set_lines(_G.BUFFER, 1, 2, false, { + '321', }) - vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { - "boop"; + vim.api.nvim_buf_set_lines(_G.BUFFER, 1, 2, false, { + 'boop', }) - vim.api.nvim_command(BUFFER.."bwipeout") - ]] + vim.api.nvim_command(_G.BUFFER .. 'bwipeout') + end) client.notify('finish') end eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler') @@ -1712,19 +1734,19 @@ describe('LSP', function() test_rpc_server { test_name = 'decode_nil', on_setup = function() - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { - "testing"; - "123"; + exec_lua(function() + _G.BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, { + 'testing', + '123', }) - ]] + end) end, on_init = function(_client) client = _client - exec_lua [[ - assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) - ]] + exec_lua(function() + assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)) + end) end, on_exit = function(code, signal) eq(0, code, 'exit code') @@ -1794,9 +1816,9 @@ describe('LSP', function() eq({ '012WorldHelloNo8901234567890123456789' }, buf_lines(1)) end) it('multiline', function() - exec_lua([[ - vim.api.nvim_buf_set_lines(1, 0, 0, true, {' {', ' "foo": "bar"', ' }'}) - ]]) + exec_lua(function() + vim.api.nvim_buf_set_lines(1, 0, 0, true, { ' {', ' "foo": "bar"', ' }' }) + end) eq({ ' {', ' "foo": "bar"', ' }', '' }, buf_lines(1)) local edits = { make_edit(0, 0, 3, 0, { '' }), @@ -2154,12 +2176,12 @@ describe('LSP', function() } end before_each(function() - target_bufnr = exec_lua [[ - local bufnr = vim.uri_to_bufnr("file:///fake/uri") - local lines = {"1st line of text", "2nd line of 语text"} + target_bufnr = exec_lua(function() + local bufnr = vim.uri_to_bufnr('file:///fake/uri') + local lines = { '1st line of text', '2nd line of 语text' } vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines) return bufnr - ]] + end) end) it('correctly goes ahead with the edit if all is normal', function() exec_lua("vim.lsp.util.apply_text_document_edit(..., nil, 'utf-16')", text_document_edit(5)) @@ -2169,17 +2191,10 @@ describe('LSP', function() }, buf_lines(target_bufnr)) end) it('always accepts edit with version = 0', function() - exec_lua( - [[ - local args = {...} - local bufnr = select(1, ...) - local text_edit = select(2, ...) + exec_lua(function(bufnr, text_edit) vim.lsp.util.buf_versions[bufnr] = 10 vim.lsp.util.apply_text_document_edit(text_edit, nil, 'utf-16') - ]], - target_bufnr, - text_document_edit(0) - ) + end, target_bufnr, text_document_edit(0)) eq({ 'First ↥ 🤦 🦄 line of text', '2nd line of 语text', @@ -2187,16 +2202,10 @@ describe('LSP', function() end) it('skips the edit if the version of the edit is behind the local buffer ', function() local apply_edit_mocking_current_version = function(edit, versionedBuf) - exec_lua( - [[ - local args = {...} - local versionedBuf = args[2] - vim.lsp.util.buf_versions[versionedBuf.bufnr] = versionedBuf.currentVersion - vim.lsp.util.apply_text_document_edit(args[1], nil, 'utf-16') - ]], - edit, - versionedBuf - ) + exec_lua(function(edit0, versionedBuf0) + vim.lsp.util.buf_versions[versionedBuf0.bufnr] = versionedBuf0.currentVersion + vim.lsp.util.apply_text_document_edit(edit0, nil, 'utf-16') + end, edit, versionedBuf) end local baseText = { @@ -2249,13 +2258,17 @@ describe('LSP', function() } eq( expected, - exec_lua [[ - local apply_edit = { - label = nil; - edit = {}; - } - return vim.lsp.handlers['workspace/applyEdit'](nil, apply_edit, {client_id = TEST_RPC_CLIENT_ID}) - ]] + exec_lua(function() + local apply_edit = { + label = nil, + edit = {}, + } + return vim.lsp.handlers['workspace/applyEdit']( + nil, + apply_edit, + { client_id = _G.TEST_RPC_CLIENT_ID } + ) + end) ) eq(table.remove(expected_handlers), { ... }) end, @@ -2288,11 +2301,11 @@ describe('LSP', function() local target_bufnr, changedtick = nil, nil before_each(function() - local ret = exec_lua [[ - local bufnr = vim.uri_to_bufnr("file:///fake/uri") + local ret = exec_lua(function() + local bufnr = vim.uri_to_bufnr('file:///fake/uri') local lines = { - "Original Line #1", - "Original Line #2" + 'Original Line #1', + 'Original Line #2', } vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines) @@ -2305,11 +2318,11 @@ describe('LSP', function() vim.api.nvim_buf_attach(bufnr, false, { on_changedtick = function() update_changed_tick() - end + end, }) - return {bufnr, vim.api.nvim_buf_get_var(bufnr, 'changedtick')} - ]] + return { bufnr, vim.api.nvim_buf_get_var(bufnr, 'changedtick') } + end) target_bufnr = ret[1] changedtick = ret[2] @@ -2330,19 +2343,11 @@ describe('LSP', function() 'First Line', 'Original Line #2', }, - exec_lua( - [[ - local args = {...} - local workspace_edits = args[1] - local target_bufnr = args[2] + exec_lua(function(workspace_edits, target_bufnr0) + vim.lsp.util.apply_workspace_edit(workspace_edits, 'utf-16') - vim.lsp.util.apply_workspace_edit(workspace_edits, 'utf-16') - - return vim.api.nvim_buf_get_lines(target_bufnr, 0, -1, false) - ]], - make_workspace_edit(edits), - target_bufnr - ) + return vim.api.nvim_buf_get_lines(target_bufnr0, 0, -1, false) + end, make_workspace_edit(edits), target_bufnr) ) end) @@ -2359,19 +2364,11 @@ describe('LSP', function() eq( new_lines, - exec_lua( - [[ - local args = {...} - local workspace_edits = args[1] - local target_bufnr = args[2] + exec_lua(function(workspace_edits, target_bufnr0) + vim.lsp.util.apply_workspace_edit(workspace_edits, 'utf-16') - vim.lsp.util.apply_workspace_edit(workspace_edits, 'utf-16') - - return vim.api.nvim_buf_get_lines(target_bufnr, 0, -1, false) - ]], - make_workspace_edit(edits), - target_bufnr - ) + return vim.api.nvim_buf_get_lines(target_bufnr0, 0, -1, false) + end, make_workspace_edit(edits), target_bufnr) ) end) it('Supports file creation with CreateFile payload', function() @@ -2450,15 +2447,11 @@ describe('LSP', function() it('DeleteFile delete file and buffer', function() local tmpfile = tmpname() write_file(tmpfile, 'Be gone') - local uri = exec_lua( - [[ - local fname = select(1, ...) + local uri = exec_lua(function(fname) local bufnr = vim.fn.bufadd(fname) vim.fn.bufload(bufnr) return vim.uri_from_fname(fname) - ]], - tmpfile - ) + end, tmpfile) local edit = { documentChanges = { { @@ -2499,21 +2492,15 @@ describe('LSP', function() write_file(old, 'Test content') local new = tmpname() os.remove(new) -- only reserve the name, file must not exist for the test scenario - local lines = exec_lua( - [[ - local old = select(1, ...) - local new = select(2, ...) - local old_bufnr = vim.fn.bufadd(old) + local lines = exec_lua(function(old0, new0) + local old_bufnr = vim.fn.bufadd(old0) vim.fn.bufload(old_bufnr) - vim.lsp.util.rename(old, new) + vim.lsp.util.rename(old0, new0) -- the existing buffer is renamed in-place and its contents is kept - local new_bufnr = vim.fn.bufadd(new) + local new_bufnr = vim.fn.bufadd(new0) vim.fn.bufload(new_bufnr) return (old_bufnr == new_bufnr) and vim.api.nvim_buf_get_lines(new_bufnr, 0, -1, true) - ]], - old, - new - ) + end, old, new) eq({ 'Test content' }, lines) local exists = vim.uv.fs_stat(old) ~= nil eq(false, exists) @@ -2533,25 +2520,15 @@ describe('LSP', function() local file = 'file.txt' write_file(old_dir .. pathsep .. file, 'Test content') - local lines = exec_lua( - [[ - local old_dir = select(1, ...) - local new_dir = select(2, ...) - local pathsep = select(3, ...) - local file = select(4, ...) - local old_bufnr = vim.fn.bufadd(old_dir .. pathsep .. file) + local lines = exec_lua(function(old_dir0, new_dir0, pathsep0, file0) + local old_bufnr = vim.fn.bufadd(old_dir0 .. pathsep0 .. file0) vim.fn.bufload(old_bufnr) - vim.lsp.util.rename(old_dir, new_dir) + vim.lsp.util.rename(old_dir0, new_dir0) -- the existing buffer is renamed in-place and its contents is kept - local new_bufnr = vim.fn.bufadd(new_dir .. pathsep .. file) + local new_bufnr = vim.fn.bufadd(new_dir0 .. pathsep0 .. file0) vim.fn.bufload(new_bufnr) return (old_bufnr == new_bufnr) and vim.api.nvim_buf_get_lines(new_bufnr, 0, -1, true) - ]], - old_dir, - new_dir, - pathsep, - file - ) + end, old_dir, new_dir, pathsep, file) eq({ 'Test content' }, lines) eq(false, vim.uv.fs_stat(old_dir) ~= nil) eq(true, vim.uv.fs_stat(new_dir) ~= nil) @@ -2566,36 +2543,28 @@ describe('LSP', function() os.remove(new) n.mkdir_p(old) - local result = exec_lua( - [[ - local old = select(1, ...) - local new = select(2, ...) - - local old_prefixed = 'explorer://' .. old - local old_suffixed = old .. '.bak' - local new_prefixed = 'explorer://' .. new - local new_suffixed = new .. '.bak' + local result = exec_lua(function(old0, new0) + local old_prefixed = 'explorer://' .. old0 + local old_suffixed = old0 .. '.bak' + local new_prefixed = 'explorer://' .. new0 + local new_suffixed = new0 .. '.bak' local old_prefixed_buf = vim.fn.bufadd(old_prefixed) local old_suffixed_buf = vim.fn.bufadd(old_suffixed) local new_prefixed_buf = vim.fn.bufadd(new_prefixed) local new_suffixed_buf = vim.fn.bufadd(new_suffixed) - vim.lsp.util.rename(old, new) - - return - vim.api.nvim_buf_is_valid(old_prefixed_buf) and - vim.api.nvim_buf_is_valid(old_suffixed_buf) and - vim.api.nvim_buf_is_valid(new_prefixed_buf) and - vim.api.nvim_buf_is_valid(new_suffixed_buf) and - vim.api.nvim_buf_get_name(old_prefixed_buf) == old_prefixed and - vim.api.nvim_buf_get_name(old_suffixed_buf) == old_suffixed and - vim.api.nvim_buf_get_name(new_prefixed_buf) == new_prefixed and - vim.api.nvim_buf_get_name(new_suffixed_buf) == new_suffixed - ]], - old, - new - ) + vim.lsp.util.rename(old0, new0) + + return vim.api.nvim_buf_is_valid(old_prefixed_buf) + and vim.api.nvim_buf_is_valid(old_suffixed_buf) + and vim.api.nvim_buf_is_valid(new_prefixed_buf) + and vim.api.nvim_buf_is_valid(new_suffixed_buf) + and vim.api.nvim_buf_get_name(old_prefixed_buf) == old_prefixed + and vim.api.nvim_buf_get_name(old_suffixed_buf) == old_suffixed + and vim.api.nvim_buf_get_name(new_prefixed_buf) == new_prefixed + and vim.api.nvim_buf_get_name(new_suffixed_buf) == new_suffixed + end, old, new) eq(true, result) os.remove(new) @@ -2608,30 +2577,16 @@ describe('LSP', function() local new = tmpname() write_file(new, 'New file') - exec_lua( - [[ - local old = select(1, ...) - local new = select(2, ...) - - vim.lsp.util.rename(old, new, { ignoreIfExists = true }) - ]], - old, - new - ) + exec_lua(function(old0, new0) + vim.lsp.util.rename(old0, new0, { ignoreIfExists = true }) + end, old, new) eq(true, vim.uv.fs_stat(old) ~= nil) eq('New file', read_file(new)) - exec_lua( - [[ - local old = select(1, ...) - local new = select(2, ...) - - vim.lsp.util.rename(old, new, { overwrite = false }) - ]], - old, - new - ) + exec_lua(function(old0, new0) + vim.lsp.util.rename(old0, new0, { overwrite = false }) + end, old, new) eq(true, vim.uv.fs_stat(old) ~= nil) eq('New file', read_file(new)) @@ -2643,26 +2598,20 @@ describe('LSP', function() local new = tmpname() os.remove(new) - local undo_kept = exec_lua( - [[ - local old = select(1, ...) - local new = select(2, ...) + local undo_kept = exec_lua(function(old0, new0) vim.opt.undofile = true - vim.cmd.edit(old) + vim.cmd.edit(old0) vim.cmd.normal('dd') vim.cmd.write() local undotree = vim.fn.undotree() - vim.lsp.util.rename(old, new) + vim.lsp.util.rename(old0, new0) -- Renaming uses :saveas, which updates the "last write" information. -- Other than that, the undotree should remain the same. undotree.save_cur = undotree.save_cur + 1 undotree.save_last = undotree.save_last + 1 undotree.entries[1].save = undotree.entries[1].save + 1 return vim.deep_equal(undotree, vim.fn.undotree()) - ]], - old, - new - ) + end, old, new) eq(false, vim.uv.fs_stat(old) ~= nil) eq(true, vim.uv.fs_stat(new) ~= nil) eq(true, undo_kept) @@ -2673,23 +2622,17 @@ describe('LSP', function() local new = tmpname() os.remove(new) - local undo_kept = exec_lua( - [[ - local old = select(1, ...) - local new = select(2, ...) + local undo_kept = exec_lua(function(old0, new0) vim.opt.undofile = true - vim.cmd.split(old) + vim.cmd.split(old0) vim.cmd.normal('dd') vim.cmd.write() local undotree = vim.fn.undotree() vim.cmd.bdelete() - vim.lsp.util.rename(old, new) - vim.cmd.edit(new) + vim.lsp.util.rename(old0, new0) + vim.cmd.edit(new0) return vim.deep_equal(undotree, vim.fn.undotree()) - ]], - old, - new - ) + end, old, new) eq(false, vim.uv.fs_stat(old) ~= nil) eq(true, vim.uv.fs_stat(new) ~= nil) eq(true, undo_kept) @@ -2700,22 +2643,16 @@ describe('LSP', function() local new = tmpname() os.remove(new) - local lines = exec_lua( - [[ - local old = select(1, ...) - local new = select(2, ...) - local old_buf = vim.fn.bufadd(old) - vim.fn.bufload(old_buf) - local conflict_buf = vim.api.nvim_create_buf(true, false) - vim.api.nvim_buf_set_name(conflict_buf, new) - vim.api.nvim_buf_set_lines(conflict_buf, 0, -1, true, {'conflict'}) - vim.api.nvim_win_set_buf(0, conflict_buf) - vim.lsp.util.rename(old, new) - return vim.api.nvim_buf_get_lines(conflict_buf, 0, -1, true) - ]], - old, - new - ) + local lines = exec_lua(function(old0, new0) + local old_buf = vim.fn.bufadd(old0) + vim.fn.bufload(old_buf) + local conflict_buf = vim.api.nvim_create_buf(true, false) + vim.api.nvim_buf_set_name(conflict_buf, new0) + vim.api.nvim_buf_set_lines(conflict_buf, 0, -1, true, { 'conflict' }) + vim.api.nvim_win_set_buf(0, conflict_buf) + vim.lsp.util.rename(old0, new0) + return vim.api.nvim_buf_get_lines(conflict_buf, 0, -1, true) + end, old, new) eq({ 'conflict' }, lines) eq('Old File', read_file(old)) end) @@ -2724,16 +2661,9 @@ describe('LSP', function() write_file(old, 'Old file') local new = tmpname() write_file(new, 'New file') - exec_lua( - [[ - local old = select(1, ...) - local new = select(2, ...) - - vim.lsp.util.rename(old, new, { overwrite = true }) - ]], - old, - new - ) + exec_lua(function(old0, new0) + vim.lsp.util.rename(old0, new0, { overwrite = true }) + end, old, new) eq(false, vim.uv.fs_stat(old) ~= nil) eq(true, vim.uv.fs_stat(new) ~= nil) @@ -2760,9 +2690,9 @@ describe('LSP', function() }, }, } - local actual = exec_lua [[ - local bufnr = vim.uri_to_bufnr("file:///fake/uri") - local lines = {"testing", "123"} + local actual = exec_lua(function() + local bufnr = vim.uri_to_bufnr('file:///fake/uri') + local lines = { 'testing', '123' } vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines) local locations = { { @@ -2770,11 +2700,11 @@ describe('LSP', function() range = { start = { line = 0, character = 2 }, ['end'] = { line = 1, character = 3 }, - } + }, }, } return vim.lsp.util.locations_to_items(locations, 'utf-16') - ]] + end) eq(expected, actual) end) it('Convert LocationLink[] to items', function() @@ -2799,9 +2729,9 @@ describe('LSP', function() }, }, } - local actual = exec_lua [[ - local bufnr = vim.uri_to_bufnr("file:///fake/uri") - local lines = {"testing", "123"} + local actual = exec_lua(function() + local bufnr = vim.uri_to_bufnr('file:///fake/uri') + local lines = { 'testing', '123' } vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines) local locations = { { @@ -2813,11 +2743,11 @@ describe('LSP', function() targetSelectionRange = { start = { line = 0, character = 2 }, ['end'] = { line = 0, character = 3 }, - } + }, }, } return vim.lsp.util.locations_to_items(locations, 'utf-16') - ]] + end) eq(expected, actual) end) end) @@ -2850,92 +2780,92 @@ describe('LSP', function() } eq( expected, - exec_lua [[ - local doc_syms = { - { - deprecated = false, - detail = "A", - kind = 1, - name = "TestA", - range = { - start = { - character = 0, - line = 1 + exec_lua(function() + local doc_syms = { + { + deprecated = false, + detail = 'A', + kind = 1, + name = 'TestA', + range = { + start = { + character = 0, + line = 1, + }, + ['end'] = { + character = 0, + line = 2, + }, }, - ["end"] = { - character = 0, - line = 2 - } - }, - selectionRange = { - start = { - character = 0, - line = 1 + selectionRange = { + start = { + character = 0, + line = 1, + }, + ['end'] = { + character = 4, + line = 1, + }, }, - ["end"] = { - character = 4, - line = 1 - } - }, - children = { - { - children = {}, - deprecated = false, - detail = "B", - kind = 2, - name = "TestB", - range = { - start = { - character = 0, - line = 3 + children = { + { + children = {}, + deprecated = false, + detail = 'B', + kind = 2, + name = 'TestB', + range = { + start = { + character = 0, + line = 3, + }, + ['end'] = { + character = 0, + line = 4, + }, }, - ["end"] = { - character = 0, - line = 4 - } - }, - selectionRange = { - start = { - character = 0, - line = 3 + selectionRange = { + start = { + character = 0, + line = 3, + }, + ['end'] = { + character = 4, + line = 3, + }, }, - ["end"] = { - character = 4, - line = 3 - } - } - } - } - }, - { - deprecated = false, - detail = "C", - kind = 3, - name = "TestC", - range = { - start = { - character = 0, - line = 5 + }, }, - ["end"] = { - character = 0, - line = 6 - } }, - selectionRange = { - start = { - character = 0, - line = 5 + { + deprecated = false, + detail = 'C', + kind = 3, + name = 'TestC', + range = { + start = { + character = 0, + line = 5, + }, + ['end'] = { + character = 0, + line = 6, + }, }, - ["end"] = { - character = 4, - line = 5 - } - } + selectionRange = { + start = { + character = 0, + line = 5, + }, + ['end'] = { + character = 4, + line = 5, + }, + }, + }, } - } - return vim.lsp.util.symbols_to_items(doc_syms, nil) - ]] + return vim.lsp.util.symbols_to_items(doc_syms, nil) + end) ) end) it('DocumentSymbol has no children', function() @@ -2957,63 +2887,63 @@ describe('LSP', function() } eq( expected, - exec_lua [[ - local doc_syms = { - { - deprecated = false, - detail = "A", - kind = 1, - name = "TestA", - range = { - start = { - character = 0, - line = 1 + exec_lua(function() + local doc_syms = { + { + deprecated = false, + detail = 'A', + kind = 1, + name = 'TestA', + range = { + start = { + character = 0, + line = 1, + }, + ['end'] = { + character = 0, + line = 2, + }, }, - ["end"] = { - character = 0, - line = 2 - } - }, - selectionRange = { - start = { - character = 0, - line = 1 + selectionRange = { + start = { + character = 0, + line = 1, + }, + ['end'] = { + character = 4, + line = 1, + }, }, - ["end"] = { - character = 4, - line = 1 - } }, - }, - { - deprecated = false, - detail = "C", - kind = 3, - name = "TestC", - range = { - start = { - character = 0, - line = 5 + { + deprecated = false, + detail = 'C', + kind = 3, + name = 'TestC', + range = { + start = { + character = 0, + line = 5, + }, + ['end'] = { + character = 0, + line = 6, + }, }, - ["end"] = { - character = 0, - line = 6 - } - }, - selectionRange = { - start = { - character = 0, - line = 5 + selectionRange = { + start = { + character = 0, + line = 5, + }, + ['end'] = { + character = 4, + line = 5, + }, }, - ["end"] = { - character = 4, - line = 5 - } - } + }, } - } - return vim.lsp.util.symbols_to_items(doc_syms, nil) - ]] + return vim.lsp.util.symbols_to_items(doc_syms, nil) + end) ) end) end) @@ -3036,49 +2966,49 @@ describe('LSP', function() } eq( expected, - exec_lua [[ + exec_lua(function() local sym_info = { { deprecated = false, kind = 1, - name = "TestA", + name = 'TestA', location = { range = { start = { character = 0, - line = 1 + line = 1, }, - ["end"] = { + ['end'] = { character = 0, - line = 2 - } + line = 2, + }, }, - uri = "file:///test_a" + uri = 'file:///test_a', }, - containerName = "TestAContainer" + containerName = 'TestAContainer', }, { deprecated = false, kind = 2, - name = "TestB", + name = 'TestB', location = { range = { start = { character = 0, - line = 3 + line = 3, }, - ["end"] = { + ['end'] = { character = 0, - line = 4 - } + line = 4, + }, }, - uri = "file:///test_b" + uri = 'file:///test_b', }, - containerName = "TestBContainer" - } + containerName = 'TestBContainer', + }, } return vim.lsp.util.symbols_to_items(sym_info, nil) - ]] + end) ) end) end) @@ -3099,12 +3029,12 @@ describe('LSP', function() local target_bufnr --- @type integer before_each(function() - target_bufnr = exec_lua [[ - local bufnr = vim.uri_to_bufnr("file:///fake/uri") - local lines = {"1st line of text", "å å ɧ 汉语 ↥ 🤦 🦄"} + target_bufnr = exec_lua(function() + local bufnr = vim.uri_to_bufnr('file:///fake/uri') + local lines = { '1st line of text', 'å å ɧ 汉语 ↥ 🤦 🦄' } vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines) return bufnr - ]] + end) end) local location = function(start_line, start_char, end_line, end_char) @@ -3173,19 +3103,19 @@ describe('LSP', function() local target_bufnr2 --- @type integer before_each(function() - target_bufnr = exec_lua([[ - local bufnr = vim.uri_to_bufnr("file:///fake/uri") - local lines = {"1st line of text", "å å ɧ 汉语 ↥ 🤦 🦄"} + target_bufnr = exec_lua(function() + local bufnr = vim.uri_to_bufnr('file:///fake/uri') + local lines = { '1st line of text', 'å å ɧ 汉语 ↥ 🤦 🦄' } vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines) return bufnr - ]]) + end) - target_bufnr2 = exec_lua([[ - local bufnr = vim.uri_to_bufnr("file:///fake/uri2") - local lines = {"1st line of text", "å å ɧ 汉语 ↥ 🤦 🦄"} + target_bufnr2 = exec_lua(function() + local bufnr = vim.uri_to_bufnr('file:///fake/uri2') + local lines = { '1st line of text', 'å å ɧ 汉语 ↥ 🤦 🦄' } vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines) return bufnr - ]]) + end) end) local location = function(start_line, start_char, end_line, end_char, second_uri) @@ -3225,14 +3155,14 @@ describe('LSP', function() it('jumps to a Location if focus is true via handler', function() exec_lua(create_server_definition) - local result = exec_lua([[ - local server = _create_server() + local result = exec_lua(function() + local server = _G._create_server() local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) local result = { uri = 'file:///fake/uri', selection = { start = { line = 0, character = 9 }, - ['end'] = { line = 0, character = 9 } + ['end'] = { line = 0, character = 9 }, }, takeFocus = true, } @@ -3243,9 +3173,9 @@ describe('LSP', function() vim.lsp.handlers['window/showDocument'](nil, result, ctx) vim.lsp.stop_client(client_id) return { - cursor = vim.api.nvim_win_get_cursor(0) + cursor = vim.api.nvim_win_get_cursor(0), } - ]]) + end) eq(1, result.cursor[1]) eq(9, result.cursor[2]) end) @@ -3320,7 +3250,9 @@ describe('LSP', function() api.nvim_win_set_buf(0, target_bufnr) api.nvim_win_set_cursor(0, { 2, 3 }) - exec_lua([[vim.cmd.new()]]) + exec_lua(function() + vim.cmd.new() + end) api.nvim_win_set_buf(0, target_bufnr2) api.nvim_win_set_cursor(0, { 2, 3 }) @@ -3336,7 +3268,9 @@ describe('LSP', function() api.nvim_win_set_buf(0, target_bufnr) local win = api.nvim_get_current_win() - exec_lua([[vim.cmd.new()]]) + exec_lua(function() + vim.cmd.new() + end) api.nvim_win_set_buf(0, target_bufnr2) api.nvim_win_set_cursor(0, { 2, 3 }) local split = api.nvim_get_current_win() @@ -3357,34 +3291,53 @@ describe('LSP', function() describe('lsp.util._make_floating_popup_size', function() before_each(function() - exec_lua [[ contents = - {"text tαxt txtα tex", - "text tααt tααt text", - "text tαxt tαxt"} - ]] + exec_lua(function() + _G.contents = { 'text tαxt txtα tex', 'text tααt tααt text', 'text tαxt tαxt' } + end) end) it('calculates size correctly', function() - eq({ 19, 3 }, exec_lua [[ return {vim.lsp.util._make_floating_popup_size(contents)} ]]) + eq( + { 19, 3 }, + exec_lua(function() + return { vim.lsp.util._make_floating_popup_size(_G.contents) } + end) + ) end) it('calculates size correctly with wrapping', function() eq( { 15, 5 }, - exec_lua [[ return {vim.lsp.util._make_floating_popup_size(contents,{width = 15, wrap_at = 14})} ]] + exec_lua(function() + return { + vim.lsp.util._make_floating_popup_size(_G.contents, { width = 15, wrap_at = 14 }), + } + end) ) end) it('handles NUL bytes in text', function() - exec_lua([[ contents = { - '\000\001\002\003\004\005\006\007\008\009', - '\010\011\012\013\014\015\016\017\018\019', - '\020\021\022\023\024\025\026\027\028\029', - } ]]) + exec_lua(function() + _G.contents = { + '\000\001\002\003\004\005\006\007\008\009', + '\010\011\012\013\014\015\016\017\018\019', + '\020\021\022\023\024\025\026\027\028\029', + } + end) command('set list listchars=') - eq({ 20, 3 }, exec_lua [[ return {vim.lsp.util._make_floating_popup_size(contents)} ]]) + eq( + { 20, 3 }, + exec_lua(function() + return { vim.lsp.util._make_floating_popup_size(_G.contents) } + end) + ) command('set display+=uhex') - eq({ 40, 3 }, exec_lua [[ return {vim.lsp.util._make_floating_popup_size(contents)} ]]) + eq( + { 40, 3 }, + exec_lua(function() + return { vim.lsp.util._make_floating_popup_size(_G.contents) } + end) + ) end) end) @@ -3392,27 +3345,29 @@ describe('LSP', function() it('properly trims empty lines', function() eq( { { 'foo', 'bar' } }, - exec_lua [[ return vim.lsp.util.trim_empty_lines({{ "foo", "bar" }, nil}) ]] + exec_lua(function() + return vim.lsp.util.trim_empty_lines({ { 'foo', 'bar' }, nil }) + end) ) end) end) describe('lsp.util.convert_signature_help_to_markdown_lines', function() it('can handle negative activeSignature', function() - local result = exec_lua [[ + local result = exec_lua(function() local signature_help = { activeParameter = 0, activeSignature = -1, signatures = { { - documentation = "some doc", - label = "TestEntity.TestEntity()", - parameters = {} + documentation = 'some doc', + label = 'TestEntity.TestEntity()', + parameters = {}, }, - } + }, } - return vim.lsp.util.convert_signature_help_to_markdown_lines(signature_help, 'cs', {','}) - ]] + return vim.lsp.util.convert_signature_help_to_markdown_lines(signature_help, 'cs', { ',' }) + end) local expected = { '```cs', 'TestEntity.TestEntity()', '```', 'some doc' } eq(expected, result) end) @@ -3440,57 +3395,61 @@ describe('LSP', function() describe('vim.lsp.buf.outgoing_calls', function() it('does nothing for an empty response', function() - local qflist_count = exec_lua([=[ - require'vim.lsp.handlers'['callHierarchy/outgoingCalls'](nil, nil, {}, nil) + local qflist_count = exec_lua(function() + require 'vim.lsp.handlers'['callHierarchy/outgoingCalls'](nil, nil, {}, nil) return #vim.fn.getqflist() - ]=]) + end) eq(0, qflist_count) end) it('opens the quickfix list with the right caller', function() - local qflist = exec_lua([=[ - local rust_analyzer_response = { { - fromRanges = { { - ['end'] = { - character = 7, - line = 3 - }, - start = { - character = 4, - line = 3 - } - } }, - to = { - detail = "fn foo()", - kind = 12, - name = "foo", - range = { - ['end'] = { - character = 11, - line = 0 + local qflist = exec_lua(function() + local rust_analyzer_response = { + { + fromRanges = { + { + ['end'] = { + character = 7, + line = 3, + }, + start = { + character = 4, + line = 3, + }, }, - start = { - character = 0, - line = 0 - } }, - selectionRange = { - ['end'] = { - character = 6, - line = 0 + to = { + detail = 'fn foo()', + kind = 12, + name = 'foo', + range = { + ['end'] = { + character = 11, + line = 0, + }, + start = { + character = 0, + line = 0, + }, }, - start = { - character = 3, - line = 0 - } + selectionRange = { + ['end'] = { + character = 6, + line = 0, + }, + start = { + character = 3, + line = 0, + }, + }, + uri = 'file:///src/main.rs', }, - uri = "file:///src/main.rs" - } - } } - local handler = require'vim.lsp.handlers'['callHierarchy/outgoingCalls'] + }, + } + local handler = require 'vim.lsp.handlers'['callHierarchy/outgoingCalls'] handler(nil, rust_analyzer_response, {}) return vim.fn.getqflist() - ]=]) + end) local expected = { { @@ -3515,58 +3474,62 @@ describe('LSP', function() describe('vim.lsp.buf.incoming_calls', function() it('does nothing for an empty response', function() - local qflist_count = exec_lua([=[ - require'vim.lsp.handlers'['callHierarchy/incomingCalls'](nil, nil, {}) + local qflist_count = exec_lua(function() + require 'vim.lsp.handlers'['callHierarchy/incomingCalls'](nil, nil, {}) return #vim.fn.getqflist() - ]=]) + end) eq(0, qflist_count) end) it('opens the quickfix list with the right callee', function() - local qflist = exec_lua([=[ - local rust_analyzer_response = { { - from = { - detail = "fn main()", - kind = 12, - name = "main", - range = { - ['end'] = { - character = 1, - line = 4 + local qflist = exec_lua(function() + local rust_analyzer_response = { + { + from = { + detail = 'fn main()', + kind = 12, + name = 'main', + range = { + ['end'] = { + character = 1, + line = 4, + }, + start = { + character = 0, + line = 2, + }, }, - start = { - character = 0, - line = 2 - } + selectionRange = { + ['end'] = { + character = 7, + line = 2, + }, + start = { + character = 3, + line = 2, + }, + }, + uri = 'file:///src/main.rs', }, - selectionRange = { - ['end'] = { - character = 7, - line = 2 + fromRanges = { + { + ['end'] = { + character = 7, + line = 3, + }, + start = { + character = 4, + line = 3, + }, }, - start = { - character = 3, - line = 2 - } }, - uri = "file:///src/main.rs" }, - fromRanges = { { - ['end'] = { - character = 7, - line = 3 - }, - start = { - character = 4, - line = 3 - } - } } - } } + } - local handler = require'vim.lsp.handlers'['callHierarchy/incomingCalls'] + local handler = require 'vim.lsp.handlers'['callHierarchy/incomingCalls'] handler(nil, rust_analyzer_response, {}) return vim.fn.getqflist() - ]=]) + end) local expected = { { @@ -3591,103 +3554,118 @@ describe('LSP', function() describe('vim.lsp.buf.typehierarchy subtypes', function() it('does nothing for an empty response', function() - local qflist_count = exec_lua([=[ - require'vim.lsp.handlers'['typeHierarchy/subtypes'](nil, nil, {}) + local qflist_count = exec_lua(function() + require 'vim.lsp.handlers'['typeHierarchy/subtypes'](nil, nil, {}) return #vim.fn.getqflist() - ]=]) + end) eq(0, qflist_count) end) it('opens the quickfix list with the right subtypes', function() clear() exec_lua(create_server_definition) - local qflist = exec_lua([=[ - local clangd_response = { { - data = { - parents = { { - parents = { { - parents = { { - parents = {}, - symbolID = "62B3D268A01B9978" - } }, - symbolID = "DC9B0AD433B43BEC" - } }, - symbolID = "06B5F6A19BA9F6A8" - } }, - symbolID = "EDC336589C09ABB2" - }, - kind = 5, - name = "D2", - range = { - ["end"] = { - character = 8, - line = 9 + local qflist = exec_lua(function() + local clangd_response = { + { + data = { + parents = { + { + parents = { + { + parents = { + { + parents = {}, + symbolID = '62B3D268A01B9978', + }, + }, + symbolID = 'DC9B0AD433B43BEC', + }, + }, + symbolID = '06B5F6A19BA9F6A8', + }, + }, + symbolID = 'EDC336589C09ABB2', }, - start = { - character = 6, - line = 9 - } - }, - selectionRange = { - ["end"] = { - character = 8, - line = 9 + kind = 5, + name = 'D2', + range = { + ['end'] = { + character = 8, + line = 9, + }, + start = { + character = 6, + line = 9, + }, }, - start = { - character = 6, - line = 9 - } - }, - uri = "file:///home/jiangyinzuo/hello.cpp" - }, { - data = { - parents = { { - parents = { { - parents = { { - parents = {}, - symbolID = "62B3D268A01B9978" - } }, - symbolID = "DC9B0AD433B43BEC" - } }, - symbolID = "06B5F6A19BA9F6A8" - } }, - symbolID = "AFFCAED15557EF08" - }, - kind = 5, - name = "D1", - range = { - ["end"] = { - character = 8, - line = 8 + selectionRange = { + ['end'] = { + character = 8, + line = 9, + }, + start = { + character = 6, + line = 9, + }, }, - start = { - character = 6, - line = 8 - } + uri = 'file:///home/jiangyinzuo/hello.cpp', }, - selectionRange = { - ["end"] = { - character = 8, - line = 8 + { + data = { + parents = { + { + parents = { + { + parents = { + { + parents = {}, + symbolID = '62B3D268A01B9978', + }, + }, + symbolID = 'DC9B0AD433B43BEC', + }, + }, + symbolID = '06B5F6A19BA9F6A8', + }, + }, + symbolID = 'AFFCAED15557EF08', }, - start = { - character = 6, - line = 8 - } + kind = 5, + name = 'D1', + range = { + ['end'] = { + character = 8, + line = 8, + }, + start = { + character = 6, + line = 8, + }, + }, + selectionRange = { + ['end'] = { + character = 8, + line = 8, + }, + start = { + character = 6, + line = 8, + }, + }, + uri = 'file:///home/jiangyinzuo/hello.cpp', }, - uri = "file:///home/jiangyinzuo/hello.cpp" - } } + } - local server = _create_server({ + local server = _G._create_server({ capabilities = { - positionEncoding = "utf-8" + positionEncoding = 'utf-8', }, }) local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) - local handler = require'vim.lsp.handlers'['typeHierarchy/subtypes'] + local handler = require 'vim.lsp.handlers'['typeHierarchy/subtypes'] handler(nil, clangd_response, { client_id = client_id, bufnr = 1 }) return vim.fn.getqflist() - ]=]) + end) local expected = { { @@ -3726,7 +3704,7 @@ describe('LSP', function() it('opens the quickfix list with the right subtypes and details', function() clear() exec_lua(create_server_definition) - local qflist = exec_lua([=[ + local qflist = exec_lua(function() local jdtls_response = { { data = { element = '=hello-java_ed323c3c/_<{Main.java[Main[A' }, @@ -3762,16 +3740,16 @@ describe('LSP', function() }, } - local server = _create_server({ + local server = _G._create_server({ capabilities = { - positionEncoding = "utf-8" + positionEncoding = 'utf-8', }, }) local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) - local handler = require'vim.lsp.handlers'['typeHierarchy/subtypes'] + local handler = require 'vim.lsp.handlers'['typeHierarchy/subtypes'] handler(nil, jdtls_response, { client_id = client_id, bufnr = 1 }) return vim.fn.getqflist() - ]=]) + end) local expected = { { @@ -3809,103 +3787,118 @@ describe('LSP', function() describe('vim.lsp.buf.typehierarchy supertypes', function() it('does nothing for an empty response', function() - local qflist_count = exec_lua([=[ - require'vim.lsp.handlers'['typeHierarchy/supertypes'](nil, nil, {}) + local qflist_count = exec_lua(function() + require 'vim.lsp.handlers'['typeHierarchy/supertypes'](nil, nil, {}) return #vim.fn.getqflist() - ]=]) + end) eq(0, qflist_count) end) it('opens the quickfix list with the right supertypes', function() clear() exec_lua(create_server_definition) - local qflist = exec_lua([=[ - local clangd_response = { { - data = { - parents = { { - parents = { { - parents = { { - parents = {}, - symbolID = "62B3D268A01B9978" - } }, - symbolID = "DC9B0AD433B43BEC" - } }, - symbolID = "06B5F6A19BA9F6A8" - } }, - symbolID = "EDC336589C09ABB2" - }, - kind = 5, - name = "D2", - range = { - ["end"] = { - character = 8, - line = 9 + local qflist = exec_lua(function() + local clangd_response = { + { + data = { + parents = { + { + parents = { + { + parents = { + { + parents = {}, + symbolID = '62B3D268A01B9978', + }, + }, + symbolID = 'DC9B0AD433B43BEC', + }, + }, + symbolID = '06B5F6A19BA9F6A8', + }, + }, + symbolID = 'EDC336589C09ABB2', }, - start = { - character = 6, - line = 9 - } - }, - selectionRange = { - ["end"] = { - character = 8, - line = 9 + kind = 5, + name = 'D2', + range = { + ['end'] = { + character = 8, + line = 9, + }, + start = { + character = 6, + line = 9, + }, }, - start = { - character = 6, - line = 9 - } - }, - uri = "file:///home/jiangyinzuo/hello.cpp" - }, { - data = { - parents = { { - parents = { { - parents = { { - parents = {}, - symbolID = "62B3D268A01B9978" - } }, - symbolID = "DC9B0AD433B43BEC" - } }, - symbolID = "06B5F6A19BA9F6A8" - } }, - symbolID = "AFFCAED15557EF08" - }, - kind = 5, - name = "D1", - range = { - ["end"] = { - character = 8, - line = 8 + selectionRange = { + ['end'] = { + character = 8, + line = 9, + }, + start = { + character = 6, + line = 9, + }, }, - start = { - character = 6, - line = 8 - } + uri = 'file:///home/jiangyinzuo/hello.cpp', }, - selectionRange = { - ["end"] = { - character = 8, - line = 8 + { + data = { + parents = { + { + parents = { + { + parents = { + { + parents = {}, + symbolID = '62B3D268A01B9978', + }, + }, + symbolID = 'DC9B0AD433B43BEC', + }, + }, + symbolID = '06B5F6A19BA9F6A8', + }, + }, + symbolID = 'AFFCAED15557EF08', }, - start = { - character = 6, - line = 8 - } + kind = 5, + name = 'D1', + range = { + ['end'] = { + character = 8, + line = 8, + }, + start = { + character = 6, + line = 8, + }, + }, + selectionRange = { + ['end'] = { + character = 8, + line = 8, + }, + start = { + character = 6, + line = 8, + }, + }, + uri = 'file:///home/jiangyinzuo/hello.cpp', }, - uri = "file:///home/jiangyinzuo/hello.cpp" - } } + } - local server = _create_server({ + local server = _G._create_server({ capabilities = { - positionEncoding = "utf-8" + positionEncoding = 'utf-8', }, }) local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) - local handler = require'vim.lsp.handlers'['typeHierarchy/supertypes'] + local handler = require 'vim.lsp.handlers'['typeHierarchy/supertypes'] handler(nil, clangd_response, { client_id = client_id, bufnr = 1 }) return vim.fn.getqflist() - ]=]) + end) local expected = { { @@ -3944,7 +3937,7 @@ describe('LSP', function() it('opens the quickfix list with the right supertypes and details', function() clear() exec_lua(create_server_definition) - local qflist = exec_lua([=[ + local qflist = exec_lua(function() local jdtls_response = { { data = { element = '=hello-java_ed323c3c/_<{Main.java[Main[A' }, @@ -3980,16 +3973,16 @@ describe('LSP', function() }, } - local server = _create_server({ + local server = _G._create_server({ capabilities = { - positionEncoding = "utf-8" + positionEncoding = 'utf-8', }, }) local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) - local handler = require'vim.lsp.handlers'['typeHierarchy/supertypes'] + local handler = require 'vim.lsp.handlers'['typeHierarchy/supertypes'] handler(nil, jdtls_response, { client_id = client_id, bufnr = 1 }) return vim.fn.getqflist() - ]=]) + end) local expected = { { @@ -4073,18 +4066,18 @@ describe('LSP', function() eq(true, client.server_capabilities().renameProvider.prepareProvider) end, on_setup = function() - exec_lua([=[ - local bufnr = vim.api.nvim_get_current_buf() - lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID) - vim.lsp._stubs = {} - vim.fn.input = function(opts, on_confirm) - vim.lsp._stubs.input_prompt = opts.prompt - vim.lsp._stubs.input_text = opts.default - return 'renameto' -- expect this value in fake lsp - end - vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {'', 'this is line two'}) - vim.fn.cursor(2, 13) -- the space between "line" and "two" - ]=]) + exec_lua(function() + local bufnr = vim.api.nvim_get_current_buf() + vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID) + vim.lsp._stubs = {} + vim.fn.input = function(opts, _) + vim.lsp._stubs.input_prompt = opts.prompt + vim.lsp._stubs.input_text = opts.default + return 'renameto' -- expect this value in fake lsp + end + vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { '', 'this is line two' }) + vim.fn.cursor(2, 13) -- the space between "line" and "two" + end) end, on_exit = function(code, signal) eq(0, code, 'exit code') @@ -4133,20 +4126,24 @@ describe('LSP', function() on_handler = function(err, result, ctx) eq(table.remove(expected_handlers), { err, result, ctx }) if ctx.method == 'start' then - exec_lua([[ - vim.lsp.commands['dummy1'] = function(cmd) - vim.lsp.commands['dummy2'] = function() - end + exec_lua(function() + vim.lsp.commands['dummy1'] = function(_) + vim.lsp.commands['dummy2'] = function() end end local bufnr = vim.api.nvim_get_current_buf() - vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID) + vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID) vim.fn.inputlist = function() return 1 end vim.lsp.buf.code_action() - ]]) + end) elseif ctx.method == 'shutdown' then - eq('function', exec_lua [[return type(vim.lsp.commands['dummy2'])]]) + eq( + 'function', + exec_lua(function() + return type(vim.lsp.commands['dummy2']) + end) + ) client.stop() end end, @@ -4178,14 +4175,14 @@ describe('LSP', function() ctx.version = nil eq(table.remove(expected_handlers), { err, result, ctx }) if ctx.method == 'start' then - exec_lua([[ + exec_lua(function() local bufnr = vim.api.nvim_get_current_buf() - vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID) + vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID) vim.fn.inputlist = function() return 1 end vim.lsp.buf.code_action() - ]]) + end) elseif ctx.method == 'shutdown' then client.stop() end @@ -4211,38 +4208,56 @@ describe('LSP', function() on_handler = function(err, result, ctx) eq(table.remove(expected_handlers), { err, result, ctx }) if ctx.method == 'start' then - exec_lua([[ - vim.lsp.commands['preferred_command'] = function(cmd) - vim.lsp.commands['executed_preferred'] = function() - end + exec_lua(function() + vim.lsp.commands['preferred_command'] = function(_) + vim.lsp.commands['executed_preferred'] = function() end end - vim.lsp.commands['type_annotate_command'] = function(cmd) - vim.lsp.commands['executed_type_annotate'] = function() - end + vim.lsp.commands['type_annotate_command'] = function(_) + vim.lsp.commands['executed_type_annotate'] = function() end end local bufnr = vim.api.nvim_get_current_buf() - vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID) - vim.lsp.buf.code_action({ filter = function(a) return a.isPreferred end, apply = true, }) + vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID) vim.lsp.buf.code_action({ - -- expect to be returned actions 'type-annotate' and 'type-annotate.foo' - context = { only = { 'type-annotate' }, }, - apply = true, - filter = function(a) - if a.kind == 'type-annotate.foo' then - vim.lsp.commands['filtered_type_annotate_foo'] = function() end - return false - elseif a.kind == 'type-annotate' then - return true - else - assert(nil, 'unreachable') - end - end, + filter = function(a) + return a.isPreferred + end, + apply = true, }) - ]]) + vim.lsp.buf.code_action({ + -- expect to be returned actions 'type-annotate' and 'type-annotate.foo' + context = { only = { 'type-annotate' } }, + apply = true, + filter = function(a) + if a.kind == 'type-annotate.foo' then + vim.lsp.commands['filtered_type_annotate_foo'] = function() end + return false + elseif a.kind == 'type-annotate' then + return true + else + assert(nil, 'unreachable') + end + end, + }) + end) elseif ctx.method == 'shutdown' then - eq('function', exec_lua [[return type(vim.lsp.commands['executed_preferred'])]]) - eq('function', exec_lua [[return type(vim.lsp.commands['filtered_type_annotate_foo'])]]) - eq('function', exec_lua [[return type(vim.lsp.commands['executed_type_annotate'])]]) + eq( + 'function', + exec_lua(function() + return type(vim.lsp.commands['executed_preferred']) + end) + ) + eq( + 'function', + exec_lua(function() + return type(vim.lsp.commands['filtered_type_annotate_foo']) + end) + ) + eq( + 'function', + exec_lua(function() + return type(vim.lsp.commands['executed_type_annotate']) + end) + ) client.stop() end end, @@ -4251,43 +4266,43 @@ describe('LSP', function() it('Fallback to command execution on resolve error', function() clear() exec_lua(create_server_definition) - local result = exec_lua([[ - local server = _create_server({ + local result = exec_lua(function() + local server = _G._create_server({ capabilities = { executeCommandProvider = { - commands = {"command:1"}, + commands = { 'command:1' }, }, codeActionProvider = { - resolveProvider = true - } + resolveProvider = true, + }, }, handlers = { - ["textDocument/codeAction"] = function(_, _, callback) + ['textDocument/codeAction'] = function(_, _, callback) callback(nil, { { - title = "Code Action 1", + title = 'Code Action 1', command = { - title = "Command 1", - command = "command:1", - } - } + title = 'Command 1', + command = 'command:1', + }, + }, }) end, - ["codeAction/resolve"] = function(_, _, callback) - callback("resolve failed", nil) + ['codeAction/resolve'] = function(_, _, callback) + callback('resolve failed', nil) end, - } + }, }) local client_id = vim.lsp.start({ - name = "dummy", + name = 'dummy', cmd = server.cmd, }) vim.lsp.buf.code_action({ apply = true }) vim.lsp.stop_client(client_id) return server.messages - ]]) + end) eq('codeAction/resolve', result[4].method) eq('workspace/executeCommand', result[5].method) eq('command:1', result[5].params.command) @@ -4330,32 +4345,32 @@ describe('LSP', function() eq(table.remove(expected_handlers), { err, result, ctx }) if ctx.method == 'start' then local fake_uri = 'file:///fake/uri' - local cmd = exec_lua( - [[ - fake_uri = ... - local bufnr = vim.uri_to_bufnr(fake_uri) + local cmd = exec_lua(function(fake_uri0) + local bufnr = vim.uri_to_bufnr(fake_uri0) vim.fn.bufload(bufnr) - vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {'One line'}) + vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { 'One line' }) local lenses = { { range = { - start = { line = 0, character = 0, }, - ['end'] = { line = 0, character = 8 } + start = { line = 0, character = 0 }, + ['end'] = { line = 0, character = 8 }, }, - command = { title = 'Lens1', command = 'Dummy' } + command = { title = 'Lens1', command = 'Dummy' }, }, } - vim.lsp.codelens.on_codelens(nil, lenses, {method='textDocument/codeLens', client_id=1, bufnr=bufnr}) + vim.lsp.codelens.on_codelens( + nil, + lenses, + { method = 'textDocument/codeLens', client_id = 1, bufnr = bufnr } + ) local cmd_called = nil - vim.lsp.commands['Dummy'] = function(command) - cmd_called = command + vim.lsp.commands['Dummy'] = function(command0) + cmd_called = command0 end vim.api.nvim_set_current_buf(bufnr) vim.lsp.codelens.run() return cmd_called - ]], - fake_uri - ) + end, fake_uri) eq({ command = 'Dummy', title = 'Lens1' }, cmd) elseif ctx.method == 'shutdown' then client.stop() @@ -4376,20 +4391,20 @@ describe('LSP', function() client = client_ end, on_setup = function() - exec_lua([=[ - local bufnr = vim.api.nvim_get_current_buf() - vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {'One line'}) - vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID) - - CALLED = false - RESPONSE = nil - local on_codelens = vim.lsp.codelens.on_codelens - vim.lsp.codelens.on_codelens = function (err, result, ...) - CALLED = true - RESPONSE = { err = err, result = result } - return on_codelens(err, result, ...) - end - ]=]) + exec_lua(function() + local bufnr = vim.api.nvim_get_current_buf() + vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { 'One line' }) + vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID) + + _G.CALLED = false + _G.RESPONSE = nil + local on_codelens = vim.lsp.codelens.on_codelens + vim.lsp.codelens.on_codelens = function(err, result, ...) + _G.CALLED = true + _G.RESPONSE = { err = err, result = result } + return on_codelens(err, result, ...) + end + end) end, on_exit = function(code, signal) eq(0, code, 'exit code') @@ -4399,42 +4414,52 @@ describe('LSP', function() eq(table.remove(expected_handlers), { err, result, ctx }) if ctx.method == 'start' then -- 1. first codelens request errors - local response = exec_lua([=[ - CALLED = false + local response = exec_lua(function() + _G.CALLED = false vim.lsp.codelens.refresh() - vim.wait(100, function () return CALLED end) - return RESPONSE - ]=]) + vim.wait(100, function() + return _G.CALLED + end) + return _G.RESPONSE + end) eq({ err = { code = -32002, message = 'ServerNotInitialized' } }, response) -- 2. second codelens request runs - response = exec_lua([=[ - CALLED = false + response = exec_lua(function() + _G.CALLED = false local cmd_called = nil - vim.lsp.commands["Dummy"] = function (command) - cmd_called = command + vim.lsp.commands['Dummy'] = function(command0) + cmd_called = command0 end vim.lsp.codelens.refresh() - vim.wait(100, function () return CALLED end) + vim.wait(100, function() + return _G.CALLED + end) vim.lsp.codelens.run() - vim.wait(100, function () return cmd_called end) + vim.wait(100, function() + return cmd_called + end) return cmd_called - ]=]) + end) eq({ command = 'Dummy', title = 'Lens1' }, response) -- 3. third codelens request runs - response = exec_lua([=[ - CALLED = false + response = exec_lua(function() + _G.CALLED = false local cmd_called = nil - vim.lsp.commands["Dummy"] = function (command) - cmd_called = command + vim.lsp.commands['Dummy'] = function(command0) + cmd_called = command0 end vim.lsp.codelens.refresh() - vim.wait(100, function () return CALLED end) + vim.wait(100, function() + return _G.CALLED + end) vim.lsp.codelens.run() - vim.wait(100, function () return cmd_called end) + vim.wait(100, function() + return cmd_called + end) return cmd_called - ]=]) + end) eq({ command = 'Dummy', title = 'Lens2' }, response) elseif ctx.method == 'shutdown' then client.stop() @@ -4452,79 +4477,73 @@ describe('LSP', function() exec_lua(create_server_definition) -- setup lsp - exec_lua( - [[ - local lens_title_per_fake_uri = ... - local server = _create_server({ - capabilities = { - codeLensProvider = { - resolveProvider = true - }, + exec_lua(function(lens_title_per_fake_uri0) + local server = _G._create_server({ + capabilities = { + codeLensProvider = { + resolveProvider = true, }, - handlers = { - ["textDocument/codeLens"] = function(method, params, callback) - local lenses = { - { - range = { - start = { line = 0, character = 0 }, - ['end'] = { line = 0, character = 0 }, - }, - command = { - title = lens_title_per_fake_uri[params.textDocument.uri], - command = 'Dummy', - }, + }, + handlers = { + ['textDocument/codeLens'] = function(_, params, callback) + local lenses = { + { + range = { + start = { line = 0, character = 0 }, + ['end'] = { line = 0, character = 0 }, }, - } - callback(nil, lenses) - end, - } - }) + command = { + title = lens_title_per_fake_uri0[params.textDocument.uri], + command = 'Dummy', + }, + }, + } + callback(nil, lenses) + end, + }, + }) - CLIENT_ID = vim.lsp.start({ - name = "dummy", - cmd = server.cmd, - }) - ]], - lens_title_per_fake_uri - ) + _G.CLIENT_ID = vim.lsp.start({ + name = 'dummy', + cmd = server.cmd, + }) + end, lens_title_per_fake_uri) -- create buffers and setup handler - exec_lua( - [[ - local lens_title_per_fake_uri = ... - local default_buf = vim.api.nvim_get_current_buf() - for fake_uri, _ in pairs(lens_title_per_fake_uri) do - local bufnr = vim.uri_to_bufnr(fake_uri) - vim.api.nvim_set_current_buf(bufnr) - vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {'Some contents'}) - vim.lsp.buf_attach_client(bufnr, CLIENT_ID) - end - vim.api.nvim_buf_delete(default_buf, {force = true}) - - REQUEST_COUNT = vim.tbl_count(lens_title_per_fake_uri) - RESPONSES = {} - local on_codelens = vim.lsp.codelens.on_codelens - vim.lsp.codelens.on_codelens = function (err, result, ctx, ...) - table.insert(RESPONSES, { err = err, result = result, ctx = ctx }) - return on_codelens(err, result, ctx, ...) - end - ]], - lens_title_per_fake_uri - ) + exec_lua(function(lens_title_per_fake_uri0) + local default_buf = vim.api.nvim_get_current_buf() + for fake_uri, _ in pairs(lens_title_per_fake_uri0) do + local bufnr = vim.uri_to_bufnr(fake_uri) + vim.api.nvim_set_current_buf(bufnr) + vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { 'Some contents' }) + vim.lsp.buf_attach_client(bufnr, _G.CLIENT_ID) + end + vim.api.nvim_buf_delete(default_buf, { force = true }) + + _G.REQUEST_COUNT = vim.tbl_count(lens_title_per_fake_uri0) + _G.RESPONSES = {} + local on_codelens = vim.lsp.codelens.on_codelens + vim.lsp.codelens.on_codelens = function(err, result, ctx, ...) + table.insert(_G.RESPONSES, { err = err, result = result, ctx = ctx }) + return on_codelens(err, result, ctx, ...) + end + end, lens_title_per_fake_uri) -- call codelens refresh - local cmds = exec_lua([[ - RESPONSES = {} + local cmds = exec_lua(function() + _G.RESPONSES = {} vim.lsp.codelens.refresh() - vim.wait(100, function () return #RESPONSES >= REQUEST_COUNT end) + vim.wait(100, function() + return #_G.RESPONSES >= _G.REQUEST_COUNT + end) local cmds = {} - for _, resp in ipairs(RESPONSES) do + for _, resp in ipairs(_G.RESPONSES) do local uri = resp.ctx.params.textDocument.uri cmds[uri] = resp.result[1].command end return cmds - ]]) + end) eq({ command = 'Dummy', title = 'Lens1' }, cmds['file:///fake/uri1']) eq({ command = 'Dummy', title = 'Lens2' }, cmds['file:///fake/uri2']) end) @@ -4539,18 +4558,18 @@ describe('LSP', function() client = c end, on_handler = function() - local notify_msg = exec_lua([[ + local notify_msg = exec_lua(function() local bufnr = vim.api.nvim_get_current_buf() - vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID) + vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID) local notify_msg local notify = vim.notify - vim.notify = function(msg, log_level) + vim.notify = function(msg, _) notify_msg = msg end vim.lsp.buf.format({ name = 'does-not-exist' }) vim.notify = notify return notify_msg - ]]) + end) eq('[LSP] Format request failed, no matching language servers.', notify_msg) client.stop() end, @@ -4570,18 +4589,18 @@ describe('LSP', function() on_handler = function(_, _, ctx) table.remove(expected_handlers) if ctx.method == 'start' then - local notify_msg = exec_lua([[ + local notify_msg = exec_lua(function() local bufnr = vim.api.nvim_get_current_buf() - vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID) + vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID) local notify_msg local notify = vim.notify - vim.notify = function(msg, log_level) + vim.notify = function(msg, _) notify_msg = msg end vim.lsp.buf.format({ bufnr = bufnr }) vim.notify = notify return notify_msg - ]]) + end) eq(NIL, notify_msg) elseif ctx.method == 'shutdown' then client.stop() @@ -4603,22 +4622,25 @@ describe('LSP', function() on_handler = function(_, _, ctx) table.remove(expected_handlers) if ctx.method == 'start' then - local notify_msg = exec_lua([[ + local notify_msg = exec_lua(function() local bufnr = vim.api.nvim_get_current_buf() - vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, {'foo', 'bar'}) - vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID) + vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, { 'foo', 'bar' }) + vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID) local notify_msg local notify = vim.notify - vim.notify = function(msg, log_level) + vim.notify = function(msg, _) notify_msg = msg end - vim.lsp.buf.format({ bufnr = bufnr, range = { - start = {1, 1}, - ['end'] = {1, 1}, - }}) + vim.lsp.buf.format({ + bufnr = bufnr, + range = { + start = { 1, 1 }, + ['end'] = { 1, 1 }, + }, + }) vim.notify = notify return notify_msg - ]]) + end) eq(NIL, notify_msg) elseif ctx.method == 'shutdown' then client.stop() @@ -4640,28 +4662,31 @@ describe('LSP', function() on_handler = function(_, _, ctx) table.remove(expected_handlers) if ctx.method == 'start' then - local notify_msg = exec_lua([[ + local notify_msg = exec_lua(function() local bufnr = vim.api.nvim_get_current_buf() - vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, {'foo', 'bar', 'baz'}) - vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID) + vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, { 'foo', 'bar', 'baz' }) + vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID) local notify_msg local notify = vim.notify - vim.notify = function(msg, log_level) + vim.notify = function(msg, _) notify_msg = msg end - vim.lsp.buf.format({ bufnr = bufnr, range = { - { - start = {1, 1}, - ['end'] = {1, 1}, + vim.lsp.buf.format({ + bufnr = bufnr, + range = { + { + start = { 1, 1 }, + ['end'] = { 1, 1 }, + }, + { + start = { 2, 2 }, + ['end'] = { 2, 2 }, + }, }, - { - start = {2, 2}, - ['end'] = {2, 2}, - } - }}) + }) vim.notify = notify return notify_msg - ]]) + end) eq(NIL, notify_msg) elseif ctx.method == 'shutdown' then client.stop() @@ -4683,29 +4708,31 @@ describe('LSP', function() on_handler = function(_, _, ctx) table.remove(expected_handlers) if ctx.method == 'start' then - local result = exec_lua([[ + local result = exec_lua(function() local bufnr = vim.api.nvim_get_current_buf() - vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID) + vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID) local notify_msg local notify = vim.notify - vim.notify = function(msg, log_level) + vim.notify = function(msg, _) notify_msg = msg end local handler = vim.lsp.handlers['textDocument/formatting'] local handler_called = false - vim.lsp.handlers['textDocument/formatting'] = function(...) + vim.lsp.handlers['textDocument/formatting'] = function() handler_called = true end vim.lsp.buf.format({ bufnr = bufnr, async = true }) - vim.wait(1000, function() return handler_called end) + vim.wait(1000, function() + return handler_called + end) vim.notify = notify vim.lsp.handlers['textDocument/formatting'] = handler - return {notify = notify_msg, handler_called = handler_called} - ]]) + return { notify = notify_msg, handler_called = handler_called } + end) eq({ handler_called = true }, result) elseif ctx.method == 'shutdown' then client.stop() @@ -4715,22 +4742,24 @@ describe('LSP', function() end) it('format formats range in visual mode', function() exec_lua(create_server_definition) - local result = exec_lua([[ - local server = _create_server({ capabilities = { - documentFormattingProvider = true, - documentRangeFormattingProvider = true, - }}) + local result = exec_lua(function() + local server = _G._create_server({ + capabilities = { + documentFormattingProvider = true, + documentRangeFormattingProvider = true, + }, + }) local bufnr = vim.api.nvim_get_current_buf() local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) vim.api.nvim_win_set_buf(0, bufnr) - vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, {'foo', 'bar'}) + vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, { 'foo', 'bar' }) vim.api.nvim_win_set_cursor(0, { 1, 0 }) vim.cmd.normal('v') vim.api.nvim_win_set_cursor(0, { 2, 3 }) vim.lsp.buf.format({ bufnr = bufnr, false }) vim.lsp.stop_client(client_id) return server.messages - ]]) + end) eq('textDocument/rangeFormatting', result[3].method) local expected_range = { start = { line = 0, character = 0 }, @@ -4740,15 +4769,17 @@ describe('LSP', function() end) it('format formats range in visual line mode', function() exec_lua(create_server_definition) - local result = exec_lua([[ - local server = _create_server({ capabilities = { - documentFormattingProvider = true, - documentRangeFormattingProvider = true, - }}) + local result = exec_lua(function() + local server = _G._create_server({ + capabilities = { + documentFormattingProvider = true, + documentRangeFormattingProvider = true, + }, + }) local bufnr = vim.api.nvim_get_current_buf() local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) vim.api.nvim_win_set_buf(0, bufnr) - vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, {'foo', 'bar baz'}) + vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, { 'foo', 'bar baz' }) vim.api.nvim_win_set_cursor(0, { 1, 2 }) vim.cmd.normal('V') vim.api.nvim_win_set_cursor(0, { 2, 1 }) @@ -4756,7 +4787,7 @@ describe('LSP', function() -- Format again with visual lines going from bottom to top -- Must result in same formatting - vim.cmd.normal("") + vim.cmd.normal('') vim.api.nvim_win_set_cursor(0, { 2, 1 }) vim.cmd.normal('V') vim.api.nvim_win_set_cursor(0, { 1, 2 }) @@ -4764,7 +4795,7 @@ describe('LSP', function() vim.lsp.stop_client(client_id) return server.messages - ]]) + end) local expected_methods = { 'initialize', 'initialized', @@ -4791,37 +4822,43 @@ describe('LSP', function() end) it('Aborts with notify if no clients support requested method', function() exec_lua(create_server_definition) - exec_lua([[ + exec_lua(function() vim.notify = function(msg, _) - notify_msg = msg + _G.notify_msg = msg end - ]]) + end) local fail_msg = '[LSP] Format request failed, no matching language servers.' --- @param name string --- @param formatting boolean --- @param range_formatting boolean local function check_notify(name, formatting, range_formatting) local timeout_msg = '[LSP][' .. name .. '] timeout' - exec_lua( - [[ - local formatting, range_formatting, name = ... - local server = _create_server({ capabilities = { - documentFormattingProvider = formatting, - documentRangeFormattingProvider = range_formatting, - }}) - vim.lsp.start({ name = name, cmd = server.cmd }) - notify_msg = nil - vim.lsp.buf.format({ name = name, timeout_ms = 1 }) - ]], - formatting, - range_formatting, - name - ) + exec_lua(function(formatting0, range_formatting0, name0) + local server = _G._create_server({ + capabilities = { + documentFormattingProvider = formatting0, + documentRangeFormattingProvider = range_formatting0, + }, + }) + vim.lsp.start({ name = name0, cmd = server.cmd }) + _G.notify_msg = nil + vim.lsp.buf.format({ name = name0, timeout_ms = 1 }) + end, formatting, range_formatting, name) eq(formatting and timeout_msg or fail_msg, exec_lua('return notify_msg')) - exec_lua([[ - notify_msg = nil - vim.lsp.buf.format({ name = name, timeout_ms = 1, range = {start={1, 0}, ['end']={1, 0}}}) - ]]) + exec_lua(function() + _G.notify_msg = nil + vim.lsp.buf.format({ + name = name, + timeout_ms = 1, + range = { + start = { 1, 0 }, + ['end'] = { + 1, + 0, + }, + }, + }) + end) eq(range_formatting and timeout_msg or fail_msg, exec_lua('return notify_msg')) end check_notify('none', false, false) @@ -4852,10 +4889,9 @@ describe('LSP', function() }, } exec_lua(create_server_definition) - exec_lua( - [[ - _G.mock_locations = ... - _G.server = _create_server({ + exec_lua(function(mock_locations0) + _G.mock_locations = mock_locations0 + _G.server = _G._create_server({ ---@type lsp.ServerCapabilities capabilities = { definitionProvider = true, @@ -4879,26 +4915,24 @@ describe('LSP', function() name = 'vim.foobar', kind = 12, ---@type lsp.SymbolKind location = _G.mock_locations[2], - } + }, }) end, }, }) - _G.client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) - ]], - mock_locations - ) + _G.client_id = vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd }) + end, mock_locations) end) after_each(function() - exec_lua [[ + exec_lua(function() vim.lsp.stop_client(_G.client_id) - ]] + end) end) it('with flags=c, returns matching tags using textDocument/definition', function() - local result = exec_lua [[ + local result = exec_lua(function() return vim.lsp.tagfunc('foobar', 'c') - ]] + end) eq({ { cmd = '/\\%6l\\%1c/', -- for location (5, 23) @@ -4909,9 +4943,9 @@ describe('LSP', function() end) it('without flags=c, returns all matching tags using workspace/symbol', function() - local result = exec_lua [[ + local result = exec_lua(function() return vim.lsp.tagfunc('foobar', '') - ]] + end) eq({ { cmd = '/\\%6l\\%1c/', -- for location (5, 23) @@ -4931,7 +4965,7 @@ describe('LSP', function() describe('cmd', function() it('can connect to lsp server via rpc.connect', function() - local result = exec_lua [[ + local result = exec_lua(function() local uv = vim.uv local server = uv.new_tcp() local init = nil @@ -4947,12 +4981,14 @@ describe('LSP', function() end) local port = server:getsockname().port vim.lsp.start({ name = 'dummy', cmd = vim.lsp.rpc.connect('127.0.0.1', port) }) - vim.wait(1000, function() return init ~= nil end) - assert(init, "server must receive `initialize` request") + vim.wait(1000, function() + return init ~= nil + end) + assert(init, 'server must receive `initialize` request') server:close() server:shutdown() return vim.json.decode(init) - ]] + end) eq('initialize', result.method) end) it('can connect to lsp server via pipe or domain_socket', function() @@ -4963,39 +4999,37 @@ describe('LSP', function() tmpfile = tmpname() os.remove(tmpfile) end - local result = exec_lua( - [[ - local SOCK = ... + local result = exec_lua(function(SOCK) local uv = vim.uv local server = uv.new_pipe(false) server:bind(SOCK) local init = nil server:listen(127, function(err) - assert(not err, err) - local client = uv.new_pipe() - server:accept(client) - client:read_start(require("vim.lsp.rpc").create_read_loop(function(body) - init = body - client:close() - end)) + assert(not err, err) + local client = uv.new_pipe() + server:accept(client) + client:read_start(require('vim.lsp.rpc').create_read_loop(function(body) + init = body + client:close() + end)) end) - vim.lsp.start({ name = "dummy", cmd = vim.lsp.rpc.connect(SOCK) }) - vim.wait(1000, function() return init ~= nil end) - assert(init, "server must receive `initialize` request") + vim.lsp.start({ name = 'dummy', cmd = vim.lsp.rpc.connect(SOCK) }) + vim.wait(1000, function() + return init ~= nil + end) + assert(init, 'server must receive `initialize` request') server:close() server:shutdown() return vim.json.decode(init) - ]], - tmpfile - ) + end, tmpfile) eq('initialize', result.method) end) end) describe('handlers', function() it('handler can return false as response', function() - local result = exec_lua [[ + local result = exec_lua(function() local uv = vim.uv local server = uv.new_tcp() local messages = {} @@ -5014,10 +5048,10 @@ describe('LSP', function() id = payload.id, jsonrpc = '2.0', result = { - capabilities = {} + capabilities = {}, }, }) - socket:write(table.concat({'Content-Length: ', tostring(#msg), '\r\n\r\n', msg})) + socket:write(table.concat({ 'Content-Length: ', tostring(#msg), '\r\n\r\n', msg })) elseif payload.method == 'initialized' then local msg = vim.json.encode({ id = 10, @@ -5025,7 +5059,7 @@ describe('LSP', function() method = 'dummy', params = {}, }) - socket:write(table.concat({'Content-Length: ', tostring(#msg), '\r\n\r\n', msg})) + socket:write(table.concat({ 'Content-Length: ', tostring(#msg), '\r\n\r\n', msg })) end else table.insert(responses, payload) @@ -5035,20 +5069,24 @@ describe('LSP', function() end) local port = server:getsockname().port local handler_called = false - vim.lsp.handlers['dummy'] = function(err, result) + vim.lsp.handlers['dummy'] = function(_, _) handler_called = true return false end - local client_id = vim.lsp.start({ name = 'dummy', cmd = vim.lsp.rpc.connect('127.0.0.1', port) }) - local client = vim.lsp.get_client_by_id(client_id) - vim.wait(1000, function() return #messages == 2 and handler_called and #responses == 1 end) + local client_id = + vim.lsp.start({ name = 'dummy', cmd = vim.lsp.rpc.connect('127.0.0.1', port) }) + vim.lsp.get_client_by_id(client_id) + vim.wait(1000, function() + return #messages == 2 and handler_called and #responses == 1 + end) server:close() server:shutdown() return { messages = messages, handler_called = handler_called, - responses = responses } - ]] + responses = responses, + } + end) local expected = { messages = { 'initialize', 'initialized' }, handler_called = true, @@ -5077,17 +5115,14 @@ describe('LSP', function() end exec_lua(create_server_definition) - local result = exec_lua( - [[ - local root_dir, tmpfile = ... - - local server = _create_server() + local result = exec_lua(function(root_dir0, tmpfile0) + local server = _G._create_server() local client_id = vim.lsp.start({ name = 'dynamic-test', cmd = server.cmd, - root_dir = root_dir, + root_dir = root_dir0, get_language_id = function() - return "dummy-lang" + return 'dummy-lang' end, capabilities = { textDocument = { @@ -5101,17 +5136,17 @@ describe('LSP', function() }, }) - local expected_messages = 2 -- initialize, initialized - vim.lsp.handlers['client/registerCapability'](nil, { registrations = { { id = 'formatting', method = 'textDocument/formatting', registerOptions = { - documentSelector = {{ - pattern = root_dir .. '/*.foo', - }}, + documentSelector = { + { + pattern = root_dir0 .. '/*.foo', + }, + }, }, }, }, @@ -5123,12 +5158,12 @@ describe('LSP', function() id = 'range-formatting', method = 'textDocument/rangeFormatting', registerOptions = { - documentSelector = { + documentSelector = { { - language = "dummy-lang" + language = 'dummy-lang', }, - } - } + }, + }, }, }, }, { client_id = client_id }) @@ -5149,22 +5184,18 @@ describe('LSP', function() result[#result + 1] = { method = method, fname = fname, - supported = client.supports_method(method, {bufnr = bufnr}) + supported = client.supports_method(method, { bufnr = bufnr }), } end - - check("textDocument/formatting") - check("textDocument/formatting", tmpfile) - check("textDocument/rangeFormatting") - check("textDocument/rangeFormatting", tmpfile) - check("textDocument/completion") + check('textDocument/formatting') + check('textDocument/formatting', tmpfile0) + check('textDocument/rangeFormatting') + check('textDocument/rangeFormatting', tmpfile0) + check('textDocument/completion') return result - ]], - root_dir, - tmpfile - ) + end, root_dir, tmpfile) eq(5, #result) eq({ method = 'textDocument/formatting', supported = false }, result[1]) @@ -5207,82 +5238,76 @@ describe('LSP', function() mkdir(root_dir) exec_lua(create_server_definition) - local result = exec_lua( - [[ - local root_dir, watchfunc = ... - - local server = _create_server() - local client_id = vim.lsp.start({ - name = 'watchfiles-test', - cmd = server.cmd, - root_dir = root_dir, - capabilities = { - workspace = { - didChangeWatchedFiles = { - dynamicRegistration = true, + local result = exec_lua(function(root_dir0, watchfunc0) + local server = _G._create_server() + local client_id = vim.lsp.start({ + name = 'watchfiles-test', + cmd = server.cmd, + root_dir = root_dir0, + capabilities = { + workspace = { + didChangeWatchedFiles = { + dynamicRegistration = true, + }, }, }, - }, - }) + }) - require('vim.lsp._watchfiles')._watchfunc = require('vim._watch')[watchfunc] + require('vim.lsp._watchfiles')._watchfunc = require('vim._watch')[watchfunc0] - local expected_messages = 0 + local expected_messages = 0 - local msg_wait_timeout = watchfunc == 'watch' and 200 or 2500 + local msg_wait_timeout = watchfunc0 == 'watch' and 200 or 2500 - local function wait_for_message(incr) - expected_messages = expected_messages + (incr or 1) - assert( - vim.wait(msg_wait_timeout, function() - return #server.messages == expected_messages - end), - 'Timed out waiting for expected number of messages. Current messages seen so far: ' - .. vim.inspect(server.messages) - ) - end + local function wait_for_message(incr) + expected_messages = expected_messages + (incr or 1) + assert( + vim.wait(msg_wait_timeout, function() + return #server.messages == expected_messages + end), + 'Timed out waiting for expected number of messages. Current messages seen so far: ' + .. vim.inspect(server.messages) + ) + end - wait_for_message(2) -- initialize, initialized + wait_for_message(2) -- initialize, initialized - vim.lsp.handlers['client/registerCapability'](nil, { - registrations = { - { - id = 'watchfiles-test-0', - method = 'workspace/didChangeWatchedFiles', - registerOptions = { - watchers = { - { - globPattern = '**/watch', - kind = 7, + vim.lsp.handlers['client/registerCapability'](nil, { + registrations = { + { + id = 'watchfiles-test-0', + method = 'workspace/didChangeWatchedFiles', + registerOptions = { + watchers = { + { + globPattern = '**/watch', + kind = 7, + }, }, }, }, }, - }, - }, { client_id = client_id }) + }, { client_id = client_id }) - if watchfunc ~= 'watch' then - vim.wait(100) - end + if watchfunc0 ~= 'watch' then + vim.wait(100) + end - local path = root_dir .. '/watch' - local tmp = vim.fn.tempname() - io.open(tmp, 'w'):close() - vim.uv.fs_rename(tmp, path) + local path = root_dir0 .. '/watch' + local tmp = vim.fn.tempname() + io.open(tmp, 'w'):close() + vim.uv.fs_rename(tmp, path) - wait_for_message() + wait_for_message() - os.remove(path) + os.remove(path) - wait_for_message() + wait_for_message() - vim.lsp.stop_client(client_id) + vim.lsp.stop_client(client_id) - return server.messages - ]], - root_dir, - watchfunc - ) + return server.messages + end, root_dir, watchfunc) local uri = vim.uri_from_fname(root_dir .. '/watch') @@ -5322,15 +5347,12 @@ describe('LSP', function() it('correctly registers and unregisters', function() local root_dir = '/some_dir' exec_lua(create_server_definition) - local result = exec_lua( - [[ - local root_dir = ... - - local server = _create_server() + local result = exec_lua(function(root_dir0) + local server = _G._create_server() local client_id = vim.lsp.start({ name = 'watchfiles-test', cmd = server.cmd, - root_dir = root_dir, + root_dir = root_dir0, capabilities = { workspace = { didChangeWatchedFiles = { @@ -5342,7 +5364,13 @@ describe('LSP', function() local expected_messages = 2 -- initialize, initialized local function wait_for_messages() - assert(vim.wait(200, function() return #server.messages == expected_messages end), 'Timed out waiting for expected number of messages. Current messages seen so far: ' .. vim.inspect(server.messages)) + assert( + vim.wait(200, function() + return #server.messages == expected_messages + end), + 'Timed out waiting for expected number of messages. Current messages seen so far: ' + .. vim.inspect(server.messages) + ) end wait_for_messages() @@ -5376,8 +5404,8 @@ describe('LSP', function() }, }, { client_id = client_id }) - send_event(root_dir .. '/file.watch0', vim._watch.FileChangeType.Created) - send_event(root_dir .. '/file.watch1', vim._watch.FileChangeType.Created) + send_event(root_dir0 .. '/file.watch0', vim._watch.FileChangeType.Created) + send_event(root_dir0 .. '/file.watch1', vim._watch.FileChangeType.Created) expected_messages = expected_messages + 1 wait_for_messages() @@ -5407,16 +5435,14 @@ describe('LSP', function() }, }, { client_id = client_id }) - send_event(root_dir .. '/file.watch0', vim._watch.FileChangeType.Created) - send_event(root_dir .. '/file.watch1', vim._watch.FileChangeType.Created) + send_event(root_dir0 .. '/file.watch0', vim._watch.FileChangeType.Created) + send_event(root_dir0 .. '/file.watch1', vim._watch.FileChangeType.Created) expected_messages = expected_messages + 1 wait_for_messages() return server.messages - ]], - root_dir - ) + end, root_dir) local function watched_uri(fname) return vim.uri_from_fname(root_dir .. '/' .. fname) @@ -5446,15 +5472,12 @@ describe('LSP', function() it('correctly handles the registered watch kind', function() local root_dir = 'some_dir' exec_lua(create_server_definition) - local result = exec_lua( - [[ - local root_dir = ... - - local server = _create_server() + local result = exec_lua(function(root_dir0) + local server = _G._create_server() local client_id = vim.lsp.start({ name = 'watchfiles-test', cmd = server.cmd, - root_dir = root_dir, + root_dir = root_dir0, capabilities = { workspace = { didChangeWatchedFiles = { @@ -5466,7 +5489,13 @@ describe('LSP', function() local expected_messages = 2 -- initialize, initialized local function wait_for_messages() - assert(vim.wait(200, function() return #server.messages == expected_messages end), 'Timed out waiting for expected number of messages. Current messages seen so far: ' .. vim.inspect(server.messages)) + assert( + vim.wait(200, function() + return #server.messages == expected_messages + end), + 'Timed out waiting for expected number of messages. Current messages seen so far: ' + .. vim.inspect(server.messages) + ) end wait_for_messages() @@ -5487,12 +5516,14 @@ describe('LSP', function() local protocol = require('vim.lsp.protocol') local watchers = {} - local max_kind = protocol.WatchKind.Create + protocol.WatchKind.Change + protocol.WatchKind.Delete + local max_kind = protocol.WatchKind.Create + + protocol.WatchKind.Change + + protocol.WatchKind.Delete for i = 0, max_kind do table.insert(watchers, { globPattern = { baseUri = vim.uri_from_fname('/dir'), - pattern = 'watch'..tostring(i), + pattern = 'watch' .. tostring(i), }, kind = i, }) @@ -5520,9 +5551,7 @@ describe('LSP', function() wait_for_messages() return server.messages - ]], - root_dir - ) + end, root_dir) local function watched_uri(fname) return vim.uri_from_fname('/dir/' .. fname) @@ -5587,15 +5616,12 @@ describe('LSP', function() it('prunes duplicate events', function() local root_dir = 'some_dir' exec_lua(create_server_definition) - local result = exec_lua( - [[ - local root_dir = ... - - local server = _create_server() + local result = exec_lua(function(root_dir0) + local server = _G._create_server() local client_id = vim.lsp.start({ name = 'watchfiles-test', cmd = server.cmd, - root_dir = root_dir, + root_dir = root_dir0, capabilities = { workspace = { didChangeWatchedFiles = { @@ -5607,7 +5633,13 @@ describe('LSP', function() local expected_messages = 2 -- initialize, initialized local function wait_for_messages() - assert(vim.wait(200, function() return #server.messages == expected_messages end), 'Timed out waiting for expected number of messages. Current messages seen so far: ' .. vim.inspect(server.messages)) + assert( + vim.wait(200, function() + return #server.messages == expected_messages + end), + 'Timed out waiting for expected number of messages. Current messages seen so far: ' + .. vim.inspect(server.messages) + ) end wait_for_messages() @@ -5646,9 +5678,7 @@ describe('LSP', function() wait_for_messages() return server.messages - ]], - root_dir - ) + end, root_dir) eq(3, #result) eq('workspace/didChangeWatchedFiles', result[3].method) @@ -5672,26 +5702,27 @@ describe('LSP', function() it("ignores registrations by servers when the client doesn't advertise support", function() exec_lua(create_server_definition) - exec_lua([[ - server = _create_server() - require('vim.lsp._watchfiles')._watchfunc = function(_, _, callback) + exec_lua(function() + _G.server = _G._create_server() + require('vim.lsp._watchfiles')._watchfunc = function(_, _, _) -- Since the registration is ignored, this should not execute and `watching` should stay false - watching = true + _G.watching = true return function() end end - ]]) + end) local function check_registered(capabilities) - return exec_lua( - [[ - watching = false + return exec_lua(function(capabilities0) + _G.watching = false local client_id = vim.lsp.start({ name = 'watchfiles-test', - cmd = server.cmd, + cmd = _G.server.cmd, root_dir = 'some_dir', - capabilities = ..., + capabilities = capabilities0, }, { - reuse_client = function() return false end, + reuse_client = function() + return false + end, }) vim.lsp.handlers['client/registerCapability'](nil, { @@ -5721,10 +5752,8 @@ describe('LSP', function() }, { client_id = client_id }) vim.lsp.stop_client(client_id, true) - return watching - ]], - capabilities - ) + return _G.watching + end, capabilities) end eq(is_os('mac') or is_os('win'), check_registered(nil)) -- start{_client}() defaults to make_client_capabilities(). diff --git a/test/functional/treesitter/fold_spec.lua b/test/functional/treesitter/fold_spec.lua index 3e81cebe71..24b085920c 100644 --- a/test/functional/treesitter/fold_spec.lua +++ b/test/functional/treesitter/fold_spec.lua @@ -48,13 +48,13 @@ void ui_refresh(void) end local function get_fold_levels() - return exec_lua([[ - local res = {} - for i = 1, vim.api.nvim_buf_line_count(0) do - res[i] = vim.treesitter.foldexpr(i) - end - return res - ]]) + return exec_lua(function() + local res = {} + for i = 1, vim.api.nvim_buf_line_count(0) do + res[i] = vim.treesitter.foldexpr(i) + end + return res + end) end it('can compute fold levels', function() @@ -246,9 +246,13 @@ function f() end -- comment]]) - exec_lua( - [[vim.treesitter.query.set('lua', 'folds', '[(function_declaration) (parameters) (arguments)] @fold')]] - ) + exec_lua(function() + vim.treesitter.query.set( + 'lua', + 'folds', + '[(function_declaration) (parameters) (arguments)] @fold' + ) + end) parse('lua') eq({ @@ -290,9 +294,13 @@ function f() ) end]]) - exec_lua( - [[vim.treesitter.query.set('lua', 'folds', '[(function_declaration) (function_definition) (parameters) (arguments)] @fold')]] - ) + exec_lua(function() + vim.treesitter.query.set( + 'lua', + 'folds', + '[(function_declaration) (function_definition) (parameters) (arguments)] @fold' + ) + end) parse('lua') -- If fold1.stop = fold2.start, then move fold1's stop up so that fold2.start gets proper level. @@ -333,9 +341,13 @@ function f(a) end end]]) - exec_lua( - [[vim.treesitter.query.set('lua', 'folds', '[(if_statement) (function_declaration) (parameters) (arguments) (table_constructor)] @fold')]] - ) + exec_lua(function() + vim.treesitter.query.set( + 'lua', + 'folds', + '[(if_statement) (function_declaration) (parameters) (arguments) (table_constructor)] @fold' + ) + end) parse('lua') eq({ diff --git a/test/functional/treesitter/highlight_spec.lua b/test/functional/treesitter/highlight_spec.lua index b0ac180738..da001e2ab1 100644 --- a/test/functional/treesitter/highlight_spec.lua +++ b/test/functional/treesitter/highlight_spec.lua @@ -156,7 +156,7 @@ local injection_grid_expected_c = [[ ]] describe('treesitter highlighting (C)', function() - local screen + local screen --- @type test.functional.ui.screen before_each(function() clear() @@ -176,7 +176,6 @@ describe('treesitter highlighting (C)', function() [11] = { foreground = Screen.colors.Cyan4 }, } - exec_lua([[ hl_query = ... ]], hl_query_c) command [[ hi link @error ErrorMsg ]] command [[ hi link @warning WarningMsg ]] end) @@ -188,22 +187,28 @@ describe('treesitter highlighting (C)', function() -- legacy syntax highlighting is used by default screen:expect(hl_grid_legacy_c) - exec_lua([[ + exec_lua(function(hl_query) vim.treesitter.query.set('c', 'highlights', hl_query) vim.treesitter.start() - ]]) + end, hl_query_c) -- treesitter highlighting is used screen:expect(hl_grid_ts_c) - exec_lua('vim.treesitter.stop()') + exec_lua(function() + vim.treesitter.stop() + end) -- legacy syntax highlighting is used screen:expect(hl_grid_legacy_c) - exec_lua('vim.treesitter.start()') + exec_lua(function() + vim.treesitter.start() + end) -- treesitter highlighting is used screen:expect(hl_grid_ts_c) - exec_lua('vim.treesitter.stop()') + exec_lua(function() + vim.treesitter.stop() + end) -- legacy syntax highlighting is used screen:expect(hl_grid_legacy_c) end) @@ -233,11 +238,11 @@ describe('treesitter highlighting (C)', function() ]], } - exec_lua [[ - local parser = vim.treesitter.get_parser(0, "c") + exec_lua(function(hl_query) + local parser = vim.treesitter.get_parser(0, 'c') local highlighter = vim.treesitter.highlighter - test_hl = highlighter.new(parser, {queries = {c = hl_query}}) - ]] + highlighter.new(parser, { queries = { c = hl_query } }) + end, hl_query_c) screen:expect(hl_grid_ts_c) feed('5Gocdd') @@ -364,10 +369,10 @@ describe('treesitter highlighting (C)', function() it('is updated with :sort', function() insert(test_text_c) - exec_lua [[ - local parser = vim.treesitter.get_parser(0, "c") - test_hl = vim.treesitter.highlighter.new(parser, {queries = {c = hl_query}}) - ]] + exec_lua(function(hl_query) + local parser = vim.treesitter.get_parser(0, 'c') + vim.treesitter.highlighter.new(parser, { queries = { c = hl_query } }) + end, hl_query_c) screen:expect { grid = [[ {3:int} width = {5:INT_MAX}, height = {5:INT_MAX}; | @@ -470,19 +475,19 @@ describe('treesitter highlighting (C)', function() ]], } - exec_lua [[ - parser = vim.treesitter.get_parser(0, "c") - query = vim.treesitter.query.parse("c", "(declaration) @decl") + exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c') + local query = vim.treesitter.query.parse('c', '(declaration) @decl') local nodes = {} for _, node in query:iter_captures(parser:parse()[1]:root(), 0, 0, 19) do table.insert(nodes, node) end - parser:set_included_regions({nodes}) + parser:set_included_regions({ nodes }) - local hl = vim.treesitter.highlighter.new(parser, {queries = {c = "(identifier) @type"}}) - ]] + vim.treesitter.highlighter.new(parser, { queries = { c = '(identifier) @type' } }) + end) screen:expect { grid = [[ @@ -513,13 +518,15 @@ describe('treesitter highlighting (C)', function() screen:expect { grid = injection_grid_c } - exec_lua [[ - local parser = vim.treesitter.get_parser(0, "c", { - injections = {c = '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c")) (preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))'} + exec_lua(function(hl_query) + local parser = vim.treesitter.get_parser(0, 'c', { + injections = { + c = '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c")) (preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))', + }, }) local highlighter = vim.treesitter.highlighter - test_hl = highlighter.new(parser, {queries = {c = hl_query}}) - ]] + highlighter.new(parser, { queries = { c = hl_query } }) + end, hl_query_c) screen:expect { grid = injection_grid_expected_c } end) @@ -529,14 +536,16 @@ describe('treesitter highlighting (C)', function() screen:expect { grid = injection_grid_c } - exec_lua [[ - vim.treesitter.language.register("c", "foo") - local parser = vim.treesitter.get_parser(0, "c", { - injections = {c = '(preproc_def (preproc_arg) @injection.content (#set! injection.language "foo")) (preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "foo"))'} + exec_lua(function(hl_query) + vim.treesitter.language.register('c', 'foo') + local parser = vim.treesitter.get_parser(0, 'c', { + injections = { + c = '(preproc_def (preproc_arg) @injection.content (#set! injection.language "foo")) (preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "foo"))', + }, }) local highlighter = vim.treesitter.highlighter - test_hl = highlighter.new(parser, {queries = {c = hl_query}}) - ]] + highlighter.new(parser, { queries = { c = hl_query } }) + end, hl_query_c) screen:expect { grid = injection_grid_expected_c } end) @@ -550,13 +559,14 @@ describe('treesitter highlighting (C)', function() } ]]) - exec_lua [[ - local injection_query = '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c")) (preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))' - vim.treesitter.query.set("c", "highlights", hl_query) - vim.treesitter.query.set("c", "injections", injection_query) + exec_lua(function(hl_query) + local injection_query = + '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c")) (preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))' + vim.treesitter.query.set('c', 'highlights', hl_query) + vim.treesitter.query.set('c', 'injections', injection_query) - vim.treesitter.highlighter.new(vim.treesitter.get_parser(0, "c")) - ]] + vim.treesitter.highlighter.new(vim.treesitter.get_parser(0, 'c')) + end, hl_query_c) screen:expect { grid = [[ @@ -576,10 +586,10 @@ describe('treesitter highlighting (C)', function() insert(hl_text_c) feed('gg') - exec_lua [[ - local parser = vim.treesitter.get_parser(0, "c") - test_hl = vim.treesitter.highlighter.new(parser, {queries = {c = hl_query}}) - ]] + exec_lua(function(hl_query) + local parser = vim.treesitter.get_parser(0, 'c') + vim.treesitter.highlighter.new(parser, { queries = { c = hl_query } }) + end, hl_query_c) screen:expect(hl_grid_ts_c) @@ -619,10 +629,14 @@ describe('treesitter highlighting (C)', function() } ]]) - exec_lua [[ - local parser = vim.treesitter.get_parser(0, "c") - test_hl = vim.treesitter.highlighter.new(parser, {queries = {c = hl_query..'\n((translation_unit) @constant (#set! "priority" 101))\n'}}) - ]] + exec_lua(function(hl_query) + local parser = vim.treesitter.get_parser(0, 'c') + vim.treesitter.highlighter.new(parser, { + queries = { + c = hl_query .. '\n((translation_unit) @constant (#set! "priority" 101))\n', + }, + }) + end, hl_query_c) -- expect everything to have Constant highlight screen:expect { grid = [[ @@ -669,11 +683,14 @@ describe('treesitter highlighting (C)', function() hi link @foo.bar Type hi link @foo String ]] - exec_lua [[ - local parser = vim.treesitter.get_parser(0, "c", {}) - local highlighter = vim.treesitter.highlighter - test_hl = highlighter.new(parser, {queries = {c = "(primitive_type) @foo.bar (string_literal) @foo"}}) - ]] + exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c', {}) + local highlighter = vim.treesitter.highlighter + highlighter.new( + parser, + { queries = { c = '(primitive_type) @foo.bar (string_literal) @foo' } } + ) + end) screen:expect { grid = [[ @@ -701,10 +718,12 @@ describe('treesitter highlighting (C)', function() insert(hl_text_c) -- conceal can be empty or a single cchar. - exec_lua [=[ + exec_lua(function() vim.opt.cole = 2 - local parser = vim.treesitter.get_parser(0, "c") - test_hl = vim.treesitter.highlighter.new(parser, {queries = {c = [[ + local parser = vim.treesitter.get_parser(0, 'c') + vim.treesitter.highlighter.new(parser, { + queries = { + c = [[ ("static" @keyword (#set! conceal "R")) @@ -717,8 +736,10 @@ describe('treesitter highlighting (C)', function() arguments: (argument_list) @arguments) (#eq? @function "multiqueue_put") (#set! @function conceal "V")) - ]]}}) - ]=] + ]], + }, + }) + end) screen:expect { grid = [[ @@ -775,11 +796,11 @@ describe('treesitter highlighting (C)', function() int z = 6; ]]) - exec_lua([[ + exec_lua(function() local query = '((declaration)+ @string)' vim.treesitter.query.set('c', 'highlights', query) vim.treesitter.highlighter.new(vim.treesitter.get_parser(0, 'c')) - ]]) + end) screen:expect { grid = [[ @@ -805,14 +826,10 @@ describe('treesitter highlighting (C)', function() declarator: (pointer_declarator) @variable.parameter) ]] - exec_lua( - [[ - local query = ... - vim.treesitter.query.set('c', 'highlights', query) + exec_lua(function(query_str) + vim.treesitter.query.set('c', 'highlights', query_str) vim.treesitter.highlighter.new(vim.treesitter.get_parser(0, 'c')) - ]], - query - ) + end, query) screen:expect { grid = [[ @@ -847,10 +864,10 @@ describe('treesitter highlighting (lua)', function() ffi.cdef("int (*fun)(int, char *);") ]] - exec_lua [[ + exec_lua(function() vim.bo.filetype = 'lua' vim.treesitter.start() - ]] + end) screen:expect { grid = [[ @@ -888,10 +905,10 @@ describe('treesitter highlighting (help)', function() < ]] - exec_lua [[ + exec_lua(function() vim.bo.filetype = 'help' vim.treesitter.start() - ]] + end) screen:expect { grid = [[ @@ -943,15 +960,15 @@ describe('treesitter highlighting (help)', function() ]] ]=]) - exec_lua [[ - parser = vim.treesitter.get_parser(0, "lua", { + exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'lua', { injections = { - lua = '(string content: (_) @injection.content (#set! injection.language lua))' - } + lua = '(string content: (_) @injection.content (#set! injection.language lua))', + }, }) vim.treesitter.highlighter.new(parser) - ]] + end) screen:expect { grid = [=[ @@ -967,7 +984,7 @@ describe('treesitter highlighting (help)', function() end) describe('treesitter highlighting (nested injections)', function() - local screen + local screen --- @type test.functional.ui.screen before_each(function() clear() @@ -996,11 +1013,11 @@ vim.cmd([[ ]]) ]=] - exec_lua [[ + exec_lua(function() vim.opt.scrolloff = 0 vim.bo.filetype = 'lua' vim.treesitter.start() - ]] + end) -- invalidate the language tree feed('ggi--[[04x') @@ -1041,10 +1058,10 @@ describe('treesitter highlighting (markdown)', function() clear() screen = Screen.new(40, 6) screen:attach() - exec_lua([[ + exec_lua(function() vim.bo.filetype = 'markdown' vim.treesitter.start() - ]]) + end) end) it('supports hyperlinks', function() diff --git a/test/functional/treesitter/inspect_tree_spec.lua b/test/functional/treesitter/inspect_tree_spec.lua index ef2ed8d970..6629751152 100644 --- a/test/functional/treesitter/inspect_tree_spec.lua +++ b/test/functional/treesitter/inspect_tree_spec.lua @@ -22,10 +22,10 @@ describe('vim.treesitter.inspect_tree', function() print() ]]) - exec_lua([[ + exec_lua(function() vim.treesitter.start(0, 'lua') vim.treesitter.inspect_tree() - ]]) + end) expect_tree [[ (chunk ; [0, 0] - [2, 0] @@ -40,10 +40,10 @@ describe('vim.treesitter.inspect_tree', function() print('hello') ]]) - exec_lua([[ + exec_lua(function() vim.treesitter.start(0, 'lua') vim.treesitter.inspect_tree() - ]]) + end) feed('a') expect_tree [[ @@ -67,11 +67,11 @@ describe('vim.treesitter.inspect_tree', function() ``` ]]) - exec_lua([[ + exec_lua(function() vim.treesitter.start(0, 'markdown') vim.treesitter.get_parser():parse() vim.treesitter.inspect_tree() - ]]) + end) expect_tree [[ (document ; [0, 0] - [4, 0] @@ -96,11 +96,11 @@ describe('vim.treesitter.inspect_tree', function() ``` ]]) - exec_lua([[ + exec_lua(function() vim.treesitter.start(0, 'markdown') vim.treesitter.get_parser():parse() vim.treesitter.inspect_tree() - ]]) + end) feed('I') expect_tree [[ @@ -125,28 +125,28 @@ describe('vim.treesitter.inspect_tree', function() ]]) -- setup two windows for the source buffer - exec_lua([[ - source_win = vim.api.nvim_get_current_win() + exec_lua(function() + _G.source_win = vim.api.nvim_get_current_win() vim.api.nvim_open_win(0, false, { win = 0, - split = 'left' + split = 'left', }) - ]]) + end) -- setup three windows for the tree buffer - exec_lua([[ + exec_lua(function() vim.treesitter.start(0, 'lua') vim.treesitter.inspect_tree() - tree_win = vim.api.nvim_get_current_win() - tree_win_copy_1 = vim.api.nvim_open_win(0, false, { + _G.tree_win = vim.api.nvim_get_current_win() + _G.tree_win_copy_1 = vim.api.nvim_open_win(0, false, { win = 0, - split = 'left' + split = 'left', }) - tree_win_copy_2 = vim.api.nvim_open_win(0, false, { + _G.tree_win_copy_2 = vim.api.nvim_open_win(0, false, { win = 0, - split = 'left' + split = 'left', }) - ]]) + end) -- close original source window exec_lua('vim.api.nvim_win_close(source_win, false)') diff --git a/test/functional/treesitter/language_spec.lua b/test/functional/treesitter/language_spec.lua index e71c39244f..ba2d2218e3 100644 --- a/test/functional/treesitter/language_spec.lua +++ b/test/functional/treesitter/language_spec.lua @@ -54,10 +54,10 @@ describe('treesitter language API', function() end) it('inspects language', function() - local keys, fields, symbols = unpack(exec_lua([[ + local keys, fields, symbols = unpack(exec_lua(function() local lang = vim.treesitter.language.inspect('c') local keys, symbols = {}, {} - for k,_ in pairs(lang) do + for k, _ in pairs(lang) do keys[k] = true end @@ -66,8 +66,8 @@ describe('treesitter language API', function() for _, v in pairs(lang.symbols) do table.insert(symbols, v) end - return {keys, lang.fields, symbols} - ]])) + return { keys, lang.fields, symbols } + end)) eq({ fields = true, symbols = true, _abi_version = true }, keys) @@ -113,12 +113,14 @@ describe('treesitter language API', function() int x = 3; }]]) - exec_lua([[ - langtree = vim.treesitter.get_parser(0, "c") - tree = langtree:tree_for_range({1, 3, 1, 3}) - ]]) - - eq('', exec_lua('return tostring(tree:root())')) + eq( + '', + exec_lua(function() + local langtree = vim.treesitter.get_parser(0, 'c') + local tree = langtree:tree_for_range({ 1, 3, 1, 3 }) + return tostring(tree:root()) + end) + ) end) it('retrieve the tree given a range when range is out of bounds relative to buffer', function() @@ -127,12 +129,14 @@ describe('treesitter language API', function() int x = 3; }]]) - exec_lua([[ - langtree = vim.treesitter.get_parser(0, "c") - tree = langtree:tree_for_range({10, 10, 10, 10}) - ]]) - - eq('', exec_lua('return tostring(tree:root())')) + eq( + '', + exec_lua(function() + local langtree = vim.treesitter.get_parser(0, 'c') + local tree = langtree:tree_for_range({ 10, 10, 10, 10 }) + return tostring(tree:root()) + end) + ) end) it('retrieve the node given a range', function() @@ -141,12 +145,14 @@ describe('treesitter language API', function() int x = 3; }]]) - exec_lua([[ - langtree = vim.treesitter.get_parser(0, "c") - node = langtree:named_node_for_range({1, 3, 1, 3}) - ]]) - - eq('', exec_lua('return tostring(node)')) + eq( + '', + exec_lua(function() + local langtree = vim.treesitter.get_parser(0, 'c') + local node = langtree:named_node_for_range({ 1, 3, 1, 3 }) + return tostring(node) + end) + ) end) it('retrieve an anonymous node given a range', function() diff --git a/test/functional/treesitter/node_spec.lua b/test/functional/treesitter/node_spec.lua index 6270ea3aa1..0e77c10e16 100644 --- a/test/functional/treesitter/node_spec.lua +++ b/test/functional/treesitter/node_spec.lua @@ -18,39 +18,39 @@ describe('treesitter node API', function() it('double free tree', function() insert('F') - exec_lua([[ + exec_lua(function() vim.treesitter.start(0, 'lua') vim.treesitter.get_node():tree() vim.treesitter.get_node():tree() collectgarbage() - ]]) + end) assert_alive() end) it('double free tree 2', function() - exec_lua([[ - parser = vim.treesitter.get_parser(0, "c") + exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c') local x = parser:parse()[1]:root():tree() - vim.api.nvim_buf_set_text(0, 0,0, 0,0, {'y'}) + vim.api.nvim_buf_set_text(0, 0, 0, 0, 0, { 'y' }) parser:parse() - vim.api.nvim_buf_set_text(0, 0,0, 0,1, {'z'}) + vim.api.nvim_buf_set_text(0, 0, 0, 0, 1, { 'z' }) parser:parse() collectgarbage() x:root() - ]]) + end) assert_alive() end) it('get_node() with lang given', function() -- this buffer doesn't have filetype set! insert('local foo = function() end') - exec_lua([[ - node = vim.treesitter.get_node({ + exec_lua(function() + _G.node = vim.treesitter.get_node({ bufnr = 0, - pos = { 0, 6 }, -- on "foo" + pos = { 0, 6 }, -- on "foo" lang = 'lua', }) - ]]) + end) eq('foo', lua_eval('vim.treesitter.get_node_text(node, 0)')) eq('identifier', lua_eval('node:type()')) end) @@ -79,16 +79,16 @@ describe('treesitter node API', function() } ]]) - exec_lua([[ - parser = vim.treesitter.get_parser(0, "c") - tree = parser:parse()[1] - root = tree:root() - lang = vim.treesitter.language.inspect('c') + exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c') + local tree = parser:parse()[1] + _G.root = tree:root() + vim.treesitter.language.inspect('c') - function node_text(node) + function _G.node_text(node) return vim.treesitter.get_node_text(node, 0) end - ]]) + end) exec_lua 'node = root:descendant_for_range(0, 11, 0, 16)' eq('int x', lua_eval('node_text(node)')) @@ -118,13 +118,13 @@ describe('treesitter node API', function() int x = 3; }]]) - local len = exec_lua([[ - tree = vim.treesitter.get_parser(0, "c"):parse()[1] - node = tree:root():child(0) - children = node:named_children() + local len = exec_lua(function() + local tree = vim.treesitter.get_parser(0, 'c'):parse()[1] + local node = tree:root():child(0) + _G.children = node:named_children() - return #children - ]]) + return #_G.children + end) eq(3, len) eq('', lua_eval('tostring(children[3])')) @@ -136,11 +136,11 @@ describe('treesitter node API', function() int x = 3; }]]) - exec_lua([[ - tree = vim.treesitter.get_parser(0, "c"):parse()[1] - root = tree:root() - node = root:child(0):child(2) - ]]) + exec_lua(function() + local tree = vim.treesitter.get_parser(0, 'c'):parse()[1] + _G.root = tree:root() + _G.node = _G.root:child(0):child(2) + end) eq(lua_eval('tostring(root)'), lua_eval('tostring(node:root())')) end) @@ -151,11 +151,11 @@ describe('treesitter node API', function() int x = 3; }]]) - exec_lua([[ - tree = vim.treesitter.get_parser(0, "c"):parse()[1] - root = tree:root() - child = root:child(0):child(0) - ]]) + exec_lua(function() + local tree = vim.treesitter.get_parser(0, 'c'):parse()[1] + _G.root = tree:root() + _G.child = _G.root:child(0):child(0) + end) eq(28, lua_eval('root:byte_length()')) eq(3, lua_eval('child:byte_length()')) @@ -167,15 +167,15 @@ describe('treesitter node API', function() int x = 3; }]]) - exec_lua([[ - tree = vim.treesitter.get_parser(0, "c"):parse()[1] - root = tree:root() - main = root:child(0) - body = main:child(2) - statement = body:child(1) - declarator = statement:child(1) - value = declarator:child(1) - ]]) + exec_lua(function() + local tree = vim.treesitter.get_parser(0, 'c'):parse()[1] + _G.root = tree:root() + _G.main = _G.root:child(0) + _G.body = _G.main:child(2) + _G.statement = _G.body:child(1) + _G.declarator = _G.statement:child(1) + _G.value = _G.declarator:child(1) + end) eq(lua_eval('main:type()'), lua_eval('root:child_containing_descendant(value):type()')) eq(lua_eval('body:type()'), lua_eval('main:child_containing_descendant(value):type()')) diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua index dbd6bb3c23..46e6a6002a 100644 --- a/test/functional/treesitter/parser_spec.lua +++ b/test/functional/treesitter/parser_spec.lua @@ -12,9 +12,9 @@ local feed = n.feed describe('treesitter parser API', function() before_each(function() clear() - exec_lua [[ + exec_lua(function() vim.g.__ts_debug = 1 - ]] + end) end) it('parses buffer', function() @@ -23,12 +23,12 @@ describe('treesitter parser API', function() int x = 3; }]]) - exec_lua([[ - parser = vim.treesitter.get_parser(0, "c") - tree = parser:parse()[1] - root = tree:root() - lang = vim.treesitter.language.inspect('c') - ]]) + exec_lua(function() + _G.parser = vim.treesitter.get_parser(0, 'c') + _G.tree = _G.parser:parse()[1] + _G.root = _G.tree:root() + _G.lang = vim.treesitter.language.inspect('c') + end) eq('', exec_lua('return tostring(tree)')) eq('', exec_lua('return tostring(root)')) @@ -59,11 +59,11 @@ describe('treesitter parser API', function() ) feed('2G7|ay') - exec_lua([[ - tree2 = parser:parse()[1] - root2 = tree2:root() - descendant2 = root2:descendant_for_range(1,2,1,13) - ]]) + exec_lua(function() + _G.tree2 = _G.parser:parse()[1] + _G.root2 = _G.tree2:root() + _G.descendant2 = _G.root2:descendant_for_range(1, 2, 1, 13) + end) eq(false, exec_lua('return tree2 == tree1')) eq(false, exec_lua('return root2 == root')) eq('', exec_lua('return tostring(descendant2)')) @@ -112,17 +112,17 @@ void ui_refresh(void) it('allows to iterate over nodes children', function() insert(test_text) - local res = exec_lua([[ - parser = vim.treesitter.get_parser(0, "c") + local res = exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c') - func_node = parser:parse()[1]:root():child(0) + local func_node = parser:parse()[1]:root():child(0) - res = {} + local res = {} for node, field in func_node:iter_children() do table.insert(res, { node:type(), field }) end return res - ]]) + end) eq({ { 'primitive_type', 'type' }, @@ -148,43 +148,43 @@ void ui_refresh(void) it('allows to get a child by field', function() insert(test_text) - local res = exec_lua([[ - parser = vim.treesitter.get_parser(0, "c") + local res = exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c') - func_node = parser:parse()[1]:root():child(0) + _G.func_node = parser:parse()[1]:root():child(0) local res = {} - for _, node in ipairs(func_node:field("type")) do + for _, node in ipairs(_G.func_node:field('type')) do table.insert(res, { node:type(), node:range() }) end return res - ]]) + end) eq({ { 'primitive_type', 0, 0, 0, 4 } }, res) - local res_fail = exec_lua([[ - parser = vim.treesitter.get_parser(0, "c") + local res_fail = exec_lua(function() + vim.treesitter.get_parser(0, 'c') - return #func_node:field("foo") == 0 - ]]) + return #_G.func_node:field('foo') == 0 + end) assert(res_fail) end) it('supports getting text of multiline node', function() insert(test_text) - local res = exec_lua([[ - local parser = vim.treesitter.get_parser(0, "c") + local res = exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c') local tree = parser:parse()[1] return vim.treesitter.get_node_text(tree:root(), 0) - ]]) + end) eq(test_text, res) - local res2 = exec_lua([[ - local parser = vim.treesitter.get_parser(0, "c") + local res2 = exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c') local root = parser:parse()[1]:root() return vim.treesitter.get_node_text(root:child(0):child(0), 0) - ]]) + end) eq('void', res2) end) @@ -196,7 +196,7 @@ end]] insert(text) eq( '', - exec_lua [[ + exec_lua(function() local fake_node = {} function fake_node:start() return 3, 0, 23 @@ -211,7 +211,7 @@ end]] return 3, 0, 3, 0 end return vim.treesitter.get_node_text(fake_node, 0) - ]] + end) ) end) @@ -221,7 +221,7 @@ end]] {} ```]] insert(text) - local result = exec_lua([[ + local result = exec_lua(function() local fake_node = {} function fake_node:start() return 1, 0, 7 @@ -233,38 +233,38 @@ end]] return 1, 0, 1, 0 end return vim.treesitter.get_node_text(fake_node, 0) == '' - ]]) + end) eq(true, result) end) it('allows to set simple ranges', function() insert(test_text) - local res = exec_lua [[ - parser = vim.treesitter.get_parser(0, "c") - return { parser:parse()[1]:root():range() } - ]] + local res = exec_lua(function() + _G.parser = vim.treesitter.get_parser(0, 'c') + return { _G.parser:parse()[1]:root():range() } + end) eq({ 0, 0, 19, 0 }, res) -- The following sets the included ranges for the current parser -- As stated here, this only includes the function (thus the whole buffer, without the last line) - local res2 = exec_lua [[ - local root = parser:parse()[1]:root() - parser:set_included_regions({{root:child(0)}}) - parser:invalidate() - return { parser:parse(true)[1]:root():range() } - ]] + local res2 = exec_lua(function() + local root = _G.parser:parse()[1]:root() + _G.parser:set_included_regions({ { root:child(0) } }) + _G.parser:invalidate() + return { _G.parser:parse(true)[1]:root():range() } + end) eq({ 0, 0, 18, 1 }, res2) eq({ { { 0, 0, 0, 18, 1, 512 } } }, exec_lua [[ return parser:included_regions() ]]) - local range_tbl = exec_lua [[ - parser:set_included_regions { { { 0, 0, 17, 1 } } } - parser:parse() - return parser:included_regions() - ]] + local range_tbl = exec_lua(function() + _G.parser:set_included_regions { { { 0, 0, 17, 1 } } } + _G.parser:parse() + return _G.parser:included_regions() + end) eq({ { { 0, 0, 0, 17, 1, 508 } } }, range_tbl) end) @@ -272,25 +272,25 @@ end]] it('allows to set complex ranges', function() insert(test_text) - local res = exec_lua [[ - parser = vim.treesitter.get_parser(0, "c") - query = vim.treesitter.query.parse("c", "(declaration) @decl") + local res = exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c') + local query = vim.treesitter.query.parse('c', '(declaration) @decl') - local nodes = {} - for _, node in query:iter_captures(parser:parse()[1]:root(), 0) do - table.insert(nodes, node) - end + local nodes = {} + for _, node in query:iter_captures(parser:parse()[1]:root(), 0) do + table.insert(nodes, node) + end - parser:set_included_regions({nodes}) + parser:set_included_regions({ nodes }) - local root = parser:parse(true)[1]:root() + local root = parser:parse(true)[1]:root() - local res = {} - for i=0,(root:named_child_count() - 1) do - table.insert(res, { root:named_child(i):range() }) - end - return res - ]] + local res = {} + for i = 0, (root:named_child_count() - 1) do + table.insert(res, { root:named_child(i):range() }) + end + return res + end) eq({ { 2, 2, 2, 40 }, @@ -304,10 +304,10 @@ end]] end) it('allows to create string parsers', function() - local ret = exec_lua [[ - local parser = vim.treesitter.get_string_parser("int foo = 42;", "c") + local ret = exec_lua(function() + local parser = vim.treesitter.get_string_parser('int foo = 42;', 'c') return { parser:parse()[1]:root():range() } - ]] + end) eq({ 0, 0, 0, 13 }, ret) end) @@ -318,33 +318,31 @@ end]] int bar = 13; ]] - local ret = exec_lua( - [[ - local str = ... - local parser = vim.treesitter.get_string_parser(str, "c") + local ret = exec_lua(function(str) + local parser = vim.treesitter.get_string_parser(str, 'c') - local nodes = {} - local query = vim.treesitter.query.parse("c", '((identifier) @id (#eq? @id "foo"))') + local nodes = {} + local query = vim.treesitter.query.parse('c', '((identifier) @id (#eq? @id "foo"))') - for _, node in query:iter_captures(parser:parse()[1]:root(), str) do - table.insert(nodes, { node:range() }) - end + for _, node in query:iter_captures(parser:parse()[1]:root(), str) do + table.insert(nodes, { node:range() }) + end - return nodes - ]], - txt - ) + return nodes + end, txt) eq({ { 0, 10, 0, 13 } }, ret) end) describe('when creating a language tree', function() local function get_ranges() - return exec_lua [[ + return exec_lua(function() local result = {} - parser:for_each_tree(function(tree) table.insert(result, {tree:root():range()}) end) + _G.parser:for_each_tree(function(tree) + table.insert(result, { tree:root():range() }) + end) return result - ]] + end) end before_each(function() @@ -360,16 +358,17 @@ int x = INT_MAX; describe('when parsing regions independently', function() it('should inject a language', function() - exec_lua([[ - parser = vim.treesitter.get_parser(0, "c", { + exec_lua(function() + _G.parser = vim.treesitter.get_parser(0, 'c', { injections = { c = ( - '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c")) ' .. - '(preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))' - ) - }}) - parser:parse(true) - ]]) + '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c")) ' + .. '(preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))' + ), + }, + }) + _G.parser:parse(true) + end) eq('table', exec_lua('return type(parser:children().c)')) eq(5, exec_lua('return #parser:children().c:trees()')) @@ -397,16 +396,17 @@ int x = INT_MAX; describe('when parsing regions combined', function() it('should inject a language', function() - exec_lua([[ - parser = vim.treesitter.get_parser(0, "c", { + exec_lua(function() + _G.parser = vim.treesitter.get_parser(0, 'c', { injections = { c = ( - '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c") (#set! injection.combined)) ' .. - '(preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c") (#set! injection.combined))' - ) - }}) - parser:parse(true) - ]]) + '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c") (#set! injection.combined)) ' + .. '(preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c") (#set! injection.combined))' + ), + }, + }) + _G.parser:parse(true) + end) eq('table', exec_lua('return type(parser:children().c)')) eq(2, exec_lua('return #parser:children().c:trees()')) @@ -447,16 +447,17 @@ int x = INT_MAX; describe('when using injection.self', function() it('should inject the source language', function() - exec_lua([[ - parser = vim.treesitter.get_parser(0, "c", { + exec_lua(function() + _G.parser = vim.treesitter.get_parser(0, 'c', { injections = { c = ( - '(preproc_def (preproc_arg) @injection.content (#set! injection.self)) ' .. - '(preproc_function_def value: (preproc_arg) @injection.content (#set! injection.self))' - ) - }}) - parser:parse(true) - ]]) + '(preproc_def (preproc_arg) @injection.content (#set! injection.self)) ' + .. '(preproc_function_def value: (preproc_arg) @injection.content (#set! injection.self))' + ), + }, + }) + _G.parser:parse(true) + end) eq('table', exec_lua('return type(parser:children().c)')) eq(5, exec_lua('return #parser:children().c:trees()')) @@ -484,16 +485,17 @@ int x = INT_MAX; describe('when using the offset directive', function() it('should shift the range by the directive amount', function() - exec_lua([[ - parser = vim.treesitter.get_parser(0, "c", { + exec_lua(function() + _G.parser = vim.treesitter.get_parser(0, 'c', { injections = { c = ( - '(preproc_def ((preproc_arg) @injection.content (#set! injection.language "c") (#offset! @injection.content 0 2 0 -1))) ' .. - '(preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))' - ) - }}) - parser:parse(true) - ]]) + '(preproc_def ((preproc_arg) @injection.content (#set! injection.language "c") (#offset! @injection.content 0 2 0 -1))) ' + .. '(preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))' + ), + }, + }) + _G.parser:parse(true) + end) eq('table', exec_lua('return type(parser:children().c)')) eq({ @@ -506,7 +508,7 @@ int x = INT_MAX; }, get_ranges()) end) it('should list all directives', function() - local res_list = exec_lua [[ + local res_list = exec_lua(function() local query = vim.treesitter.query local list = query.list_directives() @@ -514,7 +516,7 @@ int x = INT_MAX; table.sort(list) return list - ]] + end) eq({ 'gsub!', 'offset!', 'set!', 'trim!' }, res_list) end) @@ -530,18 +532,18 @@ int x = INT_MAX; end) it('should return the correct language tree', function() - local result = exec_lua([[ - parser = vim.treesitter.get_parser(0, "c", { + local result = exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c', { injections = { - c = '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c"))' - } + c = '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c"))', + }, }) parser:parse(true) - local sub_tree = parser:language_for_range({1, 18, 1, 19}) + local sub_tree = parser:language_for_range({ 1, 18, 1, 19 }) return sub_tree == parser:children().c - ]]) + end) eq(true, result) end) @@ -555,23 +557,23 @@ print() end) it('ignores optional captures #23100', function() - local result = exec_lua([[ - parser = vim.treesitter.get_parser(0, "lua", { + local result = exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'lua', { injections = { lua = ( - '(function_call ' .. - '(arguments ' .. - '(string)? @injection.content ' .. - '(number)? @injection.content ' .. - '(#offset! @injection.content 0 1 0 -1) ' .. - '(#set! injection.language "c")))' - ) - } + '(function_call ' + .. '(arguments ' + .. '(string)? @injection.content ' + .. '(number)? @injection.content ' + .. '(#offset! @injection.content 0 1 0 -1) ' + .. '(#set! injection.language "c")))' + ), + }, }) parser:parse(true) return parser:is_valid() - ]]) + end) eq(true, result) end) @@ -584,18 +586,15 @@ print() int x = 3; ]]) - local result = exec_lua([[ - local result - - query = vim.treesitter.query.parse("c", '((number_literal) @number (#set! "key" "value"))') - parser = vim.treesitter.get_parser(0, "c") + local result = exec_lua(function() + local query = + vim.treesitter.query.parse('c', '((number_literal) @number (#set! "key" "value"))') + local parser = vim.treesitter.get_parser(0, 'c') - for pattern, match, metadata in query:iter_matches(parser:parse()[1]:root(), 0, 0, -1, { all = true }) do - result = metadata.key - end - - return result - ]]) + local _, _, metadata = + query:iter_matches(parser:parse()[1]:root(), 0, 0, -1, { all = true })() + return metadata.key + end) eq('value', result) end) @@ -606,19 +605,18 @@ print() int x = 3; ]]) - local result = exec_lua([[ - local query = vim.treesitter.query - local value - - query = vim.treesitter.query.parse("c", '((number_literal) @number (#set! @number "key" "value"))') - parser = vim.treesitter.get_parser(0, "c") + local result = exec_lua(function() + local query = vim.treesitter.query.parse( + 'c', + '((number_literal) @number (#set! @number "key" "value"))' + ) + local parser = vim.treesitter.get_parser(0, 'c') - for pattern, match, metadata in query:iter_matches(parser:parse()[1]:root(), 0, 0, -1, { all = true }) do - for _, nested_tbl in pairs(metadata) do - return nested_tbl.key - end - end - ]]) + local _, _, metadata = + query:iter_matches(parser:parse()[1]:root(), 0, 0, -1, { all = true })() + local _, nested_tbl = next(metadata) + return nested_tbl.key + end) eq('value', result) end) @@ -628,19 +626,18 @@ print() int x = 3; ]]) - local result = exec_lua([[ - local query = vim.treesitter.query - local result - - query = vim.treesitter.query.parse("c", '((number_literal) @number (#set! @number "key" "value") (#set! @number "key2" "value2"))') - parser = vim.treesitter.get_parser(0, "c") + local result = exec_lua(function() + local query = vim.treesitter.query.parse( + 'c', + '((number_literal) @number (#set! @number "key" "value") (#set! @number "key2" "value2"))' + ) + local parser = vim.treesitter.get_parser(0, 'c') - for pattern, match, metadata in query:iter_matches(parser:parse()[1]:root(), 0, 0, -1, { all = true }) do - for _, nested_tbl in pairs(metadata) do - return nested_tbl - end - end - ]]) + local _, _, metadata = + query:iter_matches(parser:parse()[1]:root(), 0, 0, -1, { all = true })() + local _, nested_tbl = next(metadata) + return nested_tbl + end) local expected = { ['key'] = 'value', ['key2'] = 'value2', @@ -663,24 +660,21 @@ print() (function_definition) @function ]] - exec_lua([[ + exec_lua(function() vim.treesitter.start(0, 'c') - ]]) + end) local function run_query() - return exec_lua( - [[ - local query = vim.treesitter.query.parse("c", ...) - parser = vim.treesitter.get_parser() - tree = parser:parse()[1] - res = {} - for id, node in query:iter_captures(tree:root()) do - table.insert(res, {query.captures[id], node:range()}) - end - return res - ]], - query0 - ) + return exec_lua(function(query_str) + local query = vim.treesitter.query.parse('c', query_str) + local parser = vim.treesitter.get_parser() + local tree = parser:parse()[1] + local res = {} + for id, node in query:iter_captures(tree:root()) do + table.insert(res, { query.captures[id], node:range() }) + end + return res + end, query0) end eq({ @@ -718,18 +712,15 @@ print() ]] ]==] - local r = exec_lua( - [[ - local parser = vim.treesitter.get_string_parser(..., 'lua') - parser:parse(true) - local ranges = {} - parser:for_each_tree(function(tstree, tree) - ranges[tree:lang()] = { tstree:root():range(true) } - end) - return ranges - ]], - source - ) + local r = exec_lua(function(src) + local parser = vim.treesitter.get_string_parser(src, 'lua') + parser:parse(true) + local ranges = {} + parser:for_each_tree(function(tstree, tree) + ranges[tree:lang()] = { tstree:root():range(true) } + end) + return ranges + end, source) eq({ lua = { 0, 6, 6, 16, 4, 438 }, @@ -741,19 +732,14 @@ print() -- the ranges but only provide a Range4. Strip the byte entries from the ranges and make sure -- add_bytes() produces the same result. - local rb = exec_lua( - [[ - local r, source = ... - local add_bytes = require('vim.treesitter._range').add_bytes - for lang, range in pairs(r) do - r[lang] = {range[1], range[2], range[4], range[5]} - r[lang] = add_bytes(source, r[lang]) - end - return r - ]], - r, - source - ) + local rb = exec_lua(function(r0, source0) + local add_bytes = require('vim.treesitter._range').add_bytes + for lang, range in pairs(r0) do + r0[lang] = { range[1], range[2], range[4], range[5] } + r0[lang] = add_bytes(source0, r0[lang]) + end + return r0 + end, r, source) eq(rb, r) end) @@ -766,25 +752,25 @@ print() ]] -- This is not a valid injection since (code) has children and include-children is not set - exec_lua [[ - parser1 = require('vim.treesitter.languagetree').new(0, "vimdoc", { + exec_lua(function() + _G.parser1 = require('vim.treesitter.languagetree').new(0, 'vimdoc', { injections = { - vimdoc = "((codeblock (language) @injection.language (code) @injection.content))" - } + vimdoc = '((codeblock (language) @injection.language (code) @injection.content))', + }, }) - parser1:parse(true) - ]] + _G.parser1:parse(true) + end) eq(0, exec_lua('return #vim.tbl_keys(parser1:children())')) - exec_lua [[ - parser2 = require('vim.treesitter.languagetree').new(0, "vimdoc", { + exec_lua(function() + _G.parser2 = require('vim.treesitter.languagetree').new(0, 'vimdoc', { injections = { - vimdoc = "((codeblock (language) @injection.language (code) @injection.content) (#set! injection.include-children))" - } + vimdoc = '((codeblock (language) @injection.language (code) @injection.content) (#set! injection.include-children))', + }, }) - parser2:parse(true) - ]] + _G.parser2:parse(true) + end) eq(1, exec_lua('return #vim.tbl_keys(parser2:children())')) eq({ { { 1, 0, 21, 2, 0, 42 } } }, exec_lua('return parser2:children().lua:included_regions()')) @@ -821,46 +807,46 @@ print() < ]]) - exec_lua [[ - parser = require('vim.treesitter.languagetree').new(0, "vimdoc", { + exec_lua(function() + _G.parser = require('vim.treesitter.languagetree').new(0, 'vimdoc', { injections = { - vimdoc = "((codeblock (language) @injection.language (code) @injection.content) (#set! injection.include-children))" - } + vimdoc = '((codeblock (language) @injection.language (code) @injection.content) (#set! injection.include-children))', + }, }) - ]] + end) --- Do not parse injections by default eq( 0, - exec_lua [[ - parser:parse() - return #vim.tbl_keys(parser:children()) - ]] + exec_lua(function() + _G.parser:parse() + return #vim.tbl_keys(_G.parser:children()) + end) ) --- Only parse injections between lines 0, 2 eq( 1, - exec_lua [[ - parser:parse({0, 2}) - return #parser:children().lua:trees() - ]] + exec_lua(function() + _G.parser:parse({ 0, 2 }) + return #_G.parser:children().lua:trees() + end) ) eq( 2, - exec_lua [[ - parser:parse({2, 6}) - return #parser:children().lua:trees() - ]] + exec_lua(function() + _G.parser:parse({ 2, 6 }) + return #_G.parser:children().lua:trees() + end) ) eq( 7, - exec_lua [[ - parser:parse(true) - return #parser:children().lua:trees() - ]] + exec_lua(function() + _G.parser:parse(true) + return #_G.parser:children().lua:trees() + end) ) end) @@ -876,13 +862,13 @@ print() feed(':set ft=help') - exec_lua [[ - vim.treesitter.get_parser(0, "vimdoc", { + exec_lua(function() + vim.treesitter.get_parser(0, 'vimdoc', { injections = { - vimdoc = "((codeblock (language) @injection.language (code) @injection.content) (#set! injection.include-children))" - } + vimdoc = '((codeblock (language) @injection.language (code) @injection.content) (#set! injection.include-children))', + }, }) - ]] + end) end) it('is valid excluding, invalid including children initially', function() diff --git a/test/functional/treesitter/query_spec.lua b/test/functional/treesitter/query_spec.lua index 2212f787af..00e8071738 100644 --- a/test/functional/treesitter/query_spec.lua +++ b/test/functional/treesitter/query_spec.lua @@ -10,28 +10,26 @@ local pcall_err = t.pcall_err local api = n.api local fn = n.fn -local get_query_result_code = [[ - function get_query_result(query_text) - cquery = vim.treesitter.query.parse("c", query_text) - parser = vim.treesitter.get_parser(0, "c") - tree = parser:parse()[1] - res = {} - for cid, node in cquery:iter_captures(tree:root(), 0) do - -- can't transmit node over RPC. just check the name, range, and text - local text = vim.treesitter.get_node_text(node, 0) - local range = {node:range()} - table.insert(res, { cquery.captures[cid], node:type(), range, text }) - end - return res +local function get_query_result(query_text) + local cquery = vim.treesitter.query.parse('c', query_text) + local parser = vim.treesitter.get_parser(0, 'c') + local tree = parser:parse()[1] + local res = {} + for cid, node in cquery:iter_captures(tree:root(), 0) do + -- can't transmit node over RPC. just check the name, range, and text + local text = vim.treesitter.get_node_text(node, 0) + local range = { node:range() } + table.insert(res, { cquery.captures[cid], node:type(), range, text }) end -]] + return res +end describe('treesitter query API', function() before_each(function() clear() - exec_lua [[ + exec_lua(function() vim.g.__ts_debug = 1 - ]] + end) end) local test_text = [[ @@ -71,9 +69,9 @@ void ui_refresh(void) it('supports runtime queries', function() ---@type string[] - local ret = exec_lua [[ - return vim.treesitter.query.get("c", "highlights").captures - ]] + local ret = exec_lua(function() + return vim.treesitter.query.get('c', 'highlights').captures + end) -- see $VIMRUNTIME/queries/c/highlights.scm eq('variable', ret[1]) @@ -84,22 +82,17 @@ void ui_refresh(void) local long_query = test_query:rep(100) ---@return number local function q(_n) - return exec_lua( - [[ - local query, n = ... - local before = vim.api.nvim__stats().ts_query_parse_count - collectgarbage("stop") - for i=1, n, 1 do - cquery = vim.treesitter.query.parse("c", ...) - end - collectgarbage("restart") - collectgarbage("collect") - local after = vim.api.nvim__stats().ts_query_parse_count - return after - before - ]], - long_query, - _n - ) + return exec_lua(function(query, n0) + local before = vim.api.nvim__stats().ts_query_parse_count + collectgarbage('stop') + for _ = 1, n0, 1 do + vim.treesitter.query.parse('c', query, n0) + end + collectgarbage('restart') + collectgarbage('collect') + local after = vim.api.nvim__stats().ts_query_parse_count + return after - before + end, long_query, _n) end eq(1, q(1)) @@ -110,20 +103,17 @@ void ui_refresh(void) it('supports query and iter by capture (iter_captures)', function() insert(test_text) - local res = exec_lua( - [[ - cquery = vim.treesitter.query.parse("c", ...) - parser = vim.treesitter.get_parser(0, "c") - tree = parser:parse()[1] - res = {} - for cid, node in cquery:iter_captures(tree:root(), 0, 7, 14) do - -- can't transmit node over RPC. just check the name and range - table.insert(res, { '@' .. cquery.captures[cid], node:type(), node:range() }) - end - return res - ]], - test_query - ) + local res = exec_lua(function(test_query0) + local cquery = vim.treesitter.query.parse('c', test_query0) + local parser = vim.treesitter.get_parser(0, 'c') + local tree = parser:parse()[1] + local res = {} + for cid, node in cquery:iter_captures(tree:root(), 0, 7, 14) do + -- can't transmit node over RPC. just check the name and range + table.insert(res, { '@' .. cquery.captures[cid], node:type(), node:range() }) + end + return res + end, test_query) eq({ { '@type', 'primitive_type', 8, 2, 8, 6 }, -- bool @@ -143,26 +133,23 @@ void ui_refresh(void) insert(test_text) ---@type table - local res = exec_lua( - [[ - cquery = vim.treesitter.query.parse("c", ...) - parser = vim.treesitter.get_parser(0, "c") - tree = parser:parse()[1] - res = {} - for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14, { all = true }) do - -- can't transmit node over RPC. just check the name and range - local mrepr = {} - for cid, nodes in pairs(match) do - for _, node in ipairs(nodes) do - table.insert(mrepr, { '@' .. cquery.captures[cid], node:type(), node:range() }) - end + local res = exec_lua(function(test_query0) + local cquery = vim.treesitter.query.parse('c', test_query0) + local parser = vim.treesitter.get_parser(0, 'c') + local tree = parser:parse()[1] + local res = {} + for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14, { all = true }) do + -- can't transmit node over RPC. just check the name and range + local mrepr = {} + for cid, nodes in pairs(match) do + for _, node in ipairs(nodes) do + table.insert(mrepr, { '@' .. cquery.captures[cid], node:type(), node:range() }) end - table.insert(res, { pattern, mrepr }) end - return res - ]], - test_query - ) + table.insert(res, { pattern, mrepr }) + end + return res + end, test_query) eq({ { 3, { { '@type', 'primitive_type', 8, 2, 8, 6 } } }, @@ -191,20 +178,20 @@ void ui_refresh(void) it('supports query and iter by capture for quantifiers', function() insert(test_text) - local res = exec_lua( - [[ - cquery = vim.treesitter.query.parse("c", ...) - parser = vim.treesitter.get_parser(0, "c") - tree = parser:parse()[1] - res = {} - for cid, node in cquery:iter_captures(tree:root(), 0, 7, 14) do - -- can't transmit node over RPC. just check the name and range - table.insert(res, { '@' .. cquery.captures[cid], node:type(), node:range() }) - end - return res - ]], - '(expression_statement (assignment_expression (call_expression)))+ @funccall' - ) + local res = exec_lua(function() + local cquery = vim.treesitter.query.parse( + 'c', + '(expression_statement (assignment_expression (call_expression)))+ @funccall' + ) + local parser = vim.treesitter.get_parser(0, 'c') + local tree = parser:parse()[1] + local res = {} + for cid, node in cquery:iter_captures(tree:root(), 0, 7, 14) do + -- can't transmit node over RPC. just check the name and range + table.insert(res, { '@' .. cquery.captures[cid], node:type(), node:range() }) + end + return res + end) eq({ { '@funccall', 'expression_statement', 11, 4, 11, 34 }, @@ -216,26 +203,26 @@ void ui_refresh(void) it('supports query and iter by match for quantifiers', function() insert(test_text) - local res = exec_lua( - [[ - cquery = vim.treesitter.query.parse("c", ...) - parser = vim.treesitter.get_parser(0, "c") - tree = parser:parse()[1] - res = {} - for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14, { all = true }) do - -- can't transmit node over RPC. just check the name and range - local mrepr = {} - for cid, nodes in pairs(match) do - for _, node in ipairs(nodes) do - table.insert(mrepr, { '@' .. cquery.captures[cid], node:type(), node:range() }) - end + local res = exec_lua(function() + local cquery = vim.treesitter.query.parse( + 'c', + '(expression_statement (assignment_expression (call_expression)))+ @funccall' + ) + local parser = vim.treesitter.get_parser(0, 'c') + local tree = parser:parse()[1] + local res = {} + for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14, { all = true }) do + -- can't transmit node over RPC. just check the name and range + local mrepr = {} + for cid, nodes in pairs(match) do + for _, node in ipairs(nodes) do + table.insert(mrepr, { '@' .. cquery.captures[cid], node:type(), node:range() }) end - table.insert(res, {pattern, mrepr}) end - return res - ]], - '(expression_statement (assignment_expression (call_expression)))+ @funccall' - ) + table.insert(res, { pattern, mrepr }) + end + return res + end, '(expression_statement (assignment_expression (call_expression)))+ @funccall') eq({ { @@ -265,26 +252,26 @@ void ui_refresh(void) } ]]) - local res = exec_lua( - [[ - cquery = vim.treesitter.query.parse("c", ...) - parser = vim.treesitter.get_parser(0, "c") - tree = parser:parse()[1] - res = {} - for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14, { all = true }) do - -- can't transmit node over RPC. just check the name and range - local mrepr = {} - for cid, nodes in pairs(match) do - for _, node in ipairs(nodes) do - table.insert(mrepr, { '@' .. cquery.captures[cid], node:type(), node:range() }) - end + local res = exec_lua(function() + local cquery = vim.treesitter.query.parse( + 'c', + '(expression_statement (assignment_expression (call_expression)))+ @funccall' + ) + local parser = vim.treesitter.get_parser(0, 'c') + local tree = parser:parse()[1] + local res = {} + for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14, { all = true }) do + -- can't transmit node over RPC. just check the name and range + local mrepr = {} + for cid, nodes in pairs(match) do + for _, node in ipairs(nodes) do + table.insert(mrepr, { '@' .. cquery.captures[cid], node:type(), node:range() }) end - table.insert(res, {pattern, mrepr}) end - return res - ]], - '(expression_statement (assignment_expression (call_expression)))+ @funccall' - ) + table.insert(res, { pattern, mrepr }) + end + return res + end) eq({ { @@ -308,18 +295,18 @@ void ui_refresh(void) insert('char* astring = "\\n"; (1 + 1) * 2 != 2;') ---@type table - local res = exec_lua([[ - query = ( - '([_] @plus (#vim-match? @plus "^\\\\+$"))' .. - '([_] @times (#vim-match? @times "^\\\\*$"))' .. - '([_] @paren (#vim-match? @paren "^\\\\($"))' .. - '([_] @escape (#vim-match? @escape "^\\\\\\\\n$"))' .. - '([_] @string (#vim-match? @string "^\\"\\\\\\\\n\\"$"))' + local res = exec_lua(function() + local query = ( + '([_] @plus (#vim-match? @plus "^\\\\+$"))' + .. '([_] @times (#vim-match? @times "^\\\\*$"))' + .. '([_] @paren (#vim-match? @paren "^\\\\($"))' + .. '([_] @escape (#vim-match? @escape "^\\\\\\\\n$"))' + .. '([_] @string (#vim-match? @string "^\\"\\\\\\\\n\\"$"))' ) - cquery = vim.treesitter.query.parse("c", query) - parser = vim.treesitter.get_parser(0, "c") - tree = parser:parse()[1] - res = {} + local cquery = vim.treesitter.query.parse('c', query) + local parser = vim.treesitter.get_parser(0, 'c') + local tree = parser:parse()[1] + local res = {} for pattern, match in cquery:iter_matches(tree:root(), 0, 0, -1, { all = true }) do -- can't transmit node over RPC. just check the name and range local mrepr = {} @@ -331,7 +318,7 @@ void ui_refresh(void) table.insert(res, { pattern, mrepr }) end return res - ]]) + end) eq({ { 2, { { '@times', '*', 0, 4, 0, 5 } } }, @@ -362,10 +349,9 @@ void ui_refresh(void) return 0; } ]]) - exec_lua(get_query_result_code) local res0 = exec_lua( - [[return get_query_result(...)]], + get_query_result, [[((primitive_type) @c-keyword (#any-of? @c-keyword "int" "float"))]] ) eq({ @@ -374,7 +360,7 @@ void ui_refresh(void) }, res0) local res1 = exec_lua( - [[return get_query_result(...)]], + get_query_result, [[ ((string_literal) @fizzbuzz-strings (#any-of? @fizzbuzz-strings "\"number= %d FizzBuzz\\n\"" @@ -395,16 +381,15 @@ void ui_refresh(void) int x = 123; enum C { y = 124 }; int main() { int z = 125; }]]) - exec_lua(get_query_result_code) local result = exec_lua( - [[return get_query_result(...)]], + get_query_result, [[((number_literal) @literal (#has-ancestor? @literal "function_definition"))]] ) eq({ { 'literal', 'number_literal', { 2, 21, 2, 24 }, '125' } }, result) result = exec_lua( - [[return get_query_result(...)]], + get_query_result, [[((number_literal) @literal (#has-ancestor? @literal "function_definition" "enum_specifier"))]] ) eq({ @@ -413,7 +398,7 @@ void ui_refresh(void) }, result) result = exec_lua( - [[return get_query_result(...)]], + get_query_result, [[((number_literal) @literal (#not-has-ancestor? @literal "enum_specifier"))]] ) eq({ @@ -425,11 +410,14 @@ void ui_refresh(void) it('allows loading query with escaped quotes and capture them `#{lua,vim}-match`?', function() insert('char* astring = "Hello World!";') - local res = exec_lua([[ - cquery = vim.treesitter.query.parse("c", '([_] @quote (#vim-match? @quote "^\\"$")) ([_] @quote (#lua-match? @quote "^\\"$"))') - parser = vim.treesitter.get_parser(0, "c") - tree = parser:parse()[1] - res = {} + local res = exec_lua(function() + local cquery = vim.treesitter.query.parse( + 'c', + '([_] @quote (#vim-match? @quote "^\\"$")) ([_] @quote (#lua-match? @quote "^\\"$"))' + ) + local parser = vim.treesitter.get_parser(0, 'c') + local tree = parser:parse()[1] + local res = {} for pattern, match in cquery:iter_matches(tree:root(), 0, 0, -1, { all = true }) do -- can't transmit node over RPC. just check the name and range local mrepr = {} @@ -441,7 +429,7 @@ void ui_refresh(void) table.insert(res, { pattern, mrepr }) end return res - ]]) + end) eq({ { 1, { { '@quote', '"', 0, 16, 0, 17 } } }, @@ -461,70 +449,64 @@ void ui_refresh(void) local custom_query = '((identifier) @main (#is-main? @main))' do - local res = exec_lua( - [[ - local query = vim.treesitter.query - - local function is_main(match, pattern, bufnr, predicate) - local nodes = match[ predicate[2] ] - for _, node in ipairs(nodes) do - if vim.treesitter.get_node_text(node, bufnr) == 'main' then - return true - end + local res = exec_lua(function(custom_query0) + local query = vim.treesitter.query + + local function is_main(match, _pattern, bufnr, predicate) + local nodes = match[predicate[2]] + for _, node in ipairs(nodes) do + if vim.treesitter.get_node_text(node, bufnr) == 'main' then + return true end - return false end + return false + end - local parser = vim.treesitter.get_parser(0, "c") + local parser = vim.treesitter.get_parser(0, 'c') - -- Time bomb: update this in 0.12 - if vim.fn.has('nvim-0.12') == 1 then - return 'Update this test to remove this message and { all = true } from add_predicate' - end - query.add_predicate("is-main?", is_main, { all = true }) + -- Time bomb: update this in 0.12 + if vim.fn.has('nvim-0.12') == 1 then + return 'Update this test to remove this message and { all = true } from add_predicate' + end + query.add_predicate('is-main?', is_main, { all = true }) - local query = query.parse("c", ...) + local query0 = query.parse('c', custom_query0) - local nodes = {} - for _, node in query:iter_captures(parser:parse()[1]:root(), 0) do - table.insert(nodes, {node:range()}) - end + local nodes = {} + for _, node in query0:iter_captures(parser:parse()[1]:root(), 0) do + table.insert(nodes, { node:range() }) + end - return nodes - ]], - custom_query - ) + return nodes + end, custom_query) eq({ { 0, 4, 0, 8 } }, res) end -- Once with the old API. Remove this whole 'do' block in 0.12 do - local res = exec_lua( - [[ - local query = vim.treesitter.query + local res = exec_lua(function(custom_query0) + local query = vim.treesitter.query - local function is_main(match, pattern, bufnr, predicate) - local node = match[ predicate[2] ] + local function is_main(match, _pattern, bufnr, predicate) + local node = match[predicate[2]] - return vim.treesitter.get_node_text(node, bufnr) == 'main' - end + return vim.treesitter.get_node_text(node, bufnr) == 'main' + end - local parser = vim.treesitter.get_parser(0, "c") + local parser = vim.treesitter.get_parser(0, 'c') - query.add_predicate("is-main?", is_main, true) + query.add_predicate('is-main?', is_main, true) - local query = query.parse("c", ...) + local query0 = query.parse('c', custom_query0) - local nodes = {} - for _, node in query:iter_captures(parser:parse()[1]:root(), 0) do - table.insert(nodes, {node:range()}) - end + local nodes = {} + for _, node in query0:iter_captures(parser:parse()[1]:root(), 0) do + table.insert(nodes, { node:range() }) + end - return nodes - ]], - custom_query - ) + return nodes + end, custom_query) -- Remove this 'do' block in 0.12 eq(0, fn.has('nvim-0.12')) @@ -532,16 +514,16 @@ void ui_refresh(void) end do - local res = exec_lua [[ + local res = exec_lua(function() local query = vim.treesitter.query - local t = {} + local r = {} for _, v in ipairs(query.list_predicates()) do - t[v] = true + r[v] = true end - return t - ]] + return r + end) eq(true, res['is-main?']) end @@ -560,18 +542,15 @@ void ui_refresh(void) local function test(input, query) api.nvim_buf_set_lines(0, 0, -1, true, vim.split(dedent(input), '\n')) - return exec_lua( - [[ - local parser = vim.treesitter.get_parser(0, "lua") - local query = vim.treesitter.query.parse("lua", ...) - local nodes = {} - for _, node in query:iter_captures(parser:parse()[1]:root(), 0) do - nodes[#nodes+1] = { node:range() } - end - return nodes - ]], - query - ) + return exec_lua(function(query_str) + local parser = vim.treesitter.get_parser(0, 'lua') + local query0 = vim.treesitter.query.parse('lua', query_str) + local nodes = {} + for _, node in query0:iter_captures(parser:parse()[1]:root(), 0) do + nodes[#nodes + 1] = { node:range() } + end + return nodes + end, query) end eq( @@ -638,23 +617,21 @@ void ui_refresh(void) -- Comment ]]) - local query = [[ + local result = exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'lua') + local query = vim.treesitter.query.parse( + 'lua', + [[ (((comment (comment_content))+) @bar (#lua-match? @bar "Comment")) ]] - - local result = exec_lua( - [[ - local parser = vim.treesitter.get_parser(0, "lua") - local query = vim.treesitter.query.parse("lua", ...) - local nodes = {} - for _, node in query:iter_captures(parser:parse()[1]:root(), 0) do - nodes[#nodes+1] = { node:range() } - end - return nodes - ]], - query - ) + ) + local nodes = {} + for _, node in query:iter_captures(parser:parse()[1]:root(), 0) do + nodes[#nodes + 1] = { node:range() } + end + return nodes + end) eq({ { 0, 2, 0, 12 }, @@ -668,23 +645,20 @@ void ui_refresh(void) eq(0, fn.has('nvim-0.12')) insert(test_text) - local res = exec_lua( - [[ - cquery = vim.treesitter.query.parse("c", ...) - parser = vim.treesitter.get_parser(0, "c") - tree = parser:parse()[1] - res = {} - for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14) do - local mrepr = {} - for cid, node in pairs(match) do - table.insert(mrepr, { '@' .. cquery.captures[cid], node:type(), node:range() }) - end - table.insert(res, { pattern, mrepr }) + local res = exec_lua(function(test_query0) + local cquery = vim.treesitter.query.parse('c', test_query0) + local parser = vim.treesitter.get_parser(0, 'c') + local tree = parser:parse()[1] + local res = {} + for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14) do + local mrepr = {} + for cid, node in pairs(match) do + table.insert(mrepr, { '@' .. cquery.captures[cid], node:type(), node:range() }) end - return res - ]], - test_query - ) + table.insert(res, { pattern, mrepr }) + end + return res + end, test_query) eq({ { 3, { { '@type', 'primitive_type', 8, 2, 8, 6 } } }, @@ -716,23 +690,19 @@ void ui_refresh(void) int bar = 13; ]] - local ret = exec_lua( - [[ - local str = ... - local parser = vim.treesitter.get_string_parser(str, "c") + local ret = exec_lua(function(str) + local parser = vim.treesitter.get_string_parser(str, 'c') - local nodes = {} - local query = vim.treesitter.query.parse("c", '((identifier) @foo)') - local first_child = parser:parse()[1]:root():child(1) + local nodes = {} + local query = vim.treesitter.query.parse('c', '((identifier) @foo)') + local first_child = parser:parse()[1]:root():child(1) - for _, node in query:iter_captures(first_child, str) do - table.insert(nodes, { node:range() }) - end + for _, node in query:iter_captures(first_child, str) do + table.insert(nodes, { node:range() }) + end - return nodes - ]], - txt - ) + return nodes + end, txt) eq({ { 1, 10, 1, 13 } }, ret) end) @@ -789,7 +759,10 @@ void ui_refresh(void) const char *sql = "SELECT * FROM Students WHERE name = 'Robert'); DROP TABLE Students;--"; ]]) - local query = [[ + local result = exec_lua(function() + local query = vim.treesitter.query.parse( + 'c', + [[ (declaration type: (_) declarator: (init_declarator @@ -800,20 +773,15 @@ void ui_refresh(void) (#set! injection.language "sql") (#contains? @_id "sql")) ]] - - local result = exec_lua( - [=[ - local query = vim.treesitter.query.parse("c", ...) - local parser = vim.treesitter.get_parser(0, "c") + ) + local parser = vim.treesitter.get_parser(0, 'c') local root = parser:parse()[1]:root() - local t = {} - for id, node, metadata in query:iter_captures(root, 0) do - t[query.captures[id]] = metadata + local res = {} + for id, _, metadata in query:iter_captures(root, 0) do + res[query.captures[id]] = metadata end - return t - ]=], - query - ) + return res + end) eq({ ['_id'] = { ['injection.language'] = 'sql' }, @@ -837,25 +805,22 @@ void ui_refresh(void) (#eq? @function.name "foo")) ]] - local result = exec_lua( - [[ - local query = vim.treesitter.query.parse("c", ...) - local match_preds = query.match_preds + local result = exec_lua(function(query_str) + local query0 = vim.treesitter.query.parse('c', query_str) + local match_preds = query0.match_preds local called = 0 - function query:match_preds(...) + function query0:match_preds(...) called = called + 1 return match_preds(self, ...) end - local parser = vim.treesitter.get_parser(0, "c") + local parser = vim.treesitter.get_parser(0, 'c') local root = parser:parse()[1]:root() local captures = {} - for id, node in query:iter_captures(root, 0) do + for id in query0:iter_captures(root, 0) do captures[#captures + 1] = id end return { called, captures } - ]], - query - ) + end, query) eq({ 2, { 1, 1, 2, 2 } }, result) end) diff --git a/test/functional/treesitter/utils_spec.lua b/test/functional/treesitter/utils_spec.lua index bca0aca0cb..e079a7c8e7 100644 --- a/test/functional/treesitter/utils_spec.lua +++ b/test/functional/treesitter/utils_spec.lua @@ -17,26 +17,26 @@ describe('treesitter utils', function() int x = 3; }]]) - exec_lua([[ - parser = vim.treesitter.get_parser(0, "c") - tree = parser:parse()[1] - root = tree:root() - ancestor = root:child(0) - child = ancestor:child(0) - ]]) - - eq(true, exec_lua('return vim.treesitter.is_ancestor(ancestor, child)')) - eq(false, exec_lua('return vim.treesitter.is_ancestor(child, ancestor)')) + exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c') + local tree = parser:parse()[1] + local root = tree:root() + _G.ancestor = root:child(0) + _G.child = _G.ancestor:child(0) + end) + + eq(true, exec_lua('return vim.treesitter.is_ancestor(_G.ancestor, _G.child)')) + eq(false, exec_lua('return vim.treesitter.is_ancestor(_G.child, _G.ancestor)')) end) it('can detect if a position is contained in a node', function() - exec_lua([[ - node = { + exec_lua(function() + _G.node = { range = function() return 0, 4, 0, 8 end, } - ]]) + end) eq(false, exec_lua('return vim.treesitter.is_in_node_range(node, 0, 3)')) for i = 4, 7 do -- cgit From 6967c08840bedfecc54884af815b75ff7ab7af7b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 3 Aug 2024 08:13:20 +0800 Subject: vim-patch:9.1.0648: [security] double-free in dialog_changed() Problem: [security] double-free in dialog_changed() (SuyueGuo) Solution: Only clear pointer b_sfname pointer, if it is different than the b_ffname pointer. Don't try to free b_fname, set it to NULL instead. fixes: vim/vim#15403 Github Advisory: https://github.com/vim/vim/security/advisories/GHSA-46pw-v7qw-xc2f https://github.com/vim/vim/commit/b29f4abcd4b3382fa746edd1d0562b7b48c9de60 Co-authored-by: Christian Brabandt --- test/functional/legacy/crash_spec.lua | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'test/functional') diff --git a/test/functional/legacy/crash_spec.lua b/test/functional/legacy/crash_spec.lua index e72c3a512a..b63b3146f4 100644 --- a/test/functional/legacy/crash_spec.lua +++ b/test/functional/legacy/crash_spec.lua @@ -8,6 +8,7 @@ local eq = t.eq local eval = n.eval local exec = n.exec local feed = n.feed +local pcall_err = t.pcall_err before_each(clear) @@ -51,3 +52,14 @@ it('no crash when closing window with tag in loclist', function() eq(0, eval('bufexists(g:qf_bufnr)')) assert_alive() end) + +it('no crash when writing "Untitled" file fails', function() + t.mkdir('Untitled') + finally(function() + vim.uv.fs_rmdir('Untitled') + end) + feed('ifoobar') + command('set bufhidden=unload') + eq('Vim(enew):E502: "Untitled" is a directory', pcall_err(command, 'confirm enew')) + assert_alive() +end) -- cgit From f926cc32c9262b6254e2843276b951cef9da1afe Mon Sep 17 00:00:00 2001 From: bfredl Date: Tue, 2 Jul 2024 13:45:50 +0200 Subject: refactor(shada): rework msgpack decoding without msgpack-c This also makes shada reading slightly faster due to avoiding some copying and allocation. Use keysets to drive decoding of msgpack maps for shada entries. --- test/functional/shada/errors_spec.lua | 95 ++++++++--------------------------- 1 file changed, 20 insertions(+), 75 deletions(-) (limited to 'test/functional') diff --git a/test/functional/shada/errors_spec.lua b/test/functional/shada/errors_spec.lua index e000d0988b..321744f7dd 100644 --- a/test/functional/shada/errors_spec.lua +++ b/test/functional/shada/errors_spec.lua @@ -58,7 +58,7 @@ describe('ShaDa error handling', function() it('fails on search pattern item with zero length', function() wshada('\002\000\000') eq( - 'Vim(rshada):E576: Failed to parse ShaDa file: incomplete msgpack string at position 3', + 'Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 is not a dictionary', exc_exec(sdrcmd()) ) end) @@ -89,18 +89,10 @@ describe('ShaDa error handling', function() it('fails on search pattern item with invalid byte', function() -- 195 (== 0xC1) cannot start any valid messagepack entry (the only byte - -- that cannot do this). Specifically unpack_template.h contains - -- - -- //case 0xc1: // string - -- // again_terminal_trail(NEXT_CS(p), p+1); - -- - -- (literally: commented out code) which means that in place of this code - -- `goto _failed` is used from default: case. I do not know any other way to - -- get MSGPACK_UNPACK_PARSE_ERROR and not MSGPACK_UNPACK_CONTINUE or - -- MSGPACK_UNPACK_EXTRA_BYTES. + -- that cannot do this) wshada('\002\000\001\193') eq( - 'Vim(rshada):E576: Failed to parse ShaDa file due to a msgpack parser error at position 3', + 'Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 is not a dictionary', exc_exec(sdrcmd()) ) end) @@ -108,7 +100,7 @@ describe('ShaDa error handling', function() it('fails on search pattern item with incomplete map', function() wshada('\002\000\001\129') eq( - 'Vim(rshada):E576: Failed to parse ShaDa file: incomplete msgpack string at position 3', + 'Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 has key value which is not a string', exc_exec(sdrcmd()) ) end) @@ -124,7 +116,7 @@ describe('ShaDa error handling', function() it('fails on search pattern with extra bytes', function() wshada('\002\000\002\128\000') eq( - 'Vim(rshada):E576: Failed to parse ShaDa file: extra bytes in msgpack string at position 3', + 'Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 has no pattern', exc_exec(sdrcmd()) ) end) @@ -137,15 +129,6 @@ describe('ShaDa error handling', function() ) end) - -- sp entry is here because it causes an allocation. - it('fails on search pattern item with BIN key', function() - wshada('\002\000\014\131\162sp\196\001a\162sX\192\196\000\000') - eq( - 'Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 has key which is not a string', - exc_exec(sdrcmd()) - ) - end) - -- sp entry is here because it causes an allocation. it('fails on search pattern item with empty key', function() wshada('\002\000\013\131\162sp\196\001a\162sX\192\160\000') @@ -235,22 +218,12 @@ describe('ShaDa error handling', function() ) end) - it('fails on search pattern item with STR pat key value', function() - wshada('\002\000\011\130\162sX\192\162sp\162sp') - eq( - 'Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 has sp key value which is not a binary', - exc_exec(sdrcmd()) - ) - end) - for _, v in ipairs({ { name = 'global mark', mpack = '\007' }, { name = 'jump', mpack = '\008' }, { name = 'local mark', mpack = '\010' }, { name = 'change', mpack = '\011' }, }) do - local is_mark_test = ({ ['global mark'] = true, ['local mark'] = true })[v.name] - it('fails on ' .. v.name .. ' item with NIL value', function() wshada(v.mpack .. '\000\001\192') eq( @@ -259,15 +232,6 @@ describe('ShaDa error handling', function() ) end) - -- f entry is here because it causes an allocation. - it('fails on ' .. v.name .. ' item with BIN key', function() - wshada(v.mpack .. '\000\013\131\161f\196\001/\162mX\192\196\000\000') - eq( - 'Vim(rshada):E575: Error while reading ShaDa file: mark entry at position 0 has key which is not a string', - exc_exec(sdrcmd()) - ) - end) - -- f entry is here because it causes an allocation. it('fails on ' .. v.name .. ' item with empty key', function() wshada(v.mpack .. '\000\012\131\161f\196\001/\162mX\192\160\000') @@ -312,9 +276,7 @@ describe('ShaDa error handling', function() it('fails on ' .. v.name .. ' item with STR n key value', function() wshada(v.mpack .. '\000\011\130\162mX\192\161n\163spa') eq( - is_mark_test - and 'Vim(rshada):E575: Error while reading ShaDa file: mark entry at position 0 has n key value which is not an unsigned integer' - or 'Vim(rshada):E575: Error while reading ShaDa file: mark entry at position 0 has n key which is only valid for local and global mark entries', + 'Vim(rshada):E575: Error while reading ShaDa file: mark entry at position 0 has n key value which is not an integer', exc_exec(sdrcmd()) ) end) @@ -334,14 +296,6 @@ describe('ShaDa error handling', function() exc_exec(sdrcmd()) ) end) - - it('fails on ' .. v.name .. ' item with STR f key value', function() - wshada(v.mpack .. '\000\010\130\162mX\192\161f\162sp') - eq( - 'Vim(rshada):E575: Error while reading ShaDa file: mark entry at position 0 has f key value which is not a binary', - exc_exec(sdrcmd()) - ) - end) end it('fails on register item with NIL value', function() @@ -352,15 +306,6 @@ describe('ShaDa error handling', function() ) end) - -- rc entry is here because it causes an allocation - it('fails on register item with BIN key', function() - wshada('\005\000\015\131\162rc\145\196\001a\162rX\192\196\000\000') - eq( - 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has key which is not a string', - exc_exec(sdrcmd()) - ) - end) - -- rc entry is here because it causes an allocation it('fails on register item with BIN key', function() wshada('\005\000\014\131\162rc\145\196\001a\162rX\192\160\000') @@ -373,7 +318,7 @@ describe('ShaDa error handling', function() it('fails on register item with NIL rt key value', function() wshada('\005\000\009\130\162rX\192\162rt\192') eq( - 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has rt key value which is not an unsigned integer', + 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has rt key value which is not an integer', exc_exec(sdrcmd()) ) end) @@ -381,7 +326,7 @@ describe('ShaDa error handling', function() it('fails on register item with NIL rw key value', function() wshada('\005\000\009\130\162rX\192\162rw\192') eq( - 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has rw key value which is not an unsigned integer', + 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has rw key value which is not an integer', exc_exec(sdrcmd()) ) end) @@ -397,7 +342,7 @@ describe('ShaDa error handling', function() it('fails on register item with empty rc key value', function() wshada('\005\000\009\130\162rX\192\162rc\144') eq( - 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has rc key with empty array', + 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has rc key with missing or empty array', exc_exec(sdrcmd()) ) end) @@ -413,7 +358,7 @@ describe('ShaDa error handling', function() it('fails on register item without rc array', function() wshada('\005\000\009\129\162rX\146\196\001a\192') eq( - 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has missing rc array', + 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has rc key with missing or empty array', exc_exec(sdrcmd()) ) end) @@ -421,7 +366,7 @@ describe('ShaDa error handling', function() it('fails on history item with NIL value', function() wshada('\004\000\001\192') eq( - 'Vim(rshada):E575: Error while reading ShaDa file: history entry at position 0 is not an array', + 'Vim(rshada):E575: Error while reading ShaDa file: history entry at position 0 is not an array with enough elements', exc_exec(sdrcmd()) ) end) @@ -429,7 +374,7 @@ describe('ShaDa error handling', function() it('fails on history item with empty value', function() wshada('\004\000\001\144') eq( - 'Vim(rshada):E575: Error while reading ShaDa file: history entry at position 0 does not have enough elements', + 'Vim(rshada):E575: Error while reading ShaDa file: history entry at position 0 is not an array with enough elements', exc_exec(sdrcmd()) ) end) @@ -437,7 +382,7 @@ describe('ShaDa error handling', function() it('fails on history item with single element value', function() wshada('\004\000\002\145\000') eq( - 'Vim(rshada):E575: Error while reading ShaDa file: history entry at position 0 does not have enough elements', + 'Vim(rshada):E575: Error while reading ShaDa file: history entry at position 0 is not an array with enough elements', exc_exec(sdrcmd()) ) end) @@ -485,7 +430,7 @@ describe('ShaDa error handling', function() it('fails on variable item with NIL value', function() wshada('\006\000\001\192') eq( - 'Vim(rshada):E575: Error while reading ShaDa file: variable entry at position 0 is not an array', + 'Vim(rshada):E575: Error while reading ShaDa file: variable entry at position 0 is not an array with enough elements', exc_exec(sdrcmd()) ) end) @@ -493,7 +438,7 @@ describe('ShaDa error handling', function() it('fails on variable item with empty value', function() wshada('\006\000\001\144') eq( - 'Vim(rshada):E575: Error while reading ShaDa file: variable entry at position 0 does not have enough elements', + 'Vim(rshada):E575: Error while reading ShaDa file: variable entry at position 0 is not an array with enough elements', exc_exec(sdrcmd()) ) end) @@ -501,7 +446,7 @@ describe('ShaDa error handling', function() it('fails on variable item with single element value', function() wshada('\006\000\002\145\000') eq( - 'Vim(rshada):E575: Error while reading ShaDa file: variable entry at position 0 does not have enough elements', + 'Vim(rshada):E575: Error while reading ShaDa file: variable entry at position 0 is not an array with enough elements', exc_exec(sdrcmd()) ) end) @@ -525,7 +470,7 @@ describe('ShaDa error handling', function() it('fails on replacement item with NIL value', function() wshada('\003\000\001\192') eq( - 'Vim(rshada):E575: Error while reading ShaDa file: sub string entry at position 0 is not an array', + 'Vim(rshada):E575: Error while reading ShaDa file: sub string entry at position 0 is not an array with enough elements', exc_exec(sdrcmd()) ) end) @@ -533,7 +478,7 @@ describe('ShaDa error handling', function() it('fails on replacement item with empty value', function() wshada('\003\000\001\144') eq( - 'Vim(rshada):E575: Error while reading ShaDa file: sub string entry at position 0 does not have enough elements', + 'Vim(rshada):E575: Error while reading ShaDa file: sub string entry at position 0 is not an array with enough elements', exc_exec(sdrcmd()) ) end) @@ -577,7 +522,7 @@ describe('ShaDa error handling', function() nvim_command('set shada+=%') wshada('\009\000\017\146\129\161f\196\001/\130\161f\196\002/a\161l\192') eq( - 'Vim(rshada):E575: Error while reading ShaDa file: buffer list entry entry at position 0 has l key value which is not an integer', + 'Vim(rshada):E575: Error while reading ShaDa file: buffer list at position 0 contains entry that has l key value which is not an integer', exc_exec(sdrcmd()) ) end) @@ -613,7 +558,7 @@ describe('ShaDa error handling', function() nvim_command('set shada+=%') wshada('\009\000\017\146\129\161f\196\001/\130\161f\196\002/a\161c\192') eq( - 'Vim(rshada):E575: Error while reading ShaDa file: buffer list entry entry at position 0 has c key value which is not an integer', + 'Vim(rshada):E575: Error while reading ShaDa file: buffer list at position 0 contains entry that has c key value which is not an integer', exc_exec(sdrcmd()) ) end) -- cgit From 93347a67bf913c72ab2c1ba0aa4b26cc4ba6d1a8 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 6 Aug 2024 22:20:26 +0800 Subject: fix(filetype): fix :filetype detect error with -u NONE (#29991) :filetype detect should enable filetype detection when it hasn't been enabled before. --- test/functional/core/startup_spec.lua | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'test/functional') diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua index 45f8294b16..8d6ba9712a 100644 --- a/test/functional/core/startup_spec.lua +++ b/test/functional/core/startup_spec.lua @@ -112,6 +112,13 @@ describe('startup', function() |*2 ]]) end) + + it(':filetype detect enables filetype detection with -u NONE', function() + clear() + eq('filetype detection:OFF plugin:OFF indent:OFF', exec_capture('filetype')) + command('filetype detect') + eq('filetype detection:ON plugin:OFF indent:OFF', exec_capture('filetype')) + end) end) describe('startup', function() -- cgit From 8df6736ca14d09f87cf0a8486758ac5708819434 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Wed, 24 May 2023 10:04:49 +0200 Subject: feat(term): enable reflow by default (#21124) Problem: Contents of terminal buffer are not reflown when Nvim is resized. Solution: Enable reflow in libvterm by default. Now that libvterm is vendored, also fix "TUI rapid resize" test failures there. Note: Neovim's scrollback buffer does not support reflow (yet), so lines vanishing into the buffer due to a too small window will be restored without reflow. --- test/functional/terminal/window_spec.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'test/functional') diff --git a/test/functional/terminal/window_spec.lua b/test/functional/terminal/window_spec.lua index 64534ca8dc..18477fdf2d 100644 --- a/test/functional/terminal/window_spec.lua +++ b/test/functional/terminal/window_spec.lua @@ -87,7 +87,7 @@ describe(':terminal window', function() {7: 1 }tty ready | {7: 2 }rows: 6, cols: 48 | {7: 3 }abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO| - {7: 4 }WXYZrows: 6, cols: 41 | + {7: 4 }PQRSTUVWXYZrows: 6, cols: 41 | {7: 5 }{1: } | {7: 6 } | {3:-- TERMINAL --} | @@ -97,7 +97,7 @@ describe(':terminal window', function() {7: 1 }tty ready | {7: 2 }rows: 6, cols: 48 | {7: 3 }abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO| - {7: 4 }WXYZrows: 6, cols: 41 | + {7: 4 }PQRSTUVWXYZrows: 6, cols: 41 | {7: 5 } abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMN| {7: 6 }OPQRSTUVWXYZ{1: } | {3:-- TERMINAL --} | @@ -132,9 +132,9 @@ describe(':terminal window', function() screen:expect([[ {7:++ 7 } | {7:++ 8 }abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR| - {7:++ 9 }TUVWXYZ | + {7:++ 9 }STUVWXYZ | {7:++10 }abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR| - {7:++11 }TUVWXYZrows: 6, cols: 44 | + {7:++11 }STUVWXYZrows: 6, cols: 44 | {7:++12 }{1: } | {3:-- TERMINAL --} | ]]) -- cgit From 9b5ab66678f8efa1f5fe89205839fe053fe5efaf Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Sun, 11 Aug 2024 11:58:15 +0100 Subject: test(lsp): refactor and tidy - Merge all the top level 'LSP' describe blocks - Refactor text edit tests - Fix typing errors - Add linebreaks between tests --- test/functional/plugin/lsp/testutil.lua | 119 +++---- test/functional/plugin/lsp_spec.lua | 573 +++++++++++++++++--------------- 2 files changed, 362 insertions(+), 330 deletions(-) (limited to 'test/functional') diff --git a/test/functional/plugin/lsp/testutil.lua b/test/functional/plugin/lsp/testutil.lua index 3430a1e1a3..2595f6ad09 100644 --- a/test/functional/plugin/lsp/testutil.lua +++ b/test/functional/plugin/lsp/testutil.lua @@ -21,8 +21,8 @@ function M.clear_notrace() } end -M.create_server_definition = [[ - function _create_server(opts) +M.create_server_definition = function() + function _G._create_server(opts) opts = opts or {} local server = {} server.messages = {} @@ -42,7 +42,7 @@ M.create_server_definition = [[ handler(method, params, callback) elseif method == 'initialize' then callback(nil, { - capabilities = opts.capabilities or {} + capabilities = opts.capabilities or {}, }) elseif method == 'shutdown' then callback(nil, nil) @@ -54,7 +54,7 @@ M.create_server_definition = [[ function srv.notify(method, params) table.insert(server.messages, { method = method, - params = params + params = params, }) if method == 'exit' then dispatchers.on_exit(0, 15) @@ -74,7 +74,7 @@ M.create_server_definition = [[ return server end -]] +end -- Fake LSP server. M.fake_lsp_code = 'test/functional/fixtures/fake-lsp-server.lua' @@ -82,48 +82,53 @@ M.fake_lsp_logfile = 'Xtest-fake-lsp.log' local function fake_lsp_server_setup(test_name, timeout_ms, options, settings) exec_lua( - [=[ - lsp = require('vim.lsp') - local test_name, fake_lsp_code, fake_lsp_logfile, timeout, options, settings = ... - TEST_RPC_CLIENT_ID = lsp.start_client { - cmd_env = { - NVIM_LOG_FILE = fake_lsp_logfile; - NVIM_LUA_NOTRACK = "1"; - NVIM_APPNAME = "nvim_lsp_test"; - }; - cmd = { - vim.v.progpath, '-l', fake_lsp_code, test_name, tostring(timeout), - }; - handlers = setmetatable({}, { - __index = function(t, method) - return function(...) - return vim.rpcrequest(1, 'handler', ...) - end - end; - }); - workspace_folders = {{ - uri = 'file://' .. vim.uv.cwd(), - name = 'test_folder', - }}; - before_init = function(params, config) - vim.schedule(function() - vim.rpcrequest(1, "setup") - end) - end, - on_init = function(client, result) - TEST_RPC_CLIENT = client - vim.rpcrequest(1, "init", result) - end; - flags = { - allow_incremental_sync = options.allow_incremental_sync or false; - debounce_text_changes = options.debounce_text_changes or 0; - }; - settings = settings; - on_exit = function(...) - vim.rpcnotify(1, "exit", ...) - end; - } - ]=], + function(test_name0, fake_lsp_code0, fake_lsp_logfile0, timeout, options0, settings0) + _G.lsp = require('vim.lsp') + _G.TEST_RPC_CLIENT_ID = _G.lsp.start_client { + cmd_env = { + NVIM_LOG_FILE = fake_lsp_logfile0, + NVIM_LUA_NOTRACK = '1', + NVIM_APPNAME = 'nvim_lsp_test', + }, + cmd = { + vim.v.progpath, + '-l', + fake_lsp_code0, + test_name0, + tostring(timeout), + }, + handlers = setmetatable({}, { + __index = function(_t, _method) + return function(...) + return vim.rpcrequest(1, 'handler', ...) + end + end, + }), + workspace_folders = { + { + uri = 'file://' .. vim.uv.cwd(), + name = 'test_folder', + }, + }, + before_init = function(_params, _config) + vim.schedule(function() + vim.rpcrequest(1, 'setup') + end) + end, + on_init = function(client, result) + _G.TEST_RPC_CLIENT = client + vim.rpcrequest(1, 'init', result) + end, + flags = { + allow_incremental_sync = options0.allow_incremental_sync or false, + debounce_text_changes = options0.debounce_text_changes or 0, + }, + settings = settings0, + on_exit = function(...) + vim.rpcnotify(1, 'exit', ...) + end, + } + end, test_name, M.fake_lsp_code, M.fake_lsp_logfile, @@ -160,18 +165,14 @@ function M.test_rpc_server(config) -- Workaround for not being able to yield() inside __index for Lua 5.1 :( -- Otherwise I would just return the value here. return function(...) - return exec_lua( - [=[ - local name = ... - if type(TEST_RPC_CLIENT[name]) == 'function' then - return TEST_RPC_CLIENT[name](select(2, ...)) - else - return TEST_RPC_CLIENT[name] - end - ]=], - name, - ... - ) + return exec_lua(function(...) + local name0 = ... + if type(_G.TEST_RPC_CLIENT[name0]) == 'function' then + return _G.TEST_RPC_CLIENT[name0](select(2, ...)) + else + return _G.TEST_RPC_CLIENT[name0] + end + end, name, ...) end end, }) diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 83db4f303c..06e286f872 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -41,54 +41,80 @@ local function get_buf_option(name, bufnr) ) end +local function make_edit(y_0, x_0, y_1, x_1, text) + return { + range = { + start = { line = y_0, character = x_0 }, + ['end'] = { line = y_1, character = x_1 }, + }, + newText = type(text) == 'table' and table.concat(text, '\n') or (text or ''), + } +end + +--- @param edits [integer, integer, integer, integer, string|string[]][] +--- @param encoding? string +local function apply_text_edits(edits, encoding) + local edits1 = vim.tbl_map( + --- @param edit [integer, integer, integer, integer, string|string[]] + function(edit) + return make_edit(unpack(edit)) + end, + edits + ) + exec_lua('vim.lsp.util.apply_text_edits(...)', edits1, 1, encoding or 'utf-16') +end + -- TODO(justinmk): hangs on Windows https://github.com/neovim/neovim/pull/11837 if skip(is_os('win')) then return end -teardown(function() - os.remove(fake_lsp_logfile) -end) - describe('LSP', function() before_each(function() clear_notrace() - - -- Run an instance of nvim on the file which contains our "scripts". - -- Pass TEST_NAME to pick the script. - local test_name = 'basic_init' - exec_lua(function(test_name0, fake_lsp_code0, fake_lsp_logfile0) - _G.lsp = require('vim.lsp') - function _G.test__start_client() - return vim.lsp.start_client { - cmd_env = { - NVIM_LOG_FILE = fake_lsp_logfile0, - NVIM_APPNAME = 'nvim_lsp_test', - }, - cmd = { - vim.v.progpath, - '-l', - fake_lsp_code0, - test_name0, - }, - workspace_folders = { - { - uri = 'file://' .. vim.uv.cwd(), - name = 'test_folder', - }, - }, - } - end - _G.TEST_CLIENT1 = _G.test__start_client() - end, test_name, fake_lsp_code, fake_lsp_logfile) end) after_each(function() + stop() + exec_lua('lsp.stop_client(lsp.get_clients(), true)') api.nvim_exec_autocmds('VimLeavePre', { modeline = false }) - -- exec_lua("lsp.stop_all_clients(true)") + end) + + teardown(function() + os.remove(fake_lsp_logfile) end) describe('server_name specified', function() + before_each(function() + -- Run an instance of nvim on the file which contains our "scripts". + -- Pass TEST_NAME to pick the script. + local test_name = 'basic_init' + exec_lua(function(test_name0, fake_lsp_code0, fake_lsp_logfile0) + _G.lsp = require('vim.lsp') + function _G.test__start_client() + return vim.lsp.start_client { + cmd_env = { + NVIM_LOG_FILE = fake_lsp_logfile0, + NVIM_APPNAME = 'nvim_lsp_test', + }, + cmd = { + vim.v.progpath, + '-l', + fake_lsp_code0, + test_name0, + }, + workspace_folders = { + { + uri = 'file://' .. vim.uv.cwd(), + name = 'test_folder', + }, + }, + } + end + _G.TEST_CLIENT1 = _G.test__start_client() + end, test_name, fake_lsp_code, fake_lsp_logfile) + end) + it('start_client(), stop_client()', function() retry(nil, 4000, function() eq(1, exec_lua('return #lsp.get_clients()')) @@ -140,16 +166,8 @@ describe('LSP', function() end) end) end) -end) -describe('LSP', function() describe('basic_init test', function() - after_each(function() - stop() - exec_lua('lsp.stop_client(lsp.get_clients(), true)') - api.nvim_exec_autocmds('VimLeavePre', { modeline = false }) - end) - it('should run correctly', function() local expected_handlers = { { NIL, {}, { method = 'test', client_id = 1 } }, @@ -321,13 +339,13 @@ describe('LSP', function() _G.BUFFER = vim.api.nvim_create_buf(false, true) vim.api.nvim_create_autocmd('LspAttach', { callback = function(args) - local client0 = vim.lsp.get_client_by_id(args.data.client_id) + local client0 = assert(vim.lsp.get_client_by_id(args.data.client_id)) vim.g.lsp_attached = client0.name end, }) vim.api.nvim_create_autocmd('LspDetach', { callback = function(args) - local client0 = vim.lsp.get_client_by_id(args.data.client_id) + local client0 = assert(vim.lsp.get_client_by_id(args.data.client_id)) vim.g.lsp_detached = client0.name end, }) @@ -482,7 +500,7 @@ describe('LSP', function() }) local client_id = vim.lsp.start({ name = 'detach-dummy', cmd = server.cmd }) assert(client_id, 'lsp.start must return client_id') - local client = vim.lsp.get_client_by_id(client_id) + local client = assert(vim.lsp.get_client_by_id(client_id)) local num_attached_before = vim.tbl_count(client.attached_buffers) vim.api.nvim_buf_delete(bufnr, { force = true }) local num_attached_after = vim.tbl_count(client.attached_buffers) @@ -515,14 +533,14 @@ describe('LSP', function() }) local bufnr = vim.api.nvim_create_buf(false, true) local on_init_called = false - local client_id = vim.lsp.start({ + local client_id = assert(vim.lsp.start({ name = 'detach-dummy', cmd = server.cmd, on_init = function() vim.api.nvim_buf_delete(bufnr, {}) on_init_called = true end, - }) + })) vim.lsp.buf_attach_client(bufnr, client_id) local ok = vim.wait(1000, function() return on_init_called @@ -616,6 +634,7 @@ describe('LSP', function() end, } end) + it( 'workspace/configuration returns NIL per section if client was started without config.settings', function() @@ -710,7 +729,7 @@ describe('LSP', function() }, }, }) - local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) + local client_id = assert(vim.lsp.start({ name = 'dummy', cmd = server.cmd })) local buf = vim.api.nvim_get_current_buf() vim.api.nvim_exec_autocmds('BufWritePre', { buffer = buf, modeline = false }) vim.lsp.stop_client(client_id) @@ -748,7 +767,7 @@ describe('LSP', function() }, }) local buf = vim.api.nvim_get_current_buf() - local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) + local client_id = assert(vim.lsp.start({ name = 'dummy', cmd = server.cmd })) vim.api.nvim_exec_autocmds('BufWritePre', { buffer = buf, modeline = false }) vim.lsp.stop_client(client_id) return { @@ -1487,6 +1506,7 @@ describe('LSP', function() end, } end) + it('should check the body and didChange incremental with debounce', function() local expected_handlers = { { NIL, {}, { method = 'shutdown', client_id = 1 } }, @@ -1761,75 +1781,59 @@ describe('LSP', function() } end) end) -end) - -describe('LSP', function() - before_each(function() - clear_notrace() - end) - - local function make_edit(y_0, x_0, y_1, x_1, text) - return { - range = { - start = { line = y_0, character = x_0 }, - ['end'] = { line = y_1, character = x_1 }, - }, - newText = type(text) == 'table' and table.concat(text, '\n') or (text or ''), - } - end describe('apply vscode text_edits', function() it('single replace', function() insert('012345678901234567890123456789') - local edits = { - make_edit(0, 3, 0, 6, { 'Hello' }), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 0, 3, 0, 6, { 'Hello' } }, + }) eq({ '012Hello678901234567890123456789' }, buf_lines(1)) end) + it('two replaces', function() insert('012345678901234567890123456789') - local edits = { - make_edit(0, 3, 0, 6, { 'Hello' }), - make_edit(0, 6, 0, 9, { 'World' }), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 0, 3, 0, 6, { 'Hello' } }, + { 0, 6, 0, 9, { 'World' } }, + }) eq({ '012HelloWorld901234567890123456789' }, buf_lines(1)) end) + it('same start pos insert are kept in order', function() insert('012345678901234567890123456789') - local edits1 = { - make_edit(0, 3, 0, 3, { 'World' }), - make_edit(0, 3, 0, 3, { 'Hello' }), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits1, 1, 'utf-16') + apply_text_edits({ + { 0, 3, 0, 3, { 'World' } }, + { 0, 3, 0, 3, { 'Hello' } }, + }) eq({ '012WorldHello345678901234567890123456789' }, buf_lines(1)) end) + it('same start pos insert and replace are kept in order', function() insert('012345678901234567890123456789') - local edits1 = { - make_edit(0, 3, 0, 3, { 'World' }), - make_edit(0, 3, 0, 3, { 'Hello' }), - make_edit(0, 3, 0, 8, { 'No' }), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits1, 1, 'utf-16') + apply_text_edits({ + { 0, 3, 0, 3, { 'World' } }, + { 0, 3, 0, 3, { 'Hello' } }, + { 0, 3, 0, 8, { 'No' } }, + }) eq({ '012WorldHelloNo8901234567890123456789' }, buf_lines(1)) end) + it('multiline', function() exec_lua(function() vim.api.nvim_buf_set_lines(1, 0, 0, true, { ' {', ' "foo": "bar"', ' }' }) end) eq({ ' {', ' "foo": "bar"', ' }', '' }, buf_lines(1)) - local edits = { - make_edit(0, 0, 3, 0, { '' }), - make_edit(3, 0, 3, 0, { '{\n' }), - make_edit(3, 0, 3, 0, { ' "foo": "bar"\n' }), - make_edit(3, 0, 3, 0, { '}\n' }), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 0, 0, 3, 0, { '' } }, + { 3, 0, 3, 0, { '{\n' } }, + { 3, 0, 3, 0, { ' "foo": "bar"\n' } }, + { 3, 0, 3, 0, { '}\n' } }, + }) eq({ '{', ' "foo": "bar"', '}', '' }, buf_lines(1)) end) end) + describe('apply_text_edits', function() before_each(function() insert(dedent([[ @@ -1839,14 +1843,14 @@ describe('LSP', function() Fourth line of text å å ɧ 汉语 ↥ 🤦 🦄]])) end) + it('applies simple edits', function() - local edits = { - make_edit(0, 0, 0, 0, { '123' }), - make_edit(1, 0, 1, 1, { '2' }), - make_edit(2, 0, 2, 2, { '3' }), - make_edit(3, 2, 3, 4, { '' }), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 0, 0, 0, 0, { '123' } }, + { 1, 0, 1, 1, { '2' } }, + { 2, 0, 2, 2, { '3' } }, + { 3, 2, 3, 4, { '' } }, + }) eq({ '123First line of text', '2econd line of text', @@ -1855,18 +1859,18 @@ describe('LSP', function() 'å å ɧ 汉语 ↥ 🤦 🦄', }, buf_lines(1)) end) + it('applies complex edits', function() - local edits = { - make_edit(0, 0, 0, 0, { '', '12' }), - make_edit(0, 0, 0, 0, { '3', 'foo' }), - make_edit(0, 1, 0, 1, { 'bar', '123' }), - make_edit(0, #'First ', 0, #'First line of text', { 'guy' }), - make_edit(1, 0, 1, #'Second', { 'baz' }), - make_edit(2, #'Th', 2, #'Third', { 'e next' }), - make_edit(3, #'', 3, #'Fourth', { 'another line of text', 'before this' }), - make_edit(3, #'Fourth', 3, #'Fourth line of text', { '!' }), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 0, 0, 0, 0, { '', '12' } }, + { 0, 0, 0, 0, { '3', 'foo' } }, + { 0, 1, 0, 1, { 'bar', '123' } }, + { 0, #'First ', 0, #'First line of text', { 'guy' } }, + { 1, 0, 1, #'Second', { 'baz' } }, + { 2, #'Th', 2, #'Third', { 'e next' } }, + { 3, #'', 3, #'Fourth', { 'another line of text', 'before this' } }, + { 3, #'Fourth', 3, #'Fourth line of text', { '!' } }, + }) eq({ '', '123', @@ -1879,18 +1883,18 @@ describe('LSP', function() 'å å ɧ 汉语 ↥ 🤦 🦄', }, buf_lines(1)) end) + it('applies complex edits (reversed range)', function() - local edits = { - make_edit(0, 0, 0, 0, { '', '12' }), - make_edit(0, 0, 0, 0, { '3', 'foo' }), - make_edit(0, 1, 0, 1, { 'bar', '123' }), - make_edit(0, #'First line of text', 0, #'First ', { 'guy' }), - make_edit(1, #'Second', 1, 0, { 'baz' }), - make_edit(2, #'Third', 2, #'Th', { 'e next' }), - make_edit(3, #'Fourth', 3, #'', { 'another line of text', 'before this' }), - make_edit(3, #'Fourth line of text', 3, #'Fourth', { '!' }), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 0, 0, 0, 0, { '', '12' } }, + { 0, 0, 0, 0, { '3', 'foo' } }, + { 0, 1, 0, 1, { 'bar', '123' } }, + { 0, #'First line of text', 0, #'First ', { 'guy' } }, + { 1, #'Second', 1, 0, { 'baz' } }, + { 2, #'Third', 2, #'Th', { 'e next' } }, + { 3, #'Fourth', 3, #'', { 'another line of text', 'before this' } }, + { 3, #'Fourth line of text', 3, #'Fourth', { '!' } }, + }) eq({ '', '123', @@ -1903,11 +1907,11 @@ describe('LSP', function() 'å å ɧ 汉语 ↥ 🤦 🦄', }, buf_lines(1)) end) + it('applies non-ASCII characters edits', function() - local edits = { - make_edit(4, 3, 4, 4, { 'ä' }), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 4, 3, 4, 4, { 'ä' } }, + }) eq({ 'First line of text', 'Second line of text', @@ -1916,11 +1920,11 @@ describe('LSP', function() 'å ä ɧ 汉语 ↥ 🤦 🦄', }, buf_lines(1)) end) + it('applies text edits at the end of the document', function() - local edits = { - make_edit(5, 0, 5, 0, 'foobar'), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 5, 0, 5, 0, 'foobar' }, + }) eq({ 'First line of text', 'Second line of text', @@ -1930,12 +1934,12 @@ describe('LSP', function() 'foobar', }, buf_lines(1)) end) + it('applies multiple text edits at the end of the document', function() - local edits = { - make_edit(4, 0, 5, 0, ''), - make_edit(5, 0, 5, 0, 'foobar'), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 4, 0, 5, 0, '' }, + { 5, 0, 5, 0, 'foobar' }, + }) eq({ 'First line of text', 'Second line of text', @@ -1944,62 +1948,56 @@ describe('LSP', function() 'foobar', }, buf_lines(1)) end) + it('it restores marks', function() - local edits = { - make_edit(1, 0, 2, 5, 'foobar'), - make_edit(4, 0, 5, 0, 'barfoo'), - } eq(true, api.nvim_buf_set_mark(1, 'a', 2, 1, {})) - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 1, 0, 2, 5, 'foobar' }, + { 4, 0, 5, 0, 'barfoo' }, + }) eq({ 'First line of text', 'foobar line of text', 'Fourth line of text', 'barfoo', }, buf_lines(1)) - local mark = api.nvim_buf_get_mark(1, 'a') - eq({ 2, 1 }, mark) + eq({ 2, 1 }, api.nvim_buf_get_mark(1, 'a')) end) it('it restores marks to last valid col', function() - local edits = { - make_edit(1, 0, 2, 15, 'foobar'), - make_edit(4, 0, 5, 0, 'barfoo'), - } eq(true, api.nvim_buf_set_mark(1, 'a', 2, 10, {})) - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 1, 0, 2, 15, 'foobar' }, + { 4, 0, 5, 0, 'barfoo' }, + }) eq({ 'First line of text', 'foobarext', 'Fourth line of text', 'barfoo', }, buf_lines(1)) - local mark = api.nvim_buf_get_mark(1, 'a') - eq({ 2, 9 }, mark) + eq({ 2, 9 }, api.nvim_buf_get_mark(1, 'a')) end) it('it restores marks to last valid line', function() - local edits = { - make_edit(1, 0, 4, 5, 'foobar'), - make_edit(4, 0, 5, 0, 'barfoo'), - } eq(true, api.nvim_buf_set_mark(1, 'a', 4, 1, {})) - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 1, 0, 4, 5, 'foobar' }, + { 4, 0, 5, 0, 'barfoo' }, + }) eq({ 'First line of text', 'foobaro', }, buf_lines(1)) - local mark = api.nvim_buf_get_mark(1, 'a') - eq({ 2, 1 }, mark) + eq({ 2, 1 }, api.nvim_buf_get_mark(1, 'a')) end) describe('cursor position', function() it("don't fix the cursor if the range contains the cursor", function() api.nvim_win_set_cursor(0, { 2, 6 }) - local edits = { - make_edit(1, 0, 1, 19, 'Second line of text'), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 1, 0, 1, 19, 'Second line of text' }, + }) eq({ 'First line of text', 'Second line of text', @@ -2012,11 +2010,10 @@ describe('LSP', function() it('fix the cursor to the valid col if the content was removed', function() api.nvim_win_set_cursor(0, { 2, 6 }) - local edits = { - make_edit(1, 0, 1, 6, ''), - make_edit(1, 6, 1, 19, ''), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 1, 0, 1, 6, '' }, + { 1, 6, 1, 19, '' }, + }) eq({ 'First line of text', '', @@ -2029,11 +2026,10 @@ describe('LSP', function() it('fix the cursor to the valid row if the content was removed', function() api.nvim_win_set_cursor(0, { 2, 6 }) - local edits = { - make_edit(1, 0, 1, 6, ''), - make_edit(0, 18, 5, 0, ''), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 1, 0, 1, 6, '' }, + { 0, 18, 5, 0, '' }, + }) eq({ 'First line of text', }, buf_lines(1)) @@ -2042,10 +2038,9 @@ describe('LSP', function() it('fix the cursor row', function() api.nvim_win_set_cursor(0, { 3, 0 }) - local edits = { - make_edit(1, 0, 2, 0, ''), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 1, 0, 2, 0, '' }, + }) eq({ 'First line of text', 'Third line of text', @@ -2060,10 +2055,9 @@ describe('LSP', function() api.nvim_buf_set_lines(1, -1, -1, true, { '' }) api.nvim_win_set_cursor(0, { 2, 11 }) - local edits = { - make_edit(1, 7, 1, 11, ''), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 1, 7, 1, 11, '' }, + }) eq({ 'First line of text', 'Second of text', @@ -2077,10 +2071,9 @@ describe('LSP', function() it('fix the cursor row and col', function() api.nvim_win_set_cursor(0, { 2, 12 }) - local edits = { - make_edit(0, 11, 1, 12, ''), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 0, 11, 1, 12, '' }, + }) eq({ 'First line of text', 'Third line of text', @@ -2093,24 +2086,23 @@ describe('LSP', function() describe('with LSP end line after what Vim considers to be the end line', function() it('applies edits when the last linebreak is considered a new line', function() - local edits = { - make_edit(0, 0, 5, 0, { 'All replaced' }), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 0, 0, 5, 0, { 'All replaced' } }, + }) eq({ 'All replaced' }, buf_lines(1)) end) + it("applies edits when the end line is 2 larger than vim's", function() - local edits = { - make_edit(0, 0, 6, 0, { 'All replaced' }), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 0, 0, 6, 0, { 'All replaced' } }, + }) eq({ 'All replaced' }, buf_lines(1)) end) + it('applies edits with a column offset', function() - local edits = { - make_edit(0, 0, 5, 2, { 'All replaced' }), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 0, 0, 5, 2, { 'All replaced' } }, + }) eq({ 'All replaced' }, buf_lines(1)) end) end) @@ -2122,38 +2114,38 @@ describe('LSP', function() Test line one Test line two 21 char]])) end) + describe('with LSP end column out of bounds and start column at 0', function() it('applies edits at the end of the buffer', function() - local edits = { - make_edit(0, 0, 1, 22, { '#include "whatever.h"\r\n#include \r' }), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-8') + apply_text_edits({ + { 0, 0, 1, 22, { '#include "whatever.h"\r\n#include \r' } }, + }, 'utf-8') eq({ '#include "whatever.h"', '#include ' }, buf_lines(1)) end) + it('applies edits in the middle of the buffer', function() - local edits = { - make_edit(0, 0, 0, 22, { '#include "whatever.h"\r\n#include \r' }), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-8') + apply_text_edits({ + { 0, 0, 0, 22, { '#include "whatever.h"\r\n#include \r' } }, + }, 'utf-8') eq( { '#include "whatever.h"', '#include ', 'Test line two 21 char' }, buf_lines(1) ) end) end) + describe('with LSP end column out of bounds and start column NOT at 0', function() it('applies edits at the end of the buffer', function() - local edits = { - make_edit(0, 2, 1, 22, { '#include "whatever.h"\r\n#include \r' }), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-8') + apply_text_edits({ + { 0, 2, 1, 22, { '#include "whatever.h"\r\n#include \r' } }, + }, 'utf-8') eq({ 'Te#include "whatever.h"', '#include ' }, buf_lines(1)) end) + it('applies edits in the middle of the buffer', function() - local edits = { - make_edit(0, 2, 0, 22, { '#include "whatever.h"\r\n#include \r' }), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-8') + apply_text_edits({ + { 0, 2, 0, 22, { '#include "whatever.h"\r\n#include \r' } }, + }, 'utf-8') eq( { 'Te#include "whatever.h"', '#include ', 'Test line two 21 char' }, buf_lines(1) @@ -2164,6 +2156,7 @@ describe('LSP', function() describe('apply_text_document_edit', function() local target_bufnr --- @type integer + local text_document_edit = function(editVersion) return { edits = { @@ -2175,6 +2168,7 @@ describe('LSP', function() }, } end + before_each(function() target_bufnr = exec_lua(function() local bufnr = vim.uri_to_bufnr('file:///fake/uri') @@ -2183,6 +2177,7 @@ describe('LSP', function() return bufnr end) end) + it('correctly goes ahead with the edit if all is normal', function() exec_lua("vim.lsp.util.apply_text_document_edit(..., nil, 'utf-16')", text_document_edit(5)) eq({ @@ -2190,6 +2185,7 @@ describe('LSP', function() '2nd line of 语text', }, buf_lines(target_bufnr)) end) + it('always accepts edit with version = 0', function() exec_lua(function(bufnr, text_edit) vim.lsp.util.buf_versions[bufnr] = 10 @@ -2200,6 +2196,7 @@ describe('LSP', function() '2nd line of 语text', }, buf_lines(target_bufnr)) end) + it('skips the edit if the version of the edit is behind the local buffer ', function() local apply_edit_mocking_current_version = function(edit, versionedBuf) exec_lua(function(edit0, versionedBuf0) @@ -2371,6 +2368,7 @@ describe('LSP', function() end, make_workspace_edit(edits), target_bufnr) ) end) + it('Supports file creation with CreateFile payload', function() local tmpfile = tmpname() os.remove(tmpfile) -- Should not exist, only interested in a tmpname @@ -2386,6 +2384,7 @@ describe('LSP', function() exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit, 'utf-16') eq(true, vim.uv.fs_stat(tmpfile) ~= nil) end) + it( 'Supports file creation in folder that needs to be created with CreateFile payload', function() @@ -2405,6 +2404,7 @@ describe('LSP', function() eq(true, vim.uv.fs_stat(tmpfile) ~= nil) end ) + it('createFile does not touch file if it exists and ignoreIfExists is set', function() local tmpfile = tmpname() write_file(tmpfile, 'Dummy content') @@ -2424,6 +2424,7 @@ describe('LSP', function() eq(true, vim.uv.fs_stat(tmpfile) ~= nil) eq('Dummy content', read_file(tmpfile)) end) + it('createFile overrides file if overwrite is set', function() local tmpfile = tmpname() write_file(tmpfile, 'Dummy content') @@ -2444,6 +2445,7 @@ describe('LSP', function() eq(true, vim.uv.fs_stat(tmpfile) ~= nil) eq('', read_file(tmpfile)) end) + it('DeleteFile delete file and buffer', function() local tmpfile = tmpname() write_file(tmpfile, 'Be gone') @@ -2464,6 +2466,7 @@ describe('LSP', function() eq(false, vim.uv.fs_stat(tmpfile) ~= nil) eq(false, api.nvim_buf_is_loaded(fn.bufadd(tmpfile))) end) + it('DeleteFile fails if file does not exist and ignoreIfNotExists is false', function() local tmpfile = tmpname() os.remove(tmpfile) @@ -2508,6 +2511,7 @@ describe('LSP', function() eq(true, exists) os.remove(new) end) + it('Can rename a directory', function() -- only reserve the name, file must not exist for the test scenario local old_dir = tmpname() @@ -2536,6 +2540,7 @@ describe('LSP', function() os.remove(new_dir) end) + it('Does not touch buffers that do not match path prefix', function() local old = tmpname() local new = tmpname() @@ -2543,32 +2548,35 @@ describe('LSP', function() os.remove(new) n.mkdir_p(old) - local result = exec_lua(function(old0, new0) - local old_prefixed = 'explorer://' .. old0 - local old_suffixed = old0 .. '.bak' - local new_prefixed = 'explorer://' .. new0 - local new_suffixed = new0 .. '.bak' - - local old_prefixed_buf = vim.fn.bufadd(old_prefixed) - local old_suffixed_buf = vim.fn.bufadd(old_suffixed) - local new_prefixed_buf = vim.fn.bufadd(new_prefixed) - local new_suffixed_buf = vim.fn.bufadd(new_suffixed) - - vim.lsp.util.rename(old0, new0) - - return vim.api.nvim_buf_is_valid(old_prefixed_buf) - and vim.api.nvim_buf_is_valid(old_suffixed_buf) - and vim.api.nvim_buf_is_valid(new_prefixed_buf) - and vim.api.nvim_buf_is_valid(new_suffixed_buf) - and vim.api.nvim_buf_get_name(old_prefixed_buf) == old_prefixed - and vim.api.nvim_buf_get_name(old_suffixed_buf) == old_suffixed - and vim.api.nvim_buf_get_name(new_prefixed_buf) == new_prefixed - and vim.api.nvim_buf_get_name(new_suffixed_buf) == new_suffixed - end, old, new) - eq(true, result) + eq( + true, + exec_lua(function(old0, new0) + local old_prefixed = 'explorer://' .. old0 + local old_suffixed = old0 .. '.bak' + local new_prefixed = 'explorer://' .. new0 + local new_suffixed = new0 .. '.bak' + + local old_prefixed_buf = vim.fn.bufadd(old_prefixed) + local old_suffixed_buf = vim.fn.bufadd(old_suffixed) + local new_prefixed_buf = vim.fn.bufadd(new_prefixed) + local new_suffixed_buf = vim.fn.bufadd(new_suffixed) + + vim.lsp.util.rename(old0, new0) + + return vim.api.nvim_buf_is_valid(old_prefixed_buf) + and vim.api.nvim_buf_is_valid(old_suffixed_buf) + and vim.api.nvim_buf_is_valid(new_prefixed_buf) + and vim.api.nvim_buf_is_valid(new_suffixed_buf) + and vim.api.nvim_buf_get_name(old_prefixed_buf) == old_prefixed + and vim.api.nvim_buf_get_name(old_suffixed_buf) == old_suffixed + and vim.api.nvim_buf_get_name(new_prefixed_buf) == new_prefixed + and vim.api.nvim_buf_get_name(new_suffixed_buf) == new_suffixed + end, old, new) + ) os.remove(new) end) + it( 'Does not rename file if target exists and ignoreIfExists is set or overwrite is false', function() @@ -2592,6 +2600,7 @@ describe('LSP', function() eq('New file', read_file(new)) end ) + it('Maintains undo information for loaded buffer', function() local old = tmpname() write_file(old, 'line') @@ -2616,6 +2625,7 @@ describe('LSP', function() eq(true, vim.uv.fs_stat(new) ~= nil) eq(true, undo_kept) end) + it('Maintains undo information for unloaded buffer', function() local old = tmpname() write_file(old, 'line') @@ -2637,6 +2647,7 @@ describe('LSP', function() eq(true, vim.uv.fs_stat(new) ~= nil) eq(true, undo_kept) end) + it('Does not rename file when it conflicts with a buffer without file', function() local old = tmpname() write_file(old, 'Old File') @@ -2656,6 +2667,7 @@ describe('LSP', function() eq({ 'conflict' }, lines) eq('Old File', read_file(old)) end) + it('Does override target if overwrite is true', function() local old = tmpname() write_file(old, 'Old file') @@ -2707,6 +2719,7 @@ describe('LSP', function() end) eq(expected, actual) end) + it('Convert LocationLink[] to items', function() local expected = { { @@ -2868,6 +2881,7 @@ describe('LSP', function() end) ) end) + it('DocumentSymbol has no children', function() local expected = { { @@ -2947,6 +2961,7 @@ describe('LSP', function() ) end) end) + it('convert SymbolInformation[] to items', function() local expected = { { @@ -3018,6 +3033,7 @@ describe('LSP', function() eq('File', exec_lua('return vim.lsp.util._get_symbol_kind_name(1)')) eq('TypeParameter', exec_lua('return vim.lsp.util._get_symbol_kind_name(26)')) end) + it('returns the name not specified by protocol', function() eq('Unknown', exec_lua('return vim.lsp.util._get_symbol_kind_name(nil)')) eq('Unknown', exec_lua('return vim.lsp.util._get_symbol_kind_name(vim.NIL)')) @@ -3157,7 +3173,7 @@ describe('LSP', function() exec_lua(create_server_definition) local result = exec_lua(function() local server = _G._create_server() - local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) + local client_id = assert(vim.lsp.start({ name = 'dummy', cmd = server.cmd })) local result = { uri = 'file:///fake/uri', selection = { @@ -3346,6 +3362,7 @@ describe('LSP', function() eq( { { 'foo', 'bar' } }, exec_lua(function() + --- @diagnostic disable-next-line:deprecated return vim.lsp.util.trim_empty_lines({ { 'foo', 'bar' }, nil }) end) ) @@ -3388,6 +3405,7 @@ describe('LSP', function() it('with shiftwidth = 1', function() test_tabstop(1, 1) end) + it('with shiftwidth = 0', function() test_tabstop(2, 0) end) @@ -4149,6 +4167,7 @@ describe('LSP', function() end, } end) + it('Calls workspace/executeCommand if no client side command', function() local client --- @type vim.lsp.Client local expected_handlers = { @@ -4189,6 +4208,7 @@ describe('LSP', function() end, }) end) + it('Filters and automatically applies action if requested', function() local client --- @type vim.lsp.Client local expected_handlers = { @@ -4263,6 +4283,7 @@ describe('LSP', function() end, } end) + it('Fallback to command execution on resolve error', function() clear() exec_lua(create_server_definition) @@ -4294,10 +4315,10 @@ describe('LSP', function() }, }) - local client_id = vim.lsp.start({ + local client_id = assert(vim.lsp.start({ name = 'dummy', cmd = server.cmd, - }) + })) vim.lsp.buf.code_action({ apply = true }) vim.lsp.stop_client(client_id) @@ -4316,6 +4337,7 @@ describe('LSP', function() pcall_err(exec_lua, 'vim.lsp.commands[1] = function() end') ) end) + it('Accepts only function values', function() matches( '.*Command added to `vim.lsp.commands` must be a function', @@ -4427,7 +4449,7 @@ describe('LSP', function() -- 2. second codelens request runs response = exec_lua(function() _G.CALLED = false - local cmd_called = nil + local cmd_called --- @type string? vim.lsp.commands['Dummy'] = function(command0) cmd_called = command0 end @@ -4437,7 +4459,7 @@ describe('LSP', function() end) vim.lsp.codelens.run() vim.wait(100, function() - return cmd_called + return cmd_called ~= nil end) return cmd_called end) @@ -4446,7 +4468,7 @@ describe('LSP', function() -- 3. third codelens request runs response = exec_lua(function() _G.CALLED = false - local cmd_called = nil + local cmd_called --- @type string? vim.lsp.commands['Dummy'] = function(command0) cmd_called = command0 end @@ -4456,7 +4478,7 @@ describe('LSP', function() end) vim.lsp.codelens.run() vim.wait(100, function() - return cmd_called + return cmd_called ~= nil end) return cmd_called end) @@ -4512,7 +4534,7 @@ describe('LSP', function() -- create buffers and setup handler exec_lua(function(lens_title_per_fake_uri0) local default_buf = vim.api.nvim_get_current_buf() - for fake_uri, _ in pairs(lens_title_per_fake_uri0) do + for fake_uri in pairs(lens_title_per_fake_uri0) do local bufnr = vim.uri_to_bufnr(fake_uri) vim.api.nvim_set_current_buf(bufnr) vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { 'Some contents' }) @@ -4561,7 +4583,7 @@ describe('LSP', function() local notify_msg = exec_lua(function() local bufnr = vim.api.nvim_get_current_buf() vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID) - local notify_msg + local notify_msg --- @type string? local notify = vim.notify vim.notify = function(msg, _) notify_msg = msg @@ -4575,6 +4597,7 @@ describe('LSP', function() end, } end) + it('Sends textDocument/formatting request to format buffer', function() local expected_handlers = { { NIL, {}, { method = 'shutdown', client_id = 1 } }, @@ -4592,7 +4615,7 @@ describe('LSP', function() local notify_msg = exec_lua(function() local bufnr = vim.api.nvim_get_current_buf() vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID) - local notify_msg + local notify_msg --- @type string? local notify = vim.notify vim.notify = function(msg, _) notify_msg = msg @@ -4608,12 +4631,13 @@ describe('LSP', function() end, } end) + it('Sends textDocument/rangeFormatting request to format a range', function() local expected_handlers = { { NIL, {}, { method = 'shutdown', client_id = 1 } }, { NIL, {}, { method = 'start', client_id = 1 } }, } - local client + local client --- @type vim.lsp.Client test_rpc_server { test_name = 'range_formatting', on_init = function(c) @@ -4626,7 +4650,7 @@ describe('LSP', function() local bufnr = vim.api.nvim_get_current_buf() vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, { 'foo', 'bar' }) vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID) - local notify_msg + local notify_msg --- @type string? local notify = vim.notify vim.notify = function(msg, _) notify_msg = msg @@ -4648,12 +4672,13 @@ describe('LSP', function() end, } end) + it('Sends textDocument/rangesFormatting request to format multiple ranges', function() local expected_handlers = { { NIL, {}, { method = 'shutdown', client_id = 1 } }, { NIL, {}, { method = 'start', client_id = 1 } }, } - local client + local client --- @type vim.lsp.Client test_rpc_server { test_name = 'ranges_formatting', on_init = function(c) @@ -4666,7 +4691,7 @@ describe('LSP', function() local bufnr = vim.api.nvim_get_current_buf() vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, { 'foo', 'bar', 'baz' }) vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID) - local notify_msg + local notify_msg --- @type string? local notify = vim.notify vim.notify = function(msg, _) notify_msg = msg @@ -4694,6 +4719,7 @@ describe('LSP', function() end, } end) + it('Can format async', function() local expected_handlers = { { NIL, {}, { method = 'shutdown', client_id = 1 } }, @@ -4712,7 +4738,7 @@ describe('LSP', function() local bufnr = vim.api.nvim_get_current_buf() vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID) - local notify_msg + local notify_msg --- @type string? local notify = vim.notify vim.notify = function(msg, _) notify_msg = msg @@ -4740,6 +4766,7 @@ describe('LSP', function() end, } end) + it('format formats range in visual mode', function() exec_lua(create_server_definition) local result = exec_lua(function() @@ -4750,7 +4777,7 @@ describe('LSP', function() }, }) local bufnr = vim.api.nvim_get_current_buf() - local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) + local client_id = assert(vim.lsp.start({ name = 'dummy', cmd = server.cmd })) vim.api.nvim_win_set_buf(0, bufnr) vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, { 'foo', 'bar' }) vim.api.nvim_win_set_cursor(0, { 1, 0 }) @@ -4767,6 +4794,7 @@ describe('LSP', function() } eq(expected_range, result[3].params.range) end) + it('format formats range in visual line mode', function() exec_lua(create_server_definition) local result = exec_lua(function() @@ -4777,7 +4805,7 @@ describe('LSP', function() }, }) local bufnr = vim.api.nvim_get_current_buf() - local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) + local client_id = assert(vim.lsp.start({ name = 'dummy', cmd = server.cmd })) vim.api.nvim_win_set_buf(0, bufnr) vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, { 'foo', 'bar baz' }) vim.api.nvim_win_set_cursor(0, { 1, 2 }) @@ -4820,6 +4848,7 @@ describe('LSP', function() eq(expected_range, result[3].params.range) eq(expected_range, result[5].params.range) end) + it('Aborts with notify if no clients support requested method', function() exec_lua(create_server_definition) exec_lua(function() @@ -4923,6 +4952,7 @@ describe('LSP', function() _G.client_id = vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd }) end, mock_locations) end) + after_each(function() exec_lua(function() vim.lsp.stop_client(_G.client_id) @@ -4967,12 +4997,12 @@ describe('LSP', function() it('can connect to lsp server via rpc.connect', function() local result = exec_lua(function() local uv = vim.uv - local server = uv.new_tcp() + local server = assert(uv.new_tcp()) local init = nil server:bind('127.0.0.1', 0) server:listen(127, function(err) assert(not err, err) - local socket = uv.new_tcp() + local socket = assert(uv.new_tcp()) server:accept(socket) socket:read_start(require('vim.lsp.rpc').create_read_loop(function(body) init = body @@ -4991,6 +5021,7 @@ describe('LSP', function() end) eq('initialize', result.method) end) + it('can connect to lsp server via pipe or domain_socket', function() local tmpfile --- @type string if is_os('win') then @@ -5001,13 +5032,13 @@ describe('LSP', function() end local result = exec_lua(function(SOCK) local uv = vim.uv - local server = uv.new_pipe(false) + local server = assert(uv.new_pipe(false)) server:bind(SOCK) local init = nil server:listen(127, function(err) assert(not err, err) - local client = uv.new_pipe() + local client = assert(uv.new_pipe()) server:accept(client) client:read_start(require('vim.lsp.rpc').create_read_loop(function(body) init = body @@ -5031,13 +5062,13 @@ describe('LSP', function() it('handler can return false as response', function() local result = exec_lua(function() local uv = vim.uv - local server = uv.new_tcp() + local server = assert(uv.new_tcp()) local messages = {} local responses = {} server:bind('127.0.0.1', 0) server:listen(127, function(err) assert(not err, err) - local socket = uv.new_tcp() + local socket = assert(uv.new_tcp()) server:accept(socket) socket:read_start(require('vim.lsp.rpc').create_read_loop(function(body) local payload = vim.json.decode(body) @@ -5074,7 +5105,7 @@ describe('LSP', function() return false end local client_id = - vim.lsp.start({ name = 'dummy', cmd = vim.lsp.rpc.connect('127.0.0.1', port) }) + assert(vim.lsp.start({ name = 'dummy', cmd = vim.lsp.rpc.connect('127.0.0.1', port) })) vim.lsp.get_client_by_id(client_id) vim.wait(1000, function() return #messages == 2 and handler_called and #responses == 1 @@ -5117,7 +5148,7 @@ describe('LSP', function() exec_lua(create_server_definition) local result = exec_lua(function(root_dir0, tmpfile0) local server = _G._create_server() - local client_id = vim.lsp.start({ + local client_id = assert(vim.lsp.start({ name = 'dynamic-test', cmd = server.cmd, root_dir = root_dir0, @@ -5134,7 +5165,7 @@ describe('LSP', function() }, }, }, - }) + })) vim.lsp.handlers['client/registerCapability'](nil, { registrations = { @@ -5180,7 +5211,7 @@ describe('LSP', function() local result = {} local function check(method, fname) local bufnr = fname and vim.fn.bufadd(fname) or nil - local client = vim.lsp.get_client_by_id(client_id) + local client = assert(vim.lsp.get_client_by_id(client_id)) result[#result + 1] = { method = method, fname = fname, @@ -5240,7 +5271,7 @@ describe('LSP', function() exec_lua(create_server_definition) local result = exec_lua(function(root_dir0, watchfunc0) local server = _G._create_server() - local client_id = vim.lsp.start({ + local client_id = assert(vim.lsp.start({ name = 'watchfiles-test', cmd = server.cmd, root_dir = root_dir0, @@ -5251,7 +5282,7 @@ describe('LSP', function() }, }, }, - }) + })) require('vim.lsp._watchfiles')._watchfunc = require('vim._watch')[watchfunc0] @@ -5349,7 +5380,7 @@ describe('LSP', function() exec_lua(create_server_definition) local result = exec_lua(function(root_dir0) local server = _G._create_server() - local client_id = vim.lsp.start({ + local client_id = assert(vim.lsp.start({ name = 'watchfiles-test', cmd = server.cmd, root_dir = root_dir0, @@ -5360,7 +5391,7 @@ describe('LSP', function() }, }, }, - }) + })) local expected_messages = 2 -- initialize, initialized local function wait_for_messages() @@ -5375,7 +5406,7 @@ describe('LSP', function() wait_for_messages() - local send_event + local send_event --- @type function require('vim.lsp._watchfiles')._watchfunc = function(_, _, callback) local stopped = false send_event = function(...) @@ -5474,7 +5505,7 @@ describe('LSP', function() exec_lua(create_server_definition) local result = exec_lua(function(root_dir0) local server = _G._create_server() - local client_id = vim.lsp.start({ + local client_id = assert(vim.lsp.start({ name = 'watchfiles-test', cmd = server.cmd, root_dir = root_dir0, @@ -5485,7 +5516,7 @@ describe('LSP', function() }, }, }, - }) + })) local expected_messages = 2 -- initialize, initialized local function wait_for_messages() @@ -5500,7 +5531,7 @@ describe('LSP', function() wait_for_messages() - local watch_callbacks = {} + local watch_callbacks = {} --- @type function[] local function send_event(...) for _, cb in ipairs(watch_callbacks) do cb(...) @@ -5618,7 +5649,7 @@ describe('LSP', function() exec_lua(create_server_definition) local result = exec_lua(function(root_dir0) local server = _G._create_server() - local client_id = vim.lsp.start({ + local client_id = assert(vim.lsp.start({ name = 'watchfiles-test', cmd = server.cmd, root_dir = root_dir0, @@ -5629,7 +5660,7 @@ describe('LSP', function() }, }, }, - }) + })) local expected_messages = 2 -- initialize, initialized local function wait_for_messages() @@ -5644,7 +5675,7 @@ describe('LSP', function() wait_for_messages() - local send_event + local send_event --- @type function require('vim.lsp._watchfiles')._watchfunc = function(_, _, callback) send_event = callback return function() @@ -5714,7 +5745,7 @@ describe('LSP', function() local function check_registered(capabilities) return exec_lua(function(capabilities0) _G.watching = false - local client_id = vim.lsp.start({ + local client_id = assert(vim.lsp.start({ name = 'watchfiles-test', cmd = _G.server.cmd, root_dir = 'some_dir', @@ -5723,7 +5754,7 @@ describe('LSP', function() reuse_client = function() return false end, - }) + })) vim.lsp.handlers['client/registerCapability'](nil, { registrations = { -- cgit From b6219210745c67899900bae9f12dd231c9857e37 Mon Sep 17 00:00:00 2001 From: futsuuu Date: Tue, 23 Jul 2024 20:40:43 +0900 Subject: test: add a test to check the indentation --- test/functional/lua/loader_spec.lua | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'test/functional') diff --git a/test/functional/lua/loader_spec.lua b/test/functional/lua/loader_spec.lua index f13e6664c5..6ab23e725c 100644 --- a/test/functional/lua/loader_spec.lua +++ b/test/functional/lua/loader_spec.lua @@ -88,4 +88,18 @@ describe('vim.loader', function() eq(1, exec_lua('return loadfile(...)()', tmp1)) eq(2, exec_lua('return loadfile(...)()', tmp2)) end) + + it('correct indent on error message (#29809)', function() + exec_lua [[ + vim.loader.enable() + + local success, errmsg = pcall(require, 'non_existent_module') + assert(not success) + + errmsg = errmsg:gsub("^module 'non_existent_module' not found:\n", '') + for line in vim.gsplit(errmsg, '\n') do + assert(line:find('^\t'), ('not indented: %q'):format(line)) + end + ]] + end) end) -- cgit From ab561302a3b4dbb161aa6ef3ea39a6d1410a72fe Mon Sep 17 00:00:00 2001 From: futsuuu Date: Tue, 23 Jul 2024 21:52:18 +0900 Subject: test: remove internal assertions and simplify --- test/functional/lua/loader_spec.lua | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'test/functional') diff --git a/test/functional/lua/loader_spec.lua b/test/functional/lua/loader_spec.lua index 6ab23e725c..7d71e33ced 100644 --- a/test/functional/lua/loader_spec.lua +++ b/test/functional/lua/loader_spec.lua @@ -90,16 +90,13 @@ describe('vim.loader', function() end) it('correct indent on error message (#29809)', function() - exec_lua [[ + local errmsg = exec_lua [[ vim.loader.enable() - - local success, errmsg = pcall(require, 'non_existent_module') - assert(not success) - - errmsg = errmsg:gsub("^module 'non_existent_module' not found:\n", '') - for line in vim.gsplit(errmsg, '\n') do - assert(line:find('^\t'), ('not indented: %q'):format(line)) - end + local _, errmsg = pcall(require, 'non_existent_module') + return errmsg ]] + local errors = vim.split(errmsg, '\n') + eq("\tcache_loader: module 'non_existent_module' not found", errors[3]) + eq("\tcache_loader_lib: module 'non_existent_module' not found", errors[4]) end) end) -- cgit From ef4c9b136e0a41ca4a4740688fa0956c2ccbfb2e Mon Sep 17 00:00:00 2001 From: bfredl Date: Wed, 14 Aug 2024 13:42:05 +0200 Subject: refactor(tests): again yet more global highlight definitions --- test/functional/autocmd/autocmd_oldtest_spec.lua | 10 +-- test/functional/autocmd/autocmd_spec.lua | 25 +----- test/functional/autocmd/cmdline_spec.lua | 46 +++++------ test/functional/autocmd/show_spec.lua | 14 ++-- test/functional/lua/luaeval_spec.lua | 15 +--- test/functional/lua/thread_spec.lua | 38 +++------ test/functional/lua/vim_spec.lua | 87 +++++++-------------- test/functional/provider/clipboard_spec.lua | 37 +++------ test/functional/ui/wildmode_spec.lua | 98 ++++++++++++------------ 9 files changed, 139 insertions(+), 231 deletions(-) (limited to 'test/functional') diff --git a/test/functional/autocmd/autocmd_oldtest_spec.lua b/test/functional/autocmd/autocmd_oldtest_spec.lua index 1a3b723ac2..5e4beb7684 100644 --- a/test/functional/autocmd/autocmd_oldtest_spec.lua +++ b/test/functional/autocmd/autocmd_oldtest_spec.lua @@ -103,9 +103,9 @@ describe('oldtests', function() it('no ml_get error with TextChanged autocommand and delete', function() local screen = Screen.new(75, 10) screen:attach() - screen:set_default_attr_ids({ - [1] = { background = Screen.colors.Cyan }, - }) + screen:add_extra_attr_ids { + [100] = { background = Screen.colors.Cyan1 }, + } exec([[ set noshowcmd noruler scrolloff=0 source test/old/testdir/samples/matchparen.vim @@ -120,9 +120,9 @@ describe('oldtests', function() } | const auto &themes = _forPeer->owner().cloudThemes(); | const auto theme = themes.themeForEmoji(themeEmoji); | - if (!theme) {1:{} | + if (!theme) {100:{} | return nonCustom; | - {1:^}} | + {100:^}} | 353 fewer lines | ]], } diff --git a/test/functional/autocmd/autocmd_spec.lua b/test/functional/autocmd/autocmd_spec.lua index fbaf0c0dbf..0429cfee89 100644 --- a/test/functional/autocmd/autocmd_spec.lua +++ b/test/functional/autocmd/autocmd_spec.lua @@ -259,15 +259,6 @@ describe('autocmd', function() local screen = Screen.new(50, 10) screen:attach() - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - [2] = { background = Screen.colors.LightMagenta }, - [3] = { - background = Screen.colors.LightMagenta, - bold = true, - foreground = Screen.colors.Blue1, - }, - }) source([[ function! Doit() @@ -292,8 +283,8 @@ describe('autocmd', function() feed(':enew | doautoall User') screen:expect([[ - {2:bb }| - {3:~ }|*4 + {4:bb }| + {11:~ }|*4 {1:~ }|*4 ^:enew | doautoall User | ]]) @@ -318,8 +309,8 @@ describe('autocmd', function() command('let g:had_value = v:null') feed(':doautoall User') screen:expect([[ - {2:bb }| - {3:~ }|*4 + {4:bb }| + {11:~ }|*4 {1:~ }|*4 ^:doautoall User | ]]) @@ -343,11 +334,6 @@ describe('autocmd', function() it('`aucmd_win` cannot be changed into a normal window #13699', function() local screen = Screen.new(50, 10) screen:attach() - screen:set_default_attr_ids { - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - [2] = { reverse = true }, - [3] = { bold = true, reverse = true }, - } -- Create specific layout and ensure it's left unchanged. -- Use vim._with on a hidden buffer so aucmd_win is used. @@ -513,9 +499,6 @@ describe('autocmd', function() it(':doautocmd does not warn "No matching autocommands" #10689', function() local screen = Screen.new(32, 3) screen:attach() - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - }) feed(':doautocmd User Foo') screen:expect { diff --git a/test/functional/autocmd/cmdline_spec.lua b/test/functional/autocmd/cmdline_spec.lua index ad3bc3576f..ca137debb8 100644 --- a/test/functional/autocmd/cmdline_spec.lua +++ b/test/functional/autocmd/cmdline_spec.lua @@ -61,12 +61,6 @@ describe('cmdline autocommands', function() clear() local screen = Screen.new(72, 8) screen:attach() - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - [2] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, - [3] = { bold = true, foreground = Screen.colors.SeaGreen4 }, - [4] = { bold = true, reverse = true }, - }) command("autocmd CmdlineEnter * echoerr 'FAIL'") command("autocmd CmdlineLeave * echoerr 'very error'") @@ -74,22 +68,22 @@ describe('cmdline autocommands', function() screen:expect([[ | {1:~ }|*3 - {4: }| + {3: }| : | - {2:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} | + {9:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} | :^ | ]]) feed("put ='lorem ipsum'") screen:expect([[ | - {4: }| + {3: }| : | - {2:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} | + {9:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} | :put ='lorem ipsum' | - {2:CmdlineLeave Autocommands for "*": Vim(echoerr):very error} | + {9:CmdlineLeave Autocommands for "*": Vim(echoerr):very error} | | - {3:Press ENTER or type command to continue}^ | + {6:Press ENTER or type command to continue}^ | ]]) -- cmdline was still executed @@ -108,11 +102,11 @@ describe('cmdline autocommands', function() screen:expect([[ | lorem ipsum | - {4: }| + {3: }| : | - {2:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} | + {9:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} | :put ='lorem ipsum' | - {2:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} | + {9:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} | :put ='lorem ipsum'^ | ]]) @@ -120,37 +114,37 @@ describe('cmdline autocommands', function() screen:expect([[ | lorem ipsum | - {4: }| + {3: }| : | - {2:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} | + {9:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} | :put ='lorem ipsum' | - {2:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} | + {9:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} | :put ='lorem ipsum^' | ]]) -- edit still works feed('.') screen:expect([[ - {4: }| + {3: }| : | - {2:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} | + {9:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} | :put ='lorem ipsum' | - {2:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} | + {9:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} | :put ='lorem ipsum.' | - {2:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} | + {9:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} | :put ='lorem ipsum.^' | ]]) feed('') screen:expect([[ :put ='lorem ipsum' | - {2:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} | + {9:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} | :put ='lorem ipsum.' | - {2:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} | + {9:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} | :put ='lorem ipsum.' | - {2:CmdlineLeave Autocommands for "*": Vim(echoerr):very error} | + {9:CmdlineLeave Autocommands for "*": Vim(echoerr):very error} | | - {3:Press ENTER or type command to continue}^ | + {6:Press ENTER or type command to continue}^ | ]]) -- cmdline was still executed diff --git a/test/functional/autocmd/show_spec.lua b/test/functional/autocmd/show_spec.lua index 7e1818c4fd..10d242527f 100644 --- a/test/functional/autocmd/show_spec.lua +++ b/test/functional/autocmd/show_spec.lua @@ -43,11 +43,9 @@ describe(':autocmd', function() it('should not show group information if interrupted', function() local screen = Screen.new(50, 6) - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue1 }, -- NonText - [2] = { bold = true, foreground = Screen.colors.SeaGreen }, -- MoreMsg - [3] = { bold = true, foreground = Screen.colors.Magenta }, -- Title - }) + screen:add_extra_attr_ids { + [100] = { foreground = Screen.colors.Magenta, bold = true }, + } screen:attach() exec([[ set more @@ -73,11 +71,11 @@ describe(':autocmd', function() feed(':autocmd') screen:expect([[ :autocmd | - {3:--- Autocommands ---} | - {3:test_1} {3:BufEnter} | + {100:--- Autocommands ---} | + {100:test_1} {100:BufEnter} | A echo 'A' | B echo 'B' | - {2:-- More --}^ | + {6:-- More --}^ | ]]) feed('q') screen:expect([[ diff --git a/test/functional/lua/luaeval_spec.lua b/test/functional/lua/luaeval_spec.lua index f3db729c09..e66d457237 100644 --- a/test/functional/lua/luaeval_spec.lua +++ b/test/functional/lua/luaeval_spec.lua @@ -510,23 +510,16 @@ describe('v:lua', function() it('works in func options', function() local screen = Screen.new(60, 8) - screen:set_default_attr_ids({ - [1] = {bold = true, foreground = Screen.colors.Blue1}, - [2] = {background = Screen.colors.WebGray}, - [3] = {background = Screen.colors.LightMagenta}, - [4] = {bold = true}, - [5] = {bold = true, foreground = Screen.colors.SeaGreen4}, - }) screen:attach() api.nvim_set_option_value('omnifunc', 'v:lua.mymod.omni', {}) feed('isome st') screen:expect{grid=[[ some stuff^ | - {1:~ }{2: stuff }{1: }| - {1:~ }{3: steam }{1: }| - {1:~ }{3: strange things }{1: }| + {1:~ }{12: stuff }{1: }| + {1:~ }{4: steam }{1: }| + {1:~ }{4: strange things }{1: }| {1:~ }|*3 - {4:-- Omni completion (^O^N^P) }{5:match 1 of 3} | + {5:-- Omni completion (^O^N^P) }{6:match 1 of 3} | ]]} api.nvim_set_option_value('operatorfunc', 'v:lua.mymod.noisy', {}) feed('g@g@') diff --git a/test/functional/lua/thread_spec.lua b/test/functional/lua/thread_spec.lua index 780057b580..cbf23517dc 100644 --- a/test/functional/lua/thread_spec.lua +++ b/test/functional/lua/thread_spec.lua @@ -18,13 +18,6 @@ describe('thread', function() clear() screen = Screen.new(50, 10) screen:attach() - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - [2] = { bold = true, reverse = true }, - [3] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, - [4] = { bold = true, foreground = Screen.colors.SeaGreen4 }, - [5] = { bold = true }, - }) end) it('entry func is executed in protected mode', function() @@ -38,10 +31,10 @@ describe('thread', function() screen:expect([[ | {1:~ }|*5 - {2: }| - {3:Error in luv thread:} | - {3:[string ""]:2: Error in thread entry func} | - {4:Press ENTER or type command to continue}^ | + {3: }| + {9:Error in luv thread:} | + {9:[string ""]:2: Error in thread entry func} | + {6:Press ENTER or type command to continue}^ | ]]) feed('') assert_alive() @@ -65,10 +58,10 @@ describe('thread', function() screen:expect([[ | {1:~ }|*5 - {2: }| - {3:Error in luv callback, thread:} | - {3:[string ""]:6: Error in thread callback} | - {4:Press ENTER or type command to continue}^ | + {3: }| + {9:Error in luv callback, thread:} | + {9:[string ""]:6: Error in thread callback} | + {6:Press ENTER or type command to continue}^ | ]]) feed('') assert_alive() @@ -265,13 +258,6 @@ describe('threadpool', function() it('with invalid return value', function() local screen = Screen.new(50, 10) screen:attach() - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - [2] = { bold = true, reverse = true }, - [3] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, - [4] = { bold = true, foreground = Screen.colors.SeaGreen4 }, - [5] = { bold = true }, - }) exec_lua [[ local work = vim.uv.new_work(function() return {} end, function() end) @@ -281,10 +267,10 @@ describe('threadpool', function() screen:expect([[ | {1:~ }|*5 - {2: }| - {3:Error in luv thread:} | - {3:Error: thread arg not support type 'table' at 1} | - {4:Press ENTER or type command to continue}^ | + {3: }| + {9:Error in luv thread:} | + {9:Error: thread arg not support type 'table' at 1} | + {6:Press ENTER or type command to continue}^ | ]]) end) diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index b0720e6a94..a70f35e8e3 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -540,12 +540,6 @@ describe('lua stdlib', function() matches('big failure\nvery async', remove_trace(eval('v:errmsg'))) local screen = Screen.new(60, 5) - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - [2] = { bold = true, reverse = true }, - [3] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, - [4] = { bold = true, foreground = Screen.colors.SeaGreen4 }, - }) screen:attach() screen:expect { grid = [[ @@ -564,11 +558,11 @@ describe('lua stdlib', function() ]]) screen:expect { grid = [[ - {3:stack traceback:} | - {3: [C]: in function 'nvim_command'} | - {3: [string ""]:2: in function <[string ""]:}| - {3:1>} | - {4:Press ENTER or type command to continue}^ | + {9:stack traceback:} | + {9: [C]: in function 'nvim_command'} | + {9: [string ""]:2: in function <[string ""]:}| + {9:1>} | + {6:Press ENTER or type command to continue}^ | ]], } end) @@ -1318,12 +1312,6 @@ describe('lua stdlib', function() end) local screen = Screen.new(50, 7) - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - [2] = { bold = true, reverse = true }, - [3] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, - [4] = { bold = true, foreground = Screen.colors.SeaGreen4 }, - }) screen:attach() exec_lua([[ timer = vim.uv.new_timer() @@ -1336,13 +1324,13 @@ describe('lua stdlib', function() ]]) screen:expect { grid = [[ - {3:[string ""]:6: E5560: rpcrequest must not be}| - {3: called in a lua loop callback} | - {3:stack traceback:} | - {3: [C]: in function 'rpcrequest'} | - {3: [string ""]:6: in function <[string }| - {3:""]:2>} | - {4:Press ENTER or type command to continue}^ | + {9:[string ""]:6: E5560: rpcrequest must not be}| + {9: called in a lua loop callback} | + {9:stack traceback:} | + {9: [C]: in function 'rpcrequest'} | + {9: [string ""]:6: in function <[string }| + {9:""]:2>} | + {6:Press ENTER or type command to continue}^ | ]], } feed('') @@ -1995,16 +1983,12 @@ describe('lua stdlib', 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:~ }| | ]], } @@ -2013,7 +1997,7 @@ describe('lua stdlib', function() screen:expect { grid = [[ foo ^foo foo | - {0:~ }| + {1:~ }| | ]], } @@ -2021,8 +2005,8 @@ describe('lua stdlib', function() eq(1, eval('v:hlsearch')) screen:expect { grid = [[ - {1:foo} {1:^foo} {1:foo} | - {0:~ }| + {10:foo} {10:^foo} {10:foo} | + {1:~ }| | ]], } @@ -3542,15 +3526,11 @@ describe('lua stdlib', function() it('vim.notify_once', function() local screen = Screen.new(60, 5) - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - [1] = { foreground = Screen.colors.Red }, - }) screen:attach() screen:expect { grid = [[ ^ | - {0:~ }|*3 + {1:~ }|*3 | ]], } @@ -3558,15 +3538,15 @@ describe('lua stdlib', function() screen:expect { grid = [[ ^ | - {0:~ }|*3 - {1:I'll only tell you this once...} | + {1:~ }|*3 + {19:I'll only tell you this once...} | ]], } feed('') screen:expect { grid = [[ ^ | - {0:~ }|*3 + {1:~ }|*3 | ]], } @@ -3743,10 +3723,6 @@ describe('lua stdlib', function() it('updates ruler if cursor moved', function() -- Fixed for win_execute in vim-patch:8.1.2124, but should've applied to nvim_win_call too! local screen = Screen.new(30, 5) - screen:set_default_attr_ids { - [1] = { reverse = true }, - [2] = { bold = true, reverse = true }, - } screen:attach() exec_lua [[ _G.api = vim.api @@ -3761,9 +3737,9 @@ describe('lua stdlib', function() ]] screen:expect [[ 19 | - {1:[No Name] [+] 20,1 3%}| - ^19 | {2:[No Name] [+] 20,1 3%}| + ^19 | + {3:[No Name] [+] 20,1 3%}| | ]] exec_lua [[ @@ -3772,9 +3748,9 @@ describe('lua stdlib', function() ]] screen:expect [[ 99 | - {1:[No Name] [+] 100,1 19%}| + {2:[No Name] [+] 100,1 19%}| ^19 | - {2:[No Name] [+] 20,1 3%}| + {3:[No Name] [+] 20,1 3%}| | ]] end) @@ -3890,13 +3866,6 @@ describe('lua stdlib', function() it('vim.lua_omnifunc', function() local screen = Screen.new(60, 5) - screen:set_default_attr_ids { - [1] = { foreground = Screen.colors.Blue1, bold = true }, - [2] = { background = Screen.colors.WebGray }, - [3] = { background = Screen.colors.LightMagenta }, - [4] = { bold = true }, - [5] = { foreground = Screen.colors.SeaGreen, bold = true }, - } screen:attach() command [[ set omnifunc=v:lua.vim.lua_omnifunc ]] @@ -3906,10 +3875,10 @@ describe('lua stdlib', function() screen:expect { grid = [[ vim.inspect^ | - {1:~ }{2: inspect }{1: }| - {1:~ }{3: inspect_pos }{1: }| + {1:~ }{12: inspect }{1: }| + {1:~ }{4: inspect_pos }{1: }| {1:~ }| - {4:-- Omni completion (^O^N^P) }{5:match 1 of 2} | + {5:-- Omni completion (^O^N^P) }{6:match 1 of 2} | ]], } end) diff --git a/test/functional/provider/clipboard_spec.lua b/test/functional/provider/clipboard_spec.lua index 9e7df0ba6b..1094f9f4e5 100644 --- a/test/functional/provider/clipboard_spec.lua +++ b/test/functional/provider/clipboard_spec.lua @@ -94,12 +94,6 @@ describe('clipboard', function() before_each(function() clear() screen = Screen.new(72, 4) - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - [1] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, - [2] = { bold = true, foreground = Screen.colors.SeaGreen4 }, - [3] = { bold = true, reverse = true }, - }) screen:attach() end) @@ -114,13 +108,13 @@ describe('clipboard', function() feed('"+yl') screen:expect([[ ^a | - {0:~ }|*2 + {1:~ }|*2 clipboard: No provider. Try ":checkhealth" or ":h clipboard". | ]]) feed('"+p') screen:expect([[ a^a | - {0:~ }|*2 + {1:~ }|*2 clipboard: No provider. Try ":checkhealth" or ":h clipboard". | ]]) end) @@ -132,19 +126,19 @@ describe('clipboard', function() feed('yl') screen:expect([[ ^a | - {0:~ }|*2 + {1:~ }|*2 clipboard: No provider. Try ":checkhealth" or ":h clipboard". | ]]) feed(':') screen:expect([[ ^a | - {0:~ }|*2 + {1:~ }|*2 : | ]]) feed('p') screen:expect([[ a^a | - {0:~ }|*2 + {1:~ }|*2 : | ]]) end) @@ -154,7 +148,7 @@ describe('clipboard', function() feed_command('redir @+> | :silent echo system("cat CONTRIBUTING.md") | redir END') screen:expect([[ ^ | - {0:~ }|*2 + {1:~ }|*2 clipboard: No provider. Try ":checkhealth" or ":h clipboard". | ]]) end) @@ -166,8 +160,8 @@ describe('clipboard', function() grid = [[ {3: }| clipboard: No provider. Try ":checkhealth" or ":h clipboard". | - {1:E492: Not an editor command: bogus_cmd | redir END} | - {2:Press ENTER or type command to continue}^ | + {9:E492: Not an editor command: bogus_cmd | redir END} | + {6:Press ENTER or type command to continue}^ | ]], } end) @@ -182,7 +176,7 @@ describe('clipboard', function() feed_command('let @+="foo"') screen:expect([[ ^ | - {0:~ }|*2 + {1:~ }|*2 clipboard: No provider. Try ":checkhealth" or ":h clipboard". | ]]) end) @@ -325,15 +319,11 @@ describe('clipboard (with fake clipboard.vim)', function() it('`:redir @+>|bogus_cmd|redir END` must not recurse #7184', function() local screen = Screen.new(72, 4) screen:attach() - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - [1] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, - }) feed_command('redir @+> | bogus_cmd | redir END') screen:expect([[ ^ | - {0:~ }|*2 - {1:E492: Not an editor command: bogus_cmd | redir END} | + {1:~ }|*2 + {9:E492: Not an editor command: bogus_cmd | redir END} | ]]) end) @@ -719,9 +709,6 @@ describe('clipboard (with fake clipboard.vim)', function() feed_command('set mouse=a') local screen = Screen.new(30, 5) - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - }) screen:attach() insert([[ the source @@ -731,7 +718,7 @@ describe('clipboard (with fake clipboard.vim)', function() screen:expect([[ the ^source | a target | - {0:~ }|*2 + {1:~ }|*2 | ]]) diff --git a/test/functional/ui/wildmode_spec.lua b/test/functional/ui/wildmode_spec.lua index 6299852a69..4d01b7a779 100644 --- a/test/functional/ui/wildmode_spec.lua +++ b/test/functional/ui/wildmode_spec.lua @@ -16,30 +16,24 @@ describe("'wildmenu'", function() before_each(function() clear() screen = Screen.new(25, 5) - screen:set_default_attr_ids { - [1] = { foreground = Screen.colors.Blue, bold = true }, - [2] = { reverse = true }, - [3] = { bold = true, reverse = true }, - [5] = { bold = true }, - [31] = { foreground = Screen.colors.Grey0, background = Screen.colors.Yellow }, + screen:add_extra_attr_ids { + [100] = { background = Screen.colors.Yellow1, foreground = Screen.colors.Black }, } screen:attach() end) -- oldtest: Test_wildmenu_screendump() it('works', function() - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText - [1] = { foreground = Screen.colors.Black, background = Screen.colors.Yellow }, -- WildMenu - [2] = { bold = true, reverse = true }, -- StatusLine - }) + screen:add_extra_attr_ids { + [100] = { background = Screen.colors.Yellow1, foreground = Screen.colors.Black }, + } -- Test simple wildmenu feed(':sign ') screen:expect { grid = [[ | - {0:~ }|*2 - {1:define}{2: jump list > }| + {1:~ }|*2 + {100:define}{3: jump list > }| :sign define^ | ]], } @@ -48,8 +42,8 @@ describe("'wildmenu'", function() screen:expect { grid = [[ | - {0:~ }|*2 - {2:define }{1:jump}{2: list > }| + {1:~ }|*2 + {3:define }{100:jump}{3: list > }| :sign jump^ | ]], } @@ -58,8 +52,8 @@ describe("'wildmenu'", function() screen:expect { grid = [[ | - {0:~ }|*2 - {2:define jump }{1:list}{2: > }| + {1:~ }|*2 + {3:define jump }{100:list}{3: > }| :sign list^ | ]], } @@ -69,8 +63,8 @@ describe("'wildmenu'", function() screen:expect { grid = [[ | - {0:~ }|*2 - {2:define jump list > }| + {1:~ }|*2 + {3:define jump list > }| :sign ^ | ]], } @@ -80,7 +74,7 @@ describe("'wildmenu'", function() screen:expect { grid = [[ | - {0:~ }|*3 + {1:~ }|*3 :sign ^ | ]], } @@ -92,8 +86,8 @@ describe("'wildmenu'", function() screen:expect { grid = [[ | - {0:~ }|*2 - {1:define}{2: jump list > }| + {1:~ }|*2 + {100:define}{3: jump list > }| :sign define^ | ]], } @@ -104,7 +98,7 @@ describe("'wildmenu'", function() screen:expect { grid = [[ ^ | - {0:~ }|*3 + {1:~ }|*3 | ]], } @@ -115,7 +109,7 @@ describe("'wildmenu'", function() screen:expect([[ | {1:~ }|*2 - {31:define}{3: jump list > }| + {100:define}{3: jump list > }| :sign define^ | ]]) feed('') @@ -131,7 +125,7 @@ describe("'wildmenu'", function() screen:expect([[ | {1:~ }|*2 - {31:define}{3: jump list > }| + {100:define}{3: jump list > }| :sign define^ | ]]) feed('') @@ -148,7 +142,7 @@ describe("'wildmenu'", function() screen:expect([[ | {1:~ }|*2 - {31:define}{3: jump list > }| + {100:define}{3: jump list > }| :sign define^ | ]]) end) @@ -162,7 +156,7 @@ describe("'wildmenu'", function() screen:expect([[ | {1:~ }|*2 - {31:define}{3: jump list > }| + {100:define}{3: jump list > }| :sign define^ | ]]) feed('') @@ -188,7 +182,7 @@ describe("'wildmenu'", function() screen:expect([[ | {1:~ }|*2 - {31:!}{3: # & < = > @ > }| + {100:!}{3: # & < = > @ > }| :!^ | ]]) end) @@ -199,13 +193,17 @@ describe("'wildmenu'", function() feed((':terminal "%s" REP 5000 !terminal_output!'):format(testprg('shell-test'))) feed('G') -- Follow :terminal output. feed([[:sign ]]) -- Invoke wildmenu. - screen:set_default_attr_ids { - [31] = { foreground = Screen.colors.Black, background = Screen.colors.Yellow }, - [32] = { bold = true, foreground = Screen.colors.White, background = Screen.colors.DarkGreen }, + screen:add_extra_attr_ids { + [100] = { foreground = Screen.colors.Black, background = Screen.colors.Yellow }, + [101] = { + bold = true, + foreground = Screen.colors.White, + background = Screen.colors.DarkGreen, + }, } -- NB: in earlier versions terminal output was redrawn during cmdline mode. -- For now just assert that the screen remains unchanged. - screen:expect { any = '{31:define}{32: jump list > }|\n:sign define^ |' } + screen:expect { any = '{100:define}{101: jump list > }|\n:sign define^ |' } screen:expect_unchanged() -- cmdline CTRL-D display should also be preserved. @@ -236,7 +234,7 @@ describe("'wildmenu'", function() grid = [[ | {1:~ }|*2 - {31:define}{3: jump list > }| + {100:define}{3: jump list > }| :sign define^ | ]], } @@ -263,13 +261,17 @@ describe("'wildmenu'", function() feed([[]]) feed([[:]]) -- Invoke wildmenu. - screen:set_default_attr_ids { - [31] = { foreground = Screen.colors.Black, background = Screen.colors.Yellow }, - [32] = { bold = true, foreground = Screen.colors.White, background = Screen.colors.DarkGreen }, + screen:add_extra_attr_ids { + [100] = { foreground = Screen.colors.Black, background = Screen.colors.Yellow }, + [101] = { + bold = true, + foreground = Screen.colors.White, + background = Screen.colors.DarkGreen, + }, } -- Check only the last 2 lines, because the shell output is -- system-dependent. - screen:expect { any = '{31:!}{32: # & < = > @ > }|\n:!^' } + screen:expect { any = '{100:!}{101: # & < = > @ > }|\n:!^' } -- Because this test verifies a _lack_ of activity, we must wait the full timeout. -- So make it reasonable. screen:expect_unchanged(false, 1000) @@ -298,7 +300,7 @@ describe("'wildmenu'", function() {3: }| :set wildm | wildmenu wildmode | - {31:wildmenu}{3: wildmode }| + {100:wildmenu}{3: wildmode }| :set wildmenu^ | ]]) feed('') @@ -424,10 +426,8 @@ describe("'wildmenu'", function() end) it('works with c_CTRL_Z standard mapping', function() - screen:set_default_attr_ids { - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - [2] = { foreground = Screen.colors.Grey0, background = Screen.colors.Yellow }, - [3] = { bold = true, reverse = true }, + screen:add_extra_attr_ids { + [100] = { background = Screen.colors.Yellow1, foreground = Screen.colors.Black }, } -- Wildcharm? where we are going we aint't no need no wildcharm. @@ -444,7 +444,7 @@ describe("'wildmenu'", function() grid = [[ | {1:~ }|*2 - {2:case}{3: clear cluster > }| + {100:case}{3: clear cluster > }| :syntax case^ | ]], } @@ -489,11 +489,9 @@ describe('command line completion', function() before_each(function() clear() screen = Screen.new(40, 5) - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - [2] = { foreground = Screen.colors.Grey0, background = Screen.colors.Yellow }, - [3] = { bold = true, reverse = true }, - }) + screen:add_extra_attr_ids { + [100] = { background = Screen.colors.Yellow1, foreground = Screen.colors.Black }, + } screen:attach() end) after_each(function() @@ -521,7 +519,7 @@ describe('command line completion', function() screen:expect([[ | {1:~ }|*2 - {2:XTEST_1}{3: XTEST_2 }| + {100:XTEST_1}{3: XTEST_2 }| :!echo $XTEST_1^ | ]]) end) @@ -537,7 +535,7 @@ describe('command line completion', function() screen:expect([[ | {1:~ }|*2 - {2:XTEST_1AaあB}{3: XTEST_2 }| + {100:XTEST_1AaあB}{3: XTEST_2 }| :!echo $XTEST_1AaあB^ | ]]) end) -- cgit From 4199671047b0cb62781995a8f6a4b66fb6e8b6fd Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Thu, 15 Aug 2024 06:09:14 -0500 Subject: feat(term): support OSC 8 hyperlinks in :terminal (#30050) --- test/functional/terminal/highlight_spec.lua | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'test/functional') diff --git a/test/functional/terminal/highlight_spec.lua b/test/functional/terminal/highlight_spec.lua index 4f3d010d02..ca41cbf4a2 100644 --- a/test/functional/terminal/highlight_spec.lua +++ b/test/functional/terminal/highlight_spec.lua @@ -380,3 +380,23 @@ describe(':terminal highlight with custom palette', function() ]]) end) end) + +describe(':terminal', function() + before_each(clear) + + it('can display URLs', function() + local screen = Screen.new(50, 7) + screen:add_extra_attr_ids { + [100] = { url = 'https://example.com' }, + } + screen:attach() + local chan = api.nvim_open_term(0, {}) + api.nvim_chan_send(chan, '\027]8;;https://example.com\027\\Example\027]8;;\027\\') + screen:expect({ + grid = [[ + {100:^Example} | + |*6 + ]], + }) + end) +end) -- cgit From ee5aaba21560c3836f46d347c216832864f85668 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 15 Aug 2024 22:02:20 +0800 Subject: fix(man): avoid setting v:errmsg (#30052) --- test/functional/plugin/man_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/plugin/man_spec.lua b/test/functional/plugin/man_spec.lua index 5e4ec53f8d..c0256d1c63 100644 --- a/test/functional/plugin/man_spec.lua +++ b/test/functional/plugin/man_spec.lua @@ -20,7 +20,7 @@ local function get_search_history(name) local args = vim.split(name, ' ') local code = [[ local args = ... - local man = require('runtime.lua.man') + local man = require('man') local res = {} man.find_path = function(sect, name) table.insert(res, {sect, name}) -- cgit From cce1eb0806cc8c2f75b60aee5841b4750c2258c1 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 18 Aug 2024 07:10:27 +0800 Subject: fix(api): error properly with invalid field in nvim_open_win (#30078) --- test/functional/ui/float_spec.lua | 46 ++++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 8 deletions(-) (limited to 'test/functional') diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua index 7aff47e50e..754f0772f6 100644 --- a/test/functional/ui/float_spec.lua +++ b/test/functional/ui/float_spec.lua @@ -327,6 +327,35 @@ describe('float window', function() eq(12, pos[2]) end) + it('error message when invalid field specified for split', function() + local bufnr = api.nvim_create_buf(false, true) + eq( + "non-float cannot have 'row'", + pcall_err(api.nvim_open_win, bufnr, true, { split = 'right', row = 10 }) + ) + eq( + "non-float cannot have 'col'", + pcall_err(api.nvim_open_win, bufnr, true, { split = 'right', col = 10 }) + ) + eq( + "non-float cannot have 'bufpos'", + pcall_err(api.nvim_open_win, bufnr, true, { split = 'right', bufpos = { 0, 0 } }) + ) + local winid = api.nvim_open_win(bufnr, true, { split = 'right' }) + eq( + "non-float cannot have 'row'", + pcall_err(api.nvim_win_set_config, winid, { split = 'right', row = 10 }) + ) + eq( + "non-float cannot have 'col'", + pcall_err(api.nvim_win_set_config, winid, { split = 'right', col = 10 }) + ) + eq( + "non-float cannot have 'bufpos'", + pcall_err(api.nvim_win_set_config, winid, { split = 'right', bufpos = { 0, 0 } }) + ) + end) + it('error message when reconfig missing relative field', function() local bufnr = api.nvim_create_buf(false, true) local opts = { @@ -337,15 +366,16 @@ describe('float window', function() relative = 'editor', style = 'minimal', } - local win_id = api.nvim_open_win(bufnr, true, opts) + local winid = api.nvim_open_win(bufnr, true, opts) eq( - "Missing 'relative' field when reconfiguring floating window 1001", - pcall_err(api.nvim_win_set_config, win_id, { - width = 3, - height = 3, - row = 10, - col = 10, - })) + "Missing 'relative' field when reconfiguring floating window 1001", + pcall_err(api.nvim_win_set_config, winid, { + width = 3, + height = 3, + row = 10, + col = 10, + }) + ) end) it('is not operated on by windo when non-focusable #15374', function() -- cgit From 33464189bc02b2555e26dc4e9f7b3fbbcdd02490 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Sat, 17 Aug 2024 22:28:03 -0500 Subject: fix(vim.text): handle very long strings (#30075) Lua's string.byte has a maximum (undocumented) allowable length, so vim.text.hencode fails on large strings with the error "string slice too long". Instead of converting the string to an array of bytes up front, convert each character to a byte one at a time. --- test/functional/lua/text_spec.lua | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'test/functional') diff --git a/test/functional/lua/text_spec.lua b/test/functional/lua/text_spec.lua index 9e77953c8c..be471bfd62 100644 --- a/test/functional/lua/text_spec.lua +++ b/test/functional/lua/text_spec.lua @@ -20,5 +20,11 @@ describe('vim.text', function() eq(input, vim.text.hexdecode(output)) end end) + + it('works with very large strings', function() + local input, output = string.rep('😂', 2 ^ 16), string.rep('F09F9882', 2 ^ 16) + eq(output, vim.text.hexencode(input)) + eq(input, vim.text.hexdecode(output)) + end) end) end) -- cgit From 6d997f8068a89703823f1572c56a6331c9e024aa Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Mon, 19 Aug 2024 06:43:06 -0500 Subject: fix(terminal): handle C0 characters in OSC terminator (#30090) When a C0 character is present in an OSC terminator (i.e. after the ESC but before a \ (0x5c) or printable character), vterm executes the control character and resets the current string fragment. If the C0 character is the final byte in the sequence, the string fragment has a zero length. However, because the VT parser is still in the "escape" state, vterm attempts to subtract 1 from the string length (to account for the escape character). When the string fragment is empty, this causes an underflow in the unsigned size variable, resulting in a buffer overflow. The fix is simple: explicitly check if the string length is non-zero before subtracting. --- test/functional/terminal/parser_spec.lua | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 test/functional/terminal/parser_spec.lua (limited to 'test/functional') diff --git a/test/functional/terminal/parser_spec.lua b/test/functional/terminal/parser_spec.lua new file mode 100644 index 0000000000..67f47c7888 --- /dev/null +++ b/test/functional/terminal/parser_spec.lua @@ -0,0 +1,15 @@ +local n = require('test.functional.testnvim')() + +local clear = n.clear +local api = n.api +local assert_alive = n.assert_alive + +describe(':terminal', function() + before_each(clear) + + it('handles invalid OSC terminators #30084', function() + local chan = api.nvim_open_term(0, {}) + api.nvim_chan_send(chan, '\027]8;;https://example.com\027\\Example\027]8;;\027\n') + assert_alive() + end) +end) -- cgit From 1d11808bfd2879bf278cd05a7095a6634fa5afec Mon Sep 17 00:00:00 2001 From: ibhagwan <59988195+ibhagwan@users.noreply.github.com> Date: Mon, 19 Aug 2024 15:23:56 -0700 Subject: fix(terminal): interrupt/got_int hangs terminal (#30056) Upon `terminal_enter`, `mapped_ctrl_c` is set in order to avoid `CTRL-C` interrupts (which is proxied to the terminal process instead), `os_inchar` will then test `mapped_ctrl_c` against `State` and set `ctrl_c_interrupts=false` which prevents `process_ctrl_c` from setting `got_int=true` in a terminal state. However, if `got_int` is set outside of `process_ctrl_c`, e.g. via `interrupt()`, this will hang the neovim process as `terminal_execute` will enter an endless loop as `got_int` will never be cleared causing `safe_vgetc` to always return `Ctrl_C`. A minimal example reproducing this bug: ```vim :autocmd TermEnter * call timer_start(500, {-> interrupt()}) :terminal :startinsert ``` To fix, we make sure `got_int` is cleared inside `terminal_execute` when it detects `Ctrl_C`. Closes #20726 Co-authored-by: zeertzjq --- test/functional/terminal/buffer_spec.lua | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'test/functional') diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua index 365a4f8035..767a3dc205 100644 --- a/test/functional/terminal/buffer_spec.lua +++ b/test/functional/terminal/buffer_spec.lua @@ -312,6 +312,16 @@ describe(':terminal buffer', function() pcall_err(command, 'write test/functional/fixtures/tty-test.c') ) end) + + it('external interrupt (got_int) does not hang #20726', function() + eq({ mode = 't', blocking = false }, api.nvim_get_mode()) + command('call timer_start(0, {-> interrupt()})') + feed('') -- Add input to separate two RPC requests + eq({ mode = 't', blocking = false }, api.nvim_get_mode()) + feed([[]]) + eq({ mode = 'nt', blocking = false }, api.nvim_get_mode()) + command('bd!') + end) end) describe(':terminal buffer', function() -- cgit From a8fbe1d409e08c68b05bc26b096486020ae3162b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 20 Aug 2024 08:20:19 +0800 Subject: fix(decor): don't use separate DecorSignHighlight for url (#30096) --- test/functional/api/extmark_spec.lua | 11 ++++++++--- test/functional/ui/decorations_spec.lua | 19 +++++++++++++------ 2 files changed, 21 insertions(+), 9 deletions(-) (limited to 'test/functional') diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index a7f4ba25e0..52d8fd5097 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -1798,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/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua index 49ba4a7096..1709819575 100644 --- a/test/functional/ui/decorations_spec.lua +++ b/test/functional/ui/decorations_spec.lua @@ -2341,21 +2341,28 @@ describe('extmark decorations', function() it('supports URLs', function() insert(example_text) - local url = 'https://example.com' + local url1 = 'https://example.com' + local url2 = 'http://127.0.0.1' screen:add_extra_attr_ids { - u = { url = "https://example.com" }, + u = { url = url1 }, + uh = { url = url2, background = Screen.colors.Yellow }, } api.nvim_buf_set_extmark(0, ns, 1, 4, { end_col = 14, - url = url, + url = url1, + }) + api.nvim_buf_set_extmark(0, ns, 2, 4, { + end_col = 17, + hl_group = 'Search', + url = url2, }) - screen:expect{grid=[[ + screen:expect([[ for _,item in ipairs(items) do | {u:local text}, hl_id_cell, count = unpack(item) | - if hl_id_cell ~= nil then | + {uh:if hl_id_cell} ~= nil then | hl_id = hl_id_cell | end | for _ = 1, (count or 1) do | @@ -2368,7 +2375,7 @@ describe('extmark decorations', function() {1:~ }| {1:~ }| | - ]]} + ]]) end) it('can replace marks in place with different decorations #27211', function() -- cgit From 1f5bcc7c4ed7a68ae4e23933aee04c50b4df8bb5 Mon Sep 17 00:00:00 2001 From: glepnir Date: Fri, 23 Aug 2024 03:42:27 +0800 Subject: feat(lsp): completion opts support custom item conversion (#30060) Problem: Some items of completion results include function signatures that can cause the pum to be very long when a function has many params, because pum scales with the longest word/abbr. Solution: add custom covert function that can customise abbr to remove params. --- test/functional/plugin/lsp/completion_spec.lua | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/plugin/lsp/completion_spec.lua b/test/functional/plugin/lsp/completion_spec.lua index aad7e350ee..766dd16541 100644 --- a/test/functional/plugin/lsp/completion_spec.lua +++ b/test/functional/plugin/lsp/completion_spec.lua @@ -495,7 +495,9 @@ describe('vim.lsp.completion: protocol', function() bufnr = vim.api.nvim_get_current_buf() vim.api.nvim_win_set_buf(0, bufnr) return vim.lsp.start({ name = 'dummy', cmd = server.cmd, on_attach = function(client, bufnr) - vim.lsp.completion.enable(true, client.id, bufnr) + vim.lsp.completion.enable(true, client.id, bufnr, { convert = function(item) + return { abbr = item.label:gsub('%b()', '')} + end}) end}) ]], completion_result @@ -700,4 +702,21 @@ describe('vim.lsp.completion: protocol', function() eq(true, exec_lua('return _G.called')) end) end) + + it('custom word/abbar format', function() + create_server({ + isIncomplete = false, + items = { + { + label = 'foo(bar)', + }, + }, + }) + + feed('ifo') + trigger_at_pos({ 1, 1 }) + assert_matches(function(matches) + eq('foo', matches[1].abbr) + end) + end) end) -- cgit From bb4b6b427c1952b4a9b72f406b913ec59f0d4d22 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 24 Aug 2024 08:38:05 +0800 Subject: vim-patch:9.1.0690: cannot set special highlight kind in popupmenu (#30128) Problem: cannot set special highlight kind in popupmenu Solution: add kind_hlgroup item to complete function (glepnir) closes: vim/vim#15561 https://github.com/vim/vim/commit/38f99a1f0d61e9bde3f4a3d0cbe2d06185c4a57f Co-authored-by: glepnir --- test/functional/ui/popupmenu_spec.lua | 41 +++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'test/functional') diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index c73d5bf97a..370a18b908 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -5011,6 +5011,47 @@ describe('builtin popupmenu', function() ]]) feed('') end) + + -- oldtest: Test_pum_user_kind_hlgroup() + it('custom kind_hlgroup override', function() + exec([[ + func CompleteFunc( findstart, base ) + if a:findstart + return 0 + endif + return { + \ 'words': [ + \ { 'word': 'aword1', 'menu': 'extra text 1', 'kind': 'variable', 'kind_hlgroup': 'KindVar', 'hl_group': 'StrikeFake' }, + \ { 'word': 'aword2', 'menu': 'extra text 2', 'kind': 'function', 'kind_hlgroup': 'KindFunc' }, + \ { 'word': '你好', 'menu': 'extra text 3', 'kind': 'class', 'kind_hlgroup': 'KindClass' }, + \]} + endfunc + set completeopt=menu + set completefunc=CompleteFunc + + hi StrikeFake guifg=DarkRed + hi KindVar guifg=DarkYellow + hi KindFunc guifg=DarkBlue + hi KindClass guifg=DarkGreen + ]]) + + local attr_ids = screen:get_default_attr_ids() + attr_ids.kvs = { foreground = Screen.colors.DarkYellow, background = Screen.colors.Grey } + attr_ids.kfn = { foreground = Screen.colors.DarkBlue, background = Screen.colors.Plum1 } + attr_ids.kcn = { foreground = Screen.colors.DarkGreen, background = Screen.colors.Plum1 } + screen:set_default_attr_ids(attr_ids) + + feed('S') + screen:expect([[ + aword1^ | + {ds:aword1 }{kvs:variable }{ds:extra text 1 }{1: }| + {n:aword2 }{kfn:function }{n:extra text 2 }{1: }| + {n:你好 }{kcn:class }{n:extra text 3 }{1: }| + {1:~ }|*15 + {2:-- }{5:match 1 of 3} | + ]]) + feed('') + end) end end -- cgit From cf44121f7fb6f55a22e644a1e5e1f1dc6b90c27a Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 25 Aug 2024 06:07:43 +0800 Subject: vim-patch:9.1.0694: matchparen is slow on a long line (#30134) Problem: The matchparen plugin is slow on a long line. Solution: Don't use a regexp to get char at and before cursor. (zeertzjq) Example: ```vim call setline(1, repeat(' foobar', 100000)) runtime plugin/matchparen.vim normal! $hhhhhhhh ``` closes: vim/vim#15568 https://github.com/vim/vim/commit/81e7513c86459c40676bd983f73c2722096d67a9 --- test/functional/legacy/matchparen_spec.lua | 79 ++++++++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 4 deletions(-) (limited to 'test/functional') diff --git a/test/functional/legacy/matchparen_spec.lua b/test/functional/legacy/matchparen_spec.lua index 3841761515..df0d80f0ab 100644 --- a/test/functional/legacy/matchparen_spec.lua +++ b/test/functional/legacy/matchparen_spec.lua @@ -120,8 +120,7 @@ describe('matchparen', function() ]]) feed('i') - screen:expect { - grid = [[ + screen:expect([[ aa | aaa | aaaa | @@ -131,7 +130,79 @@ describe('matchparen', function() {4: aaaa }{1: }| {1:~ }| {5:-- }{6:match 2 of 3} | - ]], - } + ]]) + end) + + -- oldtest: Test_matchparen_mbyte() + it("works with multibyte chars in 'matchpairs'", function() + local screen = Screen.new(30, 10) + screen:set_default_attr_ids({ + [0] = { bold = true, foreground = Screen.colors.Blue }, + [1] = { background = Screen.colors.Cyan }, + [2] = { bold = true }, + }) + screen:attach() + + exec([[ + source $VIMRUNTIME/plugin/matchparen.vim + call setline(1, ['aaaaaaaa(', 'bbbb)cc']) + set matchpairs+=(:) + ]]) + + screen:expect([[ + ^aaaaaaaa( | + bbbb)cc | + {0:~ }|*7 + | + ]]) + feed('$') + screen:expect([[ + aaaaaaaa{1:^(} | + bbbb{1:)}cc | + {0:~ }|*7 + | + ]]) + feed('j') + screen:expect([[ + aaaaaaaa( | + bbbb)c^c | + {0:~ }|*7 + | + ]]) + feed('2h') + screen:expect([[ + aaaaaaaa{1:(} | + bbbb{1:^)}cc | + {0:~ }|*7 + | + ]]) + feed('0') + screen:expect([[ + aaaaaaaa( | + ^bbbb)cc | + {0:~ }|*7 + | + ]]) + feed('kA') + screen:expect([[ + aaaaaaaa{1:(}^ | + bbbb{1:)}cc | + {0:~ }|*7 + {2:-- INSERT --} | + ]]) + feed('') + screen:expect([[ + aaaaaaaa( | + bbbb)cc^ | + {0:~ }|*7 + {2:-- INSERT --} | + ]]) + feed('') + screen:expect([[ + aaaaaaaa{1:(} | + bbbb{1:)}^ | + {0:~ }|*7 + {2:-- INSERT --} | + ]]) end) end) -- cgit From 688b961d13bd54a14836f08c3ded3121d3fb15a0 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Fri, 19 Apr 2024 16:04:57 +0100 Subject: feat(treesitter): add support for wasm parsers Problem: Installing treesitter parser is hard (harder than climbing to heaven). Solution: Add optional support for wasm parsers with `wasmtime`. Notes: * Needs to be enabled by setting `ENABLE_WASMTIME` for tree-sitter and Neovim. Build with `make CMAKE_EXTRA_FLAGS=-DENABLE_WASMTIME=ON DEPS_CMAKE_FLAGS=-DENABLE_WASMTIME=ON` * Adds optional Rust (obviously) and C11 dependencies. * Wasmtime comes with a lot of features that can negatively affect Neovim performance due to library and symbol table size. Make sure to build with minimal features and full LTO. * To reduce re-compilation times, install `sccache` and build with `RUSTC_WRAPPER= make ...` --- test/functional/treesitter/language_spec.lua | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'test/functional') diff --git a/test/functional/treesitter/language_spec.lua b/test/functional/treesitter/language_spec.lua index ba2d2218e3..6c211049f0 100644 --- a/test/functional/treesitter/language_spec.lua +++ b/test/functional/treesitter/language_spec.lua @@ -57,8 +57,12 @@ describe('treesitter language API', function() local keys, fields, symbols = unpack(exec_lua(function() local lang = vim.treesitter.language.inspect('c') local keys, symbols = {}, {} - for k, _ in pairs(lang) do - keys[k] = true + for k, v in pairs(lang) do + if type(v) == 'boolean' then + keys[k] = v + else + keys[k] = true + end end -- symbols array can have "holes" and is thus not a valid msgpack array @@ -69,7 +73,7 @@ describe('treesitter language API', function() return { keys, lang.fields, symbols } end)) - eq({ fields = true, symbols = true, _abi_version = true }, keys) + eq({ fields = true, symbols = true, _abi_version = true, _wasm = false }, keys) local fset = {} for _, f in pairs(fields) do -- cgit From 59baa5e8a1f9e71b82f28c2723ccc558370b6fc0 Mon Sep 17 00:00:00 2001 From: Riley Bruins Date: Thu, 29 Aug 2024 09:36:33 -0700 Subject: fix(tohtml): apply sp color if present #30110 Problem: Things like underlines are always given a default foreground highlight regardless of the value of `sp`. Solution: Check for `sp` first, and apply that color to the text decoration color if it exists. Limitations: If there is no value of `sp`, vim applies a text decoration color that matches the foreground of the text. This is still not implemented (and seems like a much more complex problem): in TOhtml, the underline will still be given a default foreground highlight. --- test/functional/plugin/tohtml_spec.lua | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'test/functional') diff --git a/test/functional/plugin/tohtml_spec.lua b/test/functional/plugin/tohtml_spec.lua index 827db8c0f3..dbf385c0c3 100644 --- a/test/functional/plugin/tohtml_spec.lua +++ b/test/functional/plugin/tohtml_spec.lua @@ -33,6 +33,10 @@ local function html_syntax_match() attr.underline = nil attr.undercurl = true end + attr.sp = style:match('text%-decoration%-color: #(%x+)') + if attr.sp then + attr.sp = tonumber(attr.sp, 16) + end attr.bg = style:match('background%-color: #(%x+)') if attr.bg then attr.bg = tonumber(attr.bg, 16) @@ -49,7 +53,7 @@ local function html_syntax_match() local whitelist = { 'fg', 'bg', - --'sp', + 'sp', --'blend', 'bold', --'standout', @@ -216,7 +220,7 @@ describe(':TOhtml', function() it('highlight attributes generated', function() --Make sure to uncomment the attribute in `html_syntax_match()` - exec('hi LINE gui=' .. table.concat({ + exec('hi LINE guisp=#00ff00 gui=' .. table.concat({ 'bold', 'underline', 'italic', -- cgit From cfdf68a7acde16597fbd896674af68c42361102c Mon Sep 17 00:00:00 2001 From: bfredl Date: Thu, 8 Aug 2024 10:42:08 +0200 Subject: feat(mbyte): support extended grapheme clusters including more emoji Use the grapheme break algorithm from utf8proc to support grapheme clusters from recent unicode versions. Handle variant selector VS16 turning some codepoints into double-width emoji. This means we need to use ptr2cells rather than char2cells when possible. --- test/functional/api/vim_spec.lua | 22 ++++++ test/functional/ui/decorations_spec.lua | 21 ++++++ test/functional/ui/messages_spec.lua | 35 +++++++++ test/functional/ui/multibyte_spec.lua | 122 +++++++++++++++++++++++++++++--- 4 files changed, 191 insertions(+), 9 deletions(-) (limited to 'test/functional') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 4210b7ecf0..074d3ac0a3 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -1435,6 +1435,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() diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua index 1709819575..61a5e1d6f7 100644 --- a/test/functional/ui/decorations_spec.lua +++ b/test/functional/ui/decorations_spec.lua @@ -5620,6 +5620,27 @@ l5 ]] }) end) + + it('supports emoji as signs', function() + insert(example_test3) + feed 'gg' + api.nvim_buf_set_extmark(0, ns, 1, 0, {sign_text='🧑‍🌾'}) + -- VS16 can change width of character + api.nvim_buf_set_extmark(0, ns, 2, 0, {sign_text='❤️'}) + api.nvim_buf_set_extmark(0, ns, 3, 0, {sign_text='❤'}) + api.nvim_buf_set_extmark(0, ns, 4, 0, {sign_text='❤x'}) + screen:expect([[ + {7: }^l1 | + 🧑‍🌾l2 | + ❤️l3 | + ❤ l4 | + ❤xl5 | + {7: } | + {1:~ }|*3 + | + ]]) + eq("Invalid 'sign_text'", pcall_err(api.nvim_buf_set_extmark, 0, ns, 5, 0, {sign_text='❤️x'})) + end) end) describe('decorations: virt_text', function() diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua index 07192800e5..036b5ceefc 100644 --- a/test/functional/ui/messages_spec.lua +++ b/test/functional/ui/messages_spec.lua @@ -1436,6 +1436,41 @@ vimComment xxx match /\s"[^\-:.%#=*].*$/ms=s+1,lc=1 excludenl contains=@vim } end) + it('supports nvim_echo messages with emoji', function() + -- stylua: ignore + async_meths.nvim_echo( + { { 'wow, 🏳️‍⚧️🧑‍🌾❤️😂🏴‍☠️\nvariant ❤️ one\nvariant ❤ two' } }, true, {} + ) + + screen:expect([[ + | + {1:~ }| + {3: }| + wow, 🏳️‍⚧️🧑‍🌾❤️😂🏴‍☠️ | + variant ❤️ one | + variant ❤ two | + {6:Press ENTER or type command to continue}^ | + ]]) + + feed '' + screen:expect([[ + ^ | + {1:~ }|*5 + | + ]]) + + feed ':messages' + screen:expect([[ + | + {1:~ }| + {3: }| + wow, 🏳️‍⚧️🧑‍🌾❤️😂🏴‍☠️ | + variant ❤️ one | + variant ❤ two | + {6:Press ENTER or type command to continue}^ | + ]]) + end) + it('prints lines in Ex mode correctly with a burst of carriage returns #19341', function() command('set number') api.nvim_buf_set_lines(0, 0, 0, true, { 'aaa', 'bbb', 'ccc' }) diff --git a/test/functional/ui/multibyte_spec.lua b/test/functional/ui/multibyte_spec.lua index dc25a09d0d..f16f750ea1 100644 --- a/test/functional/ui/multibyte_spec.lua +++ b/test/functional/ui/multibyte_spec.lua @@ -296,6 +296,86 @@ describe('multibyte rendering', function() ]], } end) + + it('supports emoji with variant selectors and ZWJ', function() + command('set ruler') + insert('🏳️‍⚧️') + screen:expect([[ + ^🏳️‍⚧️ | + {1:~ }|*4 + 1,1 All | + ]]) + + feed('a word') + screen:expect([[ + 🏳️‍⚧️ wor^d | + {1:~ }|*4 + 1,21-7 All | + ]]) + + feed('0') + screen:expect([[ + ^🏳️‍⚧️ word | + {1:~ }|*4 + 1,1 All | + ]]) + + feed('l') + screen:expect([[ + 🏳️‍⚧️^ word | + {1:~ }|*4 + 1,17-3 All | + ]]) + + feed('h') + screen:expect([[ + ^🏳️‍⚧️ word | + {1:~ }|*4 + 1,1 All | + ]]) + + feed('o❤️ variant selected') + screen:expect([[ + 🏳️‍⚧️ word | + ❤️ variant selecte^d | + {1:~ }|*3 + 2,23-19 All | + ]]) + + feed('0') + screen:expect([[ + 🏳️‍⚧️ word | + ^❤️ variant selected | + {1:~ }|*3 + 2,1 All | + ]]) + + feed('l') + screen:expect([[ + 🏳️‍⚧️ word | + ❤️^ variant selected | + {1:~ }|*3 + 2,7-3 All | + ]]) + + feed('h') + screen:expect([[ + 🏳️‍⚧️ word | + ^❤️ variant selected | + {1:~ }|*3 + 2,1 All | + ]]) + + -- without selector: single width (note column 18 and not 19) + feed('o❤ variant selected') + screen:expect([[ + 🏳️‍⚧️ word | + ❤️ variant selected | + ❤ variant selecte^d | + {1:~ }|*2 + 3,20-18 All | + ]]) + end) end) describe('multibyte rendering: statusline', function() @@ -348,11 +428,12 @@ describe('multibyte rendering: statusline', function() it('non-printable followed by MAX_MCO unicode combination points', function() command('set statusline=Ÿ̸⃯ᷰ⃐⃧⃝') -- U+9F + U+1DF0 + U+20EF + U+0338 + U+20D0 + U+20E7 + U+20DD + -- TODO: not ideal, better with plain ">" and then space+combining screen:expect([[ - ^ | - {1:~ }| - {3:<9f><1df0><20ef><0338><20d0><20e7><20dd>}| - | + ^ | + {1:~ }| + {3:<9f≯⃯ᷰ⃐⃧⃝ }| + | ]]) end) @@ -368,9 +449,20 @@ describe('multibyte rendering: statusline', function() } end) - it('unprintable chars in filename with default stl', function() + it('emoji with ZWJ in filename with default stl', function() command('file 🧑‍💻') - -- TODO: this is wrong but avoids a crash + screen:expect { + grid = [[ + ^ | + {1:~ }| + {3:🧑‍💻 }| + | + ]], + } + end) + + it('unprintable chars in filename with default stl', function() + command('file 🧑​💻') screen:expect { grid = [[ ^ | @@ -381,15 +473,27 @@ describe('multibyte rendering: statusline', function() } end) - it('unprintable chars in filename with custom stl', function() + it('emoji with ZWJ in filename with custom stl', function() command('set statusline=xx%#ErrorMsg#%f%##yy') command('file 🧑‍💻') - -- TODO: this is also wrong but also avoids a crash screen:expect { grid = [[ ^ | {1:~ }| - {3:xx}{9:🧑<200d>💻}{3:yy }| + {3:xx}{9:🧑‍💻}{3:yy }| + | + ]], + } + end) + + it('unprintable chars in filename with custom stl', function() + command('set statusline=xx%#ErrorMsg#%f%##yy') + command('file 🧑​💻') + screen:expect { + grid = [[ + ^ | + {1:~ }| + {3:xx}{9:🧑<200b>💻}{3:yy }| | ]], } -- cgit From 42ed0ffad9851f3794a9dff080a2789c87c6d7c8 Mon Sep 17 00:00:00 2001 From: glepnir Date: Sat, 31 Aug 2024 02:23:49 +0800 Subject: fix(lsp): when prefix is non word add all result into matches (#30044) Problem: prefix can be a symbol like period, the fuzzy matching can't handle it correctly. Solution: when prefix is empty or a symbol add all lsp completion result into matches. --- test/functional/plugin/lsp/completion_spec.lua | 33 +++++++++++++++++++++----- 1 file changed, 27 insertions(+), 6 deletions(-) (limited to 'test/functional') diff --git a/test/functional/plugin/lsp/completion_spec.lua b/test/functional/plugin/lsp/completion_spec.lua index 766dd16541..16d64fc95d 100644 --- a/test/functional/plugin/lsp/completion_spec.lua +++ b/test/functional/plugin/lsp/completion_spec.lua @@ -18,35 +18,36 @@ local create_server_definition = t_lsp.create_server_definition ---@param candidates lsp.CompletionList|lsp.CompletionItem[] ---@param lnum? integer 0-based, defaults to 0 ---@return {items: table[], server_start_boundary: integer?} -local function complete(line, candidates, lnum) +local function complete(line, candidates, lnum, server_boundary) lnum = lnum or 0 -- nvim_win_get_cursor returns 0 based column, line:find returns 1 based local cursor_col = line:find('|') - 1 line = line:gsub('|', '') return exec_lua( [[ - local line, cursor_col, lnum, result = ... + local line, cursor_col, lnum, result, server_boundary = ... local line_to_cursor = line:sub(1, cursor_col) local client_start_boundary = vim.fn.match(line_to_cursor, '\\k*$') - local items, server_start_boundary = require("vim.lsp.completion")._convert_results( + local items, new_server_boundary = require("vim.lsp.completion")._convert_results( line, lnum, cursor_col, 1, client_start_boundary, - nil, + server_boundary, result, "utf-16" ) return { items = items, - server_start_boundary = server_start_boundary + server_start_boundary = new_server_boundary } ]], line, cursor_col, lnum, - candidates + candidates, + server_boundary ) end @@ -162,6 +163,26 @@ describe('vim.lsp.completion: item conversion', function() eq(expected, result) end) + it('works on non word prefix', function() + local completion_list = { + { label = ' foo', insertText = '->foo' }, + } + local result = complete('wp.|', completion_list, 0, 2) + local expected = { + { + abbr = ' foo', + word = '->foo', + }, + } + result = vim.tbl_map(function(x) + return { + abbr = x.abbr, + word = x.word, + } + end, result.items) + eq(expected, result) + end) + it('trims trailing newline or tab from textEdit', function() local range0 = { start = { line = 0, character = 0 }, -- cgit From 55dc482e757e1d8f7713daa61a2deddfdaca4e42 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 31 Aug 2024 04:03:30 +0800 Subject: fix(completion): fix inconsistent Enter behavior (#30196) Problem: Behavior of Enter in completion depends on typing speed. Solution: Don't make whether Enter selects original text depend on whether completion has been interrupted, which can happen interactively with a slow completion function. --- test/functional/editor/completion_spec.lua | 63 +++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/editor/completion_spec.lua b/test/functional/editor/completion_spec.lua index 9d5bda0acc..3f19596bd7 100644 --- a/test/functional/editor/completion_spec.lua +++ b/test/functional/editor/completion_spec.lua @@ -327,7 +327,7 @@ describe('completion', function() end end) - describe('refresh:always', function() + describe('with refresh:always and noselect', function() before_each(function() source([[ function! TestCompletion(findstart, base) abort @@ -459,6 +459,67 @@ describe('completion', function() June June]]) end) + + it('Enter does not select original text', function() + feed('iJ') + poke_eventloop() + feed('u') + poke_eventloop() + feed('') + expect([[ + Ju + ]]) + feed('J') + poke_eventloop() + feed('') + expect([[ + Ju + J + ]]) + end) + end) + + describe('with noselect but not refresh:always', function() + before_each(function() + source([[ + function! TestCompletion(findstart, base) abort + if a:findstart + let line = getline('.') + let start = col('.') - 1 + while start > 0 && line[start - 1] =~ '\a' + let start -= 1 + endwhile + return start + else + let ret = [] + for m in split("January February March April May June July August September October November December") + if m =~ a:base " match by regex + call add(ret, m) + endif + endfor + return {'words':ret} + endif + endfunction + + set completeopt=menuone,noselect + set completefunc=TestCompletion + ]]) + end) + + it('Enter selects original text after adding leader', function() + feed('iJ') + poke_eventloop() + feed('u') + poke_eventloop() + feed('') + expect('Ju') + feed('') + poke_eventloop() + -- The behavior should be the same when completion has been interrupted, + -- which can happen interactively if the completion function is slow. + feed('SJu') + expect('Ju') + end) end) describe('with a lot of items', function() -- cgit From ea2998fec90ce4666b9b85b2d1a7458e717e2a5a Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 1 Sep 2024 06:21:36 +0800 Subject: vim-patch:9.1.0704: inserting with a count is inefficient (#30206) Problem: inserting with a count is inefficient Solution: Disable calculation of the cursor position and topline, if a count has been used (Ken Takata) Optimize insertion when using :normal 10000ix. This patch optimizes the insertion with a large count (e.g. `:normal 10000ix`). It seems that calculation of the cursor position for a long line is slow and it takes O(n^2). Disable the calculation if not needed. Before: ``` $ time ./vim --clean -c 'normal 10000ix' -cq! real 0m1.879s user 0m1.328s sys 0m0.139s $ time ./vim --clean -c 'normal 20000ix' -cq! real 0m5.574s user 0m5.421s sys 0m0.093s $ time ./vim --clean -c 'normal 40000ix' -cq! real 0m23.588s user 0m23.187s sys 0m0.140s ``` After: ``` $ time ./vim --clean -c 'normal 10000ix' -cq! real 0m0.187s user 0m0.046s sys 0m0.093s $ time ./vim --clean -c 'normal 20000ix' -cq! real 0m0.217s user 0m0.046s sys 0m0.108s $ time ./vim --clean -c 'normal 40000ix' -cq! real 0m0.278s user 0m0.093s sys 0m0.140s $ time ./vim --clean -c 'normal 80000ix' -cq! real 0m0.494s user 0m0.311s sys 0m0.140s $ time ./vim --clean -c 'normal 160000ix' -cq! real 0m1.302s user 0m1.140s sys 0m0.094s ``` closes: vim/vim#15588 https://github.com/vim/vim/commit/09b80d23cfae24fa13ef4f52b0ec90625839a6ab Co-authored-by: Ken Takata --- test/functional/ui/mouse_spec.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'test/functional') diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua index 0228708958..8bda661902 100644 --- a/test/functional/ui/mouse_spec.lua +++ b/test/functional/ui/mouse_spec.lua @@ -987,7 +987,7 @@ describe('ui/mouse/input', function() command('set sidescroll=0') feed(':set nowrap') - feed('a 20Ab') + feed('a 17Ab3Ab') screen:expect([[ |*2 bbbbbbbbbbbbbbb^b | @@ -1017,7 +1017,7 @@ describe('ui/mouse/input', function() command('set sidescroll=0') feed(':set nowrap') - feed('a 20Ab') + feed('a 17Ab3Ab') screen:expect([[ |*2 bbbbbbbbbbbbbbb^b | -- cgit From bfa365a8726788e0a6df85b8f9e620a0904fe529 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 1 Sep 2024 07:57:09 +0800 Subject: fix(completion): don't include in -complete= (#30209) --- test/functional/editor/completion_spec.lua | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/editor/completion_spec.lua b/test/functional/editor/completion_spec.lua index 3f19596bd7..d543de4acd 100644 --- a/test/functional/editor/completion_spec.lua +++ b/test/functional/editor/completion_spec.lua @@ -4,7 +4,7 @@ local Screen = require('test.functional.ui.screen') local assert_alive = n.assert_alive local clear, feed = n.clear, n.feed -local eval, eq, neq = n.eval, t.eq, t.neq +local eval, eq, neq, ok = n.eval, t.eq, t.neq, t.ok local feed_command, source, expect = n.feed_command, n.source, n.expect local fn = n.fn local command = n.command @@ -947,6 +947,12 @@ describe('completion', function() eq('SpecialKey', fn.getcompletion('set winhighlight=NonText:', 'cmdline')[1]) end) + it('cmdline completion for -complete does not contain spaces', function() + for _, str in ipairs(fn.getcompletion('command -complete=', 'cmdline')) do + ok(not str:find(' '), 'string without spaces', str) + end + end) + describe('from the commandline window', function() it('is cleared after CTRL-C', function() feed('q:') -- cgit From 97f8d1de1cfaebd67bc994401da38b003b64b6df Mon Sep 17 00:00:00 2001 From: luukvbaal Date: Sun, 1 Sep 2024 14:19:19 +0200 Subject: vim-patch:9.1.0708: Recursive window update does not account for reset skipcol (#30217) Problem: Window is updated with potentially invalid skipcol in recursive window update path. I.e. cursor outside of visible range in large line that does not fit. Solution: Make sure it is valid (Luuk van Baal). https://github.com/vim/vim/commit/3d5065fc7553c8de3d0555c3085165bdd724663b --- test/functional/legacy/scroll_opt_spec.lua | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'test/functional') diff --git a/test/functional/legacy/scroll_opt_spec.lua b/test/functional/legacy/scroll_opt_spec.lua index 97578067d5..80b689df55 100644 --- a/test/functional/legacy/scroll_opt_spec.lua +++ b/test/functional/legacy/scroll_opt_spec.lua @@ -1204,16 +1204,15 @@ describe('smoothscroll', function() set smoothscroll scrolloff=3 call setline(1, ['one', 'two long '->repeat(100), 'three', 'four', 'five', 'six']) ]]) - --FIXME: incorrect screen due to reset_skipcol()/curs_columns() shenanigans feed(':norm j721|') screen:expect([[ - two long two long two long two long two | + {1:<<<}two long two long two long two long t| + wo long two long two long two long two l| + ong two long two long two long two long | + ^two long two long two long two long two | long two long two long two long two long| two long two long two long two long two| - ^ long two long two long two long two lon| - g two long two long two long two long tw| - o long two long two long two long two lo| - ng two long two long two long two long t| + long two long two long two long two lon| :norm j721| | ]]) feed('gj') @@ -1272,15 +1271,14 @@ describe('smoothscroll', function() :norm j721| | ]]) feed('gk') - --FIXME: incorrect screen due to reset_skipcol()/curs_columns() shenanigans screen:expect([[ + {1:<<<}long two long two long two long two l| + ong two long two long two long two long | two long two long two long two long two | long two long two long two long two long| two long two long two long two long two| long two long two long two long two lon| - g two long two long two long two long tw| - o long two long two long two long two lo| - ^ng two long two long two long two long t| + ^g two long two long | :norm j721| | ]]) end) -- cgit From 6913c5e1d975a11262d08b3339d50b579e6b6bb8 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Sun, 1 Sep 2024 13:01:53 -0500 Subject: feat(treesitter)!: default to correct behavior for quantified captures (#30193) For context, see https://github.com/neovim/neovim/pull/24738. Before that PR, Nvim did not correctly handle captures with quantifiers. That PR made the correct behavior opt-in to minimize breaking changes, with the intention that the correct behavior would eventually become the default. Users can still opt-in to the old (incorrect) behavior for now, but this option will eventually be removed completely. BREAKING CHANGE: Any plugin which uses `Query:iter_matches()` must update their call sites to expect an array of nodes in the `match` table, rather than a single node. --- test/functional/treesitter/parser_spec.lua | 9 +++------ test/functional/treesitter/query_spec.lua | 20 ++++++++------------ 2 files changed, 11 insertions(+), 18 deletions(-) (limited to 'test/functional') diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua index 46e6a6002a..4aa8beebae 100644 --- a/test/functional/treesitter/parser_spec.lua +++ b/test/functional/treesitter/parser_spec.lua @@ -591,8 +591,7 @@ print() vim.treesitter.query.parse('c', '((number_literal) @number (#set! "key" "value"))') local parser = vim.treesitter.get_parser(0, 'c') - local _, _, metadata = - query:iter_matches(parser:parse()[1]:root(), 0, 0, -1, { all = true })() + local _, _, metadata = query:iter_matches(parser:parse()[1]:root(), 0, 0, -1)() return metadata.key end) @@ -612,8 +611,7 @@ print() ) local parser = vim.treesitter.get_parser(0, 'c') - local _, _, metadata = - query:iter_matches(parser:parse()[1]:root(), 0, 0, -1, { all = true })() + local _, _, metadata = query:iter_matches(parser:parse()[1]:root(), 0, 0, -1)() local _, nested_tbl = next(metadata) return nested_tbl.key end) @@ -633,8 +631,7 @@ print() ) local parser = vim.treesitter.get_parser(0, 'c') - local _, _, metadata = - query:iter_matches(parser:parse()[1]:root(), 0, 0, -1, { all = true })() + local _, _, metadata = query:iter_matches(parser:parse()[1]:root(), 0, 0, -1)() local _, nested_tbl = next(metadata) return nested_tbl end) diff --git a/test/functional/treesitter/query_spec.lua b/test/functional/treesitter/query_spec.lua index 00e8071738..d8338c1335 100644 --- a/test/functional/treesitter/query_spec.lua +++ b/test/functional/treesitter/query_spec.lua @@ -138,7 +138,7 @@ void ui_refresh(void) local parser = vim.treesitter.get_parser(0, 'c') local tree = parser:parse()[1] local res = {} - for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14, { all = true }) do + for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14) do -- can't transmit node over RPC. just check the name and range local mrepr = {} for cid, nodes in pairs(match) do @@ -211,7 +211,7 @@ void ui_refresh(void) local parser = vim.treesitter.get_parser(0, 'c') local tree = parser:parse()[1] local res = {} - for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14, { all = true }) do + for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14) do -- can't transmit node over RPC. just check the name and range local mrepr = {} for cid, nodes in pairs(match) do @@ -260,7 +260,7 @@ void ui_refresh(void) local parser = vim.treesitter.get_parser(0, 'c') local tree = parser:parse()[1] local res = {} - for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14, { all = true }) do + for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14) do -- can't transmit node over RPC. just check the name and range local mrepr = {} for cid, nodes in pairs(match) do @@ -307,7 +307,7 @@ void ui_refresh(void) local parser = vim.treesitter.get_parser(0, 'c') local tree = parser:parse()[1] local res = {} - for pattern, match in cquery:iter_matches(tree:root(), 0, 0, -1, { all = true }) do + for pattern, match in cquery:iter_matches(tree:root(), 0, 0, -1) do -- can't transmit node over RPC. just check the name and range local mrepr = {} for cid, nodes in pairs(match) do @@ -418,7 +418,7 @@ void ui_refresh(void) local parser = vim.treesitter.get_parser(0, 'c') local tree = parser:parse()[1] local res = {} - for pattern, match in cquery:iter_matches(tree:root(), 0, 0, -1, { all = true }) do + for pattern, match in cquery:iter_matches(tree:root(), 0, 0, -1) do -- can't transmit node over RPC. just check the name and range local mrepr = {} for cid, nodes in pairs(match) do @@ -464,11 +464,7 @@ void ui_refresh(void) local parser = vim.treesitter.get_parser(0, 'c') - -- Time bomb: update this in 0.12 - if vim.fn.has('nvim-0.12') == 1 then - return 'Update this test to remove this message and { all = true } from add_predicate' - end - query.add_predicate('is-main?', is_main, { all = true }) + query.add_predicate('is-main?', is_main) local query0 = query.parse('c', custom_query0) @@ -496,7 +492,7 @@ void ui_refresh(void) local parser = vim.treesitter.get_parser(0, 'c') - query.add_predicate('is-main?', is_main, true) + query.add_predicate('is-main?', is_main, { all = false, force = true }) local query0 = query.parse('c', custom_query0) @@ -650,7 +646,7 @@ void ui_refresh(void) local parser = vim.treesitter.get_parser(0, 'c') local tree = parser:parse()[1] local res = {} - for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14) do + for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14, { all = false }) do local mrepr = {} for cid, node in pairs(match) do table.insert(mrepr, { '@' .. cquery.captures[cid], node:type(), node:range() }) -- cgit From 61e9137394fc5229e582a64316c2ffef55d8d7af Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 1 Sep 2024 13:01:24 -0700 Subject: docs: misc #28970 --- test/functional/lua/vim_spec.lua | 10 ++++------ test/functional/plugin/lsp/completion_spec.lua | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) (limited to 'test/functional') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index a70f35e8e3..df68020d8e 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -145,10 +145,9 @@ describe('lua stdlib', function() -- "0.10" or "0.10-dev+xxx" local curstr = ('%s.%s%s'):format(curver.major, curver.minor, prerel or '') eq( - dedent( - [[ - foo.bar() is deprecated. Run ":checkhealth vim.deprecated" for more information]] - ):format(curstr), + ([[foo.bar() is deprecated. Run ":checkhealth vim.deprecated" for more information]]):format( + curstr + ), exec_lua('return vim.deprecate(...)', 'foo.bar()', 'zub.wooo{ok=yay}', curstr) ) -- Same message as above; skipped this time. @@ -178,8 +177,7 @@ describe('lua stdlib', function() it('plugin=nil, to be deleted in the next major version (1.0)', function() eq( - dedent [[ - foo.baz() is deprecated. Run ":checkhealth vim.deprecated" for more information]], + [[foo.baz() is deprecated. Run ":checkhealth vim.deprecated" for more information]], exec_lua [[ return vim.deprecate('foo.baz()', nil, '1.0') ]] ) end) diff --git a/test/functional/plugin/lsp/completion_spec.lua b/test/functional/plugin/lsp/completion_spec.lua index 16d64fc95d..d3796082fb 100644 --- a/test/functional/plugin/lsp/completion_spec.lua +++ b/test/functional/plugin/lsp/completion_spec.lua @@ -724,7 +724,7 @@ describe('vim.lsp.completion: protocol', function() end) end) - it('custom word/abbar format', function() + it('enable(…,{convert=fn}) custom word/abbr format', function() create_server({ isIncomplete = false, items = { -- cgit From 137f98cf6428a55b1b7687c151d8481c1deb9347 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Mon, 2 Sep 2024 19:14:09 +0200 Subject: test: tmpname() can skip file creation --- test/functional/ex_cmds/profile_spec.lua | 9 ++---- test/functional/lua/loader_spec.lua | 3 +- test/functional/plugin/lsp_spec.lua | 52 +++++++++----------------------- 3 files changed, 18 insertions(+), 46 deletions(-) (limited to 'test/functional') diff --git a/test/functional/ex_cmds/profile_spec.lua b/test/functional/ex_cmds/profile_spec.lua index 57e5c6b2dc..365583948b 100644 --- a/test/functional/ex_cmds/profile_spec.lua +++ b/test/functional/ex_cmds/profile_spec.lua @@ -6,17 +6,11 @@ require('os') local eval = n.eval local command = n.command local eq, neq = t.eq, t.neq -local tempfile = t.tmpname() +local tempfile = t.tmpname(false) local source = n.source local matches = t.matches local read_file = t.read_file --- tmpname() also creates the file on POSIX systems. Remove it again. --- We just need the name, ignoring any race conditions. -if uv.fs_stat(tempfile).uid then - os.remove(tempfile) -end - local function assert_file_exists(filepath) neq(nil, uv.fs_stat(filepath).uid) end @@ -31,6 +25,7 @@ describe(':profile', function() after_each(function() n.expect_exit(command, 'qall!') if uv.fs_stat(tempfile).uid ~= nil then + -- Delete the tempfile. We just need the name, ignoring any race conditions. os.remove(tempfile) end end) diff --git a/test/functional/lua/loader_spec.lua b/test/functional/lua/loader_spec.lua index 7d71e33ced..06403e856c 100644 --- a/test/functional/lua/loader_spec.lua +++ b/test/functional/lua/loader_spec.lua @@ -74,8 +74,7 @@ describe('vim.loader', function() vim.loader.enable() ]] - local tmp = t.tmpname() - assert(os.remove(tmp)) + local tmp = t.tmpname(false) assert(t.mkdir(tmp)) assert(t.mkdir(tmp .. '/%')) local tmp1 = tmp .. '/%/x' diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 06e286f872..ff042424f9 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -800,8 +800,7 @@ describe('LSP', function() eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler') if ctx.method == 'start' then local tmpfile_old = tmpname() - local tmpfile_new = tmpname() - os.remove(tmpfile_new) + local tmpfile_new = tmpname(false) exec_lua(function(oldname, newname) _G.BUFFER = vim.api.nvim_get_current_buf() vim.api.nvim_buf_set_name(_G.BUFFER, oldname) @@ -2370,8 +2369,7 @@ describe('LSP', function() end) it('Supports file creation with CreateFile payload', function() - local tmpfile = tmpname() - os.remove(tmpfile) -- Should not exist, only interested in a tmpname + local tmpfile = tmpname(false) local uri = exec_lua('return vim.uri_from_fname(...)', tmpfile) local edit = { documentChanges = { @@ -2388,9 +2386,7 @@ describe('LSP', function() it( 'Supports file creation in folder that needs to be created with CreateFile payload', function() - local tmpfile = tmpname() - os.remove(tmpfile) -- Should not exist, only interested in a tmpname - tmpfile = tmpfile .. '/dummy/x/' + local tmpfile = tmpname(false) .. '/dummy/x/' local uri = exec_lua('return vim.uri_from_fname(...)', tmpfile) local edit = { documentChanges = { @@ -2468,8 +2464,7 @@ describe('LSP', function() end) it('DeleteFile fails if file does not exist and ignoreIfNotExists is false', function() - local tmpfile = tmpname() - os.remove(tmpfile) + local tmpfile = tmpname(false) local uri = exec_lua('return vim.uri_from_fname(...)', tmpfile) local edit = { documentChanges = { @@ -2493,8 +2488,7 @@ describe('LSP', function() it('Can rename an existing file', function() local old = tmpname() write_file(old, 'Test content') - local new = tmpname() - os.remove(new) -- only reserve the name, file must not exist for the test scenario + local new = tmpname(false) local lines = exec_lua(function(old0, new0) local old_bufnr = vim.fn.bufadd(old0) vim.fn.bufload(old_bufnr) @@ -2514,10 +2508,8 @@ describe('LSP', function() it('Can rename a directory', function() -- only reserve the name, file must not exist for the test scenario - local old_dir = tmpname() - local new_dir = tmpname() - os.remove(old_dir) - os.remove(new_dir) + local old_dir = tmpname(false) + local new_dir = tmpname(false) n.mkdir_p(old_dir) @@ -2542,10 +2534,8 @@ describe('LSP', function() end) it('Does not touch buffers that do not match path prefix', function() - local old = tmpname() - local new = tmpname() - os.remove(old) - os.remove(new) + local old = tmpname(false) + local new = tmpname(false) n.mkdir_p(old) eq( @@ -2604,8 +2594,7 @@ describe('LSP', function() it('Maintains undo information for loaded buffer', function() local old = tmpname() write_file(old, 'line') - local new = tmpname() - os.remove(new) + local new = tmpname(false) local undo_kept = exec_lua(function(old0, new0) vim.opt.undofile = true @@ -2629,8 +2618,7 @@ describe('LSP', function() it('Maintains undo information for unloaded buffer', function() local old = tmpname() write_file(old, 'line') - local new = tmpname() - os.remove(new) + local new = tmpname(false) local undo_kept = exec_lua(function(old0, new0) vim.opt.undofile = true @@ -2651,8 +2639,7 @@ describe('LSP', function() it('Does not rename file when it conflicts with a buffer without file', function() local old = tmpname() write_file(old, 'Old File') - local new = tmpname() - os.remove(new) + local new = tmpname(false) local lines = exec_lua(function(old0, new0) local old_buf = vim.fn.bufadd(old0) @@ -5023,13 +5010,7 @@ describe('LSP', function() end) it('can connect to lsp server via pipe or domain_socket', function() - local tmpfile --- @type string - if is_os('win') then - tmpfile = '\\\\.\\\\pipe\\pipe.test' - else - tmpfile = tmpname() - os.remove(tmpfile) - end + local tmpfile = is_os('win') and '\\\\.\\\\pipe\\pipe.test' or tmpname(false) local result = exec_lua(function(SOCK) local uv = vim.uv local server = assert(uv.new_pipe(false)) @@ -5135,9 +5116,7 @@ describe('LSP', function() describe('#dynamic vim.lsp._dynamic', function() it('supports dynamic registration', function() - ---@type string - local root_dir = tmpname() - os.remove(root_dir) + local root_dir = tmpname(false) mkdir(root_dir) local tmpfile = root_dir .. '/dynamic.foo' local file = io.open(tmpfile, 'w') @@ -5264,8 +5243,7 @@ describe('LSP', function() ) end - local root_dir = tmpname() - os.remove(root_dir) + local root_dir = tmpname(false) mkdir(root_dir) exec_lua(create_server_definition) -- cgit From 96128a5076b7e45fc01163151401a9e2acdff565 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Mon, 2 Sep 2024 15:57:07 +0200 Subject: feat(startup): validate --listen address Problem: `nvim --listen` does not error on EADDRINUSE. #30123 Solution: Now that `$NVIM_LISTEN_ADDRESS` is deprecated and input *only* (instead of the old, ambiguous situation where it was both an input *and* an output), we can be fail fast instead of trying to "recover". This reverts the "recovery" behavior of 704ba4151e7f67999510ee0ac19fdabb595d530c, but that was basically a workaround for the fragility of `$NVIM_LISTEN_ADDRESS`. --- test/functional/options/defaults_spec.lua | 25 ++++++++---- test/functional/vimscript/server_spec.lua | 67 ++++++++++++++++++++----------- 2 files changed, 61 insertions(+), 31 deletions(-) (limited to 'test/functional') diff --git a/test/functional/options/defaults_spec.lua b/test/functional/options/defaults_spec.lua index f61139d92d..0faced5149 100644 --- a/test/functional/options/defaults_spec.lua +++ b/test/functional/options/defaults_spec.lua @@ -247,6 +247,7 @@ describe('startup defaults', function() } }) eq('Xtest-logpath', eval('$NVIM_LOG_FILE')) end) + it('defaults to stdpath("log")/log if empty', function() eq(true, mkdir(xdgdir) and mkdir(xdgstatedir)) clear({ @@ -257,6 +258,7 @@ describe('startup defaults', function() }) eq(xdgstatedir .. '/log', string.gsub(eval('$NVIM_LOG_FILE'), '\\', '/')) end) + it('defaults to stdpath("log")/log if invalid', function() eq(true, mkdir(xdgdir) and mkdir(xdgstatedir)) clear({ @@ -266,6 +268,8 @@ describe('startup defaults', function() }, }) eq(xdgstatedir .. '/log', string.gsub(eval('$NVIM_LOG_FILE'), '\\', '/')) + -- Avoid "failed to open $NVIM_LOG_FILE" noise in test output. + expect_exit(command, 'qall!') end) end) end) @@ -339,9 +343,11 @@ describe('XDG defaults', function() local state_dir = is_os('win') and 'nvim-data' or 'nvim' local root_path = is_os('win') and 'C:' or '' - describe('with too long XDG variables', function() + describe('with too long XDG vars', function() before_each(function() clear({ + -- Ensure valid --listen address despite broken XDG vars (else Nvim won't start). + args = { '--listen', is_os('win') and '' or t.tmpname(false) }, args_rm = { 'runtimepath' }, env = { NVIM_LOG_FILE = testlog, @@ -361,6 +367,9 @@ describe('XDG defaults', function() it('are correctly set', function() if not is_os('win') then + -- Broken XDG vars cause serverstart() to fail (except on Windows, where servernames are not + -- informed by $XDG_STATE_HOME). + t.matches('Failed to start server: no such file or directory', t.pcall_err(fn.serverstart)) assert_log('Failed to start server: no such file or directory: /X/X/X', testlog, 10) end @@ -522,9 +531,11 @@ describe('XDG defaults', function() end) end) - describe('with XDG variables that can be expanded', function() + describe('with expandable XDG vars', function() before_each(function() clear({ + -- Ensure valid --listen address despite broken XDG vars (else Nvim won't start). + args = { '--listen', is_os('win') and '' or t.tmpname(false) }, args_rm = { 'runtimepath' }, env = { NVIM_LOG_FILE = testlog, @@ -544,6 +555,9 @@ describe('XDG defaults', function() it('are not expanded', function() if not is_os('win') then + -- Broken XDG vars cause serverstart() to fail (except on Windows, where servernames are not + -- informed by $XDG_STATE_HOME). + t.matches('Failed to start server: no such file or directory', t.pcall_err(fn.serverstart)) assert_log( 'Failed to start server: no such file or directory: %$XDG_RUNTIME_DIR%/', testlog, @@ -895,7 +909,7 @@ describe('stdpath()', function() assert_alive() -- Check for crash. #8393 end) - it('reacts to $NVIM_APPNAME', function() + it('supports $NVIM_APPNAME', function() local appname = 'NVIM_APPNAME_TEST' .. ('_'):rep(106) clear({ env = { NVIM_APPNAME = appname, NVIM_LOG_FILE = testlog } }) eq(appname, fn.fnamemodify(fn.stdpath('config'), ':t')) @@ -916,7 +930,7 @@ describe('stdpath()', function() local function test_appname(testAppname, expected_exitcode) local lua_code = string.format( [[ - local child = vim.fn.jobstart({ vim.v.progpath, '--clean', '--headless', '+qall!' }, { env = { NVIM_APPNAME = %q } }) + local child = vim.fn.jobstart({ vim.v.progpath, '--clean', '--headless', '--listen', 'x', '+qall!' }, { env = { NVIM_APPNAME = %q } }) return vim.fn.jobwait({ child }, %d)[1] ]], alter_slashes(testAppname), @@ -935,9 +949,6 @@ describe('stdpath()', function() -- Valid appnames: test_appname('a/b', 0) test_appname('a/b\\c', 0) - if not is_os('win') then - assert_log('Failed to start server: no such file or directory:', testlog) - end end) describe('returns a String', function() diff --git a/test/functional/vimscript/server_spec.lua b/test/functional/vimscript/server_spec.lua index 4b0dc087f6..836d841f69 100644 --- a/test/functional/vimscript/server_spec.lua +++ b/test/functional/vimscript/server_spec.lua @@ -4,7 +4,6 @@ local n = require('test.functional.testnvim')() local assert_log = t.assert_log local eq, neq, eval = t.eq, t.neq, n.eval local clear, fn, api = n.clear, n.fn, n.api -local ok = t.ok local matches = t.matches local pcall_err = t.pcall_err local check_close = n.check_close @@ -49,15 +48,6 @@ describe('server', function() eq('', eval('$NVIM_LISTEN_ADDRESS')) end) - it('sets new v:servername if $NVIM_LISTEN_ADDRESS is invalid', function() - clear({ env = { NVIM_LISTEN_ADDRESS = '.' } }) - -- Cleared on startup. - eq('', eval('$NVIM_LISTEN_ADDRESS')) - local servers = fn.serverlist() - eq(1, #servers) - ok(string.len(servers[1]) > 4) -- "~/.local/state/nvim…/…" or "\\.\pipe\…" - end) - it('sets v:servername at startup or if all servers were stopped', function() clear() local initial_server = api.nvim_get_vvar('servername') @@ -89,20 +79,26 @@ describe('server', function() end) it('serverstop() returns false for invalid input', function() - clear { env = { - NVIM_LOG_FILE = testlog, - NVIM_LISTEN_ADDRESS = '.', - } } + clear { + args_rm = { '--listen' }, + env = { + NVIM_LOG_FILE = testlog, + NVIM_LISTEN_ADDRESS = '', + }, + } eq(0, eval("serverstop('')")) eq(0, eval("serverstop('bogus-socket-name')")) assert_log('Not listening on bogus%-socket%-name', testlog, 10) end) it('parses endpoints', function() - clear { env = { - NVIM_LOG_FILE = testlog, - NVIM_LISTEN_ADDRESS = '.', - } } + clear { + args_rm = { '--listen' }, + env = { + NVIM_LOG_FILE = testlog, + NVIM_LISTEN_ADDRESS = '', + }, + } clear_serverlist() eq({}, fn.serverlist()) @@ -178,18 +174,41 @@ end) describe('startup --listen', function() it('validates', function() clear() - local cmd = { unpack(n.nvim_argv) } - table.insert(cmd, '--listen') - matches('nvim.*: Argument missing after: "%-%-listen"', fn.system(cmd)) - cmd = { unpack(n.nvim_argv) } - table.insert(cmd, '--listen2') - matches('nvim.*: Garbage after option argument: "%-%-listen2"', fn.system(cmd)) + -- Tests args with and without "--headless". + local function _test(args, expected) + -- XXX: clear v:shell_error, sigh... + fn.system({ n.nvim_prog, '-es', '+qall!' }) + assert(0 == eval('v:shell_error')) + local cmd = vim.list_extend({ unpack(n.nvim_argv) }, vim.list_extend({ '--headless' }, args)) + local output = fn.system(cmd) + assert(0 ~= eval('v:shell_error')) + -- TODO(justinmk): output not properly captured on Windows? + if is_os('win') then + return + end + matches(expected, output) + cmd = vim.list_extend({ unpack(n.nvim_argv) }, args) + matches(expected, fn.system(cmd)) + end + + _test({ '--listen' }, 'nvim.*: Argument missing after: "%-%-listen"') + _test({ '--listen2' }, 'nvim.*: Garbage after option argument: "%-%-listen2"') + _test({ '--listen', n.eval('v:servername') }, 'nvim.*: Failed to %-%-listen: ".* already .*"') + _test({ '--listen', '/' }, 'nvim.*: Failed to %-%-listen: ".*"') + _test( + { '--listen', 'https://example.com' }, + ('nvim.*: Failed to %%-%%-listen: "%s"'):format( + (is_os('mac') or is_os('win')) and 'unknown node or service' + or 'service not available for socket type' + ) + ) end) it('sets v:servername, overrides $NVIM_LISTEN_ADDRESS', function() local addr = (is_os('win') and [[\\.\pipe\Xtest-listen-pipe]] or './Xtest-listen-pipe') clear({ env = { NVIM_LISTEN_ADDRESS = './Xtest-env-pipe' }, args = { '--listen', addr } }) + eq('', eval('$NVIM_LISTEN_ADDRESS')) -- Cleared on startup. eq(addr, api.nvim_get_vvar('servername')) -- Address without slashes is a "name" which is appended to a generated path. #8519 -- cgit From ea2d9493514a82bb5077e73957a22648cb5d7d14 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Tue, 3 Sep 2024 02:18:17 -0700 Subject: test: tmpname(create:boolean) #30242 Problem: 137f98cf6428 added the `create` parameter to `tmpname()` but didn't fully implement it. Solution: - Update impl for the `os.tmpname()` codepath. - Inspect all usages of `tmpname()`, update various tests. --- test/functional/core/fileio_spec.lua | 2 +- test/functional/lua/watch_spec.lua | 3 +-- test/functional/plugin/man_spec.lua | 2 -- test/functional/vimscript/server_spec.lua | 3 +-- 4 files changed, 3 insertions(+), 7 deletions(-) (limited to 'test/functional') diff --git a/test/functional/core/fileio_spec.lua b/test/functional/core/fileio_spec.lua index 1c4f42eb43..073041fced 100644 --- a/test/functional/core/fileio_spec.lua +++ b/test/functional/core/fileio_spec.lua @@ -325,7 +325,7 @@ describe('tmpdir', function() before_each(function() -- Fake /tmp dir so that we can mess it up. - os_tmpdir = vim.uv.fs_mkdtemp(vim.fs.dirname(t.tmpname()) .. '/nvim_XXXXXXXXXX') + os_tmpdir = vim.uv.fs_mkdtemp(vim.fs.dirname(t.tmpname(false)) .. '/nvim_XXXXXXXXXX') end) after_each(function() diff --git a/test/functional/lua/watch_spec.lua b/test/functional/lua/watch_spec.lua index 3d2dda716e..ab6b1416aa 100644 --- a/test/functional/lua/watch_spec.lua +++ b/test/functional/lua/watch_spec.lua @@ -12,7 +12,6 @@ local skip = t.skip -- events which can happen with some backends on some platforms local function touch(path) local tmp = t.tmpname() - io.open(tmp, 'w'):close() assert(vim.uv.fs_rename(tmp, path)) end @@ -42,7 +41,7 @@ describe('vim._watch', function() ) end - local root_dir = vim.uv.fs_mkdtemp(vim.fs.dirname(t.tmpname()) .. '/nvim_XXXXXXXXXX') + local root_dir = vim.uv.fs_mkdtemp(vim.fs.dirname(t.tmpname(false)) .. '/nvim_XXXXXXXXXX') local expected_events = 0 diff --git a/test/functional/plugin/man_spec.lua b/test/functional/plugin/man_spec.lua index c0256d1c63..057748f51d 100644 --- a/test/functional/plugin/man_spec.lua +++ b/test/functional/plugin/man_spec.lua @@ -8,7 +8,6 @@ local exec_lua = n.exec_lua local fn = n.fn local nvim_prog = n.nvim_prog local matches = t.matches -local write_file = t.write_file local tmpname = t.tmpname local eq = t.eq local pesc = vim.pesc @@ -226,7 +225,6 @@ describe(':Man', function() local actual_file = tmpname() -- actual_file must be an absolute path to an existent file for us to test against it matches('^/.+', actual_file) - write_file(actual_file, '') local args = { nvim_prog, '--headless', '+:Man ' .. actual_file, '+q' } matches( ('Error detected while processing command line:\r\n' .. 'man.lua: "no manual entry for %s"'):format( diff --git a/test/functional/vimscript/server_spec.lua b/test/functional/vimscript/server_spec.lua index 836d841f69..2dabe1afc1 100644 --- a/test/functional/vimscript/server_spec.lua +++ b/test/functional/vimscript/server_spec.lua @@ -188,8 +188,7 @@ describe('startup --listen', function() return end matches(expected, output) - cmd = vim.list_extend({ unpack(n.nvim_argv) }, args) - matches(expected, fn.system(cmd)) + matches(expected, fn.system(vim.list_extend({ unpack(n.nvim_argv) }, args))) end _test({ '--listen' }, 'nvim.*: Argument missing after: "%-%-listen"') -- cgit From d1d7d5468091fc71fb85c090da87253efdfcdf08 Mon Sep 17 00:00:00 2001 From: vanaigr Date: Tue, 3 Sep 2024 08:01:42 -0500 Subject: fix(api): nvim_buf_get_text() crashes with large negative column #28740 Problem: crash when calling nvim_buf_get_text() with a large negative start_col: call nvim_buf_get_text(0, 0, -123456789, 0, 0, {}) Solution: clamp start_col after subtracting it from the line length. --- test/functional/api/buffer_spec.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua index f836c1c540..3775c8c7b7 100644 --- a/test/functional/api/buffer_spec.lua +++ b/test/functional/api/buffer_spec.lua @@ -1891,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() @@ -1904,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) -- cgit From 45e76acaa053a077cab49b6606536d3f2646f033 Mon Sep 17 00:00:00 2001 From: Tristan Knight Date: Tue, 3 Sep 2024 16:10:39 +0100 Subject: feat(lsp): support hostname in rpc.connect #30238 Updated the `rpc.connect` function to support connecting to LSP servers using hostnames, not just IP addresses. This change includes updates to the documentation and additional test cases to verify the new functionality. - Modified `connect` function to resolve hostnames. - Updated documentation to reflect the change. - Added test case for connecting using hostname. Added a TCP echo server utility function to the LSP test suite. This server echoes the first message it receives and is used in tests to verify LSP server connections via both IP address and hostname. Refactored existing tests to use the new utility function. --- test/functional/plugin/lsp/testutil.lua | 27 ++++++++++++++++++++++ test/functional/plugin/lsp_spec.lua | 40 ++++++++++++++++++++------------- 2 files changed, 51 insertions(+), 16 deletions(-) (limited to 'test/functional') diff --git a/test/functional/plugin/lsp/testutil.lua b/test/functional/plugin/lsp/testutil.lua index 2595f6ad09..f60d111f87 100644 --- a/test/functional/plugin/lsp/testutil.lua +++ b/test/functional/plugin/lsp/testutil.lua @@ -21,6 +21,33 @@ function M.clear_notrace() } end +M.create_tcp_echo_server = function() + --- Create a TCP server that echos the first message it receives. + --- @param host string + ---@return uv.uv_tcp_t + ---@return integer + ---@return fun():string|nil + function _G._create_tcp_server(host) + local uv = vim.uv + local server = assert(uv.new_tcp()) + local init = nil + server:bind(host, 0) + server:listen(127, function(err) + assert(not err, err) + local socket = assert(uv.new_tcp()) + server:accept(socket) + socket:read_start(require('vim.lsp.rpc').create_read_loop(function(body) + init = body + socket:close() + end)) + end) + local port = server:getsockname().port + return server, port, function() + return init + end + end +end + M.create_server_definition = function() function _G._create_server(opts) opts = opts or {} diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index ff042424f9..1347ea9745 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -33,6 +33,7 @@ local create_server_definition = t_lsp.create_server_definition local fake_lsp_code = t_lsp.fake_lsp_code local fake_lsp_logfile = t_lsp.fake_lsp_logfile local test_rpc_server = t_lsp.test_rpc_server +local create_tcp_echo_server = t_lsp.create_tcp_echo_server local function get_buf_option(name, bufnr) bufnr = bufnr or 'BUFFER' @@ -4981,26 +4982,33 @@ describe('LSP', function() end) describe('cmd', function() - it('can connect to lsp server via rpc.connect', function() + it('connects to lsp server via rpc.connect using ip address', function() + exec_lua(create_tcp_echo_server) local result = exec_lua(function() - local uv = vim.uv - local server = assert(uv.new_tcp()) - local init = nil - server:bind('127.0.0.1', 0) - server:listen(127, function(err) - assert(not err, err) - local socket = assert(uv.new_tcp()) - server:accept(socket) - socket:read_start(require('vim.lsp.rpc').create_read_loop(function(body) - init = body - socket:close() - end)) - end) - local port = server:getsockname().port + local server, port, last_message = _G._create_tcp_server('127.0.0.1') vim.lsp.start({ name = 'dummy', cmd = vim.lsp.rpc.connect('127.0.0.1', port) }) vim.wait(1000, function() - return init ~= nil + return last_message() ~= nil + end) + local init = last_message() + assert(init, 'server must receive `initialize` request') + server:close() + server:shutdown() + return vim.json.decode(init) + end) + eq('initialize', result.method) + end) + + it('connects to lsp server via rpc.connect using hostname', function() + skip(is_os('bsd'), 'issue with host resolution in ci') + exec_lua(create_tcp_echo_server) + local result = exec_lua(function() + local server, port, last_message = _G._create_tcp_server('::1') + vim.lsp.start({ name = 'dummy', cmd = vim.lsp.rpc.connect('localhost', port) }) + vim.wait(1000, function() + return last_message() ~= nil end) + local init = last_message() assert(init, 'server must receive `initialize` request') server:close() server:shutdown() -- cgit From b6e350a6b4df40fcc99931c460668c36fadc9989 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Tue, 3 Sep 2024 17:14:25 +0100 Subject: fix(lua): allows tables with integer keys to be merged in tbl_deep_extend - The exclusion of lists was never justified in the commit history and is the wrong thing to do for a function that deals with tables. - Move the error checks out of the recursive path. Fixes #23654 --- test/functional/lua/vim_spec.lua | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index df68020d8e..7bba24483e 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -1059,7 +1059,7 @@ describe('lua stdlib', function() local a = { a = {[2] = 3} } local b = { a = {[3] = 3} } local c = vim.tbl_deep_extend("force", a, b) - return vim.deep_equal(c, {a = {[3] = 3}}) + return vim.deep_equal(c, {a = {[2] = 3, [3] = 3}}) ]])) eq( @@ -1071,6 +1071,14 @@ describe('lua stdlib', function() ]]) ) + -- Fix github issue #23654 + ok(exec_lua([[ + local a = { sub = { [1] = 'a' } } + local b = { sub = { b = 'a' } } + local c = vim.tbl_deep_extend('force', a, b) + return vim.deep_equal(c, { sub = { [1] = 'a', b = 'a' } }) + ]])) + matches( 'invalid "behavior": nil', pcall_err( -- cgit From 34ded4d97b78063f5174b0e8dfb9d9bafdcb3110 Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Mon, 2 Sep 2024 16:21:34 +0200 Subject: fix(decor): exclude invalid marks from meta total Problem: Marktree meta count still includes invalidated marks, making guards that check the meta total ineffective. Solution: Revise marktree metadata when in/revalidating a mark. --- test/functional/ui/decorations_spec.lua | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'test/functional') diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua index 61a5e1d6f7..042975f898 100644 --- a/test/functional/ui/decorations_spec.lua +++ b/test/functional/ui/decorations_spec.lua @@ -5641,6 +5641,19 @@ l5 ]]) eq("Invalid 'sign_text'", pcall_err(api.nvim_buf_set_extmark, 0, ns, 5, 0, {sign_text='❤️x'})) end) + + it('auto signcolumn hides with invalidated sign', function() + api.nvim_set_option_value('signcolumn', 'auto', {}) + api.nvim_buf_set_extmark(0, ns, 0, 0, {sign_text='S1', invalidate=true}) + feed('iabdd') + screen:expect({ + grid = [[ + ^a | + {1:~ }|*8 + | + ]] + }) + end) end) describe('decorations: virt_text', function() -- cgit From 882a450a2982caa05fcbbe90e94246a8c2b45b8b Mon Sep 17 00:00:00 2001 From: Tristan Knight Date: Thu, 5 Sep 2024 08:23:11 +0100 Subject: fix(lsp): handle locations exceeding line length #30253 Problem: LSP spec [states](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#position) that "if the character value is greater than the line length it defaults back to the line length", but `locations_to_items` fails in that case. Solution: Adjust locations_to_items to follow the spec. closes #28281 --- test/functional/plugin/lsp_spec.lua | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) (limited to 'test/functional') diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 1347ea9745..1d43b5d449 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -2673,7 +2673,7 @@ describe('LSP', function() describe('lsp.util.locations_to_items', function() it('Convert Location[] to items', function() - local expected = { + local expected_template = { { filename = '/fake/uri', lnum = 1, @@ -2681,7 +2681,12 @@ describe('LSP', function() col = 3, end_col = 4, text = 'testing', - user_data = { + user_data = {}, + }, + } + local test_params = { + { + { uri = 'file:///fake/uri', range = { start = { line = 0, character = 2 }, @@ -2689,23 +2694,28 @@ describe('LSP', function() }, }, }, - } - local actual = exec_lua(function() - local bufnr = vim.uri_to_bufnr('file:///fake/uri') - local lines = { 'testing', '123' } - vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines) - local locations = { + { { uri = 'file:///fake/uri', range = { start = { line = 0, character = 2 }, - ['end'] = { line = 1, character = 3 }, + -- LSP spec: if character > line length, default to the line length. + ['end'] = { line = 1, character = 10000 }, }, }, - } - return vim.lsp.util.locations_to_items(locations, 'utf-16') - end) - eq(expected, actual) + }, + } + for _, params in ipairs(test_params) do + local actual = exec_lua(function(params0) + local bufnr = vim.uri_to_bufnr('file:///fake/uri') + local lines = { 'testing', '123' } + vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines) + return vim.lsp.util.locations_to_items(params0, 'utf-16') + end, params) + local expected = vim.deepcopy(expected_template) + expected[1].user_data = params[1] + eq(expected, actual) + end end) it('Convert LocationLink[] to items', function() -- cgit From 975aeee537375a14c0e16916e1ef312aae90b85f Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Thu, 5 Sep 2024 02:39:58 -0700 Subject: test: avoid noise in CI logs #30264 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: Since 96128a5076b7 the test logs have noise from tests that *expect* failures: $NVIM_LOG_FILE: /tmp/cirrus-ci-build/build/.nvimlog (last 100 lines) ERR 2024-09-04T13:38:45.181 T949.28335.0/c terminfo_start:486: uv_pipe_open failed: no such device or address ERR 2024-09-04T13:38:45.181 T949.28335.0/c flush_buf:2527: uv_write failed: bad file descriptor ERR 2024-09-04T13:38:45.181 T949.28335.0/c flush_buf:2527: uv_write failed: bad file descriptor WRN 2024-09-04T13:43:43.294 ?.35904 server_start:173: Failed to start server: address already in use: /…/Xtest_tmpdir/…/T7159.35895.0 WRN 2024-09-04T13:43:43.314 ?.35907 server_start:173: Failed to start server: illegal operation on a directory: / ERR 2024-09-04T13:43:43.332 ?.35909 socket_watcher_init:60: Host lookup failed: https://example.com Solution: Rewrite the test to use `vim.system()`. Set NVIM_LOG_FILE in the child process to a "throwaway" logfile. --- test/functional/vimscript/server_spec.lua | 54 +++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 17 deletions(-) (limited to 'test/functional') diff --git a/test/functional/vimscript/server_spec.lua b/test/functional/vimscript/server_spec.lua index 2dabe1afc1..8d2025e822 100644 --- a/test/functional/vimscript/server_spec.lua +++ b/test/functional/vimscript/server_spec.lua @@ -1,7 +1,6 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() -local assert_log = t.assert_log local eq, neq, eval = t.eq, t.neq, n.eval local clear, fn, api = n.clear, n.fn, n.api local matches = t.matches @@ -88,7 +87,7 @@ describe('server', function() } eq(0, eval("serverstop('')")) eq(0, eval("serverstop('bogus-socket-name')")) - assert_log('Not listening on bogus%-socket%-name', testlog, 10) + t.assert_log('Not listening on bogus%-socket%-name', testlog, 10) end) it('parses endpoints', function() @@ -122,7 +121,7 @@ describe('server', function() if status then table.insert(expected, v4) pcall(fn.serverstart, v4) -- exists already; ignore - assert_log('Failed to start server: address already in use: 127%.0%.0%.1', testlog, 10) + t.assert_log('Failed to start server: address already in use: 127%.0%.0%.1', testlog, 10) end local v6 = '::1:12345' @@ -130,7 +129,7 @@ describe('server', function() if status then table.insert(expected, v6) pcall(fn.serverstart, v6) -- exists already; ignore - assert_log('Failed to start server: address already in use: ::1', testlog, 10) + t.assert_log('Failed to start server: address already in use: ::1', testlog, 10) end eq(expected, fn.serverlist()) clear_serverlist() @@ -173,24 +172,43 @@ end) describe('startup --listen', function() it('validates', function() - clear() + os.remove(testlog) + clear { env = { NVIM_LOG_FILE = testlog } } -- Tests args with and without "--headless". local function _test(args, expected) - -- XXX: clear v:shell_error, sigh... - fn.system({ n.nvim_prog, '-es', '+qall!' }) - assert(0 == eval('v:shell_error')) - local cmd = vim.list_extend({ unpack(n.nvim_argv) }, vim.list_extend({ '--headless' }, args)) - local output = fn.system(cmd) - assert(0 ~= eval('v:shell_error')) - -- TODO(justinmk): output not properly captured on Windows? + local function run(cmd) + return n.exec_lua(function(cmd_) + return vim + .system(cmd_, { + text = true, + env = { + -- Avoid noise in the logs; we expect failures for these tests. + NVIM_LOG_FILE = testlog, + }, + }) + :wait() + end, cmd) --[[@as vim.SystemCompleted]] + end + + local cmd = vim.list_extend({ n.nvim_prog, '+qall!', '--headless' }, args) + local r = run(cmd) + eq(1, r.code) + matches(expected, (r.stderr .. r.stdout):gsub('\\n', ' ')) + if is_os('win') then - return + return -- On Windows, output without --headless is garbage. end - matches(expected, output) - matches(expected, fn.system(vim.list_extend({ unpack(n.nvim_argv) }, args))) + table.remove(cmd, 3) -- Remove '--headless'. + assert(not vim.tbl_contains(cmd, '--headless')) + r = run(cmd) + eq(1, r.code) + matches(expected, (r.stderr .. r.stdout):gsub('\\n', ' ')) end + t.assert_nolog('Failed to start server', testlog, 100) + t.assert_nolog('Host lookup failed', testlog, 100) + _test({ '--listen' }, 'nvim.*: Argument missing after: "%-%-listen"') _test({ '--listen2' }, 'nvim.*: Garbage after option argument: "%-%-listen2"') _test({ '--listen', n.eval('v:servername') }, 'nvim.*: Failed to %-%-listen: ".* already .*"') @@ -198,10 +216,12 @@ describe('startup --listen', function() _test( { '--listen', 'https://example.com' }, ('nvim.*: Failed to %%-%%-listen: "%s"'):format( - (is_os('mac') or is_os('win')) and 'unknown node or service' - or 'service not available for socket type' + is_os('mac') and 'unknown node or service' or 'service not available for socket type' ) ) + + t.assert_log('Failed to start server', testlog, 100) + t.assert_log('Host lookup failed', testlog, 100) end) it('sets v:servername, overrides $NVIM_LISTEN_ADDRESS', function() -- cgit From 76aa3e52be7a5a8b53b3775981c35313284230ac Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Thu, 5 Sep 2024 05:56:00 -0700 Subject: feat(defaults): popupmenu "Open in browser", "Go to definition" #30261 - Use the popup to expose more features such as LSP and gx. - Move the copy/paste items lower in the menu, they are lower priority. --- test/functional/editor/defaults_spec.lua | 100 ++++++++++++++++++++++++++++++ test/functional/options/defaults_spec.lua | 26 ++------ test/functional/terminal/tui_spec.lua | 2 + test/functional/ui/multigrid_spec.lua | 1 + test/functional/ui/popupmenu_spec.lua | 9 +++ test/functional/vimscript/server_spec.lua | 15 +++-- 6 files changed, 127 insertions(+), 26 deletions(-) create mode 100644 test/functional/editor/defaults_spec.lua (limited to 'test/functional') diff --git a/test/functional/editor/defaults_spec.lua b/test/functional/editor/defaults_spec.lua new file mode 100644 index 0000000000..47fd177f7b --- /dev/null +++ b/test/functional/editor/defaults_spec.lua @@ -0,0 +1,100 @@ +-- +-- Tests for default autocmds, mappings, commands, and menus. +-- +-- See options/defaults_spec.lua for default options and environment decisions. +-- + +local t = require('test.testutil') +local n = require('test.functional.testnvim')() +local Screen = require('test.functional.ui.screen') + +describe('default', function() + describe('autocommands', function() + it('nvim_terminal.TermClose closes terminal with default shell on success', function() + n.clear() + n.api.nvim_set_option_value('shell', n.testprg('shell-test'), {}) + n.command('set shellcmdflag=EXIT shellredir= shellpipe= shellquote= shellxquote=') + + -- Should not block other events + n.command('let g:n=0') + n.command('au BufEnter * let g:n = g:n + 1') + + n.command('terminal') + t.eq(1, n.eval('get(g:, "n", 0)')) + + t.retry(nil, 1000, function() + t.neq('terminal', n.api.nvim_get_option_value('buftype', { buf = 0 })) + t.eq(2, n.eval('get(g:, "n", 0)')) + end) + end) + end) + + describe('popupmenu', function() + it('can be disabled by user', function() + n.clear { + args = { '+autocmd! nvim_popupmenu', '+aunmenu PopUp' }, + } + local screen = Screen.new(40, 8) + screen:attach() + n.insert([[ + 1 line 1 + 2 https://example.com + 3 line 3 + 4 line 4]]) + + n.api.nvim_input_mouse('right', 'press', '', 0, 1, 4) + screen:expect({ + grid = [[ + 1 line 1 | + 2 ht^tps://example.com | + 3 line 3 | + 4 line 4 | + {1:~ }|*3 + | + ]], + }) + end) + + it('right-click on URL shows "Open in web browser"', function() + n.clear() + local screen = Screen.new(40, 8) + screen:attach() + n.insert([[ + 1 line 1 + 2 https://example.com + 3 line 3 + 4 line 4]]) + + n.api.nvim_input_mouse('right', 'press', '', 0, 3, 4) + screen:expect({ + grid = [[ + 1 line 1 | + 2 https://example.com | + 3 line 3 | + 4 li^ne 4 | + {1:~ }{4: Inspect }{1: }| + {1:~ }{4: }{1: }| + {1:~ }{4: Paste }{1: }| + {4: Select All } | + ]], + }) + + n.api.nvim_input_mouse('right', 'press', '', 0, 1, 4) + screen:expect({ + grid = [[ + 1 line 1 | + 2 ht^tps://example.com | + 3 l{4: Open in web browser } | + 4 l{4: Inspect } | + {1:~ }{4: }{1: }| + {1:~ }{4: Paste }{1: }| + {1:~ }{4: Select All }{1: }| + {4: } | + ]], + }) + end) + end) + + -- describe('key mappings', function() + -- end) +end) diff --git a/test/functional/options/defaults_spec.lua b/test/functional/options/defaults_spec.lua index 0faced5149..ca4a6eaca7 100644 --- a/test/functional/options/defaults_spec.lua +++ b/test/functional/options/defaults_spec.lua @@ -1,3 +1,9 @@ +-- +-- Tests for default options and environment decisions. +-- +-- See editor/defaults_spec.lua for default autocmds, mappings, commands, and menus. +-- + local t = require('test.testutil') local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') @@ -1255,23 +1261,3 @@ describe('stdpath()', function() end) end) end) - -describe('autocommands', function() - it('closes terminal with default shell on success', function() - clear() - api.nvim_set_option_value('shell', n.testprg('shell-test'), {}) - command('set shellcmdflag=EXIT shellredir= shellpipe= shellquote= shellxquote=') - - -- Should not block other events - command('let g:n=0') - command('au BufEnter * let g:n = g:n + 1') - - command('terminal') - eq(1, eval('get(g:, "n", 0)')) - - t.retry(nil, 1000, function() - neq('terminal', api.nvim_get_option_value('buftype', { buf = 0 })) - eq(2, eval('get(g:, "n", 0)')) - end) - end) -end) diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 50199bd83d..bba1436bdc 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -630,6 +630,8 @@ describe('TUI', function() set mouse=a mousemodel=popup aunmenu PopUp + " Delete the default MenuPopup event handler. + autocmd! nvim_popupmenu menu PopUp.foo :let g:menustr = 'foo' menu PopUp.bar :let g:menustr = 'bar' menu PopUp.baz :let g:menustr = 'baz' diff --git a/test/functional/ui/multigrid_spec.lua b/test/functional/ui/multigrid_spec.lua index dc48061a6c..63ae38d3c3 100644 --- a/test/functional/ui/multigrid_spec.lua +++ b/test/functional/ui/multigrid_spec.lua @@ -1095,6 +1095,7 @@ describe('ext_multigrid', function() end) it('supports mouse', function() + command('autocmd! nvim_popupmenu') -- Delete the default MenuPopup event handler. insert('some text\nto be clicked') screen:expect{grid=[[ ## grid 1 diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index 370a18b908..3acbd5d987 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -851,6 +851,8 @@ describe('ui/ext_popupmenu', function() set mouse=a mousemodel=popup aunmenu PopUp + " Delete the default MenuPopup event handler. + autocmd! nvim_popupmenu menu PopUp.foo :let g:menustr = 'foo' menu PopUp.bar :let g:menustr = 'bar' menu PopUp.baz :let g:menustr = 'baz' @@ -3805,6 +3807,8 @@ describe('builtin popupmenu', function() call setline(1, 'popup menu test') set mouse=a mousemodel=popup + " Delete the default MenuPopup event handler. + autocmd! nvim_popupmenu aunmenu PopUp menu PopUp.foo :let g:menustr = 'foo' menu PopUp.bar :let g:menustr = 'bar' @@ -4489,6 +4493,9 @@ describe('builtin popupmenu', function() -- oldtest: Test_popup_command_dump() it(':popup command', function() exec([[ + " Delete the default MenuPopup event handler. + autocmd! nvim_popupmenu + func ChangeMenu() aunmenu PopUp.&Paste nnoremenu 1.40 PopUp.&Paste :echomsg "pasted" @@ -4646,6 +4653,8 @@ describe('builtin popupmenu', function() screen:try_resize(50, 20) exec([[ set mousemodel=popup_setpos + " Delete the default MenuPopup event handler. + autocmd! nvim_popupmenu aunmenu * source $VIMRUNTIME/menu.vim call setline(1, join(range(20))) diff --git a/test/functional/vimscript/server_spec.lua b/test/functional/vimscript/server_spec.lua index 8d2025e822..f3c72b7da8 100644 --- a/test/functional/vimscript/server_spec.lua +++ b/test/functional/vimscript/server_spec.lua @@ -18,12 +18,16 @@ local function clear_serverlist() end end -describe('server', function() - after_each(function() - check_close() - os.remove(testlog) - end) +after_each(function() + check_close() + os.remove(testlog) +end) +before_each(function() + os.remove(testlog) +end) + +describe('server', function() it('serverstart() stores sockets in $XDG_RUNTIME_DIR', function() local dir = 'Xtest_xdg_run' mkdir(dir) @@ -172,7 +176,6 @@ end) describe('startup --listen', function() it('validates', function() - os.remove(testlog) clear { env = { NVIM_LOG_FILE = testlog } } -- Tests args with and without "--headless". -- cgit From fa99afe35eb5d8cf01d875e12b53165bf1104a60 Mon Sep 17 00:00:00 2001 From: bfredl Date: Wed, 4 Sep 2024 12:09:42 +0200 Subject: fix(multibyte): handle backspace of wide clusters in replace mode Make utf_head_off more robust against invalid sequences and embedded NUL chars --- test/functional/editor/mode_insert_spec.lua | 93 +++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) (limited to 'test/functional') diff --git a/test/functional/editor/mode_insert_spec.lua b/test/functional/editor/mode_insert_spec.lua index fc1e6c4ee4..87d5c46134 100644 --- a/test/functional/editor/mode_insert_spec.lua +++ b/test/functional/editor/mode_insert_spec.lua @@ -351,4 +351,97 @@ describe('insert-mode', function() eq(2, api.nvim_win_get_cursor(0)[1]) end) end) + + it('backspace after replacing multibyte chars', function() + local screen = Screen.new(30, 3) + screen:attach() + api.nvim_buf_set_lines(0, 0, -1, true, { 'test ȧ̟̜̝̅̚m̆̉̐̐̇̈ å' }) + feed('^Rabcdefghi') + screen:expect([[ + abcdefghi^ | + {1:~ }| + {5:-- REPLACE --} | + ]]) + + feed('') + screen:expect([[ + abcdefgh^å | + {1:~ }| + {5:-- REPLACE --} | + ]]) + + feed('') + screen:expect([[ + abcdefg^ å | + {1:~ }| + {5:-- REPLACE --} | + ]]) + + feed('') + screen:expect([[ + abcdef^m̆̉̐̐̇̈ å | + {1:~ }| + {5:-- REPLACE --} | + ]]) + + feed('') + screen:expect([[ + abcde^ȧ̟̜̝̅̚m̆̉̐̐̇̈ å | + {1:~ }| + {5:-- REPLACE --} | + ]]) + + feed('') + screen:expect([[ + abcd^ ȧ̟̜̝̅̚m̆̉̐̐̇̈ å | + {1:~ }| + {5:-- REPLACE --} | + ]]) + + feed('') + + api.nvim_buf_set_lines(0, 0, -1, true, { 'wow 🧑‍🌾🏳️‍⚧️x' }) + feed('^Rabcd') + + screen:expect([[ + abcd^🧑‍🌾🏳️‍⚧️x | + {1:~ }| + {5:-- REPLACE --} | + ]]) + + feed('e') + screen:expect([[ + abcde^🏳️‍⚧️x | + {1:~ }| + {5:-- REPLACE --} | + ]]) + + feed('f') + screen:expect([[ + abcdef^x | + {1:~ }| + {5:-- REPLACE --} | + ]]) + + feed('') + screen:expect([[ + abcde^🏳️‍⚧️x | + {1:~ }| + {5:-- REPLACE --} | + ]]) + + feed('') + screen:expect([[ + abcd^🧑‍🌾🏳️‍⚧️x | + {1:~ }| + {5:-- REPLACE --} | + ]]) + + feed('') + screen:expect([[ + abc^ 🧑‍🌾🏳️‍⚧️x | + {1:~ }| + {5:-- REPLACE --} | + ]]) + end) end) -- cgit From 5ddf2ab7684b799073f2b9c0240692f250bc7c02 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sat, 7 Sep 2024 09:41:02 -0700 Subject: test(lua): tbl_deep_extend "after second argument" #30297 --- test/functional/lua/vim_spec.lua | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-) (limited to 'test/functional') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 7bba24483e..7f10dcd8da 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -1079,34 +1079,21 @@ describe('lua stdlib', function() return vim.deep_equal(c, { sub = { [1] = 'a', b = 'a' } }) ]])) - matches( - 'invalid "behavior": nil', - pcall_err( - exec_lua, - [[ - return vim.tbl_deep_extend() - ]] - ) - ) + matches('invalid "behavior": nil', pcall_err(exec_lua, [[return vim.tbl_deep_extend()]])) matches( 'wrong number of arguments %(given 1, expected at least 3%)', - pcall_err( - exec_lua, - [[ - return vim.tbl_deep_extend("keep") - ]] - ) + pcall_err(exec_lua, [[return vim.tbl_deep_extend("keep")]]) ) matches( 'wrong number of arguments %(given 2, expected at least 3%)', - pcall_err( - exec_lua, - [[ - return vim.tbl_deep_extend("keep", {}) - ]] - ) + pcall_err(exec_lua, [[return vim.tbl_deep_extend("keep", {})]]) + ) + + matches( + 'after the second argument%: expected table, got number', + pcall_err(exec_lua, [[return vim.tbl_deep_extend("keep", {}, 42)]]) ) end) -- cgit From e37404f7fecc5f57e4f3df4cf5ba0adec67bfbb3 Mon Sep 17 00:00:00 2001 From: yayoyuyu <112897090+yayoyuyu@users.noreply.github.com> Date: Tue, 20 Aug 2024 23:29:27 +0900 Subject: fix(tohtml): enclose font-family names in quotation marks Font-family names must be enclosed in quotation marks to ensure that fonts are applied correctly when there are spaces in the name. Fix an issue where multiple fonts specified in `vim.o.guifont` are inserted as a single element, treating them as a single font. Support for escaping commas with backslash and ignoring spaces after a comma. ref `:help 'guifont'` --- test/functional/plugin/tohtml_spec.lua | 85 +++++++++++++++++++++------------- 1 file changed, 53 insertions(+), 32 deletions(-) (limited to 'test/functional') diff --git a/test/functional/plugin/tohtml_spec.lua b/test/functional/plugin/tohtml_spec.lua index dbf385c0c3..8cb7105660 100644 --- a/test/functional/plugin/tohtml_spec.lua +++ b/test/functional/plugin/tohtml_spec.lua @@ -136,6 +136,53 @@ local function run_tohtml_and_assert(screen, func) screen:expect({ grid = expected.grid, attr_ids = expected.attr_ids }) end +---@param guifont boolean +local function test_generates_html(guifont) + insert([[line]]) + exec('set termguicolors') + local bg = fn.synIDattr(fn.hlID('Normal'), 'bg#', 'gui') + local fg = fn.synIDattr(fn.hlID('Normal'), 'fg#', 'gui') + if guifont then + exec_lua [[ + vim.o.guifont="Font,Escape\\,comma, Ignore space after comma" + local outfile = vim.fn.tempname() .. '.html' + local html = require('tohtml').tohtml(0,{title="title"}) + vim.fn.writefile(html, outfile) + vim.cmd.split(outfile) + ]] + else + exec_lua [[ + local outfile = vim.fn.tempname() .. '.html' + local html = require('tohtml').tohtml(0,{title="title",font={ "dumyfont","anotherfont" }}) + vim.fn.writefile(html, outfile) + vim.cmd.split(outfile) + ]] + end + local out_file = api.nvim_buf_get_name(api.nvim_get_current_buf()) + eq({ + '', + '', + '', + '', + 'title', + (''):format(api.nvim_get_var('colors_name')), + '', + '', + '', + '
',
+    'line',
+    '',
+    '
', + '', + '', + }, fn.readfile(out_file)) +end + describe(':TOhtml', function() --- @type test.functional.ui.screen local screen @@ -146,38 +193,12 @@ describe(':TOhtml', function() exec('colorscheme default') end) - it('expected internal html generated', function() - insert([[line]]) - exec('set termguicolors') - local bg = fn.synIDattr(fn.hlID('Normal'), 'bg#', 'gui') - local fg = fn.synIDattr(fn.hlID('Normal'), 'fg#', 'gui') - exec_lua [[ - local outfile = vim.fn.tempname() .. '.html' - local html = require('tohtml').tohtml(0,{title="title",font="dumyfont"}) - vim.fn.writefile(html, outfile) - vim.cmd.split(outfile) - ]] - local out_file = api.nvim_buf_get_name(api.nvim_get_current_buf()) - eq({ - '', - '', - '', - '', - 'title', - (''):format(api.nvim_get_var('colors_name')), - '', - '', - '', - '
',
-      'line',
-      '',
-      '
', - '', - '', - }, fn.readfile(out_file)) + it('generates html', function() + test_generates_html(false) + end) + + it("generates html, respects 'guifont'", function() + test_generates_html(true) end) it('expected internal html generated from range', function() -- cgit From 95b65a7554f1b1041e4f1e7427e540993b68e47e Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 8 Sep 2024 12:15:13 +0200 Subject: test(tohtml): simplify font test --- test/functional/plugin/tohtml_spec.lua | 48 ++++++++++++++++------------------ 1 file changed, 23 insertions(+), 25 deletions(-) (limited to 'test/functional') diff --git a/test/functional/plugin/tohtml_spec.lua b/test/functional/plugin/tohtml_spec.lua index 8cb7105660..98a422935c 100644 --- a/test/functional/plugin/tohtml_spec.lua +++ b/test/functional/plugin/tohtml_spec.lua @@ -137,27 +137,26 @@ local function run_tohtml_and_assert(screen, func) end ---@param guifont boolean -local function test_generates_html(guifont) +local function test_generates_html(guifont, expect_font) insert([[line]]) exec('set termguicolors') local bg = fn.synIDattr(fn.hlID('Normal'), 'bg#', 'gui') local fg = fn.synIDattr(fn.hlID('Normal'), 'fg#', 'gui') - if guifont then - exec_lua [[ - vim.o.guifont="Font,Escape\\,comma, Ignore space after comma" - local outfile = vim.fn.tempname() .. '.html' - local html = require('tohtml').tohtml(0,{title="title"}) - vim.fn.writefile(html, outfile) - vim.cmd.split(outfile) - ]] - else - exec_lua [[ - local outfile = vim.fn.tempname() .. '.html' - local html = require('tohtml').tohtml(0,{title="title",font={ "dumyfont","anotherfont" }}) - vim.fn.writefile(html, outfile) - vim.cmd.split(outfile) - ]] - end + local tmpfile = t.tmpname() + + exec_lua( + [[ + local guifont, outfile = ... + local html = (guifont + and require('tohtml').tohtml(0,{title="title"}) + or require('tohtml').tohtml(0,{title="title",font={ "dumyfont","anotherfont" }})) + vim.fn.writefile(html, outfile) + vim.cmd.split(outfile) + ]], + guifont, + tmpfile + ) + local out_file = api.nvim_buf_get_name(api.nvim_get_current_buf()) eq({ '', @@ -167,9 +166,7 @@ local function test_generates_html(guifont) 'title', (''):format(api.nvim_get_var('colors_name')), '', '', @@ -193,15 +190,16 @@ describe(':TOhtml', function() exec('colorscheme default') end) - it('generates html', function() - test_generates_html(false) + it('generates html with given font', function() + test_generates_html(false, '"dumyfont","anotherfont"') end) it("generates html, respects 'guifont'", function() - test_generates_html(true) + exec_lua [[vim.o.guifont='Font,Escape\\,comma, Ignore space after comma']] + test_generates_html(true, '"Font","Escape,comma","Ignore space after comma"') end) - it('expected internal html generated from range', function() + it('generates html from range', function() insert([[ line1 line2 @@ -239,7 +237,7 @@ describe(':TOhtml', function() }, fn.readfile(out_file)) end) - it('highlight attributes generated', function() + it('generates highlight attributes', function() --Make sure to uncomment the attribute in `html_syntax_match()` exec('hi LINE guisp=#00ff00 gui=' .. table.concat({ 'bold', -- cgit From 003b8a251dc1184e36c222f675bf79a50a40ab3a Mon Sep 17 00:00:00 2001 From: Tristan Knight Date: Sun, 8 Sep 2024 11:44:46 +0100 Subject: fix(lsp): handle out-of-bounds character positions #30288 Problem: str_byteindex_enc could return an error if the index was longer than the lline length. This was handled in each of the calls to it individually Solution: * Fix the call at the source level so that if the index is higher than the line length, line length is returned as per LSP specification * Remove pcalls on str_byteindex_enc calls. No longer needed now that str_byteindex_enc has a bounds check. --- test/functional/plugin/lsp_spec.lua | 81 ++++++++++++++++++++++++++----------- 1 file changed, 57 insertions(+), 24 deletions(-) (limited to 'test/functional') diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 1d43b5d449..88b0e0c991 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -3607,21 +3607,21 @@ describe('LSP', function() range = { ['end'] = { character = 8, - line = 9, + line = 3, }, start = { character = 6, - line = 9, + line = 3, }, }, selectionRange = { ['end'] = { character = 8, - line = 9, + line = 3, }, start = { character = 6, - line = 9, + line = 3, }, }, uri = 'file:///home/jiangyinzuo/hello.cpp', @@ -3651,21 +3651,21 @@ describe('LSP', function() range = { ['end'] = { character = 8, - line = 8, + line = 2, }, start = { character = 6, - line = 8, + line = 2, }, }, selectionRange = { ['end'] = { character = 8, - line = 8, + line = 2, }, start = { character = 6, - line = 8, + line = 2, }, }, uri = 'file:///home/jiangyinzuo/hello.cpp', @@ -3679,7 +3679,15 @@ describe('LSP', function() }) local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) local handler = require 'vim.lsp.handlers'['typeHierarchy/subtypes'] - handler(nil, clangd_response, { client_id = client_id, bufnr = 1 }) + local bufnr = vim.api.nvim_get_current_buf() + vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { + 'class B : public A{};', + 'class C : public B{};', + 'class D1 : public C{};', + 'class D2 : public C{};', + 'class E : public D1, D2 {};', + }) + handler(nil, clangd_response, { client_id = client_id, bufnr = bufnr }) return vim.fn.getqflist() end) @@ -3689,7 +3697,7 @@ describe('LSP', function() col = 7, end_col = 0, end_lnum = 0, - lnum = 10, + lnum = 4, module = '', nr = 0, pattern = '', @@ -3703,7 +3711,7 @@ describe('LSP', function() col = 7, end_col = 0, end_lnum = 0, - lnum = 9, + lnum = 3, module = '', nr = 0, pattern = '', @@ -3763,7 +3771,15 @@ describe('LSP', function() }) local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) local handler = require 'vim.lsp.handlers'['typeHierarchy/subtypes'] - handler(nil, jdtls_response, { client_id = client_id, bufnr = 1 }) + local bufnr = vim.api.nvim_get_current_buf() + vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { + 'package mylist;', + '', + 'public class MyList {', + ' static class Inner extends MyList{}', + '~}', + }) + handler(nil, jdtls_response, { client_id = client_id, bufnr = bufnr }) return vim.fn.getqflist() end) @@ -3840,21 +3856,21 @@ describe('LSP', function() range = { ['end'] = { character = 8, - line = 9, + line = 3, }, start = { character = 6, - line = 9, + line = 3, }, }, selectionRange = { ['end'] = { character = 8, - line = 9, + line = 3, }, start = { character = 6, - line = 9, + line = 3, }, }, uri = 'file:///home/jiangyinzuo/hello.cpp', @@ -3884,21 +3900,21 @@ describe('LSP', function() range = { ['end'] = { character = 8, - line = 8, + line = 2, }, start = { character = 6, - line = 8, + line = 2, }, }, selectionRange = { ['end'] = { character = 8, - line = 8, + line = 2, }, start = { character = 6, - line = 8, + line = 2, }, }, uri = 'file:///home/jiangyinzuo/hello.cpp', @@ -3912,7 +3928,16 @@ describe('LSP', function() }) local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) local handler = require 'vim.lsp.handlers'['typeHierarchy/supertypes'] - handler(nil, clangd_response, { client_id = client_id, bufnr = 1 }) + local bufnr = vim.api.nvim_get_current_buf() + vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { + 'class B : public A{};', + 'class C : public B{};', + 'class D1 : public C{};', + 'class D2 : public C{};', + 'class E : public D1, D2 {};', + }) + + handler(nil, clangd_response, { client_id = client_id, bufnr = bufnr }) return vim.fn.getqflist() end) @@ -3922,7 +3947,7 @@ describe('LSP', function() col = 7, end_col = 0, end_lnum = 0, - lnum = 10, + lnum = 4, module = '', nr = 0, pattern = '', @@ -3936,7 +3961,7 @@ describe('LSP', function() col = 7, end_col = 0, end_lnum = 0, - lnum = 9, + lnum = 3, module = '', nr = 0, pattern = '', @@ -3996,7 +4021,15 @@ describe('LSP', function() }) local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) local handler = require 'vim.lsp.handlers'['typeHierarchy/supertypes'] - handler(nil, jdtls_response, { client_id = client_id, bufnr = 1 }) + local bufnr = vim.api.nvim_get_current_buf() + vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { + 'package mylist;', + '', + 'public class MyList {', + ' static class Inner extends MyList{}', + '~}', + }) + handler(nil, jdtls_response, { client_id = client_id, bufnr = bufnr }) return vim.fn.getqflist() end) -- cgit From 08153ddd1c149c867948f4681846531d53ba7759 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 8 Sep 2024 07:07:19 -0700 Subject: fix(startup): ignore broken $XDG_RUNTIME_DIR #30285 Problem: $XDG_RUNTIME_DIR may be broken on WSL, which prevents starting (and even building) Nvim. #30282 Solution: - When startup fails, mention the servername in the error message. - If an autogenerated server address fails, log an error and continue with an empty `v:servername`. It's only fatal if a user provides a bad `--listen` or `$NVIM_LISTEN_ADDRESS` address. Before: $ nvim --headless --listen ./hello.sock nvim: Failed to --listen: "address already in use" $ NVIM_LISTEN_ADDRESS='./hello.sock' ./build/bin/nvim --headless nvim: Failed to --listen: "address already in use" After: $ nvim --headless --listen ./hello.sock nvim: Failed to --listen: address already in use: "./hello.sock" $ NVIM_LISTEN_ADDRESS='./hello.sock' ./build/bin/nvim --headless nvim: Failed $NVIM_LISTEN_ADDRESS: address already in use: "./hello.sock" --- test/functional/vimscript/server_spec.lua | 110 ++++++++++++++++++++---------- 1 file changed, 74 insertions(+), 36 deletions(-) (limited to 'test/functional') diff --git a/test/functional/vimscript/server_spec.lua b/test/functional/vimscript/server_spec.lua index f3c72b7da8..85a179b3d5 100644 --- a/test/functional/vimscript/server_spec.lua +++ b/test/functional/vimscript/server_spec.lua @@ -41,6 +41,21 @@ describe('server', function() end end) + it('broken $XDG_RUNTIME_DIR is not fatal #30282', function() + clear { + args_rm = { '--listen' }, + env = { NVIM_LOG_FILE = testlog, XDG_RUNTIME_DIR = '/non-existent-dir/subdir//' }, + } + + if is_os('win') then + -- Windows pipes have a special namespace and thus aren't decided by $XDG_RUNTIME_DIR. + matches('nvim', api.nvim_get_vvar('servername')) + else + eq('', api.nvim_get_vvar('servername')) + t.assert_log('Failed to start server%: no such file or directory', testlog, 100) + end + end) + it('serverstart(), serverstop() does not set $NVIM', function() clear() local s = eval('serverstart()') @@ -175,56 +190,79 @@ describe('server', function() end) describe('startup --listen', function() - it('validates', function() - clear { env = { NVIM_LOG_FILE = testlog } } + -- Tests Nvim output when failing to start, with and without "--headless". + -- TODO(justinmk): clear() should have a way to get stdout if Nvim fails to start. + local function _test(args, env, expected) + local function run(cmd) + return n.exec_lua(function(cmd_, env_) + return vim + .system(cmd_, { + text = true, + env = vim.tbl_extend( + 'force', + -- Avoid noise in the logs; we expect failures for these tests. + { NVIM_LOG_FILE = testlog }, + env_ or {} + ), + }) + :wait() + end, cmd, env) --[[@as vim.SystemCompleted]] + end + + local cmd = vim.list_extend({ n.nvim_prog, '+qall!', '--headless' }, args) + local r = run(cmd) + eq(1, r.code) + matches(expected, (r.stderr .. r.stdout):gsub('\\n', ' ')) - -- Tests args with and without "--headless". - local function _test(args, expected) - local function run(cmd) - return n.exec_lua(function(cmd_) - return vim - .system(cmd_, { - text = true, - env = { - -- Avoid noise in the logs; we expect failures for these tests. - NVIM_LOG_FILE = testlog, - }, - }) - :wait() - end, cmd) --[[@as vim.SystemCompleted]] - end - - local cmd = vim.list_extend({ n.nvim_prog, '+qall!', '--headless' }, args) - local r = run(cmd) - eq(1, r.code) - matches(expected, (r.stderr .. r.stdout):gsub('\\n', ' ')) - - if is_os('win') then - return -- On Windows, output without --headless is garbage. - end - table.remove(cmd, 3) -- Remove '--headless'. - assert(not vim.tbl_contains(cmd, '--headless')) - r = run(cmd) - eq(1, r.code) - matches(expected, (r.stderr .. r.stdout):gsub('\\n', ' ')) + if is_os('win') then + return -- On Windows, output without --headless is garbage. end + table.remove(cmd, 3) -- Remove '--headless'. + assert(not vim.tbl_contains(cmd, '--headless')) + r = run(cmd) + eq(1, r.code) + matches(expected, (r.stderr .. r.stdout):gsub('\\n', ' ')) + end + + it('validates', function() + clear { env = { NVIM_LOG_FILE = testlog } } + local in_use = n.eval('v:servername') ---@type string Address already used by another server. t.assert_nolog('Failed to start server', testlog, 100) t.assert_nolog('Host lookup failed', testlog, 100) - _test({ '--listen' }, 'nvim.*: Argument missing after: "%-%-listen"') - _test({ '--listen2' }, 'nvim.*: Garbage after option argument: "%-%-listen2"') - _test({ '--listen', n.eval('v:servername') }, 'nvim.*: Failed to %-%-listen: ".* already .*"') - _test({ '--listen', '/' }, 'nvim.*: Failed to %-%-listen: ".*"') + _test({ '--listen' }, nil, 'nvim.*: Argument missing after: "%-%-listen"') + _test({ '--listen2' }, nil, 'nvim.*: Garbage after option argument: "%-%-listen2"') + _test( + { '--listen', in_use }, + nil, + ('nvim.*: Failed to %%-%%-listen: [^:]+ already [^:]+: "%s"'):format(vim.pesc(in_use)) + ) + _test({ '--listen', '/' }, nil, 'nvim.*: Failed to %-%-listen: [^:]+: "/"') _test( { '--listen', 'https://example.com' }, - ('nvim.*: Failed to %%-%%-listen: "%s"'):format( + nil, + ('nvim.*: Failed to %%-%%-listen: %s: "https://example.com"'):format( is_os('mac') and 'unknown node or service' or 'service not available for socket type' ) ) t.assert_log('Failed to start server', testlog, 100) t.assert_log('Host lookup failed', testlog, 100) + + _test( + {}, + { NVIM_LISTEN_ADDRESS = in_use }, + ('nvim.*: Failed $NVIM_LISTEN_ADDRESS: [^:]+ already [^:]+: "%s"'):format(vim.pesc(in_use)) + ) + _test({}, { NVIM_LISTEN_ADDRESS = '/' }, 'nvim.*: Failed $NVIM_LISTEN_ADDRESS: [^:]+: "/"') + _test( + {}, + { NVIM_LISTEN_ADDRESS = 'https://example.com' }, + ('nvim.*: Failed $NVIM_LISTEN_ADDRESS: %s: "https://example.com"'):format( + is_os('mac') and 'unknown node or service' or 'service not available for socket type' + ) + ) end) it('sets v:servername, overrides $NVIM_LISTEN_ADDRESS', function() -- cgit From 3a881132460430d23f2fdc87822c87d47f721cfc Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sun, 8 Sep 2024 18:23:46 +0200 Subject: fix(lua): revert vim.tbl_extend behavior change and document it Problem: vim.tbl_deep_extend had an undocumented feature where arrays (integer-indexed tables) were not merged but compared literally (used for merging default and user config, where one list should overwrite the other completely). Turns out this behavior was relied on in quite a number of plugins (even though it wasn't a robust solution even for that use case, since lists of tables (e.g., plugin specs) can be array-like as well). Solution: Revert the removal of this special feature. Check for list-like (contiguous integer indices) instead, as this is closer to the intent. Document this behavior. --- test/functional/lua/vim_spec.lua | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'test/functional') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 7f10dcd8da..599b688bf4 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -1071,12 +1071,11 @@ describe('lua stdlib', function() ]]) ) - -- Fix github issue #23654 ok(exec_lua([[ - local a = { sub = { [1] = 'a' } } - local b = { sub = { b = 'a' } } + local a = { sub = { 'a', 'b' } } + local b = { sub = { 'b', 'c' } } local c = vim.tbl_deep_extend('force', a, b) - return vim.deep_equal(c, { sub = { [1] = 'a', b = 'a' } }) + return vim.deep_equal(c, { sub = { 'b', 'c' } }) ]])) matches('invalid "behavior": nil', pcall_err(exec_lua, [[return vim.tbl_deep_extend()]])) -- cgit From 8a2aec99748229ad9d1e12c1cbc0768d063e8eed Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 8 Sep 2024 12:48:32 -0700 Subject: fix(startup): server fails if $NVIM_APPNAME is relative dir #30310 Problem: If $NVIM_APPNAME is a relative dir path, Nvim fails to start its primary/default server, and `v:servername` is empty. Root cause is d34c64e342dfba9248d1055e702d02620a1b31a8, but this wasn't noticed until 96128a5076b7 started reporting the error more loudly. Solution: - `server_address_new`: replace slashes "/" in the appname before using it as a servername. - `vim_mktempdir`: always prefer the system-wide top-level "nvim.user/" directory. That isn't intended to be specific to NVIM_APPNAME; rather, each *subdirectory* ("nvim.user/xxx") is owned by each Nvim instance. Nvim "apps" can be identified by the server socket(s) stored in those per-Nvim subdirs. fix #30256 --- test/functional/core/fileio_spec.lua | 15 +- test/functional/core/server_spec.lua | 278 ++++++++++++++++++++++++++++++ test/functional/options/defaults_spec.lua | 21 ++- test/functional/testnvim.lua | 3 +- test/functional/vimscript/server_spec.lua | 278 ------------------------------ 5 files changed, 301 insertions(+), 294 deletions(-) create mode 100644 test/functional/core/server_spec.lua delete mode 100644 test/functional/vimscript/server_spec.lua (limited to 'test/functional') diff --git a/test/functional/core/fileio_spec.lua b/test/functional/core/fileio_spec.lua index 073041fced..d33710a63d 100644 --- a/test/functional/core/fileio_spec.lua +++ b/test/functional/core/fileio_spec.lua @@ -321,11 +321,11 @@ end) describe('tmpdir', function() local tmproot_pat = [=[.*[/\\]nvim%.[^/\\]+]=] local testlog = 'Xtest_tmpdir_log' - local os_tmpdir + local os_tmpdir ---@type string before_each(function() -- Fake /tmp dir so that we can mess it up. - os_tmpdir = vim.uv.fs_mkdtemp(vim.fs.dirname(t.tmpname(false)) .. '/nvim_XXXXXXXXXX') + os_tmpdir = assert(vim.uv.fs_mkdtemp(vim.fs.dirname(t.tmpname(false)) .. '/nvim_XXXXXXXXXX')) end) after_each(function() @@ -414,15 +414,4 @@ describe('tmpdir', function() rm_tmpdir() eq('E5431: tempdir disappeared (3 times)', api.nvim_get_vvar('errmsg')) end) - - it('$NVIM_APPNAME relative path', function() - clear({ - env = { - NVIM_APPNAME = 'a/b', - NVIM_LOG_FILE = testlog, - TMPDIR = os_tmpdir, - }, - }) - matches([=[.*[/\\]a%%b%.[^/\\]+]=], fn.tempname()) - end) end) diff --git a/test/functional/core/server_spec.lua b/test/functional/core/server_spec.lua new file mode 100644 index 0000000000..0ec11169e9 --- /dev/null +++ b/test/functional/core/server_spec.lua @@ -0,0 +1,278 @@ +local t = require('test.testutil') +local n = require('test.functional.testnvim')() + +local eq, neq, eval = t.eq, t.neq, n.eval +local clear, fn, api = n.clear, n.fn, n.api +local matches = t.matches +local pcall_err = t.pcall_err +local check_close = n.check_close +local mkdir = t.mkdir +local rmdir = n.rmdir +local is_os = t.is_os + +local testlog = 'Xtest-server-log' + +local function clear_serverlist() + for _, server in pairs(fn.serverlist()) do + fn.serverstop(server) + end +end + +after_each(function() + check_close() + os.remove(testlog) +end) + +before_each(function() + os.remove(testlog) +end) + +describe('server', function() + it('serverstart() stores sockets in $XDG_RUNTIME_DIR', function() + local dir = 'Xtest_xdg_run' + mkdir(dir) + finally(function() + rmdir(dir) + end) + clear({ env = { XDG_RUNTIME_DIR = dir } }) + matches(dir, fn.stdpath('run')) + if not is_os('win') then + matches(dir, fn.serverstart()) + end + end) + + it('broken $XDG_RUNTIME_DIR is not fatal #30282', function() + clear { + args_rm = { '--listen' }, + env = { NVIM_LOG_FILE = testlog, XDG_RUNTIME_DIR = '/non-existent-dir/subdir//' }, + } + + if is_os('win') then + -- Windows pipes have a special namespace and thus aren't decided by $XDG_RUNTIME_DIR. + matches('nvim', api.nvim_get_vvar('servername')) + else + eq('', api.nvim_get_vvar('servername')) + t.assert_log('Failed to start server%: no such file or directory', testlog, 100) + end + end) + + it('serverstart(), serverstop() does not set $NVIM', function() + clear() + local s = eval('serverstart()') + assert(s ~= nil and s:len() > 0, 'serverstart() returned empty') + eq('', eval('$NVIM')) + eq('', eval('$NVIM_LISTEN_ADDRESS')) + eq(1, eval("serverstop('" .. s .. "')")) + eq('', eval('$NVIM_LISTEN_ADDRESS')) + end) + + it('sets v:servername at startup or if all servers were stopped', function() + clear() + local initial_server = api.nvim_get_vvar('servername') + assert(initial_server ~= nil and initial_server:len() > 0, 'v:servername was not initialized') + + -- v:servername is readonly so we cannot unset it--but we can test that it + -- does not get set again thereafter. + local s = fn.serverstart() + assert(s ~= nil and s:len() > 0, 'serverstart() returned empty') + neq(initial_server, s) + + -- serverstop() does _not_ modify v:servername... + eq(1, fn.serverstop(s)) + eq(initial_server, api.nvim_get_vvar('servername')) + + -- ...unless we stop _all_ servers. + eq(1, fn.serverstop(fn.serverlist()[1])) + eq('', api.nvim_get_vvar('servername')) + + -- v:servername and $NVIM take the next available server. + local servername = ( + is_os('win') and [[\\.\pipe\Xtest-functional-server-pipe]] + or './Xtest-functional-server-socket' + ) + fn.serverstart(servername) + eq(servername, api.nvim_get_vvar('servername')) + -- Not set in the current process, only in children. + eq('', eval('$NVIM')) + end) + + it('serverstop() returns false for invalid input', function() + clear { + args_rm = { '--listen' }, + env = { + NVIM_LOG_FILE = testlog, + NVIM_LISTEN_ADDRESS = '', + }, + } + eq(0, eval("serverstop('')")) + eq(0, eval("serverstop('bogus-socket-name')")) + t.assert_log('Not listening on bogus%-socket%-name', testlog, 10) + end) + + it('parses endpoints', function() + clear { + args_rm = { '--listen' }, + env = { + NVIM_LOG_FILE = testlog, + NVIM_LISTEN_ADDRESS = '', + }, + } + clear_serverlist() + eq({}, fn.serverlist()) + + local s = fn.serverstart('127.0.0.1:0') -- assign random port + if #s > 0 then + matches('127.0.0.1:%d+', s) + eq(s, fn.serverlist()[1]) + clear_serverlist() + end + + s = fn.serverstart('127.0.0.1:') -- assign random port + if #s > 0 then + matches('127.0.0.1:%d+', s) + eq(s, fn.serverlist()[1]) + clear_serverlist() + end + + local expected = {} + local v4 = '127.0.0.1:12345' + local status, _ = pcall(fn.serverstart, v4) + if status then + table.insert(expected, v4) + pcall(fn.serverstart, v4) -- exists already; ignore + t.assert_log('Failed to start server: address already in use: 127%.0%.0%.1', testlog, 10) + end + + local v6 = '::1:12345' + status, _ = pcall(fn.serverstart, v6) + if status then + table.insert(expected, v6) + pcall(fn.serverstart, v6) -- exists already; ignore + t.assert_log('Failed to start server: address already in use: ::1', testlog, 10) + end + eq(expected, fn.serverlist()) + clear_serverlist() + + -- Address without slashes is a "name" which is appended to a generated path. #8519 + matches([[[/\\]xtest1%.2%.3%.4[^/\\]*]], fn.serverstart('xtest1.2.3.4')) + clear_serverlist() + + eq('Vim:Failed to start server: invalid argument', pcall_err(fn.serverstart, '127.0.0.1:65536')) -- invalid port + eq({}, fn.serverlist()) + end) + + it('serverlist() returns the list of servers', function() + clear() + -- There should already be at least one server. + local _n = eval('len(serverlist())') + + -- Add some servers. + local servs = ( + is_os('win') and { [[\\.\pipe\Xtest-pipe0934]], [[\\.\pipe\Xtest-pipe4324]] } + or { [[./Xtest-pipe0934]], [[./Xtest-pipe4324]] } + ) + for _, s in ipairs(servs) do + eq(s, eval("serverstart('" .. s .. "')")) + end + + local new_servs = eval('serverlist()') + + -- Exactly #servs servers should be added. + eq(_n + #servs, #new_servs) + -- The new servers should be at the end of the list. + for i = 1, #servs do + eq(servs[i], new_servs[i + _n]) + eq(1, eval("serverstop('" .. servs[i] .. "')")) + end + -- After serverstop() the servers should NOT be in the list. + eq(_n, eval('len(serverlist())')) + end) +end) + +describe('startup --listen', function() + -- Tests Nvim output when failing to start, with and without "--headless". + -- TODO(justinmk): clear() should have a way to get stdout if Nvim fails to start. + local function _test(args, env, expected) + local function run(cmd) + return n.exec_lua(function(cmd_, env_) + return vim + .system(cmd_, { + text = true, + env = vim.tbl_extend( + 'force', + -- Avoid noise in the logs; we expect failures for these tests. + { NVIM_LOG_FILE = testlog }, + env_ or {} + ), + }) + :wait() + end, cmd, env) --[[@as vim.SystemCompleted]] + end + + local cmd = vim.list_extend({ n.nvim_prog, '+qall!', '--headless' }, args) + local r = run(cmd) + eq(1, r.code) + matches(expected, (r.stderr .. r.stdout):gsub('\\n', ' ')) + + if is_os('win') then + return -- On Windows, output without --headless is garbage. + end + table.remove(cmd, 3) -- Remove '--headless'. + assert(not vim.tbl_contains(cmd, '--headless')) + r = run(cmd) + eq(1, r.code) + matches(expected, (r.stderr .. r.stdout):gsub('\\n', ' ')) + end + + it('validates', function() + clear { env = { NVIM_LOG_FILE = testlog } } + local in_use = n.eval('v:servername') ---@type string Address already used by another server. + + t.assert_nolog('Failed to start server', testlog, 100) + t.assert_nolog('Host lookup failed', testlog, 100) + + _test({ '--listen' }, nil, 'nvim.*: Argument missing after: "%-%-listen"') + _test({ '--listen2' }, nil, 'nvim.*: Garbage after option argument: "%-%-listen2"') + _test( + { '--listen', in_use }, + nil, + ('nvim.*: Failed to %%-%%-listen: [^:]+ already [^:]+: "%s"'):format(vim.pesc(in_use)) + ) + _test({ '--listen', '/' }, nil, 'nvim.*: Failed to %-%-listen: [^:]+: "/"') + _test( + { '--listen', 'https://example.com' }, + nil, + ('nvim.*: Failed to %%-%%-listen: %s: "https://example.com"'):format( + is_os('mac') and 'unknown node or service' or 'service not available for socket type' + ) + ) + + t.assert_log('Failed to start server', testlog, 100) + t.assert_log('Host lookup failed', testlog, 100) + + _test( + {}, + { NVIM_LISTEN_ADDRESS = in_use }, + ('nvim.*: Failed $NVIM_LISTEN_ADDRESS: [^:]+ already [^:]+: "%s"'):format(vim.pesc(in_use)) + ) + _test({}, { NVIM_LISTEN_ADDRESS = '/' }, 'nvim.*: Failed $NVIM_LISTEN_ADDRESS: [^:]+: "/"') + _test( + {}, + { NVIM_LISTEN_ADDRESS = 'https://example.com' }, + ('nvim.*: Failed $NVIM_LISTEN_ADDRESS: %s: "https://example.com"'):format( + is_os('mac') and 'unknown node or service' or 'service not available for socket type' + ) + ) + end) + + it('sets v:servername, overrides $NVIM_LISTEN_ADDRESS', function() + local addr = (is_os('win') and [[\\.\pipe\Xtest-listen-pipe]] or './Xtest-listen-pipe') + clear({ env = { NVIM_LISTEN_ADDRESS = './Xtest-env-pipe' }, args = { '--listen', addr } }) + eq('', eval('$NVIM_LISTEN_ADDRESS')) -- Cleared on startup. + eq(addr, api.nvim_get_vvar('servername')) + + -- Address without slashes is a "name" which is appended to a generated path. #8519 + clear({ args = { '--listen', 'test-name' } }) + matches([[[/\\]test%-name[^/\\]*]], api.nvim_get_vvar('servername')) + end) +end) diff --git a/test/functional/options/defaults_spec.lua b/test/functional/options/defaults_spec.lua index ca4a6eaca7..ad94ef1206 100644 --- a/test/functional/options/defaults_spec.lua +++ b/test/functional/options/defaults_spec.lua @@ -915,7 +915,7 @@ describe('stdpath()', function() assert_alive() -- Check for crash. #8393 end) - it('supports $NVIM_APPNAME', function() + it('$NVIM_APPNAME', function() local appname = 'NVIM_APPNAME_TEST' .. ('_'):rep(106) clear({ env = { NVIM_APPNAME = appname, NVIM_LOG_FILE = testlog } }) eq(appname, fn.fnamemodify(fn.stdpath('config'), ':t')) @@ -957,6 +957,25 @@ describe('stdpath()', function() test_appname('a/b\\c', 0) end) + it('$NVIM_APPNAME relative path', function() + local tmpdir = t.tmpname(false) + t.mkdir(tmpdir) + + clear({ + args_rm = { '--listen' }, + env = { + NVIM_APPNAME = 'relative/appname', + NVIM_LOG_FILE = testlog, + TMPDIR = tmpdir, + }, + }) + + t.matches(vim.pesc(tmpdir), fn.tempname():gsub('\\', '/')) + t.assert_nolog('tempdir', testlog, 100) + t.assert_nolog('TMPDIR', testlog, 100) + t.matches([=[[/\\]relative%-appname.[^/\\]+]=], api.nvim_get_vvar('servername')) + end) + describe('returns a String', function() describe('with "config"', function() it('knows XDG_CONFIG_HOME', function() diff --git a/test/functional/testnvim.lua b/test/functional/testnvim.lua index 66ce6daacb..d74e8055ef 100644 --- a/test/functional/testnvim.lua +++ b/test/functional/testnvim.lua @@ -14,8 +14,7 @@ local is_os = t.is_os local ok = t.ok local sleep = uv.sleep ---- This module uses functions from the context of the test session, i.e. in the context of the ---- nvim being tests. +--- Functions executing in the current nvim session/process being tested. local M = {} local runtime_set = 'set runtimepath^=./build/lib/nvim/' diff --git a/test/functional/vimscript/server_spec.lua b/test/functional/vimscript/server_spec.lua deleted file mode 100644 index 85a179b3d5..0000000000 --- a/test/functional/vimscript/server_spec.lua +++ /dev/null @@ -1,278 +0,0 @@ -local t = require('test.testutil') -local n = require('test.functional.testnvim')() - -local eq, neq, eval = t.eq, t.neq, n.eval -local clear, fn, api = n.clear, n.fn, n.api -local matches = t.matches -local pcall_err = t.pcall_err -local check_close = n.check_close -local mkdir = t.mkdir -local rmdir = n.rmdir -local is_os = t.is_os - -local testlog = 'Xtest-server-log' - -local function clear_serverlist() - for _, server in pairs(fn.serverlist()) do - fn.serverstop(server) - end -end - -after_each(function() - check_close() - os.remove(testlog) -end) - -before_each(function() - os.remove(testlog) -end) - -describe('server', function() - it('serverstart() stores sockets in $XDG_RUNTIME_DIR', function() - local dir = 'Xtest_xdg_run' - mkdir(dir) - finally(function() - rmdir(dir) - end) - clear({ env = { XDG_RUNTIME_DIR = dir } }) - matches(dir, fn.stdpath('run')) - if not is_os('win') then - matches(dir, fn.serverstart()) - end - end) - - it('broken $XDG_RUNTIME_DIR is not fatal #30282', function() - clear { - args_rm = { '--listen' }, - env = { NVIM_LOG_FILE = testlog, XDG_RUNTIME_DIR = '/non-existent-dir/subdir//' }, - } - - if is_os('win') then - -- Windows pipes have a special namespace and thus aren't decided by $XDG_RUNTIME_DIR. - matches('nvim', api.nvim_get_vvar('servername')) - else - eq('', api.nvim_get_vvar('servername')) - t.assert_log('Failed to start server%: no such file or directory', testlog, 100) - end - end) - - it('serverstart(), serverstop() does not set $NVIM', function() - clear() - local s = eval('serverstart()') - assert(s ~= nil and s:len() > 0, 'serverstart() returned empty') - eq('', eval('$NVIM')) - eq('', eval('$NVIM_LISTEN_ADDRESS')) - eq(1, eval("serverstop('" .. s .. "')")) - eq('', eval('$NVIM_LISTEN_ADDRESS')) - end) - - it('sets v:servername at startup or if all servers were stopped', function() - clear() - local initial_server = api.nvim_get_vvar('servername') - assert(initial_server ~= nil and initial_server:len() > 0, 'v:servername was not initialized') - - -- v:servername is readonly so we cannot unset it--but we can test that it - -- does not get set again thereafter. - local s = fn.serverstart() - assert(s ~= nil and s:len() > 0, 'serverstart() returned empty') - neq(initial_server, s) - - -- serverstop() does _not_ modify v:servername... - eq(1, fn.serverstop(s)) - eq(initial_server, api.nvim_get_vvar('servername')) - - -- ...unless we stop _all_ servers. - eq(1, fn.serverstop(fn.serverlist()[1])) - eq('', api.nvim_get_vvar('servername')) - - -- v:servername and $NVIM take the next available server. - local servername = ( - is_os('win') and [[\\.\pipe\Xtest-functional-server-pipe]] - or './Xtest-functional-server-socket' - ) - fn.serverstart(servername) - eq(servername, api.nvim_get_vvar('servername')) - -- Not set in the current process, only in children. - eq('', eval('$NVIM')) - end) - - it('serverstop() returns false for invalid input', function() - clear { - args_rm = { '--listen' }, - env = { - NVIM_LOG_FILE = testlog, - NVIM_LISTEN_ADDRESS = '', - }, - } - eq(0, eval("serverstop('')")) - eq(0, eval("serverstop('bogus-socket-name')")) - t.assert_log('Not listening on bogus%-socket%-name', testlog, 10) - end) - - it('parses endpoints', function() - clear { - args_rm = { '--listen' }, - env = { - NVIM_LOG_FILE = testlog, - NVIM_LISTEN_ADDRESS = '', - }, - } - clear_serverlist() - eq({}, fn.serverlist()) - - local s = fn.serverstart('127.0.0.1:0') -- assign random port - if #s > 0 then - matches('127.0.0.1:%d+', s) - eq(s, fn.serverlist()[1]) - clear_serverlist() - end - - s = fn.serverstart('127.0.0.1:') -- assign random port - if #s > 0 then - matches('127.0.0.1:%d+', s) - eq(s, fn.serverlist()[1]) - clear_serverlist() - end - - local expected = {} - local v4 = '127.0.0.1:12345' - local status, _ = pcall(fn.serverstart, v4) - if status then - table.insert(expected, v4) - pcall(fn.serverstart, v4) -- exists already; ignore - t.assert_log('Failed to start server: address already in use: 127%.0%.0%.1', testlog, 10) - end - - local v6 = '::1:12345' - status, _ = pcall(fn.serverstart, v6) - if status then - table.insert(expected, v6) - pcall(fn.serverstart, v6) -- exists already; ignore - t.assert_log('Failed to start server: address already in use: ::1', testlog, 10) - end - eq(expected, fn.serverlist()) - clear_serverlist() - - -- Address without slashes is a "name" which is appended to a generated path. #8519 - matches([[.*[/\\]xtest1%.2%.3%.4[^/\\]*]], fn.serverstart('xtest1.2.3.4')) - clear_serverlist() - - eq('Vim:Failed to start server: invalid argument', pcall_err(fn.serverstart, '127.0.0.1:65536')) -- invalid port - eq({}, fn.serverlist()) - end) - - it('serverlist() returns the list of servers', function() - clear() - -- There should already be at least one server. - local _n = eval('len(serverlist())') - - -- Add some servers. - local servs = ( - is_os('win') and { [[\\.\pipe\Xtest-pipe0934]], [[\\.\pipe\Xtest-pipe4324]] } - or { [[./Xtest-pipe0934]], [[./Xtest-pipe4324]] } - ) - for _, s in ipairs(servs) do - eq(s, eval("serverstart('" .. s .. "')")) - end - - local new_servs = eval('serverlist()') - - -- Exactly #servs servers should be added. - eq(_n + #servs, #new_servs) - -- The new servers should be at the end of the list. - for i = 1, #servs do - eq(servs[i], new_servs[i + _n]) - eq(1, eval("serverstop('" .. servs[i] .. "')")) - end - -- After serverstop() the servers should NOT be in the list. - eq(_n, eval('len(serverlist())')) - end) -end) - -describe('startup --listen', function() - -- Tests Nvim output when failing to start, with and without "--headless". - -- TODO(justinmk): clear() should have a way to get stdout if Nvim fails to start. - local function _test(args, env, expected) - local function run(cmd) - return n.exec_lua(function(cmd_, env_) - return vim - .system(cmd_, { - text = true, - env = vim.tbl_extend( - 'force', - -- Avoid noise in the logs; we expect failures for these tests. - { NVIM_LOG_FILE = testlog }, - env_ or {} - ), - }) - :wait() - end, cmd, env) --[[@as vim.SystemCompleted]] - end - - local cmd = vim.list_extend({ n.nvim_prog, '+qall!', '--headless' }, args) - local r = run(cmd) - eq(1, r.code) - matches(expected, (r.stderr .. r.stdout):gsub('\\n', ' ')) - - if is_os('win') then - return -- On Windows, output without --headless is garbage. - end - table.remove(cmd, 3) -- Remove '--headless'. - assert(not vim.tbl_contains(cmd, '--headless')) - r = run(cmd) - eq(1, r.code) - matches(expected, (r.stderr .. r.stdout):gsub('\\n', ' ')) - end - - it('validates', function() - clear { env = { NVIM_LOG_FILE = testlog } } - local in_use = n.eval('v:servername') ---@type string Address already used by another server. - - t.assert_nolog('Failed to start server', testlog, 100) - t.assert_nolog('Host lookup failed', testlog, 100) - - _test({ '--listen' }, nil, 'nvim.*: Argument missing after: "%-%-listen"') - _test({ '--listen2' }, nil, 'nvim.*: Garbage after option argument: "%-%-listen2"') - _test( - { '--listen', in_use }, - nil, - ('nvim.*: Failed to %%-%%-listen: [^:]+ already [^:]+: "%s"'):format(vim.pesc(in_use)) - ) - _test({ '--listen', '/' }, nil, 'nvim.*: Failed to %-%-listen: [^:]+: "/"') - _test( - { '--listen', 'https://example.com' }, - nil, - ('nvim.*: Failed to %%-%%-listen: %s: "https://example.com"'):format( - is_os('mac') and 'unknown node or service' or 'service not available for socket type' - ) - ) - - t.assert_log('Failed to start server', testlog, 100) - t.assert_log('Host lookup failed', testlog, 100) - - _test( - {}, - { NVIM_LISTEN_ADDRESS = in_use }, - ('nvim.*: Failed $NVIM_LISTEN_ADDRESS: [^:]+ already [^:]+: "%s"'):format(vim.pesc(in_use)) - ) - _test({}, { NVIM_LISTEN_ADDRESS = '/' }, 'nvim.*: Failed $NVIM_LISTEN_ADDRESS: [^:]+: "/"') - _test( - {}, - { NVIM_LISTEN_ADDRESS = 'https://example.com' }, - ('nvim.*: Failed $NVIM_LISTEN_ADDRESS: %s: "https://example.com"'):format( - is_os('mac') and 'unknown node or service' or 'service not available for socket type' - ) - ) - end) - - it('sets v:servername, overrides $NVIM_LISTEN_ADDRESS', function() - local addr = (is_os('win') and [[\\.\pipe\Xtest-listen-pipe]] or './Xtest-listen-pipe') - clear({ env = { NVIM_LISTEN_ADDRESS = './Xtest-env-pipe' }, args = { '--listen', addr } }) - eq('', eval('$NVIM_LISTEN_ADDRESS')) -- Cleared on startup. - eq(addr, api.nvim_get_vvar('servername')) - - -- Address without slashes is a "name" which is appended to a generated path. #8519 - clear({ args = { '--listen', 'test-name' } }) - matches([[.*[/\\]test%-name[^/\\]*]], api.nvim_get_vvar('servername')) - end) -end) -- cgit From ed832b9ddf45705abe9d7f4a50cedc27072c8e16 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 8 Sep 2024 21:29:20 +0200 Subject: refactor(test): rename alter_slashes, invert its behavior - `alter_slashes` belongs in `testutil.lua`, not `testnvim.lua`. - `alter_slashes` is an unusual name. Rename it to `fix_slashes`. - invert its behavior, to emphasize that `/` slashes are the preferred, pervasive convention, not `\` slashes. --- test/functional/api/vim_spec.lua | 22 +- test/functional/autocmd/dirchanged_spec.lua | 2 +- test/functional/core/startup_spec.lua | 20 +- test/functional/ex_cmds/mksession_spec.lua | 2 +- test/functional/lua/uri_spec.lua | 2 +- test/functional/options/autochdir_spec.lua | 2 +- test/functional/options/defaults_spec.lua | 509 ++++++++++++------------- test/functional/terminal/buffer_spec.lua | 2 +- test/functional/testnvim.lua | 20 - test/functional/vimscript/fnamemodify_spec.lua | 3 +- 10 files changed, 277 insertions(+), 307 deletions(-) (limited to 'test/functional') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 074d3ac0a3..71703c9b05 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -3201,7 +3201,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 +3210,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) diff --git a/test/functional/autocmd/dirchanged_spec.lua b/test/functional/autocmd/dirchanged_spec.lua index 24ac737b5b..1cde0e0552 100644 --- a/test/functional/autocmd/dirchanged_spec.lua +++ b/test/functional/autocmd/dirchanged_spec.lua @@ -9,7 +9,7 @@ local request = n.request local is_os = t.is_os describe('autocmd DirChanged and DirChangedPre', function() - local curdir = vim.uv.cwd():gsub('\\', '/') + local curdir = t.fix_slashes(vim.uv.cwd()) local dirs = { curdir .. '/Xtest-functional-autocmd-dirchanged.dir1', curdir .. '/Xtest-functional-autocmd-dirchanged.dir2', diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua index 8d6ba9712a..f48bcb9360 100644 --- a/test/functional/core/startup_spec.lua +++ b/test/functional/core/startup_spec.lua @@ -27,7 +27,6 @@ local sleep = vim.uv.sleep local startswith = vim.startswith local write_file = t.write_file local api = n.api -local alter_slashes = n.alter_slashes local is_os = t.is_os local dedent = t.dedent local tbl_map = vim.tbl_map @@ -40,22 +39,15 @@ local testlog = 'Xtest-startupspec-log' describe('startup', function() it('--clean', function() clear() - ok( - string.find( - alter_slashes(api.nvim_get_option_value('runtimepath', {})), - fn.stdpath('config'), - 1, - true - ) ~= nil + matches( + vim.pesc(t.fix_slashes(fn.stdpath('config'))), + t.fix_slashes(api.nvim_get_option_value('runtimepath', {})) ) + clear('--clean') ok( - string.find( - alter_slashes(api.nvim_get_option_value('runtimepath', {})), - fn.stdpath('config'), - 1, - true - ) == nil + not t.fix_slashes(api.nvim_get_option_value('runtimepath', {})) + :match(vim.pesc(t.fix_slashes(fn.stdpath('config')))) ) end) diff --git a/test/functional/ex_cmds/mksession_spec.lua b/test/functional/ex_cmds/mksession_spec.lua index 9b24854362..8f09e802eb 100644 --- a/test/functional/ex_cmds/mksession_spec.lua +++ b/test/functional/ex_cmds/mksession_spec.lua @@ -170,7 +170,7 @@ describe(':mksession', function() skip(is_os('win'), 'causes rmdir() to fail') local cwd_dir = fn.fnamemodify('.', ':p:~'):gsub([[[\/]*$]], '') - cwd_dir = cwd_dir:gsub([[\]], '/') -- :mksession always uses unix slashes. + cwd_dir = t.fix_slashes(cwd_dir) -- :mksession always uses unix slashes. local session_path = cwd_dir .. '/' .. session_file command('cd ' .. tab_dir) diff --git a/test/functional/lua/uri_spec.lua b/test/functional/lua/uri_spec.lua index 553afb35d3..258b96bc43 100644 --- a/test/functional/lua/uri_spec.lua +++ b/test/functional/lua/uri_spec.lua @@ -217,7 +217,7 @@ describe('URI methods', function() ]], file ) - local expected_uri = 'file:///' .. file:gsub('\\', '/') + local expected_uri = 'file:///' .. t.fix_slashes(file) eq(expected_uri, exec_lua(test_case)) os.remove(file) end) diff --git a/test/functional/options/autochdir_spec.lua b/test/functional/options/autochdir_spec.lua index c490ab67a9..a409262d84 100644 --- a/test/functional/options/autochdir_spec.lua +++ b/test/functional/options/autochdir_spec.lua @@ -22,7 +22,7 @@ describe("'autochdir'", function() end) it('is not overwritten by getwinvar() call #17609', function() - local curdir = vim.uv.cwd():gsub('\\', '/') + local curdir = t.fix_slashes(vim.uv.cwd()) local dir_a = curdir .. '/Xtest-functional-options-autochdir.dir_a' local dir_b = curdir .. '/Xtest-functional-options-autochdir.dir_b' mkdir(dir_a) diff --git a/test/functional/options/defaults_spec.lua b/test/functional/options/defaults_spec.lua index ad94ef1206..43c9768776 100644 --- a/test/functional/options/defaults_spec.lua +++ b/test/functional/options/defaults_spec.lua @@ -23,7 +23,6 @@ local insert = n.insert local neq = t.neq local mkdir = t.mkdir local rmdir = n.rmdir -local alter_slashes = n.alter_slashes local tbl_contains = vim.tbl_contains local expect_exit = n.expect_exit local check_close = n.check_close @@ -262,7 +261,7 @@ describe('startup defaults', function() NVIM_LOG_FILE = '', -- Empty is invalid. }, }) - eq(xdgstatedir .. '/log', string.gsub(eval('$NVIM_LOG_FILE'), '\\', '/')) + eq(xdgstatedir .. '/log', t.fix_slashes(eval('$NVIM_LOG_FILE'))) end) it('defaults to stdpath("log")/log if invalid', function() @@ -273,7 +272,7 @@ describe('startup defaults', function() NVIM_LOG_FILE = '.', -- Any directory is invalid. }, }) - eq(xdgstatedir .. '/log', string.gsub(eval('$NVIM_LOG_FILE'), '\\', '/')) + eq(xdgstatedir .. '/log', t.fix_slashes(eval('$NVIM_LOG_FILE'))) -- Avoid "failed to open $NVIM_LOG_FILE" noise in test output. expect_exit(command, 'qall!') end) @@ -383,69 +382,69 @@ describe('XDG defaults', function() eq( ( - ( + t.fix_slashes( root_path - .. ('/x'):rep(4096) - .. '/nvim' - .. ',' - .. root_path - .. ('/a'):rep(2048) - .. '/nvim' - .. ',' - .. root_path - .. ('/b'):rep(2048) - .. '/nvim' - .. (',' .. root_path .. '/c/nvim') - .. ',' - .. root_path - .. ('/X'):rep(4096) - .. '/' - .. data_dir - .. '/site' - .. ',' - .. root_path - .. ('/A'):rep(2048) - .. '/nvim/site' - .. ',' - .. root_path - .. ('/B'):rep(2048) - .. '/nvim/site' - .. (',' .. root_path .. '/C/nvim/site') - .. ',' - .. vimruntime - .. ',' - .. libdir - .. (',' .. root_path .. '/C/nvim/site/after') - .. ',' - .. root_path - .. ('/B'):rep(2048) - .. '/nvim/site/after' - .. ',' - .. root_path - .. ('/A'):rep(2048) - .. '/nvim/site/after' - .. ',' - .. root_path - .. ('/X'):rep(4096) - .. '/' - .. data_dir - .. '/site/after' - .. (',' .. root_path .. '/c/nvim/after') - .. ',' - .. root_path - .. ('/b'):rep(2048) - .. '/nvim/after' - .. ',' - .. root_path - .. ('/a'):rep(2048) - .. '/nvim/after' - .. ',' - .. root_path - .. ('/x'):rep(4096) - .. '/nvim/after' - ):gsub('\\', '/') + .. ('/x'):rep(4096) + .. '/nvim' + .. ',' + .. root_path + .. ('/a'):rep(2048) + .. '/nvim' + .. ',' + .. root_path + .. ('/b'):rep(2048) + .. '/nvim' + .. (',' .. root_path .. '/c/nvim') + .. ',' + .. root_path + .. ('/X'):rep(4096) + .. '/' + .. data_dir + .. '/site' + .. ',' + .. root_path + .. ('/A'):rep(2048) + .. '/nvim/site' + .. ',' + .. root_path + .. ('/B'):rep(2048) + .. '/nvim/site' + .. (',' .. root_path .. '/C/nvim/site') + .. ',' + .. vimruntime + .. ',' + .. libdir + .. (',' .. root_path .. '/C/nvim/site/after') + .. ',' + .. root_path + .. ('/B'):rep(2048) + .. '/nvim/site/after' + .. ',' + .. root_path + .. ('/A'):rep(2048) + .. '/nvim/site/after' + .. ',' + .. root_path + .. ('/X'):rep(4096) + .. '/' + .. data_dir + .. '/site/after' + .. (',' .. root_path .. '/c/nvim/after') + .. ',' + .. root_path + .. ('/b'):rep(2048) + .. '/nvim/after' + .. ',' + .. root_path + .. ('/a'):rep(2048) + .. '/nvim/after' + .. ',' + .. root_path + .. ('/x'):rep(4096) + .. '/nvim/after' + ) ), - (api.nvim_get_option_value('runtimepath', {})):gsub('\\', '/') + t.fix_slashes(api.nvim_get_option_value('runtimepath', {})) ) command('set runtimepath&') command('set backupdir&') @@ -454,85 +453,85 @@ describe('XDG defaults', function() command('set viewdir&') eq( ( - ( + t.fix_slashes( root_path - .. ('/x'):rep(4096) - .. '/nvim' - .. ',' - .. root_path - .. ('/a'):rep(2048) - .. '/nvim' - .. ',' - .. root_path - .. ('/b'):rep(2048) - .. '/nvim' - .. (',' .. root_path .. '/c/nvim') - .. ',' - .. root_path - .. ('/X'):rep(4096) - .. '/' - .. data_dir - .. '/site' - .. ',' - .. root_path - .. ('/A'):rep(2048) - .. '/nvim/site' - .. ',' - .. root_path - .. ('/B'):rep(2048) - .. '/nvim/site' - .. (',' .. root_path .. '/C/nvim/site') - .. ',' - .. vimruntime - .. ',' - .. libdir - .. (',' .. root_path .. '/C/nvim/site/after') - .. ',' - .. root_path - .. ('/B'):rep(2048) - .. '/nvim/site/after' - .. ',' - .. root_path - .. ('/A'):rep(2048) - .. '/nvim/site/after' - .. ',' - .. root_path - .. ('/X'):rep(4096) - .. '/' - .. data_dir - .. '/site/after' - .. (',' .. root_path .. '/c/nvim/after') - .. ',' - .. root_path - .. ('/b'):rep(2048) - .. '/nvim/after' - .. ',' - .. root_path - .. ('/a'):rep(2048) - .. '/nvim/after' - .. ',' - .. root_path - .. ('/x'):rep(4096) - .. '/nvim/after' - ):gsub('\\', '/') + .. ('/x'):rep(4096) + .. '/nvim' + .. ',' + .. root_path + .. ('/a'):rep(2048) + .. '/nvim' + .. ',' + .. root_path + .. ('/b'):rep(2048) + .. '/nvim' + .. (',' .. root_path .. '/c/nvim') + .. ',' + .. root_path + .. ('/X'):rep(4096) + .. '/' + .. data_dir + .. '/site' + .. ',' + .. root_path + .. ('/A'):rep(2048) + .. '/nvim/site' + .. ',' + .. root_path + .. ('/B'):rep(2048) + .. '/nvim/site' + .. (',' .. root_path .. '/C/nvim/site') + .. ',' + .. vimruntime + .. ',' + .. libdir + .. (',' .. root_path .. '/C/nvim/site/after') + .. ',' + .. root_path + .. ('/B'):rep(2048) + .. '/nvim/site/after' + .. ',' + .. root_path + .. ('/A'):rep(2048) + .. '/nvim/site/after' + .. ',' + .. root_path + .. ('/X'):rep(4096) + .. '/' + .. data_dir + .. '/site/after' + .. (',' .. root_path .. '/c/nvim/after') + .. ',' + .. root_path + .. ('/b'):rep(2048) + .. '/nvim/after' + .. ',' + .. root_path + .. ('/a'):rep(2048) + .. '/nvim/after' + .. ',' + .. root_path + .. ('/x'):rep(4096) + .. '/nvim/after' + ) ), - (api.nvim_get_option_value('runtimepath', {})):gsub('\\', '/') + t.fix_slashes(api.nvim_get_option_value('runtimepath', {})) ) eq( '.,' .. root_path .. ('/X'):rep(4096) .. '/' .. state_dir .. '/backup//', - (api.nvim_get_option_value('backupdir', {}):gsub('\\', '/')) + t.fix_slashes(api.nvim_get_option_value('backupdir', {})) ) eq( root_path .. ('/X'):rep(4096) .. '/' .. state_dir .. '/swap//', - (api.nvim_get_option_value('directory', {})):gsub('\\', '/') + t.fix_slashes(api.nvim_get_option_value('directory', {})) ) eq( root_path .. ('/X'):rep(4096) .. '/' .. state_dir .. '/undo//', - (api.nvim_get_option_value('undodir', {})):gsub('\\', '/') + t.fix_slashes(api.nvim_get_option_value('undodir', {})) ) eq( root_path .. ('/X'):rep(4096) .. '/' .. state_dir .. '/view//', - (api.nvim_get_option_value('viewdir', {})):gsub('\\', '/') + t.fix_slashes(api.nvim_get_option_value('viewdir', {})) ) end) end) @@ -574,26 +573,26 @@ describe('XDG defaults', function() local vimruntime, libdir = vimruntime_and_libdir() eq( ( - ( + t.fix_slashes( '$XDG_DATA_HOME/nvim' - .. ',$XDG_DATA_DIRS/nvim' - .. ',$XDG_CONFIG_HOME/' - .. data_dir - .. '/site' - .. ',$XDG_CONFIG_DIRS/nvim/site' - .. ',' - .. vimruntime - .. ',' - .. libdir - .. ',$XDG_CONFIG_DIRS/nvim/site/after' - .. ',$XDG_CONFIG_HOME/' - .. data_dir - .. '/site/after' - .. ',$XDG_DATA_DIRS/nvim/after' - .. ',$XDG_DATA_HOME/nvim/after' - ):gsub('\\', '/') + .. ',$XDG_DATA_DIRS/nvim' + .. ',$XDG_CONFIG_HOME/' + .. data_dir + .. '/site' + .. ',$XDG_CONFIG_DIRS/nvim/site' + .. ',' + .. vimruntime + .. ',' + .. libdir + .. ',$XDG_CONFIG_DIRS/nvim/site/after' + .. ',$XDG_CONFIG_HOME/' + .. data_dir + .. '/site/after' + .. ',$XDG_DATA_DIRS/nvim/after' + .. ',$XDG_DATA_HOME/nvim/after' + ) ), - (api.nvim_get_option_value('runtimepath', {})):gsub('\\', '/') + t.fix_slashes(api.nvim_get_option_value('runtimepath', {})) ) command('set runtimepath&') command('set backupdir&') @@ -602,80 +601,80 @@ describe('XDG defaults', function() command('set viewdir&') eq( ( - ( + t.fix_slashes( '$XDG_DATA_HOME/nvim' - .. ',$XDG_DATA_DIRS/nvim' - .. ',$XDG_CONFIG_HOME/' - .. data_dir - .. '/site' - .. ',$XDG_CONFIG_DIRS/nvim/site' - .. ',' - .. vimruntime - .. ',' - .. libdir - .. ',$XDG_CONFIG_DIRS/nvim/site/after' - .. ',$XDG_CONFIG_HOME/' - .. data_dir - .. '/site/after' - .. ',$XDG_DATA_DIRS/nvim/after' - .. ',$XDG_DATA_HOME/nvim/after' - ):gsub('\\', '/') + .. ',$XDG_DATA_DIRS/nvim' + .. ',$XDG_CONFIG_HOME/' + .. data_dir + .. '/site' + .. ',$XDG_CONFIG_DIRS/nvim/site' + .. ',' + .. vimruntime + .. ',' + .. libdir + .. ',$XDG_CONFIG_DIRS/nvim/site/after' + .. ',$XDG_CONFIG_HOME/' + .. data_dir + .. '/site/after' + .. ',$XDG_DATA_DIRS/nvim/after' + .. ',$XDG_DATA_HOME/nvim/after' + ) ), - (api.nvim_get_option_value('runtimepath', {})):gsub('\\', '/') + t.fix_slashes(api.nvim_get_option_value('runtimepath', {})) ) eq( ('.,$XDG_CONFIG_HOME/' .. state_dir .. '/backup//'), - api.nvim_get_option_value('backupdir', {}):gsub('\\', '/') + t.fix_slashes(api.nvim_get_option_value('backupdir', {})) ) eq( ('$XDG_CONFIG_HOME/' .. state_dir .. '/swap//'), - api.nvim_get_option_value('directory', {}):gsub('\\', '/') + t.fix_slashes(api.nvim_get_option_value('directory', {})) ) eq( ('$XDG_CONFIG_HOME/' .. state_dir .. '/undo//'), - api.nvim_get_option_value('undodir', {}):gsub('\\', '/') + t.fix_slashes(api.nvim_get_option_value('undodir', {})) ) eq( ('$XDG_CONFIG_HOME/' .. state_dir .. '/view//'), - api.nvim_get_option_value('viewdir', {}):gsub('\\', '/') + t.fix_slashes(api.nvim_get_option_value('viewdir', {})) ) command('set all&') eq( - ( + t.fix_slashes( '$XDG_DATA_HOME/nvim' - .. ',$XDG_DATA_DIRS/nvim' - .. ',$XDG_CONFIG_HOME/' - .. data_dir - .. '/site' - .. ',$XDG_CONFIG_DIRS/nvim/site' - .. ',' - .. vimruntime - .. ',' - .. libdir - .. ',$XDG_CONFIG_DIRS/nvim/site/after' - .. ',$XDG_CONFIG_HOME/' - .. data_dir - .. '/site/after' - .. ',$XDG_DATA_DIRS/nvim/after' - .. ',$XDG_DATA_HOME/nvim/after' - ):gsub('\\', '/'), - (api.nvim_get_option_value('runtimepath', {})):gsub('\\', '/') + .. ',$XDG_DATA_DIRS/nvim' + .. ',$XDG_CONFIG_HOME/' + .. data_dir + .. '/site' + .. ',$XDG_CONFIG_DIRS/nvim/site' + .. ',' + .. vimruntime + .. ',' + .. libdir + .. ',$XDG_CONFIG_DIRS/nvim/site/after' + .. ',$XDG_CONFIG_HOME/' + .. data_dir + .. '/site/after' + .. ',$XDG_DATA_DIRS/nvim/after' + .. ',$XDG_DATA_HOME/nvim/after' + ), + t.fix_slashes(api.nvim_get_option_value('runtimepath', {})) ) eq( ('.,$XDG_CONFIG_HOME/' .. state_dir .. '/backup//'), - api.nvim_get_option_value('backupdir', {}):gsub('\\', '/') + t.fix_slashes(api.nvim_get_option_value('backupdir', {})) ) eq( ('$XDG_CONFIG_HOME/' .. state_dir .. '/swap//'), - api.nvim_get_option_value('directory', {}):gsub('\\', '/') + t.fix_slashes(api.nvim_get_option_value('directory', {})) ) eq( ('$XDG_CONFIG_HOME/' .. state_dir .. '/undo//'), - api.nvim_get_option_value('undodir', {}):gsub('\\', '/') + t.fix_slashes(api.nvim_get_option_value('undodir', {})) ) eq( ('$XDG_CONFIG_HOME/' .. state_dir .. '/view//'), - api.nvim_get_option_value('viewdir', {}):gsub('\\', '/') + t.fix_slashes(api.nvim_get_option_value('viewdir', {})) ) eq(nil, (fn.tempname()):match('XDG_RUNTIME_DIR')) end) @@ -939,7 +938,7 @@ describe('stdpath()', function() local child = vim.fn.jobstart({ vim.v.progpath, '--clean', '--headless', '--listen', 'x', '+qall!' }, { env = { NVIM_APPNAME = %q } }) return vim.fn.jobwait({ child }, %d)[1] ]], - alter_slashes(testAppname), + testAppname, 3000 ) eq(expected_exitcode, exec_lua(lua_code)) @@ -970,7 +969,7 @@ describe('stdpath()', function() }, }) - t.matches(vim.pesc(tmpdir), fn.tempname():gsub('\\', '/')) + t.matches(vim.pesc(tmpdir), t.fix_slashes(fn.tempname())) t.assert_nolog('tempdir', testlog, 100) t.assert_nolog('TMPDIR', testlog, 100) t.matches([=[[/\\]relative%-appname.[^/\\]+]=], api.nvim_get_vvar('servername')) @@ -981,19 +980,19 @@ describe('stdpath()', function() it('knows XDG_CONFIG_HOME', function() clear({ env = { - XDG_CONFIG_HOME = alter_slashes('/home/docwhat/.config'), + XDG_CONFIG_HOME = '/home/docwhat/.config', }, }) - eq(alter_slashes('/home/docwhat/.config/nvim'), fn.stdpath('config')) + eq('/home/docwhat/.config/nvim', t.fix_slashes(fn.stdpath('config'))) end) it('handles changes during runtime', function() clear({ env = { - XDG_CONFIG_HOME = alter_slashes('/home/original'), + XDG_CONFIG_HOME = '/home/original', } }) - eq(alter_slashes('/home/original/nvim'), fn.stdpath('config')) - command("let $XDG_CONFIG_HOME='" .. alter_slashes('/home/new') .. "'") - eq(alter_slashes('/home/new/nvim'), fn.stdpath('config')) + eq('/home/original/nvim', t.fix_slashes(fn.stdpath('config'))) + command("let $XDG_CONFIG_HOME='/home/new'") + eq('/home/new/nvim', t.fix_slashes(fn.stdpath('config'))) end) it("doesn't expand $VARIABLES", function() @@ -1003,32 +1002,32 @@ describe('stdpath()', function() VARIABLES = 'this-should-not-happen', }, }) - eq(alter_slashes('$VARIABLES/nvim'), fn.stdpath('config')) + eq('$VARIABLES/nvim', t.fix_slashes(fn.stdpath('config'))) end) it("doesn't expand ~/", function() clear({ env = { - XDG_CONFIG_HOME = alter_slashes('~/frobnitz'), + XDG_CONFIG_HOME = '~/frobnitz', } }) - eq(alter_slashes('~/frobnitz/nvim'), fn.stdpath('config')) + eq('~/frobnitz/nvim', t.fix_slashes(fn.stdpath('config'))) end) end) describe('with "data"', function() it('knows XDG_DATA_HOME', function() clear({ env = { - XDG_DATA_HOME = alter_slashes('/home/docwhat/.local'), + XDG_DATA_HOME = '/home/docwhat/.local', } }) - eq(alter_slashes('/home/docwhat/.local/' .. datadir), fn.stdpath('data')) + eq('/home/docwhat/.local/' .. datadir, t.fix_slashes(fn.stdpath('data'))) end) it('handles changes during runtime', function() clear({ env = { - XDG_DATA_HOME = alter_slashes('/home/original'), + XDG_DATA_HOME = '/home/original', } }) - eq(alter_slashes('/home/original/' .. datadir), fn.stdpath('data')) - command("let $XDG_DATA_HOME='" .. alter_slashes('/home/new') .. "'") - eq(alter_slashes('/home/new/' .. datadir), fn.stdpath('data')) + eq('/home/original/' .. datadir, t.fix_slashes(fn.stdpath('data'))) + command("let $XDG_DATA_HOME='/home/new'") + eq('/home/new/' .. datadir, t.fix_slashes(fn.stdpath('data'))) end) it("doesn't expand $VARIABLES", function() @@ -1038,14 +1037,14 @@ describe('stdpath()', function() VARIABLES = 'this-should-not-happen', }, }) - eq(alter_slashes('$VARIABLES/' .. datadir), fn.stdpath('data')) + eq('$VARIABLES/' .. datadir, t.fix_slashes(fn.stdpath('data'))) end) it("doesn't expand ~/", function() clear({ env = { - XDG_DATA_HOME = alter_slashes('~/frobnitz'), + XDG_DATA_HOME = '~/frobnitz', } }) - eq(alter_slashes('~/frobnitz/' .. datadir), fn.stdpath('data')) + eq('~/frobnitz/' .. datadir, t.fix_slashes(fn.stdpath('data'))) end) end) @@ -1053,19 +1052,19 @@ describe('stdpath()', function() it('knows XDG_STATE_HOME', function() clear({ env = { - XDG_STATE_HOME = alter_slashes('/home/docwhat/.local'), + XDG_STATE_HOME = '/home/docwhat/.local', }, }) - eq(alter_slashes('/home/docwhat/.local/' .. statedir), fn.stdpath('state')) + eq('/home/docwhat/.local/' .. statedir, t.fix_slashes(fn.stdpath('state'))) end) it('handles changes during runtime', function() clear({ env = { - XDG_STATE_HOME = alter_slashes('/home/original'), + XDG_STATE_HOME = '/home/original', } }) - eq(alter_slashes('/home/original/' .. statedir), fn.stdpath('state')) - command("let $XDG_STATE_HOME='" .. alter_slashes('/home/new') .. "'") - eq(alter_slashes('/home/new/' .. statedir), fn.stdpath('state')) + eq('/home/original/' .. statedir, t.fix_slashes(fn.stdpath('state'))) + command("let $XDG_STATE_HOME='" .. '/home/new' .. "'") + eq('/home/new/' .. statedir, t.fix_slashes(fn.stdpath('state'))) end) it("doesn't expand $VARIABLES", function() @@ -1075,14 +1074,14 @@ describe('stdpath()', function() VARIABLES = 'this-should-not-happen', }, }) - eq(alter_slashes('$VARIABLES/' .. statedir), fn.stdpath('state')) + eq('$VARIABLES/' .. statedir, t.fix_slashes(fn.stdpath('state'))) end) it("doesn't expand ~/", function() clear({ env = { - XDG_STATE_HOME = alter_slashes('~/frobnitz'), + XDG_STATE_HOME = '~/frobnitz', } }) - eq(alter_slashes('~/frobnitz/' .. statedir), fn.stdpath('state')) + eq('~/frobnitz/' .. statedir, t.fix_slashes(fn.stdpath('state'))) end) end) @@ -1090,19 +1089,19 @@ describe('stdpath()', function() it('knows XDG_CACHE_HOME', function() clear({ env = { - XDG_CACHE_HOME = alter_slashes('/home/docwhat/.cache'), + XDG_CACHE_HOME = '/home/docwhat/.cache', }, }) - eq(alter_slashes('/home/docwhat/.cache/nvim'), fn.stdpath('cache')) + eq('/home/docwhat/.cache/nvim', t.fix_slashes(fn.stdpath('cache'))) end) it('handles changes during runtime', function() clear({ env = { - XDG_CACHE_HOME = alter_slashes('/home/original'), + XDG_CACHE_HOME = '/home/original', } }) - eq(alter_slashes('/home/original/nvim'), fn.stdpath('cache')) - command("let $XDG_CACHE_HOME='" .. alter_slashes('/home/new') .. "'") - eq(alter_slashes('/home/new/nvim'), fn.stdpath('cache')) + eq('/home/original/nvim', t.fix_slashes(fn.stdpath('cache'))) + command("let $XDG_CACHE_HOME='" .. '/home/new' .. "'") + eq('/home/new/nvim', t.fix_slashes(fn.stdpath('cache'))) end) it("doesn't expand $VARIABLES", function() @@ -1112,14 +1111,14 @@ describe('stdpath()', function() VARIABLES = 'this-should-not-happen', }, }) - eq(alter_slashes('$VARIABLES/nvim'), fn.stdpath('cache')) + eq('$VARIABLES/nvim', t.fix_slashes(fn.stdpath('cache'))) end) it("doesn't expand ~/", function() clear({ env = { - XDG_CACHE_HOME = alter_slashes('~/frobnitz'), + XDG_CACHE_HOME = '~/frobnitz', } }) - eq(alter_slashes('~/frobnitz/nvim'), fn.stdpath('cache')) + eq('~/frobnitz/nvim', t.fix_slashes(fn.stdpath('cache'))) end) end) end) @@ -1166,12 +1165,12 @@ describe('stdpath()', function() describe(msg, function() it('set via system', function() set_paths_via_system(env_var_name, paths) - eq(expected_paths, fn.stdpath(stdpath_arg)) + eq(expected_paths, t.fix_slashes(fn.stdpath(stdpath_arg))) end) it('set at runtime', function() set_paths_at_runtime(env_var_name, paths) - eq(expected_paths, fn.stdpath(stdpath_arg)) + eq(expected_paths, t.fix_slashes(fn.stdpath(stdpath_arg))) end) end) end @@ -1182,10 +1181,10 @@ describe('stdpath()', function() 'config_dirs', 'XDG_CONFIG_DIRS', { - alter_slashes('/home/docwhat/.config'), + t.fix_slashes('/home/docwhat/.config'), }, { - alter_slashes('/home/docwhat/.config/nvim'), + t.fix_slashes('/home/docwhat/.config/nvim'), } ) @@ -1194,12 +1193,12 @@ describe('stdpath()', function() 'config_dirs', 'XDG_CONFIG_DIRS', { - alter_slashes('/home/docwhat/.config'), - alter_slashes('/etc/config'), + t.fix_slashes('/home/docwhat/.config'), + t.fix_slashes('/etc/config'), }, { - alter_slashes('/home/docwhat/.config/nvim'), - alter_slashes('/etc/config/nvim'), + t.fix_slashes('/home/docwhat/.config/nvim'), + t.fix_slashes('/etc/config/nvim'), } ) @@ -1209,25 +1208,25 @@ describe('stdpath()', function() 'XDG_CONFIG_DIRS', { '$HOME', '$TMP' }, { - alter_slashes('$HOME/nvim'), - alter_slashes('$TMP/nvim'), + t.fix_slashes('$HOME/nvim'), + t.fix_slashes('$TMP/nvim'), } ) behaves_like_dir_list_env("doesn't expand ~/", 'config_dirs', 'XDG_CONFIG_DIRS', { - alter_slashes('~/.oldconfig'), - alter_slashes('~/.olderconfig'), + t.fix_slashes('~/.oldconfig'), + t.fix_slashes('~/.olderconfig'), }, { - alter_slashes('~/.oldconfig/nvim'), - alter_slashes('~/.olderconfig/nvim'), + t.fix_slashes('~/.oldconfig/nvim'), + t.fix_slashes('~/.olderconfig/nvim'), }) end) describe('with "data_dirs"', function() behaves_like_dir_list_env('knows XDG_DATA_DIRS with one path', 'data_dirs', 'XDG_DATA_DIRS', { - alter_slashes('/home/docwhat/.data'), + t.fix_slashes('/home/docwhat/.data'), }, { - alter_slashes('/home/docwhat/.data/nvim'), + t.fix_slashes('/home/docwhat/.data/nvim'), }) behaves_like_dir_list_env( @@ -1235,12 +1234,12 @@ describe('stdpath()', function() 'data_dirs', 'XDG_DATA_DIRS', { - alter_slashes('/home/docwhat/.data'), - alter_slashes('/etc/local'), + t.fix_slashes('/home/docwhat/.data'), + t.fix_slashes('/etc/local'), }, { - alter_slashes('/home/docwhat/.data/nvim'), - alter_slashes('/etc/local/nvim'), + t.fix_slashes('/home/docwhat/.data/nvim'), + t.fix_slashes('/etc/local/nvim'), } ) @@ -1250,17 +1249,17 @@ describe('stdpath()', function() 'XDG_DATA_DIRS', { '$HOME', '$TMP' }, { - alter_slashes('$HOME/nvim'), - alter_slashes('$TMP/nvim'), + t.fix_slashes('$HOME/nvim'), + t.fix_slashes('$TMP/nvim'), } ) behaves_like_dir_list_env("doesn't expand ~/", 'data_dirs', 'XDG_DATA_DIRS', { - alter_slashes('~/.oldconfig'), - alter_slashes('~/.olderconfig'), + t.fix_slashes('~/.oldconfig'), + t.fix_slashes('~/.olderconfig'), }, { - alter_slashes('~/.oldconfig/nvim'), - alter_slashes('~/.olderconfig/nvim'), + t.fix_slashes('~/.oldconfig/nvim'), + t.fix_slashes('~/.olderconfig/nvim'), }) end) end) diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua index 767a3dc205..888c4538af 100644 --- a/test/functional/terminal/buffer_spec.lua +++ b/test/functional/terminal/buffer_spec.lua @@ -342,7 +342,7 @@ describe(':terminal buffer', function() command('wincmd p') -- cwd will be inserted in a file URI, which cannot contain backs - local cwd = fn.getcwd():gsub('\\', '/') + local cwd = t.fix_slashes(fn.getcwd()) local parent = cwd:match('^(.+/)') local expected = '\027]7;file://host' .. parent api.nvim_chan_send(term, string.format('%s\027\\', expected)) diff --git a/test/functional/testnvim.lua b/test/functional/testnvim.lua index d74e8055ef..8c8b239cd8 100644 --- a/test/functional/testnvim.lua +++ b/test/functional/testnvim.lua @@ -902,26 +902,6 @@ function M.missing_provider(provider) assert(false, 'Unknown provider: ' .. provider) end ---- @param obj string|table ---- @return any -function M.alter_slashes(obj) - if not is_os('win') then - return obj - end - if type(obj) == 'string' then - local ret = obj:gsub('/', '\\') - return ret - elseif type(obj) == 'table' then - --- @cast obj table - local ret = {} --- @type table - for k, v in pairs(obj) do - ret[k] = M.alter_slashes(v) - end - return ret - end - assert(false, 'expected string or table of strings, got ' .. type(obj)) -end - local load_factor = 1 if t.is_ci() then -- Compute load factor only once (but outside of any tests). diff --git a/test/functional/vimscript/fnamemodify_spec.lua b/test/functional/vimscript/fnamemodify_spec.lua index 51b1e8489a..f2cee9b83e 100644 --- a/test/functional/vimscript/fnamemodify_spec.lua +++ b/test/functional/vimscript/fnamemodify_spec.lua @@ -7,11 +7,10 @@ local fnamemodify = n.fn.fnamemodify local getcwd = n.fn.getcwd local command = n.command local write_file = t.write_file -local alter_slashes = n.alter_slashes local is_os = t.is_os local function eq_slashconvert(expected, got) - eq(alter_slashes(expected), alter_slashes(got)) + eq(t.fix_slashes(expected), t.fix_slashes(got)) end describe('fnamemodify()', function() -- cgit From c8e3618e0e68485c92bba3790a06d472d9b62697 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Mon, 9 Sep 2024 00:03:25 +0200 Subject: fix(test): "tempdir not a directory" in CI logs $NVIM_LOG_FILE: /Users/runner/work/neovim/neovim/build/.nvimlog WRN 2024-09-08T21:48:13.279 ?.21134 vim_mktempdir:3281: $TMPDIR tempdir not a directory (or does not exist): TMPDIR-should-be-ignored WRN 2024-09-08T21:48:13.312 ?.21137 vim_mktempdir:3281: $TMPDIR tempdir not a directory (or does not exist): TMPDIR-should-be-ignored --- test/functional/options/defaults_spec.lua | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'test/functional') diff --git a/test/functional/options/defaults_spec.lua b/test/functional/options/defaults_spec.lua index 43c9768776..e3d15fa30f 100644 --- a/test/functional/options/defaults_spec.lua +++ b/test/functional/options/defaults_spec.lua @@ -1132,6 +1132,7 @@ describe('stdpath()', function() HOMEDRIVE = 'C:', HOMEPATH = '\\Users\\docwhat', LOCALAPPDATA = 'C:\\Users\\docwhat\\AppData\\Local', + NVIM_LOG_FILE = testlog, TEMP = 'C:\\Users\\docwhat\\AppData\\Local\\Temp', TMPDIR = 'C:\\Users\\docwhat\\AppData\\Local\\Temp', TMP = 'C:\\Users\\docwhat\\AppData\\Local\\Temp', @@ -1142,6 +1143,7 @@ describe('stdpath()', function() HOMEDRIVE = 'HOMEDRIVE-should-be-ignored', HOMEPATH = 'HOMEPATH-should-be-ignored', LOCALAPPDATA = 'LOCALAPPDATA-should-be-ignored', + NVIM_LOG_FILE = testlog, TEMP = 'TEMP-should-be-ignored', TMPDIR = 'TMPDIR-should-be-ignored', TMP = 'TMP-should-be-ignored', @@ -1166,11 +1168,17 @@ describe('stdpath()', function() it('set via system', function() set_paths_via_system(env_var_name, paths) eq(expected_paths, t.fix_slashes(fn.stdpath(stdpath_arg))) + if not is_os('win') then + assert_log('$TMPDIR tempdir not a directory.*TMPDIR%-should%-be%-ignored', testlog, 100) + end end) it('set at runtime', function() set_paths_at_runtime(env_var_name, paths) eq(expected_paths, t.fix_slashes(fn.stdpath(stdpath_arg))) + if not is_os('win') then + assert_log('$TMPDIR tempdir not a directory.*TMPDIR%-should%-be%-ignored', testlog, 100) + end end) end) end -- cgit From 8e81212e151a4e20cff33931b95279e14c4e21c2 Mon Sep 17 00:00:00 2001 From: glepnir Date: Sat, 7 Sep 2024 20:41:20 +0800 Subject: fix(highlight): floating windows inherit NormalFloat from global-ns Problem: floating windows did not correctly inherit the NormalFloat highlight group from the global namespace when it was not defined in the window-specific namespace. This led to floating windows losing their background highlight when switching between namespaces. Solution: Updated the window highlight logic in update_window_hl() to handle the fallback. This fix resolves issues with floating window backgrounds not displaying as expected in certain namespace configurations. --- test/functional/ui/float_spec.lua | 47 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) (limited to 'test/functional') diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua index 754f0772f6..409cf5aac4 100644 --- a/test/functional/ui/float_spec.lua +++ b/test/functional/ui/float_spec.lua @@ -1344,6 +1344,53 @@ describe('float window', function() | ]]) end + + -- + -- floating windows inherit NormalFloat from global-ns. + -- + command('fclose') + command('hi NormalFloat guibg=LightRed') + api.nvim_open_win(0, false, { relative = 'win', row = 3, col = 3, width = 12, height = 3, style = 'minimal' }) + api.nvim_set_hl_ns(api.nvim_create_namespace('test1')) + if multigrid then + screen:expect({ + grid = [[ + ## grid 1 + [2:----------------------------------------]|*6 + [3:----------------------------------------]| + ## grid 2 + {14: 1 }^x | + {14: 2 }y | + {14: 3 } | + {0:~ }|*3 + ## grid 3 + | + ## grid 5 + {22:x }| + {22:y }| + {22: }| + ]], float_pos={ + [5] = {1002, "NW", 2, 3, 3, true, 50}; + }, win_viewport={ + [2] = {win = 1000, topline = 0, botline = 4, curline = 0, curcol = 0, linecount = 3, sum_scroll_delta = 0}; + [5] = {win = 1002, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3, sum_scroll_delta = 0}; + }, win_viewport_margins={ + [2] = { bottom = 0, left = 0, right = 0, top = 0, win = 1000 }, + [5] = { bottom = 0, left = 0, right = 0, top = 0, win = 1002 } + }}) + else + screen:expect({ + grid = [[ + {14: 1 }^x | + {14: 2 }y | + {14: 3 } | + {0:~ }{22:x }{0: }| + {0:~ }{22:y }{0: }| + {0:~ }{22: }{0: }| + | + ]] + }) + end end) it("can use 'minimal' style", function() -- cgit From 7b680e0ca995cacadd9e7c8cb13d5f6ef203694a Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Wed, 11 Sep 2024 11:40:56 +0200 Subject: test(health): "test_plug/health/init.lua" completes as "test_plug" --- test/functional/plugin/health_spec.lua | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) (limited to 'test/functional') diff --git a/test/functional/plugin/health_spec.lua b/test/functional/plugin/health_spec.lua index 9c7c953fb0..20bb8227b3 100644 --- a/test/functional/plugin/health_spec.lua +++ b/test/functional/plugin/health_spec.lua @@ -40,11 +40,22 @@ describe(':checkhealth', function() matches('ERROR $VIM .* zub', curbuf_contents()) end) - it('completions can be listed via getcompletion()', function() - clear() + it('getcompletion()', function() + clear { args = { '-u', 'NORC', '+set runtimepath+=test/functional/fixtures' } } + eq('vim.deprecated', getcompletion('vim', 'checkhealth')[1]) eq('vim.provider', getcompletion('vim.prov', 'checkhealth')[1]) eq('vim.lsp', getcompletion('vim.ls', 'checkhealth')[1]) + + -- "test_plug/health/init.lua" should complete as "test_plug", not "test_plug.health". #30342 + eq({ + 'test_plug', + 'test_plug.full_render', + 'test_plug.submodule', + 'test_plug.submodule_empty', + 'test_plug.success1', + 'test_plug.success2', + }, getcompletion('test_plug', 'checkhealth')) end) it('completion checks for vim.health._complete() return type #28456', function() @@ -57,11 +68,9 @@ describe(':checkhealth', function() end) end) -describe('health.vim', function() +describe('vim.health', function() before_each(function() - clear { args = { '-u', 'NORC' } } - -- Provides healthcheck functions - command('set runtimepath+=test/functional/fixtures') + clear { args = { '-u', 'NORC', '+set runtimepath+=test/functional/fixtures' } } end) describe(':checkhealth', function() @@ -207,9 +216,7 @@ end) describe(':checkhealth window', function() before_each(function() - clear { args = { '-u', 'NORC' } } - -- Provides healthcheck functions - command('set runtimepath+=test/functional/fixtures') + clear { args = { '-u', 'NORC', '+set runtimepath+=test/functional/fixtures' } } command('set nofoldenable nowrap laststatus=0') end) -- cgit From 98ba65b8be8cb2dde839502357e70916c4a3e37a Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Wed, 11 Sep 2024 15:32:08 -0500 Subject: fix: replace NVIM with Nvim in default titlestring (#30348) --- test/functional/ui/title_spec.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'test/functional') diff --git a/test/functional/ui/title_spec.lua b/test/functional/ui/title_spec.lua index fddda2c07a..3189232957 100644 --- a/test/functional/ui/title_spec.lua +++ b/test/functional/ui/title_spec.lua @@ -22,7 +22,7 @@ describe('title', function() end) it('has correct default title with unnamed file', function() - local expected = '[No Name] - NVIM' + local expected = '[No Name] - Nvim' command('set title') screen:expect(function() eq(expected, screen.title) @@ -30,7 +30,7 @@ describe('title', function() end) it('has correct default title with named file', function() - local expected = (is_os('win') and 'myfile (C:\\mydir) - NVIM' or 'myfile (/mydir) - NVIM') + local expected = (is_os('win') and 'myfile (C:\\mydir) - Nvim' or 'myfile (/mydir) - Nvim') command('set title') command(is_os('win') and 'file C:\\mydir\\myfile' or 'file /mydir/myfile') screen:expect(function() @@ -41,7 +41,7 @@ describe('title', function() describe('is not changed by', function() local file1 = is_os('win') and 'C:\\mydir\\myfile1' or '/mydir/myfile1' local file2 = is_os('win') and 'C:\\mydir\\myfile2' or '/mydir/myfile2' - local expected = (is_os('win') and 'myfile1 (C:\\mydir) - NVIM' or 'myfile1 (/mydir) - NVIM') + local expected = (is_os('win') and 'myfile1 (C:\\mydir) - Nvim' or 'myfile1 (/mydir) - Nvim') local buf2 before_each(function() -- cgit From 5931f780e0282ad486fa070bb05b3877cc1d44f0 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Wed, 11 Sep 2024 17:25:00 -0700 Subject: feat(log): use "ui" as default name for TUI client #30345 The default "session name" for the builtin TUI is "ui". before: INF 2024-09-10T14:57:35.385 hello.sock os_exit:692: Nvim exit: 1 INF 2024-09-10T14:57:35.388 ?.4543 os_exit:692: Nvim exit: 1 after: INF 2024-09-10T14:59:19.919 hello.sock os_exit:692: Nvim exit: 1 INF 2024-09-10T14:59:19.922 ui.5684 os_exit:692: Nvim exit: 1 --- test/functional/core/log_spec.lua | 57 ++++++++++++++++++++++++++++++++++----- 1 file changed, 51 insertions(+), 6 deletions(-) (limited to 'test/functional') diff --git a/test/functional/core/log_spec.lua b/test/functional/core/log_spec.lua index cac61cda2d..03beedbfd3 100644 --- a/test/functional/core/log_spec.lua +++ b/test/functional/core/log_spec.lua @@ -1,5 +1,6 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() +local tt = require('test.functional.terminal.testutil') local assert_log = t.assert_log local clear = n.clear @@ -29,10 +30,54 @@ describe('log', function() assert(request('nvim__stats').log_skip <= 13) end) - it('messages are formatted with name or test id', function() + it('TUI client name is "ui"', function() + local function setup(env) + clear() + -- Start Nvim with builtin UI. + local screen = tt.setup_child_nvim({ + '-u', + 'NONE', + '-i', + 'NONE', + '--cmd', + n.nvim_set, + }, { + env = env, + }) + screen:expect([[ + {1: } | + ~ |*4 + | + {3:-- TERMINAL --} | + ]]) + end + + -- Without $NVIM parent. + setup({ + NVIM = '', + NVIM_LISTEN_ADDRESS = '', + NVIM_LOG_FILE = testlog, + __NVIM_TEST_LOG = '1', + }) + -- Example: + -- ERR 2024-09-11T16:40:02.421 ui.47056 ui_client_run:165: test log message + assert_log(' ui%.%d+% +ui_client_run:%d+: test log message', testlog, 100) + + -- With $NVIM parent. + setup({ + NVIM_LOG_FILE = testlog, + __NVIM_TEST_LOG = '1', + }) + -- Example: + -- ERR 2024-09-11T16:41:17.539 ui/c/T2.47826.0 ui_client_run:165: test log message + local tid = _G._nvim_test_id + assert_log(' ui/c/' .. tid .. '%.%d+%.%d +ui_client_run:%d+: test log message', testlog, 100) + end) + + it('formats messages with session name or test id', function() -- Examples: - -- ERR 2022-05-29T12:30:03.800 T2 log_init:110: test log message - -- ERR 2022-05-29T12:30:03.814 T2/child log_init:110: test log message + -- ERR 2024-09-11T16:44:33.794 T3.49429.0 server_init:58: test log message + -- ERR 2024-09-11T16:44:33.823 c/T3.49429.0 server_init:58: test log message clear({ env = { @@ -47,10 +92,10 @@ describe('log', function() exec_lua([[ local j1 = vim.fn.jobstart({ vim.v.progpath, '-es', '-V1', '+foochild', '+qa!' }, vim.empty_dict()) - vim.fn.jobwait({ j1 }, 10000) + vim.fn.jobwait({ j1 }, 5000) ]]) - -- Child Nvim spawned by jobstart() appends "/c" to parent name. - assert_log('%.%d+%.%d/c +server_init:%d+: test log message', testlog, 100) + -- Child Nvim spawned by jobstart() prepends "c/" to parent name. + assert_log('c/' .. tid .. '%.%d+%.%d +server_init:%d+: test log message', testlog, 100) end) end) -- cgit From b9b408a56c7e607972beaa7214719ff1494e384c Mon Sep 17 00:00:00 2001 From: Riley Bruins Date: Fri, 13 Sep 2024 05:09:11 -0700 Subject: feat(treesitter): start moving get_parser to return nil #30313 **Problem:** `vim.treesitter.get_parser` will throw an error if no parser can be found. - This means the caller is responsible for wrapping it in a `pcall`, which is easy to forget - It also makes it slightly harder to potentially memoize `get_parser` in the future - It's a bit unintuitive since many other `get_*` style functions conventionally return `nil` if no object is found (e.g. `get_node`, `get_lang`, `query.get`, etc.) **Solution:** Return `nil` if no parser can be found or created - This requires a function signature change, and some new assertions in places where the parser will always (or should always) be found. - This commit starts by making this change internally, since it is breaking. Eventually it will be rolled out to the public API. --- test/functional/treesitter/language_spec.lua | 8 ++++++-- test/functional/treesitter/parser_spec.lua | 4 +--- 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'test/functional') diff --git a/test/functional/treesitter/language_spec.lua b/test/functional/treesitter/language_spec.lua index 6c211049f0..b9934a2e5f 100644 --- a/test/functional/treesitter/language_spec.lua +++ b/test/functional/treesitter/language_spec.lua @@ -8,6 +8,7 @@ local exec_lua = n.exec_lua local pcall_err = t.pcall_err local matches = t.matches local insert = n.insert +local NIL = vim.NIL before_each(clear) @@ -15,10 +16,12 @@ describe('treesitter language API', function() -- error tests not requiring a parser library it('handles missing language', function() eq( - ".../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers", + '.../treesitter.lua:0: Parser not found.', pcall_err(exec_lua, "parser = vim.treesitter.get_parser(0, 'borklang')") ) + eq(NIL, exec_lua("return vim.treesitter._get_parser(0, 'borklang')")) + -- actual message depends on platform matches( "Failed to load parser for language 'borklang': uv_dlopen: .+", @@ -105,9 +108,10 @@ describe('treesitter language API', function() command('set filetype=borklang') -- Should throw an error when filetype changes to borklang eq( - ".../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers", + '.../treesitter.lua:0: Parser not found.', pcall_err(exec_lua, "new_parser = vim.treesitter.get_parser(0, 'borklang')") ) + eq(NIL, exec_lua("return vim.treesitter._get_parser(0, 'borklang')")) end ) diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua index 4aa8beebae..61af007782 100644 --- a/test/functional/treesitter/parser_spec.lua +++ b/test/functional/treesitter/parser_spec.lua @@ -135,9 +135,7 @@ void ui_refresh(void) insert(test_text) eq( - '.../treesitter.lua:0: There is no parser available for buffer 1 and one' - .. ' could not be created because lang could not be determined. Either' - .. ' pass lang or set the buffer filetype', + '.../treesitter.lua:0: Parser not found.', pcall_err(exec_lua, 'vim.treesitter.get_parser(0)') ) -- cgit From 90585e47feb7b4c4d878ad32480e2fc09744a7ed Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 14 Sep 2024 19:20:56 +0800 Subject: vim-patch:9.1.0729: Wrong cursor-screenline when resizing window Problem: Wrong cursor-screenline when resizing window Solution: Invalidate saved left_col and right_col when width1 or width2 change. closes: vim/vim#15679 https://github.com/vim/vim/commit/86dc4f8b432233a01d022c3e71df53db58229713 --- test/functional/ui/highlight_spec.lua | 38 +++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'test/functional') diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua index b7b46ddfae..277bd96bd8 100644 --- a/test/functional/ui/highlight_spec.lua +++ b/test/functional/ui/highlight_spec.lua @@ -1078,6 +1078,44 @@ describe('CursorLine and CursorLineNr highlights', function() ]]) end) + -- oldtest: Test_cursorline_screenline_resize() + it("'cursorlineopt' screenline is updated on window resize", function() + local screen = Screen.new(75, 8) + screen:attach() + exec([[ + 50vnew + call setline(1, repeat('xyz ', 30)) + setlocal number cursorline cursorlineopt=screenline + normal! $ + ]]) + screen:expect([[ + {8: 1 }xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz xy│ | + {8: }z xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz │{1:~ }| + {8: }{21:xyz xyz xyz xyz xyz xyz xyz^ }│{1:~ }| + {1:~ }│{1:~ }|*3 + {3:[No Name] [+] }{2:[No Name] }| + | + ]]) + command('vertical resize -4') + screen:expect([[ + {8: 1 }xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz xy│ | + {8: }z xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz │{1:~ }| + {8: }{21:xyz xyz xyz xyz xyz xyz xyz xyz xyz^ }│{1:~ }| + {1:~ }│{1:~ }|*3 + {3:[No Name] [+] }{2:[No Name] }| + | + ]]) + command('set cpoptions+=n') + screen:expect([[ + {8: 1 }xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz xy│ | + z xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz │{1:~ }| + {21:xyz xyz xyz xyz xyz xyz xyz xyz^ }│{1:~ }| + {1:~ }│{1:~ }|*3 + {3:[No Name] [+] }{2:[No Name] }| + | + ]]) + end) + -- oldtest: Test_cursorline_after_yank() it('always updated. vim-patch:8.1.0849', function() local screen = Screen.new(50, 5) -- cgit From 5792546777332361a9ac49107e46149c703de90e Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 15 Sep 2024 03:28:14 -0700 Subject: refactor(tests): rename terminal/testutil.lua => testterm.lua #30372 This module is generally used by any tests that need the full Nvim TUI instead of `screen.lua`. Thus it should live in `functional/` instead of in `functional/terminal/`. --- test/functional/autocmd/focus_spec.lua | 2 +- test/functional/autocmd/termxx_spec.lua | 4 +- test/functional/core/job_spec.lua | 2 +- test/functional/core/log_spec.lua | 2 +- test/functional/terminal/altscreen_spec.lua | 4 +- test/functional/terminal/api_spec.lua | 2 +- test/functional/terminal/buffer_spec.lua | 6 +- test/functional/terminal/cursor_spec.lua | 4 +- test/functional/terminal/highlight_spec.lua | 2 +- test/functional/terminal/mouse_spec.lua | 4 +- test/functional/terminal/scrollback_spec.lua | 16 +- test/functional/terminal/testutil.lua | 196 -------------------- test/functional/terminal/tui_spec.lua | 4 +- test/functional/terminal/window_spec.lua | 6 +- test/functional/terminal/window_split_tab_spec.lua | 4 +- test/functional/testnvim.lua | 3 + test/functional/testterm.lua | 200 +++++++++++++++++++++ test/functional/ui/hlstate_spec.lua | 2 +- test/functional/ui/output_spec.lua | 2 +- 19 files changed, 236 insertions(+), 229 deletions(-) delete mode 100644 test/functional/terminal/testutil.lua create mode 100644 test/functional/testterm.lua (limited to 'test/functional') diff --git a/test/functional/autocmd/focus_spec.lua b/test/functional/autocmd/focus_spec.lua index 5163b576db..7f6092bf48 100644 --- a/test/functional/autocmd/focus_spec.lua +++ b/test/functional/autocmd/focus_spec.lua @@ -1,6 +1,6 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() -local tt = require('test.functional.terminal.testutil') +local tt = require('test.functional.testterm') local clear = n.clear local feed_command = n.feed_command diff --git a/test/functional/autocmd/termxx_spec.lua b/test/functional/autocmd/termxx_spec.lua index a63996ae36..64f16cf779 100644 --- a/test/functional/autocmd/termxx_spec.lua +++ b/test/functional/autocmd/termxx_spec.lua @@ -1,6 +1,6 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() -local tt = require('test.functional.terminal.testutil') +local tt = require('test.functional.testterm') local uv = vim.uv local clear, command, testprg = n.clear, n.command, n.testprg @@ -199,7 +199,7 @@ end) describe('autocmd TextChangedT', function() clear() - local screen = tt.screen_setup() + local screen = tt.setup_screen() it('works', function() command('autocmd TextChangedT * ++once let g:called = 1') diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua index bf10033f53..68ac0a50f6 100644 --- a/test/functional/core/job_spec.lua +++ b/test/functional/core/job_spec.lua @@ -1,7 +1,7 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') -local tt = require('test.functional.terminal.testutil') +local tt = require('test.functional.testterm') local clear = n.clear local eq = t.eq diff --git a/test/functional/core/log_spec.lua b/test/functional/core/log_spec.lua index 03beedbfd3..a952730779 100644 --- a/test/functional/core/log_spec.lua +++ b/test/functional/core/log_spec.lua @@ -1,6 +1,6 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() -local tt = require('test.functional.terminal.testutil') +local tt = require('test.functional.testterm') local assert_log = t.assert_log local clear = n.clear diff --git a/test/functional/terminal/altscreen_spec.lua b/test/functional/terminal/altscreen_spec.lua index 12c8615799..4a61e0203d 100644 --- a/test/functional/terminal/altscreen_spec.lua +++ b/test/functional/terminal/altscreen_spec.lua @@ -1,7 +1,7 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() -local tt = require('test.functional.terminal.testutil') +local tt = require('test.functional.testterm') local clear, eq, api = n.clear, t.eq, n.api local feed = n.feed local feed_data = tt.feed_data @@ -17,7 +17,7 @@ describe(':terminal altscreen', function() before_each(function() clear() - screen = tt.screen_setup() + screen = tt.setup_screen() feed_data({ 'line1', 'line2', diff --git a/test/functional/terminal/api_spec.lua b/test/functional/terminal/api_spec.lua index 1f10dda551..b550df80c3 100644 --- a/test/functional/terminal/api_spec.lua +++ b/test/functional/terminal/api_spec.lua @@ -1,7 +1,7 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() -local tt = require('test.functional.terminal.testutil') +local tt = require('test.functional.testterm') local ok = t.ok if t.skip(t.is_os('win')) then diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua index 888c4538af..7a30367917 100644 --- a/test/functional/terminal/buffer_spec.lua +++ b/test/functional/terminal/buffer_spec.lua @@ -1,7 +1,7 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') -local tt = require('test.functional.terminal.testutil') +local tt = require('test.functional.testterm') local assert_alive = n.assert_alive local feed, clear = n.feed, n.clear @@ -29,7 +29,7 @@ describe(':terminal buffer', function() before_each(function() clear() command('set modifiable swapfile undolevels=20') - screen = tt.screen_setup() + screen = tt.setup_screen() end) it('terminal-mode forces various options', function() @@ -574,7 +574,7 @@ if is_os('win') then feed_command('set modifiable swapfile undolevels=20') poke_eventloop() local cmd = { 'cmd.exe', '/K', 'PROMPT=$g$s' } - screen = tt.screen_setup(nil, cmd) + screen = tt.setup_screen(nil, cmd) end) it('"put" operator sends data normally', function() diff --git a/test/functional/terminal/cursor_spec.lua b/test/functional/terminal/cursor_spec.lua index 51c6b12e62..0c5de45829 100644 --- a/test/functional/terminal/cursor_spec.lua +++ b/test/functional/terminal/cursor_spec.lua @@ -1,7 +1,7 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') -local tt = require('test.functional.terminal.testutil') +local tt = require('test.functional.testterm') local feed, clear = n.feed, n.clear local testprg, command = n.testprg, n.command @@ -18,7 +18,7 @@ describe(':terminal cursor', function() before_each(function() clear() - screen = tt.screen_setup() + screen = tt.setup_screen() end) it('moves the screen cursor when focused', function() diff --git a/test/functional/terminal/highlight_spec.lua b/test/functional/terminal/highlight_spec.lua index ca41cbf4a2..05d68f6754 100644 --- a/test/functional/terminal/highlight_spec.lua +++ b/test/functional/terminal/highlight_spec.lua @@ -1,7 +1,7 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') -local tt = require('test.functional.terminal.testutil') +local tt = require('test.functional.testterm') local feed, clear = n.feed, n.clear local api = n.api diff --git a/test/functional/terminal/mouse_spec.lua b/test/functional/terminal/mouse_spec.lua index 476e2a5fe5..38d6b83417 100644 --- a/test/functional/terminal/mouse_spec.lua +++ b/test/functional/terminal/mouse_spec.lua @@ -1,7 +1,7 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() -local tt = require('test.functional.terminal.testutil') +local tt = require('test.functional.testterm') local clear, eq, eval = n.clear, t.eq, n.eval local feed, api, command = n.feed, n.api, n.command local feed_data = tt.feed_data @@ -14,7 +14,7 @@ describe(':terminal mouse', function() before_each(function() clear() api.nvim_set_option_value('statusline', '==========', {}) - screen = tt.screen_setup() + screen = tt.setup_screen() command('highlight StatusLine NONE') command('highlight StatusLineNC NONE') command('highlight StatusLineTerm NONE') diff --git a/test/functional/terminal/scrollback_spec.lua b/test/functional/terminal/scrollback_spec.lua index 229a169996..da0bd97270 100644 --- a/test/functional/terminal/scrollback_spec.lua +++ b/test/functional/terminal/scrollback_spec.lua @@ -1,7 +1,7 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') -local tt = require('test.functional.terminal.testutil') +local tt = require('test.functional.testterm') local clear, eq = n.clear, t.eq local feed, testprg = n.feed, n.testprg @@ -22,7 +22,7 @@ describe(':terminal scrollback', function() before_each(function() clear() - screen = tt.screen_setup(nil, nil, 30) + screen = tt.setup_screen(nil, nil, 30) end) describe('when the limit is exceeded', function() @@ -399,9 +399,9 @@ describe("'scrollback' option", function() it('set to 0 behaves as 1', function() local screen if is_os('win') then - screen = tt.screen_setup(nil, { 'cmd.exe' }, 30) + screen = tt.setup_screen(nil, { 'cmd.exe' }, 30) else - screen = tt.screen_setup(nil, { 'sh' }, 30) + screen = tt.setup_screen(nil, { 'sh' }, 30) end api.nvim_set_option_value('scrollback', 0, {}) @@ -416,10 +416,10 @@ describe("'scrollback' option", function() local screen if is_os('win') then command([[let $PROMPT='$$']]) - screen = tt.screen_setup(nil, { 'cmd.exe' }, 30) + screen = tt.setup_screen(nil, { 'cmd.exe' }, 30) else command('let $PS1 = "$"') - screen = tt.screen_setup(nil, { 'sh' }, 30) + screen = tt.setup_screen(nil, { 'sh' }, 30) end api.nvim_set_option_value('scrollback', 200, {}) @@ -480,8 +480,8 @@ describe("'scrollback' option", function() end) it('deletes extra lines immediately', function() - -- Scrollback is 10 on screen_setup - local screen = tt.screen_setup(nil, nil, 30) + -- Scrollback is 10 on setup_screen + local screen = tt.setup_screen(nil, nil, 30) local lines = {} for i = 1, 30 do table.insert(lines, 'line' .. tostring(i)) diff --git a/test/functional/terminal/testutil.lua b/test/functional/terminal/testutil.lua deleted file mode 100644 index 7eb4af4940..0000000000 --- a/test/functional/terminal/testutil.lua +++ /dev/null @@ -1,196 +0,0 @@ --- To test tui/input.c, this module spawns `nvim` inside :terminal and sends --- bytes via jobsend(). Note: the functional/testutil.lua test-session methods --- operate on the _host_ session, _not_ the child session. -local n = require('test.functional.testnvim')() -local Screen = require('test.functional.ui.screen') - -local testprg = n.testprg -local exec_lua = n.exec_lua -local api = n.api -local nvim_prog = n.nvim_prog - -local function feed_data(data) - if type(data) == 'table' then - data = table.concat(data, '\n') - end - exec_lua('vim.api.nvim_chan_send(vim.b.terminal_job_id, ...)', data) -end - -local function feed_termcode(data) - feed_data('\027' .. data) -end - -local function make_lua_executor(session) - return function(code, ...) - local status, rv = session:request('nvim_exec_lua', code, { ... }) - if not status then - session:stop() - error(rv[2]) - end - return rv - end -end - --- some t for controlling the terminal. the codes were taken from --- infocmp xterm-256color which is less what libvterm understands --- civis/cnorm -local function hide_cursor() - feed_termcode('[?25l') -end -local function show_cursor() - feed_termcode('[?25h') -end --- smcup/rmcup -local function enter_altscreen() - feed_termcode('[?1049h') -end -local function exit_altscreen() - feed_termcode('[?1049l') -end --- character attributes -local function set_fg(num) - feed_termcode('[38;5;' .. num .. 'm') -end -local function set_bg(num) - feed_termcode('[48;5;' .. num .. 'm') -end -local function set_bold() - feed_termcode('[1m') -end -local function set_italic() - feed_termcode('[3m') -end -local function set_underline() - feed_termcode('[4m') -end -local function set_underdouble() - feed_termcode('[4:2m') -end -local function set_undercurl() - feed_termcode('[4:3m') -end -local function set_strikethrough() - feed_termcode('[9m') -end -local function clear_attrs() - feed_termcode('[0;10m') -end --- mouse -local function enable_mouse() - feed_termcode('[?1002h') -end -local function disable_mouse() - feed_termcode('[?1002l') -end - -local default_command = { testprg('tty-test') } - -local function screen_setup(extra_rows, command, cols, env, screen_opts) - extra_rows = extra_rows and extra_rows or 0 - command = command and command or default_command - cols = cols and cols or 50 - - api.nvim_command('highlight TermCursor cterm=reverse') - api.nvim_command('highlight TermCursorNC ctermbg=11') - api.nvim_command('highlight StatusLineTerm ctermbg=2 ctermfg=0') - api.nvim_command('highlight StatusLineTermNC ctermbg=2 ctermfg=8') - - local screen = Screen.new(cols, 7 + extra_rows) - screen:set_default_attr_ids({ - [1] = { reverse = true }, -- focused cursor - [2] = { background = 11 }, -- unfocused cursor - [3] = { bold = true }, - [4] = { foreground = 12 }, -- NonText in :terminal session - [5] = { bold = true, reverse = true }, - [6] = { foreground = 81 }, -- SpecialKey in :terminal session - [7] = { foreground = 130 }, -- LineNr in host session - [8] = { foreground = 15, background = 1 }, -- ErrorMsg in :terminal session - [9] = { foreground = 4 }, - [10] = { foreground = 121 }, -- MoreMsg in :terminal session - [11] = { foreground = 11 }, -- LineNr in :terminal session - [12] = { underline = true }, - [13] = { underline = true, reverse = true }, - [14] = { underline = true, reverse = true, bold = true }, - [15] = { underline = true, foreground = 12 }, - [16] = { background = 248, foreground = 0 }, -- Visual in :terminal session - [17] = { background = 2, foreground = 0 }, -- StatusLineTerm - [18] = { background = 2, foreground = 8 }, -- StatusLineTermNC - }) - - screen:attach(screen_opts or { rgb = false }) - - api.nvim_command('enew') - api.nvim_call_function('termopen', { command, env and { env = env } or nil }) - api.nvim_input('') - local vim_errmsg = api.nvim_eval('v:errmsg') - if vim_errmsg and '' ~= vim_errmsg then - error(vim_errmsg) - end - - api.nvim_command('setlocal scrollback=10') - api.nvim_command('startinsert') - api.nvim_input('') -- Add input to separate two RPC requests - - -- tty-test puts the terminal into raw mode and echoes input. Tests work by - -- feeding termcodes to control the display and asserting by screen:expect. - if command == default_command and screen_opts == nil then - -- Wait for "tty ready" to be printed before each test or the terminal may - -- still be in canonical mode (will echo characters for example). - local empty_line = (' '):rep(cols) - local expected = { - 'tty ready' .. (' '):rep(cols - 9), - '{1: }' .. (' '):rep(cols - 1), - empty_line, - empty_line, - empty_line, - empty_line, - } - for _ = 1, extra_rows do - table.insert(expected, empty_line) - end - - table.insert(expected, '{3:-- TERMINAL --}' .. ((' '):rep(cols - 14))) - screen:expect(table.concat(expected, '|\n') .. '|') - else - -- This eval also acts as a poke_eventloop(). - if 0 == api.nvim_eval("exists('b:terminal_job_id')") then - error('terminal job failed to start') - end - end - return screen -end - -local function setup_child_nvim(args, opts) - opts = opts or {} - local argv = { nvim_prog, unpack(args) } - - local env = opts.env or {} - if not env.VIMRUNTIME then - env.VIMRUNTIME = os.getenv('VIMRUNTIME') - end - - return screen_setup(opts.extra_rows, argv, opts.cols, env) -end - -return { - feed_data = feed_data, - feed_termcode = feed_termcode, - make_lua_executor = make_lua_executor, - hide_cursor = hide_cursor, - show_cursor = show_cursor, - enter_altscreen = enter_altscreen, - exit_altscreen = exit_altscreen, - set_fg = set_fg, - set_bg = set_bg, - set_bold = set_bold, - set_italic = set_italic, - set_underline = set_underline, - set_underdouble = set_underdouble, - set_undercurl = set_undercurl, - set_strikethrough = set_strikethrough, - clear_attrs = clear_attrs, - enable_mouse = enable_mouse, - disable_mouse = disable_mouse, - screen_setup = screen_setup, - setup_child_nvim = setup_child_nvim, -} diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index bba1436bdc..6375e6fbae 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -7,7 +7,7 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') -local tt = require('test.functional.terminal.testutil') +local tt = require('test.functional.testterm') local eq = t.eq local feed_data = tt.feed_data @@ -2111,7 +2111,7 @@ describe('TUI', function() finally(function() os.remove('testF') end) - local screen = tt.screen_setup( + local screen = tt.setup_screen( 0, ('"%s" -u NONE -i NONE --cmd "set noswapfile noshowcmd noruler" --cmd "normal iabc" > /dev/null 2>&1 && cat testF && rm testF'):format( nvim_prog diff --git a/test/functional/terminal/window_spec.lua b/test/functional/terminal/window_spec.lua index 18477fdf2d..f97bfd0a2f 100644 --- a/test/functional/terminal/window_spec.lua +++ b/test/functional/terminal/window_spec.lua @@ -1,7 +1,7 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() -local tt = require('test.functional.terminal.testutil') +local tt = require('test.functional.testterm') local feed_data = tt.feed_data local feed, clear = n.feed, n.clear local poke_eventloop = n.poke_eventloop @@ -37,7 +37,7 @@ describe(':terminal window', function() before_each(function() clear() - screen = tt.screen_setup() + screen = tt.setup_screen() end) it('sets topline correctly #8556', function() @@ -198,7 +198,7 @@ describe(':terminal with multigrid', function() before_each(function() clear() - screen = tt.screen_setup(0, nil, 50, nil, { ext_multigrid = true }) + screen = tt.setup_screen(0, nil, 50, nil, { ext_multigrid = true }) end) it('resizes to requested size', function() diff --git a/test/functional/terminal/window_split_tab_spec.lua b/test/functional/terminal/window_split_tab_spec.lua index ccd6a5218b..e9218e9a3b 100644 --- a/test/functional/terminal/window_split_tab_spec.lua +++ b/test/functional/terminal/window_split_tab_spec.lua @@ -1,7 +1,7 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() -local tt = require('test.functional.terminal.testutil') +local tt = require('test.functional.testterm') local assert_alive = n.assert_alive local clear = n.clear local feed = n.feed @@ -22,7 +22,7 @@ describe(':terminal', function() -- set the statusline to a constant value because of variables like pid -- and current directory and to improve visibility of splits api.nvim_set_option_value('statusline', '==========', {}) - screen = tt.screen_setup(3) + screen = tt.setup_screen(3) command('highlight StatusLine NONE') command('highlight StatusLineNC NONE') command('highlight StatusLineTerm NONE') diff --git a/test/functional/testnvim.lua b/test/functional/testnvim.lua index 8c8b239cd8..a66f0cd52c 100644 --- a/test/functional/testnvim.lua +++ b/test/functional/testnvim.lua @@ -250,6 +250,8 @@ function M.set_method_error(err) method_error = err end +--- Runs the event loop of the given session. +--- --- @param lsession test.Session --- @param request_cb function? --- @param notification_cb function? @@ -296,6 +298,7 @@ function M.run_session(lsession, request_cb, notification_cb, setup_cb, timeout) return lsession.eof_err end +--- Runs the event loop of the current global session. function M.run(request_cb, notification_cb, setup_cb, timeout) assert(session) return M.run_session(session, request_cb, notification_cb, setup_cb, timeout) diff --git a/test/functional/testterm.lua b/test/functional/testterm.lua new file mode 100644 index 0000000000..e46ae0793c --- /dev/null +++ b/test/functional/testterm.lua @@ -0,0 +1,200 @@ +-- Functions to test :terminal and the Nvim TUI. +-- Starts a child process in a `:terminal` and sends bytes to the child via nvim_chan_send(). +-- Note: the global functional/testutil.lua test-session is _host_ session, _not_ +-- the child session. +-- +-- - Use `setup_screen()` to test `:terminal` behavior with an arbitrary command. +-- - Use `setup_child_nvim()` to test the Nvim TUI. +-- - NOTE: Only use this if your test actually needs the full lifecycle/capabilities of the +-- builtin Nvim TUI. Most tests should just use `Screen.new()` directly, or plain old API calls. + +local n = require('test.functional.testnvim')() +local Screen = require('test.functional.ui.screen') + +local testprg = n.testprg +local exec_lua = n.exec_lua +local api = n.api +local nvim_prog = n.nvim_prog + +local M = {} + +function M.feed_data(data) + if type(data) == 'table' then + data = table.concat(data, '\n') + end + exec_lua('vim.api.nvim_chan_send(vim.b.terminal_job_id, ...)', data) +end + +function M.feed_termcode(data) + M.feed_data('\027' .. data) +end + +function M.make_lua_executor(session) + return function(code, ...) + local status, rv = session:request('nvim_exec_lua', code, { ... }) + if not status then + session:stop() + error(rv[2]) + end + return rv + end +end + +-- some t for controlling the terminal. the codes were taken from +-- infocmp xterm-256color which is less what libvterm understands +-- civis/cnorm +function M.hide_cursor() + M.feed_termcode('[?25l') +end +function M.show_cursor() + M.feed_termcode('[?25h') +end +-- smcup/rmcup +function M.enter_altscreen() + M.feed_termcode('[?1049h') +end +function M.exit_altscreen() + M.feed_termcode('[?1049l') +end +-- character attributes +function M.set_fg(num) + M.feed_termcode('[38;5;' .. num .. 'm') +end +function M.set_bg(num) + M.feed_termcode('[48;5;' .. num .. 'm') +end +function M.set_bold() + M.feed_termcode('[1m') +end +function M.set_italic() + M.feed_termcode('[3m') +end +function M.set_underline() + M.feed_termcode('[4m') +end +function M.set_underdouble() + M.feed_termcode('[4:2m') +end +function M.set_undercurl() + M.feed_termcode('[4:3m') +end +function M.set_strikethrough() + M.feed_termcode('[9m') +end +function M.clear_attrs() + M.feed_termcode('[0;10m') +end +-- mouse +function M.enable_mouse() + M.feed_termcode('[?1002h') +end +function M.disable_mouse() + M.feed_termcode('[?1002l') +end + +local default_command = { testprg('tty-test') } + +--- Runs `cmd` in a :terminal, and returns a `Screen` object. +--- +---@param extra_rows? integer Extra rows to add to the default screen. +---@param cmd? string|string[] Command to run in the terminal (default: `{ 'tty-test' }`) +---@param cols? integer Create screen with this many columns (default: 50) +---@param env? table Environment set on the `cmd` job. +---@param screen_opts? table Options for `Screen.new()`. +---@return test.functional.ui.screen # Screen attached to the global (not child) Nvim session. +function M.setup_screen(extra_rows, cmd, cols, env, screen_opts) + extra_rows = extra_rows and extra_rows or 0 + cmd = cmd and cmd or default_command + cols = cols and cols or 50 + + api.nvim_command('highlight TermCursor cterm=reverse') + api.nvim_command('highlight TermCursorNC ctermbg=11') + api.nvim_command('highlight StatusLineTerm ctermbg=2 ctermfg=0') + api.nvim_command('highlight StatusLineTermNC ctermbg=2 ctermfg=8') + + local screen = Screen.new(cols, 7 + extra_rows) + screen:set_default_attr_ids({ + [1] = { reverse = true }, -- focused cursor + [2] = { background = 11 }, -- unfocused cursor + [3] = { bold = true }, + [4] = { foreground = 12 }, -- NonText in :terminal session + [5] = { bold = true, reverse = true }, + [6] = { foreground = 81 }, -- SpecialKey in :terminal session + [7] = { foreground = 130 }, -- LineNr in host session + [8] = { foreground = 15, background = 1 }, -- ErrorMsg in :terminal session + [9] = { foreground = 4 }, + [10] = { foreground = 121 }, -- MoreMsg in :terminal session + [11] = { foreground = 11 }, -- LineNr in :terminal session + [12] = { underline = true }, + [13] = { underline = true, reverse = true }, + [14] = { underline = true, reverse = true, bold = true }, + [15] = { underline = true, foreground = 12 }, + [16] = { background = 248, foreground = 0 }, -- Visual in :terminal session + [17] = { background = 2, foreground = 0 }, -- StatusLineTerm + [18] = { background = 2, foreground = 8 }, -- StatusLineTermNC + }) + + screen:attach(screen_opts or { rgb = false }) + + api.nvim_command('enew') + api.nvim_call_function('termopen', { cmd, env and { env = env } or nil }) + api.nvim_input('') + local vim_errmsg = api.nvim_eval('v:errmsg') + if vim_errmsg and '' ~= vim_errmsg then + error(vim_errmsg) + end + + api.nvim_command('setlocal scrollback=10') + api.nvim_command('startinsert') + api.nvim_input('') -- Add input to separate two RPC requests + + -- tty-test puts the terminal into raw mode and echoes input. Tests work by + -- feeding termcodes to control the display and asserting by screen:expect. + if cmd == default_command and screen_opts == nil then + -- Wait for "tty ready" to be printed before each test or the terminal may + -- still be in canonical mode (will echo characters for example). + local empty_line = (' '):rep(cols) + local expected = { + 'tty ready' .. (' '):rep(cols - 9), + '{1: }' .. (' '):rep(cols - 1), + empty_line, + empty_line, + empty_line, + empty_line, + } + for _ = 1, extra_rows do + table.insert(expected, empty_line) + end + + table.insert(expected, '{3:-- TERMINAL --}' .. ((' '):rep(cols - 14))) + screen:expect(table.concat(expected, '|\n') .. '|') + else + -- This eval also acts as a poke_eventloop(). + if 0 == api.nvim_eval("exists('b:terminal_job_id')") then + error('terminal job failed to start') + end + end + return screen +end + +--- Spawns Nvim with `args` in a :terminal, and returns a `Screen` object. +--- +--- @note Only use this if you actually need the full lifecycle/capabilities of the builtin Nvim +--- TUI. Most tests should just use `Screen.new()` directly, or plain old API calls. +--- +---@param args? string[] Args passed to child Nvim. +---@param opts? table Options +---@return test.functional.ui.screen # Screen attached to the global (not child) Nvim session. +function M.setup_child_nvim(args, opts) + opts = opts or {} + local argv = { nvim_prog, unpack(args or {}) } + + local env = opts.env or {} + if not env.VIMRUNTIME then + env.VIMRUNTIME = os.getenv('VIMRUNTIME') + end + + return M.setup_screen(opts.extra_rows, argv, opts.cols, env) +end + +return M diff --git a/test/functional/ui/hlstate_spec.lua b/test/functional/ui/hlstate_spec.lua index 8d14c9f73d..a255047ed7 100644 --- a/test/functional/ui/hlstate_spec.lua +++ b/test/functional/ui/hlstate_spec.lua @@ -1,7 +1,7 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') -local tt = require('test.functional.terminal.testutil') +local tt = require('test.functional.testterm') local clear, insert = n.clear, n.insert local command = n.command diff --git a/test/functional/ui/output_spec.lua b/test/functional/ui/output_spec.lua index 4f6454a0fb..220af06f53 100644 --- a/test/functional/ui/output_spec.lua +++ b/test/functional/ui/output_spec.lua @@ -1,7 +1,7 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') -local tt = require('test.functional.terminal.testutil') +local tt = require('test.functional.testterm') local assert_alive = n.assert_alive local mkdir, write_file, rmdir = t.mkdir, t.write_file, n.rmdir -- cgit From 23dcd7cd73dc19212befcdbbc06ddf80db082ec4 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Mon, 16 Sep 2024 11:44:56 +0200 Subject: test(vim.ui.open): opt.cmd --- test/functional/lua/ui_spec.lua | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'test/functional') diff --git a/test/functional/lua/ui_spec.lua b/test/functional/lua/ui_spec.lua index d69e893c96..d5eede2885 100644 --- a/test/functional/lua/ui_spec.lua +++ b/test/functional/lua/ui_spec.lua @@ -157,5 +157,28 @@ describe('vim.ui', function() exec_lua [[local _, err = vim.ui.open('foo') ; return err]] ) end) + + it('opt.cmd #29490', function() + t.matches( + 'ENOENT: no such file or directory', + t.pcall_err(exec_lua, function() + vim.ui.open('foo', { cmd = { 'non-existent-tool' } }) + end) + ) + + eq( + { + code = 0, + signal = 0, + stderr = '', + stdout = 'arg1=arg1;arg2=https://example.com;', + }, + exec_lua(function(cmd_) + local cmd, err = vim.ui.open('https://example.com', { cmd = cmd_ }) + assert(cmd and not err) + return cmd:wait() + end, { n.testprg('printargs-test'), 'arg1' }) + ) + end) end) end) -- cgit From ff85e54939b0aca34a779a2b6381d09db1858b29 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Wed, 18 Sep 2024 04:14:06 -0700 Subject: feat(tui): builtin UI (TUI) sets client info #30397 Problem: The default builtin UI client does not declare its client info. This reduces discoverability and makes it difficult for plugins to identify the UI. Solution: - Call nvim_set_client_info after attaching, as recommended by `:help dev-ui`. - Also set the "pid" field. - Also change `ui_active()` to return a count. Not directly relevant to this commit, but will be useful later. --- test/functional/terminal/tui_spec.lua | 46 ++++++++++++++++++++++++++++++++--- test/functional/testnvim.lua | 2 +- 2 files changed, 43 insertions(+), 5 deletions(-) (limited to 'test/functional') diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 6375e6fbae..3e837e796d 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -40,8 +40,8 @@ if t.skip(is_os('win')) then end describe('TUI', function() - local screen - local child_session + local screen --[[@type test.functional.ui.screen]] + local child_session --[[@type test.Session]] local child_exec_lua before_each(function() @@ -1651,12 +1651,13 @@ describe('TUI', function() ]]) end) - it('in nvim_list_uis()', function() + it('in nvim_list_uis(), sets nvim_set_client_info()', function() -- $TERM in :terminal. local exp_term = is_os('bsd') and 'builtin_xterm' or 'xterm-256color' + local ui_chan = 1 local expected = { { - chan = 1, + chan = ui_chan, ext_cmdline = false, ext_hlstate = false, ext_linegrid = true, @@ -1679,6 +1680,43 @@ describe('TUI', function() } local _, rv = child_session:request('nvim_list_uis') eq(expected, rv) + + ---@type table + local expected_version = ({ + child_session:request('nvim_exec_lua', 'return vim.version()', {}), + })[2] + -- vim.version() returns `prerelease` string. Coerce it to boolean. + expected_version.prerelease = not not expected_version.prerelease + + local expected_chan_info = { + client = { + attributes = { + license = 'Apache 2', + -- pid = 5371, + website = 'https://neovim.io', + }, + methods = {}, + name = 'nvim-tui', + type = 'ui', + version = expected_version, + }, + id = ui_chan, + mode = 'rpc', + stream = 'stdio', + } + + local status, chan_info = child_session:request('nvim_get_chan_info', ui_chan) + ok(status) + local info = chan_info.client + ok(info.attributes.pid and info.attributes.pid > 0, 'PID', info.attributes.pid or 'nil') + ok(info.version.major >= 0) + ok(info.version.minor >= 0) + ok(info.version.patch >= 0) + + -- Delete variable fields so we can deep-compare. + info.attributes.pid = nil + + eq(expected_chan_info, chan_info) end) it('allows grid to assume wider ambiwidth chars than host terminal', function() diff --git a/test/functional/testnvim.lua b/test/functional/testnvim.lua index a66f0cd52c..ac2ec89271 100644 --- a/test/functional/testnvim.lua +++ b/test/functional/testnvim.lua @@ -458,7 +458,7 @@ end --- @param argv string[] --- @param merge boolean? --- @param env string[]? ---- @param keep boolean +--- @param keep boolean? --- @param io_extra uv.uv_pipe_t? used for stdin_fd, see :help ui-option --- @return test.Session function M.spawn(argv, merge, env, keep, io_extra) -- cgit From 7dbbaaec3fae62667b273c4c2d362bee91316083 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 19 Sep 2024 18:05:27 +0800 Subject: refactor!: rename 'jumpoptions' flag "unload" to "clean" (#30418) Follow-up to #29347 --- test/functional/editor/jump_spec.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'test/functional') diff --git a/test/functional/editor/jump_spec.lua b/test/functional/editor/jump_spec.lua index 6d2f75e7c5..ab4cefaf84 100644 --- a/test/functional/editor/jump_spec.lua +++ b/test/functional/editor/jump_spec.lua @@ -194,7 +194,7 @@ describe("jumpoptions=stack behaves like 'tagstack'", function() end) end) -describe('buffer deletion with jumpoptions+=unload', function() +describe('buffer deletion with jumpoptions+=clean', function() local base_file = 'Xtest-functional-buffer-deletion' local file1 = base_file .. '1' local file2 = base_file .. '2' @@ -325,7 +325,7 @@ describe('buffer deletion with jumpoptions+=unload', function() end) end) -describe('buffer deletion with jumpoptions-=unload', function() +describe('buffer deletion with jumpoptions-=clean', function() local base_file = 'Xtest-functional-buffer-deletion' local file1 = base_file .. '1' local file2 = base_file .. '2' @@ -336,7 +336,7 @@ describe('buffer deletion with jumpoptions-=unload', function() before_each(function() clear() command('clearjumps') - command('set jumpoptions-=unload') + command('set jumpoptions-=clean') write_file(file1, content1, false, false) write_file(file2, content2, false, false) -- cgit From f01c764cc6f82399edfa0d47a7bafbf7c95e2747 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 20 Sep 2024 06:59:46 +0800 Subject: vim-patch:35699f1: runtime(vim): Update base-syntax, improve folding function matches (#30427) - Allow function command modifiers. - Match function bodies starting with empty lines. Command modifiers reported by @Konfekt. fixes vim/vim#15671 closes: vim/vim#15674 https://github.com/vim/vim/commit/35699f17497dcdcfdd747fedaef28f208ac6eb5f Co-authored-by: Doug Kearns --- test/functional/ui/messages_spec.lua | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua index 036b5ceefc..a3e5068e55 100644 --- a/test/functional/ui/messages_spec.lua +++ b/test/functional/ui/messages_spec.lua @@ -1165,7 +1165,12 @@ describe('ui/builtin messages', function() it(':syntax list langGroup output', function() command('syntax on') - command('set syntax=vim') + exec([[ + syn match vimComment excludenl +\s"[^\-:.%#=*].*$+lc=1 contains=@vimCommentGroup,vimCommentString + syn match vimComment +\') screen:expect([[ -- cgit From e5c174421df3872df0dd3a676609d1e74dfef6a9 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Sun, 11 Aug 2024 09:27:48 +0100 Subject: test: support upvalues in exec_lua --- test/functional/lua/buffer_updates_spec.lua | 12 +- test/functional/lua/diagnostic_spec.lua | 127 ++-- test/functional/lua/ffi_spec.lua | 56 +- test/functional/lua/filetype_spec.lua | 17 +- test/functional/lua/fs_spec.lua | 34 +- test/functional/lua/glob_spec.lua | 7 +- test/functional/lua/highlight_spec.lua | 68 ++- test/functional/lua/inspector_spec.lua | 31 +- test/functional/lua/loader_spec.lua | 42 +- test/functional/lua/loop_spec.lua | 74 +-- test/functional/lua/mpack_spec.lua | 16 +- test/functional/lua/overrides_spec.lua | 16 +- test/functional/lua/system_spec.lua | 32 +- test/functional/plugin/editorconfig_spec.lua | 7 +- test/functional/plugin/lsp/codelens_spec.lua | 84 ++- test/functional/plugin/lsp/completion_spec.lua | 99 ++-- test/functional/plugin/lsp/diagnostic_spec.lua | 519 +++++++++-------- test/functional/plugin/lsp/handler_spec.lua | 23 +- .../plugin/lsp/incremental_sync_spec.lua | 47 +- test/functional/plugin/lsp/inlay_hint_spec.lua | 268 +++++---- .../functional/plugin/lsp/semantic_tokens_spec.lua | 358 ++++++------ test/functional/plugin/lsp/testutil.lua | 109 ++-- test/functional/plugin/lsp/utils_spec.lua | 47 +- test/functional/plugin/lsp_spec.lua | 641 +++++++++++++-------- test/functional/plugin/man_spec.lua | 15 +- test/functional/plugin/tohtml_spec.lua | 16 +- test/functional/testnvim.lua | 164 +++++- test/functional/treesitter/highlight_spec.lua | 54 +- test/functional/treesitter/inspect_tree_spec.lua | 8 +- test/functional/treesitter/language_spec.lua | 8 +- test/functional/treesitter/node_spec.lua | 12 +- test/functional/treesitter/parser_spec.lua | 24 +- test/functional/treesitter/query_spec.lua | 60 +- 33 files changed, 1736 insertions(+), 1359 deletions(-) (limited to 'test/functional') diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua index 8ca97c8e5e..f277868b1c 100644 --- a/test/functional/lua/buffer_updates_spec.lua +++ b/test/functional/lua/buffer_updates_spec.lua @@ -282,19 +282,19 @@ describe('lua buffer event callbacks: on_lines', function() end) it('does not SEGFAULT when accessing window buffer info in on_detach #14998', function() - local code = [[ + local code = function() local buf = vim.api.nvim_create_buf(false, false) - vim.cmd"split" + vim.cmd 'split' vim.api.nvim_win_set_buf(0, buf) vim.api.nvim_buf_attach(buf, false, { - on_detach = function(_, buf) + on_detach = function(_, buf0) vim.fn.tabpagebuflist() - vim.fn.win_findbuf(buf) - end + vim.fn.win_findbuf(buf0) + end, }) - ]] + end exec_lua(code) command('q!') diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua index 718b9469a3..4ae1146703 100644 --- a/test/functional/lua/diagnostic_spec.lua +++ b/test/functional/lua/diagnostic_spec.lua @@ -1,7 +1,6 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() -local NIL = vim.NIL local command = n.command local clear = n.clear local exec_lua = n.exec_lua @@ -175,11 +174,11 @@ describe('vim.diagnostic', function() eq(3, #result) eq( 2, - exec_lua(function(result0) + exec_lua(function() return #vim.tbl_filter(function(d) return d.bufnr == _G.diagnostic_bufnr - end, result0) - end, result) + end, result) + end) ) eq('Diagnostic #1', result[1].message) end) @@ -792,7 +791,7 @@ describe('vim.diagnostic', function() --- @return table local function test_enable(legacy) - local result = exec_lua(function(legacy0) + return exec_lua(function() local other_bufnr = vim.api.nvim_create_buf(true, false) vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) @@ -823,7 +822,7 @@ describe('vim.diagnostic', function() + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) ) - if legacy0 then + if legacy then vim.diagnostic.disable(_G.diagnostic_bufnr, _G.diagnostic_ns) else vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns }) @@ -836,7 +835,7 @@ describe('vim.diagnostic', function() + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) ) - if legacy0 then + if legacy then vim.diagnostic.disable(_G.diagnostic_bufnr, _G.other_ns) else vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr, ns_id = _G.other_ns }) @@ -849,7 +848,7 @@ describe('vim.diagnostic', function() + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) ) - if legacy0 then + if legacy then vim.diagnostic.enable(_G.diagnostic_bufnr, _G.diagnostic_ns) else vim.diagnostic.enable(true, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns }) @@ -862,7 +861,7 @@ describe('vim.diagnostic', function() + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) ) - if legacy0 then + if legacy then -- Should have no effect vim.diagnostic.disable(other_bufnr, _G.other_ns) else @@ -878,9 +877,7 @@ describe('vim.diagnostic', function() ) return result - end, legacy) - - return result + end) end it('with both buffer and namespace arguments', function() @@ -1052,7 +1049,7 @@ describe('vim.diagnostic', function() it('will not cycle when wrap is off', function() eq( - vim.NIL, + nil, exec_lua(function() vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { _G.make_error('Diagnostic #1', 1, 1, 1, 1), @@ -1261,7 +1258,7 @@ describe('vim.diagnostic', function() it('respects wrap parameter', function() eq( - vim.NIL, + nil, exec_lua(function() vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { _G.make_error('Diagnostic #2', 4, 4, 4, 4), @@ -1514,12 +1511,14 @@ describe('vim.diagnostic', function() describe('count', function() it('returns actually present severity counts', function() eq( - exec_lua [[return { - [vim.diagnostic.severity.ERROR] = 4, - [vim.diagnostic.severity.WARN] = 3, - [vim.diagnostic.severity.INFO] = 2, - [vim.diagnostic.severity.HINT] = 1, - }]], + exec_lua(function() + return { + [vim.diagnostic.severity.ERROR] = 4, + [vim.diagnostic.severity.WARN] = 3, + [vim.diagnostic.severity.INFO] = 2, + [vim.diagnostic.severity.HINT] = 1, + } + end), exec_lua(function() vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { _G.make_error('Error 1', 1, 1, 1, 2), @@ -1537,10 +1536,12 @@ describe('vim.diagnostic', function() end) ) eq( - exec_lua [[return { - [vim.diagnostic.severity.ERROR] = 2, - [vim.diagnostic.severity.INFO] = 1, - }]], + exec_lua(function() + return { + [vim.diagnostic.severity.ERROR] = 2, + [vim.diagnostic.severity.INFO] = 1, + } + end), exec_lua(function() vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { _G.make_error('Error 1', 1, 1, 1, 2), @@ -1554,11 +1555,17 @@ describe('vim.diagnostic', function() it('returns only requested diagnostics count when severity range is supplied', function() eq( - exec_lua [[return { - { [vim.diagnostic.severity.ERROR] = 1, [vim.diagnostic.severity.WARN] = 1 }, - { [vim.diagnostic.severity.WARN] = 1, [vim.diagnostic.severity.INFO] = 1, [vim.diagnostic.severity.HINT] = 1 }, - { [vim.diagnostic.severity.WARN] = 1, [vim.diagnostic.severity.INFO] = 1 }, - }]], + exec_lua(function() + return { + { [vim.diagnostic.severity.ERROR] = 1, [vim.diagnostic.severity.WARN] = 1 }, + { + [vim.diagnostic.severity.WARN] = 1, + [vim.diagnostic.severity.INFO] = 1, + [vim.diagnostic.severity.HINT] = 1, + }, + { [vim.diagnostic.severity.WARN] = 1, [vim.diagnostic.severity.INFO] = 1 }, + } + end), exec_lua(function() vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { _G.make_error('Error 1', 1, 1, 1, 5), @@ -1589,11 +1596,13 @@ describe('vim.diagnostic', function() it('returns only requested diagnostics when severities are supplied', function() eq( - exec_lua [[return { - { [vim.diagnostic.severity.WARN] = 1 }, - { [vim.diagnostic.severity.ERROR] = 1 }, - { [vim.diagnostic.severity.WARN] = 1, [vim.diagnostic.severity.INFO] = 1 }, - }]], + exec_lua(function() + return { + { [vim.diagnostic.severity.WARN] = 1 }, + { [vim.diagnostic.severity.ERROR] = 1 }, + { [vim.diagnostic.severity.WARN] = 1, [vim.diagnostic.severity.INFO] = 1 }, + } + end), exec_lua(function() vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { _G.make_error('Error 1', 1, 1, 1, 5), @@ -1624,10 +1633,12 @@ describe('vim.diagnostic', function() it('allows filtering by line', function() eq( - exec_lua [[return { - [vim.diagnostic.severity.WARN] = 1, - [vim.diagnostic.severity.INFO] = 1, - }]], + exec_lua(function() + return { + [vim.diagnostic.severity.WARN] = 1, + [vim.diagnostic.severity.INFO] = 1, + } + end), exec_lua(function() vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { _G.make_error('Error 1', 1, 1, 1, 5), @@ -1764,11 +1775,11 @@ describe('vim.diagnostic', function() it('allows filtering by severity', function() local get_extmark_count_with_severity = function(min_severity) - return exec_lua(function(min_severity0) + return exec_lua(function() vim.diagnostic.config({ underline = false, virtual_text = { - severity = { min = min_severity0 }, + severity = { min = min_severity }, }, }) @@ -1777,7 +1788,7 @@ describe('vim.diagnostic', function() }) return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) - end, min_severity) + end) end -- No messages with Error or higher @@ -2512,7 +2523,7 @@ describe('vim.diagnostic', function() -- End position is exclusive eq( - vim.NIL, + nil, exec_lua(function() local diagnostics = { _G.make_error('Syntax error', 1, 1, 2, 0), @@ -2606,7 +2617,7 @@ describe('vim.diagnostic', function() -- End position is exclusive eq( - vim.NIL, + nil, exec_lua(function() local diagnostics = { _G.make_error('Syntax error', 1, 1, 1, 3), @@ -2851,10 +2862,10 @@ describe('vim.diagnostic', function() it('can filter by severity', function() local count_diagnostics_with_severity = function(min_severity, max_severity) - return exec_lua(function(min_severity0, max_severity0) + return exec_lua(function() vim.diagnostic.config({ float = { - severity = { min = min_severity0, max = max_severity0 }, + severity = { min = min_severity, max = max_severity }, }, }) @@ -2874,7 +2885,7 @@ describe('vim.diagnostic', function() local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return #lines - end, min_severity, max_severity) + end) end eq(2, count_diagnostics_with_severity('ERROR')) @@ -3060,7 +3071,7 @@ describe('vim.diagnostic', function() -- open float failed non diagnostic lnum eq( - vim.NIL, + nil, exec_lua(function() vim.api.nvim_win_set_cursor(0, { 1, 0 }) local _, winnr = vim.diagnostic.open_float(0, { header = false }) @@ -3068,7 +3079,7 @@ describe('vim.diagnostic', function() end) ) eq( - vim.NIL, + nil, exec_lua(function() vim.api.nvim_win_set_cursor(0, { 1, 0 }) local _, winnr = vim.diagnostic.open_float(0, { header = false, scope = 'cursor' }) @@ -3180,19 +3191,19 @@ describe('vim.diagnostic', function() } eq( diagnostic, - exec_lua(function(msg0) + exec_lua(function() return vim.diagnostic.match( - msg0, + msg, '^(%w+): [^:]+:(%d+):(%d+):(.+)$', { 'severity', 'lnum', 'col', 'message' } ) - end, msg) + end) ) end) it('returns nil if the pattern fails to match', function() eq( - NIL, + nil, exec_lua(function() local msg = 'The answer to life, the universe, and everything is' return vim.diagnostic.match(msg, 'This definitely will not match', {}) @@ -3212,15 +3223,15 @@ describe('vim.diagnostic', function() } eq( diagnostic, - exec_lua(function(msg0) + exec_lua(function() return vim.diagnostic.match( - msg0, + msg, '^[^:]+:(%d+):(.+)$', { 'lnum', 'message' }, nil, { severity = vim.diagnostic.severity.INFO } ) - end, msg) + end) ) end) @@ -3236,14 +3247,14 @@ describe('vim.diagnostic', function() } eq( diagnostic, - exec_lua(function(msg0) + exec_lua(function() return vim.diagnostic.match( - msg0, + msg, '^(%d+):(%w+):(.+)$', { 'lnum', 'severity', 'message' }, { FATAL = vim.diagnostic.severity.ERROR } ) - end, msg) + end) ) end) end) diff --git a/test/functional/lua/ffi_spec.lua b/test/functional/lua/ffi_spec.lua index 85ca264107..96f5812493 100644 --- a/test/functional/lua/ffi_spec.lua +++ b/test/functional/lua/ffi_spec.lua @@ -15,27 +15,27 @@ describe('ffi.cdef', function() eq( 12, - exec_lua [=[ - local ffi = require('ffi') + exec_lua(function() + local ffi = require('ffi') - ffi.cdef [[ + ffi.cdef [[ typedef struct window_S win_T; int win_col_off(win_T *wp); extern win_T *curwin; ]] - vim.cmd('set number numberwidth=4 signcolumn=yes:4') + vim.cmd('set number numberwidth=4 signcolumn=yes:4') - return ffi.C.win_col_off(ffi.C.curwin) - ]=] + return ffi.C.win_col_off(ffi.C.curwin) + end) ) eq( 20, - exec_lua [=[ - local ffi = require('ffi') + exec_lua(function() + local ffi = require('ffi') - ffi.cdef[[ + ffi.cdef [[ typedef struct {} stl_hlrec_t; typedef struct {} StlClickRecord; typedef struct {} statuscol_T; @@ -58,32 +58,32 @@ describe('ffi.cdef', function() ); ]] - return ffi.C.build_stl_str_hl( - ffi.C.find_window_by_handle(0, ffi.new('Error')), - ffi.new('char[1024]'), - 1024, - ffi.cast('char*', 'StatusLineOfLength20'), - -1, - 0, - 0, - 0, - nil, - nil, - nil - ) - ]=] + return ffi.C.build_stl_str_hl( + ffi.C.find_window_by_handle(0, ffi.new('Error')), + ffi.new('char[1024]'), + 1024, + ffi.cast('char*', 'StatusLineOfLength20'), + -1, + 0, + 0, + 0, + nil, + nil, + nil + ) + end) ) -- Check that extern symbols are exported and accessible eq( true, - exec_lua [[ - local ffi = require('ffi') + exec_lua(function() + local ffi = require('ffi') - ffi.cdef('uint64_t display_tick;') + ffi.cdef('uint64_t display_tick;') - return ffi.C.display_tick >= 0 - ]] + return ffi.C.display_tick >= 0 + end) ) end) end) diff --git a/test/functional/lua/filetype_spec.lua b/test/functional/lua/filetype_spec.lua index b5eb9fab23..574c837f92 100644 --- a/test/functional/lua/filetype_spec.lua +++ b/test/functional/lua/filetype_spec.lua @@ -70,15 +70,15 @@ describe('vim.filetype', function() eq( 'dosini', - exec_lua(function(root0) + exec_lua(function() vim.filetype.add({ filename = { ['config'] = 'toml', - [root0 .. '/.config/fun/config'] = 'dosini', + [root .. '/.config/fun/config'] = 'dosini', }, }) - return vim.filetype.match({ filename = root0 .. '/.config/fun/config' }) - end, root) + return vim.filetype.match({ filename = root .. '/.config/fun/config' }) + end) ) end) @@ -123,7 +123,7 @@ describe('vim.filetype', function() exec_lua(function() -- Needs to be set so detect#sh doesn't fail vim.g.ft_ignore_pat = '\\.\\(Z\\|gz\\|bz2\\|zip\\|tgz\\)$' - return vim.filetype.match({ contents = { '#!/usr/bin/env bash' } }) + return (vim.filetype.match({ contents = { '#!/usr/bin/env bash' } })) end) ) end) @@ -152,7 +152,12 @@ describe('vim.filetype', function() xml = { formatexpr = 'xmlformat#Format()' }, } do for option, value in pairs(opts) do - eq(value, exec_lua([[ return vim.filetype.get_option(...) ]], ft, option)) + eq( + value, + exec_lua(function() + return vim.filetype.get_option(ft, option) + end) + ) end end end) diff --git a/test/functional/lua/fs_spec.lua b/test/functional/lua/fs_spec.lua index 4848787ed2..f0d49205e7 100644 --- a/test/functional/lua/fs_spec.lua +++ b/test/functional/lua/fs_spec.lua @@ -141,14 +141,14 @@ describe('vim.fs', function() it('works', function() eq( true, - exec_lua(function(dir, nvim) - for name, type in vim.fs.dir(dir) do - if name == nvim and type == 'file' then + exec_lua(function() + for name, type in vim.fs.dir(nvim_dir) do + if name == nvim_prog_basename and type == 'file' then return true end end return false - end, nvim_dir, nvim_prog_basename) + end) ) end) @@ -167,22 +167,21 @@ describe('vim.fs', function() io.open('testd/a/b/c/c4', 'w'):close() local function run(dir, depth, skip) - local r = exec_lua(function(dir0, depth0, skip0) + return exec_lua(function() local r = {} local skip_f - if skip0 then + if skip then skip_f = function(n0) - if vim.tbl_contains(skip0 or {}, n0) then + if vim.tbl_contains(skip or {}, n0) then return false end end end - for name, type_ in vim.fs.dir(dir0, { depth = depth0, skip = skip_f }) do + for name, type_ in vim.fs.dir(dir, { depth = depth, skip = skip_f }) do r[name] = type_ end return r - end, dir, depth, skip) - return r + end) end local exp = {} @@ -252,9 +251,12 @@ describe('vim.fs', function() opts = { path = test_source_path .. '/contrib', limit = math.huge } eq( - exec_lua(function(dir) - return vim.tbl_map(vim.fs.basename, vim.fn.glob(dir .. '/contrib/*', false, true)) - end, test_source_path), + exec_lua(function() + return vim.tbl_map( + vim.fs.basename, + vim.fn.glob(test_source_path .. '/contrib/*', false, true) + ) + end), vim.tbl_map( vim.fs.basename, vim.fs.find(function(_, d) @@ -337,10 +339,10 @@ describe('vim.fs', function() local xdg_config_home = test_build_dir .. '/.config' eq( xdg_config_home .. '/nvim', - exec_lua(function(...) - vim.env.XDG_CONFIG_HOME = ... + exec_lua(function() + vim.env.XDG_CONFIG_HOME = xdg_config_home return vim.fs.normalize('$XDG_CONFIG_HOME/nvim') - end, xdg_config_home) + end) ) end) diff --git a/test/functional/lua/glob_spec.lua b/test/functional/lua/glob_spec.lua index 6f1e5be501..8302c7334d 100644 --- a/test/functional/lua/glob_spec.lua +++ b/test/functional/lua/glob_spec.lua @@ -2,16 +2,15 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() local eq = t.eq -local exec_lua = n.exec_lua describe('glob', function() before_each(n.clear) after_each(n.clear) - local match = function(...) - return exec_lua(function(pattern, str) + local match = function(pattern, str) + return n.exec_lua(function() return require('vim.glob').to_lpeg(pattern):match(str) ~= nil - end, ...) + end) end describe('glob matching', function() diff --git a/test/functional/lua/highlight_spec.lua b/test/functional/lua/highlight_spec.lua index ad709a06f1..c048949df8 100644 --- a/test/functional/lua/highlight_spec.lua +++ b/test/functional/lua/highlight_spec.lua @@ -31,10 +31,10 @@ describe('vim.highlight.range', function() end) it('works with charwise selection', function() - exec_lua([[ + exec_lua(function() local ns = vim.api.nvim_create_namespace('') vim.highlight.range(0, ns, 'Search', { 1, 5 }, { 3, 10 }) - ]]) + end) screen:expect([[ ^asdfghjkl{1:$} | «口{10:=口»}{100:$} | @@ -46,10 +46,10 @@ describe('vim.highlight.range', function() end) it('works with linewise selection', function() - exec_lua([[ + exec_lua(function() local ns = vim.api.nvim_create_namespace('') vim.highlight.range(0, ns, 'Search', { 0, 0 }, { 4, 0 }, { regtype = 'V' }) - ]]) + end) screen:expect([[ {10:^asdfghjkl}{100:$} | {10:«口=口»}{100:$} | @@ -61,10 +61,10 @@ describe('vim.highlight.range', function() end) it('works with blockwise selection', function() - exec_lua([[ + exec_lua(function() local ns = vim.api.nvim_create_namespace('') vim.highlight.range(0, ns, 'Search', { 0, 0 }, { 4, 4 }, { regtype = '\022' }) - ]]) + end) screen:expect([[ {10:^asdf}ghjkl{1:$} | {10:«口=}口»{1:$} | @@ -76,10 +76,10 @@ describe('vim.highlight.range', function() end) it('works with blockwise selection with width', function() - exec_lua([[ + exec_lua(function() local ns = vim.api.nvim_create_namespace('') vim.highlight.range(0, ns, 'Search', { 0, 4 }, { 4, 7 }, { regtype = '\0226' }) - ]]) + end) screen:expect([[ ^asdf{10:ghjkl}{1:$} | «口={10:口»}{1:$} | @@ -91,11 +91,11 @@ describe('vim.highlight.range', function() end) it('can use -1 or v:maxcol to indicate end of line', function() - exec_lua([[ + exec_lua(function() local ns = vim.api.nvim_create_namespace('') vim.highlight.range(0, ns, 'Search', { 0, 4 }, { 1, -1 }, {}) vim.highlight.range(0, ns, 'Search', { 2, 6 }, { 3, vim.v.maxcol }, {}) - ]]) + end) screen:expect([[ ^asdf{10:ghjkl}{100:$} | {10:«口=口»}{100:$} | @@ -114,33 +114,37 @@ describe('vim.highlight.on_yank', function() it('does not show errors even if buffer is wiped before timeout', function() command('new') - exec_lua([[ - vim.highlight.on_yank({timeout = 10, on_macro = true, event = {operator = "y", regtype = "v"}}) + exec_lua(function() + vim.highlight.on_yank({ + timeout = 10, + on_macro = true, + event = { operator = 'y', regtype = 'v' }, + }) vim.cmd('bwipeout!') - ]]) + end) vim.uv.sleep(10) n.feed('') -- avoid hang if error message exists eq('', eval('v:errmsg')) end) it('does not close timer twice', function() - exec_lua([[ - vim.highlight.on_yank({timeout = 10, on_macro = true, event = {operator = "y"}}) + exec_lua(function() + vim.highlight.on_yank({ timeout = 10, on_macro = true, event = { operator = 'y' } }) vim.uv.sleep(10) vim.schedule(function() - vim.highlight.on_yank({timeout = 0, on_macro = true, event = {operator = "y"}}) + vim.highlight.on_yank({ timeout = 0, on_macro = true, event = { operator = 'y' } }) end) - ]]) + end) eq('', eval('v:errmsg')) end) it('does not show in another window', function() command('vsplit') - exec_lua([[ - vim.api.nvim_buf_set_mark(0,"[",1,1,{}) - vim.api.nvim_buf_set_mark(0,"]",1,1,{}) - vim.highlight.on_yank({timeout = math.huge, on_macro = true, event = {operator = "y"}}) - ]]) + exec_lua(function() + vim.api.nvim_buf_set_mark(0, '[', 1, 1, {}) + vim.api.nvim_buf_set_mark(0, ']', 1, 1, {}) + vim.highlight.on_yank({ timeout = math.huge, on_macro = true, event = { operator = 'y' } }) + end) local ns = api.nvim_create_namespace('hlyank') local win = api.nvim_get_current_win() eq({ win }, api.nvim__ns_get(ns).wins) @@ -150,19 +154,19 @@ describe('vim.highlight.on_yank', function() it('removes old highlight if new one is created before old one times out', function() command('vnew') - exec_lua([[ - vim.api.nvim_buf_set_mark(0,"[",1,1,{}) - vim.api.nvim_buf_set_mark(0,"]",1,1,{}) - vim.highlight.on_yank({timeout = math.huge, on_macro = true, event = {operator = "y"}}) - ]]) + exec_lua(function() + vim.api.nvim_buf_set_mark(0, '[', 1, 1, {}) + vim.api.nvim_buf_set_mark(0, ']', 1, 1, {}) + vim.highlight.on_yank({ timeout = math.huge, on_macro = true, event = { operator = 'y' } }) + end) local ns = api.nvim_create_namespace('hlyank') eq(api.nvim_get_current_win(), api.nvim__ns_get(ns).wins[1]) command('wincmd w') - exec_lua([[ - vim.api.nvim_buf_set_mark(0,"[",1,1,{}) - vim.api.nvim_buf_set_mark(0,"]",1,1,{}) - vim.highlight.on_yank({timeout = math.huge, on_macro = true, event = {operator = "y"}}) - ]]) + exec_lua(function() + vim.api.nvim_buf_set_mark(0, '[', 1, 1, {}) + vim.api.nvim_buf_set_mark(0, ']', 1, 1, {}) + vim.highlight.on_yank({ timeout = math.huge, on_macro = true, event = { operator = 'y' } }) + end) local win = api.nvim_get_current_win() eq({ win }, api.nvim__ns_get(ns).wins) command('wincmd w') diff --git a/test/functional/lua/inspector_spec.lua b/test/functional/lua/inspector_spec.lua index 8fadba6ee8..3a1263f6a3 100644 --- a/test/functional/lua/inspector_spec.lua +++ b/test/functional/lua/inspector_spec.lua @@ -12,22 +12,21 @@ describe('vim.inspect_pos', function() end) it('it returns items', function() - local ret = exec_lua([[ + local buf, items, other_buf_syntax = exec_lua(function() local buf = vim.api.nvim_create_buf(true, false) local buf1 = vim.api.nvim_create_buf(true, false) - local ns1 = vim.api.nvim_create_namespace("ns1") - local ns2 = vim.api.nvim_create_namespace("") + local ns1 = vim.api.nvim_create_namespace('ns1') + local ns2 = vim.api.nvim_create_namespace('') vim.api.nvim_set_current_buf(buf) - vim.api.nvim_buf_set_lines(0, 0, -1, false, {"local a = 123"}) - vim.api.nvim_buf_set_lines(buf1, 0, -1, false, {"--commentline"}) + vim.api.nvim_buf_set_lines(0, 0, -1, false, { 'local a = 123' }) + vim.api.nvim_buf_set_lines(buf1, 0, -1, false, { '--commentline' }) vim.bo[buf].filetype = 'lua' vim.bo[buf1].filetype = 'lua' - vim.api.nvim_buf_set_extmark(buf, ns1, 0, 10, { hl_group = "Normal" }) - vim.api.nvim_buf_set_extmark(buf, ns2, 0, 10, { hl_group = "Normal" }) - vim.cmd("syntax on") - return {buf, vim.inspect_pos(0, 0, 10), vim.inspect_pos(buf1, 0, 10).syntax } - ]]) - local buf, items, other_buf_syntax = unpack(ret) + vim.api.nvim_buf_set_extmark(buf, ns1, 0, 10, { hl_group = 'Normal' }) + vim.api.nvim_buf_set_extmark(buf, ns2, 0, 10, { hl_group = 'Normal' }) + vim.cmd('syntax on') + return buf, vim.inspect_pos(0, 0, 10), vim.inspect_pos(buf1, 0, 10).syntax + end) eq('', eval('v:errmsg')) eq({ @@ -95,14 +94,14 @@ describe('vim.show_pos', function() end) it('it does not error', function() - exec_lua([[ + exec_lua(function() local buf = vim.api.nvim_create_buf(true, false) vim.api.nvim_set_current_buf(buf) - vim.api.nvim_buf_set_lines(0, 0, -1, false, {"local a = 123"}) + vim.api.nvim_buf_set_lines(0, 0, -1, false, { 'local a = 123' }) vim.bo[buf].filetype = 'lua' - vim.cmd("syntax on") - return {buf, vim.show_pos(0, 0, 10)} - ]]) + vim.cmd('syntax on') + return { buf, vim.show_pos(0, 0, 10) } + end) eq('', eval('v:errmsg')) end) end) diff --git a/test/functional/lua/loader_spec.lua b/test/functional/lua/loader_spec.lua index 06403e856c..8508f2aa14 100644 --- a/test/functional/lua/loader_spec.lua +++ b/test/functional/lua/loader_spec.lua @@ -12,14 +12,14 @@ describe('vim.loader', function() it('can work in compatibility with --luamod-dev #27413', function() clear({ args = { '--luamod-dev' } }) - exec_lua [[ + exec_lua(function() vim.loader.enable() - require("vim.fs") + require('vim.fs') -- try to load other vim submodules as well (Nvim Lua stdlib) for key, _ in pairs(vim._submodules) do - local modname = 'vim.' .. key -- e.g. "vim.fs" + local modname = 'vim.' .. key -- e.g. "vim.fs" local lhs = vim[key] local rhs = require(modname) @@ -28,28 +28,25 @@ describe('vim.loader', function() ('%s != require("%s"), %s != %s'):format(modname, modname, tostring(lhs), tostring(rhs)) ) end - ]] + end) end) it('handles changing files (#23027)', function() - exec_lua [[ + exec_lua(function() vim.loader.enable() - ]] + end) local tmp = t.tmpname() command('edit ' .. tmp) eq( 1, - exec_lua( - [[ - vim.api.nvim_buf_set_lines(0, 0, -1, true, {'_G.TEST=1'}) - vim.cmd.write() - loadfile(...)() - return _G.TEST - ]], - tmp - ) + exec_lua(function() + vim.api.nvim_buf_set_lines(0, 0, -1, true, { '_G.TEST=1' }) + vim.cmd.write() + loadfile(tmp)() + return _G.TEST + end) ) -- fs latency @@ -57,15 +54,12 @@ describe('vim.loader', function() eq( 2, - exec_lua( - [[ - vim.api.nvim_buf_set_lines(0, 0, -1, true, {'_G.TEST=2'}) - vim.cmd.write() - loadfile(...)() - return _G.TEST - ]], - tmp - ) + exec_lua(function() + vim.api.nvim_buf_set_lines(0, 0, -1, true, { '_G.TEST=2' }) + vim.cmd.write() + loadfile(tmp)() + return _G.TEST + end) ) end) diff --git a/test/functional/lua/loop_spec.lua b/test/functional/lua/loop_spec.lua index 566a171a84..de8200a5f1 100644 --- a/test/functional/lua/loop_spec.lua +++ b/test/functional/lua/loop_spec.lua @@ -25,30 +25,34 @@ describe('vim.uv', function() it('timer', function() exec_lua('vim.api.nvim_set_var("coroutine_cnt", 0)', {}) - local code = [[ + local code = function() local touch = 0 local function wait(ms) local this = coroutine.running() assert(this) - local timer = vim.uv.new_timer() - timer:start(ms, 0, vim.schedule_wrap(function () - timer:close() - touch = touch + 1 - coroutine.resume(this) - touch = touch + 1 - assert(touch==3) - vim.api.nvim_set_var("coroutine_cnt_1", touch) - end)) + local timer = assert(vim.uv.new_timer()) + timer:start( + ms, + 0, + vim.schedule_wrap(function() + timer:close() + touch = touch + 1 + coroutine.resume(this) + touch = touch + 1 + assert(touch == 3) + vim.api.nvim_set_var('coroutine_cnt_1', touch) + end) + ) coroutine.yield() touch = touch + 1 return touch end coroutine.wrap(function() local touched = wait(10) - assert(touched==touch) - vim.api.nvim_set_var("coroutine_cnt", touched) + assert(touched == touch) + vim.api.nvim_set_var('coroutine_cnt', touched) end)() - ]] + end eq(0, api.nvim_get_var('coroutine_cnt')) exec_lua(code) @@ -99,15 +103,19 @@ describe('vim.uv', function() -- callbacks can be scheduled to be executed in the main event loop -- where the entire API is available - exec_lua([[ - local timer = vim.uv.new_timer() - timer:start(20, 0, vim.schedule_wrap(function () - _G.is_fast = vim.in_fast_event() - timer:close() - vim.api.nvim_set_var("valid", true) - vim.api.nvim_command("echomsg 'howdy'") - end)) - ]]) + exec_lua(function() + local timer = assert(vim.uv.new_timer()) + timer:start( + 20, + 0, + vim.schedule_wrap(function() + _G.is_fast = vim.in_fast_event() + timer:close() + vim.api.nvim_set_var('valid', true) + vim.api.nvim_command("echomsg 'howdy'") + end) + ) + end) screen:expect([[ ^ | @@ -118,15 +126,15 @@ describe('vim.uv', function() eq(false, exec_lua('return _G.is_fast')) -- fast (not deferred) API functions are allowed to be called directly - exec_lua([[ - local timer = vim.uv.new_timer() - timer:start(20, 0, function () + exec_lua(function() + local timer = assert(vim.uv.new_timer()) + timer:start(20, 0, function() timer:close() -- input is queued for processing after the callback returns - vim.api.nvim_input("isneaky") + vim.api.nvim_input('isneaky') _G.mode = vim.api.nvim_get_mode() end) - ]]) + end) screen:expect([[ sneaky^ | {1:~ }|*8 @@ -134,15 +142,15 @@ describe('vim.uv', function() ]]) eq({ blocking = false, mode = 'n' }, exec_lua('return _G.mode')) - exec_lua([[ - local timer = vim.uv.new_timer() - timer:start(20, 0, function () + exec_lua(function() + local timer = assert(vim.uv.new_timer()) + timer:start(20, 0, function() _G.is_fast = vim.in_fast_event() timer:close() - _G.value = vim.fn.has("nvim-0.5") - _G.unvalue = vim.fn.has("python3") + _G.value = vim.fn.has('nvim-0.5') + _G.unvalue = vim.fn.has('python3') end) - ]]) + end) screen:expect({ any = [[{3:Vim:E5560: Vimscript function must not be called i}]] }) feed('') diff --git a/test/functional/lua/mpack_spec.lua b/test/functional/lua/mpack_spec.lua index efd69d4607..ebede26936 100644 --- a/test/functional/lua/mpack_spec.lua +++ b/test/functional/lua/mpack_spec.lua @@ -11,20 +11,20 @@ describe('lua vim.mpack', function() it('encodes vim.NIL', function() eq( { true, true, true, true }, - exec_lua [[ - local var = vim.mpack.decode(vim.mpack.encode({33, vim.NIL, 77})) - return {var[1]==33, var[2]==vim.NIL, var[3]==77, var[4]==nil} - ]] + exec_lua(function() + local var = vim.mpack.decode(vim.mpack.encode({ 33, vim.NIL, 77 })) + return { var[1] == 33, var[2] == vim.NIL, var[3] == 77, var[4] == nil } + end) ) end) it('encodes vim.empty_dict()', function() eq( { { {}, 'foo', {} }, true, false }, - exec_lua [[ - local var = vim.mpack.decode(vim.mpack.encode({{}, "foo", vim.empty_dict()})) - return {var, vim.islist(var[1]), vim.islist(var[3])} - ]] + exec_lua(function() + local var = vim.mpack.decode(vim.mpack.encode({ {}, 'foo', vim.empty_dict() })) + return { var, vim.islist(var[1]), vim.islist(var[3]) } + end) ) end) end) diff --git a/test/functional/lua/overrides_spec.lua b/test/functional/lua/overrides_spec.lua index 849978f080..33a2813200 100644 --- a/test/functional/lua/overrides_spec.lua +++ b/test/functional/lua/overrides_spec.lua @@ -134,14 +134,12 @@ describe('print', function() eq('abc def', exec_capture('lua print("abc", "", "def")')) end) it('defers printing in luv event handlers', function() - exec_lua( - [[ - local cmd = ... + exec_lua(function(cmd) function test() local timer = vim.uv.new_timer() local done = false timer:start(10, 0, function() - print("very fast") + print('very fast') timer:close() done = true end) @@ -149,14 +147,12 @@ describe('print', function() -- loop until we know for sure the callback has been executed while not done do os.execute(cmd) - vim.uv.run("nowait") -- fake os_breakcheck() + vim.uv.run('nowait') -- fake os_breakcheck() end - print("very slow") - vim.api.nvim_command("sleep 1m") -- force deferred event processing + print('very slow') + vim.api.nvim_command('sleep 1m') -- force deferred event processing end - ]], - (is_os('win') and 'timeout 1') or 'sleep 0.1' - ) + end, (is_os('win') and 'timeout 1') or 'sleep 0.1') eq('very slow\nvery fast', exec_capture('lua test()')) end) diff --git a/test/functional/lua/system_spec.lua b/test/functional/lua/system_spec.lua index e72a009d2e..482bfcf1a9 100644 --- a/test/functional/lua/system_spec.lua +++ b/test/functional/lua/system_spec.lua @@ -6,10 +6,8 @@ local exec_lua = n.exec_lua local eq = t.eq local function system_sync(cmd, opts) - return exec_lua( - [[ - local cmd, opts = ... - local obj = vim.system(...) + return exec_lua(function() + local obj = vim.system(cmd, opts) if opts.timeout then -- Minor delay before calling wait() so the timeout uv timer can have a headstart over the @@ -24,16 +22,11 @@ local function system_sync(cmd, opts) assert(not proc, 'process still exists') return res - ]], - cmd, - opts - ) + end) end local function system_async(cmd, opts) - return exec_lua( - [[ - local cmd, opts = ... + return exec_lua(function() _G.done = false local obj = vim.system(cmd, opts, function(obj) _G.done = true @@ -51,10 +44,7 @@ local function system_async(cmd, opts) assert(not proc, 'process still exists') return _G.ret - ]], - cmd, - opts - ) + end) end describe('vim.system', function() @@ -84,7 +74,7 @@ describe('vim.system', function() end it('kill processes', function() - exec_lua([[ + exec_lua(function() local signal local cmd = vim.system({ 'cat', '-' }, { stdin = true }, function(r) signal = r.signal @@ -104,19 +94,21 @@ describe('vim.system', function() assert(not proc, 'process still exists') assert(signal == 2) - ]]) + end) end) it('SystemObj:wait() does not process non-fast events #27292', function() eq( false, - exec_lua([[ + exec_lua(function() _G.processed = false local cmd = vim.system({ 'sleep', '1' }) - vim.schedule(function() _G.processed = true end) + vim.schedule(function() + _G.processed = true + end) cmd:wait() return _G.processed - ]]) + end) ) eq(true, exec_lua([[return _G.processed]])) end) diff --git a/test/functional/plugin/editorconfig_spec.lua b/test/functional/plugin/editorconfig_spec.lua index 242ed9b57f..5f69b8938a 100644 --- a/test/functional/plugin/editorconfig_spec.lua +++ b/test/functional/plugin/editorconfig_spec.lua @@ -7,7 +7,6 @@ local eq = t.eq local pathsep = n.get_pathsep() local fn = n.fn local api = n.api -local exec_lua = n.exec_lua local testdir = 'Xtest-editorconfig' @@ -227,12 +226,12 @@ But not this one end) it('does not operate on invalid buffers', function() - local ok, err = unpack(exec_lua([[ + local ok, err = unpack(n.exec_lua(function() vim.cmd.edit('test.txt') local bufnr = vim.api.nvim_get_current_buf() vim.cmd.bwipeout(bufnr) - return {pcall(require('editorconfig').config, bufnr)} - ]])) + return { pcall(require('editorconfig').config, bufnr) } + end)) eq(true, ok, err) end) diff --git a/test/functional/plugin/lsp/codelens_spec.lua b/test/functional/plugin/lsp/codelens_spec.lua index cd20e95dd1..20ef1cb49e 100644 --- a/test/functional/plugin/lsp/codelens_spec.lua +++ b/test/functional/plugin/lsp/codelens_spec.lua @@ -13,36 +13,34 @@ describe('vim.lsp.codelens', function() it('on_codelens_stores_and_displays_lenses', function() local fake_uri = 'file:///fake/uri' - local bufnr = exec_lua( - [[ - fake_uri = ... + local bufnr = exec_lua(function() local bufnr = vim.uri_to_bufnr(fake_uri) - local lines = {'So', 'many', 'lines'} + local lines = { 'So', 'many', 'lines' } vim.fn.bufload(bufnr) vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines) return bufnr - ]], - fake_uri - ) + end) - exec_lua( - [[ - local bufnr = ... + exec_lua(function() local lenses = { { range = { - start = { line = 0, character = 0, }, - ['end'] = { line = 0, character = 0 } + start = { line = 0, character = 0 }, + ['end'] = { line = 0, character = 0 }, }, - command = { title = 'Lens1', command = 'Dummy' } + command = { title = 'Lens1', command = 'Dummy' }, }, } - vim.lsp.codelens.on_codelens(nil, lenses, {method='textDocument/codeLens', client_id=1, bufnr=bufnr}) - ]], - bufnr - ) + vim.lsp.codelens.on_codelens( + nil, + lenses, + { method = 'textDocument/codeLens', client_id = 1, bufnr = bufnr } + ) + end) - local stored_lenses = exec_lua('return vim.lsp.codelens.get(...)', bufnr) + local stored_lenses = exec_lua(function() + return vim.lsp.codelens.get(bufnr) + end) local expected = { { range = { @@ -57,58 +55,54 @@ describe('vim.lsp.codelens', function() } eq(expected, stored_lenses) - local virtual_text_chunks = exec_lua( - [[ - local bufnr = ... + local virtual_text_chunks = exec_lua(function() local ns = vim.lsp.codelens.__namespaces[1] local extmarks = vim.api.nvim_buf_get_extmarks(bufnr, ns, 0, -1, {}) return vim.api.nvim_buf_get_extmark_by_id(bufnr, ns, extmarks[1][1], { details = true })[3].virt_text - ]], - bufnr - ) + end) eq({ [1] = { 'Lens1', 'LspCodeLens' } }, virtual_text_chunks) end) it('can clear all lens', function() local fake_uri = 'file:///fake/uri' - local bufnr = exec_lua( - [[ - fake_uri = ... + local bufnr = exec_lua(function() local bufnr = vim.uri_to_bufnr(fake_uri) - local lines = {'So', 'many', 'lines'} + local lines = { 'So', 'many', 'lines' } vim.fn.bufload(bufnr) vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines) return bufnr - ]], - fake_uri - ) + end) - exec_lua( - [[ - local bufnr = ... + exec_lua(function() local lenses = { { range = { - start = { line = 0, character = 0, }, - ['end'] = { line = 0, character = 0 } + start = { line = 0, character = 0 }, + ['end'] = { line = 0, character = 0 }, }, - command = { title = 'Lens1', command = 'Dummy' } + command = { title = 'Lens1', command = 'Dummy' }, }, } - vim.lsp.codelens.on_codelens(nil, lenses, {method='textDocument/codeLens', client_id=1, bufnr=bufnr}) - ]], - bufnr - ) + vim.lsp.codelens.on_codelens( + nil, + lenses, + { method = 'textDocument/codeLens', client_id = 1, bufnr = bufnr } + ) + end) - local stored_lenses = exec_lua('return vim.lsp.codelens.get(...)', bufnr) + local stored_lenses = exec_lua(function() + return vim.lsp.codelens.get(bufnr) + end) eq(1, #stored_lenses) - exec_lua([[ + exec_lua(function() vim.lsp.codelens.clear() - ]]) + end) - stored_lenses = exec_lua('return vim.lsp.codelens.get(...)', bufnr) + stored_lenses = exec_lua(function() + return vim.lsp.codelens.get(bufnr) + end) eq(0, #stored_lenses) end) end) diff --git a/test/functional/plugin/lsp/completion_spec.lua b/test/functional/plugin/lsp/completion_spec.lua index d3796082fb..4df8d77d44 100644 --- a/test/functional/plugin/lsp/completion_spec.lua +++ b/test/functional/plugin/lsp/completion_spec.lua @@ -23,12 +23,10 @@ local function complete(line, candidates, lnum, server_boundary) -- nvim_win_get_cursor returns 0 based column, line:find returns 1 based local cursor_col = line:find('|') - 1 line = line:gsub('|', '') - return exec_lua( - [[ - local line, cursor_col, lnum, result, server_boundary = ... + return exec_lua(function(result) local line_to_cursor = line:sub(1, cursor_col) local client_start_boundary = vim.fn.match(line_to_cursor, '\\k*$') - local items, new_server_boundary = require("vim.lsp.completion")._convert_results( + local items, new_server_boundary = require('vim.lsp.completion')._convert_results( line, lnum, cursor_col, @@ -36,19 +34,13 @@ local function complete(line, candidates, lnum, server_boundary) client_start_boundary, server_boundary, result, - "utf-16" + 'utf-16' ) return { items = items, - server_start_boundary = new_server_boundary + server_start_boundary = new_server_boundary, } - ]], - line, - cursor_col, - lnum, - candidates, - server_boundary - ) + end, candidates) end describe('vim.lsp.completion: item conversion', function() @@ -483,13 +475,14 @@ describe('vim.lsp.completion: protocol', function() before_each(function() clear() exec_lua(create_server_definition) - exec_lua([[ + exec_lua(function() _G.capture = {} + --- @diagnostic disable-next-line:duplicate-set-field vim.fn.complete = function(col, matches) _G.capture.col = col _G.capture.matches = matches end - ]]) + end) end) after_each(clear) @@ -497,32 +490,34 @@ describe('vim.lsp.completion: protocol', function() --- @param completion_result lsp.CompletionList --- @return integer local function create_server(completion_result) - return exec_lua( - [[ - local result = ... - local server = _create_server({ + return exec_lua(function() + local server = _G._create_server({ capabilities = { completionProvider = { - triggerCharacters = { '.' } - } + triggerCharacters = { '.' }, + }, }, handlers = { ['textDocument/completion'] = function(_, _, callback) - callback(nil, result) - end - } + callback(nil, completion_result) + end, + }, }) - bufnr = vim.api.nvim_get_current_buf() + local bufnr = vim.api.nvim_get_current_buf() vim.api.nvim_win_set_buf(0, bufnr) - return vim.lsp.start({ name = 'dummy', cmd = server.cmd, on_attach = function(client, bufnr) - vim.lsp.completion.enable(true, client.id, bufnr, { convert = function(item) - return { abbr = item.label:gsub('%b()', '')} - end}) - end}) - ]], - completion_result - ) + return vim.lsp.start({ + name = 'dummy', + cmd = server.cmd, + on_attach = function(client, bufnr0) + vim.lsp.completion.enable(true, client.id, bufnr0, { + convert = function(item) + return { abbr = item.label:gsub('%b()', '') } + end, + }) + end, + }) + end) end local function assert_matches(fn) @@ -533,14 +528,11 @@ describe('vim.lsp.completion: protocol', function() --- @param pos [integer, integer] local function trigger_at_pos(pos) - exec_lua( - [[ + exec_lua(function() local win = vim.api.nvim_get_current_win() - vim.api.nvim_win_set_cursor(win, ...) + vim.api.nvim_win_set_cursor(win, pos) vim.lsp.completion.trigger() - ]], - pos - ) + end) retry(nil, nil, function() neq(nil, exec_lua('return _G.capture.col')) @@ -683,37 +675,30 @@ describe('vim.lsp.completion: protocol', function() } local client_id = create_server(completion_list) - exec_lua( - [[ + exec_lua(function() _G.called = false - local client = vim.lsp.get_client_by_id(...) - client.commands.dummy = function () + local client = assert(vim.lsp.get_client_by_id(client_id)) + client.commands.dummy = function() _G.called = true end - ]], - client_id - ) + end) feed('ih') trigger_at_pos({ 1, 1 }) - exec_lua( - [[ - local client_id, item = ... + local item = completion_list.items[1] + exec_lua(function() vim.v.completed_item = { user_data = { nvim = { lsp = { client_id = client_id, - completion_item = item - } - } - } + completion_item = item, + }, + }, + }, } - ]], - client_id, - completion_list.items[1] - ) + end) feed('') diff --git a/test/functional/plugin/lsp/diagnostic_spec.lua b/test/functional/plugin/lsp/diagnostic_spec.lua index 76b1808883..78c684083b 100644 --- a/test/functional/plugin/lsp/diagnostic_spec.lua +++ b/test/functional/plugin/lsp/diagnostic_spec.lua @@ -11,7 +11,9 @@ local neq = t.neq local create_server_definition = t_lsp.create_server_definition describe('vim.lsp.diagnostic', function() - local fake_uri + local fake_uri --- @type string + local client_id --- @type integer + local diagnostic_bufnr --- @type integer before_each(function() clear { env = { @@ -19,79 +21,98 @@ describe('vim.lsp.diagnostic', function() VIMRUNTIME = os.getenv 'VIMRUNTIME', } } - exec_lua [[ + exec_lua(function() require('vim.lsp') - make_range = function(x1, y1, x2, y2) + _G.make_range = function(x1, y1, x2, y2) return { start = { line = x1, character = y1 }, ['end'] = { line = x2, character = y2 } } end - make_error = function(msg, x1, y1, x2, y2) + _G.make_error = function(msg, x1, y1, x2, y2) return { - range = make_range(x1, y1, x2, y2), + range = _G.make_range(x1, y1, x2, y2), message = msg, severity = 1, } end - make_warning = function(msg, x1, y1, x2, y2) + _G.make_warning = function(msg, x1, y1, x2, y2) return { - range = make_range(x1, y1, x2, y2), + range = _G.make_range(x1, y1, x2, y2), message = msg, severity = 2, } end - make_information = function(msg, x1, y1, x2, y2) + _G.make_information = function(msg, x1, y1, x2, y2) return { - range = make_range(x1, y1, x2, y2), + range = _G.make_range(x1, y1, x2, y2), message = msg, severity = 3, } end - function get_extmarks(bufnr, client_id) - local namespace = vim.lsp.diagnostic.get_namespace(client_id) + function _G.get_extmarks(bufnr, client_id0) + local namespace = vim.lsp.diagnostic.get_namespace(client_id0) local ns = vim.diagnostic.get_namespace(namespace) local extmarks = {} if ns.user_data.virt_text_ns then - for _, e in pairs(vim.api.nvim_buf_get_extmarks(bufnr, ns.user_data.virt_text_ns, 0, -1, {details=true})) do + for _, e in + pairs( + vim.api.nvim_buf_get_extmarks( + bufnr, + ns.user_data.virt_text_ns, + 0, + -1, + { details = true } + ) + ) + do table.insert(extmarks, e) end end if ns.user_data.underline_ns then - for _, e in pairs(vim.api.nvim_buf_get_extmarks(bufnr, ns.user_data.underline_ns, 0, -1, {details=true})) do + for _, e in + pairs( + vim.api.nvim_buf_get_extmarks( + bufnr, + ns.user_data.underline_ns, + 0, + -1, + { details = true } + ) + ) + do table.insert(extmarks, e) end end return extmarks end - client_id = vim.lsp.start_client { + client_id = assert(vim.lsp.start_client { cmd_env = { - NVIM_LUA_NOTRACK = "1"; - }; + NVIM_LUA_NOTRACK = '1', + }, cmd = { - vim.v.progpath, '-es', '-u', 'NONE', '--headless' - }; - offset_encoding = "utf-16"; - } - ]] + vim.v.progpath, + '-es', + '-u', + 'NONE', + '--headless', + }, + offset_encoding = 'utf-16', + }) + end) fake_uri = 'file:///fake/uri' - exec_lua( - [[ - fake_uri = ... + exec_lua(function() diagnostic_bufnr = vim.uri_to_bufnr(fake_uri) - local lines = {"1st line of text", "2nd line of text", "wow", "cool", "more", "lines"} + local lines = { '1st line of text', '2nd line of text', 'wow', 'cool', 'more', 'lines' } vim.fn.bufload(diagnostic_bufnr) vim.api.nvim_buf_set_lines(diagnostic_bufnr, 0, 1, false, lines) vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - return diagnostic_bufnr - ]], - fake_uri - ) + end) end) after_each(function() @@ -101,89 +122,73 @@ describe('vim.lsp.diagnostic', function() describe('vim.lsp.diagnostic.on_publish_diagnostics', function() it('allows configuring the virtual text via vim.lsp.with', function() local expected_spacing = 10 - local extmarks = exec_lua( - [[ - PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, { + local extmarks = exec_lua(function() + _G.PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, { virtual_text = { - spacing = ..., + spacing = expected_spacing, }, }) - PublishDiagnostics(nil, { - uri = fake_uri, - diagnostics = { - make_error('Delayed Diagnostic', 4, 4, 4, 4), - } - }, {client_id=client_id} - ) + _G.PublishDiagnostics(nil, { + uri = fake_uri, + diagnostics = { + _G.make_error('Delayed Diagnostic', 4, 4, 4, 4), + }, + }, { client_id = client_id }) - return get_extmarks(diagnostic_bufnr, client_id) - ]], - expected_spacing - ) + return _G.get_extmarks(diagnostic_bufnr, client_id) + end) - local virt_text = extmarks[1][4].virt_text - local spacing = virt_text[1][1] + local spacing = extmarks[1][4].virt_text[1][1] eq(expected_spacing, #spacing) end) it('allows configuring the virtual text via vim.lsp.with using a function', function() local expected_spacing = 10 - local extmarks = exec_lua( - [[ - spacing = ... - - PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, { + local extmarks = exec_lua(function() + _G.PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, { virtual_text = function() return { - spacing = spacing, + spacing = expected_spacing, } end, }) - PublishDiagnostics(nil, { - uri = fake_uri, - diagnostics = { - make_error('Delayed Diagnostic', 4, 4, 4, 4), - } - }, {client_id=client_id} - ) + _G.PublishDiagnostics(nil, { + uri = fake_uri, + diagnostics = { + _G.make_error('Delayed Diagnostic', 4, 4, 4, 4), + }, + }, { client_id = client_id }) - return get_extmarks(diagnostic_bufnr, client_id) - ]], - expected_spacing - ) + return _G.get_extmarks(diagnostic_bufnr, client_id) + end) - local virt_text = extmarks[1][4].virt_text - local spacing = virt_text[1][1] + local spacing = extmarks[1][4].virt_text[1][1] eq(expected_spacing, #spacing) end) it('allows filtering via severity limit', function() local get_extmark_count_with_severity = function(severity_limit) - return exec_lua( - [[ - PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, { + return exec_lua(function() + _G.PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, { underline = false, virtual_text = { - severity = { min = ... } + severity = { min = severity_limit }, }, }) - PublishDiagnostics(nil, { - uri = fake_uri, - diagnostics = { - make_warning('Delayed Diagnostic', 4, 4, 4, 4), - } - }, {client_id=client_id} - ) - - return #get_extmarks(diagnostic_bufnr, client_id) - ]], - severity_limit - ) + _G.PublishDiagnostics(nil, { + uri = fake_uri, + diagnostics = { + _G.make_warning('Delayed Diagnostic', 4, 4, 4, 4), + }, + }, { client_id = client_id }) + + return #_G.get_extmarks(diagnostic_bufnr, client_id) + end, client_id, fake_uri, severity_limit) end -- No messages with Error or higher @@ -196,246 +201,284 @@ describe('vim.lsp.diagnostic', function() it('correctly handles UTF-16 offsets', function() local line = 'All 💼 and no 🎉 makes Jack a dull 👦' - local result = exec_lua( - [[ - local line = ... - vim.api.nvim_buf_set_lines(diagnostic_bufnr, 0, -1, false, {line}) + local result = exec_lua(function() + vim.api.nvim_buf_set_lines(diagnostic_bufnr, 0, -1, false, { line }) vim.lsp.diagnostic.on_publish_diagnostics(nil, { - uri = fake_uri, - diagnostics = { - make_error('UTF-16 Diagnostic', 0, 7, 0, 8), - } - }, {client_id=client_id} - ) + uri = fake_uri, + diagnostics = { + _G.make_error('UTF-16 Diagnostic', 0, 7, 0, 8), + }, + }, { client_id = client_id }) local diags = vim.diagnostic.get(diagnostic_bufnr) vim.lsp.stop_client(client_id) vim.api.nvim_exec_autocmds('VimLeavePre', { modeline = false }) return diags - ]], - line - ) + end) eq(1, #result) - eq(exec_lua([[return vim.str_byteindex(..., 7, true)]], line), result[1].col) - eq(exec_lua([[return vim.str_byteindex(..., 8, true)]], line), result[1].end_col) + eq( + exec_lua(function() + return vim.str_byteindex(line, 7, true) + end), + result[1].col + ) + eq( + exec_lua(function() + return vim.str_byteindex(line, 8, true) + end), + result[1].end_col + ) end) it('does not create buffer on empty diagnostics', function() - local bufnr - -- No buffer is created without diagnostics - bufnr = exec_lua [[ - vim.lsp.diagnostic.on_publish_diagnostics(nil, { - uri = "file:///fake/uri2", - diagnostics = {}, - }, {client_id=client_id}) - return vim.fn.bufnr(vim.uri_to_fname("file:///fake/uri2")) - ]] - eq(-1, bufnr) + eq( + -1, + exec_lua(function() + vim.lsp.diagnostic.on_publish_diagnostics(nil, { + uri = 'file:///fake/uri2', + diagnostics = {}, + }, { client_id = client_id }) + return vim.fn.bufnr(vim.uri_to_fname('file:///fake/uri2')) + end) + ) -- Create buffer on diagnostics - bufnr = exec_lua [[ - vim.lsp.diagnostic.on_publish_diagnostics(nil, { - uri = "file:///fake/uri2", - diagnostics = { - make_error('Diagnostic', 0, 0, 0, 0), - }, - }, {client_id=client_id}) - return vim.fn.bufnr(vim.uri_to_fname("file:///fake/uri2")) - ]] - neq(-1, bufnr) - eq(1, exec_lua([[return #vim.diagnostic.get(...)]], bufnr)) + neq( + -1, + exec_lua(function() + vim.lsp.diagnostic.on_publish_diagnostics(nil, { + uri = 'file:///fake/uri2', + diagnostics = { + _G.make_error('Diagnostic', 0, 0, 0, 0), + }, + }, { client_id = client_id }) + return vim.fn.bufnr(vim.uri_to_fname('file:///fake/uri2')) + end) + ) + eq( + 1, + exec_lua(function() + return #vim.diagnostic.get(_G.bufnr) + end) + ) -- Clear diagnostics after buffer was created - bufnr = exec_lua [[ - vim.lsp.diagnostic.on_publish_diagnostics(nil, { - uri = "file:///fake/uri2", - diagnostics = {}, - }, {client_id=client_id}) - return vim.fn.bufnr(vim.uri_to_fname("file:///fake/uri2")) - ]] - neq(-1, bufnr) - eq(0, exec_lua([[return #vim.diagnostic.get(...)]], bufnr)) + neq( + -1, + exec_lua(function() + vim.lsp.diagnostic.on_publish_diagnostics(nil, { + uri = 'file:///fake/uri2', + diagnostics = {}, + }, { client_id = client_id }) + return vim.fn.bufnr(vim.uri_to_fname('file:///fake/uri2')) + end) + ) + eq( + 0, + exec_lua(function() + return #vim.diagnostic.get(_G.bufnr) + end) + ) end) end) describe('vim.lsp.diagnostic.on_diagnostic', function() before_each(function() exec_lua(create_server_definition) - exec_lua([[ - server = _create_server({ + exec_lua(function() + _G.server = _G._create_server({ capabilities = { - diagnosticProvider = { - } - } + diagnosticProvider = {}, + }, }) - function get_extmarks(bufnr, client_id) - local namespace = vim.lsp.diagnostic.get_namespace(client_id, true) + function _G.get_extmarks(bufnr, client_id0) + local namespace = vim.lsp.diagnostic.get_namespace(client_id0, true) local ns = vim.diagnostic.get_namespace(namespace) local extmarks = {} if ns.user_data.virt_text_ns then - for _, e in pairs(vim.api.nvim_buf_get_extmarks(bufnr, ns.user_data.virt_text_ns, 0, -1, {details=true})) do + for _, e in + pairs( + vim.api.nvim_buf_get_extmarks( + bufnr, + ns.user_data.virt_text_ns, + 0, + -1, + { details = true } + ) + ) + do table.insert(extmarks, e) end end if ns.user_data.underline_ns then - for _, e in pairs(vim.api.nvim_buf_get_extmarks(bufnr, ns.user_data.underline_ns, 0, -1, {details=true})) do + for _, e in + pairs( + vim.api.nvim_buf_get_extmarks( + bufnr, + ns.user_data.underline_ns, + 0, + -1, + { details = true } + ) + ) + do table.insert(extmarks, e) end end return extmarks end - client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) - ]]) + client_id = vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd }) + end) end) it('adds diagnostics to vim.diagnostics', function() - local diags = exec_lua([[ - vim.lsp.diagnostic.on_diagnostic(nil, - { - kind = 'full', - items = { - make_error('Pull Diagnostic', 4, 4, 4, 4), - } + local diags = exec_lua(function() + vim.lsp.diagnostic.on_diagnostic(nil, { + kind = 'full', + items = { + _G.make_error('Pull Diagnostic', 4, 4, 4, 4), }, - { - params = { - textDocument = { uri = fake_uri }, - }, - uri = fake_uri, - client_id = client_id, + }, { + params = { + textDocument = { uri = fake_uri }, }, - {} - ) + uri = fake_uri, + client_id = client_id, + }, {}) return vim.diagnostic.get(diagnostic_bufnr) - ]]) + end) eq(1, #diags) eq('Pull Diagnostic', diags[1].message) end) it('severity defaults to error if missing', function() ---@type vim.Diagnostic[] - local diagnostics = exec_lua([[ - vim.lsp.diagnostic.on_diagnostic(nil, - { - kind = 'full', - items = { - { - range = make_range(4, 4, 4, 4), - message = "bad!", - } - } - }, - { - params = { - textDocument = { uri = fake_uri }, + local diagnostics = exec_lua(function() + vim.lsp.diagnostic.on_diagnostic(nil, { + kind = 'full', + items = { + { + range = _G.make_range(4, 4, 4, 4), + message = 'bad!', }, - uri = fake_uri, - client_id = client_id, }, - {} - ) + }, { + params = { + textDocument = { uri = fake_uri }, + }, + uri = fake_uri, + client_id = client_id, + }, {}) return vim.diagnostic.get(diagnostic_bufnr) - ]]) + end) eq(1, #diagnostics) eq(1, diagnostics[1].severity) end) it('allows configuring the virtual text via vim.lsp.with', function() local expected_spacing = 10 - local extmarks = exec_lua( - [[ - Diagnostic = vim.lsp.with(vim.lsp.diagnostic.on_diagnostic, { + local extmarks = exec_lua(function() + _G.Diagnostic = vim.lsp.with(vim.lsp.diagnostic.on_diagnostic, { virtual_text = { - spacing = ..., + spacing = expected_spacing, }, }) - Diagnostic(nil, - { - kind = 'full', - items = { - make_error('Pull Diagnostic', 4, 4, 4, 4), - } + _G.Diagnostic(nil, { + kind = 'full', + items = { + _G.make_error('Pull Diagnostic', 4, 4, 4, 4), }, - { - params = { - textDocument = { uri = fake_uri }, - }, - uri = fake_uri, - client_id = client_id, + }, { + params = { + textDocument = { uri = fake_uri }, }, - {} - ) + uri = fake_uri, + client_id = client_id, + }, {}) - return get_extmarks(diagnostic_bufnr, client_id) - ]], - expected_spacing - ) + return _G.get_extmarks(diagnostic_bufnr, client_id) + end) eq(2, #extmarks) eq(expected_spacing, #extmarks[1][4].virt_text[1][1]) end) it('clears diagnostics when client detaches', function() - exec_lua([[ - vim.lsp.diagnostic.on_diagnostic(nil, - { - kind = 'full', - items = { - make_error('Pull Diagnostic', 4, 4, 4, 4), - } + exec_lua(function() + vim.lsp.diagnostic.on_diagnostic(nil, { + kind = 'full', + items = { + _G.make_error('Pull Diagnostic', 4, 4, 4, 4), }, - { - params = { - textDocument = { uri = fake_uri }, - }, - uri = fake_uri, - client_id = client_id, + }, { + params = { + textDocument = { uri = fake_uri }, }, - {} - ) - ]]) - local diags = exec_lua([[return vim.diagnostic.get(diagnostic_bufnr)]]) - eq(1, #diags) + uri = fake_uri, + client_id = client_id, + }, {}) + end) + + eq( + 1, + exec_lua(function() + return #vim.diagnostic.get(diagnostic_bufnr) + end) + ) - exec_lua([[ vim.lsp.stop_client(client_id) ]]) + exec_lua(function() + vim.lsp.stop_client(client_id) + end) - diags = exec_lua([[return vim.diagnostic.get(diagnostic_bufnr)]]) - eq(0, #diags) + eq( + 0, + exec_lua(function() + return #vim.diagnostic.get(diagnostic_bufnr) + end) + ) end) it('keeps diagnostics when one client detaches and others still are attached', function() - exec_lua([[ - client_id2 = vim.lsp.start({ name = 'dummy2', cmd = server.cmd }) - - vim.lsp.diagnostic.on_diagnostic(nil, - { - kind = 'full', - items = { - make_error('Pull Diagnostic', 4, 4, 4, 4), - } + local client_id2 + exec_lua(function() + client_id2 = vim.lsp.start({ name = 'dummy2', cmd = _G.server.cmd }) + + vim.lsp.diagnostic.on_diagnostic(nil, { + kind = 'full', + items = { + _G.make_error('Pull Diagnostic', 4, 4, 4, 4), }, - { - params = { - textDocument = { uri = fake_uri }, - }, - uri = fake_uri, - client_id = client_id, + }, { + params = { + textDocument = { uri = fake_uri }, }, - {} - ) - ]]) - local diags = exec_lua([[return vim.diagnostic.get(diagnostic_bufnr)]]) - eq(1, #diags) + uri = fake_uri, + client_id = client_id, + }, {}) + end) + + eq( + 1, + exec_lua(function() + return #vim.diagnostic.get(diagnostic_bufnr) + end) + ) - exec_lua([[ vim.lsp.stop_client(client_id2) ]]) + exec_lua(function() + vim.lsp.stop_client(client_id2) + end) - diags = exec_lua([[return vim.diagnostic.get(diagnostic_bufnr)]]) - eq(1, #diags) + eq( + 1, + exec_lua(function() + return #vim.diagnostic.get(diagnostic_bufnr) + end) + ) end) end) end) diff --git a/test/functional/plugin/lsp/handler_spec.lua b/test/functional/plugin/lsp/handler_spec.lua index 013a5fb5e7..4b05b676a8 100644 --- a/test/functional/plugin/lsp/handler_spec.lua +++ b/test/functional/plugin/lsp/handler_spec.lua @@ -11,28 +11,31 @@ describe('lsp-handlers', function() it('should return a table with the default keys', function() eq( { hello = 'world' }, - exec_lua [[ - return vim.lsp._with_extend('test', { hello = 'world' }) - ]] + exec_lua(function() + return vim.lsp._with_extend('test', { hello = 'world' }) + end) ) end) it('should override with config keys', function() eq( { hello = 'universe', other = true }, - exec_lua [[ - return vim.lsp._with_extend('test', { other = true, hello = 'world' }, { hello = 'universe' }) - ]] + exec_lua(function() + return vim.lsp._with_extend( + 'test', + { other = true, hello = 'world' }, + { hello = 'universe' } + ) + end) ) end) it('should not allow invalid keys', function() matches( '.*Invalid option for `test`.*', - pcall_err( - exec_lua, - "return vim.lsp._with_extend('test', { hello = 'world' }, { invalid = true })" - ) + pcall_err(exec_lua, function() + return vim.lsp._with_extend('test', { hello = 'world' }, { invalid = true }) + end) ) end) end) diff --git a/test/functional/plugin/lsp/incremental_sync_spec.lua b/test/functional/plugin/lsp/incremental_sync_spec.lua index 1e463d5117..f60e159d64 100644 --- a/test/functional/plugin/lsp/incremental_sync_spec.lua +++ b/test/functional/plugin/lsp/incremental_sync_spec.lua @@ -10,11 +10,9 @@ local feed = n.feed before_each(function() clear() - exec_lua [[ - local evname = ... + exec_lua(function() local sync = require('vim.lsp.sync') local events = {} - local buffer_cache = {} -- local format_line_ending = { -- ["unix"] = '\n', @@ -24,35 +22,43 @@ before_each(function() -- local line_ending = format_line_ending[vim.api.nvim_get_option_value('fileformat', {})] - - function test_register(bufnr, id, offset_encoding, line_ending) - local curr_lines + --- @diagnostic disable-next-line:duplicate-set-field + function _G.test_register(bufnr, id, offset_encoding, line_ending) local prev_lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, true) - local function callback(_, bufnr, changedtick, firstline, lastline, new_lastline) - if test_unreg == id then + local function callback(_, bufnr0, _changedtick, firstline, lastline, new_lastline) + if _G.test_unreg == id then return true end - local curr_lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, true) + local curr_lines = vim.api.nvim_buf_get_lines(bufnr0, 0, -1, true) local incremental_change = sync.compute_diff( - prev_lines, curr_lines, firstline, lastline, new_lastline, offset_encoding, line_ending) + prev_lines, + curr_lines, + firstline, + lastline, + new_lastline, + offset_encoding, + line_ending + ) table.insert(events, incremental_change) prev_lines = curr_lines end - local opts = {on_lines=callback, on_detach=callback, on_reload=callback} + local opts = { on_lines = callback, on_detach = callback, on_reload = callback } vim.api.nvim_buf_attach(bufnr, false, opts) end - function get_events() + --- @diagnostic disable-next-line:duplicate-set-field + function _G.get_events() local ret_events = events events = {} return ret_events end - ]] + end) end) +--- @param edit_operations string[] local function test_edit( prev_buffer, edit_operations, @@ -64,13 +70,22 @@ local function test_edit( line_ending = line_ending or '\n' api.nvim_buf_set_lines(0, 0, -1, true, prev_buffer) - exec_lua('return test_register(...)', 0, 'test1', offset_encoding, line_ending) + exec_lua(function() + return _G.test_register(0, 'test1', offset_encoding, line_ending) + end) for _, edit in ipairs(edit_operations) do feed(edit) end - eq(expected_text_changes, exec_lua('return get_events(...)')) - exec_lua("test_unreg = 'test1'") + eq( + expected_text_changes, + exec_lua(function() + return _G.get_events() + end) + ) + exec_lua(function() + _G.test_unreg = 'test1' + end) end describe('incremental synchronization', function() diff --git a/test/functional/plugin/lsp/inlay_hint_spec.lua b/test/functional/plugin/lsp/inlay_hint_spec.lua index 00f79b9963..471f2cc3e8 100644 --- a/test/functional/plugin/lsp/inlay_hint_spec.lua +++ b/test/functional/plugin/lsp/inlay_hint_spec.lua @@ -57,36 +57,39 @@ int main() { --- @type test.functional.ui.screen local screen + + --- @type integer + local client_id + + --- @type integer + local bufnr + before_each(function() clear_notrace() screen = Screen.new(50, 9) screen:attach() + bufnr = n.api.nvim_get_current_buf() exec_lua(create_server_definition) - exec_lua( - [[ - local response = ... - server = _create_server({ - capabilities = { - inlayHintProvider = true, - }, - handlers = { - ['textDocument/inlayHint'] = function(_, _, callback) - callback(nil, vim.json.decode(response)) - end, - } - }) - - bufnr = vim.api.nvim_get_current_buf() - vim.api.nvim_win_set_buf(0, bufnr) + client_id = exec_lua(function() + _G.server = _G._create_server({ + capabilities = { + inlayHintProvider = true, + }, + handlers = { + ['textDocument/inlayHint'] = function(_, _, callback) + callback(nil, vim.json.decode(response)) + end, + }, + }) - client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) - ]], - response - ) + return vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd }) + end) insert(text) - exec_lua([[vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })]]) + exec_lua(function() + vim.lsp.inlay_hint.enable(true, { bufnr = bufnr }) + end) screen:expect({ grid = grid_with_inlay_hints }) end) @@ -95,13 +98,15 @@ int main() { end) it('clears inlay hints when sole client detaches', function() - exec_lua([[vim.lsp.stop_client(client_id)]]) + exec_lua(function() + vim.lsp.stop_client(client_id) + end) screen:expect({ grid = grid_without_inlay_hints, unchanged = true }) end) it('does not clear inlay hints when one of several clients detaches', function() - exec_lua([[ - server2 = _create_server({ + local client_id2 = exec_lua(function() + _G.server2 = _G._create_server({ capabilities = { inlayHintProvider = true, }, @@ -109,13 +114,16 @@ int main() { ['textDocument/inlayHint'] = function(_, _, callback) callback(nil, {}) end, - } + }, }) - client2 = vim.lsp.start({ name = 'dummy2', cmd = server2.cmd }) + local client_id2 = vim.lsp.start({ name = 'dummy2', cmd = _G.server2.cmd }) vim.lsp.inlay_hint.enable(true, { bufnr = bufnr }) - ]]) + return client_id2 + end) - exec_lua([[ vim.lsp.stop_client(client2) ]]) + exec_lua(function() + vim.lsp.stop_client(client_id2) + end) screen:expect({ grid = grid_with_inlay_hints, unchanged = true }) end) @@ -123,61 +131,85 @@ int main() { it('validation', function() t.matches( 'enable: expected boolean, got table', - t.pcall_err(exec_lua, [[vim.lsp.inlay_hint.enable({}, { bufnr = bufnr })]]) + t.pcall_err(exec_lua, function() + --- @diagnostic disable-next-line:param-type-mismatch + vim.lsp.inlay_hint.enable({}, { bufnr = bufnr }) + end) ) t.matches( 'enable: expected boolean, got number', - t.pcall_err(exec_lua, [[vim.lsp.inlay_hint.enable(42)]]) + t.pcall_err(exec_lua, function() + --- @diagnostic disable-next-line:param-type-mismatch + vim.lsp.inlay_hint.enable(42) + end) ) t.matches( 'filter: expected table, got number', - t.pcall_err(exec_lua, [[vim.lsp.inlay_hint.enable(true, 42)]]) + t.pcall_err(exec_lua, function() + --- @diagnostic disable-next-line:param-type-mismatch + vim.lsp.inlay_hint.enable(true, 42) + end) ) end) describe('clears/applies inlay hints when passed false/true/nil', function() + local bufnr2 --- @type integer before_each(function() - exec_lua([[ - bufnr2 = vim.api.nvim_create_buf(true, false) - vim.lsp.buf_attach_client(bufnr2, client_id) - vim.api.nvim_win_set_buf(0, bufnr2) - ]]) + bufnr2 = exec_lua(function() + local bufnr2_0 = vim.api.nvim_create_buf(true, false) + vim.lsp.buf_attach_client(bufnr2_0, client_id) + vim.api.nvim_win_set_buf(0, bufnr2_0) + return bufnr2_0 + end) insert(text) - exec_lua([[vim.lsp.inlay_hint.enable(true, { bufnr = bufnr2 })]]) - exec_lua([[vim.api.nvim_win_set_buf(0, bufnr)]]) + exec_lua(function() + vim.lsp.inlay_hint.enable(true, { bufnr = bufnr2 }) + end) + n.api.nvim_win_set_buf(0, bufnr) screen:expect({ grid = grid_with_inlay_hints }) end) it('for one single buffer', function() - exec_lua([[ + exec_lua(function() vim.lsp.inlay_hint.enable(false, { bufnr = bufnr }) vim.api.nvim_win_set_buf(0, bufnr2) - ]]) + end) screen:expect({ grid = grid_with_inlay_hints, unchanged = true }) - exec_lua([[vim.api.nvim_win_set_buf(0, bufnr)]]) + n.api.nvim_win_set_buf(0, bufnr) screen:expect({ grid = grid_without_inlay_hints, unchanged = true }) - exec_lua([[vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })]]) + exec_lua(function() + vim.lsp.inlay_hint.enable(true, { bufnr = bufnr }) + end) screen:expect({ grid = grid_with_inlay_hints, unchanged = true }) - exec_lua( - [[vim.lsp.inlay_hint.enable(not vim.lsp.inlay_hint.is_enabled({ bufnr = bufnr }), { bufnr = bufnr })]] - ) + exec_lua(function() + vim.lsp.inlay_hint.enable( + not vim.lsp.inlay_hint.is_enabled({ bufnr = bufnr }), + { bufnr = bufnr } + ) + end) screen:expect({ grid = grid_without_inlay_hints, unchanged = true }) - exec_lua([[vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })]]) + exec_lua(function() + vim.lsp.inlay_hint.enable(true, { bufnr = bufnr }) + end) screen:expect({ grid = grid_with_inlay_hints, unchanged = true }) end) it('for all buffers', function() - exec_lua([[vim.lsp.inlay_hint.enable(false)]]) + exec_lua(function() + vim.lsp.inlay_hint.enable(false) + end) screen:expect({ grid = grid_without_inlay_hints, unchanged = true }) - exec_lua([[vim.api.nvim_win_set_buf(0, bufnr2)]]) + n.api.nvim_win_set_buf(0, bufnr2) screen:expect({ grid = grid_without_inlay_hints, unchanged = true }) - exec_lua([[vim.lsp.inlay_hint.enable(true)]]) + exec_lua(function() + vim.lsp.inlay_hint.enable(true) + end) screen:expect({ grid = grid_with_inlay_hints, unchanged = true }) - exec_lua([[vim.api.nvim_win_set_buf(0, bufnr)]]) + n.api.nvim_win_set_buf(0, bufnr) screen:expect({ grid = grid_with_inlay_hints, unchanged = true }) end) end) @@ -198,10 +230,8 @@ int main() { paddingRight = false, } - exec_lua( - [[ - local expected2 = ... - server2 = _create_server({ + exec_lua(function() + _G.server2 = _G._create_server({ capabilities = { inlayHintProvider = true, }, @@ -209,52 +239,63 @@ int main() { ['textDocument/inlayHint'] = function(_, _, callback) callback(nil, { expected2 }) end, - } + }, }) - client2 = vim.lsp.start({ name = 'dummy2', cmd = server2.cmd }) + _G.client2 = vim.lsp.start({ name = 'dummy2', cmd = _G.server2.cmd }) vim.lsp.inlay_hint.enable(true, { bufnr = bufnr }) - ]], - expected2 - ) + end) --- @type vim.lsp.inlay_hint.get.ret - local res = exec_lua([[return vim.lsp.inlay_hint.get()]]) - eq({ - { bufnr = 1, client_id = 1, inlay_hint = expected[1] }, - { bufnr = 1, client_id = 1, inlay_hint = expected[2] }, - { bufnr = 1, client_id = 1, inlay_hint = expected[3] }, - { bufnr = 1, client_id = 2, inlay_hint = expected2 }, - }, res) + eq( + { + { bufnr = 1, client_id = 1, inlay_hint = expected[1] }, + { bufnr = 1, client_id = 1, inlay_hint = expected[2] }, + { bufnr = 1, client_id = 1, inlay_hint = expected[3] }, + { bufnr = 1, client_id = 2, inlay_hint = expected2 }, + }, + exec_lua(function() + return vim.lsp.inlay_hint.get() + end) + ) - --- @type vim.lsp.inlay_hint.get.ret - res = exec_lua([[return vim.lsp.inlay_hint.get({ - range = { - start = { line = 2, character = 10 }, - ["end"] = { line = 2, character = 10 }, + eq( + { + { bufnr = 1, client_id = 2, inlay_hint = expected2 }, }, - })]]) - eq({ - { bufnr = 1, client_id = 2, inlay_hint = expected2 }, - }, res) + exec_lua(function() + return vim.lsp.inlay_hint.get({ + range = { + start = { line = 2, character = 10 }, + ['end'] = { line = 2, character = 10 }, + }, + }) + end) + ) - --- @type vim.lsp.inlay_hint.get.ret - res = exec_lua([[return vim.lsp.inlay_hint.get({ - bufnr = vim.api.nvim_get_current_buf(), - range = { - start = { line = 4, character = 18 }, - ["end"] = { line = 5, character = 17 }, + eq( + { + { bufnr = 1, client_id = 1, inlay_hint = expected[2] }, + { bufnr = 1, client_id = 1, inlay_hint = expected[3] }, }, - })]]) - eq({ - { bufnr = 1, client_id = 1, inlay_hint = expected[2] }, - { bufnr = 1, client_id = 1, inlay_hint = expected[3] }, - }, res) + exec_lua(function() + return vim.lsp.inlay_hint.get({ + bufnr = vim.api.nvim_get_current_buf(), + range = { + start = { line = 4, character = 18 }, + ['end'] = { line = 5, character = 17 }, + }, + }) + end) + ) - --- @type vim.lsp.inlay_hint.get.ret - res = exec_lua([[return vim.lsp.inlay_hint.get({ - bufnr = vim.api.nvim_get_current_buf() + 1, - })]]) - eq({}, res) + eq( + {}, + exec_lua(function() + return vim.lsp.inlay_hint.get({ + bufnr = vim.api.nvim_get_current_buf() + 1, + }) + end) + ) end) end) end) @@ -288,40 +329,45 @@ test text --- @type test.functional.ui.screen local screen + + --- @type integer + local client_id + + --- @type integer + local bufnr + before_each(function() clear_notrace() screen = Screen.new(50, 3) screen:attach() exec_lua(create_server_definition) - exec_lua( - [[ - local response = ... - server = _create_server({ - capabilities = { - inlayHintProvider = true, - }, - handlers = { - ['textDocument/inlayHint'] = function(_, _, callback) - callback(nil, vim.json.decode(response)) - end, - } - }) + bufnr = n.api.nvim_get_current_buf() + client_id = exec_lua(function() + _G.server = _G._create_server({ + capabilities = { + inlayHintProvider = true, + }, + handlers = { + ['textDocument/inlayHint'] = function(_, _, callback) + callback(nil, vim.json.decode(response)) + end, + }, + }) - bufnr = vim.api.nvim_get_current_buf() - vim.api.nvim_win_set_buf(0, bufnr) + vim.api.nvim_win_set_buf(0, bufnr) - client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) - ]], - response - ) + return vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd }) + end) insert(text) end) it('renders hints with same position in received order', function() exec_lua([[vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })]]) screen:expect({ grid = grid_with_inlay_hints }) - exec_lua([[vim.lsp.stop_client(client_id)]]) + exec_lua(function() + vim.lsp.stop_client(client_id) + end) screen:expect({ grid = grid_without_inlay_hints, unchanged = true }) end) diff --git a/test/functional/plugin/lsp/semantic_tokens_spec.lua b/test/functional/plugin/lsp/semantic_tokens_spec.lua index 9babb080e7..f72aab7e0b 100644 --- a/test/functional/plugin/lsp/semantic_tokens_spec.lua +++ b/test/functional/plugin/lsp/semantic_tokens_spec.lua @@ -25,7 +25,7 @@ after_each(function() end) describe('semantic token highlighting', function() - local screen + local screen --- @type test.functional.ui.screen before_each(function() screen = Screen.new(40, 16) screen:attach() @@ -84,10 +84,8 @@ describe('semantic token highlighting', function() before_each(function() exec_lua(create_server_definition) - exec_lua( - [[ - local legend, response, edit_response = ... - server = _create_server({ + exec_lua(function() + _G.server = _G._create_server({ capabilities = { semanticTokensProvider = { full = { delta = true }, @@ -101,23 +99,19 @@ describe('semantic token highlighting', function() ['textDocument/semanticTokens/full/delta'] = function(_, _, callback) callback(nil, vim.fn.json_decode(edit_response)) end, - } + }, }) - ]], - legend, - response, - edit_response - ) + end, legend, response, edit_response) end) it('buffer is highlighted when attached', function() insert(text) - exec_lua([[ - bufnr = vim.api.nvim_get_current_buf() + exec_lua(function() + local bufnr = vim.api.nvim_get_current_buf() vim.api.nvim_win_set_buf(0, bufnr) vim.bo[bufnr].filetype = 'some-filetype' - client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) - ]]) + vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd }) + end) screen:expect { grid = [[ @@ -141,21 +135,19 @@ describe('semantic token highlighting', function() it('use LspTokenUpdate and highlight_token', function() insert(text) - exec_lua([[ - vim.api.nvim_create_autocmd("LspTokenUpdate", { + exec_lua(function() + vim.api.nvim_create_autocmd('LspTokenUpdate', { callback = function(args) - local token = args.data.token - if token.type == "function" and token.modifiers.declaration then - vim.lsp.semantic_tokens.highlight_token( - token, args.buf, args.data.client_id, "Macro" - ) + local token = args.data.token --- @type STTokenRange + if token.type == 'function' and token.modifiers.declaration then + vim.lsp.semantic_tokens.highlight_token(token, args.buf, args.data.client_id, 'Macro') end end, }) - bufnr = vim.api.nvim_get_current_buf() + local bufnr = vim.api.nvim_get_current_buf() vim.api.nvim_win_set_buf(0, bufnr) - client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) - ]]) + vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd }) + end) screen:expect { grid = [[ @@ -180,19 +172,21 @@ describe('semantic token highlighting', function() it('buffer is unhighlighted when client is detached', function() insert(text) - exec_lua([[ - bufnr = vim.api.nvim_get_current_buf() + local bufnr = n.api.nvim_get_current_buf() + local client_id = exec_lua(function() vim.api.nvim_win_set_buf(0, bufnr) - client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) + local client_id = vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd }) vim.wait(1000, function() - return #server.messages > 1 + return #_G.server.messages > 1 end) - ]]) + return client_id + end) - exec_lua([[ + exec_lua(function() + --- @diagnostic disable-next-line:duplicate-set-field vim.notify = function() end vim.lsp.buf_detach_client(bufnr, client_id) - ]]) + end) screen:expect { grid = [[ @@ -217,18 +211,19 @@ describe('semantic token highlighting', function() it( 'buffer is highlighted and unhighlighted when semantic token highlighting is started and stopped', function() - exec_lua([[ - bufnr = vim.api.nvim_get_current_buf() - vim.api.nvim_win_set_buf(0, bufnr) - client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) - ]]) + local bufnr = n.api.nvim_get_current_buf() + local client_id = exec_lua(function() + vim.api.nvim_win_set_buf(0, bufnr) + return vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd }) + end) insert(text) - exec_lua([[ - vim.notify = function() end - vim.lsp.semantic_tokens.stop(bufnr, client_id) - ]]) + exec_lua(function() + --- @diagnostic disable-next-line:duplicate-set-field + vim.notify = function() end + vim.lsp.semantic_tokens.stop(bufnr, client_id) + end) screen:expect { grid = [[ @@ -249,9 +244,9 @@ describe('semantic token highlighting', function() ]], } - exec_lua([[ - vim.lsp.semantic_tokens.start(bufnr, client_id) - ]]) + exec_lua(function() + vim.lsp.semantic_tokens.start(bufnr, client_id) + end) screen:expect { grid = [[ @@ -275,18 +270,17 @@ describe('semantic token highlighting', function() ) it('highlights start and stop when using "0" for current buffer', function() - exec_lua([[ - bufnr = vim.api.nvim_get_current_buf() - vim.api.nvim_win_set_buf(0, bufnr) - client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) - ]]) + local client_id = exec_lua(function() + return vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd }) + end) insert(text) - exec_lua([[ + exec_lua(function() + --- @diagnostic disable-next-line:duplicate-set-field vim.notify = function() end vim.lsp.semantic_tokens.stop(0, client_id) - ]]) + end) screen:expect { grid = [[ @@ -307,9 +301,9 @@ describe('semantic token highlighting', function() ]], } - exec_lua([[ + exec_lua(function() vim.lsp.semantic_tokens.start(0, client_id) - ]]) + end) screen:expect { grid = [[ @@ -333,11 +327,9 @@ describe('semantic token highlighting', function() it('buffer is re-highlighted when force refreshed', function() insert(text) - exec_lua([[ - bufnr = vim.api.nvim_get_current_buf() - vim.api.nvim_win_set_buf(0, bufnr) - client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) - ]]) + exec_lua(function() + vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd }) + end) screen:expect { grid = [[ @@ -358,9 +350,9 @@ describe('semantic token highlighting', function() ]], } - exec_lua([[ - vim.lsp.semantic_tokens.force_refresh(bufnr) - ]]) + exec_lua(function() + vim.lsp.semantic_tokens.force_refresh() + end) screen:expect { grid = [[ @@ -384,7 +376,9 @@ describe('semantic token highlighting', function() local messages = exec_lua('return server.messages') local token_request_count = 0 - for _, message in ipairs(messages) do + for _, message in + ipairs(messages --[[@as {method:string,params:table}[] ]]) + do assert(message.method ~= 'textDocument/semanticTokens/full/delta', 'delta request received') if message.method == 'textDocument/semanticTokens/full' then token_request_count = token_request_count + 1 @@ -394,31 +388,28 @@ describe('semantic token highlighting', function() end) it('destroys the highlighter if the buffer is deleted', function() - exec_lua([[ - bufnr = vim.api.nvim_get_current_buf() - vim.api.nvim_win_set_buf(0, bufnr) - client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) - ]]) + exec_lua(function() + vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd }) + end) insert(text) - local highlighters = exec_lua([[ - vim.api.nvim_buf_delete(bufnr, { force = true }) - local semantic_tokens = vim.lsp.semantic_tokens - return semantic_tokens.__STHighlighter.active - ]]) - - eq({}, highlighters) + eq( + {}, + exec_lua(function() + local bufnr = vim.api.nvim_get_current_buf() + vim.api.nvim_buf_delete(bufnr, { force = true }) + return vim.lsp.semantic_tokens.__STHighlighter.active + end) + ) end) it('updates highlights with delta request on buffer change', function() insert(text) - exec_lua([[ - bufnr = vim.api.nvim_get_current_buf() - vim.api.nvim_win_set_buf(0, bufnr) - client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) - ]]) + exec_lua(function() + vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd }) + end) screen:expect { grid = [[ @@ -460,45 +451,49 @@ describe('semantic token highlighting', function() end) it('prevents starting semantic token highlighting with invalid conditions', function() - exec_lua([[ - bufnr = vim.api.nvim_get_current_buf() - vim.api.nvim_win_set_buf(0, bufnr) - client_id = vim.lsp.start_client({ name = 'dummy', cmd = server.cmd }) - notifications = {} - vim.notify = function(...) table.insert(notifications, 1, {...}) end - ]]) - eq(false, exec_lua('return vim.lsp.buf_is_attached(bufnr, client_id)')) + local client_id = exec_lua(function() + _G.notifications = {} + --- @diagnostic disable-next-line:duplicate-set-field + vim.notify = function(...) + table.insert(_G.notifications, 1, { ... }) + end + return vim.lsp.start_client({ name = 'dummy', cmd = _G.server.cmd }) + end) + eq(false, exec_lua('return vim.lsp.buf_is_attached(0, ...)', client_id)) insert(text) - local notifications = exec_lua([[ - vim.lsp.semantic_tokens.start(bufnr, client_id) - return notifications - ]]) - matches('%[LSP%] Client with id %d not attached to buffer %d', notifications[1][1]) - - notifications = exec_lua([[ - vim.lsp.semantic_tokens.start(bufnr, client_id + 1) - return notifications - ]]) - matches('%[LSP%] No client with id %d', notifications[1][1]) + matches( + '%[LSP%] Client with id %d not attached to buffer %d', + exec_lua(function() + vim.lsp.semantic_tokens.start(0, client_id) + return _G.notifications[1][1] + end) + ) + + matches( + '%[LSP%] No client with id %d', + exec_lua(function() + vim.lsp.semantic_tokens.start(0, client_id + 1) + return _G.notifications[1][1] + end) + ) end) it( 'opt-out: does not activate semantic token highlighting if disabled in client attach', function() - exec_lua([[ - bufnr = vim.api.nvim_get_current_buf() - vim.api.nvim_win_set_buf(0, bufnr) - client_id = vim.lsp.start({ + local client_id = exec_lua(function() + return vim.lsp.start({ name = 'dummy', - cmd = server.cmd, - on_attach = vim.schedule_wrap(function(client, bufnr) + cmd = _G.server.cmd, + --- @param client vim.lsp.Client + on_attach = vim.schedule_wrap(function(client, _bufnr) client.server_capabilities.semanticTokensProvider = nil end), }) - ]]) - eq(true, exec_lua('return vim.lsp.buf_is_attached(bufnr, client_id)')) + end) + eq(true, exec_lua('return vim.lsp.buf_is_attached(0, ...)', client_id)) insert(text) @@ -521,13 +516,18 @@ describe('semantic token highlighting', function() ]], } - local notifications = exec_lua([[ - local notifications = {} - vim.notify = function(...) table.insert(notifications, 1, {...}) end - vim.lsp.semantic_tokens.start(bufnr, client_id) - return notifications - ]]) - eq('[LSP] Server does not support semantic tokens', notifications[1][1]) + eq( + '[LSP] Server does not support semantic tokens', + exec_lua(function() + local notifications = {} + --- @diagnostic disable-next-line:duplicate-set-field + vim.notify = function(...) + table.insert(notifications, 1, { ... }) + end + vim.lsp.semantic_tokens.start(0, client_id) + return notifications[1][1] + end) + ) screen:expect { grid = [[ @@ -552,28 +552,32 @@ describe('semantic token highlighting', function() ) it('ignores null responses from the server', function() - exec_lua([[ - local legend, response, edit_response = ... - server2 = _create_server({ + local client_id = exec_lua(function() + _G.server2 = _G._create_server({ capabilities = { semanticTokensProvider = { full = { delta = false }, }, }, handlers = { + --- @param callback function ['textDocument/semanticTokens/full'] = function(_, _, callback) callback(nil, nil) end, - ['textDocument/semanticTokens/full/delta'] = function() + --- @param callback function + ['textDocument/semanticTokens/full/delta'] = function(_, _, callback) callback(nil, nil) end, - } + }, }) - bufnr = vim.api.nvim_get_current_buf() - vim.api.nvim_win_set_buf(0, bufnr) - client_id = vim.lsp.start({ name = 'dummy', cmd = server2.cmd }) - ]]) - eq(true, exec_lua('return vim.lsp.buf_is_attached(bufnr, client_id)')) + return vim.lsp.start({ name = 'dummy', cmd = _G.server2.cmd }) + end) + eq( + true, + exec_lua(function() + return vim.lsp.buf_is_attached(0, client_id) + end) + ) insert(text) @@ -599,10 +603,8 @@ describe('semantic token highlighting', function() it('does not send delta requests if not supported by server', function() insert(text) - exec_lua( - [[ - local legend, response, edit_response = ... - server2 = _create_server({ + exec_lua(function() + _G.server2 = _G._create_server({ capabilities = { semanticTokensProvider = { full = { delta = false }, @@ -616,16 +618,10 @@ describe('semantic token highlighting', function() ['textDocument/semanticTokens/full/delta'] = function(_, _, callback) callback(nil, vim.fn.json_decode(edit_response)) end, - } + }, }) - bufnr = vim.api.nvim_get_current_buf() - vim.api.nvim_win_set_buf(0, bufnr) - client_id = vim.lsp.start({ name = 'dummy', cmd = server2.cmd }) - ]], - legend, - response, - edit_response - ) + return vim.lsp.start({ name = 'dummy', cmd = _G.server2.cmd }) + end) screen:expect { grid = [[ @@ -670,7 +666,9 @@ describe('semantic token highlighting', function() } local messages = exec_lua('return server2.messages') local token_request_count = 0 - for _, message in ipairs(messages) do + for _, message in + ipairs(messages --[[@as {method:string,params:table}[] ]]) + do assert(message.method ~= 'textDocument/semanticTokens/full/delta', 'delta request received') if message.method == 'textDocument/semanticTokens/full' then token_request_count = token_request_count + 1 @@ -1065,10 +1063,8 @@ b = "as"]], }) do it(test.it, function() exec_lua(create_server_definition) - exec_lua( - [[ - local legend, resp = ... - server = _create_server({ + local client_id = exec_lua(function(legend, resp) + _G.server = _G._create_server({ capabilities = { semanticTokensProvider = { full = { delta = false }, @@ -1079,25 +1075,22 @@ b = "as"]], ['textDocument/semanticTokens/full'] = function(_, _, callback) callback(nil, vim.fn.json_decode(resp)) end, - } + }, }) - bufnr = vim.api.nvim_get_current_buf() - vim.api.nvim_win_set_buf(0, bufnr) - client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) - ]], - test.legend, - test.response - ) + return vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd }) + end, test.legend, test.response) insert(test.text) test.expected_screen() - local highlights = exec_lua([[ - local semantic_tokens = vim.lsp.semantic_tokens - return semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights - ]]) - eq(test.expected, highlights) + eq( + test.expected, + exec_lua(function() + local bufnr = vim.api.nvim_get_current_buf() + return vim.lsp.semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights + end) + ) end) end end) @@ -1450,12 +1443,11 @@ int main() }, }) do it(test.it, function() + local bufnr = n.api.nvim_get_current_buf() insert(test.text1) exec_lua(create_server_definition) - exec_lua( - [[ - local legend, resp1, resp2 = ... - server = _create_server({ + local client_id = exec_lua(function(legend, resp1, resp2) + _G.server = _G._create_server({ capabilities = { semanticTokensProvider = { full = { delta = true }, @@ -1469,52 +1461,44 @@ int main() ['textDocument/semanticTokens/full/delta'] = function(_, _, callback) callback(nil, vim.fn.json_decode(resp2)) end, - } + }, }) - bufnr = vim.api.nvim_get_current_buf() - vim.api.nvim_win_set_buf(0, bufnr) - client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) + local client_id = assert(vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })) -- speed up vim.api.nvim_buf_set_lines calls by changing debounce to 10 for these tests - semantic_tokens = vim.lsp.semantic_tokens vim.schedule(function() - semantic_tokens.stop(bufnr, client_id) - semantic_tokens.start(bufnr, client_id, { debounce = 10 }) + vim.lsp.semantic_tokens.stop(bufnr, client_id) + vim.lsp.semantic_tokens.start(bufnr, client_id, { debounce = 10 }) end) - ]], - test.legend, - test.response1, - test.response2 - ) + return client_id + end, test.legend, test.response1, test.response2) test.expected_screen1() - local highlights = exec_lua([[ - return semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights - ]]) - - eq(test.expected1, highlights) + eq( + test.expected1, + exec_lua(function() + return vim.lsp.semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights + end) + ) if test.edit then feed(test.edit) else - exec_lua( - [[ - local text = ... - vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, vim.fn.split(text, "\n")) + exec_lua(function(text) + vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, vim.fn.split(text, '\n')) vim.wait(15) -- wait for debounce - ]], - test.text2 - ) + end, test.text2) end test.expected_screen2() - highlights = exec_lua([[ - return semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights - ]]) - - eq(test.expected2, highlights) + eq( + test.expected2, + exec_lua(function() + return vim.lsp.semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights + end) + ) end) end end) diff --git a/test/functional/plugin/lsp/testutil.lua b/test/functional/plugin/lsp/testutil.lua index f60d111f87..a36cbac568 100644 --- a/test/functional/plugin/lsp/testutil.lua +++ b/test/functional/plugin/lsp/testutil.lua @@ -108,61 +108,55 @@ M.fake_lsp_code = 'test/functional/fixtures/fake-lsp-server.lua' M.fake_lsp_logfile = 'Xtest-fake-lsp.log' local function fake_lsp_server_setup(test_name, timeout_ms, options, settings) - exec_lua( - function(test_name0, fake_lsp_code0, fake_lsp_logfile0, timeout, options0, settings0) - _G.lsp = require('vim.lsp') - _G.TEST_RPC_CLIENT_ID = _G.lsp.start_client { - cmd_env = { - NVIM_LOG_FILE = fake_lsp_logfile0, - NVIM_LUA_NOTRACK = '1', - NVIM_APPNAME = 'nvim_lsp_test', - }, - cmd = { - vim.v.progpath, - '-l', - fake_lsp_code0, - test_name0, - tostring(timeout), - }, - handlers = setmetatable({}, { - __index = function(_t, _method) - return function(...) - return vim.rpcrequest(1, 'handler', ...) - end - end, - }), - workspace_folders = { - { - uri = 'file://' .. vim.uv.cwd(), - name = 'test_folder', - }, - }, - before_init = function(_params, _config) - vim.schedule(function() - vim.rpcrequest(1, 'setup') - end) - end, - on_init = function(client, result) - _G.TEST_RPC_CLIENT = client - vim.rpcrequest(1, 'init', result) + exec_lua(function(fake_lsp_code, fake_lsp_logfile, timeout) + options = options or {} + settings = settings or {} + _G.lsp = require('vim.lsp') + _G.TEST_RPC_CLIENT_ID = _G.lsp.start_client { + cmd_env = { + NVIM_LOG_FILE = fake_lsp_logfile, + NVIM_LUA_NOTRACK = '1', + NVIM_APPNAME = 'nvim_lsp_test', + }, + cmd = { + vim.v.progpath, + '-l', + fake_lsp_code, + test_name, + tostring(timeout), + }, + handlers = setmetatable({}, { + __index = function(_t, _method) + return function(...) + return vim.rpcrequest(1, 'handler', ...) + end end, - flags = { - allow_incremental_sync = options0.allow_incremental_sync or false, - debounce_text_changes = options0.debounce_text_changes or 0, + }), + workspace_folders = { + { + uri = 'file://' .. vim.uv.cwd(), + name = 'test_folder', }, - settings = settings0, - on_exit = function(...) - vim.rpcnotify(1, 'exit', ...) - end, - } - end, - test_name, - M.fake_lsp_code, - M.fake_lsp_logfile, - timeout_ms or 1e3, - options or {}, - settings or {} - ) + }, + before_init = function(_params, _config) + vim.schedule(function() + vim.rpcrequest(1, 'setup') + end) + end, + on_init = function(client, result) + _G.TEST_RPC_CLIENT = client + vim.rpcrequest(1, 'init', result) + end, + flags = { + allow_incremental_sync = options.allow_incremental_sync or false, + debounce_text_changes = options.debounce_text_changes or 0, + }, + settings = settings, + on_exit = function(...) + vim.rpcnotify(1, 'exit', ...) + end, + } + end, M.fake_lsp_code, M.fake_lsp_logfile, timeout_ms or 1e3) end --- @class test.lsp.Config @@ -193,13 +187,12 @@ function M.test_rpc_server(config) -- Otherwise I would just return the value here. return function(...) return exec_lua(function(...) - local name0 = ... - if type(_G.TEST_RPC_CLIENT[name0]) == 'function' then - return _G.TEST_RPC_CLIENT[name0](select(2, ...)) + if type(_G.TEST_RPC_CLIENT[name]) == 'function' then + return _G.TEST_RPC_CLIENT[name](...) else - return _G.TEST_RPC_CLIENT[name0] + return _G.TEST_RPC_CLIENT[name] end - end, name, ...) + end, ...) end end, }) diff --git a/test/functional/plugin/lsp/utils_spec.lua b/test/functional/plugin/lsp/utils_spec.lua index 6c6dec0667..c1f56f2722 100644 --- a/test/functional/plugin/lsp/utils_spec.lua +++ b/test/functional/plugin/lsp/utils_spec.lua @@ -11,21 +11,11 @@ describe('vim.lsp.util', function() describe('stylize_markdown', function() local stylize_markdown = function(content, opts) - return exec_lua( - [[ - local bufnr = vim.uri_to_bufnr("file:///fake/uri") + return exec_lua(function() + local bufnr = vim.uri_to_bufnr('file:///fake/uri') vim.fn.bufload(bufnr) - - local args = { ... } - local content = args[1] - local opts = args[2] - local stripped_content = vim.lsp.util.stylize_markdown(bufnr, content, opts) - - return stripped_content - ]], - content, - opts - ) + return vim.lsp.util.stylize_markdown(bufnr, content, opts) + end) end it('code fences', function() @@ -95,7 +85,7 @@ describe('vim.lsp.util', function() describe('normalize_markdown', function() it('collapses consecutive blank lines', function() - local result = exec_lua [[ + local result = exec_lua(function() local lines = { 'foo', '', @@ -103,25 +93,25 @@ describe('vim.lsp.util', function() '', 'bar', '', - 'baz' + 'baz', } return vim.lsp.util._normalize_markdown(lines) - ]] + end) local expected = { 'foo', '', 'bar', '', 'baz' } eq(expected, result) end) it('removes preceding and trailing empty lines', function() - local result = exec_lua [[ + local result = exec_lua(function() local lines = { '', 'foo', 'bar', '', - '' + '', } return vim.lsp.util._normalize_markdown(lines) - ]] + end) local expected = { 'foo', 'bar' } eq(expected, result) end) @@ -129,19 +119,14 @@ describe('vim.lsp.util', function() 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 - ) + local opts = exec_lua(function() + return vim.lsp.util.make_floating_popup_options(30, 10, { anchor_bias = anchor_bias }) + end) eq(expected_anchor, string.sub(opts.anchor, 1, 1)) end - local screen + local screen --- @type test.functional.ui.screen before_each(function() n.clear() screen = Screen.new(80, 80) @@ -221,9 +206,9 @@ describe('vim.lsp.util', function() end) it('bordered window truncates dimensions correctly', function() - local opts = exec_lua([[ + local opts = exec_lua(function() return vim.lsp.util.make_floating_popup_options(100, 100, { border = 'single' }) - ]]) + end) eq(56, opts.height) end) diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 88b0e0c991..9956fdf628 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -36,10 +36,10 @@ local test_rpc_server = t_lsp.test_rpc_server local create_tcp_echo_server = t_lsp.create_tcp_echo_server local function get_buf_option(name, bufnr) - bufnr = bufnr or 'BUFFER' - return exec_lua( - string.format("return vim.api.nvim_get_option_value('%s', { buf = %s })", name, bufnr) - ) + return exec_lua(function() + bufnr = bufnr or _G.BUFFER + return vim.api.nvim_get_option_value(name, { buf = bufnr }) + end) end local function make_edit(y_0, x_0, y_1, x_1, text) @@ -62,7 +62,9 @@ local function apply_text_edits(edits, encoding) end, edits ) - exec_lua('vim.lsp.util.apply_text_edits(...)', edits1, 1, encoding or 'utf-16') + exec_lua(function() + vim.lsp.util.apply_text_edits(edits1, 1, encoding or 'utf-16') + end) end -- TODO(justinmk): hangs on Windows https://github.com/neovim/neovim/pull/11837 @@ -90,19 +92,19 @@ describe('LSP', function() -- Run an instance of nvim on the file which contains our "scripts". -- Pass TEST_NAME to pick the script. local test_name = 'basic_init' - exec_lua(function(test_name0, fake_lsp_code0, fake_lsp_logfile0) + exec_lua(function() _G.lsp = require('vim.lsp') function _G.test__start_client() return vim.lsp.start_client { cmd_env = { - NVIM_LOG_FILE = fake_lsp_logfile0, + NVIM_LOG_FILE = fake_lsp_logfile, NVIM_APPNAME = 'nvim_lsp_test', }, cmd = { vim.v.progpath, '-l', - fake_lsp_code0, - test_name0, + fake_lsp_code, + test_name, }, workspace_folders = { { @@ -113,12 +115,17 @@ describe('LSP', function() } end _G.TEST_CLIENT1 = _G.test__start_client() - end, test_name, fake_lsp_code, fake_lsp_logfile) + end) end) it('start_client(), stop_client()', function() retry(nil, 4000, function() - eq(1, exec_lua('return #lsp.get_clients()')) + eq( + 1, + exec_lua(function() + return #vim.lsp.get_clients() + end) + ) end) eq( 2, @@ -135,20 +142,54 @@ describe('LSP', function() end) ) retry(nil, 4000, function() - eq(3, exec_lua('return #lsp.get_clients()')) + eq( + 3, + exec_lua(function() + return #vim.lsp.get_clients() + end) + ) end) - eq(false, exec_lua('return lsp.get_client_by_id(TEST_CLIENT1) == nil')) - eq(false, exec_lua('return lsp.get_client_by_id(TEST_CLIENT1).is_stopped()')) - exec_lua('return lsp.get_client_by_id(TEST_CLIENT1).stop()') + eq( + false, + exec_lua(function() + return vim.lsp.get_client_by_id(_G.TEST_CLIENT1) == nil + end) + ) + eq( + false, + exec_lua(function() + return vim.lsp.get_client_by_id(_G.TEST_CLIENT1).is_stopped() + end) + ) + exec_lua(function() + return vim.lsp.get_client_by_id(_G.TEST_CLIENT1).stop() + end) retry(nil, 4000, function() - eq(2, exec_lua('return #lsp.get_clients()')) + eq( + 2, + exec_lua(function() + return #vim.lsp.get_clients() + end) + ) end) - eq(true, exec_lua('return lsp.get_client_by_id(TEST_CLIENT1) == nil')) + eq( + true, + exec_lua(function() + return vim.lsp.get_client_by_id(_G.TEST_CLIENT1) == nil + end) + ) - exec_lua('lsp.stop_client({TEST_CLIENT2, TEST_CLIENT3})') + exec_lua(function() + vim.lsp.stop_client({ _G.TEST_CLIENT2, _G.TEST_CLIENT3 }) + end) retry(nil, 4000, function() - eq(0, exec_lua('return #lsp.get_clients()')) + eq( + 0, + exec_lua(function() + return #vim.lsp.get_clients() + end) + ) end) end) @@ -158,12 +199,24 @@ describe('LSP', function() _G.TEST_CLIENT3 = _G.test__start_client() end) retry(nil, 4000, function() - eq(3, exec_lua('return #lsp.get_clients()')) + eq( + 3, + exec_lua(function() + return #vim.lsp.get_clients() + end) + ) end) -- Stop all clients. - exec_lua('lsp.stop_client(lsp.get_clients())') + exec_lua(function() + vim.lsp.stop_client(vim.lsp.get_clients()) + end) retry(nil, 4000, function() - eq(0, exec_lua('return #lsp.get_clients()')) + eq( + 0, + exec_lua(function() + return #vim.lsp.get_clients() + end) + ) end) end) end) @@ -306,10 +359,20 @@ describe('LSP', function() exec_lua(function() _G.BUFFER = vim.api.nvim_create_buf(false, true) end) - eq(true, exec_lua('return lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)')) - eq(true, exec_lua('return lsp.buf_is_attached(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)')) + eq( + true, + exec_lua(function() + return vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID) + end) + ) + eq( + true, + exec_lua(function() + return vim.lsp.buf_is_attached(_G.BUFFER, _G.TEST_RPC_CLIENT_ID) + end) + ) exec_lua(function() - vim.api.nvim_command(_G.BUFFER .. 'bwipeout') + vim.cmd(_G.BUFFER .. 'bwipeout') end) end, on_init = function(_client) @@ -323,8 +386,15 @@ describe('LSP', function() on_handler = function(err, result, ctx) eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler') if ctx.method == 'finish' then - exec_lua('return vim.lsp.buf_detach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)') - eq(false, exec_lua('return vim.lsp.buf_is_attached(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)')) + exec_lua(function() + return vim.lsp.buf_detach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID) + end) + eq( + false, + exec_lua(function() + return vim.lsp.buf_is_attached(_G.BUFFER, _G.TEST_RPC_CLIENT_ID) + end) + ) client.stop() end end, @@ -354,13 +424,20 @@ describe('LSP', function() end, on_init = function(_client) client = _client - eq(true, exec_lua('return vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)')) + eq( + true, + exec_lua(function() + return vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID) + end) + ) client.notify('finish') end, on_handler = function(_, _, ctx) if ctx.method == 'finish' then eq('basic_init', api.nvim_get_var('lsp_attached')) - exec_lua('return vim.lsp.buf_detach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)') + exec_lua(function() + return vim.lsp.buf_detach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID) + end) eq('basic_init', api.nvim_get_var('lsp_detached')) client.stop() end @@ -388,7 +465,7 @@ describe('LSP', function() eq( true, exec_lua(function() - local keymap + local keymap --- @type table vim._with({ buf = _G.BUFFER }, function() keymap = vim.fn.maparg('K', 'n', false, true) end) @@ -405,7 +482,7 @@ describe('LSP', function() eq( '', exec_lua(function() - local keymap + local keymap --- @type string vim._with({ buf = _G.BUFFER }, function() keymap = vim.fn.maparg('K', 'n', false, false) end) @@ -418,40 +495,42 @@ describe('LSP', function() it('should overwrite options set by ftplugins', function() local client --- @type vim.lsp.Client + local BUFFER_1 --- @type integer + local BUFFER_2 --- @type integer test_rpc_server { test_name = 'set_defaults_all_capabilities', on_init = function(_client) client = _client exec_lua(function() vim.api.nvim_command('filetype plugin on') - _G.BUFFER_1 = vim.api.nvim_create_buf(false, true) - _G.BUFFER_2 = vim.api.nvim_create_buf(false, true) - vim.api.nvim_set_option_value('filetype', 'man', { buf = _G.BUFFER_1 }) - vim.api.nvim_set_option_value('filetype', 'xml', { buf = _G.BUFFER_2 }) + BUFFER_1 = vim.api.nvim_create_buf(false, true) + BUFFER_2 = vim.api.nvim_create_buf(false, true) + vim.api.nvim_set_option_value('filetype', 'man', { buf = BUFFER_1 }) + vim.api.nvim_set_option_value('filetype', 'xml', { buf = BUFFER_2 }) end) -- Sanity check to ensure that some values are set after setting filetype. - eq("v:lua.require'man'.goto_tag", get_buf_option('tagfunc', '_G.BUFFER_1')) - eq('xmlcomplete#CompleteTags', get_buf_option('omnifunc', '_G.BUFFER_2')) - eq('xmlformat#Format()', get_buf_option('formatexpr', '_G.BUFFER_2')) + eq("v:lua.require'man'.goto_tag", get_buf_option('tagfunc', BUFFER_1)) + eq('xmlcomplete#CompleteTags', get_buf_option('omnifunc', BUFFER_2)) + eq('xmlformat#Format()', get_buf_option('formatexpr', BUFFER_2)) exec_lua(function() - vim.lsp.buf_attach_client(_G.BUFFER_1, _G.TEST_RPC_CLIENT_ID) - vim.lsp.buf_attach_client(_G.BUFFER_2, _G.TEST_RPC_CLIENT_ID) + vim.lsp.buf_attach_client(BUFFER_1, _G.TEST_RPC_CLIENT_ID) + vim.lsp.buf_attach_client(BUFFER_2, _G.TEST_RPC_CLIENT_ID) end) end, on_handler = function(_, _, ctx) if ctx.method == 'test' then - eq('v:lua.vim.lsp.tagfunc', get_buf_option('tagfunc', '_G.BUFFER_1')) - eq('v:lua.vim.lsp.omnifunc', get_buf_option('omnifunc', '_G.BUFFER_2')) - eq('v:lua.vim.lsp.formatexpr()', get_buf_option('formatexpr', '_G.BUFFER_2')) + eq('v:lua.vim.lsp.tagfunc', get_buf_option('tagfunc', BUFFER_1)) + eq('v:lua.vim.lsp.omnifunc', get_buf_option('omnifunc', BUFFER_2)) + eq('v:lua.vim.lsp.formatexpr()', get_buf_option('formatexpr', BUFFER_2)) client.stop() end end, on_exit = function(_, _) - eq('', get_buf_option('tagfunc', '_G.BUFFER_1')) - eq('', get_buf_option('omnifunc', '_G.BUFFER_2')) - eq('', get_buf_option('formatexpr', '_G.BUFFER_2')) + eq('', get_buf_option('tagfunc', BUFFER_1)) + eq('', get_buf_option('omnifunc', BUFFER_2)) + eq('', get_buf_option('formatexpr', BUFFER_2)) end, } end) @@ -620,13 +699,18 @@ describe('LSP', function() end) end if ctx.method == 'workspace/configuration' then - local server_result = exec_lua(function(method, params) + local server_result = exec_lua( + [[ + local method, params = ... return require 'vim.lsp.handlers'['workspace/configuration']( err, params, { method = method, client_id = _G.TEST_RPC_CLIENT_ID } ) - end, ctx.method, result) + ]], + ctx.method, + result + ) client.notify('workspace/configuration', server_result) end if ctx.method == 'shutdown' then @@ -673,7 +757,9 @@ describe('LSP', function() test_name = 'basic_check_capabilities', on_init = function(client) client.stop() - local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") + local full_kind = exec_lua(function() + return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full + end) eq(full_kind, client.server_capabilities().textDocumentSync.change) eq({ includeText = false }, client.server_capabilities().textDocumentSync.save) eq(false, client.server_capabilities().codeLensProvider) @@ -802,15 +888,15 @@ describe('LSP', function() if ctx.method == 'start' then local tmpfile_old = tmpname() local tmpfile_new = tmpname(false) - exec_lua(function(oldname, newname) + exec_lua(function() _G.BUFFER = vim.api.nvim_get_current_buf() - vim.api.nvim_buf_set_name(_G.BUFFER, oldname) + vim.api.nvim_buf_set_name(_G.BUFFER, tmpfile_old) vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, true, { 'help me' }) vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID) vim._with({ buf = _G.BUFFER }, function() - vim.cmd('saveas ' .. newname) + vim.cmd('saveas ' .. tmpfile_new) end) - end, tmpfile_old, tmpfile_new) + end) else client.stop() end @@ -904,7 +990,9 @@ describe('LSP', function() end, on_init = function(client) client.stop() - exec_lua('vim.lsp.buf.type_definition()') + exec_lua(function() + vim.lsp.buf.type_definition() + end) end, on_exit = function(code, signal) eq(0, code, 'exit code') @@ -931,7 +1019,9 @@ describe('LSP', function() end, on_init = function(client) client.stop() - exec_lua('vim.lsp.buf.type_definition()') + exec_lua(function() + vim.lsp.buf.type_definition() + end) end, on_exit = function(code, signal) eq(0, code, 'exit code') @@ -1032,7 +1122,7 @@ describe('LSP', function() local request = exec_lua(function() return _G.TEST_RPC_CLIENT.requests[2] end) - eq(NIL, request) + eq(nil, request) client.notify('finish') end if ctx.method == 'finish' then @@ -1070,7 +1160,7 @@ describe('LSP', function() local request = exec_lua(function() return _G.TEST_RPC_CLIENT.requests[2] end) - eq(NIL, request) + eq(nil, request) if ctx.method == 'finish' then client.stop() end @@ -1113,7 +1203,7 @@ describe('LSP', function() local request = exec_lua(function() return _G.TEST_RPC_CLIENT.requests[2] end) - eq(NIL, request) + eq(nil, request) client.notify('finish') end if ctx.method == 'finish' then @@ -1182,7 +1272,9 @@ describe('LSP', function() end, on_init = function(_client) client = _client - local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") + local full_kind = exec_lua(function() + return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full + end) eq(full_kind, client.server_capabilities().textDocumentSync.change) eq(true, client.server_capabilities().textDocumentSync.openClose) client.notify('finish') @@ -1223,7 +1315,9 @@ describe('LSP', function() end, on_init = function(_client) client = _client - local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") + local full_kind = exec_lua(function() + return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full + end) eq(full_kind, client.server_capabilities().textDocumentSync.change) eq(true, client.server_capabilities().textDocumentSync.openClose) exec_lua(function() @@ -1269,7 +1363,9 @@ describe('LSP', function() end, on_init = function(_client) client = _client - local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") + local full_kind = exec_lua(function() + return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full + end) eq(full_kind, client.server_capabilities().textDocumentSync.change) eq(true, client.server_capabilities().textDocumentSync.openClose) exec_lua(function() @@ -1312,7 +1408,9 @@ describe('LSP', function() end, on_init = function(_client) client = _client - local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") + local full_kind = exec_lua(function() + return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full + end) eq(full_kind, client.server_capabilities().textDocumentSync.change) eq(true, client.server_capabilities().textDocumentSync.openClose) exec_lua(function() @@ -1361,7 +1459,9 @@ describe('LSP', function() end, on_init = function(_client) client = _client - local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") + local full_kind = exec_lua(function() + return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full + end) eq(full_kind, client.server_capabilities().textDocumentSync.change) eq(true, client.server_capabilities().textDocumentSync.openClose) exec_lua(function() @@ -1478,8 +1578,9 @@ describe('LSP', function() end, on_init = function(_client) client = _client - local sync_kind = - exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Incremental") + local sync_kind = exec_lua(function() + return require 'vim.lsp.protocol'.TextDocumentSyncKind.Incremental + end) eq(sync_kind, client.server_capabilities().textDocumentSync.change) eq(true, client.server_capabilities().textDocumentSync.openClose) exec_lua(function() @@ -1531,8 +1632,9 @@ describe('LSP', function() end, on_init = function(_client) client = _client - local sync_kind = - exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Incremental") + local sync_kind = exec_lua(function() + return require 'vim.lsp.protocol'.TextDocumentSyncKind.Incremental + end) eq(sync_kind, client.server_capabilities().textDocumentSync.change) eq(true, client.server_capabilities().textDocumentSync.openClose) exec_lua(function() @@ -1581,8 +1683,9 @@ describe('LSP', function() end, on_init = function(_client) client = _client - local sync_kind = - exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Incremental") + local sync_kind = exec_lua(function() + return require 'vim.lsp.protocol'.TextDocumentSyncKind.Incremental + end) eq(sync_kind, client.server_capabilities().textDocumentSync.change) eq(true, client.server_capabilities().textDocumentSync.openClose) exec_lua(function() @@ -1626,7 +1729,9 @@ describe('LSP', function() end, on_init = function(_client) client = _client - local sync_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") + local sync_kind = exec_lua(function() + return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full + end) eq(sync_kind, client.server_capabilities().textDocumentSync.change) eq(true, client.server_capabilities().textDocumentSync.openClose) exec_lua(function() @@ -1677,7 +1782,9 @@ describe('LSP', function() end, on_init = function(_client) client = _client - local sync_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") + local sync_kind = exec_lua(function() + return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full + end) eq(sync_kind, client.server_capabilities().textDocumentSync.change) eq(true, client.server_capabilities().textDocumentSync.openClose) exec_lua(function() @@ -2179,7 +2286,9 @@ describe('LSP', function() end) it('correctly goes ahead with the edit if all is normal', function() - exec_lua("vim.lsp.util.apply_text_document_edit(..., nil, 'utf-16')", text_document_edit(5)) + exec_lua(function(text_edit) + vim.lsp.util.apply_text_document_edit(text_edit, nil, 'utf-16') + end, text_document_edit(5)) eq({ 'First ↥ 🤦 🦄 line of text', '2nd line of 语text', @@ -2187,10 +2296,10 @@ describe('LSP', function() end) it('always accepts edit with version = 0', function() - exec_lua(function(bufnr, text_edit) - vim.lsp.util.buf_versions[bufnr] = 10 + exec_lua(function(text_edit) + vim.lsp.util.buf_versions[target_bufnr] = 10 vim.lsp.util.apply_text_document_edit(text_edit, nil, 'utf-16') - end, target_bufnr, text_document_edit(0)) + end, text_document_edit(0)) eq({ 'First ↥ 🤦 🦄 line of text', '2nd line of 语text', @@ -2199,10 +2308,10 @@ describe('LSP', function() it('skips the edit if the version of the edit is behind the local buffer ', function() local apply_edit_mocking_current_version = function(edit, versionedBuf) - exec_lua(function(edit0, versionedBuf0) - vim.lsp.util.buf_versions[versionedBuf0.bufnr] = versionedBuf0.currentVersion - vim.lsp.util.apply_text_document_edit(edit0, nil, 'utf-16') - end, edit, versionedBuf) + exec_lua(function() + vim.lsp.util.buf_versions[versionedBuf.bufnr] = versionedBuf.currentVersion + vim.lsp.util.apply_text_document_edit(edit, nil, 'utf-16') + end) end local baseText = { @@ -2295,34 +2404,30 @@ describe('LSP', function() } end - local target_bufnr, changedtick = nil, nil + local target_bufnr --- @type integer + local changedtick --- @type integer before_each(function() - local ret = exec_lua(function() - local bufnr = vim.uri_to_bufnr('file:///fake/uri') + exec_lua(function() + target_bufnr = vim.uri_to_bufnr('file:///fake/uri') local lines = { 'Original Line #1', 'Original Line #2', } - vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines) + vim.api.nvim_buf_set_lines(target_bufnr, 0, -1, false, lines) - local update_changed_tick = function() - vim.lsp.util.buf_versions[bufnr] = vim.api.nvim_buf_get_var(bufnr, 'changedtick') + local function update_changed_tick() + vim.lsp.util.buf_versions[target_bufnr] = vim.b[target_bufnr].changedtick end update_changed_tick() - vim.api.nvim_buf_attach(bufnr, false, { - on_changedtick = function() - update_changed_tick() - end, + vim.api.nvim_buf_attach(target_bufnr, false, { + on_changedtick = update_changed_tick, }) - return { bufnr, vim.api.nvim_buf_get_var(bufnr, 'changedtick') } + changedtick = vim.b[target_bufnr].changedtick end) - - target_bufnr = ret[1] - changedtick = ret[2] end) it('apply_workspace_edit applies a single edit', function() @@ -2340,11 +2445,11 @@ describe('LSP', function() 'First Line', 'Original Line #2', }, - exec_lua(function(workspace_edits, target_bufnr0) + exec_lua(function(workspace_edits) vim.lsp.util.apply_workspace_edit(workspace_edits, 'utf-16') - return vim.api.nvim_buf_get_lines(target_bufnr0, 0, -1, false) - end, make_workspace_edit(edits), target_bufnr) + return vim.api.nvim_buf_get_lines(target_bufnr, 0, -1, false) + end, make_workspace_edit(edits)) ) end) @@ -2361,11 +2466,10 @@ describe('LSP', function() eq( new_lines, - exec_lua(function(workspace_edits, target_bufnr0) + exec_lua(function(workspace_edits) vim.lsp.util.apply_workspace_edit(workspace_edits, 'utf-16') - - return vim.api.nvim_buf_get_lines(target_bufnr0, 0, -1, false) - end, make_workspace_edit(edits), target_bufnr) + return vim.api.nvim_buf_get_lines(target_bufnr, 0, -1, false) + end, make_workspace_edit(edits)) ) end) @@ -2380,7 +2484,9 @@ describe('LSP', function() }, }, } - exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit, 'utf-16') + exec_lua(function() + vim.lsp.util.apply_workspace_edit(edit, 'utf-16') + end) eq(true, vim.uv.fs_stat(tmpfile) ~= nil) end) @@ -2397,7 +2503,9 @@ describe('LSP', function() }, }, } - exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit, 'utf-16') + exec_lua(function() + vim.lsp.util.apply_workspace_edit(edit, 'utf-16') + end) eq(true, vim.uv.fs_stat(tmpfile) ~= nil) end ) @@ -2446,11 +2554,11 @@ describe('LSP', function() it('DeleteFile delete file and buffer', function() local tmpfile = tmpname() write_file(tmpfile, 'Be gone') - local uri = exec_lua(function(fname) - local bufnr = vim.fn.bufadd(fname) + local uri = exec_lua(function() + local bufnr = vim.fn.bufadd(tmpfile) vim.fn.bufload(bufnr) - return vim.uri_from_fname(fname) - end, tmpfile) + return vim.uri_from_fname(tmpfile) + end) local edit = { documentChanges = { { @@ -2490,15 +2598,15 @@ describe('LSP', function() local old = tmpname() write_file(old, 'Test content') local new = tmpname(false) - local lines = exec_lua(function(old0, new0) - local old_bufnr = vim.fn.bufadd(old0) + local lines = exec_lua(function() + local old_bufnr = vim.fn.bufadd(old) vim.fn.bufload(old_bufnr) - vim.lsp.util.rename(old0, new0) + vim.lsp.util.rename(old, new) -- the existing buffer is renamed in-place and its contents is kept - local new_bufnr = vim.fn.bufadd(new0) + local new_bufnr = vim.fn.bufadd(new) vim.fn.bufload(new_bufnr) return (old_bufnr == new_bufnr) and vim.api.nvim_buf_get_lines(new_bufnr, 0, -1, true) - end, old, new) + end) eq({ 'Test content' }, lines) local exists = vim.uv.fs_stat(old) ~= nil eq(false, exists) @@ -2517,15 +2625,15 @@ describe('LSP', function() local file = 'file.txt' write_file(old_dir .. pathsep .. file, 'Test content') - local lines = exec_lua(function(old_dir0, new_dir0, pathsep0, file0) - local old_bufnr = vim.fn.bufadd(old_dir0 .. pathsep0 .. file0) + local lines = exec_lua(function() + local old_bufnr = vim.fn.bufadd(old_dir .. pathsep .. file) vim.fn.bufload(old_bufnr) - vim.lsp.util.rename(old_dir0, new_dir0) + vim.lsp.util.rename(old_dir, new_dir) -- the existing buffer is renamed in-place and its contents is kept - local new_bufnr = vim.fn.bufadd(new_dir0 .. pathsep0 .. file0) + local new_bufnr = vim.fn.bufadd(new_dir .. pathsep .. file) vim.fn.bufload(new_bufnr) return (old_bufnr == new_bufnr) and vim.api.nvim_buf_get_lines(new_bufnr, 0, -1, true) - end, old_dir, new_dir, pathsep, file) + end) eq({ 'Test content' }, lines) eq(false, vim.uv.fs_stat(old_dir) ~= nil) eq(true, vim.uv.fs_stat(new_dir) ~= nil) @@ -2541,18 +2649,18 @@ describe('LSP', function() eq( true, - exec_lua(function(old0, new0) - local old_prefixed = 'explorer://' .. old0 - local old_suffixed = old0 .. '.bak' - local new_prefixed = 'explorer://' .. new0 - local new_suffixed = new0 .. '.bak' + exec_lua(function() + local old_prefixed = 'explorer://' .. old + local old_suffixed = old .. '.bak' + local new_prefixed = 'explorer://' .. new + local new_suffixed = new .. '.bak' local old_prefixed_buf = vim.fn.bufadd(old_prefixed) local old_suffixed_buf = vim.fn.bufadd(old_suffixed) local new_prefixed_buf = vim.fn.bufadd(new_prefixed) local new_suffixed_buf = vim.fn.bufadd(new_suffixed) - vim.lsp.util.rename(old0, new0) + vim.lsp.util.rename(old, new) return vim.api.nvim_buf_is_valid(old_prefixed_buf) and vim.api.nvim_buf_is_valid(old_suffixed_buf) @@ -2562,7 +2670,7 @@ describe('LSP', function() and vim.api.nvim_buf_get_name(old_suffixed_buf) == old_suffixed and vim.api.nvim_buf_get_name(new_prefixed_buf) == new_prefixed and vim.api.nvim_buf_get_name(new_suffixed_buf) == new_suffixed - end, old, new) + end) ) os.remove(new) @@ -2576,16 +2684,16 @@ describe('LSP', function() local new = tmpname() write_file(new, 'New file') - exec_lua(function(old0, new0) - vim.lsp.util.rename(old0, new0, { ignoreIfExists = true }) - end, old, new) + exec_lua(function() + vim.lsp.util.rename(old, new, { ignoreIfExists = true }) + end) eq(true, vim.uv.fs_stat(old) ~= nil) eq('New file', read_file(new)) - exec_lua(function(old0, new0) - vim.lsp.util.rename(old0, new0, { overwrite = false }) - end, old, new) + exec_lua(function() + vim.lsp.util.rename(old, new, { overwrite = false }) + end) eq(true, vim.uv.fs_stat(old) ~= nil) eq('New file', read_file(new)) @@ -2597,20 +2705,20 @@ describe('LSP', function() write_file(old, 'line') local new = tmpname(false) - local undo_kept = exec_lua(function(old0, new0) + local undo_kept = exec_lua(function() vim.opt.undofile = true - vim.cmd.edit(old0) + vim.cmd.edit(old) vim.cmd.normal('dd') vim.cmd.write() local undotree = vim.fn.undotree() - vim.lsp.util.rename(old0, new0) + vim.lsp.util.rename(old, new) -- Renaming uses :saveas, which updates the "last write" information. -- Other than that, the undotree should remain the same. undotree.save_cur = undotree.save_cur + 1 undotree.save_last = undotree.save_last + 1 undotree.entries[1].save = undotree.entries[1].save + 1 return vim.deep_equal(undotree, vim.fn.undotree()) - end, old, new) + end) eq(false, vim.uv.fs_stat(old) ~= nil) eq(true, vim.uv.fs_stat(new) ~= nil) eq(true, undo_kept) @@ -2621,17 +2729,17 @@ describe('LSP', function() write_file(old, 'line') local new = tmpname(false) - local undo_kept = exec_lua(function(old0, new0) + local undo_kept = exec_lua(function() vim.opt.undofile = true - vim.cmd.split(old0) + vim.cmd.split(old) vim.cmd.normal('dd') vim.cmd.write() local undotree = vim.fn.undotree() vim.cmd.bdelete() - vim.lsp.util.rename(old0, new0) - vim.cmd.edit(new0) + vim.lsp.util.rename(old, new) + vim.cmd.edit(new) return vim.deep_equal(undotree, vim.fn.undotree()) - end, old, new) + end) eq(false, vim.uv.fs_stat(old) ~= nil) eq(true, vim.uv.fs_stat(new) ~= nil) eq(true, undo_kept) @@ -2642,16 +2750,16 @@ describe('LSP', function() write_file(old, 'Old File') local new = tmpname(false) - local lines = exec_lua(function(old0, new0) - local old_buf = vim.fn.bufadd(old0) + local lines = exec_lua(function() + local old_buf = vim.fn.bufadd(old) vim.fn.bufload(old_buf) local conflict_buf = vim.api.nvim_create_buf(true, false) - vim.api.nvim_buf_set_name(conflict_buf, new0) + vim.api.nvim_buf_set_name(conflict_buf, new) vim.api.nvim_buf_set_lines(conflict_buf, 0, -1, true, { 'conflict' }) vim.api.nvim_win_set_buf(0, conflict_buf) - vim.lsp.util.rename(old0, new0) + vim.lsp.util.rename(old, new) return vim.api.nvim_buf_get_lines(conflict_buf, 0, -1, true) - end, old, new) + end) eq({ 'conflict' }, lines) eq('Old File', read_file(old)) end) @@ -2661,9 +2769,9 @@ describe('LSP', function() write_file(old, 'Old file') local new = tmpname() write_file(new, 'New file') - exec_lua(function(old0, new0) - vim.lsp.util.rename(old0, new0, { overwrite = true }) - end, old, new) + exec_lua(function() + vim.lsp.util.rename(old, new, { overwrite = true }) + end) eq(false, vim.uv.fs_stat(old) ~= nil) eq(true, vim.uv.fs_stat(new) ~= nil) @@ -3028,14 +3136,39 @@ describe('LSP', function() describe('lsp.util._get_symbol_kind_name', function() it('returns the name specified by protocol', function() - eq('File', exec_lua('return vim.lsp.util._get_symbol_kind_name(1)')) - eq('TypeParameter', exec_lua('return vim.lsp.util._get_symbol_kind_name(26)')) + eq( + 'File', + exec_lua(function() + return vim.lsp.util._get_symbol_kind_name(1) + end) + ) + eq( + 'TypeParameter', + exec_lua(function() + return vim.lsp.util._get_symbol_kind_name(26) + end) + ) end) it('returns the name not specified by protocol', function() - eq('Unknown', exec_lua('return vim.lsp.util._get_symbol_kind_name(nil)')) - eq('Unknown', exec_lua('return vim.lsp.util._get_symbol_kind_name(vim.NIL)')) - eq('Unknown', exec_lua('return vim.lsp.util._get_symbol_kind_name(1000)')) + eq( + 'Unknown', + exec_lua(function() + return vim.lsp.util._get_symbol_kind_name(nil) + end) + ) + eq( + 'Unknown', + exec_lua(function() + return vim.lsp.util._get_symbol_kind_name(vim.NIL) + end) + ) + eq( + 'Unknown', + exec_lua(function() + return vim.lsp.util._get_symbol_kind_name(1000) + end) + ) end) end) @@ -3397,7 +3530,12 @@ describe('LSP', function() ]], shiftwidth )) - eq(tabsize, exec_lua('return vim.lsp.util.get_effective_tabstop()')) + eq( + tabsize, + exec_lua(function() + return vim.lsp.util.get_effective_tabstop() + end) + ) end it('with shiftwidth = 1', function() @@ -4119,6 +4257,7 @@ describe('LSP', function() local bufnr = vim.api.nvim_get_current_buf() vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID) vim.lsp._stubs = {} + --- @diagnostic disable-next-line:duplicate-set-field vim.fn.input = function(opts, _) vim.lsp._stubs.input_prompt = opts.prompt vim.lsp._stubs.input_text = opts.default @@ -4140,12 +4279,24 @@ describe('LSP', function() eq(table.remove(test.expected_handlers), { err, result, ctx }, 'expected handler') if ctx.method == 'start' then - exec_lua('vim.lsp.buf.rename()') + exec_lua(function() + vim.lsp.buf.rename() + end) end if ctx.method == 'shutdown' then if test.expected_text then - eq('New Name: ', exec_lua('return vim.lsp._stubs.input_prompt')) - eq(test.expected_text, exec_lua('return vim.lsp._stubs.input_text')) + eq( + 'New Name: ', + exec_lua(function() + return vim.lsp._stubs.input_prompt + end) + ) + eq( + test.expected_text, + exec_lua(function() + return vim.lsp._stubs.input_text + end) + ) end client.stop() end @@ -4181,6 +4332,7 @@ describe('LSP', function() end local bufnr = vim.api.nvim_get_current_buf() vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID) + --- @diagnostic disable-next-line:duplicate-set-field vim.fn.inputlist = function() return 1 end @@ -4398,8 +4550,8 @@ describe('LSP', function() eq(table.remove(expected_handlers), { err, result, ctx }) if ctx.method == 'start' then local fake_uri = 'file:///fake/uri' - local cmd = exec_lua(function(fake_uri0) - local bufnr = vim.uri_to_bufnr(fake_uri0) + local cmd = exec_lua(function() + local bufnr = vim.uri_to_bufnr(fake_uri) vim.fn.bufload(bufnr) vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { 'One line' }) local lenses = { @@ -4423,7 +4575,7 @@ describe('LSP', function() vim.api.nvim_set_current_buf(bufnr) vim.lsp.codelens.run() return cmd_called - end, fake_uri) + end) eq({ command = 'Dummy', title = 'Lens1' }, cmd) elseif ctx.method == 'shutdown' then client.stop() @@ -4530,7 +4682,7 @@ describe('LSP', function() exec_lua(create_server_definition) -- setup lsp - exec_lua(function(lens_title_per_fake_uri0) + exec_lua(function() local server = _G._create_server({ capabilities = { codeLensProvider = { @@ -4546,7 +4698,7 @@ describe('LSP', function() ['end'] = { line = 0, character = 0 }, }, command = { - title = lens_title_per_fake_uri0[params.textDocument.uri], + title = lens_title_per_fake_uri[params.textDocument.uri], command = 'Dummy', }, }, @@ -4560,12 +4712,12 @@ describe('LSP', function() name = 'dummy', cmd = server.cmd, }) - end, lens_title_per_fake_uri) + end) -- create buffers and setup handler - exec_lua(function(lens_title_per_fake_uri0) + exec_lua(function() local default_buf = vim.api.nvim_get_current_buf() - for fake_uri in pairs(lens_title_per_fake_uri0) do + for fake_uri in pairs(lens_title_per_fake_uri) do local bufnr = vim.uri_to_bufnr(fake_uri) vim.api.nvim_set_current_buf(bufnr) vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { 'Some contents' }) @@ -4573,14 +4725,14 @@ describe('LSP', function() end vim.api.nvim_buf_delete(default_buf, { force = true }) - _G.REQUEST_COUNT = vim.tbl_count(lens_title_per_fake_uri0) + _G.REQUEST_COUNT = vim.tbl_count(lens_title_per_fake_uri) _G.RESPONSES = {} local on_codelens = vim.lsp.codelens.on_codelens vim.lsp.codelens.on_codelens = function(err, result, ctx, ...) table.insert(_G.RESPONSES, { err = err, result = result, ctx = ctx }) return on_codelens(err, result, ctx, ...) end - end, lens_title_per_fake_uri) + end) -- call codelens refresh local cmds = exec_lua(function() @@ -4655,7 +4807,7 @@ describe('LSP', function() vim.notify = notify return notify_msg end) - eq(NIL, notify_msg) + eq(nil, notify_msg) elseif ctx.method == 'shutdown' then client.stop() end @@ -4696,7 +4848,7 @@ describe('LSP', function() vim.notify = notify return notify_msg end) - eq(NIL, notify_msg) + eq(nil, notify_msg) elseif ctx.method == 'shutdown' then client.stop() end @@ -4743,7 +4895,7 @@ describe('LSP', function() vim.notify = notify return notify_msg end) - eq(NIL, notify_msg) + eq(nil, notify_msg) elseif ctx.method == 'shutdown' then client.stop() end @@ -4893,18 +5045,23 @@ describe('LSP', function() --- @param range_formatting boolean local function check_notify(name, formatting, range_formatting) local timeout_msg = '[LSP][' .. name .. '] timeout' - exec_lua(function(formatting0, range_formatting0, name0) + exec_lua(function() local server = _G._create_server({ capabilities = { - documentFormattingProvider = formatting0, - documentRangeFormattingProvider = range_formatting0, + documentFormattingProvider = formatting, + documentRangeFormattingProvider = range_formatting, }, }) - vim.lsp.start({ name = name0, cmd = server.cmd }) + vim.lsp.start({ name = name, cmd = server.cmd }) _G.notify_msg = nil - vim.lsp.buf.format({ name = name0, timeout_ms = 1 }) - end, formatting, range_formatting, name) - eq(formatting and timeout_msg or fail_msg, exec_lua('return notify_msg')) + vim.lsp.buf.format({ name = name, timeout_ms = 1 }) + end) + eq( + formatting and timeout_msg or fail_msg, + exec_lua(function() + return _G.notify_msg + end) + ) exec_lua(function() _G.notify_msg = nil vim.lsp.buf.format({ @@ -4919,7 +5076,12 @@ describe('LSP', function() }, }) end) - eq(range_formatting and timeout_msg or fail_msg, exec_lua('return notify_msg')) + eq( + range_formatting and timeout_msg or fail_msg, + exec_lua(function() + return _G.notify_msg + end) + ) end check_notify('none', false, false) check_notify('formatting', true, false) @@ -4949,8 +5111,8 @@ describe('LSP', function() }, } exec_lua(create_server_definition) - exec_lua(function(mock_locations0) - _G.mock_locations = mock_locations0 + exec_lua(function() + _G.mock_locations = mock_locations _G.server = _G._create_server({ ---@type lsp.ServerCapabilities capabilities = { @@ -4981,7 +5143,7 @@ describe('LSP', function() }, }) _G.client_id = vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd }) - end, mock_locations) + end) end) after_each(function() @@ -5062,22 +5224,22 @@ describe('LSP', function() it('can connect to lsp server via pipe or domain_socket', function() local tmpfile = is_os('win') and '\\\\.\\\\pipe\\pipe.test' or tmpname(false) - local result = exec_lua(function(SOCK) + local result = exec_lua(function() local uv = vim.uv local server = assert(uv.new_pipe(false)) - server:bind(SOCK) + server:bind(tmpfile) local init = nil server:listen(127, function(err) assert(not err, err) - local client = assert(uv.new_pipe()) + local client = assert(vim.uv.new_pipe()) server:accept(client) client:read_start(require('vim.lsp.rpc').create_read_loop(function(body) init = body client:close() end)) end) - vim.lsp.start({ name = 'dummy', cmd = vim.lsp.rpc.connect(SOCK) }) + vim.lsp.start({ name = 'dummy', cmd = vim.lsp.rpc.connect(tmpfile) }) vim.wait(1000, function() return init ~= nil end) @@ -5085,7 +5247,7 @@ describe('LSP', function() server:close() server:shutdown() return vim.json.decode(init) - end, tmpfile) + end) eq('initialize', result.method) end) end) @@ -5093,14 +5255,13 @@ describe('LSP', function() describe('handlers', function() it('handler can return false as response', function() local result = exec_lua(function() - local uv = vim.uv - local server = assert(uv.new_tcp()) + local server = assert(vim.uv.new_tcp()) local messages = {} local responses = {} server:bind('127.0.0.1', 0) server:listen(127, function(err) assert(not err, err) - local socket = assert(uv.new_tcp()) + local socket = assert(vim.uv.new_tcp()) server:accept(socket) socket:read_start(require('vim.lsp.rpc').create_read_loop(function(body) local payload = vim.json.decode(body) @@ -5176,12 +5337,12 @@ describe('LSP', function() end exec_lua(create_server_definition) - local result = exec_lua(function(root_dir0, tmpfile0) + local result = exec_lua(function() local server = _G._create_server() local client_id = assert(vim.lsp.start({ name = 'dynamic-test', cmd = server.cmd, - root_dir = root_dir0, + root_dir = root_dir, get_language_id = function() return 'dummy-lang' end, @@ -5205,7 +5366,7 @@ describe('LSP', function() registerOptions = { documentSelector = { { - pattern = root_dir0 .. '/*.foo', + pattern = root_dir .. '/*.foo', }, }, }, @@ -5250,13 +5411,13 @@ describe('LSP', function() end check('textDocument/formatting') - check('textDocument/formatting', tmpfile0) + check('textDocument/formatting', tmpfile) check('textDocument/rangeFormatting') - check('textDocument/rangeFormatting', tmpfile0) + check('textDocument/rangeFormatting', tmpfile) check('textDocument/completion') return result - end, root_dir, tmpfile) + end) eq(5, #result) eq({ method = 'textDocument/formatting', supported = false }, result[1]) @@ -5268,6 +5429,16 @@ describe('LSP', function() end) describe('vim.lsp._watchfiles', function() + --- @type integer, integer, integer + local created, changed, deleted + + setup(function() + clear() + created = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]) + changed = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]) + deleted = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]) + end) + local function test_filechanges(watchfunc) it( string.format('sends notifications when files change (watchfunc=%s)', watchfunc), @@ -5298,12 +5469,12 @@ describe('LSP', function() mkdir(root_dir) exec_lua(create_server_definition) - local result = exec_lua(function(root_dir0, watchfunc0) + local result = exec_lua(function() local server = _G._create_server() local client_id = assert(vim.lsp.start({ name = 'watchfiles-test', cmd = server.cmd, - root_dir = root_dir0, + root_dir = root_dir, capabilities = { workspace = { didChangeWatchedFiles = { @@ -5313,11 +5484,11 @@ describe('LSP', function() }, })) - require('vim.lsp._watchfiles')._watchfunc = require('vim._watch')[watchfunc0] + require('vim.lsp._watchfiles')._watchfunc = require('vim._watch')[watchfunc] local expected_messages = 0 - local msg_wait_timeout = watchfunc0 == 'watch' and 200 or 2500 + local msg_wait_timeout = watchfunc == 'watch' and 200 or 2500 local function wait_for_message(incr) expected_messages = expected_messages + (incr or 1) @@ -5349,11 +5520,11 @@ describe('LSP', function() }, }, { client_id = client_id }) - if watchfunc0 ~= 'watch' then + if watchfunc ~= 'watch' then vim.wait(100) end - local path = root_dir0 .. '/watch' + local path = root_dir .. '/watch' local tmp = vim.fn.tempname() io.open(tmp, 'w'):close() vim.uv.fs_rename(tmp, path) @@ -5367,7 +5538,7 @@ describe('LSP', function() vim.lsp.stop_client(client_id) return server.messages - end, root_dir, watchfunc) + end) local uri = vim.uri_from_fname(root_dir .. '/watch') @@ -5378,7 +5549,7 @@ describe('LSP', function() params = { changes = { { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), + type = created, uri = uri, }, }, @@ -5390,7 +5561,7 @@ describe('LSP', function() params = { changes = { { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]), + type = deleted, uri = uri, }, }, @@ -5407,12 +5578,12 @@ describe('LSP', function() it('correctly registers and unregisters', function() local root_dir = '/some_dir' exec_lua(create_server_definition) - local result = exec_lua(function(root_dir0) + local result = exec_lua(function() local server = _G._create_server() local client_id = assert(vim.lsp.start({ name = 'watchfiles-test', cmd = server.cmd, - root_dir = root_dir0, + root_dir = root_dir, capabilities = { workspace = { didChangeWatchedFiles = { @@ -5464,8 +5635,8 @@ describe('LSP', function() }, }, { client_id = client_id }) - send_event(root_dir0 .. '/file.watch0', vim._watch.FileChangeType.Created) - send_event(root_dir0 .. '/file.watch1', vim._watch.FileChangeType.Created) + send_event(root_dir .. '/file.watch0', vim._watch.FileChangeType.Created) + send_event(root_dir .. '/file.watch1', vim._watch.FileChangeType.Created) expected_messages = expected_messages + 1 wait_for_messages() @@ -5495,14 +5666,14 @@ describe('LSP', function() }, }, { client_id = client_id }) - send_event(root_dir0 .. '/file.watch0', vim._watch.FileChangeType.Created) - send_event(root_dir0 .. '/file.watch1', vim._watch.FileChangeType.Created) + send_event(root_dir .. '/file.watch0', vim._watch.FileChangeType.Created) + send_event(root_dir .. '/file.watch1', vim._watch.FileChangeType.Created) expected_messages = expected_messages + 1 wait_for_messages() return server.messages - end, root_dir) + end) local function watched_uri(fname) return vim.uri_from_fname(root_dir .. '/' .. fname) @@ -5513,7 +5684,7 @@ describe('LSP', function() eq({ changes = { { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), + type = created, uri = watched_uri('file.watch0'), }, }, @@ -5522,7 +5693,7 @@ describe('LSP', function() eq({ changes = { { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), + type = created, uri = watched_uri('file.watch1'), }, }, @@ -5532,12 +5703,12 @@ describe('LSP', function() it('correctly handles the registered watch kind', function() local root_dir = 'some_dir' exec_lua(create_server_definition) - local result = exec_lua(function(root_dir0) + local result = exec_lua(function() local server = _G._create_server() local client_id = assert(vim.lsp.start({ name = 'watchfiles-test', cmd = server.cmd, - root_dir = root_dir0, + root_dir = root_dir, capabilities = { workspace = { didChangeWatchedFiles = { @@ -5611,7 +5782,7 @@ describe('LSP', function() wait_for_messages() return server.messages - end, root_dir) + end) local function watched_uri(fname) return vim.uri_from_fname('/dir/' .. fname) @@ -5622,51 +5793,51 @@ describe('LSP', function() eq({ changes = { { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), + type = created, uri = watched_uri('watch1'), }, { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]), + type = changed, uri = watched_uri('watch2'), }, { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), + type = created, uri = watched_uri('watch3'), }, { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]), + type = changed, uri = watched_uri('watch3'), }, { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]), + type = deleted, uri = watched_uri('watch4'), }, { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), + type = created, uri = watched_uri('watch5'), }, { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]), + type = deleted, uri = watched_uri('watch5'), }, { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]), + type = changed, uri = watched_uri('watch6'), }, { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]), + type = deleted, uri = watched_uri('watch6'), }, { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), + type = created, uri = watched_uri('watch7'), }, { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]), + type = changed, uri = watched_uri('watch7'), }, { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]), + type = deleted, uri = watched_uri('watch7'), }, }, @@ -5676,12 +5847,12 @@ describe('LSP', function() it('prunes duplicate events', function() local root_dir = 'some_dir' exec_lua(create_server_definition) - local result = exec_lua(function(root_dir0) + local result = exec_lua(function() local server = _G._create_server() local client_id = assert(vim.lsp.start({ name = 'watchfiles-test', cmd = server.cmd, - root_dir = root_dir0, + root_dir = root_dir, capabilities = { workspace = { didChangeWatchedFiles = { @@ -5738,22 +5909,22 @@ describe('LSP', function() wait_for_messages() return server.messages - end, root_dir) + end) eq(3, #result) eq('workspace/didChangeWatchedFiles', result[3].method) eq({ changes = { { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), + type = created, uri = vim.uri_from_fname('file1'), }, { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]), + type = changed, uri = vim.uri_from_fname('file1'), }, { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), + type = created, uri = vim.uri_from_fname('file2'), }, }, @@ -5772,13 +5943,13 @@ describe('LSP', function() end) local function check_registered(capabilities) - return exec_lua(function(capabilities0) + return exec_lua(function() _G.watching = false local client_id = assert(vim.lsp.start({ name = 'watchfiles-test', cmd = _G.server.cmd, root_dir = 'some_dir', - capabilities = capabilities0, + capabilities = capabilities, }, { reuse_client = function() return false @@ -5813,7 +5984,7 @@ describe('LSP', function() vim.lsp.stop_client(client_id, true) return _G.watching - end, capabilities) + end) end eq(is_os('mac') or is_os('win'), check_registered(nil)) -- start{_client}() defaults to make_client_capabilities(). diff --git a/test/functional/plugin/man_spec.lua b/test/functional/plugin/man_spec.lua index 057748f51d..6f0eeff748 100644 --- a/test/functional/plugin/man_spec.lua +++ b/test/functional/plugin/man_spec.lua @@ -16,21 +16,20 @@ local is_ci = t.is_ci -- Collects all names passed to find_path() after attempting ":Man foo". local function get_search_history(name) - local args = vim.split(name, ' ') - local code = [[ - local args = ... + return exec_lua(function() + local args = vim.split(name, ' ') local man = require('man') local res = {} - man.find_path = function(sect, name) - table.insert(res, {sect, name}) + --- @diagnostic disable-next-line:duplicate-set-field + man.find_path = function(sect, name0) + table.insert(res, { sect, name0 }) return nil end - local ok, rv = pcall(man.open_page, -1, {tab = 0}, args) + local ok, rv = pcall(man.open_page, -1, { tab = 0 }, args) assert(not ok) assert(rv and rv:match('no manual entry')) return res - ]] - return exec_lua(code, args) + end) end clear() diff --git a/test/functional/plugin/tohtml_spec.lua b/test/functional/plugin/tohtml_spec.lua index 98a422935c..1d05f4d6b4 100644 --- a/test/functional/plugin/tohtml_spec.lua +++ b/test/functional/plugin/tohtml_spec.lua @@ -210,9 +210,7 @@ describe(':TOhtml', function() exec('set termguicolors') local bg = fn.synIDattr(fn.hlID('Normal'), 'bg#', 'gui') local fg = fn.synIDattr(fn.hlID('Normal'), 'fg#', 'gui') - exec_lua [[ - local html = vim.cmd'2,2TOhtml' - ]] + n.command('2,2TOhtml') local out_file = api.nvim_buf_get_name(api.nvim_get_current_buf()) eq({ '', @@ -408,12 +406,12 @@ describe(':TOhtml', function() local function run() local buf = api.nvim_get_current_buf() run_tohtml_and_assert(screen, function() - exec_lua [[ - local outfile = vim.fn.tempname() .. '.html' - local html = require('tohtml').tohtml(0,{number_lines=true}) - vim.fn.writefile(html, outfile) - vim.cmd.split(outfile) - ]] + exec_lua(function() + local outfile = vim.fn.tempname() .. '.html' + local html = require('tohtml').tohtml(0, { number_lines = true }) + vim.fn.writefile(html, outfile) + vim.cmd.split(outfile) + end) end) api.nvim_set_current_buf(buf) end diff --git a/test/functional/testnvim.lua b/test/functional/testnvim.lua index ac2ec89271..36e6b4d7bd 100644 --- a/test/functional/testnvim.lua +++ b/test/functional/testnvim.lua @@ -837,19 +837,171 @@ function M.exec_capture(code) return M.api.nvim_exec2(code, { output = true }).output end +--- @param f function +--- @return table +local function get_upvalues(f) + local i = 1 + local upvalues = {} --- @type table + while true do + local n, v = debug.getupvalue(f, i) + if not n then + break + end + upvalues[n] = v + i = i + 1 + end + return upvalues +end + +--- @param f function +--- @param upvalues table +local function set_upvalues(f, upvalues) + local i = 1 + while true do + local n = debug.getupvalue(f, i) + if not n then + break + end + if upvalues[n] then + debug.setupvalue(f, i, upvalues[n]) + end + i = i + 1 + end +end + +--- @type fun(f: function): table +_G.__get_upvalues = nil + +--- @type fun(f: function, upvalues: table) +_G.__set_upvalues = nil + +--- @param self table +--- @param bytecode string +--- @param upvalues table +--- @param ... any[] +--- @return any[] result +--- @return table upvalues +local function exec_lua_handler(self, bytecode, upvalues, ...) + local f = assert(loadstring(bytecode)) + self.set_upvalues(f, upvalues) + local ret = { f(...) } --- @type any[] + --- @type table + local new_upvalues = self.get_upvalues(f) + + do -- Check return value types for better error messages + local invalid_types = { + ['thread'] = true, + ['function'] = true, + ['userdata'] = true, + } + + for k, v in pairs(ret) do + if invalid_types[type(v)] then + error( + string.format( + "Return index %d with value '%s' of type '%s' cannot be serialized over RPC", + k, + tostring(v), + type(v) + ) + ) + end + end + end + + return ret, new_upvalues +end + +--- Execute Lua code in the wrapped Nvim session. +--- +--- When `code` is passed as a function, it is converted into Lua byte code. +--- +--- Direct upvalues are copied over, however upvalues contained +--- within nested functions are not. Upvalues are also copied back when `code` +--- finishes executing. See `:help lua-upvalue`. +--- +--- Only types which can be serialized can be transferred over, e.g: +--- `table`, `number`, `boolean`, `string`. +--- +--- `code` runs with a different environment and thus will have a different global +--- environment. See `:help lua-environments`. +--- +--- Example: +--- ```lua +--- local upvalue1 = 'upvalue1' +--- exec_lua(function(a, b, c) +--- print(upvalue1, a, b, c) +--- (function() +--- print(upvalue2) +--- end)() +--- end, 'a', 'b', 'c' +--- ``` +--- Prints: +--- ``` +--- upvalue1 a b c +--- nil +--- ``` +--- +--- Not supported: +--- ```lua +--- local a = vim.uv.new_timer() +--- exec_lua(function() +--- print(a) -- Error: a is of type 'userdata' which cannot be serialized. +--- end) +--- ``` --- @param code string|function +--- @param ... any --- @return any function M.exec_lua(code, ...) - if type(code) == 'function' then - return M.api.nvim_exec_lua( + if type(code) == 'string' then + return M.api.nvim_exec_lua(code, { ... }) + end + + assert(session) + + if not session.exec_lua_setup then + M.api.nvim_exec_lua( [[ - local code = ... - return loadstring(code)(select(2, ...)) + _G.__test_exec_lua = { + get_upvalues = loadstring((select(1,...))), + set_upvalues = loadstring((select(2,...))), + handler = loadstring((select(3,...))) + } + setmetatable(_G.__test_exec_lua, { __index = _G.__test_exec_lua }) ]], - { string.dump(code), ... } + { string.dump(get_upvalues), string.dump(set_upvalues), string.dump(exec_lua_handler) } ) + session.exec_lua_setup = true end - return M.api.nvim_exec_lua(code, { ... }) + + --- @type any[], table + local ret, upvalues = unpack(M.api.nvim_exec_lua( + [[ + return { + _G.__test_exec_lua:handler(...) + } + ]], + { + string.dump(code), + get_upvalues(code), + ..., + } + )) + + -- Update upvalues + if next(upvalues) then + local caller = debug.getinfo(2) + local f = caller.func + -- On PUC-Lua, if the function is a tail call, then func will be nil. + -- In this case we need to use the current function. + if not f then + assert(caller.source == '=(tail call)') + f = debug.getinfo(1).func + end + set_upvalues(f, upvalues) + end + + return unpack(ret, 1, table.maxn(ret)) end function M.get_pathsep() diff --git a/test/functional/treesitter/highlight_spec.lua b/test/functional/treesitter/highlight_spec.lua index da001e2ab1..50f5734230 100644 --- a/test/functional/treesitter/highlight_spec.lua +++ b/test/functional/treesitter/highlight_spec.lua @@ -187,10 +187,10 @@ describe('treesitter highlighting (C)', function() -- legacy syntax highlighting is used by default screen:expect(hl_grid_legacy_c) - exec_lua(function(hl_query) - vim.treesitter.query.set('c', 'highlights', hl_query) + exec_lua(function() + vim.treesitter.query.set('c', 'highlights', hl_query_c) vim.treesitter.start() - end, hl_query_c) + end) -- treesitter highlighting is used screen:expect(hl_grid_ts_c) @@ -238,11 +238,11 @@ describe('treesitter highlighting (C)', function() ]], } - exec_lua(function(hl_query) + exec_lua(function() local parser = vim.treesitter.get_parser(0, 'c') local highlighter = vim.treesitter.highlighter - highlighter.new(parser, { queries = { c = hl_query } }) - end, hl_query_c) + highlighter.new(parser, { queries = { c = hl_query_c } }) + end) screen:expect(hl_grid_ts_c) feed('5Gocdd') @@ -369,10 +369,10 @@ describe('treesitter highlighting (C)', function() it('is updated with :sort', function() insert(test_text_c) - exec_lua(function(hl_query) + exec_lua(function() local parser = vim.treesitter.get_parser(0, 'c') - vim.treesitter.highlighter.new(parser, { queries = { c = hl_query } }) - end, hl_query_c) + vim.treesitter.highlighter.new(parser, { queries = { c = hl_query_c } }) + end) screen:expect { grid = [[ {3:int} width = {5:INT_MAX}, height = {5:INT_MAX}; | @@ -518,15 +518,15 @@ describe('treesitter highlighting (C)', function() screen:expect { grid = injection_grid_c } - exec_lua(function(hl_query) + exec_lua(function() local parser = vim.treesitter.get_parser(0, 'c', { injections = { c = '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c")) (preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))', }, }) local highlighter = vim.treesitter.highlighter - highlighter.new(parser, { queries = { c = hl_query } }) - end, hl_query_c) + highlighter.new(parser, { queries = { c = hl_query_c } }) + end) screen:expect { grid = injection_grid_expected_c } end) @@ -536,7 +536,7 @@ describe('treesitter highlighting (C)', function() screen:expect { grid = injection_grid_c } - exec_lua(function(hl_query) + exec_lua(function() vim.treesitter.language.register('c', 'foo') local parser = vim.treesitter.get_parser(0, 'c', { injections = { @@ -544,8 +544,8 @@ describe('treesitter highlighting (C)', function() }, }) local highlighter = vim.treesitter.highlighter - highlighter.new(parser, { queries = { c = hl_query } }) - end, hl_query_c) + highlighter.new(parser, { queries = { c = hl_query_c } }) + end) screen:expect { grid = injection_grid_expected_c } end) @@ -559,14 +559,14 @@ describe('treesitter highlighting (C)', function() } ]]) - exec_lua(function(hl_query) + exec_lua(function() local injection_query = '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c")) (preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))' - vim.treesitter.query.set('c', 'highlights', hl_query) + vim.treesitter.query.set('c', 'highlights', hl_query_c) vim.treesitter.query.set('c', 'injections', injection_query) vim.treesitter.highlighter.new(vim.treesitter.get_parser(0, 'c')) - end, hl_query_c) + end) screen:expect { grid = [[ @@ -586,10 +586,10 @@ describe('treesitter highlighting (C)', function() insert(hl_text_c) feed('gg') - exec_lua(function(hl_query) + exec_lua(function() local parser = vim.treesitter.get_parser(0, 'c') - vim.treesitter.highlighter.new(parser, { queries = { c = hl_query } }) - end, hl_query_c) + vim.treesitter.highlighter.new(parser, { queries = { c = hl_query_c } }) + end) screen:expect(hl_grid_ts_c) @@ -629,14 +629,14 @@ describe('treesitter highlighting (C)', function() } ]]) - exec_lua(function(hl_query) + exec_lua(function() local parser = vim.treesitter.get_parser(0, 'c') vim.treesitter.highlighter.new(parser, { queries = { - c = hl_query .. '\n((translation_unit) @constant (#set! "priority" 101))\n', + c = hl_query_c .. '\n((translation_unit) @constant (#set! "priority" 101))\n', }, }) - end, hl_query_c) + end) -- expect everything to have Constant highlight screen:expect { grid = [[ @@ -826,10 +826,10 @@ describe('treesitter highlighting (C)', function() declarator: (pointer_declarator) @variable.parameter) ]] - exec_lua(function(query_str) - vim.treesitter.query.set('c', 'highlights', query_str) + exec_lua(function() + vim.treesitter.query.set('c', 'highlights', query) vim.treesitter.highlighter.new(vim.treesitter.get_parser(0, 'c')) - end, query) + end) screen:expect { grid = [[ diff --git a/test/functional/treesitter/inspect_tree_spec.lua b/test/functional/treesitter/inspect_tree_spec.lua index 6629751152..1f7d15cc96 100644 --- a/test/functional/treesitter/inspect_tree_spec.lua +++ b/test/functional/treesitter/inspect_tree_spec.lua @@ -156,10 +156,10 @@ describe('vim.treesitter.inspect_tree', function() eq('', n.api.nvim_get_vvar('errmsg')) -- close original tree window - exec_lua([[ - vim.api.nvim_set_current_win(tree_win_copy_1) - vim.api.nvim_win_close(tree_win, false) - ]]) + exec_lua(function() + vim.api.nvim_set_current_win(_G.tree_win_copy_1) + vim.api.nvim_win_close(_G.tree_win, false) + end) -- navigates correctly to the remaining source buffer window feed('') diff --git a/test/functional/treesitter/language_spec.lua b/test/functional/treesitter/language_spec.lua index b9934a2e5f..f8191d603a 100644 --- a/test/functional/treesitter/language_spec.lua +++ b/test/functional/treesitter/language_spec.lua @@ -166,10 +166,10 @@ describe('treesitter language API', function() it('retrieve an anonymous node given a range', function() insert([[vim.fn.input()]]) - exec_lua([[ - langtree = vim.treesitter.get_parser(0, "lua") - node = langtree:node_for_range({0, 3, 0, 3}) - ]]) + exec_lua(function() + _G.langtree = vim.treesitter.get_parser(0, 'lua') + _G.node = _G.langtree:node_for_range({ 0, 3, 0, 3 }) + end) eq('.', exec_lua('return node:type()')) end) diff --git a/test/functional/treesitter/node_spec.lua b/test/functional/treesitter/node_spec.lua index 0e77c10e16..d07ed35368 100644 --- a/test/functional/treesitter/node_spec.lua +++ b/test/functional/treesitter/node_spec.lua @@ -58,15 +58,15 @@ describe('treesitter node API', function() it('get_node() with anonymous nodes included', function() insert([[print('test')]]) - exec_lua([[ - parser = vim.treesitter.get_parser(0, 'lua') - tree = parser:parse()[1] - node = vim.treesitter.get_node({ + exec_lua(function() + _G.parser = vim.treesitter.get_parser(0, 'lua') + _G.tree = _G.parser:parse()[1] + _G.node = vim.treesitter.get_node({ bufnr = 0, pos = { 0, 6 }, -- on the first apostrophe include_anonymous = true, }) - ]]) + end) eq("'", lua_eval('node:type()')) eq(false, lua_eval('node:named()')) @@ -120,7 +120,7 @@ describe('treesitter node API', function() local len = exec_lua(function() local tree = vim.treesitter.get_parser(0, 'c'):parse()[1] - local node = tree:root():child(0) + local node = assert(tree:root():child(0)) _G.children = node:named_children() return #_G.children diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua index 61af007782..92379a71bd 100644 --- a/test/functional/treesitter/parser_spec.lua +++ b/test/functional/treesitter/parser_spec.lua @@ -660,8 +660,8 @@ print() end) local function run_query() - return exec_lua(function(query_str) - local query = vim.treesitter.query.parse('c', query_str) + return exec_lua(function() + local query = vim.treesitter.query.parse('c', query0) local parser = vim.treesitter.get_parser() local tree = parser:parse()[1] local res = {} @@ -669,7 +669,7 @@ print() table.insert(res, { query.captures[id], node:range() }) end return res - end, query0) + end) end eq({ @@ -707,15 +707,15 @@ print() ]] ]==] - local r = exec_lua(function(src) - local parser = vim.treesitter.get_string_parser(src, 'lua') + local r = exec_lua(function() + local parser = vim.treesitter.get_string_parser(source, 'lua') parser:parse(true) local ranges = {} parser:for_each_tree(function(tstree, tree) ranges[tree:lang()] = { tstree:root():range(true) } end) return ranges - end, source) + end) eq({ lua = { 0, 6, 6, 16, 4, 438 }, @@ -727,14 +727,14 @@ print() -- the ranges but only provide a Range4. Strip the byte entries from the ranges and make sure -- add_bytes() produces the same result. - local rb = exec_lua(function(r0, source0) + local rb = exec_lua(function() local add_bytes = require('vim.treesitter._range').add_bytes - for lang, range in pairs(r0) do - r0[lang] = { range[1], range[2], range[4], range[5] } - r0[lang] = add_bytes(source0, r0[lang]) + for lang, range in pairs(r) do + r[lang] = { range[1], range[2], range[4], range[5] } + r[lang] = add_bytes(source, r[lang]) end - return r0 - end, r, source) + return r + end) eq(rb, r) end) diff --git a/test/functional/treesitter/query_spec.lua b/test/functional/treesitter/query_spec.lua index d8338c1335..c97619c913 100644 --- a/test/functional/treesitter/query_spec.lua +++ b/test/functional/treesitter/query_spec.lua @@ -82,17 +82,17 @@ void ui_refresh(void) local long_query = test_query:rep(100) ---@return number local function q(_n) - return exec_lua(function(query, n0) + return exec_lua(function() local before = vim.api.nvim__stats().ts_query_parse_count collectgarbage('stop') - for _ = 1, n0, 1 do - vim.treesitter.query.parse('c', query, n0) + for _ = 1, _n, 1 do + vim.treesitter.query.parse('c', long_query, _n) end collectgarbage('restart') collectgarbage('collect') local after = vim.api.nvim__stats().ts_query_parse_count return after - before - end, long_query, _n) + end) end eq(1, q(1)) @@ -103,8 +103,8 @@ void ui_refresh(void) it('supports query and iter by capture (iter_captures)', function() insert(test_text) - local res = exec_lua(function(test_query0) - local cquery = vim.treesitter.query.parse('c', test_query0) + local res = exec_lua(function() + local cquery = vim.treesitter.query.parse('c', test_query) local parser = vim.treesitter.get_parser(0, 'c') local tree = parser:parse()[1] local res = {} @@ -113,7 +113,7 @@ void ui_refresh(void) table.insert(res, { '@' .. cquery.captures[cid], node:type(), node:range() }) end return res - end, test_query) + end) eq({ { '@type', 'primitive_type', 8, 2, 8, 6 }, -- bool @@ -133,8 +133,8 @@ void ui_refresh(void) insert(test_text) ---@type table - local res = exec_lua(function(test_query0) - local cquery = vim.treesitter.query.parse('c', test_query0) + local res = exec_lua(function() + local cquery = vim.treesitter.query.parse('c', test_query) local parser = vim.treesitter.get_parser(0, 'c') local tree = parser:parse()[1] local res = {} @@ -149,7 +149,7 @@ void ui_refresh(void) table.insert(res, { pattern, mrepr }) end return res - end, test_query) + end) eq({ { 3, { { '@type', 'primitive_type', 8, 2, 8, 6 } } }, @@ -449,7 +449,7 @@ void ui_refresh(void) local custom_query = '((identifier) @main (#is-main? @main))' do - local res = exec_lua(function(custom_query0) + local res = exec_lua(function() local query = vim.treesitter.query local function is_main(match, _pattern, bufnr, predicate) @@ -466,7 +466,7 @@ void ui_refresh(void) query.add_predicate('is-main?', is_main) - local query0 = query.parse('c', custom_query0) + local query0 = query.parse('c', custom_query) local nodes = {} for _, node in query0:iter_captures(parser:parse()[1]:root(), 0) do @@ -474,14 +474,14 @@ void ui_refresh(void) end return nodes - end, custom_query) + end) eq({ { 0, 4, 0, 8 } }, res) end -- Once with the old API. Remove this whole 'do' block in 0.12 do - local res = exec_lua(function(custom_query0) + local res = exec_lua(function() local query = vim.treesitter.query local function is_main(match, _pattern, bufnr, predicate) @@ -494,7 +494,7 @@ void ui_refresh(void) query.add_predicate('is-main?', is_main, { all = false, force = true }) - local query0 = query.parse('c', custom_query0) + local query0 = query.parse('c', custom_query) local nodes = {} for _, node in query0:iter_captures(parser:parse()[1]:root(), 0) do @@ -502,7 +502,7 @@ void ui_refresh(void) end return nodes - end, custom_query) + end) -- Remove this 'do' block in 0.12 eq(0, fn.has('nvim-0.12')) @@ -538,15 +538,15 @@ void ui_refresh(void) local function test(input, query) api.nvim_buf_set_lines(0, 0, -1, true, vim.split(dedent(input), '\n')) - return exec_lua(function(query_str) + return exec_lua(function() local parser = vim.treesitter.get_parser(0, 'lua') - local query0 = vim.treesitter.query.parse('lua', query_str) + local query0 = vim.treesitter.query.parse('lua', query) local nodes = {} for _, node in query0:iter_captures(parser:parse()[1]:root(), 0) do nodes[#nodes + 1] = { node:range() } end return nodes - end, query) + end) end eq( @@ -641,8 +641,8 @@ void ui_refresh(void) eq(0, fn.has('nvim-0.12')) insert(test_text) - local res = exec_lua(function(test_query0) - local cquery = vim.treesitter.query.parse('c', test_query0) + local res = exec_lua(function() + local cquery = vim.treesitter.query.parse('c', test_query) local parser = vim.treesitter.get_parser(0, 'c') local tree = parser:parse()[1] local res = {} @@ -654,7 +654,7 @@ void ui_refresh(void) table.insert(res, { pattern, mrepr }) end return res - end, test_query) + end) eq({ { 3, { { '@type', 'primitive_type', 8, 2, 8, 6 } } }, @@ -686,19 +686,19 @@ void ui_refresh(void) int bar = 13; ]] - local ret = exec_lua(function(str) - local parser = vim.treesitter.get_string_parser(str, 'c') + local ret = exec_lua(function() + local parser = vim.treesitter.get_string_parser(txt, 'c') local nodes = {} local query = vim.treesitter.query.parse('c', '((identifier) @foo)') - local first_child = parser:parse()[1]:root():child(1) + local first_child = assert(parser:parse()[1]:root():child(1)) - for _, node in query:iter_captures(first_child, str) do + for _, node in query:iter_captures(first_child, txt) do table.insert(nodes, { node:range() }) end return nodes - end, txt) + end) eq({ { 1, 10, 1, 13 } }, ret) end) @@ -801,8 +801,8 @@ void ui_refresh(void) (#eq? @function.name "foo")) ]] - local result = exec_lua(function(query_str) - local query0 = vim.treesitter.query.parse('c', query_str) + local result = exec_lua(function() + local query0 = vim.treesitter.query.parse('c', query) local match_preds = query0.match_preds local called = 0 function query0:match_preds(...) @@ -816,7 +816,7 @@ void ui_refresh(void) captures[#captures + 1] = id end return { called, captures } - end, query) + end) eq({ 2, { 1, 1, 2, 2 } }, result) end) -- cgit From 4e4b1b65903b973cb447b5a70413d0e0363c20f0 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sat, 21 Sep 2024 18:26:25 +0200 Subject: test(terminal): unskip wrap tests on windows These should have been unskipped again when reflow was reenabled. --- test/functional/terminal/window_spec.lua | 2 -- 1 file changed, 2 deletions(-) (limited to 'test/functional') diff --git a/test/functional/terminal/window_spec.lua b/test/functional/terminal/window_spec.lua index f97bfd0a2f..fdb606e959 100644 --- a/test/functional/terminal/window_spec.lua +++ b/test/functional/terminal/window_spec.lua @@ -57,7 +57,6 @@ describe(':terminal window', function() describe("with 'number'", function() it('wraps text', function() - skip(is_os('win')) -- todo(clason): unskip when reenabling reflow feed([[]]) feed([[:set numberwidth=1 numberi]]) screen:expect([[ @@ -107,7 +106,6 @@ describe(':terminal window', function() describe("with 'statuscolumn'", function() it('wraps text', function() - skip(is_os('win')) -- todo(clason): unskip when reenabling reflow command([[set number statuscolumn=++%l\ \ ]]) screen:expect([[ {7:++1 }tty ready | -- cgit From e697c1b43dfbeab132fee4149157f7abd08c51a0 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 22 Sep 2024 06:02:48 +0800 Subject: fix(paste): improve repeating of pasted text (#30438) - Fixes 'autoindent' being applied during redo. - Makes redoing a large paste significantly faster. - Stores pasted text in the register being recorded. Fix #28561 --- test/functional/api/vim_spec.lua | 56 ++++++++++++++++++++++++++++++++++- test/functional/terminal/tui_spec.lua | 13 ++++++-- 2 files changed, 66 insertions(+), 3 deletions(-) (limited to 'test/functional') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 71703c9b05..ae61e50624 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -1301,8 +1301,62 @@ 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 '' 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('vim.paste() failure', function() api.nvim_exec_lua('vim.paste = (function(lines, phase) error("fake fail") end)', {}) diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 3e837e796d..a8a664a568 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -1106,7 +1106,7 @@ describe('TUI', function() screen:expect(expected_grid1) -- Dot-repeat/redo. feed_data('.') - screen:expect([[ + local expected_grid2 = [[ ESC:{6:^[} / CR: | xline 1 | ESC:{6:^[} / CR: | @@ -1114,7 +1114,8 @@ describe('TUI', function() {5:[No Name] [+] 5,1 Bot}| | {3:-- TERMINAL --} | - ]]) + ]] + screen:expect(expected_grid2) -- Undo. feed_data('u') expect_child_buf_lines(expected_crlf) @@ -1128,6 +1129,14 @@ describe('TUI', function() feed_data('\027[200~' .. table.concat(expected_lf, '\r\n') .. '\027[201~') screen:expect(expected_grid1) expect_child_buf_lines(expected_crlf) + -- Dot-repeat/redo. + feed_data('.') + screen:expect(expected_grid2) + -- Undo. + feed_data('u') + expect_child_buf_lines(expected_crlf) + feed_data('u') + expect_child_buf_lines({ '' }) end) it('paste: cmdline-mode inserts 1 line', function() -- cgit From 29bceb4f758097cc6b66726f1dcd3967ad170e35 Mon Sep 17 00:00:00 2001 From: Evgeni Chasnovski Date: Sun, 22 Sep 2024 13:51:22 +0300 Subject: docs(api): nvim_get_runtime_file preserves 'runtimepath' order #30454 --- test/functional/api/vim_spec.lua | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'test/functional') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index ae61e50624..ea6b70f4d7 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -3307,6 +3307,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() -- cgit From 511b991e66892b4bb8176ce64c0e8fefb300f638 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Sat, 21 Sep 2024 16:23:00 +0100 Subject: feat(fs.lua): add vim.fs.rm() Analogous to the shell `rm` command. --- test/functional/testnvim.lua | 43 +++---------------------------------------- 1 file changed, 3 insertions(+), 40 deletions(-) (limited to 'test/functional') diff --git a/test/functional/testnvim.lua b/test/functional/testnvim.lua index 36e6b4d7bd..8a2281e2a1 100644 --- a/test/functional/testnvim.lua +++ b/test/functional/testnvim.lua @@ -759,58 +759,21 @@ function M.assert_visible(bufnr, visible) end end ---- @param path string -local function do_rmdir(path) - local stat = uv.fs_stat(path) - if stat == nil then - return - end - if stat.type ~= 'directory' then - error(string.format('rmdir: not a directory: %s', path)) - end - for file in vim.fs.dir(path) do - if file ~= '.' and file ~= '..' then - local abspath = path .. '/' .. file - if t.isdir(abspath) then - do_rmdir(abspath) -- recurse - else - local ret, err = os.remove(abspath) - if not ret then - if not session then - error('os.remove: ' .. err) - else - -- Try Nvim delete(): it handles `readonly` attribute on Windows, - -- and avoids Lua cross-version/platform incompatibilities. - if -1 == M.call('delete', abspath) then - local hint = (is_os('win') and ' (hint: try :%bwipeout! before rmdir())' or '') - error('delete() failed' .. hint .. ': ' .. abspath) - end - end - end - end - end - end - local ret, err = uv.fs_rmdir(path) - if not ret then - error('luv.fs_rmdir(' .. path .. '): ' .. err) - end -end - local start_dir = uv.cwd() function M.rmdir(path) - local ret, _ = pcall(do_rmdir, path) + local ret, _ = pcall(vim.fs.rm, path, { recursive = true, force = true }) if not ret and is_os('win') then -- Maybe "Permission denied"; try again after changing the nvim -- process to the top-level directory. M.command([[exe 'cd '.fnameescape(']] .. start_dir .. "')") - ret, _ = pcall(do_rmdir, path) + ret, _ = pcall(vim.fs.rm, path, { recursive = true, force = true }) end -- During teardown, the nvim process may not exit quickly enough, then rmdir() -- will fail (on Windows). if not ret then -- Try again. sleep(1000) - do_rmdir(path) + vim.fs.rm(path, { recursive = true, force = true }) end end -- cgit From bfe0acaea167a5ce18d4c63f65ccd45966203413 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 23 Sep 2024 12:04:07 +0800 Subject: vim-patch:9.1.0740: incorrect internal diff with empty file (#30471) Problem: incorrect internal diff with an empty file Solution: Set pointer to NULL, instead of using an empty line file (Yukihiro Nakadaira) When using internal diff, empty file is read as one empty line file. So result differs from external diff. closes: vim/vim#15719 https://github.com/vim/vim/commit/f1694b439bb175d956b49da620f1253462ec507b Co-authored-by: Yukihiro Nakadaira --- test/functional/ui/diff_spec.lua | 28 ++++++++++++++++++++++++++++ test/functional/ui/highlight_spec.lua | 6 +++--- 2 files changed, 31 insertions(+), 3 deletions(-) (limited to 'test/functional') diff --git a/test/functional/ui/diff_spec.lua b/test/functional/ui/diff_spec.lua index bad35dd2af..8db6f776d1 100644 --- a/test/functional/ui/diff_spec.lua +++ b/test/functional/ui/diff_spec.lua @@ -614,6 +614,34 @@ int main(int argc, char **argv) ]]) end) + it('Diff empty and non-empty file', function() + write_file(fname, '', false) + write_file(fname_2, 'foo\nbar\nbaz', false) + reread() + + feed(':set diffopt=filler') + screen:expect([[ + {7: }{23:------------------}│{7: }{22:foo }| + {7: }{23:------------------}│{7: }{22:bar }| + {7: }{23:------------------}│{7: }{22:baz }| + {7: }^ │{1:~ }| + {1:~ }│{1:~ }|*10 + {3:') + screen:expect([[ + {7: }{23:------------------}│{7: }{22:foo }| + {7: }{23:------------------}│{7: }{22:bar }| + {7: }{23:------------------}│{7: }{22:baz }| + {7: }^ │{1:~ }| + {1:~ }│{1:~ }|*10 + {3: Date: Mon, 23 Sep 2024 19:50:57 +0800 Subject: test(tui_spec): prevent another case of race between paste and input (#30481) Problem: When input immediately follows end of bracketed paste, the nvim_input may be processed before the nvim_paste. Solution: Ensure some waiting after the end of a bracketed paste. --- test/functional/terminal/tui_spec.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index a8a664a568..b85ddec0f0 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -975,6 +975,7 @@ describe('TUI', function() {3:-- TERMINAL --} | ]]) feed_data('\027[201~') -- End paste. + screen:expect_unchanged() feed_data('\027[27u') -- ESC: go to Normal mode. wait_for_mode('n') screen:expect([[ @@ -1200,6 +1201,7 @@ describe('TUI', function() expect_cmdline('"stuff 1 more"') -- End the paste sequence. feed_data('\027[201~') + expect_cmdline('"stuff 1 more"') feed_data(' typed') expect_cmdline('"stuff 1 more typed"') end) @@ -1243,6 +1245,7 @@ describe('TUI', function() feed_data('line 7\nline 8\n') -- Stop paste. feed_data('\027[201~') + screen:expect_unchanged() feed_data('\n') -- to dismiss hit-enter prompt expect_child_buf_lines({ 'foo', '' }) -- Dot-repeat/redo is not modified by failed paste. @@ -1290,6 +1293,7 @@ describe('TUI', function() {} ) feed_data('\027[200~line A\nline B\n\027[201~') + expect_child_buf_lines({ '' }) feed_data('ifoo\n\027[27u') expect_child_buf_lines({ 'foo', '' }) end) @@ -1412,7 +1416,6 @@ describe('TUI', function() feed_data('\n') -- Send the "stop paste" sequence. feed_data('\027[201~') - screen:expect([[ | pasted from terminal (1) | -- cgit From 737f58e23230ea14f1648ac1fc7f442ea0f8563c Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Fri, 20 Sep 2024 07:34:50 +0200 Subject: refactor(api)!: rename Dictionary => Dict In the api_info() output: :new|put =map(filter(api_info().functions, '!has_key(v:val,''deprecated_since'')'), 'v:val') ... {'return_type': 'ArrayOf(Integer, 2)', 'name': 'nvim_win_get_position', 'method': v:true, 'parameters': [['Window', 'window']], 'since': 1} The `ArrayOf(Integer, 2)` return type didn't break clients when we added it, which is evidence that clients don't use the `return_type` field, thus renaming Dictionary => Dict in api_info() is not (in practice) a breaking change. --- test/functional/api/vim_spec.lua | 8 +- test/functional/lua/api_spec.lua | 25 ++-- test/functional/lua/luaeval_spec.lua | 2 +- test/functional/lua/vim_spec.lua | 128 ++++++++++----------- test/functional/plugin/health_spec.lua | 2 +- test/functional/shada/errors_spec.lua | 12 +- test/functional/vimscript/changedtick_spec.lua | 4 +- test/functional/vimscript/ctx_functions_spec.lua | 6 +- test/functional/vimscript/input_spec.lua | 8 +- test/functional/vimscript/json_functions_spec.lua | 2 +- test/functional/vimscript/map_functions_spec.lua | 4 +- .../vimscript/msgpack_functions_spec.lua | 14 +-- test/functional/vimscript/string_spec.lua | 8 +- 13 files changed, 110 insertions(+), 113 deletions(-) (limited to 'test/functional') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index ea6b70f4d7..b35ccb0c40 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -693,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( @@ -1573,7 +1573,7 @@ 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() }) @@ -2212,7 +2212,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))) @@ -2228,7 +2228,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 = { {} } }) diff --git a/test/functional/lua/api_spec.lua b/test/functional/lua/api_spec.lua index 4bbb57c3a8..741ed0cf6e 100644 --- a/test/functional/lua/api_spec.lua +++ b/test/functional/lua/api_spec.lua @@ -224,42 +224,39 @@ describe('luaeval(vim.api.…)', function() end) it('correctly converts dictionaries with type_idx to API objects', function() - eq( - 4, - eval([[type(luaeval('vim.api.nvim__id_dictionary({[vim.type_idx]=vim.types.dictionary})'))]]) - ) + eq(4, eval([[type(luaeval('vim.api.nvim__id_dict({[vim.type_idx]=vim.types.dictionary})'))]])) - eq({}, fn.luaeval('vim.api.nvim__id_dictionary({[vim.type_idx]=vim.types.dictionary})')) + eq({}, fn.luaeval('vim.api.nvim__id_dict({[vim.type_idx]=vim.types.dictionary})')) eq( { v = { 42 } }, fn.luaeval( - 'vim.api.nvim__id_dictionary({v={[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}})' + 'vim.api.nvim__id_dict({v={[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}})' ) ) eq( { foo = 2 }, fn.luaeval( - 'vim.api.nvim__id_dictionary({[vim.type_idx]=vim.types.dictionary, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})' + 'vim.api.nvim__id_dict({[vim.type_idx]=vim.types.dictionary, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})' ) ) eq( { v = 10 }, fn.luaeval( - 'vim.api.nvim__id_dictionary({v={[vim.type_idx]=vim.types.float, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}})' + 'vim.api.nvim__id_dict({v={[vim.type_idx]=vim.types.float, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}})' ) ) eq( { v = {} }, fn.luaeval( - 'vim.api.nvim__id_dictionary({v={[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2}})' + 'vim.api.nvim__id_dict({v={[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2}})' ) ) - -- If API requests dictionary, then empty table will be the one. This is not + -- If API requests dict, then empty table will be the one. This is not -- the case normally because empty table is an empty array. - eq({}, fn.luaeval('vim.api.nvim__id_dictionary({})')) - eq(4, eval([[type(luaeval('vim.api.nvim__id_dictionary({})'))]])) + eq({}, fn.luaeval('vim.api.nvim__id_dict({})')) + eq(4, eval([[type(luaeval('vim.api.nvim__id_dict({})'))]])) end) it('converts booleans in positional args', function() @@ -365,12 +362,12 @@ describe('luaeval(vim.api.…)', function() eq( [[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Invalid 'dct': Expected Lua table]], - remove_trace(exc_exec([[call luaeval("vim.api.nvim__id_dictionary(1)")]])) + remove_trace(exc_exec([[call luaeval("vim.api.nvim__id_dict(1)")]])) ) eq( [[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Invalid 'dct': Expected Dict-like Lua table]], remove_trace( - exc_exec([[call luaeval("vim.api.nvim__id_dictionary({[vim.type_idx]=vim.types.array})")]]) + exc_exec([[call luaeval("vim.api.nvim__id_dict({[vim.type_idx]=vim.types.array})")]]) ) ) diff --git a/test/functional/lua/luaeval_spec.lua b/test/functional/lua/luaeval_spec.lua index e66d457237..2b23f72c7d 100644 --- a/test/functional/lua/luaeval_spec.lua +++ b/test/functional/lua/luaeval_spec.lua @@ -186,7 +186,7 @@ describe('luaeval()', function() end) it('issues an error in some cases', function() - eq("Vim(call):E5100: Cannot convert given lua table: table should contain either only integer keys or only string keys", + eq("Vim(call):E5100: Cannot convert given Lua table: table should contain either only integer keys or only string keys", exc_exec('call luaeval("{1, foo=2}")')) startswith("Vim(call):E5107: Error loading lua [string \"luaeval()\"]:", diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 599b688bf4..1e199818d3 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -1229,7 +1229,7 @@ describe('lua stdlib', function() ) end) - it('vim.fn should error when calling API function', function() + it('vim.fn errors when calling API function', function() matches( 'Tried to call API function with vim.fn: use vim.api.nvim_get_current_line instead', pcall_err(exec_lua, 'vim.fn.nvim_get_current_line()') @@ -1947,7 +1947,7 @@ describe('lua stdlib', function() eq(NIL, fn.luaeval 'vim.v.null') matches([[attempt to index .* nil value]], pcall_err(exec_lua, 'return vim.v[0].progpath')) eq('Key is read-only: count', pcall_err(exec_lua, [[vim.v.count = 42]])) - eq('Dictionary is locked', pcall_err(exec_lua, [[vim.v.nosuchvar = 42]])) + eq('Dict is locked', pcall_err(exec_lua, [[vim.v.nosuchvar = 42]])) eq('Key is fixed: errmsg', pcall_err(exec_lua, [[vim.v.errmsg = nil]])) exec_lua([[vim.v.errmsg = 'set by Lua']]) eq('set by Lua', eval('v:errmsg')) @@ -2067,7 +2067,7 @@ describe('lua stdlib', function() -- TODO: We still need to write some tests for optlocal, opt and then getting the options -- Probably could also do some stuff with getting things from viml side as well to confirm behavior is the same. - it('should allow setting number values', function() + it('allows setting number values', function() local scrolloff = exec_lua [[ vim.opt.scrolloff = 10 return vim.o.scrolloff @@ -2075,7 +2075,7 @@ describe('lua stdlib', function() eq(10, scrolloff) end) - pending('should handle STUPID window things', function() + pending('handles STUPID window things', function() local result = exec_lua [[ local result = {} @@ -2088,7 +2088,7 @@ describe('lua stdlib', function() eq({}, result) end) - it('should allow setting tables', function() + it('allows setting tables', function() local wildignore = exec_lua [[ vim.opt.wildignore = { 'hello', 'world' } return vim.o.wildignore @@ -2096,7 +2096,7 @@ describe('lua stdlib', function() eq('hello,world', wildignore) end) - it('should allow setting tables with shortnames', function() + it('allows setting tables with shortnames', function() local wildignore = exec_lua [[ vim.opt.wig = { 'hello', 'world' } return vim.o.wildignore @@ -2104,7 +2104,7 @@ describe('lua stdlib', function() eq('hello,world', wildignore) end) - it('should error when you attempt to set string values to numeric options', function() + it('errors when you attempt to set string values to numeric options', function() local result = exec_lua [[ return { pcall(function() vim.opt.textwidth = 'hello world' end) @@ -2114,7 +2114,7 @@ describe('lua stdlib', function() eq(false, result[1]) end) - it('should error when you attempt to setlocal a global value', function() + it('errors when you attempt to setlocal a global value', function() local result = exec_lua [[ return pcall(function() vim.opt_local.clipboard = "hello" end) ]] @@ -2122,7 +2122,7 @@ describe('lua stdlib', function() eq(false, result) end) - it('should allow you to set boolean values', function() + it('allows you to set boolean values', function() eq( { true, false, true }, exec_lua [[ @@ -2142,7 +2142,7 @@ describe('lua stdlib', function() ) end) - it('should change current buffer values and defaults for global local values', function() + it('changes current buffer values and defaults for global local values', function() local result = exec_lua [[ local result = {} @@ -2181,7 +2181,7 @@ describe('lua stdlib', function() eq('', result[8]) end) - it('should allow you to retrieve window opts even if they have not been set', function() + it('allows you to retrieve window opts even if they have not been set', function() local result = exec_lua [[ local result = {} table.insert(result, vim.opt.number:get()) @@ -2196,7 +2196,7 @@ describe('lua stdlib', function() eq({ false, false, true, true }, result) end) - it('should allow all sorts of string manipulation', function() + it('allows all sorts of string manipulation', function() eq( { 'hello', 'hello world', 'start hello world' }, exec_lua [[ @@ -2217,7 +2217,7 @@ describe('lua stdlib', function() end) describe('option:get()', function() - it('should work for boolean values', function() + it('works for boolean values', function() eq( false, exec_lua [[ @@ -2227,7 +2227,7 @@ describe('lua stdlib', function() ) end) - it('should work for number values', function() + it('works for number values', function() local tabstop = exec_lua [[ vim.opt.tabstop = 10 return vim.opt.tabstop:get() @@ -2236,7 +2236,7 @@ describe('lua stdlib', function() eq(10, tabstop) end) - it('should work for string values', function() + it('works for string values', function() eq( 'hello world', exec_lua [[ @@ -2246,7 +2246,7 @@ describe('lua stdlib', function() ) end) - it('should work for set type flaglists', function() + it('works for set type flaglists', function() local formatoptions = exec_lua [[ vim.opt.formatoptions = 'tcro' return vim.opt.formatoptions:get() @@ -2256,7 +2256,7 @@ describe('lua stdlib', function() eq(true, not formatoptions.q) end) - it('should work for set type flaglists', function() + it('works for set type flaglists', function() local formatoptions = exec_lua [[ vim.opt.formatoptions = { t = true, c = true, r = true, o = true } return vim.opt.formatoptions:get() @@ -2266,7 +2266,7 @@ describe('lua stdlib', function() eq(true, not formatoptions.q) end) - it('should work for array list type options', function() + it('works for array list type options', function() local wildignore = exec_lua [[ vim.opt.wildignore = "*.c,*.o,__pycache__" return vim.opt.wildignore:get() @@ -2276,7 +2276,7 @@ describe('lua stdlib', function() eq('*.c', wildignore[1]) end) - it('should work for options that are both commalist and flaglist', function() + it('works for options that are both commalist and flaglist', function() local result = exec_lua [[ vim.opt.whichwrap = "b,s" return vim.opt.whichwrap:get() @@ -2292,7 +2292,7 @@ describe('lua stdlib', function() eq({ b = true, h = true }, result) end) - it('should work for key-value pair options', function() + it('works for key-value pair options', function() local listchars = exec_lua [[ vim.opt.listchars = "tab:> ,space:_" return vim.opt.listchars:get() @@ -2304,7 +2304,7 @@ describe('lua stdlib', function() }, listchars) end) - it('should allow you to add numeric options', function() + it('allows you to add numeric options', function() eq( 16, exec_lua [[ @@ -2315,7 +2315,7 @@ describe('lua stdlib', function() ) end) - it('should allow you to subtract numeric options', function() + it('allows you to subtract numeric options', function() eq( 2, exec_lua [[ @@ -2328,7 +2328,7 @@ describe('lua stdlib', function() end) describe('key:value style options', function() - it('should handle dictionary style', function() + it('handles dict style', function() local listchars = exec_lua [[ vim.opt.listchars = { eol = "~", @@ -2340,7 +2340,7 @@ describe('lua stdlib', function() eq('eol:~,space:.', listchars) end) - it('should allow adding dictionary style', function() + it('allows adding dict style', function() local listchars = exec_lua [[ vim.opt.listchars = { eol = "~", @@ -2355,7 +2355,7 @@ describe('lua stdlib', function() eq('eol:~,space:-', listchars) end) - it('should allow adding dictionary style', function() + it('allows adding dict style', function() local listchars = exec_lua [[ vim.opt.listchars = { eol = "~", @@ -2369,7 +2369,7 @@ describe('lua stdlib', function() eq('eol:~,space:_', listchars) end) - it('should allow completely new keys', function() + it('allows completely new keys', function() local listchars = exec_lua [[ vim.opt.listchars = { eol = "~", @@ -2383,7 +2383,7 @@ describe('lua stdlib', function() eq('eol:~,space:.,tab:>>>', listchars) end) - it('should allow subtracting dictionary style', function() + it('allows subtracting dict style', function() local listchars = exec_lua [[ vim.opt.listchars = { eol = "~", @@ -2397,7 +2397,7 @@ describe('lua stdlib', function() eq('eol:~', listchars) end) - it('should allow subtracting dictionary style', function() + it('allows subtracting dict style', function() local listchars = exec_lua [[ vim.opt.listchars = { eol = "~", @@ -2411,7 +2411,7 @@ describe('lua stdlib', function() eq('', listchars) end) - it('should allow subtracting dictionary style multiple times', function() + it('allows subtracting dict style multiple times', function() local listchars = exec_lua [[ vim.opt.listchars = { eol = "~", @@ -2425,7 +2425,7 @@ describe('lua stdlib', function() eq('eol:~', listchars) end) - it('should allow adding a key:value string to a listchars', function() + it('allows adding a key:value string to a listchars', function() local listchars = exec_lua [[ vim.opt.listchars = { eol = "~", @@ -2439,7 +2439,7 @@ describe('lua stdlib', function() eq('eol:~,space:.,tab:>~', listchars) end) - it('should allow prepending a key:value string to a listchars', function() + it('allows prepending a key:value string to a listchars', function() local listchars = exec_lua [[ vim.opt.listchars = { eol = "~", @@ -2454,7 +2454,7 @@ describe('lua stdlib', function() end) end) - it('should automatically set when calling remove', function() + it('automatically sets when calling remove', function() eq( 'foo,baz', exec_lua [[ @@ -2466,7 +2466,7 @@ describe('lua stdlib', function() ) end) - it('should automatically set when calling remove with a table', function() + it('automatically sets when calling remove with a table', function() eq( 'foo', exec_lua [[ @@ -2478,7 +2478,7 @@ describe('lua stdlib', function() ) end) - it('should automatically set when calling append', function() + it('automatically sets when calling append', function() eq( 'foo,bar,baz,bing', exec_lua [[ @@ -2490,7 +2490,7 @@ describe('lua stdlib', function() ) end) - it('should automatically set when calling append with a table', function() + it('automatically sets when calling append with a table', function() eq( 'foo,bar,baz,bing,zap', exec_lua [[ @@ -2502,7 +2502,7 @@ describe('lua stdlib', function() ) end) - it('should allow adding tables', function() + it('allows adding tables', function() local wildignore = exec_lua [[ vim.opt.wildignore = 'foo' return vim.o.wildignore @@ -2516,7 +2516,7 @@ describe('lua stdlib', function() eq('foo,bar,baz', wildignore) end) - it('should handle adding duplicates', function() + it('handles adding duplicates', function() local wildignore = exec_lua [[ vim.opt.wildignore = 'foo' return vim.o.wildignore @@ -2536,7 +2536,7 @@ describe('lua stdlib', function() eq('foo,bar,baz', wildignore) end) - it('should allow adding multiple times', function() + it('allows adding multiple times', function() local wildignore = exec_lua [[ vim.opt.wildignore = 'foo' vim.opt.wildignore = vim.opt.wildignore + 'bar' + 'baz' @@ -2545,7 +2545,7 @@ describe('lua stdlib', function() eq('foo,bar,baz', wildignore) end) - it('should remove values when you use minus', function() + it('removes values when you use minus', function() local wildignore = exec_lua [[ vim.opt.wildignore = 'foo' return vim.o.wildignore @@ -2565,7 +2565,7 @@ describe('lua stdlib', function() eq('foo,baz', wildignore) end) - it('should prepend values when using ^', function() + it('prepends values when using ^', function() local wildignore = exec_lua [[ vim.opt.wildignore = 'foo' vim.opt.wildignore = vim.opt.wildignore ^ 'first' @@ -2580,7 +2580,7 @@ describe('lua stdlib', function() eq('super_first,first,foo', wildignore) end) - it('should not remove duplicates from wildmode: #14708', function() + it('does not remove duplicates from wildmode: #14708', function() local wildmode = exec_lua [[ vim.opt.wildmode = {"full", "list", "full"} return vim.o.wildmode @@ -2590,7 +2590,7 @@ describe('lua stdlib', function() end) describe('option types', function() - it('should allow to set option with numeric value', function() + it('allows to set option with numeric value', function() eq( 4, exec_lua [[ @@ -2639,7 +2639,7 @@ describe('lua stdlib', function() ) end) - it('should allow to set option with boolean value', function() + it('allows to set option with boolean value', function() eq( true, exec_lua [[ @@ -2688,7 +2688,7 @@ describe('lua stdlib', function() ) end) - it('should allow to set option with array or string value', function() + it('allows to set option with array or string value', function() eq( 'indent,eol,start', exec_lua [[ @@ -2735,7 +2735,7 @@ describe('lua stdlib', function() ) end) - it('should allow set option with map or string value', function() + it('allows set option with map or string value', function() eq( 'eol:~,space:.', exec_lua [[ @@ -2785,7 +2785,7 @@ describe('lua stdlib', function() ) end) - it('should allow set option with set or string value', function() + it('allows set option with set or string value', function() local ww = exec_lua [[ vim.opt.whichwrap = { b = true, @@ -3235,11 +3235,11 @@ describe('lua stdlib', function() ]] end) - it('should run from lua', function() + it('runs from lua', function() exec_lua [[vim.wait(100, function() return true end)]] end) - it('should wait the expected time if false', function() + it('waits the expected time if false', function() eq( { time = true, wait_result = { false, -1 } }, exec_lua [[ @@ -3255,7 +3255,7 @@ describe('lua stdlib', function() ) end) - it('should not block other events', function() + it('does not block other events', function() eq( { time = true, wait_result = true }, exec_lua [[ @@ -3280,7 +3280,7 @@ describe('lua stdlib', function() ) end) - it('should not process non-fast events when commanded', function() + it('does not process non-fast events when commanded', function() eq( { wait_result = false }, exec_lua [[ @@ -3303,7 +3303,7 @@ describe('lua stdlib', function() ) end) - it('should work with vim.defer_fn', function() + it('works with vim.defer_fn', function() eq( { time = true, wait_result = true }, exec_lua [[ @@ -3320,7 +3320,7 @@ describe('lua stdlib', function() ) end) - it('should not crash when callback errors', function() + it('does not crash when callback errors', function() local result = exec_lua [[ return {pcall(function() vim.wait(1000, function() error("As Expected") end) end)} ]] @@ -3336,7 +3336,7 @@ describe('lua stdlib', function() ) end) - it('should allow waiting with no callback, explicit', function() + it('allows waiting with no callback, explicit', function() eq( true, exec_lua [[ @@ -3347,7 +3347,7 @@ describe('lua stdlib', function() ) end) - it('should allow waiting with no callback, implicit', function() + it('allows waiting with no callback, implicit', function() eq( true, exec_lua [[ @@ -3358,7 +3358,7 @@ describe('lua stdlib', function() ) end) - it('should call callbacks exactly once if they return true immediately', function() + it('calls callbacks exactly once if they return true immediately', function() eq( true, exec_lua [[ @@ -3372,7 +3372,7 @@ describe('lua stdlib', function() ) end) - it('should call callbacks few times with large `interval`', function() + it('calls callbacks few times with large `interval`', function() eq( true, exec_lua [[ @@ -3383,7 +3383,7 @@ describe('lua stdlib', function() ) end) - it('should play nice with `not` when fails', function() + it('plays nice with `not` when fails', function() eq( true, exec_lua [[ @@ -3396,7 +3396,7 @@ describe('lua stdlib', function() ) end) - it('should play nice with `if` when success', function() + it('plays nice with `if` when success', function() eq( true, exec_lua [[ @@ -3409,7 +3409,7 @@ describe('lua stdlib', function() ) end) - it('should return immediately with false if timeout is 0', function() + it('returns immediately with false if timeout is 0', function() eq( { false, -1 }, exec_lua [[ @@ -3420,7 +3420,7 @@ describe('lua stdlib', function() ) end) - it('should work with tables with __call', function() + it('works with tables with __call', function() eq( true, exec_lua [[ @@ -3430,7 +3430,7 @@ describe('lua stdlib', function() ) end) - it('should work with tables with __call that change', function() + it('works with tables with __call that change', function() eq( true, exec_lua [[ @@ -3447,7 +3447,7 @@ describe('lua stdlib', function() ) end) - it('should not work with negative intervals', function() + it('fails with negative intervals', function() local pcall_result = exec_lua [[ return pcall(function() vim.wait(1000, function() return false end, -1) end) ]] @@ -3455,7 +3455,7 @@ describe('lua stdlib', function() eq(false, pcall_result) end) - it('should not work with weird intervals', function() + it('fails with weird intervals', function() local pcall_result = exec_lua [[ return pcall(function() vim.wait(1000, function() return false end, 'a string value') end) ]] @@ -3498,7 +3498,7 @@ describe('lua stdlib', function() end) end) - it('should not run in fast callbacks #26122', function() + it('fails in fast callbacks #26122', function() local screen = Screen.new(80, 10) screen:attach() exec_lua([[ diff --git a/test/functional/plugin/health_spec.lua b/test/functional/plugin/health_spec.lua index 20bb8227b3..42b7fbd7d7 100644 --- a/test/functional/plugin/health_spec.lua +++ b/test/functional/plugin/health_spec.lua @@ -389,7 +389,7 @@ describe(':checkhealth window', function() command('file my_buff') command('checkhealth success1') -- define a function that collects all buffers in each tab - -- returns a dictionary like {tab1 = ["buf1", "buf2"], tab2 = ["buf3"]} + -- returns a dict like {tab1 = ["buf1", "buf2"], tab2 = ["buf3"]} source([[ function CollectBuffersPerTab() let buffs = {} diff --git a/test/functional/shada/errors_spec.lua b/test/functional/shada/errors_spec.lua index 321744f7dd..0016e0bdf9 100644 --- a/test/functional/shada/errors_spec.lua +++ b/test/functional/shada/errors_spec.lua @@ -58,7 +58,7 @@ describe('ShaDa error handling', function() it('fails on search pattern item with zero length', function() wshada('\002\000\000') eq( - 'Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 is not a dictionary', + 'Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 is not a dict', exc_exec(sdrcmd()) ) end) @@ -92,7 +92,7 @@ describe('ShaDa error handling', function() -- that cannot do this) wshada('\002\000\001\193') eq( - 'Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 is not a dictionary', + 'Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 is not a dict', exc_exec(sdrcmd()) ) end) @@ -124,7 +124,7 @@ describe('ShaDa error handling', function() it('fails on search pattern item with NIL value', function() wshada('\002\000\001\192') eq( - 'Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 is not a dictionary', + 'Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 is not a dict', exc_exec(sdrcmd()) ) end) @@ -227,7 +227,7 @@ describe('ShaDa error handling', function() it('fails on ' .. v.name .. ' item with NIL value', function() wshada(v.mpack .. '\000\001\192') eq( - 'Vim(rshada):E575: Error while reading ShaDa file: mark entry at position 0 is not a dictionary', + 'Vim(rshada):E575: Error while reading ShaDa file: mark entry at position 0 is not a dict', exc_exec(sdrcmd()) ) end) @@ -301,7 +301,7 @@ describe('ShaDa error handling', function() it('fails on register item with NIL value', function() wshada('\005\000\001\192') eq( - 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 is not a dictionary', + 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 is not a dict', exc_exec(sdrcmd()) ) end) @@ -504,7 +504,7 @@ describe('ShaDa error handling', function() nvim_command('set shada+=%') wshada('\009\000\008\146\129\161f\196\001/\192') eq( - 'Vim(rshada):E575: Error while reading ShaDa file: buffer list at position 0 contains entry that is not a dictionary', + 'Vim(rshada):E575: Error while reading ShaDa file: buffer list at position 0 contains entry that is not a dict', exc_exec(sdrcmd()) ) end) diff --git a/test/functional/vimscript/changedtick_spec.lua b/test/functional/vimscript/changedtick_spec.lua index baea53a700..ef9d6b1a69 100644 --- a/test/functional/vimscript/changedtick_spec.lua +++ b/test/functional/vimscript/changedtick_spec.lua @@ -38,7 +38,7 @@ describe('b:changedtick', function() -- Somehow undo counts as two changes eq(5, changedtick()) end) - it('is present in b: dictionary', function() + it('is present in b: dict', function() eq(2, changedtick()) command('let d = b:') eq(2, api.nvim_get_var('d').changedtick) @@ -168,7 +168,7 @@ describe('b:changedtick', function() ) eq(2, changedtick()) end) - it('does not inherit VAR_FIXED when copying dictionary over', function() + it('does not inherit VAR_FIXED when copying dict over', function() eq(2, changedtick()) eq('', exec_capture('let d1 = copy(b:)|let d1.changedtick = 42')) eq('', exec_capture('let d2 = copy(b:)|unlet d2.changedtick')) diff --git a/test/functional/vimscript/ctx_functions_spec.lua b/test/functional/vimscript/ctx_functions_spec.lua index 5e9a803b5d..873e4f820d 100644 --- a/test/functional/vimscript/ctx_functions_spec.lua +++ b/test/functional/vimscript/ctx_functions_spec.lua @@ -295,7 +295,7 @@ describe('context functions', function() eq(outofbounds, pcall_err(call, 'ctxget', 0)) end) - it('returns context dictionary at index in context stack', function() + it('returns context dict at index in context stack', function() feed('i123ddddddqahjklq') command('edit! ' .. fname1) feed('G') @@ -404,7 +404,7 @@ describe('context functions', function() eq(outofbounds, pcall_err(call, 'ctxset', { dummy = 1 }, 0)) end) - it('errors when context dictionary is invalid', function() + it('errors when context dict is invalid', function() call('ctxpush') eq( 'Vim:E474: Failed to convert list to msgpack string buffer', @@ -412,7 +412,7 @@ describe('context functions', function() ) end) - it('sets context dictionary at index in context stack', function() + it('sets context dict at index in context stack', function() api.nvim_set_var('one', 1) api.nvim_set_var('Two', 2) api.nvim_set_var('THREE', 3) diff --git a/test/functional/vimscript/input_spec.lua b/test/functional/vimscript/input_spec.lua index 552ae6d5cc..0b774404eb 100644 --- a/test/functional/vimscript/input_spec.lua +++ b/test/functional/vimscript/input_spec.lua @@ -108,7 +108,7 @@ describe('input()', function() {T:1}^ | ]]) end) - it('allows unequal numeric values when using {opts} dictionary', function() + it('allows unequal numeric values when using {opts} dict', function() command('echohl Test') api.nvim_set_var('opts', { prompt = 1, default = 2, cancelreturn = 3 }) feed([[:echo input(opts)]]) @@ -164,7 +164,7 @@ describe('input()', function() reset = true, } end) - it('allows omitting everything with dictionary argument', function() + it('allows omitting everything with dict argument', function() command('echohl Test') feed([[:call input({})]]) screen:expect([[ @@ -290,7 +290,7 @@ describe('inputdialog()', function() {T:1}^ | ]]) end) - it('allows unequal numeric values when using {opts} dictionary', function() + it('allows unequal numeric values when using {opts} dict', function() command('echohl Test') api.nvim_set_var('opts', { prompt = 1, default = 2, cancelreturn = 3 }) feed([[:echo input(opts)]]) @@ -346,7 +346,7 @@ describe('inputdialog()', function() reset = true, } end) - it('allows omitting everything with dictionary argument', function() + it('allows omitting everything with dict argument', function() command('echohl Test') feed(':echo inputdialog({})') screen:expect([[ diff --git a/test/functional/vimscript/json_functions_spec.lua b/test/functional/vimscript/json_functions_spec.lua index c6e0e75bdc..895e722e96 100644 --- a/test/functional/vimscript/json_functions_spec.lua +++ b/test/functional/vimscript/json_functions_spec.lua @@ -911,7 +911,7 @@ describe('json_encode() function', function() eq('[]', eval('json_encode(v:_null_list)')) end) - it('can dump NULL dictionary', function() + it('can dump NULL dict', function() eq('{}', eval('json_encode(v:_null_dict)')) end) diff --git a/test/functional/vimscript/map_functions_spec.lua b/test/functional/vimscript/map_functions_spec.lua index 44be5b3185..b69b7dbd57 100644 --- a/test/functional/vimscript/map_functions_spec.lua +++ b/test/functional/vimscript/map_functions_spec.lua @@ -36,7 +36,7 @@ describe('maparg()', function() lnum = 0, } - it('returns a dictionary', function() + it('returns a dict', function() command('nnoremap foo bar') eq('bar', fn.maparg('foo')) eq(foo_bar_map_table, fn.maparg('foo', 'n', false, true)) @@ -54,7 +54,7 @@ describe('maparg()', function() eq('', fn.maparg('not a mapping')) end) - it('returns an empty dictionary when no map is present and dict is requested', function() + it('returns an empty dict when no map is present and dict is requested', function() eq({}, fn.maparg('not a mapping', 'n', false, true)) end) diff --git a/test/functional/vimscript/msgpack_functions_spec.lua b/test/functional/vimscript/msgpack_functions_spec.lua index 6b77811e35..d2011f9fec 100644 --- a/test/functional/vimscript/msgpack_functions_spec.lua +++ b/test/functional/vimscript/msgpack_functions_spec.lua @@ -437,16 +437,16 @@ describe('msgpackparse() function', function() parse_eq({ 'ab' }, { '\196\002ab' }) end) - it('restores FIXEXT1 as special dictionary', function() + it('restores FIXEXT1 as special dict', function() parse_eq({ { _TYPE = {}, _VAL = { 0x10, { '', '' } } } }, { '\212\016', '' }) eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.ext')) end) - it('restores MAP with BIN key as ordinary dictionary', function() + it('restores MAP with BIN key as ordinary dict', function() parse_eq({ { a = '' } }, { '\129\196\001a\196\n' }) end) - it('restores MAP with duplicate STR keys as special dictionary', function() + it('restores MAP with duplicate STR keys as special dict', function() command('let dumped = ["\\x82\\xA1a\\xC4\\n\\xA1a\\xC4\\n"]') -- FIXME Internal error bug, can't use parse_eq() here command('silent! let parsed = msgpackparse(dumped)') @@ -464,7 +464,7 @@ describe('msgpackparse() function', function() eq(eval('v:t_string'), eval('type(g:parsed[0]._VAL[1][0])')) end) - it('restores MAP with MAP key as special dictionary', function() + it('restores MAP with MAP key as special dict', function() parse_eq({ { _TYPE = {}, _VAL = { { {}, '' } } } }, { '\129\128\196\n' }) eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.map')) end) @@ -510,7 +510,7 @@ describe('msgpackparse() function', function() ) end) - it('fails to parse a dictionary', function() + it('fails to parse a dict', function() eq( 'Vim(call):E899: Argument of msgpackparse() must be a List or Blob', exc_exec('call msgpackparse({})') @@ -764,7 +764,7 @@ describe('msgpackdump() function', function() ) end) - it('fails to dump a dictionary', function() + it('fails to dump a dict', function() eq('Vim(call):E686: Argument of msgpackdump() must be a List', exc_exec('call msgpackdump({})')) end) @@ -813,7 +813,7 @@ describe('msgpackdump() function', function() eq({ '\144' }, eval('msgpackdump([v:_null_list])')) end) - it('can dump NULL dictionary', function() + it('can dump NULL dict', function() eq({ '\128' }, eval('msgpackdump([v:_null_dict])')) end) end) diff --git a/test/functional/vimscript/string_spec.lua b/test/functional/vimscript/string_spec.lua index 32aa04c0d0..4df9104e1e 100644 --- a/test/functional/vimscript/string_spec.lua +++ b/test/functional/vimscript/string_spec.lua @@ -170,9 +170,9 @@ describe('string() function', function() ) end) - it('does not show errors when dumping partials referencing the same dictionary', function() + it('does not show errors when dumping partials referencing the same dict', function() command('let d = {}') - -- Regression for “eval/typval_encode: Dump empty dictionary before + -- Regression for “eval/typval_encode: Dump empty dict before -- checking for refcycle”, results in error. eq( "[function('tr', {}), function('tr', {})]", @@ -256,7 +256,7 @@ describe('string() function', function() end) describe('used to represent dictionaries', function() - it('dumps empty dictionary', function() + it('dumps empty dict', function() eq('{}', eval('string({})')) end) @@ -267,7 +267,7 @@ describe('string() function', function() eq("[{}, function('tr', {})]", eval('string([d, function("tr", d)])')) end) - it('dumps non-empty dictionary', function() + it('dumps non-empty dict', function() eq("{'t''est': 1}", fn.string({ ["t'est"] = 1 })) end) -- cgit From 17027d64726864c7bbdba5bee004eb581ac4b54a Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Mon, 23 Sep 2024 12:15:06 +0200 Subject: refactor(api): rename Dictionary => Dict In the api_info() output: :new|put =map(filter(api_info().functions, '!has_key(v:val,''deprecated_since'')'), 'v:val') ... {'return_type': 'ArrayOf(Integer, 2)', 'name': 'nvim_win_get_position', 'method': v:true, 'parameters': [['Window', 'window']], 'since': 1} The `ArrayOf(Integer, 2)` return type didn't break clients when we added it, which is evidence that clients don't use the `return_type` field, thus renaming Dictionary => Dict in api_info() is not a breaking change. --- test/functional/api/version_spec.lua | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'test/functional') 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) -- cgit From d831392b156087ddc38eb75b0260c03f955dd23c Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 24 Sep 2024 07:14:14 +0800 Subject: feat(paste): unify cancel and error behavior (#30476) Before this PR, the behavior of nvim_paste is: - When vim.paste() returns false, return false to the client, but treat following chunks normally (i.e. rely on the client cancelling the paste as expected). - When vim.paste() throws an error, still return true to the client, but drain the following chunks in the stream without calling vim.paste(). There are two problems with such behavior: - When vim.paste() errors, the client is still supposed to send the remaining chunks of the stream, even though they do nothing. - Having different code paths for two uncommon but similar situations complicates maintenance. This PR makes both the cancel case and the error case return false to the client and drain the remaining chunks of the stream, which, apart from sharing the same code path, is beneficial whether the client checks the return value of nvim_paste or not: - If the client checks the return value, it can avoid sending the following chunks needlessly after an error. - If the client doesn't check the return value, chunks following a cancelled chunk won't be pasted on the server regardless, which leads to less confusing behavior. --- test/functional/api/vim_spec.lua | 69 +++++++++++++++++++++++++++++++++-- test/functional/terminal/tui_spec.lua | 35 ++++++++++++++++++ 2 files changed, 101 insertions(+), 3 deletions(-) (limited to 'test/functional') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index b35ccb0c40..1b34945f13 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -1358,9 +1358,72 @@ describe('API', function() test_paste_repeat_visual_select(true) end) 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)) + 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('') + expect('') + feed('.') + expect('') + end) + it('in phase 1', function() + feed('A') + check_paste_cancel_error('CANCEL', true, 1) + feed('') + 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('') + 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('') + expect('aaabbb') + feed('.') + expect('aaabbbaaabbb') + end) + end + describe('vim.paste() cancel', function() + test_paste_cancel_error(false) + end) + describe('vim.paste() error', function() + test_paste_cancel_error(true) end) end) diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index b85ddec0f0..a7d87bb231 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -1298,6 +1298,41 @@ describe('TUI', function() expect_child_buf_lines({ 'foo', '' }) end) + it('paste: vim.paste() cancel (retval=false) with streaming #30462', function() + child_session:request( + 'nvim_exec_lua', + [[ + vim.paste = (function(overridden) + return function(lines, phase) + for i, line in ipairs(lines) do + if line:find('!') then + return false + end + end + return overridden(lines, phase) + end + end)(vim.paste) + ]], + {} + ) + feed_data('A') + wait_for_mode('i') + feed_data('\027[200~aaa') + expect_child_buf_lines({ 'aaa' }) + feed_data('bbb') + expect_child_buf_lines({ 'aaabbb' }) + feed_data('ccc!') -- This chunk is cancelled. + expect_child_buf_lines({ 'aaabbb' }) + feed_data('ddd\027[201~') -- This chunk is ignored. + expect_child_buf_lines({ 'aaabbb' }) + feed_data('\027[27u') + wait_for_mode('n') + feed_data('.') -- Dot-repeat only includes chunks actually pasted. + expect_child_buf_lines({ 'aaabbbaaabbb' }) + feed_data('$\027[200~eee\027[201~') -- A following paste works normally. + expect_child_buf_lines({ 'aaabbbaaabbbeee' }) + end) + it("paste: 'nomodifiable' buffer", function() child_session:request('nvim_command', 'set nomodifiable') child_session:request( -- cgit From 052875b9dc3de3283844a30dce9646f26982542d Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 24 Sep 2024 19:48:40 +0800 Subject: fix(paste): only record a paste when it's from RPC (#30491) Problem: When using nvim_paste in a mapping during a macro recording, both the mapping and the paste are recorded, causing the paste to be performed twice when replaying the macro. Solution: Only record a paste when it is from RPC. Unfortunately this means there is no way for a script to make a recorded paste. A way to enable that can be discussed later if there is need. --- test/functional/api/vim_spec.lua | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'test/functional') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 1b34945f13..af4d4854f5 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -1358,6 +1358,13 @@ describe('API', function() test_paste_repeat_visual_select(true) end) end) + it('in a mapping recorded in a macro', function() + command([[nnoremap call nvim_paste('foo', v:false, -1)]]) + feed('qr$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(([[ -- cgit From f3b7444e6638095305d86fa96fe0b7407c9b1648 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Wed, 25 Sep 2024 07:01:27 -0700 Subject: refactor(lua): vim.keymap.set tests, docs #30511 --- test/functional/lua/vim_spec.lua | 41 ++++++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) (limited to 'test/functional') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 1e199818d3..3c65ec664e 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -4043,7 +4043,36 @@ end) describe('vim.keymap', function() before_each(clear) - it('can make a mapping', function() + it('validates', function() + matches( + 'mode: expected string|table, got number', + pcall_err(exec_lua, [[vim.keymap.set(42, 'x', print)]]) + ) + + matches( + 'rhs: expected string|function, got nil', + pcall_err(exec_lua, [[vim.keymap.set('n', 'x')]]) + ) + + matches( + 'lhs: expected string, got table', + pcall_err(exec_lua, [[vim.keymap.set('n', {}, print)]]) + ) + + matches( + 'opts: expected table, got function', + pcall_err(exec_lua, [[vim.keymap.set({}, 'x', 42, function() end)]]) + ) + + matches( + 'rhs: expected string|function, got number', + pcall_err(exec_lua, [[vim.keymap.set('z', 'x', 42)]]) + ) + + matches('Invalid mode shortname: "z"', pcall_err(exec_lua, [[vim.keymap.set('z', 'x', 'y')]])) + end) + + it('mapping', function() eq( 0, exec_lua [[ @@ -4058,7 +4087,7 @@ describe('vim.keymap', function() eq(1, exec_lua [[return GlobalCount]]) end) - it('can make an expr mapping', function() + it('expr mapping', function() exec_lua [[ vim.keymap.set('n', 'aa', function() return 'πfoo' end, {expr = true}) ]] @@ -4068,7 +4097,7 @@ describe('vim.keymap', function() eq({ 'πfoo<' }, api.nvim_buf_get_lines(0, 0, -1, false)) end) - it('can overwrite a mapping', function() + it('overwrite a mapping', function() eq( 0, exec_lua [[ @@ -4091,7 +4120,7 @@ describe('vim.keymap', function() eq(0, exec_lua [[return GlobalCount]]) end) - it('can unmap a mapping', function() + it('unmap', function() eq( 0, exec_lua [[ @@ -4115,7 +4144,7 @@ describe('vim.keymap', function() eq('\nNo mapping found', n.exec_capture('nmap asdf')) end) - it('works with buffer-local mappings', function() + it('buffer-local mappings', function() eq( 0, exec_lua [[ @@ -4157,7 +4186,7 @@ describe('vim.keymap', function() ) end) - it('can do mappings', function() + it(' mappings', function() eq( 0, exec_lua [[ -- cgit From 64847fbdc908bf0a301b8f1e1814ff71bd425bae Mon Sep 17 00:00:00 2001 From: Riley Bruins Date: Wed, 25 Sep 2024 11:33:14 -0700 Subject: perf(treesitter): use `child_containing_descendant()` in `is_ancestor()` **Problem:** `is_ancestor()` uses a slow, bottom-up parent lookup which has performance pitfalls detailed in #28512. **Solution:** Take `is_ancestor()` from $O(n^2)$ to $O(n)$ by incorporating the use of the `child_containing_descendant()` function --- test/functional/treesitter/utils_spec.lua | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'test/functional') diff --git a/test/functional/treesitter/utils_spec.lua b/test/functional/treesitter/utils_spec.lua index e079a7c8e7..34bea349f6 100644 --- a/test/functional/treesitter/utils_spec.lua +++ b/test/functional/treesitter/utils_spec.lua @@ -21,12 +21,16 @@ describe('treesitter utils', function() local parser = vim.treesitter.get_parser(0, 'c') local tree = parser:parse()[1] local root = tree:root() - _G.ancestor = root:child(0) - _G.child = _G.ancestor:child(0) + _G.ancestor = assert(root:child(0)) + _G.child = assert(_G.ancestor:named_child(1)) + _G.child_sibling = assert(_G.ancestor:named_child(2)) + _G.grandchild = assert(_G.child:named_child(0)) end) eq(true, exec_lua('return vim.treesitter.is_ancestor(_G.ancestor, _G.child)')) + eq(true, exec_lua('return vim.treesitter.is_ancestor(_G.ancestor, _G.grandchild)')) eq(false, exec_lua('return vim.treesitter.is_ancestor(_G.child, _G.ancestor)')) + eq(false, exec_lua('return vim.treesitter.is_ancestor(_G.child, _G.child_sibling)')) end) it('can detect if a position is contained in a node', function() -- cgit From 80709882476206b8f1ab3c004c82a1efd039c684 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 26 Sep 2024 16:36:50 +0800 Subject: fix(channel): handle writing to file instead of pipe (#30519) --- test/functional/core/channels_spec.lua | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'test/functional') diff --git a/test/functional/core/channels_spec.lua b/test/functional/core/channels_spec.lua index a98e190a60..dee13d19ae 100644 --- a/test/functional/core/channels_spec.lua +++ b/test/functional/core/channels_spec.lua @@ -288,6 +288,37 @@ describe('channels', function() eq({ 'notification', 'exit', { 3, 0 } }, next_msg()) end) + it('stdio channel works with stdout redirected to file #30509', function() + t.write_file( + 'Xstdio_write.vim', + [[ + let chan = stdioopen({}) + call chansend(chan, 'foo') + call chansend(chan, 'bar') + qall! + ]] + ) + local fd = assert(vim.uv.fs_open('Xstdio_redir', 'w', 420)) + local exit_code, exit_signal + local handle = vim.uv.spawn(nvim_prog, { + args = { '-u', 'NONE', '-i', 'NONE', '--headless', '-S', 'Xstdio_write.vim' }, + -- Simulate shell redirection: "nvim ... > Xstdio_redir". #30509 + stdio = { nil, fd, nil }, + }, function(code, signal) + vim.uv.stop() + exit_code, exit_signal = code, signal + end) + finally(function() + handle:close() + vim.uv.fs_close(fd) + os.remove('Xstdio_write.vim') + os.remove('Xstdio_redir') + end) + vim.uv.run('default') + eq({ 0, 0 }, { exit_code, exit_signal }) + eq('foobar', t.read_file('Xstdio_redir')) + end) + it('can use buffered output mode', function() skip(fn.executable('grep') == 0, 'missing "grep" command') source([[ -- cgit From 66197dde7084484c9d23fa488b2288bcae364ba7 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 26 Sep 2024 18:34:35 +0800 Subject: test(api/buffer_updates_spec): prevent flakiness (#30521) Use poke_eventloop() to wait for Nvim to finish processing input. --- test/functional/api/buffer_updates_spec.lua | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'test/functional') 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) -- cgit From f2fa4ca97ea3812dba78820323a1ccbf58921b40 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Thu, 26 Sep 2024 07:45:03 -0700 Subject: feat(health): highlight headings #30525 Problem: checkhealth report sections are not visually separated. Solution: Highlight with "reverse". TODO: migrate checkhealth filetype to use treesitter. TODO: default :help should also highlight headings more boldy! --- test/functional/plugin/health_spec.lua | 68 ++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 32 deletions(-) (limited to 'test/functional') diff --git a/test/functional/plugin/health_spec.lua b/test/functional/plugin/health_spec.lua index 42b7fbd7d7..7089313303 100644 --- a/test/functional/plugin/health_spec.lua +++ b/test/functional/plugin/health_spec.lua @@ -79,7 +79,7 @@ describe('vim.health', function() n.expect([[ ============================================================================== - test_plug.full_render: require("test_plug.full_render.health").check() + test_plug.full_render: require("test_plug.full_render.health").check() report 1 ~ - OK life is fine @@ -102,7 +102,7 @@ describe('vim.health', function() n.expect([[ ============================================================================== - test_plug: require("test_plug.health").check() + test_plug: require("test_plug.health").check() report 1 ~ - OK everything is fine @@ -111,7 +111,7 @@ describe('vim.health', function() - OK nothing to see here ============================================================================== - test_plug.success1: require("test_plug.success1.health").check() + test_plug.success1: require("test_plug.success1.health").check() report 1 ~ - OK everything is fine @@ -120,7 +120,7 @@ describe('vim.health', function() - OK nothing to see here ============================================================================== - test_plug.success2: require("test_plug.success2.health").check() + test_plug.success2: require("test_plug.success2.health").check() another 1 ~ - OK ok @@ -132,7 +132,7 @@ describe('vim.health', function() n.expect([[ ============================================================================== - test_plug.submodule: require("test_plug.submodule.health").check() + test_plug.submodule: require("test_plug.submodule.health").check() report 1 ~ - OK everything is fine @@ -157,9 +157,10 @@ describe('vim.health', function() local screen = Screen.new(50, 12) screen:attach() screen:set_default_attr_ids({ + h1 = { reverse = true }, + h2 = { foreground = tonumber('0x6a0dad') }, Ok = { foreground = Screen.colors.LightGreen }, Error = { foreground = Screen.colors.Red }, - Heading = { foreground = tonumber('0x6a0dad') }, Bar = { foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGrey }, }) command('checkhealth foo success1') @@ -167,15 +168,15 @@ describe('vim.health', function() screen:expect { grid = [[ ^ | - {Bar:──────────────────────────────────────────────────}| - {Heading:foo: } | + {Bar: }| + {h1:foo: }| | - {Error:ERROR} No healthcheck found for "foo" plugin. | | - {Bar:──────────────────────────────────────────────────}| - {Heading:test_plug.success1: require("test_plug.success1.he}| + {Bar: }| + {h1:test_plug.success1: require("test_pl}| | - {Heading:report 1} | + {h2:report 1} | - {Ok:OK} everything is fine | | ]], @@ -188,7 +189,7 @@ describe('vim.health', function() n.expect([[ ============================================================================== - non_existent_healthcheck: + non_existent_healthcheck: - ERROR No healthcheck found for "non_existent_healthcheck" plugin. ]]) @@ -223,9 +224,10 @@ describe(':checkhealth window', function() it('opens directly if no buffer created', function() local screen = Screen.new(50, 12) screen:set_default_attr_ids { + h1 = { reverse = true }, + h2 = { foreground = tonumber('0x6a0dad') }, [1] = { foreground = Screen.colors.Blue, bold = true }, [14] = { foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGray }, - [31] = { foreground = tonumber('0x6a0dad') }, [32] = { foreground = Screen.colors.PaleGreen2 }, } screen:attach({ ext_multigrid = true }) @@ -237,15 +239,15 @@ describe(':checkhealth window', function() [3:--------------------------------------------------]| ## grid 2 ^ | - {14:──────────────────────────────────────────────────}| - {14:────────────────────────────} | - {31:test_plug.success1: require("test_plug.success1. }| - {31:health").check()} | + {14: }| + {14: } | + {h1:test_plug.success1: }| + {h1:require("test_plug.success1.health").check()} | | - {31:report 1} | + {h2:report 1} | - {32:OK} everything is fine | | - {31:report 2} | + {h2:report 2} | - {32:OK} nothing to see here | ## grid 3 | @@ -256,9 +258,10 @@ describe(':checkhealth window', function() local function test_health_vsplit(left, emptybuf, mods) local screen = Screen.new(50, 20) screen:set_default_attr_ids { + h1 = { reverse = true }, + h2 = { foreground = tonumber('0x6a0dad') }, [1] = { foreground = Screen.colors.Blue, bold = true }, [14] = { foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGray }, - [31] = { foreground = tonumber('0x6a0dad') }, [32] = { foreground = Screen.colors.PaleGreen2 }, } screen:attach({ ext_multigrid = true }) @@ -278,19 +281,20 @@ describe(':checkhealth window', function() | ## grid 4 ^ | - {14:─────────────────────────}|*3 - {14:───} | - {31:test_plug.success1: }| - {31:require("test_plug. }| - {31:success1.health").check()}| + {14: }|*3 + {14: } | + {h1:test_plug. }| + {h1:success1: }| + {h1:require("test_plug. }| + {h1:success1.health").check()}| | - {31:report 1} | + {h2:report 1} | - {32:OK} everything is fine | | - {31:report 2} | + {h2:report 2} | - {32:OK} nothing to see here | | - {1:~ }|*4 + {1:~ }|*3 ]]):format( left and '[4:-------------------------]│[2:------------------------]|*19' or '[2:------------------------]│[4:-------------------------]|*19', @@ -337,10 +341,10 @@ describe(':checkhealth window', function() | ## grid 4 ^ | - ──────────────────────────────────────────────────| - ──────────────────────────── | - test_plug.success1: require("test_plug.success1. | - health").check() | + | + | + test_plug.success1: | + require("test_plug.success1.health").check() | | report 1 | - OK everything is fine | -- cgit From 6f2fe8a791646d6d662e89d7eccf6c515ccc9c8c Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 27 Sep 2024 15:14:39 +0800 Subject: vim-patch:9.1.0743: diff mode does not handle overlapping diffs correctly (#30532) Problem: diff mode does not handle overlapping diffs correctly Solution: correct the logic to handle overlapping blocks (Yukihiro Nakadaira) Vim merges overlapped diff blocks and it doesn't work expectedly in some situation. closes: vim/vim#15735 https://github.com/vim/vim/commit/06fe70c183a53ea97cd42ace490d4fb9fd14f042 Co-authored-by: Yukihiro Nakadaira --- test/functional/ui/diff_spec.lua | 539 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 539 insertions(+) (limited to 'test/functional') diff --git a/test/functional/ui/diff_spec.lua b/test/functional/ui/diff_spec.lua index 8db6f776d1..d6a04f90f6 100644 --- a/test/functional/ui/diff_spec.lua +++ b/test/functional/ui/diff_spec.lua @@ -12,6 +12,19 @@ local exec = n.exec local eq = t.eq local api = n.api +local function WriteDiffFiles(text1, text2) + write_file('Xdifile1', text1) + write_file('Xdifile2', text2) + command('checktime') +end + +local function WriteDiffFiles3(text1, text2, text3) + write_file('Xdifile1', text1) + write_file('Xdifile2', text2) + write_file('Xdifile3', text3) + command('checktime') +end + before_each(clear) describe('Diff mode screen', function() @@ -1515,3 +1528,529 @@ it("diff mode draws 'breakindent' correctly after filler lines", function() | ]]) end) + +-- oldtest: Test_diff_overlapped_diff_blocks_will_be_merged() +it('diff mode overlapped diff blocks will be merged', function() + write_file('Xdifile1', '') + write_file('Xdifile2', '') + write_file('Xdifile3', '') + + finally(function() + os.remove('Xdifile1') + os.remove('Xdifile2') + os.remove('Xdifile3') + os.remove('Xdiin1') + os.remove('Xdinew1') + os.remove('Xdiout1') + os.remove('Xdiin2') + os.remove('Xdinew2') + os.remove('Xdiout2') + end) + + exec([[ + func DiffExprStub() + let txt_in = readfile(v:fname_in) + let txt_new = readfile(v:fname_new) + if txt_in == ["line1"] && txt_new == ["line2"] + call writefile(["1c1"], v:fname_out) + elseif txt_in == readfile("Xdiin1") && txt_new == readfile("Xdinew1") + call writefile(readfile("Xdiout1"), v:fname_out) + elseif txt_in == readfile("Xdiin2") && txt_new == readfile("Xdinew2") + call writefile(readfile("Xdiout2"), v:fname_out) + endif + endfunc + ]]) + + local screen = Screen.new(35, 20) + screen:attach() + command('set winwidth=10 diffopt=filler,internal') + + command('args Xdifile1 Xdifile2 | vert all | windo diffthis') + + WriteDiffFiles('a\nb', 'x\nx') + write_file('Xdiin1', 'a\nb') + write_file('Xdinew1', 'x\nx') + write_file('Xdiout1', '1c1\n2c2') + command('set diffexpr=DiffExprStub()') + screen:expect([[ + {7: }{27:a}{4: }│{7: }{27:^x}{4: }| + {7: }{27:b}{4: }│{7: }{27:x}{4: }| + {1:~ }│{1:~ }|*16 + {2:Xdifile1 }{3:Xdifile2 }| + | + ]]) + command('set diffexpr&') + + WriteDiffFiles('a\nb\nc', 'x\nc') + write_file('Xdiin1', 'a\nb\nc') + write_file('Xdinew1', 'x\nc') + write_file('Xdiout1', '1c1\n2c1') + command('set diffexpr=DiffExprStub()') + screen:expect([[ + {7: }{27:a}{4: }│{7: }{27:^x}{4: }| + {7: }{22:b }│{7: }{23:---------------}| + {7: }c │{7: }c | + {1:~ }│{1:~ }|*15 + {2:Xdifile1 }{3:Xdifile2 }| + | + ]]) + command('set diffexpr&') + + WriteDiffFiles('a\nc', 'x\nx\nc') + write_file('Xdiin1', 'a\nc') + write_file('Xdinew1', 'x\nx\nc') + write_file('Xdiout1', '1c1\n1a2') + command('set diffexpr=DiffExprStub()') + screen:expect([[ + {7: }{27:a}{4: }│{7: }{27:^x}{4: }| + {7: }{23:---------------}│{7: }{22:x }| + {7: }c │{7: }c | + {1:~ }│{1:~ }|*15 + {2:Xdifile1 }{3:Xdifile2 }| + | + ]]) + command('set diffexpr&') + + command('args Xdifile1 Xdifile2 Xdifile3 | vert all | windo diffthis') + + WriteDiffFiles3('a\nb\nc', 'a\nx\nc', 'y\nb\nc') + screen:expect([[ + {7: }{27:a}{4: }│{7: }{27:a}{4: }│{7: }{27:^y}{4: }| + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:b}{4: }| + {7: }c │{7: }c │{7: }c | + {1:~ }│{1:~ }│{1:~ }|*15 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc', 'a\nx\nc', 'a\ny\nc') + screen:expect([[ + {7: }a │{7: }a │{7: }^a | + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }c │{7: }c │{7: }c | + {1:~ }│{1:~ }│{1:~ }|*15 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc', 'a\nx\nc', 'a\nb\ny') + screen:expect([[ + {7: }a │{7: }a │{7: }^a | + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:b}{4: }| + {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:y}{4: }| + {1:~ }│{1:~ }│{1:~ }|*15 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc', 'a\nx\nc', 'y\ny\nc') + screen:expect([[ + {7: }{27:a}{4: }│{7: }{27:a}{4: }│{7: }{27:^y}{4: }| + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }c │{7: }c │{7: }c | + {1:~ }│{1:~ }│{1:~ }|*15 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc', 'a\nx\nc', 'a\ny\ny') + screen:expect([[ + {7: }a │{7: }a │{7: }^a | + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:y}{4: }| + {1:~ }│{1:~ }│{1:~ }|*15 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc', 'a\nx\nc', 'y\ny\ny') + screen:expect([[ + {7: }{27:a}{4: }│{7: }{27:a}{4: }│{7: }{27:^y}{4: }| + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:y}{4: }| + {1:~ }│{1:~ }│{1:~ }|*15 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc', 'a\nx\nx', 'y\ny\nc') + screen:expect([[ + {7: }{27:a}{4: }│{7: }{27:a}{4: }│{7: }{27:^y}{4: }| + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }{27:c}{4: }│{7: }{27:x}{4: }│{7: }{27:c}{4: }| + {1:~ }│{1:~ }│{1:~ }|*15 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc', 'x\nx\nc', 'a\ny\ny') + screen:expect([[ + {7: }{27:a}{4: }│{7: }{27:x}{4: }│{7: }{27:^a}{4: }| + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:y}{4: }| + {1:~ }│{1:~ }│{1:~ }|*15 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'y\ny\ny\nd\ne') + screen:expect([[ + {7: }{27:a}{4: }│{7: }{27:a}{4: }│{7: }{27:^y}{4: }| + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:y}{4: }| + {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{27:d}{4: }| + {7: }e │{7: }e │{7: }e | + {1:~ }│{1:~ }│{1:~ }|*13 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'y\ny\ny\ny\ne') + screen:expect([[ + {7: }{27:a}{4: }│{7: }{27:a}{4: }│{7: }{27:^y}{4: }| + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:y}{4: }| + {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }e │{7: }e │{7: }e | + {1:~ }│{1:~ }│{1:~ }|*13 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'y\ny\ny\ny\ny') + screen:expect([[ + {7: }{27:a}{4: }│{7: }{27:a}{4: }│{7: }{27:^y}{4: }| + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:y}{4: }| + {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }{27:e}{4: }│{7: }{27:e}{4: }│{7: }{27:y}{4: }| + {1:~ }│{1:~ }│{1:~ }|*13 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'a\ny\ny\nd\ne') + screen:expect([[ + {7: }a │{7: }a │{7: }^a | + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:y}{4: }| + {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{27:d}{4: }| + {7: }e │{7: }e │{7: }e | + {1:~ }│{1:~ }│{1:~ }|*13 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'a\ny\ny\ny\ne') + screen:expect([[ + {7: }a │{7: }a │{7: }^a | + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:y}{4: }| + {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }e │{7: }e │{7: }e | + {1:~ }│{1:~ }│{1:~ }|*13 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'a\ny\ny\ny\ny') + screen:expect([[ + {7: }a │{7: }a │{7: }^a | + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:y}{4: }| + {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }{27:e}{4: }│{7: }{27:e}{4: }│{7: }{27:y}{4: }| + {1:~ }│{1:~ }│{1:~ }|*13 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'a\nb\ny\nd\ne') + screen:expect([[ + {7: }a │{7: }a │{7: }^a | + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:b}{4: }| + {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:y}{4: }| + {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{27:d}{4: }| + {7: }e │{7: }e │{7: }e | + {1:~ }│{1:~ }│{1:~ }|*13 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'a\nb\ny\ny\ne') + screen:expect([[ + {7: }a │{7: }a │{7: }^a | + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:b}{4: }| + {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:y}{4: }| + {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }e │{7: }e │{7: }e | + {1:~ }│{1:~ }│{1:~ }|*13 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'a\nb\ny\ny\ny') + screen:expect([[ + {7: }a │{7: }a │{7: }^a | + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:b}{4: }| + {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:y}{4: }| + {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }{27:e}{4: }│{7: }{27:e}{4: }│{7: }{27:y}{4: }| + {1:~ }│{1:~ }│{1:~ }|*13 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb', 'x\nb', 'y\ny') + write_file('Xdiin1', 'a\nb') + write_file('Xdinew1', 'x\nb') + write_file('Xdiout1', '1c1') + write_file('Xdiin2', 'a\nb') + write_file('Xdinew2', 'y\ny') + write_file('Xdiout2', '1c1\n2c2') + command('set diffexpr=DiffExprStub()') + screen:expect([[ + {7: }{27:a}{4: }│{7: }{27:x}{4: }│{7: }{27:^y}{4: }| + {7: }{27:b}{4: }│{7: }{27:b}{4: }│{7: }{27:y}{4: }| + {1:~ }│{1:~ }│{1:~ }|*16 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + command('set diffexpr&') + + WriteDiffFiles3('a\nb\nc\nd', 'x\nb\nx\nd', 'y\ny\nc\nd') + write_file('Xdiin1', 'a\nb\nc\nd') + write_file('Xdinew1', 'x\nb\nx\nd') + write_file('Xdiout1', '1c1\n3c3') + write_file('Xdiin2', 'a\nb\nc\nd') + write_file('Xdinew2', 'y\ny\nc\nd') + write_file('Xdiout2', '1c1\n2c2') + command('set diffexpr=DiffExprStub()') + screen:expect([[ + {7: }{27:a}{4: }│{7: }{27:x}{4: }│{7: }{27:^y}{4: }| + {7: }{27:b}{4: }│{7: }{27:b}{4: }│{7: }{27:y}{4: }| + {7: }{27:c}{4: }│{7: }{27:x}{4: }│{7: }{27:c}{4: }| + {7: }d │{7: }d │{7: }d | + {1:~ }│{1:~ }│{1:~ }|*14 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + command('set diffexpr&') + + WriteDiffFiles3('a\nb\nc\nd', 'x\nb\nx\nd', 'y\ny\ny\nd') + write_file('Xdiin1', 'a\nb\nc\nd') + write_file('Xdinew1', 'x\nb\nx\nd') + write_file('Xdiout1', '1c1\n3c3') + write_file('Xdiin2', 'a\nb\nc\nd') + write_file('Xdinew2', 'y\ny\ny\nd') + write_file('Xdiout2', '1c1\n2,3c2,3') + command('set diffexpr=DiffExprStub()') + screen:expect([[ + {7: }{27:a}{4: }│{7: }{27:x}{4: }│{7: }{27:^y}{4: }| + {7: }{27:b}{4: }│{7: }{27:b}{4: }│{7: }{27:y}{4: }| + {7: }{27:c}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }d │{7: }d │{7: }d | + {1:~ }│{1:~ }│{1:~ }|*14 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + command('set diffexpr&') + + WriteDiffFiles3('a\nb\nc\nd', 'x\nb\nx\nd', 'y\ny\ny\ny') + write_file('Xdiin1', 'a\nb\nc\nd') + write_file('Xdinew1', 'x\nb\nx\nd') + write_file('Xdiout1', '1c1\n3c3') + write_file('Xdiin2', 'a\nb\nc\nd') + write_file('Xdinew2', 'y\ny\ny\ny') + write_file('Xdiout2', '1c1\n2,4c2,4') + command('set diffexpr=DiffExprStub()') + screen:expect([[ + {7: }{27:a}{4: }│{7: }{27:x}{4: }│{7: }{27:^y}{4: }| + {7: }{27:b}{4: }│{7: }{27:b}{4: }│{7: }{27:y}{4: }| + {7: }{27:c}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }{27:d}{4: }│{7: }{27:d}{4: }│{7: }{27:y}{4: }| + {1:~ }│{1:~ }│{1:~ }|*14 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + command('set diffexpr&') + + WriteDiffFiles3('a\nb\nc', 'a\nx\nc', 'b\nc') + screen:expect([[ + {7: }{27:a}{4: }│{7: }{27:a}{4: }│{7: }{27:^b}{4: }| + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}| + {7: }c │{7: }c │{7: }c | + {1:~ }│{1:~ }│{1:~ }|*15 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc', 'a\nx\nc', 'c') + screen:expect([[ + {7: }{4:a }│{7: }{4:a }│{7: }{23:---------}| + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}| + {7: }c │{7: }c │{7: }^c | + {1:~ }│{1:~ }│{1:~ }|*15 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc', 'a\nx\nc', '') + screen:expect([[ + {7: }{4:a }│{7: }{4:a }│{7: }{23:---------}| + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}| + {7: }{4:c }│{7: }{4:c }│{7: }{23:---------}| + {1:~ }│{1:~ }│{7: }^ | + {1:~ }│{1:~ }│{1:~ }|*14 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc', 'a\nx\nc', 'a\nc') + screen:expect([[ + {7: }a │{7: }a │{7: }^a | + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}| + {7: }c │{7: }c │{7: }c | + {1:~ }│{1:~ }│{1:~ }|*15 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc', 'a\nx\nc', 'a') + screen:expect([[ + {7: }a │{7: }a │{7: }^a | + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}| + {7: }{4:c }│{7: }{4:c }│{7: }{23:---------}| + {1:~ }│{1:~ }│{1:~ }|*15 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc', 'a\nx\nc', 'b') + screen:expect([[ + {7: }{27:a}{4: }│{7: }{27:a}{4: }│{7: }{27:^b}{4: }| + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}| + {7: }{4:c }│{7: }{4:c }│{7: }{23:---------}| + {1:~ }│{1:~ }│{1:~ }|*15 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'd\ne') + screen:expect([[ + {7: }{27:a}{4: }│{7: }{27:a}{4: }│{7: }{27:^d}{4: }| + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}| + {7: }{4:c }│{7: }{4:c }│{7: }{23:---------}| + {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}| + {7: }e │{7: }e │{7: }e | + {1:~ }│{1:~ }│{1:~ }|*13 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'e') + screen:expect([[ + {7: }{4:a }│{7: }{4:a }│{7: }{23:---------}| + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}| + {7: }{4:c }│{7: }{4:c }│{7: }{23:---------}| + {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}| + {7: }e │{7: }e │{7: }^e | + {1:~ }│{1:~ }│{1:~ }|*13 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'a\nd\ne') + screen:expect([[ + {7: }a │{7: }a │{7: }^a | + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:d}{4: }| + {7: }{4:c }│{7: }{4:c }│{7: }{23:---------}| + {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}| + {7: }e │{7: }e │{7: }e | + {1:~ }│{1:~ }│{1:~ }|*13 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'a\ne') + screen:expect([[ + {7: }a │{7: }a │{7: }^a | + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}| + {7: }{4:c }│{7: }{4:c }│{7: }{23:---------}| + {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}| + {7: }e │{7: }e │{7: }e | + {1:~ }│{1:~ }│{1:~ }|*13 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'a') + screen:expect([[ + {7: }a │{7: }a │{7: }^a | + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}| + {7: }{4:c }│{7: }{4:c }│{7: }{23:---------}| + {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}| + {7: }{4:e }│{7: }{4:e }│{7: }{23:---------}| + {1:~ }│{1:~ }│{1:~ }|*13 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'a\nb\nd\ne') + screen:expect([[ + {7: }a │{7: }a │{7: }^a | + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:b}{4: }| + {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:d}{4: }| + {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}| + {7: }e │{7: }e │{7: }e | + {1:~ }│{1:~ }│{1:~ }|*13 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'a\nb\ne') + screen:expect([[ + {7: }a │{7: }a │{7: }^a | + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:b}{4: }| + {7: }{4:c }│{7: }{4:c }│{7: }{23:---------}| + {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}| + {7: }e │{7: }e │{7: }e | + {1:~ }│{1:~ }│{1:~ }|*13 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'a\nb') + screen:expect([[ + {7: }a │{7: }a │{7: }^a | + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:b}{4: }| + {7: }{4:c }│{7: }{4:c }│{7: }{23:---------}| + {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}| + {7: }{4:e }│{7: }{4:e }│{7: }{23:---------}| + {1:~ }│{1:~ }│{1:~ }|*13 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc', 'a\nx\nc', 'a\ny\nb\nc') + screen:expect([[ + {7: }a │{7: }a │{7: }^a | + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }{23:---------}│{7: }{23:---------}│{7: }{22:b }| + {7: }c │{7: }c │{7: }c | + {1:~ }│{1:~ }│{1:~ }|*14 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc', 'a\nx\nc', 'a\nb\ny\nc') + screen:expect([[ + {7: }a │{7: }a │{7: }^a | + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:b}{4: }| + {7: }{23:---------}│{7: }{23:---------}│{7: }{22:y }| + {7: }c │{7: }c │{7: }c | + {1:~ }│{1:~ }│{1:~ }|*14 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) +end) -- cgit From eea6b84a87fb72d66f83e8b5c440764ccbdf69b5 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 27 Sep 2024 19:10:55 +0800 Subject: test(api/window_spec): remove duplicate test (#30538) --- test/functional/api/window_spec.lua | 40 +++++++------------------------------ 1 file changed, 7 insertions(+), 33 deletions(-) (limited to 'test/functional') diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua index 046e7107c0..63cde9dfb2 100644 --- a/test/functional/api/window_spec.lua +++ b/test/functional/api/window_spec.lua @@ -2765,61 +2765,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 = {} }) -- cgit From f55213ce0e2b0053ded8416e8ae922a0e406012f Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 27 Sep 2024 22:33:24 +0800 Subject: fix(api): fix crash/leak with float title/footer on error (#30543) --- test/functional/api/window_spec.lua | 77 ++++++++++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua index 63cde9dfb2..135b24fa5f 100644 --- a/test/functional/api/window_spec.lua +++ b/test/functional/api/window_spec.lua @@ -164,7 +164,7 @@ 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) @@ -1809,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 = 5, + col = 5, + height = 5, + width = 5, + 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 = 5, + col = 5, + height = 5, + width = 5, + border = 'single', + title = 0, + footer = { { 'FOOTER' } }, + }) + ) + end) end) describe('set_config', function() @@ -2801,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 = 5, + col = 5, + height = 5, + width = 5, + 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) -- cgit From 09d76afe84dd5b895e102dcd8df8ce6271bebfef Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Fri, 27 Sep 2024 08:53:30 -0700 Subject: feat(defaults): pretty :help headings #30544 Problem: Headings in :help do not stand out visually. Solution: Define a non-standard `@markup.heading.1.delimiter` group and special-case it in `highlight_group.c`. FUTURE: This is a cheap workaround until we have #25718 which will enable: - fully driven by `vimdoc/highlights.scm` instead of using highlight tricks (`guibg=bg guifg=bg guisp=fg`) - better support of "cterm" ('notermguicolors') --- test/functional/treesitter/highlight_spec.lua | 36 +++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'test/functional') diff --git a/test/functional/treesitter/highlight_spec.lua b/test/functional/treesitter/highlight_spec.lua index 50f5734230..b5a6cb5c17 100644 --- a/test/functional/treesitter/highlight_spec.lua +++ b/test/functional/treesitter/highlight_spec.lua @@ -894,9 +894,45 @@ describe('treesitter highlighting (help)', function() [3] = { bold = true, foreground = Screen.colors.Brown }, [4] = { foreground = Screen.colors.Cyan4 }, [5] = { foreground = Screen.colors.Magenta1 }, + title = { bold = true, foreground = Screen.colors.Magenta1 }, + h1_delim = { nocombine = true, underdouble = true }, + h2_delim = { nocombine = true, underline = true }, } end) + it('defaults in vimdoc/highlights.scm', function() + -- Avoid regressions when syncing upstream vimdoc queries. + + insert [[ + ============================================================================== + NVIM DOCUMENTATION + + ------------------------------------------------------------------------------ + ABOUT NVIM *tag-1* *tag-2* + + |news| News + |nvim| NVim + ]] + + feed('gg') + exec_lua(function() + vim.wo.wrap = false + vim.bo.filetype = 'help' + vim.treesitter.start() + end) + + screen:expect({ + grid = [[ + {h1_delim:^========================================}| + {title:NVIM DOCUMENTATION} | + | + {h2_delim:----------------------------------------}| + {title:ABOUT NVIM} | + | + ]], + }) + end) + it('correctly redraws added/removed injections', function() insert [[ >ruby -- cgit From 7b71fdbc1e9fcb71e642e67e0ac9a2711dd67df0 Mon Sep 17 00:00:00 2001 From: glepnir Date: Sat, 28 Sep 2024 06:02:14 +0800 Subject: fix(window): respect hide flag of float windows when switching (#30507) --- test/functional/ui/float_spec.lua | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'test/functional') diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua index 409cf5aac4..52b46d0ecb 100644 --- a/test/functional/ui/float_spec.lua +++ b/test/functional/ui/float_spec.lua @@ -9068,6 +9068,7 @@ describe('float window', function() end) it('float window with hide option', function() + local cwin = api.nvim_get_current_win() local buf = api.nvim_create_buf(false,false) local win = api.nvim_open_win(buf, false, {relative='editor', width=10, height=2, row=2, col=5, hide = true}) local expected_pos = { @@ -9147,6 +9148,22 @@ describe('float window', function() | ]]) end + -- check window jump with hide + feed('') + -- should keep on current window + eq(cwin, api.nvim_get_current_win()) + api.nvim_win_set_config(win, {hide=false}) + api.nvim_set_current_win(win) + local win3 = api.nvim_open_win(buf, true, {relative='editor', width=4, height=4, row=2, col=5, hide = false}) + api.nvim_win_set_config(win, {hide=true}) + feed('w') + -- should goto the first window with prev + eq(cwin, api.nvim_get_current_win()) + -- windo + command('windo set winheight=6') + eq(win3, api.nvim_get_current_win()) + eq(6, api.nvim_win_get_height(win3)) + eq(2, api.nvim_win_get_height(win)) end) it(':fclose command #9663', function() -- cgit From 0f067cd34d09b38f9aaf2e1732d825e89b573077 Mon Sep 17 00:00:00 2001 From: Riley Bruins Date: Sat, 14 Sep 2024 12:57:33 -0700 Subject: fix(treesitter): suppress get_parser warnings via opts.error --- test/functional/lua/deprecated_spec.lua | 22 ++++++++++++++++++++++ test/functional/treesitter/language_spec.lua | 8 ++++---- test/functional/treesitter/parser_spec.lua | 2 +- 3 files changed, 27 insertions(+), 5 deletions(-) create mode 100644 test/functional/lua/deprecated_spec.lua (limited to 'test/functional') diff --git a/test/functional/lua/deprecated_spec.lua b/test/functional/lua/deprecated_spec.lua new file mode 100644 index 0000000000..fee34336cc --- /dev/null +++ b/test/functional/lua/deprecated_spec.lua @@ -0,0 +1,22 @@ +local t = require('test.testutil') +local n = require('test.functional.testnvim')() + +local clear = n.clear +local exec_lua = n.exec_lua +local eq = t.eq + +describe('deprecated lua code', function() + before_each(clear) + + describe('vim.treesitter.get_parser()', function() + it('returns nil for versions >= 0.12', function() + local result = exec_lua(function() + if vim.version.ge(vim.version(), '0.12') then + return vim.treesitter.get_parser(0, 'borklang') + end + return nil + end) + eq(nil, result) + end) + end) +end) diff --git a/test/functional/treesitter/language_spec.lua b/test/functional/treesitter/language_spec.lua index f8191d603a..3947ab23b2 100644 --- a/test/functional/treesitter/language_spec.lua +++ b/test/functional/treesitter/language_spec.lua @@ -16,11 +16,11 @@ describe('treesitter language API', function() -- error tests not requiring a parser library it('handles missing language', function() eq( - '.../treesitter.lua:0: Parser not found.', + '.../treesitter.lua:0: Parser could not be created for buffer 1 and language "borklang"', pcall_err(exec_lua, "parser = vim.treesitter.get_parser(0, 'borklang')") ) - eq(NIL, exec_lua("return vim.treesitter._get_parser(0, 'borklang')")) + eq(NIL, exec_lua("return vim.treesitter.get_parser(0, 'borklang', { error = false })")) -- actual message depends on platform matches( @@ -108,10 +108,10 @@ describe('treesitter language API', function() command('set filetype=borklang') -- Should throw an error when filetype changes to borklang eq( - '.../treesitter.lua:0: Parser not found.', + '.../treesitter.lua:0: Parser could not be created for buffer 1 and language "borklang"', pcall_err(exec_lua, "new_parser = vim.treesitter.get_parser(0, 'borklang')") ) - eq(NIL, exec_lua("return vim.treesitter._get_parser(0, 'borklang')")) + eq(NIL, exec_lua("return vim.treesitter.get_parser(0, 'borklang', { error = false })")) end ) diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua index 92379a71bd..c8829f4785 100644 --- a/test/functional/treesitter/parser_spec.lua +++ b/test/functional/treesitter/parser_spec.lua @@ -135,7 +135,7 @@ void ui_refresh(void) insert(test_text) eq( - '.../treesitter.lua:0: Parser not found.', + '.../treesitter.lua:0: Parser not found for buffer 1: language could not be determined', pcall_err(exec_lua, 'vim.treesitter.get_parser(0)') ) -- cgit From 4f9311b759fff0371433fb5b5355fccb001d54e7 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 28 Sep 2024 10:21:06 +0800 Subject: fix(window): making float with title/footer non-float leaks memory (#30551) --- test/functional/api/window_spec.lua | 24 ++++++++++++------------ test/functional/ui/float_spec.lua | 31 +++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 12 deletions(-) (limited to 'test/functional') diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua index 135b24fa5f..5ce93f9e04 100644 --- a/test/functional/api/window_spec.lua +++ b/test/functional/api/window_spec.lua @@ -1815,10 +1815,10 @@ describe('API/win', function() 'title/footer must be string or array', pcall_err(api.nvim_open_win, 0, false, { relative = 'editor', - row = 5, - col = 5, - height = 5, - width = 5, + row = 10, + col = 10, + height = 10, + width = 10, border = 'single', title = { { 'TITLE' } }, footer = 0, @@ -1831,10 +1831,10 @@ describe('API/win', function() 'title/footer must be string or array', pcall_err(api.nvim_open_win, 0, false, { relative = 'editor', - row = 5, - col = 5, - height = 5, - width = 5, + row = 10, + col = 10, + height = 10, + width = 10, border = 'single', title = 0, footer = { { 'FOOTER' } }, @@ -2840,10 +2840,10 @@ describe('API/win', function() before_each(function() win = api.nvim_open_win(0, false, { relative = 'editor', - row = 5, - col = 5, - height = 5, - width = 5, + row = 10, + col = 10, + height = 10, + width = 10, border = 'single', title = { { 'OLD_TITLE' } }, footer = { { 'OLD_FOOTER' } }, diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua index 52b46d0ecb..b2ed5f5a5f 100644 --- a/test/functional/ui/float_spec.lua +++ b/test/functional/ui/float_spec.lua @@ -2562,6 +2562,37 @@ describe('float window', function() end eq({{"🦄", ""}, {"BB", {"B0", "B1", ""}}}, api.nvim_win_get_config(win).title) eq({{"🦄", ""}, {"BB", {"B0", "B1", ""}}}, api.nvim_win_get_config(win).footer) + + -- making it a split should not leak memory + api.nvim_win_set_config(win, { vertical = true }) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [4:--------------------]{5:│}[2:-------------------]|*5 + {5:[No Name] [+] }{4:[No Name] }| + [3:----------------------------------------]| + ## grid 2 + ^ | + {0:~ }|*4 + ## grid 3 + | + ## grid 4 + halloj! | + BORDAA | + {0:~ }|*3 + ]], win_viewport={ + [2] = {win = 1000, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = 1001, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; + }} + else + screen:expect{grid=[[ + halloj! {5:│}^ | + BORDAA {5:│}{0:~ }| + {0:~ }{5:│}{0:~ }|*3 + {5:[No Name] [+] }{4:[No Name] }| + | + ]]} + end end) it('terminates border on edge of viewport when window extends past viewport', function() -- cgit From d5f6f61879bac3ac90512efe05d68e3500125a08 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 28 Sep 2024 17:16:22 +0800 Subject: fix(column): set signcolumn width after splitting window (#30556) --- test/functional/ui/sign_spec.lua | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'test/functional') diff --git a/test/functional/ui/sign_spec.lua b/test/functional/ui/sign_spec.lua index 6f4bf5695d..30da79af47 100644 --- a/test/functional/ui/sign_spec.lua +++ b/test/functional/ui/sign_spec.lua @@ -4,6 +4,7 @@ local Screen = require('test.functional.ui.screen') local api, clear, eq = n.api, n.clear, t.eq local eval, exec, feed = n.eval, n.exec, n.feed +local exec_lua = n.exec_lua describe('Signs', function() local screen @@ -607,4 +608,15 @@ describe('Signs', function() exec('sign unplace 1') screen:expect(s1) end) + + it('signcolumn width is set immediately after splitting window #30547', function() + local infos = exec_lua([[ + vim.o.number = true + vim.o.signcolumn = 'yes' + vim.cmd.wincmd('v') + return vim.fn.getwininfo() + ]]) + eq(6, infos[1].textoff) + eq(6, infos[2].textoff) + end) end) -- cgit From df915f3afccb2717bc62e7b8649d76885cc3916c Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 29 Sep 2024 18:38:17 +0800 Subject: fix(float): properly find last window of tabpage (#30571) --- test/functional/ui/float_spec.lua | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'test/functional') diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua index b2ed5f5a5f..9b77cb4014 100644 --- a/test/functional/ui/float_spec.lua +++ b/test/functional/ui/float_spec.lua @@ -662,6 +662,22 @@ describe('float window', function() screen:detach() end) + it('no crash with relative="win" after %bdelete #30569', function() + exec([[ + botright vsplit + %bdelete + ]]) + api.nvim_open_win(0, false, { + relative = 'win', + win = 0, + row = 0, + col = 5, + width = 5, + height = 5, + }) + assert_alive() + end) + describe('with only one tabpage,', function() local float_opts = {relative = 'editor', row = 1, col = 1, width = 1, height = 1} local old_buf, old_win -- cgit From 99e0facf3a001608287ec6db69b01c77443c7b9d Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sun, 15 Sep 2024 14:19:08 +0200 Subject: feat(treesitter)!: use return values in `language.add()` Problem: No clear way to check whether parsers are available for a given language. Solution: Make `language.add()` return `true` if a parser was successfully added and `nil` otherwise. Use explicit `assert` instead of relying on thrown errors. --- test/functional/treesitter/language_spec.lua | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) (limited to 'test/functional') diff --git a/test/functional/treesitter/language_spec.lua b/test/functional/treesitter/language_spec.lua index 3947ab23b2..e1e34fcecc 100644 --- a/test/functional/treesitter/language_spec.lua +++ b/test/functional/treesitter/language_spec.lua @@ -31,29 +31,21 @@ describe('treesitter language API', function() ) ) - eq(false, exec_lua("return pcall(vim.treesitter.language.add, 'borklang')")) + eq(NIL, exec_lua("return vim.treesitter.language.add('borklang')")) eq( false, exec_lua("return pcall(vim.treesitter.language.add, 'borklang', { path = 'borkbork.so' })") ) - eq( - ".../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers", - pcall_err(exec_lua, "parser = vim.treesitter.language.inspect('borklang')") - ) - matches( 'Failed to load parser: uv_dlsym: .+', pcall_err(exec_lua, 'vim.treesitter.language.add("c", { symbol_name = "borklang" })') ) end) - it('shows error for invalid language name', function() - eq( - ".../language.lua:0: '/foo/' is not a valid language name", - pcall_err(exec_lua, 'vim.treesitter.language.add("/foo/")') - ) + it('does not load parser for invalid language name', function() + eq(NIL, exec_lua('vim.treesitter.language.add("/foo/")')) end) it('inspects language', function() -- cgit From c65646c2474d22948c604168a68f6626a645d1d2 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 26 Sep 2024 16:10:11 +0100 Subject: fix(diff): use mmfile_t in linematch Problem: Linematch used to use strchr to navigate a string, however strchr does not supoprt embedded NULs. Solution: Use `mmfile_t` instead of `char *` in linematch and introduce `strnchr()`. Also remove heap allocations from `matching_char_iwhite()` Fixes: #30505 --- test/functional/lua/xdiff_spec.lua | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'test/functional') diff --git a/test/functional/lua/xdiff_spec.lua b/test/functional/lua/xdiff_spec.lua index d5589c1f13..ed65193244 100644 --- a/test/functional/lua/xdiff_spec.lua +++ b/test/functional/lua/xdiff_spec.lua @@ -174,4 +174,13 @@ describe('xdiff bindings', function() pcall_err(exec_lua, [[vim.diff('a', 'b', { on_hunk = true })]]) ) end) + + it('can handle strings with embedded NUL characters (GitHub #30305)', function() + eq( + { { 0, 0, 1, 1 }, { 1, 0, 3, 2 } }, + exec_lua(function() + return vim.diff('\n', '\0\n\n\nb', { linematch = true, result_type = 'indices' }) + end) + ) + end) end) -- cgit From 0fb5299e53cc0d7a5c03c333b1ed79262a0db3f9 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Sun, 29 Sep 2024 11:20:18 +0100 Subject: test: refactor exec_lua in xdiff_spec --- test/functional/lua/xdiff_spec.lua | 103 ++++++++++++++++++++----------------- 1 file changed, 57 insertions(+), 46 deletions(-) (limited to 'test/functional') diff --git a/test/functional/lua/xdiff_spec.lua b/test/functional/lua/xdiff_spec.lua index ed65193244..269dbde10a 100644 --- a/test/functional/lua/xdiff_spec.lua +++ b/test/functional/lua/xdiff_spec.lua @@ -12,15 +12,11 @@ describe('xdiff bindings', function() end) describe('can diff text', function() - before_each(function() - exec_lua [[ - a1 = 'Hello\n' - b1 = 'Helli\n' - - a2 = 'Hello\nbye\nfoo\n' - b2 = 'Helli\nbye\nbar\nbaz\n' - ]] - end) + local a1 = 'Hello\n' + local b1 = 'Helli\n' + + local a2 = 'Hello\nbye\nfoo\n' + local b2 = 'Helli\nbye\nbar\nbaz\n' it('with no callback', function() eq( @@ -30,7 +26,9 @@ describe('xdiff bindings', function() '+Helli', '', }, '\n'), - exec_lua('return vim.diff(a1, b1)') + exec_lua(function() + return vim.diff(a1, b1) + end) ) eq( @@ -44,63 +42,81 @@ describe('xdiff bindings', function() '+baz', '', }, '\n'), - exec_lua('return vim.diff(a2, b2)') + exec_lua(function() + return vim.diff(a2, b2) + end) ) end) it('with callback', function() - exec_lua([[on_hunk = function(sa, ca, sb, cb) - exp[#exp+1] = {sa, ca, sb, cb} - end]]) - eq( { { 1, 1, 1, 1 } }, - exec_lua [[ - exp = {} - assert(vim.diff(a1, b1, {on_hunk = on_hunk}) == nil) + exec_lua(function() + local exp = {} --- @type table[] + assert(vim.diff(a1, b1, { + on_hunk = function(...) + exp[#exp + 1] = { ... } + end, + }) == nil) return exp - ]] + end) ) eq( { { 1, 1, 1, 1 }, { 3, 1, 3, 2 } }, - exec_lua [[ - exp = {} - assert(vim.diff(a2, b2, {on_hunk = on_hunk}) == nil) + exec_lua(function() + local exp = {} --- @type table[] + assert(vim.diff(a2, b2, { + on_hunk = function(...) + exp[#exp + 1] = { ... } + end, + }) == nil) return exp - ]] + end) ) -- gives higher precedence to on_hunk over result_type eq( { { 1, 1, 1, 1 }, { 3, 1, 3, 2 } }, - exec_lua [[ - exp = {} - assert(vim.diff(a2, b2, {on_hunk = on_hunk, result_type='indices'}) == nil) + exec_lua(function() + local exp = {} --- @type table[] + assert(vim.diff(a2, b2, { + on_hunk = function(...) + exp[#exp + 1] = { ... } + end, + result_type = 'indices', + }) == nil) return exp - ]] + end) ) end) it('with error callback', function() - exec_lua [[ - on_hunk = function(sa, ca, sb, cb) - error('ERROR1') - end - ]] - eq( - [[error running function on_hunk: [string ""]:0: ERROR1]], - pcall_err(exec_lua, [[vim.diff(a1, b1, {on_hunk = on_hunk})]]) + [[.../xdiff_spec.lua:0: error running function on_hunk: .../xdiff_spec.lua:0: ERROR1]], + pcall_err(exec_lua, function() + vim.diff(a1, b1, { + on_hunk = function() + error('ERROR1') + end, + }) + end) ) end) it('with hunk_lines', function() - eq({ { 1, 1, 1, 1 } }, exec_lua([[return vim.diff(a1, b1, {result_type = 'indices'})]])) + eq( + { { 1, 1, 1, 1 } }, + exec_lua(function() + return vim.diff(a1, b1, { result_type = 'indices' }) + end) + ) eq( { { 1, 1, 1, 1 }, { 3, 1, 3, 2 } }, - exec_lua([[return vim.diff(a2, b2, {result_type = 'indices'})]]) + exec_lua(function() + return vim.diff(a2, b2, { result_type = 'indices' }) + end) ) end) @@ -143,16 +159,11 @@ describe('xdiff bindings', function() '+}', '', }, '\n'), - exec_lua( - [[ - local args = {...} - return vim.diff(args[1], args[2], { - algorithm = 'patience' + exec_lua(function() + return vim.diff(a, b, { + algorithm = 'patience', }) - ]], - a, - b - ) + end) ) end) end) -- cgit From 1c30d86c337ec6f859061db9feac42933d5fdf78 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 1 Oct 2024 19:46:30 +0800 Subject: fix(tabline): restore behavior of click after last tabpage (#30602) Also correct the comments about tabpage labels in custom tabline. --- test/functional/ui/mouse_spec.lua | 73 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 69 insertions(+), 4 deletions(-) (limited to 'test/functional') diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua index 8bda661902..bc18680749 100644 --- a/test/functional/ui/mouse_spec.lua +++ b/test/functional/ui/mouse_spec.lua @@ -367,7 +367,7 @@ describe('ui/mouse/input', function() }) end) - it('left click in default tabline (position 4) switches to tab', function() + it('left click in default tabline (tabpage label) switches to tab', function() feed_command('%delete') insert('this is foo') feed_command('silent file foo | tabnew | file bar') @@ -385,9 +385,47 @@ describe('ui/mouse/input', function() {0:~ }|*2 | ]]) + feed('<6,0>') + screen:expect_unchanged() + feed('<10,0>') + screen:expect([[ + {tab: + foo }{sel: + bar }{fill: }{tab:X}| + this is ba^r{0:$} | + {0:~ }|*2 + | + ]]) + feed('<12,0>') + screen:expect_unchanged() end) - it('left click in default tabline (position 24) closes tab', function() + it('left click in default tabline (blank space) switches tab', function() + feed_command('%delete') + insert('this is foo') + feed_command('silent file foo | tabnew | file bar') + insert('this is bar') + screen:expect([[ + {tab: + foo }{sel: + bar }{fill: }{tab:X}| + this is ba^r{0:$} | + {0:~ }|*2 + | + ]]) + feed('<20,0>') + screen:expect([[ + {sel: + foo }{tab: + bar }{fill: }{tab:X}| + this is fo^o | + {0:~ }|*2 + | + ]]) + feed('<22,0>') + screen:expect([[ + {tab: + foo }{sel: + bar }{fill: }{tab:X}| + this is ba^r{0:$} | + {0:~ }|*2 + | + ]]) + end) + + it('left click in default tabline (close label) closes tab', function() api.nvim_set_option_value('hidden', true, {}) feed_command('%delete') insert('this is foo') @@ -407,8 +445,7 @@ describe('ui/mouse/input', function() ]]) end) - it('double click in default tabline (position 4) opens new tab', function() - api.nvim_set_option_value('hidden', true, {}) + it('double click in default tabline opens new tab before', function() feed_command('%delete') insert('this is foo') feed_command('silent file foo | tabnew | file bar') @@ -426,6 +463,34 @@ describe('ui/mouse/input', function() {0:~ }|*2 | ]]) + command('tabclose') + screen:expect([[ + {sel: + foo }{tab: + bar }{fill: }{tab:X}| + this is fo^o | + {0:~ }|*2 + | + ]]) + feed('<2-LeftMouse><20,0>') + screen:expect([[ + {tab: + foo + bar }{sel: Name] }{fill: }{tab:X}| + {0:^$} | + {0:~ }|*2 + | + ]]) + command('tabclose') + screen:expect([[ + {tab: + foo }{sel: + bar }{fill: }{tab:X}| + this is ba^r{0:$} | + {0:~ }|*2 + | + ]]) + feed('<2-LeftMouse><10,0>') + screen:expect([[ + {tab: + foo }{sel: Name] }{tab: + bar }{fill: }{tab:X}| + {0:^$} | + {0:~ }|*2 + | + ]]) end) describe('%@ label', function() -- cgit From 0e484c2041f9196f61c2b5dfaed38e81d068680d Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 2 Oct 2024 06:55:43 +0800 Subject: vim-patch:9.1.0753: Wrong display when typing in diff mode with 'smoothscroll' (#30614) Problem: Wrong display when typing in diff mode with 'smoothscroll'. Solution: Use adjust_plines_for_skipcol() (zeertzjq). closes: vim/vim#15776 https://github.com/vim/vim/commit/47f8584a80006cd25e7dc6fa7fb1bfe2e768403c --- test/functional/legacy/scroll_opt_spec.lua | 102 +++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) (limited to 'test/functional') diff --git a/test/functional/legacy/scroll_opt_spec.lua b/test/functional/legacy/scroll_opt_spec.lua index 80b689df55..ec1dc59d53 100644 --- a/test/functional/legacy/scroll_opt_spec.lua +++ b/test/functional/legacy/scroll_opt_spec.lua @@ -375,6 +375,108 @@ describe('smoothscroll', function() screen:expect_unchanged() end) + -- oldtest: Test_smoothscroll_diff_change_line() + it('works in diff mode when changing line', function() + screen:try_resize(55, 20) + exec([[ + set diffopt+=followwrap smoothscroll + call setline(1, repeat(' abc', &columns)) + call setline(2, 'bar') + call setline(3, repeat(' abc', &columns)) + vnew + call setline(1, repeat(' abc', &columns)) + call setline(2, 'foo') + call setline(3, 'bar') + call setline(4, repeat(' abc', &columns)) + windo exe "normal! 2gg5\" + windo diffthis + ]]) + + screen:expect([[ + {1:<<<}bc abc abc abc abc abc a│{1:<<<}bc abc abc abc abc abc a| + {7: }bc abc abc abc abc abc ab│{7: }bc abc abc abc abc abc ab| + {7: }c abc abc abc abc abc abc│{7: }c abc abc abc abc abc abc| + {7: } abc abc abc abc abc │{7: } abc abc abc abc abc | + {7: }{22:foo }│{7: }{23:-------------------------}| + {7: }bar │{7: }^bar | + {7: } abc abc abc abc abc abc │{7: } abc abc abc abc abc abc | + {7: }abc abc abc abc abc abc a│{7: }abc abc abc abc abc abc a| + {7: }bc abc abc abc abc abc ab│{7: }bc abc abc abc abc abc ab| + {7: }c abc abc abc abc abc abc│{7: }c abc abc abc abc abc abc| + {7: } abc abc abc abc abc abc │{7: } abc abc abc abc abc abc | + {7: }abc abc abc abc abc abc a│{7: }abc abc abc abc abc abc a| + {7: }bc abc abc abc abc abc ab│{7: }bc abc abc abc abc abc ab| + {7: }c abc abc abc abc abc abc│{7: }c abc abc abc abc abc abc| + {7: } abc abc abc abc abc │{7: } abc abc abc abc abc | + {1:~ }│{1:~ }|*3 + {2:[No Name] [+] }{3:[No Name] [+] }| + | + ]]) + feed('Abar') + screen:expect([[ + {1:<<<}bc abc abc abc abc abc a│{1:<<<}bc abc abc abc abc abc a| + {7: }bc abc abc abc abc abc ab│{7: }bc abc abc abc abc abc ab| + {7: }c abc abc abc abc abc abc│{7: }c abc abc abc abc abc abc| + {7: } abc abc abc abc abc │{7: } abc abc abc abc abc | + {7: }{22:foo }│{7: }{23:-------------------------}| + {7: }bar │{7: }barbar^ | + {7: } abc abc abc abc abc abc │{7: } abc abc abc abc abc abc | + {7: }abc abc abc abc abc abc a│{7: }abc abc abc abc abc abc a| + {7: }bc abc abc abc abc abc ab│{7: }bc abc abc abc abc abc ab| + {7: }c abc abc abc abc abc abc│{7: }c abc abc abc abc abc abc| + {7: } abc abc abc abc abc abc │{7: } abc abc abc abc abc abc | + {7: }abc abc abc abc abc abc a│{7: }abc abc abc abc abc abc a| + {7: }bc abc abc abc abc abc ab│{7: }bc abc abc abc abc abc ab| + {7: }c abc abc abc abc abc abc│{7: }c abc abc abc abc abc abc| + {7: } abc abc abc abc abc │{7: } abc abc abc abc abc | + {1:~ }│{1:~ }|*3 + {2:[No Name] [+] }{3:[No Name] [+] }| + {5:-- INSERT --} | + ]]) + feed('') + screen:expect([[ + {1:<<<}bc abc abc abc abc abc a│{1:<<<}bc abc abc abc abc abc a| + {7: }bc abc abc abc abc abc ab│{7: }bc abc abc abc abc abc ab| + {7: }c abc abc abc abc abc abc│{7: }c abc abc abc abc abc abc| + {7: } abc abc abc abc abc │{7: } abc abc abc abc abc | + {7: }{27:foo}{4: }│{7: }{27:barba^r}{4: }| + {7: }{22:bar }│{7: }{23:-------------------------}| + {7: } abc abc abc abc abc abc │{7: } abc abc abc abc abc abc | + {7: }abc abc abc abc abc abc a│{7: }abc abc abc abc abc abc a| + {7: }bc abc abc abc abc abc ab│{7: }bc abc abc abc abc abc ab| + {7: }c abc abc abc abc abc abc│{7: }c abc abc abc abc abc abc| + {7: } abc abc abc abc abc abc │{7: } abc abc abc abc abc abc | + {7: }abc abc abc abc abc abc a│{7: }abc abc abc abc abc abc a| + {7: }bc abc abc abc abc abc ab│{7: }bc abc abc abc abc abc ab| + {7: }c abc abc abc abc abc abc│{7: }c abc abc abc abc abc abc| + {7: } abc abc abc abc abc │{7: } abc abc abc abc abc | + {1:~ }│{1:~ }|*3 + {2:[No Name] [+] }{3:[No Name] [+] }| + | + ]]) + feed('yyp') + screen:expect([[ + {1:<<<}bc abc abc abc abc abc a│{1:<<<}bc abc abc abc abc abc a| + {7: }bc abc abc abc abc abc ab│{7: }bc abc abc abc abc abc ab| + {7: }c abc abc abc abc abc abc│{7: }c abc abc abc abc abc abc| + {7: } abc abc abc abc abc │{7: } abc abc abc abc abc | + {7: }{27:foo}{4: }│{7: }{27:barbar}{4: }| + {7: }{4:bar }│{7: }{4:^bar}{27:bar}{4: }| + {7: } abc abc abc abc abc abc │{7: } abc abc abc abc abc abc | + {7: }abc abc abc abc abc abc a│{7: }abc abc abc abc abc abc a| + {7: }bc abc abc abc abc abc ab│{7: }bc abc abc abc abc abc ab| + {7: }c abc abc abc abc abc abc│{7: }c abc abc abc abc abc abc| + {7: } abc abc abc abc abc abc │{7: } abc abc abc abc abc abc | + {7: }abc abc abc abc abc abc a│{7: }abc abc abc abc abc abc a| + {7: }bc abc abc abc abc abc ab│{7: }bc abc abc abc abc abc ab| + {7: }c abc abc abc abc abc abc│{7: }c abc abc abc abc abc abc| + {7: } abc abc abc abc abc │{7: } abc abc abc abc abc | + {1:~ }│{1:~ }|*3 + {2:[No Name] [+] }{3:[No Name] [+] }| + | + ]]) + end) + -- oldtest: Test_smoothscroll_wrap_scrolloff_zero() it("works with zero 'scrolloff'", function() screen:try_resize(40, 8) -- cgit From 9e23b4e1852f9ad6418b45f827d1fb160611d8cf Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Mon, 30 Sep 2024 15:25:44 +0200 Subject: fix(watch): ignore nonexistent paths (ENOENT) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: The `_watch.watch()` strategy may fail if the given path does not exist: …/vim/_watch.lua:101: ENOENT: no such file or directory stack traceback: [C]: in function 'assert' …/vim/_watch.lua:101: in function <…/vim/_watch.lua:61> [string ""]:5: in main chunk - `_watch.watch()` actively asserts any error returned by `handle:start()`. - whereas `_watch.watchdirs()` just ignores the result of `root_handle:start()`. Servers may send "client/registerCapability" with "workspace/didChangeWatchedFiles" item(s) (`baseUri`) which do not actually exist on the filesystem: https://github.com/neovim/neovim/issues/28058#issuecomment-2189929424 { method = "client/registerCapability", params = { registrations = { { method = "workspace/didChangeWatchedFiles", registerOptions = { watchers = { { globPattern = { baseUri = "file:///Users/does/not/exist", pattern = "**/*.{ts,js,mts,mjs,cjs,cts,json,svelte}" } }, ... } Solution: - Remove the assert in `_watch.watch()`. - Show a once-only message for both cases. - More detailed logging is blocked until we have `nvim_log` / `vim.log`. fix #28058 --- test/functional/lua/watch_spec.lua | 92 ++++++++++++++++++++++++++------------ 1 file changed, 64 insertions(+), 28 deletions(-) (limited to 'test/functional') diff --git a/test/functional/lua/watch_spec.lua b/test/functional/lua/watch_spec.lua index ab6b1416aa..a1e4a42ebe 100644 --- a/test/functional/lua/watch_spec.lua +++ b/test/functional/lua/watch_spec.lua @@ -21,16 +21,72 @@ describe('vim._watch', function() end) local function run(watchfunc) - it('detects file changes (watchfunc=' .. watchfunc .. '())', function() + -- Monkey-patches vim.notify_once so we can "spy" on it. + local function spy_notify_once() + exec_lua [[ + _G.__notify_once_msgs = {} + vim.notify_once = (function(overridden) + return function(msg, level, opts) + table.insert(_G.__notify_once_msgs, msg) + return overridden(msg, level, opts) + end + end)(vim.notify_once) + ]] + end + + local function last_notify_once_msg() + return exec_lua 'return _G.__notify_once_msgs[#_G.__notify_once_msgs]' + end + + local function do_watch(root_dir, watchfunc_) + exec_lua( + [[ + local root_dir, watchfunc = ... + + _G.events = {} + + _G.stop_watch = vim._watch[watchfunc](root_dir, { + debounce = 100, + include_pattern = vim.lpeg.P(root_dir) * vim.lpeg.P("/file") ^ -1, + exclude_pattern = vim.lpeg.P(root_dir .. '/file.unwatched'), + }, function(path, change_type) + table.insert(_G.events, { path = path, change_type = change_type }) + end) + ]], + root_dir, + watchfunc_ + ) + end + + it(watchfunc .. '() ignores nonexistent paths', function() + if watchfunc == 'inotify' then + skip(n.fn.executable('inotifywait') == 0, 'inotifywait not found') + skip(is_os('bsd'), 'inotifywait on bsd CI seems to expect path to exist?') + end + + local msg = ('watch.%s: ENOENT: no such file or directory'):format(watchfunc) + + spy_notify_once() + do_watch('/i am /very/funny.go', watchfunc) + + if watchfunc ~= 'inotify' then -- watch.inotify() doesn't (currently) call vim.notify_once. + t.retry(nil, 2000, function() + t.eq(msg, last_notify_once_msg()) + end) + end + eq(0, exec_lua [[return #_G.events]]) + + exec_lua [[_G.stop_watch()]] + end) + + it(watchfunc .. '() detects file changes', function() if watchfunc == 'inotify' then skip(is_os('win'), 'not supported on windows') skip(is_os('mac'), 'flaky test on mac') - skip( - not is_ci() and n.fn.executable('inotifywait') == 0, - 'inotify-tools not installed and not on CI' - ) + skip(not is_ci() and n.fn.executable('inotifywait') == 0, 'inotifywait not found') end + -- Note: because this is not `elseif`, BSD is skipped for *all* cases...? if watchfunc == 'watch' then skip(is_os('mac'), 'flaky test on mac') skip(is_os('bsd'), 'Stopped working on bsd after 3ca967387c49c754561c3b11a574797504d40f38') @@ -41,10 +97,8 @@ describe('vim._watch', function() ) end - local root_dir = vim.uv.fs_mkdtemp(vim.fs.dirname(t.tmpname(false)) .. '/nvim_XXXXXXXXXX') - local expected_events = 0 - + --- Waits for a new event, or fails if no events are triggered. local function wait_for_event() expected_events = expected_events + 1 exec_lua( @@ -65,26 +119,11 @@ describe('vim._watch', function() ) end + local root_dir = vim.uv.fs_mkdtemp(vim.fs.dirname(t.tmpname(false)) .. '/nvim_XXXXXXXXXX') local unwatched_path = root_dir .. '/file.unwatched' local watched_path = root_dir .. '/file' - exec_lua( - [[ - local root_dir, watchfunc = ... - - _G.events = {} - - _G.stop_watch = vim._watch[watchfunc](root_dir, { - debounce = 100, - include_pattern = vim.lpeg.P(root_dir) * vim.lpeg.P("/file") ^ -1, - exclude_pattern = vim.lpeg.P(root_dir .. '/file.unwatched'), - }, function(path, change_type) - table.insert(_G.events, { path = path, change_type = change_type }) - end) - ]], - root_dir, - watchfunc - ) + do_watch(root_dir, watchfunc) if watchfunc ~= 'watch' then vim.uv.sleep(200) @@ -92,16 +131,13 @@ describe('vim._watch', function() touch(watched_path) touch(unwatched_path) - wait_for_event() os.remove(watched_path) os.remove(unwatched_path) - wait_for_event() exec_lua [[_G.stop_watch()]] - -- No events should come through anymore vim.uv.sleep(100) -- cgit From bbf208784ca279178ba0075b60d3e9c80f11da7a Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Wed, 2 Oct 2024 16:36:50 +0200 Subject: tests: skip watch.watchdirs test on macos 14 CI Problem: Strange failure only in macos 14 CI FAILED test/functional/lua/watch_spec.lua @ 82: vim._watch watchdirs() detects file changes test/functional/lua/watch_spec.lua:149: Expected objects to be the same. Passed in: (table: 0x0116023758) { *[1] = { [change_type] = 3 *[path] = '/Users/runner/work/neovim/neovim/build/Xtest_tmpdir/nvim_KFMvPbXk9a/nvim_KFMvPbXk9a' } [2] = { [change_type] = 3 [path] = '/Users/runner/work/neovim/neovim/build/Xtest_tmpdir/nvim_KFMvPbXk9a/file' } } Expected: (table: 0x010d9d6548) { *[1] = { [change_type] = 1 *[path] = '/Users/runner/work/neovim/neovim/build/Xtest_tmpdir/nvim_KFMvPbXk9a/file' } [2] = { [change_type] = 3 [path] = '/Users/runner/work/neovim/neovim/build/Xtest_tmpdir/nvim_KFMvPbXk9a/file' } } stack traceback: test/functional/lua/watch_spec.lua:149: in function Solution: Skip test for that exact version. --- test/functional/lua/watch_spec.lua | 3 +++ 1 file changed, 3 insertions(+) (limited to 'test/functional') diff --git a/test/functional/lua/watch_spec.lua b/test/functional/lua/watch_spec.lua index a1e4a42ebe..0c575900d3 100644 --- a/test/functional/lua/watch_spec.lua +++ b/test/functional/lua/watch_spec.lua @@ -90,6 +90,9 @@ describe('vim._watch', function() if watchfunc == 'watch' then skip(is_os('mac'), 'flaky test on mac') skip(is_os('bsd'), 'Stopped working on bsd after 3ca967387c49c754561c3b11a574797504d40f38') + elseif watchfunc == 'watchdirs' and is_os('mac') then + -- Bump this (or fix the bug) if CI continues to fail in future versions of macos CI. + skip(is_ci() and vim.uv.os_uname().release == '23.6.0', 'weird failure for macOS arm 14 CI') else skip( is_os('bsd'), -- cgit From 6a2f8958e832aebc20cf42d8ade4cb58fe33df9e Mon Sep 17 00:00:00 2001 From: glepnir Date: Thu, 3 Oct 2024 06:45:01 +0800 Subject: vim-patch:9.1.0754: fixed order of items in insert-mode completion menu (#30619) Problem: fixed order of items in insert-mode completion menu Solution: Introduce the 'completeitemalign' option with default value "abbr,kind,menu" (glepnir). Adding an new option `completeitemalign` abbr is `cia` to custom the complete-item order in popupmenu. closes: vim/vim#14006 closes: vim/vim#15760 https://github.com/vim/vim/commit/6a89c94a9eeee53481ced1a1260a177bffde4c0f --- test/functional/ui/popupmenu_spec.lua | 102 ++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) (limited to 'test/functional') diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index 3acbd5d987..e2f7e31c6c 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -5061,6 +5061,108 @@ describe('builtin popupmenu', function() ]]) feed('') end) + + -- oldtest: Test_pum_completeitemalign() + it('completeitemalign option', function() + screen:try_resize(30, 15) + exec([[ + func Omni_test(findstart, base) + if a:findstart + return col(".") + endif + return { + \ 'words': [ + \ { 'word': 'foo', 'kind': 'S', 'menu': 'menu' }, + \ { 'word': 'bar', 'kind': 'T', 'menu': 'menu' }, + \ { 'word': '你好', 'kind': 'C', 'menu': '中文' }, + \]} + endfunc + set omnifunc=Omni_test + ]]) + -- T1 + command('set cia=abbr,kind,menu') + feed('S') + screen:expect([[ + foo^ | + {s:foo S menu }{1: }| + {n:bar T menu }{1: }| + {n:你好 C 中文 }{1: }| + {1:~ }|*10 + {2:-- }{5:match 1 of 3} | + ]]) + feed('') + -- T2 + command('set cia=abbr,menu,kind') + feed('S') + screen:expect([[ + foo^ | + {s:foo menu S }{1: }| + {n:bar menu T }{1: }| + {n:你好 中文 C }{1: }| + {1:~ }|*10 + {2:-- }{5:match 1 of 3} | + ]]) + feed('') + -- T3 + command('set cia=kind,abbr,menu') + feed('S') + screen:expect([[ + foo^ | + {s:S foo menu }{1: }| + {n:T bar menu }{1: }| + {n:C 你好 中文 }{1: }| + {1:~ }|*10 + {2:-- }{5:match 1 of 3} | + ]]) + feed('') + -- T4 + command('set cia=kind,menu,abbr') + feed('S') + screen:expect([[ + foo^ | + {s:S menu foo }{1: }| + {n:T menu bar }{1: }| + {n:C 中文 你好 }{1: }| + {1:~ }|*10 + {2:-- }{5:match 1 of 3} | + ]]) + feed('') + -- T5 + command('set cia=menu,abbr,kind') + feed('S') + screen:expect([[ + foo^ | + {s:menu foo S }{1: }| + {n:menu bar T }{1: }| + {n:中文 你好 C }{1: }| + {1:~ }|*10 + {2:-- }{5:match 1 of 3} | + ]]) + feed('') + -- T6 + command('set cia=menu,kind,abbr') + feed('S') + screen:expect([[ + foo^ | + {s:menu S foo }{1: }| + {n:menu T bar }{1: }| + {n:中文 C 你好 }{1: }| + {1:~ }|*10 + {2:-- }{5:match 1 of 3} | + ]]) + feed('') + -- T7 + command('set cia&') + feed('S') + screen:expect([[ + foo^ | + {s:foo S menu }{1: }| + {n:bar T menu }{1: }| + {n:你好 C 中文 }{1: }| + {1:~ }|*10 + {2:-- }{5:match 1 of 3} | + ]]) + end) end end -- cgit From 7eba016c86818c5f6fa1542500b19d27bb7ab15c Mon Sep 17 00:00:00 2001 From: fredizzimo Date: Thu, 3 Oct 2024 12:31:17 +0300 Subject: fix(ui): ensure screen update before waiting for input #30576 Ensure the screen is fully updated before blocking for input. This did not always happen before, for example when setting `cursorline scrolloff=9999`, which lead to jerky movement when using some GUI applications. Because of the duality of redraw_later, this can't be done in command-line or when waiting for "Press ENTER". In many of those cases the redraw is expected AFTER the key press, while normally it should update the screen immediately. So, those special cases are excluded. --- test/functional/ui/multigrid_spec.lua | 253 ++++++++++++++++++++++++++++++++++ 1 file changed, 253 insertions(+) (limited to 'test/functional') diff --git a/test/functional/ui/multigrid_spec.lua b/test/functional/ui/multigrid_spec.lua index 63ae38d3c3..e009ed0a29 100644 --- a/test/functional/ui/multigrid_spec.lua +++ b/test/functional/ui/multigrid_spec.lua @@ -2599,4 +2599,257 @@ describe('ext_multigrid', function() ]]) eq(1, api.nvim_get_option_value('cmdheight', {})) end) + + describe('centered cursorline', function() + before_each(function() + -- Force a centered cursorline, this caused some redrawing problems described in #30576. + -- Most importantly, win_viewport was not received in time, and sum_scroll_delta did not refresh. + command('set cursorline scrolloff=9999') + end) + it('insert line scrolls correctly', function() + for i = 1, 11 do + insert('line' .. i .. '\n') + end + screen:expect({ + grid = [[ + ## grid 1 + [2:-----------------------------------------------------]|*12 + {11:[No Name] [+] }| + [3:-----------------------------------------------------]| + ## grid 2 + line1 | + line2 | + line3 | + line4 | + line5 | + line6 | + line7 | + line8 | + line9 | + line10 | + line11 | + {23:^ }| + ## grid 3 + | + ]], win_viewport={ + [2] = {win = 1000, topline = 0, botline = 12, curline = 11, curcol = 0, linecount = 12, sum_scroll_delta = 0}; + }, win_viewport_margins={ + [2] = { + bottom = 0, + left = 0, + right = 0, + top = 0, + win = 1000 + } + }}) + insert('line12\n') + screen:expect({ + grid = [[ + ## grid 1 + [2:-----------------------------------------------------]|*12 + {11:[No Name] [+] }| + [3:-----------------------------------------------------]| + ## grid 2 + line2 | + line3 | + line4 | + line5 | + line6 | + line7 | + line8 | + line9 | + line10 | + line11 | + line12 | + {23:^ }| + ## grid 3 + | + ]], win_viewport={ + [2] = {win = 1000, topline = 1, botline = 13, curline = 12, curcol = 0, linecount = 13, sum_scroll_delta = 1}; + }, win_viewport_margins={ + [2] = { + bottom = 0, + left = 0, + right = 0, + top = 0, + win = 1000 + } + }}) + end) + + it('got to top scrolls correctly', function() + for i = 1, 20 do + insert('line' .. i .. '\n') + end + screen:expect({ + grid = [[ + ## grid 1 + [2:-----------------------------------------------------]|*12 + {11:[No Name] [+] }| + [3:-----------------------------------------------------]| + ## grid 2 + line10 | + line11 | + line12 | + line13 | + line14 | + line15 | + line16 | + line17 | + line18 | + line19 | + line20 | + {23:^ }| + ## grid 3 + | + ]], win_viewport={ + [2] = {win = 1000, topline = 9, botline = 21, curline = 20, curcol = 0, linecount = 21, sum_scroll_delta = 9}; + }, win_viewport_margins={ + [2] = { + bottom = 0, + left = 0, + right = 0, + top = 0, + win = 1000 + } + }}) + feed('gg') + screen:expect({ + grid = [[ + ## grid 1 + [2:-----------------------------------------------------]|*12 + {11:[No Name] [+] }| + [3:-----------------------------------------------------]| + ## grid 2 + {23:^line1 }| + line2 | + line3 | + line4 | + line5 | + line6 | + line7 | + line8 | + line9 | + line10 | + line11 | + line12 | + ## grid 3 + | + ]], win_viewport={ + [2] = {win = 1000, topline = 0, botline = 13, curline = 0, curcol = 0, linecount = 21, sum_scroll_delta = 0}; + }, win_viewport_margins={ + [2] = { + bottom = 0, + left = 0, + right = 0, + top = 0, + win = 1000 + } + }}) + end) + + it('scrolls in the middle', function() + for i = 1, 20 do + insert('line' .. i .. '\n') + end + screen:expect({ + grid = [[ + ## grid 1 + [2:-----------------------------------------------------]|*12 + {11:[No Name] [+] }| + [3:-----------------------------------------------------]| + ## grid 2 + line10 | + line11 | + line12 | + line13 | + line14 | + line15 | + line16 | + line17 | + line18 | + line19 | + line20 | + {23:^ }| + ## grid 3 + | + ]], win_viewport={ + [2] = {win = 1000, topline = 9, botline = 21, curline = 20, curcol = 0, linecount = 21, sum_scroll_delta = 9}; + }, win_viewport_margins={ + [2] = { + bottom = 0, + left = 0, + right = 0, + top = 0, + win = 1000 + } + }}) + feed('M') + screen:expect({ + grid = [[ + ## grid 1 + [2:-----------------------------------------------------]|*12 + {11:[No Name] [+] }| + [3:-----------------------------------------------------]| + ## grid 2 + line10 | + line11 | + line12 | + line13 | + line14 | + {23:^line15 }| + line16 | + line17 | + line18 | + line19 | + line20 | + | + ## grid 3 + | + ]], win_viewport={ + [2] = {win = 1000, topline = 9, botline = 21, curline = 14, curcol = 0, linecount = 21, sum_scroll_delta = 9}; + }, win_viewport_margins={ + [2] = { + bottom = 0, + left = 0, + right = 0, + top = 0, + win = 1000 + } + }}) + feed('k') + screen:expect({ + grid = [[ + ## grid 1 + [2:-----------------------------------------------------]|*12 + {11:[No Name] [+] }| + [3:-----------------------------------------------------]| + ## grid 2 + line9 | + line10 | + line11 | + line12 | + line13 | + {23:^line14 }| + line15 | + line16 | + line17 | + line18 | + line19 | + line20 | + ## grid 3 + | + ]], win_viewport={ + [2] = {win = 1000, topline = 8, botline = 21, curline = 13, curcol = 0, linecount = 21, sum_scroll_delta = 8}; + }, win_viewport_margins={ + [2] = { + bottom = 0, + left = 0, + right = 0, + top = 0, + win = 1000 + } + }}) + end) + end) end) -- cgit From cc300e553b458e08c4b1d4be117ee51a289cbdee Mon Sep 17 00:00:00 2001 From: glepnir Date: Thu, 3 Oct 2024 17:58:15 +0800 Subject: vim-patch:9.1.0756: missing change from patch v9.1.0754 (#30636) Problem: missing change from patch v9.1.0754 Solution: use correct width for the actual item in pum_redraw() (glepnir) closes: vim/vim#15786 https://github.com/vim/vim/commit/a6d9e3c4e07f73f6523699961d8b7b54bdb80cf6 --- test/functional/ui/popupmenu_spec.lua | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'test/functional') diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index e2f7e31c6c..f84362ede8 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -5077,6 +5077,17 @@ describe('builtin popupmenu', function() \ { 'word': '你好', 'kind': 'C', 'menu': '中文' }, \]} endfunc + + func Omni_long(findstart, base) + if a:findstart + return col(".") + endif + return { + \ 'words': [ + \ { 'word': 'loooong_foo', 'kind': 'S', 'menu': 'menu' }, + \ { 'word': 'loooong_bar', 'kind': 'T', 'menu': 'menu' }, + \]} + endfunc set omnifunc=Omni_test ]]) -- T1 @@ -5162,6 +5173,20 @@ describe('builtin popupmenu', function() {1:~ }|*10 {2:-- }{5:match 1 of 3} | ]]) + feed('') + + -- Test_pum_completeitemalign_07 + command('set cia=menu,kind,abbr columns=12 cmdheight=2 omnifunc=Omni_long') + feed('S') + screen:expect([[ + loooong_foo^ | + {s:menu S loooo}| + {n:menu T loooo}| + {1:~ }|*10 + | + {2:--} | + ]]) + feed('') end) end end -- cgit From 385fbfb3e739b457027b469782678f86eefdf7fc Mon Sep 17 00:00:00 2001 From: James Trew <66286082+jamestrew@users.noreply.github.com> Date: Thu, 3 Oct 2024 10:45:51 +0000 Subject: docs: improve luacats support #30580 Some composite/compound types even as basic as `(string|number)[]` are not currently supported by the luacats LPEG grammar used by gen_vimdoc. It would be parsed & rendered as just `string|number`. Changeset adds better support for these types. --- test/functional/script/luacats_grammar_spec.lua | 118 ++++++++++++++++++++++++ 1 file changed, 118 insertions(+) (limited to 'test/functional') diff --git a/test/functional/script/luacats_grammar_spec.lua b/test/functional/script/luacats_grammar_spec.lua index 9c6417f7bf..8bc55879d4 100644 --- a/test/functional/script/luacats_grammar_spec.lua +++ b/test/functional/script/luacats_grammar_spec.lua @@ -166,4 +166,122 @@ describe('luacats grammar', function() name = 'type', type = '[number,string,"good"|"bad"]', }) + + test('@class vim.diagnostic.JumpOpts', { + kind = 'class', + name = 'vim.diagnostic.JumpOpts', + }) + + test('@class vim.diagnostic.JumpOpts : vim.diagnostic.GetOpts', { + kind = 'class', + name = 'vim.diagnostic.JumpOpts', + parent = 'vim.diagnostic.GetOpts', + }) + + test('@param opt? { cmd?: string[] } Options', { + kind = 'param', + name = 'opt?', + type = '{ cmd?: string[] }', + desc = 'Options', + }) + + ---@type [string, string?][] + local test_cases = { + { 'foo' }, + { 'foo ', 'foo' }, -- trims whitespace + { 'true' }, + { 'vim.type' }, + { 'vim-type' }, + { 'vim_type' }, + { 'foo.bar-baz_baz' }, + { '`ABC`' }, + { '42' }, + { '-42' }, + { '(foo)', 'foo' }, -- removes unnecessary parens + { 'true?' }, + { '(true)?' }, + { 'string[]' }, + { 'string|number' }, + { '(string)[]' }, + { '(string|number)[]' }, + { 'coalesce??', 'coalesce?' }, -- removes unnecessary ? + { 'number?|string' }, + { "'foo'|'bar'|'baz'" }, + { '"foo"|"bar"|"baz"' }, + { '(number)?|string' }, -- + { 'number[]|string' }, + { 'string[]?' }, + { 'foo?[]' }, + { 'vim.type?|string? ', 'vim.type?|string?' }, + { 'number[][]' }, + { 'number[][][]' }, + { 'number[][]?' }, + { 'string|integer[][]?' }, + + -- tuples + { '[string]' }, + { '[1]' }, + { '[string, number]' }, + { '[string, number]?' }, + { '[string, number][]' }, + { '[string, number]|string' }, + { '[string|number, number?]' }, + { 'string|[string, number]' }, + { '(true)?|[foo]' }, + { '[fun(a: string):boolean]' }, + + -- dict + { '{[string]:string}' }, + { '{ [ string ] : string }' }, + { '{ [ string|any ] : string }' }, + { '{[string]: string, [number]: boolean}' }, + + -- key-value table + { 'table' }, + { 'table' }, + { 'string|table|boolean' }, + { 'string|table|(boolean)' }, + + -- table literal + { '{foo: number}' }, + { '{foo: string, bar: [number, boolean]?}' }, + { 'boolean|{reverse?:boolean}' }, + { '{ cmd?: string[] }' }, + + -- function + { 'fun(a: string, b:foo|bar): string' }, + { 'fun(a?: string): string' }, + { 'fun(a?: string): number?,string?' }, + { '(fun(a: string, b:foo|bar): string)?' }, + { 'fun(a: string, b:foo|bar): string, string' }, + { 'fun(a: string, b:foo|bar)' }, + { 'fun(_, foo, bar): string' }, + { 'fun(...): number' }, + { 'fun( ... ): number' }, + { 'fun(...:number): number' }, + { 'fun( ... : number): number' }, + + -- generics + { 'elem_or_list' }, + { + 'elem_or_list', + nil, + }, + } + + for _, tc in ipairs(test_cases) do + local ty, exp_ty = tc[1], tc[2] + if exp_ty == nil then + exp_ty = ty + end + + local var, desc = 'x', 'some desc' + local param = string.format('@param %s %s %s', var, ty, desc) + test(param, { + kind = 'param', + name = var, + type = exp_ty, + desc = desc, + }) + end end) -- cgit From b45c50f3140e7ece593f2126840900f5cc3d39ea Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Fri, 4 Oct 2024 02:13:31 -0700 Subject: docs: render `@since` versions, 0 means experimental #30649 An implication of this current approach is that `NVIM_API_LEVEL` should be bumped when a new Lua function is added. TODO(future): add a lint check which requires `@since` on all new functions. ref #25416 --- test/functional/script/text_utils_spec.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'test/functional') diff --git a/test/functional/script/text_utils_spec.lua b/test/functional/script/text_utils_spec.lua index 176c2ef816..74098b9287 100644 --- a/test/functional/script/text_utils_spec.lua +++ b/test/functional/script/text_utils_spec.lua @@ -11,8 +11,8 @@ local function md_to_vimdoc(text, start_indent, indent, text_width) start_indent = start_indent or 0 indent = indent or 0 text_width = text_width or 70 - local text_utils = require('scripts/text_utils') - return text_utils.md_to_vimdoc(table.concat(text, '\n'), start_indent, indent, text_width) + local util = require('scripts/util') + return util.md_to_vimdoc(table.concat(text, '\n'), start_indent, indent, text_width) ]], text, start_indent, -- cgit From 86c5c8724bd85154c4e94474d1d9a0b01e296028 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 4 Oct 2024 21:31:28 +0800 Subject: fix(mouse): indicate X1 and X2 button clicks on statusline (#30655) --- test/functional/ui/statusline_spec.lua | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'test/functional') diff --git a/test/functional/ui/statusline_spec.lua b/test/functional/ui/statusline_spec.lua index 3087a0cde1..937e709d66 100644 --- a/test/functional/ui/statusline_spec.lua +++ b/test/functional/ui/statusline_spec.lua @@ -63,6 +63,22 @@ for _, model in ipairs(mousemodels) do eq('0 3 r', eval('g:testvar')) api.nvim_input_mouse('right', 'press', '', 0, 6, 28) eq('0 4 r', eval('g:testvar')) + api.nvim_input_mouse('x1', 'press', '', 0, 6, 17) + eq('0 1 x1', eval('g:testvar')) + api.nvim_input_mouse('x1', 'press', '', 0, 6, 17) + eq('0 2 x1', eval('g:testvar')) + api.nvim_input_mouse('x1', 'press', '', 0, 6, 17) + eq('0 3 x1', eval('g:testvar')) + api.nvim_input_mouse('x1', 'press', '', 0, 6, 17) + eq('0 4 x1', eval('g:testvar')) + api.nvim_input_mouse('x2', 'press', '', 0, 6, 28) + eq('0 1 x2', eval('g:testvar')) + api.nvim_input_mouse('x2', 'press', '', 0, 6, 28) + eq('0 2 x2', eval('g:testvar')) + api.nvim_input_mouse('x2', 'press', '', 0, 6, 28) + eq('0 3 x2', eval('g:testvar')) + api.nvim_input_mouse('x2', 'press', '', 0, 6, 28) + eq('0 4 x2', eval('g:testvar')) end) it('works with control characters and highlight', function() -- cgit From d5ae5c84e94a2b15374ee0c7e2f4444c161a8a63 Mon Sep 17 00:00:00 2001 From: Jongwook Choi Date: Fri, 4 Oct 2024 09:48:31 -0400 Subject: feat(lua): completion for vim.fn, vim.v, vim.o #30472 Problem: Lua accessors for - global, local, and special variables (`vim.{g,t,w,b,v}.*`), and - options (`vim.{o,bo,wo,opt,opt_local,opt_global}.*`), do not have command-line completion, unlike their vimscript counterparts (e.g., `g:`, `b:`, `:set`, `:setlocal`, `:call `, etc.). Completion for vimscript functions (`vim.fn.*`) is incomplete and does not list all the available functions. Solution: Implement completion for vimscript function, variable and option accessors in `vim._expand_pat` through: - `getcompletion()` for variable and vimscript function accessors, and - `nvim_get_all_options_info()` for option accessors. Note/Remark: - Short names for options are yet to be implemented. - Completions for accessors with handles (e.g. `vim.b[0]`, `vim.wo[0]`) are also yet to be implemented, and are left as future work, which involves some refactoring of options. - For performance reasons, we may want to introduce caching for completing options, but this is not considered at this time since the number of the available options is not very big (only ~350) and Lua completion for option accessors appears to be pretty fast. - Can we have a more "general" framework for customizing completions? In the future, we may want to improve the implementation by moving the core logic for generating completion candidates to each accessor (or its metatable) or through some central interface, rather than writing all the accessor-specific completion implementations in a single function: `vim._expand_pat`. --- .../lua/command_line_completion_spec.lua | 171 ++++++++++++++++++++- 1 file changed, 169 insertions(+), 2 deletions(-) (limited to 'test/functional') diff --git a/test/functional/lua/command_line_completion_spec.lua b/test/functional/lua/command_line_completion_spec.lua index 2ba432133b..f8786a45bb 100644 --- a/test/functional/lua/command_line_completion_spec.lua +++ b/test/functional/lua/command_line_completion_spec.lua @@ -5,12 +5,14 @@ local clear = n.clear local eq = t.eq local exec_lua = n.exec_lua +--- @return { [1]: string[], [2]: integer } local get_completions = function(input, env) - return exec_lua('return {vim._expand_pat(...)}', input, env) + return exec_lua('return { vim._expand_pat(...) }', input, env) end +--- @return { [1]: string[], [2]: integer } local get_compl_parts = function(parts) - return exec_lua('return {vim._expand_pat_get_parts(...)}', parts) + return exec_lua('return { vim._expand_pat_get_parts(...) }', parts) end before_each(clear) @@ -123,6 +125,171 @@ describe('nlua_expand_pat', function() ) end) + describe('should complete vim.fn', function() + it('correctly works for simple completion', function() + local actual = get_completions('vim.fn.did') + local expected = { + { 'did_filetype' }, + #'vim.fn.', + } + eq(expected, actual) + end) + it('should not suggest items with #', function() + exec_lua [[ + -- ensure remote#host#... functions exist + vim.cmd [=[ + runtime! autoload/remote/host.vim + ]=] + -- make a dummy call to ensure vim.fn contains an entry: remote#host#... + vim.fn['remote#host#IsRunning']('python3') + ]] + local actual = get_completions('vim.fn.remo') + local expected = { + { 'remove' }, -- there should be no completion "remote#host#..." + #'vim.fn.', + } + eq(expected, actual) + end) + end) + + describe('should complete for variable accessors for', function() + it('vim.v', function() + local actual = get_completions('vim.v.t_') + local expected = { + { 't_blob', 't_bool', 't_dict', 't_float', 't_func', 't_list', 't_number', 't_string' }, + #'vim.v.', + } + eq(expected, actual) + end) + + it('vim.g', function() + exec_lua [[ + vim.cmd [=[ + let g:nlua_foo = 'completion' + let g:nlua_foo_bar = 'completion' + let g:nlua_foo#bar = 'nocompletion' " should be excluded from lua completion + ]=] + ]] + local actual = get_completions('vim.g.nlua') + local expected = { + { 'nlua_foo', 'nlua_foo_bar' }, + #'vim.g.', + } + eq(expected, actual) + end) + + it('vim.b', function() + exec_lua [[ + vim.b.nlua_foo_buf = 'bar' + vim.b.some_other_vars = 'bar' + ]] + local actual = get_completions('vim.b.nlua') + local expected = { + { 'nlua_foo_buf' }, + #'vim.b.', + } + eq(expected, actual) + end) + + it('vim.w', function() + exec_lua [[ + vim.w.nlua_win_var = 42 + ]] + local actual = get_completions('vim.w.nlua') + local expected = { + { 'nlua_win_var' }, + #'vim.w.', + } + eq(expected, actual) + end) + + it('vim.t', function() + exec_lua [[ + vim.t.nlua_tab_var = 42 + ]] + local actual = get_completions('vim.t.') + local expected = { + { 'nlua_tab_var' }, + #'vim.t.', + } + eq(expected, actual) + end) + end) + + describe('should complete for option accessors for', function() + -- for { vim.o, vim.go, vim.opt, vim.opt_local, vim.opt_global } + local test_opt = function(accessor) + do + local actual = get_completions(accessor .. '.file') + local expected = { + 'fileencoding', + 'fileencodings', + 'fileformat', + 'fileformats', + 'fileignorecase', + 'filetype', + } + eq({ expected, #accessor + 1 }, actual, accessor .. '.file') + end + do + local actual = get_completions(accessor .. '.winh') + local expected = { + 'winheight', + 'winhighlight', + } + eq({ expected, #accessor + 1 }, actual, accessor .. '.winh') + end + end + + test_opt('vim.o') + test_opt('vim.go') + test_opt('vim.opt') + test_opt('vim.opt_local') + test_opt('vim.opt_global') + + it('vim.o, suggesting all the known options', function() + local completions = get_completions('vim.o.')[1] ---@type string[] + eq( + exec_lua [[ + return vim.tbl_count(vim.api.nvim_get_all_options_info()) + ]], + #completions + ) + end) + + it('vim.bo', function() + do + local actual = get_completions('vim.bo.file') + local compls = { + -- should contain buffer options only + 'fileencoding', + 'fileformat', + 'filetype', + } + eq({ compls, #'vim.bo.' }, actual) + end + do + local actual = get_completions('vim.bo.winh') + local compls = {} + eq({ compls, #'vim.bo.' }, actual) + end + end) + + it('vim.wo', function() + do + local actual = get_completions('vim.wo.file') + local compls = {} + eq({ compls, #'vim.wo.' }, actual) + end + do + local actual = get_completions('vim.wo.winh') + -- should contain window options only + local compls = { 'winhighlight' } + eq({ compls, #'vim.wo.' }, actual) + end + end) + end) + it('should return everything if the input is of length 0', function() eq({ { 'other', 'vim' }, 0 }, get_completions('', { vim = true, other = true })) end) -- cgit From 00d1078ede9e0f03dd5eecbc9599d39c913ab953 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Sat, 5 Oct 2024 19:03:11 +0200 Subject: ci: bump macos runner version to macos-15 --- test/functional/lua/watch_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/lua/watch_spec.lua b/test/functional/lua/watch_spec.lua index 0c575900d3..ad16df8a7c 100644 --- a/test/functional/lua/watch_spec.lua +++ b/test/functional/lua/watch_spec.lua @@ -92,7 +92,7 @@ describe('vim._watch', function() skip(is_os('bsd'), 'Stopped working on bsd after 3ca967387c49c754561c3b11a574797504d40f38') elseif watchfunc == 'watchdirs' and is_os('mac') then -- Bump this (or fix the bug) if CI continues to fail in future versions of macos CI. - skip(is_ci() and vim.uv.os_uname().release == '23.6.0', 'weird failure for macOS arm 14 CI') + skip(is_ci() and vim.uv.os_uname().release == '24.0.0', 'weird failure for macOS arm 15 CI') else skip( is_os('bsd'), -- cgit From 27f3750817b188c9ababe94eade22c30d8819585 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 6 Oct 2024 12:20:40 -0700 Subject: feat(lsp): improve LSP doc hover rendering #30695 Problem: - Some servers like LuaLS add unwanted blank lines after multiline `@param` description. - List items do not wrap nicely. Solution: - When rendering the LSP doc hover, remove blank lines in each `@param` or `@return`. - But ensure exactly one empty line before each. - Set 'breakindent'. --- test/functional/plugin/lsp/utils_spec.lua | 57 ++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/plugin/lsp/utils_spec.lua b/test/functional/plugin/lsp/utils_spec.lua index c1f56f2722..64d58eeffd 100644 --- a/test/functional/plugin/lsp/utils_spec.lua +++ b/test/functional/plugin/lsp/utils_spec.lua @@ -83,7 +83,62 @@ describe('vim.lsp.util', function() end) end) - describe('normalize_markdown', function() + it('convert_input_to_markdown_lines', function() + local r = exec_lua(function() + local hover_data = { + kind = 'markdown', + value = '```lua\nfunction vim.api.nvim_buf_attach(buffer: integer, send_buffer: boolean, opts: vim.api.keyset.buf_attach)\n -> boolean\n```\n\n---\n\n Activates buffer-update events. Example:\n\n\n\n ```lua\n events = {}\n vim.api.nvim_buf_attach(0, false, {\n on_lines = function(...)\n table.insert(events, {...})\n end,\n })\n ```\n\n\n @see `nvim_buf_detach()`\n @see `api-buffer-updates-lua`\n@*param* `buffer` — Buffer handle, or 0 for current buffer\n\n\n\n@*param* `send_buffer` — True if whole buffer.\n Else the first notification will be `nvim_buf_changedtick_event`.\n\n\n@*param* `opts` — Optional parameters.\n\n - on_lines: Lua callback. Args:\n - the string "lines"\n - buffer handle\n - b:changedtick\n@*return* — False if foo;\n\n otherwise True.\n\n@see foo\n@see bar\n\n', + } + return vim.lsp.util.convert_input_to_markdown_lines(hover_data) + end) + local expected = { + '```lua', + 'function vim.api.nvim_buf_attach(buffer: integer, send_buffer: boolean, opts: vim.api.keyset.buf_attach)', + ' -> boolean', + '```', + '', + '---', + '', + ' Activates buffer-update events. Example:', + '', + '', + '', + ' ```lua', + ' events = {}', + ' vim.api.nvim_buf_attach(0, false, {', + ' on_lines = function(...)', + ' table.insert(events, {...})', + ' end,', + ' })', + ' ```', + '', + '', + ' @see `nvim_buf_detach()`', + ' @see `api-buffer-updates-lua`', + '', + -- For each @param/@return: #30695 + -- - Separate each by one empty line. + -- - Remove all other blank lines. + '@*param* `buffer` — Buffer handle, or 0 for current buffer', + '', + '@*param* `send_buffer` — True if whole buffer.', + ' Else the first notification will be `nvim_buf_changedtick_event`.', + '', + '@*param* `opts` — Optional parameters.', + ' - on_lines: Lua callback. Args:', + ' - the string "lines"', + ' - buffer handle', + ' - b:changedtick', + '', + '@*return* — False if foo;', + ' otherwise True.', + '@see foo', + '@see bar', + } + eq(expected, r) + end) + + describe('_normalize_markdown', function() it('collapses consecutive blank lines', function() local result = exec_lua(function() local lines = { -- cgit