test: support upvalues in exec_lua

This commit is contained in:
Lewis Russell
2024-08-11 09:27:48 +01:00
committed by Lewis Russell
parent a19e89022d
commit e5c174421d
34 changed files with 1740 additions and 1362 deletions

View File

@@ -7,6 +7,7 @@ local MsgpackRpcStream = require('test.client.msgpack_rpc_stream')
--- @field private _prepare uv.uv_prepare_t --- @field private _prepare uv.uv_prepare_t
--- @field private _timer uv.uv_timer_t --- @field private _timer uv.uv_timer_t
--- @field private _is_running boolean --- @field private _is_running boolean
--- @field exec_lua_setup boolean
local Session = {} local Session = {}
Session.__index = Session Session.__index = Session
if package.loaded['jit'] then if package.loaded['jit'] then

View File

@@ -282,19 +282,19 @@ describe('lua buffer event callbacks: on_lines', function()
end) end)
it('does not SEGFAULT when accessing window buffer info in on_detach #14998', function() 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) 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_win_set_buf(0, buf)
vim.api.nvim_buf_attach(buf, false, { vim.api.nvim_buf_attach(buf, false, {
on_detach = function(_, buf) on_detach = function(_, buf0)
vim.fn.tabpagebuflist() vim.fn.tabpagebuflist()
vim.fn.win_findbuf(buf) vim.fn.win_findbuf(buf0)
end end,
}) })
]] end
exec_lua(code) exec_lua(code)
command('q!') command('q!')

View File

@@ -1,7 +1,6 @@
local t = require('test.testutil') local t = require('test.testutil')
local n = require('test.functional.testnvim')() local n = require('test.functional.testnvim')()
local NIL = vim.NIL
local command = n.command local command = n.command
local clear = n.clear local clear = n.clear
local exec_lua = n.exec_lua local exec_lua = n.exec_lua
@@ -175,11 +174,11 @@ describe('vim.diagnostic', function()
eq(3, #result) eq(3, #result)
eq( eq(
2, 2,
exec_lua(function(result0) exec_lua(function()
return #vim.tbl_filter(function(d) return #vim.tbl_filter(function(d)
return d.bufnr == _G.diagnostic_bufnr return d.bufnr == _G.diagnostic_bufnr
end, result0)
end, result) end, result)
end)
) )
eq('Diagnostic #1', result[1].message) eq('Diagnostic #1', result[1].message)
end) end)
@@ -792,7 +791,7 @@ describe('vim.diagnostic', function()
--- @return table --- @return table
local function test_enable(legacy) 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) local other_bufnr = vim.api.nvim_create_buf(true, false)
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) 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) + _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
) )
if legacy0 then if legacy then
vim.diagnostic.disable(_G.diagnostic_bufnr, _G.diagnostic_ns) vim.diagnostic.disable(_G.diagnostic_bufnr, _G.diagnostic_ns)
else else
vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns }) 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) + _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
) )
if legacy0 then if legacy then
vim.diagnostic.disable(_G.diagnostic_bufnr, _G.other_ns) vim.diagnostic.disable(_G.diagnostic_bufnr, _G.other_ns)
else else
vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr, ns_id = _G.other_ns }) 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) + _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
) )
if legacy0 then if legacy then
vim.diagnostic.enable(_G.diagnostic_bufnr, _G.diagnostic_ns) vim.diagnostic.enable(_G.diagnostic_bufnr, _G.diagnostic_ns)
else else
vim.diagnostic.enable(true, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns }) 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) + _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
) )
if legacy0 then if legacy then
-- Should have no effect -- Should have no effect
vim.diagnostic.disable(other_bufnr, _G.other_ns) vim.diagnostic.disable(other_bufnr, _G.other_ns)
else else
@@ -878,9 +877,7 @@ describe('vim.diagnostic', function()
) )
return result return result
end, legacy) end)
return result
end end
it('with both buffer and namespace arguments', function() 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() it('will not cycle when wrap is off', function()
eq( eq(
vim.NIL, nil,
exec_lua(function() exec_lua(function()
vim.diagnostic.set(_G.diagnostic_ns, _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 #1', 1, 1, 1, 1),
@@ -1261,7 +1258,7 @@ describe('vim.diagnostic', function()
it('respects wrap parameter', function() it('respects wrap parameter', function()
eq( eq(
vim.NIL, nil,
exec_lua(function() exec_lua(function()
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
_G.make_error('Diagnostic #2', 4, 4, 4, 4), _G.make_error('Diagnostic #2', 4, 4, 4, 4),
@@ -1514,12 +1511,14 @@ describe('vim.diagnostic', function()
describe('count', function() describe('count', function()
it('returns actually present severity counts', function() it('returns actually present severity counts', function()
eq( eq(
exec_lua [[return { exec_lua(function()
return {
[vim.diagnostic.severity.ERROR] = 4, [vim.diagnostic.severity.ERROR] = 4,
[vim.diagnostic.severity.WARN] = 3, [vim.diagnostic.severity.WARN] = 3,
[vim.diagnostic.severity.INFO] = 2, [vim.diagnostic.severity.INFO] = 2,
[vim.diagnostic.severity.HINT] = 1, [vim.diagnostic.severity.HINT] = 1,
}]], }
end),
exec_lua(function() exec_lua(function()
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
_G.make_error('Error 1', 1, 1, 1, 2), _G.make_error('Error 1', 1, 1, 1, 2),
@@ -1537,10 +1536,12 @@ describe('vim.diagnostic', function()
end) end)
) )
eq( eq(
exec_lua [[return { exec_lua(function()
return {
[vim.diagnostic.severity.ERROR] = 2, [vim.diagnostic.severity.ERROR] = 2,
[vim.diagnostic.severity.INFO] = 1, [vim.diagnostic.severity.INFO] = 1,
}]], }
end),
exec_lua(function() exec_lua(function()
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
_G.make_error('Error 1', 1, 1, 1, 2), _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() it('returns only requested diagnostics count when severity range is supplied', function()
eq( eq(
exec_lua [[return { exec_lua(function()
return {
{ [vim.diagnostic.severity.ERROR] = 1, [vim.diagnostic.severity.WARN] = 1 }, { [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,
[vim.diagnostic.severity.HINT] = 1,
},
{ [vim.diagnostic.severity.WARN] = 1, [vim.diagnostic.severity.INFO] = 1 }, { [vim.diagnostic.severity.WARN] = 1, [vim.diagnostic.severity.INFO] = 1 },
}]], }
end),
exec_lua(function() exec_lua(function()
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
_G.make_error('Error 1', 1, 1, 1, 5), _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() it('returns only requested diagnostics when severities are supplied', function()
eq( eq(
exec_lua [[return { exec_lua(function()
return {
{ [vim.diagnostic.severity.WARN] = 1 }, { [vim.diagnostic.severity.WARN] = 1 },
{ [vim.diagnostic.severity.ERROR] = 1 }, { [vim.diagnostic.severity.ERROR] = 1 },
{ [vim.diagnostic.severity.WARN] = 1, [vim.diagnostic.severity.INFO] = 1 }, { [vim.diagnostic.severity.WARN] = 1, [vim.diagnostic.severity.INFO] = 1 },
}]], }
end),
exec_lua(function() exec_lua(function()
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
_G.make_error('Error 1', 1, 1, 1, 5), _G.make_error('Error 1', 1, 1, 1, 5),
@@ -1624,10 +1633,12 @@ describe('vim.diagnostic', function()
it('allows filtering by line', function() it('allows filtering by line', function()
eq( eq(
exec_lua [[return { exec_lua(function()
return {
[vim.diagnostic.severity.WARN] = 1, [vim.diagnostic.severity.WARN] = 1,
[vim.diagnostic.severity.INFO] = 1, [vim.diagnostic.severity.INFO] = 1,
}]], }
end),
exec_lua(function() exec_lua(function()
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
_G.make_error('Error 1', 1, 1, 1, 5), _G.make_error('Error 1', 1, 1, 1, 5),
@@ -1764,11 +1775,11 @@ describe('vim.diagnostic', function()
it('allows filtering by severity', function() it('allows filtering by severity', function()
local get_extmark_count_with_severity = function(min_severity) local get_extmark_count_with_severity = function(min_severity)
return exec_lua(function(min_severity0) return exec_lua(function()
vim.diagnostic.config({ vim.diagnostic.config({
underline = false, underline = false,
virtual_text = { 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) return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
end, min_severity) end)
end end
-- No messages with Error or higher -- No messages with Error or higher
@@ -2512,7 +2523,7 @@ describe('vim.diagnostic', function()
-- End position is exclusive -- End position is exclusive
eq( eq(
vim.NIL, nil,
exec_lua(function() exec_lua(function()
local diagnostics = { local diagnostics = {
_G.make_error('Syntax error', 1, 1, 2, 0), _G.make_error('Syntax error', 1, 1, 2, 0),
@@ -2606,7 +2617,7 @@ describe('vim.diagnostic', function()
-- End position is exclusive -- End position is exclusive
eq( eq(
vim.NIL, nil,
exec_lua(function() exec_lua(function()
local diagnostics = { local diagnostics = {
_G.make_error('Syntax error', 1, 1, 1, 3), _G.make_error('Syntax error', 1, 1, 1, 3),
@@ -2851,10 +2862,10 @@ describe('vim.diagnostic', function()
it('can filter by severity', function() it('can filter by severity', function()
local count_diagnostics_with_severity = function(min_severity, max_severity) 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({ vim.diagnostic.config({
float = { 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) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
vim.api.nvim_win_close(winnr, true) vim.api.nvim_win_close(winnr, true)
return #lines return #lines
end, min_severity, max_severity) end)
end end
eq(2, count_diagnostics_with_severity('ERROR')) eq(2, count_diagnostics_with_severity('ERROR'))
@@ -3060,7 +3071,7 @@ describe('vim.diagnostic', function()
-- open float failed non diagnostic lnum -- open float failed non diagnostic lnum
eq( eq(
vim.NIL, nil,
exec_lua(function() exec_lua(function()
vim.api.nvim_win_set_cursor(0, { 1, 0 }) vim.api.nvim_win_set_cursor(0, { 1, 0 })
local _, winnr = vim.diagnostic.open_float(0, { header = false }) local _, winnr = vim.diagnostic.open_float(0, { header = false })
@@ -3068,7 +3079,7 @@ describe('vim.diagnostic', function()
end) end)
) )
eq( eq(
vim.NIL, nil,
exec_lua(function() exec_lua(function()
vim.api.nvim_win_set_cursor(0, { 1, 0 }) vim.api.nvim_win_set_cursor(0, { 1, 0 })
local _, winnr = vim.diagnostic.open_float(0, { header = false, scope = 'cursor' }) local _, winnr = vim.diagnostic.open_float(0, { header = false, scope = 'cursor' })
@@ -3180,19 +3191,19 @@ describe('vim.diagnostic', function()
} }
eq( eq(
diagnostic, diagnostic,
exec_lua(function(msg0) exec_lua(function()
return vim.diagnostic.match( return vim.diagnostic.match(
msg0, msg,
'^(%w+): [^:]+:(%d+):(%d+):(.+)$', '^(%w+): [^:]+:(%d+):(%d+):(.+)$',
{ 'severity', 'lnum', 'col', 'message' } { 'severity', 'lnum', 'col', 'message' }
) )
end, msg) end)
) )
end) end)
it('returns nil if the pattern fails to match', function() it('returns nil if the pattern fails to match', function()
eq( eq(
NIL, nil,
exec_lua(function() exec_lua(function()
local msg = 'The answer to life, the universe, and everything is' local msg = 'The answer to life, the universe, and everything is'
return vim.diagnostic.match(msg, 'This definitely will not match', {}) return vim.diagnostic.match(msg, 'This definitely will not match', {})
@@ -3212,15 +3223,15 @@ describe('vim.diagnostic', function()
} }
eq( eq(
diagnostic, diagnostic,
exec_lua(function(msg0) exec_lua(function()
return vim.diagnostic.match( return vim.diagnostic.match(
msg0, msg,
'^[^:]+:(%d+):(.+)$', '^[^:]+:(%d+):(.+)$',
{ 'lnum', 'message' }, { 'lnum', 'message' },
nil, nil,
{ severity = vim.diagnostic.severity.INFO } { severity = vim.diagnostic.severity.INFO }
) )
end, msg) end)
) )
end) end)
@@ -3236,14 +3247,14 @@ describe('vim.diagnostic', function()
} }
eq( eq(
diagnostic, diagnostic,
exec_lua(function(msg0) exec_lua(function()
return vim.diagnostic.match( return vim.diagnostic.match(
msg0, msg,
'^(%d+):(%w+):(.+)$', '^(%d+):(%w+):(.+)$',
{ 'lnum', 'severity', 'message' }, { 'lnum', 'severity', 'message' },
{ FATAL = vim.diagnostic.severity.ERROR } { FATAL = vim.diagnostic.severity.ERROR }
) )
end, msg) end)
) )
end) end)
end) end)

View File

@@ -15,7 +15,7 @@ describe('ffi.cdef', function()
eq( eq(
12, 12,
exec_lua [=[ exec_lua(function()
local ffi = require('ffi') local ffi = require('ffi')
ffi.cdef [[ ffi.cdef [[
@@ -27,12 +27,12 @@ describe('ffi.cdef', function()
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( eq(
20, 20,
exec_lua [=[ exec_lua(function()
local ffi = require('ffi') local ffi = require('ffi')
ffi.cdef [[ ffi.cdef [[
@@ -71,19 +71,19 @@ describe('ffi.cdef', function()
nil, nil,
nil nil
) )
]=] end)
) )
-- Check that extern symbols are exported and accessible -- Check that extern symbols are exported and accessible
eq( eq(
true, true,
exec_lua [[ exec_lua(function()
local ffi = require('ffi') 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)
end) end)

View File

@@ -70,15 +70,15 @@ describe('vim.filetype', function()
eq( eq(
'dosini', 'dosini',
exec_lua(function(root0) exec_lua(function()
vim.filetype.add({ vim.filetype.add({
filename = { filename = {
['config'] = 'toml', ['config'] = 'toml',
[root0 .. '/.config/fun/config'] = 'dosini', [root .. '/.config/fun/config'] = 'dosini',
}, },
}) })
return vim.filetype.match({ filename = root0 .. '/.config/fun/config' }) return vim.filetype.match({ filename = root .. '/.config/fun/config' })
end, root) end)
) )
end) end)
@@ -123,7 +123,7 @@ describe('vim.filetype', function()
exec_lua(function() exec_lua(function()
-- Needs to be set so detect#sh doesn't fail -- Needs to be set so detect#sh doesn't fail
vim.g.ft_ignore_pat = '\\.\\(Z\\|gz\\|bz2\\|zip\\|tgz\\)$' 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)
) )
end) end)
@@ -152,7 +152,12 @@ describe('vim.filetype', function()
xml = { formatexpr = 'xmlformat#Format()' }, xml = { formatexpr = 'xmlformat#Format()' },
} do } do
for option, value in pairs(opts) 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 end
end) end)

View File

@@ -141,14 +141,14 @@ describe('vim.fs', function()
it('works', function() it('works', function()
eq( eq(
true, true,
exec_lua(function(dir, nvim) exec_lua(function()
for name, type in vim.fs.dir(dir) do for name, type in vim.fs.dir(nvim_dir) do
if name == nvim and type == 'file' then if name == nvim_prog_basename and type == 'file' then
return true return true
end end
end end
return false return false
end, nvim_dir, nvim_prog_basename) end)
) )
end) end)
@@ -167,22 +167,21 @@ describe('vim.fs', function()
io.open('testd/a/b/c/c4', 'w'):close() io.open('testd/a/b/c/c4', 'w'):close()
local function run(dir, depth, skip) local function run(dir, depth, skip)
local r = exec_lua(function(dir0, depth0, skip0) return exec_lua(function()
local r = {} local r = {}
local skip_f local skip_f
if skip0 then if skip then
skip_f = function(n0) skip_f = function(n0)
if vim.tbl_contains(skip0 or {}, n0) then if vim.tbl_contains(skip or {}, n0) then
return false return false
end end
end 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_ r[name] = type_
end end
return r return r
end, dir, depth, skip) end)
return r
end end
local exp = {} local exp = {}
@@ -252,9 +251,12 @@ describe('vim.fs', function()
opts = { path = test_source_path .. '/contrib', limit = math.huge } opts = { path = test_source_path .. '/contrib', limit = math.huge }
eq( eq(
exec_lua(function(dir) exec_lua(function()
return vim.tbl_map(vim.fs.basename, vim.fn.glob(dir .. '/contrib/*', false, true)) return vim.tbl_map(
end, test_source_path), vim.fs.basename,
vim.fn.glob(test_source_path .. '/contrib/*', false, true)
)
end),
vim.tbl_map( vim.tbl_map(
vim.fs.basename, vim.fs.basename,
vim.fs.find(function(_, d) vim.fs.find(function(_, d)
@@ -337,10 +339,10 @@ describe('vim.fs', function()
local xdg_config_home = test_build_dir .. '/.config' local xdg_config_home = test_build_dir .. '/.config'
eq( eq(
xdg_config_home .. '/nvim', xdg_config_home .. '/nvim',
exec_lua(function(...) exec_lua(function()
vim.env.XDG_CONFIG_HOME = ... vim.env.XDG_CONFIG_HOME = xdg_config_home
return vim.fs.normalize('$XDG_CONFIG_HOME/nvim') return vim.fs.normalize('$XDG_CONFIG_HOME/nvim')
end, xdg_config_home) end)
) )
end) end)

View File

@@ -2,16 +2,15 @@ local t = require('test.testutil')
local n = require('test.functional.testnvim')() local n = require('test.functional.testnvim')()
local eq = t.eq local eq = t.eq
local exec_lua = n.exec_lua
describe('glob', function() describe('glob', function()
before_each(n.clear) before_each(n.clear)
after_each(n.clear) after_each(n.clear)
local match = function(...) local match = function(pattern, str)
return exec_lua(function(pattern, str) return n.exec_lua(function()
return require('vim.glob').to_lpeg(pattern):match(str) ~= nil return require('vim.glob').to_lpeg(pattern):match(str) ~= nil
end, ...) end)
end end
describe('glob matching', function() describe('glob matching', function()

View File

@@ -31,10 +31,10 @@ describe('vim.highlight.range', function()
end) end)
it('works with charwise selection', function() it('works with charwise selection', function()
exec_lua([[ exec_lua(function()
local ns = vim.api.nvim_create_namespace('') local ns = vim.api.nvim_create_namespace('')
vim.highlight.range(0, ns, 'Search', { 1, 5 }, { 3, 10 }) vim.highlight.range(0, ns, 'Search', { 1, 5 }, { 3, 10 })
]]) end)
screen:expect([[ screen:expect([[
^asdfghjkl{1:$} | ^asdfghjkl{1:$} |
«口{10:=口»}{100:$} | «口{10:=口»}{100:$} |
@@ -46,10 +46,10 @@ describe('vim.highlight.range', function()
end) end)
it('works with linewise selection', function() it('works with linewise selection', function()
exec_lua([[ exec_lua(function()
local ns = vim.api.nvim_create_namespace('') local ns = vim.api.nvim_create_namespace('')
vim.highlight.range(0, ns, 'Search', { 0, 0 }, { 4, 0 }, { regtype = 'V' }) vim.highlight.range(0, ns, 'Search', { 0, 0 }, { 4, 0 }, { regtype = 'V' })
]]) end)
screen:expect([[ screen:expect([[
{10:^asdfghjkl}{100:$} | {10:^asdfghjkl}{100:$} |
{10:«口=口»}{100:$} | {10:«口=口»}{100:$} |
@@ -61,10 +61,10 @@ describe('vim.highlight.range', function()
end) end)
it('works with blockwise selection', function() it('works with blockwise selection', function()
exec_lua([[ exec_lua(function()
local ns = vim.api.nvim_create_namespace('') local ns = vim.api.nvim_create_namespace('')
vim.highlight.range(0, ns, 'Search', { 0, 0 }, { 4, 4 }, { regtype = '\022' }) vim.highlight.range(0, ns, 'Search', { 0, 0 }, { 4, 4 }, { regtype = '\022' })
]]) end)
screen:expect([[ screen:expect([[
{10:^asdf}ghjkl{1:$} | {10:^asdf}ghjkl{1:$} |
{10:«口=}口»{1:$} | {10:«口=}口»{1:$} |
@@ -76,10 +76,10 @@ describe('vim.highlight.range', function()
end) end)
it('works with blockwise selection with width', function() it('works with blockwise selection with width', function()
exec_lua([[ exec_lua(function()
local ns = vim.api.nvim_create_namespace('') local ns = vim.api.nvim_create_namespace('')
vim.highlight.range(0, ns, 'Search', { 0, 4 }, { 4, 7 }, { regtype = '\0226' }) vim.highlight.range(0, ns, 'Search', { 0, 4 }, { 4, 7 }, { regtype = '\0226' })
]]) end)
screen:expect([[ screen:expect([[
^asdf{10:ghjkl}{1:$} | ^asdf{10:ghjkl}{1:$} |
«口={10:口»}{1:$} | «口={10:口»}{1:$} |
@@ -91,11 +91,11 @@ describe('vim.highlight.range', function()
end) end)
it('can use -1 or v:maxcol to indicate end of line', function() 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('') local ns = vim.api.nvim_create_namespace('')
vim.highlight.range(0, ns, 'Search', { 0, 4 }, { 1, -1 }, {}) vim.highlight.range(0, ns, 'Search', { 0, 4 }, { 1, -1 }, {})
vim.highlight.range(0, ns, 'Search', { 2, 6 }, { 3, vim.v.maxcol }, {}) vim.highlight.range(0, ns, 'Search', { 2, 6 }, { 3, vim.v.maxcol }, {})
]]) end)
screen:expect([[ screen:expect([[
^asdf{10:ghjkl}{100:$} | ^asdf{10:ghjkl}{100:$} |
{10:«口=口»}{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() it('does not show errors even if buffer is wiped before timeout', function()
command('new') command('new')
exec_lua([[ exec_lua(function()
vim.highlight.on_yank({timeout = 10, on_macro = true, event = {operator = "y", regtype = "v"}}) vim.highlight.on_yank({
timeout = 10,
on_macro = true,
event = { operator = 'y', regtype = 'v' },
})
vim.cmd('bwipeout!') vim.cmd('bwipeout!')
]]) end)
vim.uv.sleep(10) vim.uv.sleep(10)
n.feed('<cr>') -- avoid hang if error message exists n.feed('<cr>') -- avoid hang if error message exists
eq('', eval('v:errmsg')) eq('', eval('v:errmsg'))
end) end)
it('does not close timer twice', function() it('does not close timer twice', function()
exec_lua([[ exec_lua(function()
vim.highlight.on_yank({timeout = 10, on_macro = true, event = {operator = "y"}}) vim.highlight.on_yank({ timeout = 10, on_macro = true, event = { operator = 'y' } })
vim.uv.sleep(10) vim.uv.sleep(10)
vim.schedule(function() 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) end)
]])
eq('', eval('v:errmsg')) eq('', eval('v:errmsg'))
end) end)
it('does not show in another window', function() it('does not show in another window', function()
command('vsplit') command('vsplit')
exec_lua([[ exec_lua(function()
vim.api.nvim_buf_set_mark(0,"[",1,1,{}) vim.api.nvim_buf_set_mark(0, '[', 1, 1, {})
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"}}) vim.highlight.on_yank({ timeout = math.huge, on_macro = true, event = { operator = 'y' } })
]]) end)
local ns = api.nvim_create_namespace('hlyank') local ns = api.nvim_create_namespace('hlyank')
local win = api.nvim_get_current_win() local win = api.nvim_get_current_win()
eq({ win }, api.nvim__ns_get(ns).wins) 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() it('removes old highlight if new one is created before old one times out', function()
command('vnew') command('vnew')
exec_lua([[ exec_lua(function()
vim.api.nvim_buf_set_mark(0,"[",1,1,{}) vim.api.nvim_buf_set_mark(0, '[', 1, 1, {})
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"}}) vim.highlight.on_yank({ timeout = math.huge, on_macro = true, event = { operator = 'y' } })
]]) end)
local ns = api.nvim_create_namespace('hlyank') local ns = api.nvim_create_namespace('hlyank')
eq(api.nvim_get_current_win(), api.nvim__ns_get(ns).wins[1]) eq(api.nvim_get_current_win(), api.nvim__ns_get(ns).wins[1])
command('wincmd w') command('wincmd w')
exec_lua([[ exec_lua(function()
vim.api.nvim_buf_set_mark(0,"[",1,1,{}) vim.api.nvim_buf_set_mark(0, '[', 1, 1, {})
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"}}) vim.highlight.on_yank({ timeout = math.huge, on_macro = true, event = { operator = 'y' } })
]]) end)
local win = api.nvim_get_current_win() local win = api.nvim_get_current_win()
eq({ win }, api.nvim__ns_get(ns).wins) eq({ win }, api.nvim__ns_get(ns).wins)
command('wincmd w') command('wincmd w')

View File

@@ -12,22 +12,21 @@ describe('vim.inspect_pos', function()
end) end)
it('it returns items', function() 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 buf = vim.api.nvim_create_buf(true, false)
local buf1 = 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 ns1 = vim.api.nvim_create_namespace('ns1')
local ns2 = vim.api.nvim_create_namespace("") local ns2 = vim.api.nvim_create_namespace('')
vim.api.nvim_set_current_buf(buf) 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.api.nvim_buf_set_lines(buf1, 0, -1, false, {"--commentline"}) vim.api.nvim_buf_set_lines(buf1, 0, -1, false, { '--commentline' })
vim.bo[buf].filetype = 'lua' vim.bo[buf].filetype = 'lua'
vim.bo[buf1].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, ns1, 0, 10, { hl_group = 'Normal' })
vim.api.nvim_buf_set_extmark(buf, ns2, 0, 10, { hl_group = "Normal" }) vim.api.nvim_buf_set_extmark(buf, ns2, 0, 10, { hl_group = 'Normal' })
vim.cmd("syntax on") vim.cmd('syntax on')
return {buf, vim.inspect_pos(0, 0, 10), vim.inspect_pos(buf1, 0, 10).syntax } return buf, vim.inspect_pos(0, 0, 10), vim.inspect_pos(buf1, 0, 10).syntax
]]) end)
local buf, items, other_buf_syntax = unpack(ret)
eq('', eval('v:errmsg')) eq('', eval('v:errmsg'))
eq({ eq({
@@ -95,14 +94,14 @@ describe('vim.show_pos', function()
end) end)
it('it does not error', function() it('it does not error', function()
exec_lua([[ exec_lua(function()
local buf = vim.api.nvim_create_buf(true, false) local buf = vim.api.nvim_create_buf(true, false)
vim.api.nvim_set_current_buf(buf) 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.bo[buf].filetype = 'lua'
vim.cmd("syntax on") vim.cmd('syntax on')
return { buf, vim.show_pos(0, 0, 10) } return { buf, vim.show_pos(0, 0, 10) }
]]) end)
eq('', eval('v:errmsg')) eq('', eval('v:errmsg'))
end) end)
end) end)

View File

@@ -12,10 +12,10 @@ describe('vim.loader', function()
it('can work in compatibility with --luamod-dev #27413', function() it('can work in compatibility with --luamod-dev #27413', function()
clear({ args = { '--luamod-dev' } }) clear({ args = { '--luamod-dev' } })
exec_lua [[ exec_lua(function()
vim.loader.enable() vim.loader.enable()
require("vim.fs") require('vim.fs')
-- try to load other vim submodules as well (Nvim Lua stdlib) -- try to load other vim submodules as well (Nvim Lua stdlib)
for key, _ in pairs(vim._submodules) do for key, _ in pairs(vim._submodules) do
@@ -28,28 +28,25 @@ describe('vim.loader', function()
('%s != require("%s"), %s != %s'):format(modname, modname, tostring(lhs), tostring(rhs)) ('%s != require("%s"), %s != %s'):format(modname, modname, tostring(lhs), tostring(rhs))
) )
end end
]] end)
end) end)
it('handles changing files (#23027)', function() it('handles changing files (#23027)', function()
exec_lua [[ exec_lua(function()
vim.loader.enable() vim.loader.enable()
]] end)
local tmp = t.tmpname() local tmp = t.tmpname()
command('edit ' .. tmp) command('edit ' .. tmp)
eq( eq(
1, 1,
exec_lua( exec_lua(function()
[[
vim.api.nvim_buf_set_lines(0, 0, -1, true, { '_G.TEST=1' }) vim.api.nvim_buf_set_lines(0, 0, -1, true, { '_G.TEST=1' })
vim.cmd.write() vim.cmd.write()
loadfile(...)() loadfile(tmp)()
return _G.TEST return _G.TEST
]], end)
tmp
)
) )
-- fs latency -- fs latency
@@ -57,15 +54,12 @@ describe('vim.loader', function()
eq( eq(
2, 2,
exec_lua( exec_lua(function()
[[
vim.api.nvim_buf_set_lines(0, 0, -1, true, { '_G.TEST=2' }) vim.api.nvim_buf_set_lines(0, 0, -1, true, { '_G.TEST=2' })
vim.cmd.write() vim.cmd.write()
loadfile(...)() loadfile(tmp)()
return _G.TEST return _G.TEST
]], end)
tmp
)
) )
end) end)

View File

@@ -25,20 +25,24 @@ describe('vim.uv', function()
it('timer', function() it('timer', function()
exec_lua('vim.api.nvim_set_var("coroutine_cnt", 0)', {}) exec_lua('vim.api.nvim_set_var("coroutine_cnt", 0)', {})
local code = [[ local code = function()
local touch = 0 local touch = 0
local function wait(ms) local function wait(ms)
local this = coroutine.running() local this = coroutine.running()
assert(this) assert(this)
local timer = vim.uv.new_timer() local timer = assert(vim.uv.new_timer())
timer:start(ms, 0, vim.schedule_wrap(function () timer:start(
ms,
0,
vim.schedule_wrap(function()
timer:close() timer:close()
touch = touch + 1 touch = touch + 1
coroutine.resume(this) coroutine.resume(this)
touch = touch + 1 touch = touch + 1
assert(touch == 3) assert(touch == 3)
vim.api.nvim_set_var("coroutine_cnt_1", touch) vim.api.nvim_set_var('coroutine_cnt_1', touch)
end)) end)
)
coroutine.yield() coroutine.yield()
touch = touch + 1 touch = touch + 1
return touch return touch
@@ -46,9 +50,9 @@ describe('vim.uv', function()
coroutine.wrap(function() coroutine.wrap(function()
local touched = wait(10) local touched = wait(10)
assert(touched == touch) assert(touched == touch)
vim.api.nvim_set_var("coroutine_cnt", touched) vim.api.nvim_set_var('coroutine_cnt', touched)
end)() end)()
]] end
eq(0, api.nvim_get_var('coroutine_cnt')) eq(0, api.nvim_get_var('coroutine_cnt'))
exec_lua(code) exec_lua(code)
@@ -99,15 +103,19 @@ describe('vim.uv', function()
-- callbacks can be scheduled to be executed in the main event loop -- callbacks can be scheduled to be executed in the main event loop
-- where the entire API is available -- where the entire API is available
exec_lua([[ exec_lua(function()
local timer = vim.uv.new_timer() local timer = assert(vim.uv.new_timer())
timer:start(20, 0, vim.schedule_wrap(function () timer:start(
20,
0,
vim.schedule_wrap(function()
_G.is_fast = vim.in_fast_event() _G.is_fast = vim.in_fast_event()
timer:close() timer:close()
vim.api.nvim_set_var("valid", true) vim.api.nvim_set_var('valid', true)
vim.api.nvim_command("echomsg 'howdy'") vim.api.nvim_command("echomsg 'howdy'")
end)) end)
]]) )
end)
screen:expect([[ screen:expect([[
^ | ^ |
@@ -118,15 +126,15 @@ describe('vim.uv', function()
eq(false, exec_lua('return _G.is_fast')) eq(false, exec_lua('return _G.is_fast'))
-- fast (not deferred) API functions are allowed to be called directly -- fast (not deferred) API functions are allowed to be called directly
exec_lua([[ exec_lua(function()
local timer = vim.uv.new_timer() local timer = assert(vim.uv.new_timer())
timer:start(20, 0, function() timer:start(20, 0, function()
timer:close() timer:close()
-- input is queued for processing after the callback returns -- 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() _G.mode = vim.api.nvim_get_mode()
end) end)
]]) end)
screen:expect([[ screen:expect([[
sneaky^ | sneaky^ |
{1:~ }|*8 {1:~ }|*8
@@ -134,15 +142,15 @@ describe('vim.uv', function()
]]) ]])
eq({ blocking = false, mode = 'n' }, exec_lua('return _G.mode')) eq({ blocking = false, mode = 'n' }, exec_lua('return _G.mode'))
exec_lua([[ exec_lua(function()
local timer = vim.uv.new_timer() local timer = assert(vim.uv.new_timer())
timer:start(20, 0, function() timer:start(20, 0, function()
_G.is_fast = vim.in_fast_event() _G.is_fast = vim.in_fast_event()
timer:close() timer:close()
_G.value = vim.fn.has("nvim-0.5") _G.value = vim.fn.has('nvim-0.5')
_G.unvalue = vim.fn.has("python3") _G.unvalue = vim.fn.has('python3')
end)
end) end)
]])
screen:expect({ any = [[{3:Vim:E5560: Vimscript function must not be called i}]] }) screen:expect({ any = [[{3:Vim:E5560: Vimscript function must not be called i}]] })
feed('<cr>') feed('<cr>')

View File

@@ -11,20 +11,20 @@ describe('lua vim.mpack', function()
it('encodes vim.NIL', function() it('encodes vim.NIL', function()
eq( eq(
{ true, true, true, true }, { true, true, true, true },
exec_lua [[ exec_lua(function()
local var = vim.mpack.decode(vim.mpack.encode({ 33, vim.NIL, 77 })) 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 } return { var[1] == 33, var[2] == vim.NIL, var[3] == 77, var[4] == nil }
]] end)
) )
end) end)
it('encodes vim.empty_dict()', function() it('encodes vim.empty_dict()', function()
eq( eq(
{ { {}, 'foo', {} }, true, false }, { { {}, 'foo', {} }, true, false },
exec_lua [[ exec_lua(function()
local var = vim.mpack.decode(vim.mpack.encode({{}, "foo", vim.empty_dict()})) local var = vim.mpack.decode(vim.mpack.encode({ {}, 'foo', vim.empty_dict() }))
return { var, vim.islist(var[1]), vim.islist(var[3]) } return { var, vim.islist(var[1]), vim.islist(var[3]) }
]] end)
) )
end) end)
end) end)

View File

@@ -134,14 +134,12 @@ describe('print', function()
eq('abc def', exec_capture('lua print("abc", "", "def")')) eq('abc def', exec_capture('lua print("abc", "", "def")'))
end) end)
it('defers printing in luv event handlers', function() it('defers printing in luv event handlers', function()
exec_lua( exec_lua(function(cmd)
[[
local cmd = ...
function test() function test()
local timer = vim.uv.new_timer() local timer = vim.uv.new_timer()
local done = false local done = false
timer:start(10, 0, function() timer:start(10, 0, function()
print("very fast") print('very fast')
timer:close() timer:close()
done = true done = true
end) end)
@@ -149,14 +147,12 @@ describe('print', function()
-- loop until we know for sure the callback has been executed -- loop until we know for sure the callback has been executed
while not done do while not done do
os.execute(cmd) os.execute(cmd)
vim.uv.run("nowait") -- fake os_breakcheck() vim.uv.run('nowait') -- fake os_breakcheck()
end end
print("very slow") print('very slow')
vim.api.nvim_command("sleep 1m") -- force deferred event processing vim.api.nvim_command('sleep 1m') -- force deferred event processing
end end
]], end, (is_os('win') and 'timeout 1') or 'sleep 0.1')
(is_os('win') and 'timeout 1') or 'sleep 0.1'
)
eq('very slow\nvery fast', exec_capture('lua test()')) eq('very slow\nvery fast', exec_capture('lua test()'))
end) end)

View File

@@ -6,10 +6,8 @@ local exec_lua = n.exec_lua
local eq = t.eq local eq = t.eq
local function system_sync(cmd, opts) local function system_sync(cmd, opts)
return exec_lua( return exec_lua(function()
[[ local obj = vim.system(cmd, opts)
local cmd, opts = ...
local obj = vim.system(...)
if opts.timeout then if opts.timeout then
-- Minor delay before calling wait() so the timeout uv timer can have a headstart over the -- 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') assert(not proc, 'process still exists')
return res return res
]], end)
cmd,
opts
)
end end
local function system_async(cmd, opts) local function system_async(cmd, opts)
return exec_lua( return exec_lua(function()
[[
local cmd, opts = ...
_G.done = false _G.done = false
local obj = vim.system(cmd, opts, function(obj) local obj = vim.system(cmd, opts, function(obj)
_G.done = true _G.done = true
@@ -51,10 +44,7 @@ local function system_async(cmd, opts)
assert(not proc, 'process still exists') assert(not proc, 'process still exists')
return _G.ret return _G.ret
]], end)
cmd,
opts
)
end end
describe('vim.system', function() describe('vim.system', function()
@@ -84,7 +74,7 @@ describe('vim.system', function()
end end
it('kill processes', function() it('kill processes', function()
exec_lua([[ exec_lua(function()
local signal local signal
local cmd = vim.system({ 'cat', '-' }, { stdin = true }, function(r) local cmd = vim.system({ 'cat', '-' }, { stdin = true }, function(r)
signal = r.signal signal = r.signal
@@ -104,19 +94,21 @@ describe('vim.system', function()
assert(not proc, 'process still exists') assert(not proc, 'process still exists')
assert(signal == 2) assert(signal == 2)
]]) end)
end) end)
it('SystemObj:wait() does not process non-fast events #27292', function() it('SystemObj:wait() does not process non-fast events #27292', function()
eq( eq(
false, false,
exec_lua([[ exec_lua(function()
_G.processed = false _G.processed = false
local cmd = vim.system({ 'sleep', '1' }) local cmd = vim.system({ 'sleep', '1' })
vim.schedule(function() _G.processed = true end) vim.schedule(function()
_G.processed = true
end)
cmd:wait() cmd:wait()
return _G.processed return _G.processed
]]) end)
) )
eq(true, exec_lua([[return _G.processed]])) eq(true, exec_lua([[return _G.processed]]))
end) end)

View File

@@ -7,7 +7,6 @@ local eq = t.eq
local pathsep = n.get_pathsep() local pathsep = n.get_pathsep()
local fn = n.fn local fn = n.fn
local api = n.api local api = n.api
local exec_lua = n.exec_lua
local testdir = 'Xtest-editorconfig' local testdir = 'Xtest-editorconfig'
@@ -227,12 +226,12 @@ But not this one
end) end)
it('does not operate on invalid buffers', function() 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') vim.cmd.edit('test.txt')
local bufnr = vim.api.nvim_get_current_buf() local bufnr = vim.api.nvim_get_current_buf()
vim.cmd.bwipeout(bufnr) vim.cmd.bwipeout(bufnr)
return { pcall(require('editorconfig').config, bufnr) } return { pcall(require('editorconfig').config, bufnr) }
]])) end))
eq(true, ok, err) eq(true, ok, err)
end) end)

View File

@@ -13,36 +13,34 @@ describe('vim.lsp.codelens', function()
it('on_codelens_stores_and_displays_lenses', function() it('on_codelens_stores_and_displays_lenses', function()
local fake_uri = 'file:///fake/uri' local fake_uri = 'file:///fake/uri'
local bufnr = exec_lua( local bufnr = exec_lua(function()
[[
fake_uri = ...
local bufnr = vim.uri_to_bufnr(fake_uri) local bufnr = vim.uri_to_bufnr(fake_uri)
local lines = { 'So', 'many', 'lines' } local lines = { 'So', 'many', 'lines' }
vim.fn.bufload(bufnr) vim.fn.bufload(bufnr)
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines) vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines)
return bufnr return bufnr
]], end)
fake_uri
)
exec_lua( exec_lua(function()
[[
local bufnr = ...
local lenses = { local lenses = {
{ {
range = { range = {
start = { line = 0, character = 0, }, start = { line = 0, character = 0 },
['end'] = { 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}) vim.lsp.codelens.on_codelens(
]], nil,
bufnr 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 = { local expected = {
{ {
range = { range = {
@@ -57,58 +55,54 @@ describe('vim.lsp.codelens', function()
} }
eq(expected, stored_lenses) eq(expected, stored_lenses)
local virtual_text_chunks = exec_lua( local virtual_text_chunks = exec_lua(function()
[[
local bufnr = ...
local ns = vim.lsp.codelens.__namespaces[1] local ns = vim.lsp.codelens.__namespaces[1]
local extmarks = vim.api.nvim_buf_get_extmarks(bufnr, ns, 0, -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 return vim.api.nvim_buf_get_extmark_by_id(bufnr, ns, extmarks[1][1], { details = true })[3].virt_text
]], end)
bufnr
)
eq({ [1] = { 'Lens1', 'LspCodeLens' } }, virtual_text_chunks) eq({ [1] = { 'Lens1', 'LspCodeLens' } }, virtual_text_chunks)
end) end)
it('can clear all lens', function() it('can clear all lens', function()
local fake_uri = 'file:///fake/uri' local fake_uri = 'file:///fake/uri'
local bufnr = exec_lua( local bufnr = exec_lua(function()
[[
fake_uri = ...
local bufnr = vim.uri_to_bufnr(fake_uri) local bufnr = vim.uri_to_bufnr(fake_uri)
local lines = { 'So', 'many', 'lines' } local lines = { 'So', 'many', 'lines' }
vim.fn.bufload(bufnr) vim.fn.bufload(bufnr)
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines) vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines)
return bufnr return bufnr
]], end)
fake_uri
)
exec_lua( exec_lua(function()
[[
local bufnr = ...
local lenses = { local lenses = {
{ {
range = { range = {
start = { line = 0, character = 0, }, start = { line = 0, character = 0 },
['end'] = { 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}) vim.lsp.codelens.on_codelens(
]], nil,
bufnr 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) eq(1, #stored_lenses)
exec_lua([[ exec_lua(function()
vim.lsp.codelens.clear() 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) eq(0, #stored_lenses)
end) end)
end) end)

View File

@@ -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 -- nvim_win_get_cursor returns 0 based column, line:find returns 1 based
local cursor_col = line:find('|') - 1 local cursor_col = line:find('|') - 1
line = line:gsub('|', '') line = line:gsub('|', '')
return exec_lua( return exec_lua(function(result)
[[
local line, cursor_col, lnum, result, server_boundary = ...
local line_to_cursor = line:sub(1, cursor_col) local line_to_cursor = line:sub(1, cursor_col)
local client_start_boundary = vim.fn.match(line_to_cursor, '\\k*$') 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, line,
lnum, lnum,
cursor_col, cursor_col,
@@ -36,19 +34,13 @@ local function complete(line, candidates, lnum, server_boundary)
client_start_boundary, client_start_boundary,
server_boundary, server_boundary,
result, result,
"utf-16" 'utf-16'
) )
return { return {
items = items, items = items,
server_start_boundary = new_server_boundary server_start_boundary = new_server_boundary,
} }
]], end, candidates)
line,
cursor_col,
lnum,
candidates,
server_boundary
)
end end
describe('vim.lsp.completion: item conversion', function() describe('vim.lsp.completion: item conversion', function()
@@ -483,13 +475,14 @@ describe('vim.lsp.completion: protocol', function()
before_each(function() before_each(function()
clear() clear()
exec_lua(create_server_definition) exec_lua(create_server_definition)
exec_lua([[ exec_lua(function()
_G.capture = {} _G.capture = {}
--- @diagnostic disable-next-line:duplicate-set-field
vim.fn.complete = function(col, matches) vim.fn.complete = function(col, matches)
_G.capture.col = col _G.capture.col = col
_G.capture.matches = matches _G.capture.matches = matches
end end
]]) end)
end) end)
after_each(clear) after_each(clear)
@@ -497,32 +490,34 @@ describe('vim.lsp.completion: protocol', function()
--- @param completion_result lsp.CompletionList --- @param completion_result lsp.CompletionList
--- @return integer --- @return integer
local function create_server(completion_result) local function create_server(completion_result)
return exec_lua( return exec_lua(function()
[[ local server = _G._create_server({
local result = ...
local server = _create_server({
capabilities = { capabilities = {
completionProvider = { completionProvider = {
triggerCharacters = { '.' } triggerCharacters = { '.' },
} },
}, },
handlers = { handlers = {
['textDocument/completion'] = function(_, _, callback) ['textDocument/completion'] = function(_, _, callback)
callback(nil, result) callback(nil, completion_result)
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) vim.api.nvim_win_set_buf(0, bufnr)
return vim.lsp.start({ name = 'dummy', cmd = server.cmd, on_attach = function(client, bufnr) return vim.lsp.start({
vim.lsp.completion.enable(true, client.id, bufnr, { convert = function(item) 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()', '') } return { abbr = item.label:gsub('%b()', '') }
end}) end,
end}) })
]], end,
completion_result })
) end)
end end
local function assert_matches(fn) local function assert_matches(fn)
@@ -533,14 +528,11 @@ describe('vim.lsp.completion: protocol', function()
--- @param pos [integer, integer] --- @param pos [integer, integer]
local function trigger_at_pos(pos) local function trigger_at_pos(pos)
exec_lua( exec_lua(function()
[[
local win = vim.api.nvim_get_current_win() 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() vim.lsp.completion.trigger()
]], end)
pos
)
retry(nil, nil, function() retry(nil, nil, function()
neq(nil, exec_lua('return _G.capture.col')) 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) local client_id = create_server(completion_list)
exec_lua( exec_lua(function()
[[
_G.called = false _G.called = false
local client = vim.lsp.get_client_by_id(...) local client = assert(vim.lsp.get_client_by_id(client_id))
client.commands.dummy = function() client.commands.dummy = function()
_G.called = true _G.called = true
end end
]], end)
client_id
)
feed('ih') feed('ih')
trigger_at_pos({ 1, 1 }) trigger_at_pos({ 1, 1 })
exec_lua( local item = completion_list.items[1]
[[ exec_lua(function()
local client_id, item = ...
vim.v.completed_item = { vim.v.completed_item = {
user_data = { user_data = {
nvim = { nvim = {
lsp = { lsp = {
client_id = client_id, client_id = client_id,
completion_item = item completion_item = item,
},
},
},
} }
} end)
}
}
]],
client_id,
completion_list.items[1]
)
feed('<C-x><C-o><C-y>') feed('<C-x><C-o><C-y>')

View File

@@ -11,7 +11,9 @@ local neq = t.neq
local create_server_definition = t_lsp.create_server_definition local create_server_definition = t_lsp.create_server_definition
describe('vim.lsp.diagnostic', function() 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() before_each(function()
clear { env = { clear { env = {
@@ -19,79 +21,98 @@ describe('vim.lsp.diagnostic', function()
VIMRUNTIME = os.getenv 'VIMRUNTIME', VIMRUNTIME = os.getenv 'VIMRUNTIME',
} } } }
exec_lua [[ exec_lua(function()
require('vim.lsp') 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 } } return { start = { line = x1, character = y1 }, ['end'] = { line = x2, character = y2 } }
end end
make_error = function(msg, x1, y1, x2, y2) _G.make_error = function(msg, x1, y1, x2, y2)
return { return {
range = make_range(x1, y1, x2, y2), range = _G.make_range(x1, y1, x2, y2),
message = msg, message = msg,
severity = 1, severity = 1,
} }
end end
make_warning = function(msg, x1, y1, x2, y2) _G.make_warning = function(msg, x1, y1, x2, y2)
return { return {
range = make_range(x1, y1, x2, y2), range = _G.make_range(x1, y1, x2, y2),
message = msg, message = msg,
severity = 2, severity = 2,
} }
end end
make_information = function(msg, x1, y1, x2, y2) _G.make_information = function(msg, x1, y1, x2, y2)
return { return {
range = make_range(x1, y1, x2, y2), range = _G.make_range(x1, y1, x2, y2),
message = msg, message = msg,
severity = 3, severity = 3,
} }
end end
function get_extmarks(bufnr, client_id) function _G.get_extmarks(bufnr, client_id0)
local namespace = vim.lsp.diagnostic.get_namespace(client_id) local namespace = vim.lsp.diagnostic.get_namespace(client_id0)
local ns = vim.diagnostic.get_namespace(namespace) local ns = vim.diagnostic.get_namespace(namespace)
local extmarks = {} local extmarks = {}
if ns.user_data.virt_text_ns then 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) table.insert(extmarks, e)
end end
end end
if ns.user_data.underline_ns then 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) table.insert(extmarks, e)
end end
end end
return extmarks return extmarks
end end
client_id = vim.lsp.start_client { client_id = assert(vim.lsp.start_client {
cmd_env = { cmd_env = {
NVIM_LUA_NOTRACK = "1"; NVIM_LUA_NOTRACK = '1',
}; },
cmd = { cmd = {
vim.v.progpath, '-es', '-u', 'NONE', '--headless' vim.v.progpath,
}; '-es',
offset_encoding = "utf-16"; '-u',
} 'NONE',
]] '--headless',
},
offset_encoding = 'utf-16',
})
end)
fake_uri = 'file:///fake/uri' fake_uri = 'file:///fake/uri'
exec_lua( exec_lua(function()
[[
fake_uri = ...
diagnostic_bufnr = vim.uri_to_bufnr(fake_uri) 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.fn.bufload(diagnostic_bufnr)
vim.api.nvim_buf_set_lines(diagnostic_bufnr, 0, 1, false, lines) vim.api.nvim_buf_set_lines(diagnostic_bufnr, 0, 1, false, lines)
vim.api.nvim_win_set_buf(0, diagnostic_bufnr) vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
return diagnostic_bufnr end)
]],
fake_uri
)
end) end)
after_each(function() after_each(function()
@@ -101,89 +122,73 @@ describe('vim.lsp.diagnostic', function()
describe('vim.lsp.diagnostic.on_publish_diagnostics', function() describe('vim.lsp.diagnostic.on_publish_diagnostics', function()
it('allows configuring the virtual text via vim.lsp.with', function() it('allows configuring the virtual text via vim.lsp.with', function()
local expected_spacing = 10 local expected_spacing = 10
local extmarks = exec_lua( local extmarks = exec_lua(function()
[[ _G.PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
virtual_text = { virtual_text = {
spacing = ..., spacing = expected_spacing,
}, },
}) })
PublishDiagnostics(nil, { _G.PublishDiagnostics(nil, {
uri = fake_uri, uri = fake_uri,
diagnostics = { diagnostics = {
make_error('Delayed Diagnostic', 4, 4, 4, 4), _G.make_error('Delayed Diagnostic', 4, 4, 4, 4),
} },
}, {client_id=client_id} }, { client_id = client_id })
)
return get_extmarks(diagnostic_bufnr, client_id) return _G.get_extmarks(diagnostic_bufnr, client_id)
]], end)
expected_spacing
)
local virt_text = extmarks[1][4].virt_text local spacing = extmarks[1][4].virt_text[1][1]
local spacing = virt_text[1][1]
eq(expected_spacing, #spacing) eq(expected_spacing, #spacing)
end) end)
it('allows configuring the virtual text via vim.lsp.with using a function', function() it('allows configuring the virtual text via vim.lsp.with using a function', function()
local expected_spacing = 10 local expected_spacing = 10
local extmarks = exec_lua( local extmarks = exec_lua(function()
[[ _G.PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
spacing = ...
PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
virtual_text = function() virtual_text = function()
return { return {
spacing = spacing, spacing = expected_spacing,
} }
end, end,
}) })
PublishDiagnostics(nil, { _G.PublishDiagnostics(nil, {
uri = fake_uri, uri = fake_uri,
diagnostics = { diagnostics = {
make_error('Delayed Diagnostic', 4, 4, 4, 4), _G.make_error('Delayed Diagnostic', 4, 4, 4, 4),
} },
}, {client_id=client_id} }, { client_id = client_id })
)
return get_extmarks(diagnostic_bufnr, client_id) return _G.get_extmarks(diagnostic_bufnr, client_id)
]], end)
expected_spacing
)
local virt_text = extmarks[1][4].virt_text local spacing = extmarks[1][4].virt_text[1][1]
local spacing = virt_text[1][1]
eq(expected_spacing, #spacing) eq(expected_spacing, #spacing)
end) end)
it('allows filtering via severity limit', function() it('allows filtering via severity limit', function()
local get_extmark_count_with_severity = function(severity_limit) local get_extmark_count_with_severity = function(severity_limit)
return exec_lua( return exec_lua(function()
[[ _G.PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
underline = false, underline = false,
virtual_text = { virtual_text = {
severity = { min = ... } severity = { min = severity_limit },
}, },
}) })
PublishDiagnostics(nil, { _G.PublishDiagnostics(nil, {
uri = fake_uri, uri = fake_uri,
diagnostics = { diagnostics = {
make_warning('Delayed Diagnostic', 4, 4, 4, 4), _G.make_warning('Delayed Diagnostic', 4, 4, 4, 4),
} },
}, {client_id=client_id} }, { client_id = client_id })
)
return #get_extmarks(diagnostic_bufnr, client_id) return #_G.get_extmarks(diagnostic_bufnr, client_id)
]], end, client_id, fake_uri, severity_limit)
severity_limit
)
end end
-- No messages with Error or higher -- No messages with Error or higher
@@ -196,246 +201,284 @@ describe('vim.lsp.diagnostic', function()
it('correctly handles UTF-16 offsets', function() it('correctly handles UTF-16 offsets', function()
local line = 'All 💼 and no 🎉 makes Jack a dull 👦' local line = 'All 💼 and no 🎉 makes Jack a dull 👦'
local result = exec_lua( local result = exec_lua(function()
[[
local line = ...
vim.api.nvim_buf_set_lines(diagnostic_bufnr, 0, -1, false, { line }) vim.api.nvim_buf_set_lines(diagnostic_bufnr, 0, -1, false, { line })
vim.lsp.diagnostic.on_publish_diagnostics(nil, { vim.lsp.diagnostic.on_publish_diagnostics(nil, {
uri = fake_uri, uri = fake_uri,
diagnostics = { diagnostics = {
make_error('UTF-16 Diagnostic', 0, 7, 0, 8), _G.make_error('UTF-16 Diagnostic', 0, 7, 0, 8),
} },
}, {client_id=client_id} }, { client_id = client_id })
)
local diags = vim.diagnostic.get(diagnostic_bufnr) local diags = vim.diagnostic.get(diagnostic_bufnr)
vim.lsp.stop_client(client_id) vim.lsp.stop_client(client_id)
vim.api.nvim_exec_autocmds('VimLeavePre', { modeline = false }) vim.api.nvim_exec_autocmds('VimLeavePre', { modeline = false })
return diags return diags
]], end)
line
)
eq(1, #result) eq(1, #result)
eq(exec_lua([[return vim.str_byteindex(..., 7, true)]], line), result[1].col) eq(
eq(exec_lua([[return vim.str_byteindex(..., 8, true)]], line), result[1].end_col) 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) end)
it('does not create buffer on empty diagnostics', function() it('does not create buffer on empty diagnostics', function()
local bufnr
-- No buffer is created without diagnostics -- No buffer is created without diagnostics
bufnr = exec_lua [[ eq(
-1,
exec_lua(function()
vim.lsp.diagnostic.on_publish_diagnostics(nil, { vim.lsp.diagnostic.on_publish_diagnostics(nil, {
uri = "file:///fake/uri2", uri = 'file:///fake/uri2',
diagnostics = {}, diagnostics = {},
}, { client_id = client_id }) }, { client_id = client_id })
return vim.fn.bufnr(vim.uri_to_fname("file:///fake/uri2")) return vim.fn.bufnr(vim.uri_to_fname('file:///fake/uri2'))
]] end)
eq(-1, bufnr) )
-- Create buffer on diagnostics -- Create buffer on diagnostics
bufnr = exec_lua [[ neq(
-1,
exec_lua(function()
vim.lsp.diagnostic.on_publish_diagnostics(nil, { vim.lsp.diagnostic.on_publish_diagnostics(nil, {
uri = "file:///fake/uri2", uri = 'file:///fake/uri2',
diagnostics = { diagnostics = {
make_error('Diagnostic', 0, 0, 0, 0), _G.make_error('Diagnostic', 0, 0, 0, 0),
}, },
}, { client_id = client_id }) }, { client_id = client_id })
return vim.fn.bufnr(vim.uri_to_fname("file:///fake/uri2")) return vim.fn.bufnr(vim.uri_to_fname('file:///fake/uri2'))
]] end)
neq(-1, bufnr) )
eq(1, exec_lua([[return #vim.diagnostic.get(...)]], bufnr)) eq(
1,
exec_lua(function()
return #vim.diagnostic.get(_G.bufnr)
end)
)
-- Clear diagnostics after buffer was created -- Clear diagnostics after buffer was created
bufnr = exec_lua [[ neq(
-1,
exec_lua(function()
vim.lsp.diagnostic.on_publish_diagnostics(nil, { vim.lsp.diagnostic.on_publish_diagnostics(nil, {
uri = "file:///fake/uri2", uri = 'file:///fake/uri2',
diagnostics = {}, diagnostics = {},
}, { client_id = client_id }) }, { client_id = client_id })
return vim.fn.bufnr(vim.uri_to_fname("file:///fake/uri2")) return vim.fn.bufnr(vim.uri_to_fname('file:///fake/uri2'))
]] end)
neq(-1, bufnr) )
eq(0, exec_lua([[return #vim.diagnostic.get(...)]], bufnr)) eq(
0,
exec_lua(function()
return #vim.diagnostic.get(_G.bufnr)
end)
)
end) end)
end) end)
describe('vim.lsp.diagnostic.on_diagnostic', function() describe('vim.lsp.diagnostic.on_diagnostic', function()
before_each(function() before_each(function()
exec_lua(create_server_definition) exec_lua(create_server_definition)
exec_lua([[ exec_lua(function()
server = _create_server({ _G.server = _G._create_server({
capabilities = { capabilities = {
diagnosticProvider = { diagnosticProvider = {},
} },
}
}) })
function get_extmarks(bufnr, client_id) function _G.get_extmarks(bufnr, client_id0)
local namespace = vim.lsp.diagnostic.get_namespace(client_id, true) local namespace = vim.lsp.diagnostic.get_namespace(client_id0, true)
local ns = vim.diagnostic.get_namespace(namespace) local ns = vim.diagnostic.get_namespace(namespace)
local extmarks = {} local extmarks = {}
if ns.user_data.virt_text_ns then 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) table.insert(extmarks, e)
end end
end end
if ns.user_data.underline_ns then 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) table.insert(extmarks, e)
end end
end end
return extmarks return extmarks
end end
client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) client_id = vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
]]) end)
end) end)
it('adds diagnostics to vim.diagnostics', function() it('adds diagnostics to vim.diagnostics', function()
local diags = exec_lua([[ local diags = exec_lua(function()
vim.lsp.diagnostic.on_diagnostic(nil, vim.lsp.diagnostic.on_diagnostic(nil, {
{
kind = 'full', kind = 'full',
items = { items = {
make_error('Pull Diagnostic', 4, 4, 4, 4), _G.make_error('Pull Diagnostic', 4, 4, 4, 4),
}
}, },
{ }, {
params = { params = {
textDocument = { uri = fake_uri }, textDocument = { uri = fake_uri },
}, },
uri = fake_uri, uri = fake_uri,
client_id = client_id, client_id = client_id,
}, }, {})
{}
)
return vim.diagnostic.get(diagnostic_bufnr) return vim.diagnostic.get(diagnostic_bufnr)
]]) end)
eq(1, #diags) eq(1, #diags)
eq('Pull Diagnostic', diags[1].message) eq('Pull Diagnostic', diags[1].message)
end) end)
it('severity defaults to error if missing', function() it('severity defaults to error if missing', function()
---@type vim.Diagnostic[] ---@type vim.Diagnostic[]
local diagnostics = exec_lua([[ local diagnostics = exec_lua(function()
vim.lsp.diagnostic.on_diagnostic(nil, vim.lsp.diagnostic.on_diagnostic(nil, {
{
kind = 'full', kind = 'full',
items = { items = {
{ {
range = make_range(4, 4, 4, 4), range = _G.make_range(4, 4, 4, 4),
message = "bad!", message = 'bad!',
}
}
}, },
{ },
}, {
params = { params = {
textDocument = { uri = fake_uri }, textDocument = { uri = fake_uri },
}, },
uri = fake_uri, uri = fake_uri,
client_id = client_id, client_id = client_id,
}, }, {})
{}
)
return vim.diagnostic.get(diagnostic_bufnr) return vim.diagnostic.get(diagnostic_bufnr)
]]) end)
eq(1, #diagnostics) eq(1, #diagnostics)
eq(1, diagnostics[1].severity) eq(1, diagnostics[1].severity)
end) end)
it('allows configuring the virtual text via vim.lsp.with', function() it('allows configuring the virtual text via vim.lsp.with', function()
local expected_spacing = 10 local expected_spacing = 10
local extmarks = exec_lua( local extmarks = exec_lua(function()
[[ _G.Diagnostic = vim.lsp.with(vim.lsp.diagnostic.on_diagnostic, {
Diagnostic = vim.lsp.with(vim.lsp.diagnostic.on_diagnostic, {
virtual_text = { virtual_text = {
spacing = ..., spacing = expected_spacing,
}, },
}) })
Diagnostic(nil, _G.Diagnostic(nil, {
{
kind = 'full', kind = 'full',
items = { items = {
make_error('Pull Diagnostic', 4, 4, 4, 4), _G.make_error('Pull Diagnostic', 4, 4, 4, 4),
}
}, },
{ }, {
params = { params = {
textDocument = { uri = fake_uri }, textDocument = { uri = fake_uri },
}, },
uri = fake_uri, uri = fake_uri,
client_id = client_id, client_id = client_id,
}, }, {})
{}
)
return get_extmarks(diagnostic_bufnr, client_id) return _G.get_extmarks(diagnostic_bufnr, client_id)
]], end)
expected_spacing
)
eq(2, #extmarks) eq(2, #extmarks)
eq(expected_spacing, #extmarks[1][4].virt_text[1][1]) eq(expected_spacing, #extmarks[1][4].virt_text[1][1])
end) end)
it('clears diagnostics when client detaches', function() it('clears diagnostics when client detaches', function()
exec_lua([[ exec_lua(function()
vim.lsp.diagnostic.on_diagnostic(nil, vim.lsp.diagnostic.on_diagnostic(nil, {
{
kind = 'full', kind = 'full',
items = { items = {
make_error('Pull Diagnostic', 4, 4, 4, 4), _G.make_error('Pull Diagnostic', 4, 4, 4, 4),
}
}, },
{ }, {
params = { params = {
textDocument = { uri = fake_uri }, textDocument = { uri = fake_uri },
}, },
uri = fake_uri, uri = fake_uri,
client_id = client_id, client_id = client_id,
}, }, {})
{} end)
eq(
1,
exec_lua(function()
return #vim.diagnostic.get(diagnostic_bufnr)
end)
) )
]])
local diags = exec_lua([[return vim.diagnostic.get(diagnostic_bufnr)]])
eq(1, #diags)
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(
eq(0, #diags) 0,
exec_lua(function()
return #vim.diagnostic.get(diagnostic_bufnr)
end)
)
end) end)
it('keeps diagnostics when one client detaches and others still are attached', function() it('keeps diagnostics when one client detaches and others still are attached', function()
exec_lua([[ local client_id2
client_id2 = vim.lsp.start({ name = 'dummy2', cmd = server.cmd }) exec_lua(function()
client_id2 = vim.lsp.start({ name = 'dummy2', cmd = _G.server.cmd })
vim.lsp.diagnostic.on_diagnostic(nil, vim.lsp.diagnostic.on_diagnostic(nil, {
{
kind = 'full', kind = 'full',
items = { items = {
make_error('Pull Diagnostic', 4, 4, 4, 4), _G.make_error('Pull Diagnostic', 4, 4, 4, 4),
}
}, },
{ }, {
params = { params = {
textDocument = { uri = fake_uri }, textDocument = { uri = fake_uri },
}, },
uri = fake_uri, uri = fake_uri,
client_id = client_id, client_id = client_id,
}, }, {})
{} end)
eq(
1,
exec_lua(function()
return #vim.diagnostic.get(diagnostic_bufnr)
end)
) )
]])
local diags = exec_lua([[return vim.diagnostic.get(diagnostic_bufnr)]])
eq(1, #diags)
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(
eq(1, #diags) 1,
exec_lua(function()
return #vim.diagnostic.get(diagnostic_bufnr)
end)
)
end) end)
end) end)
end) end)

View File

@@ -11,28 +11,31 @@ describe('lsp-handlers', function()
it('should return a table with the default keys', function() it('should return a table with the default keys', function()
eq( eq(
{ hello = 'world' }, { hello = 'world' },
exec_lua [[ exec_lua(function()
return vim.lsp._with_extend('test', { hello = 'world' }) return vim.lsp._with_extend('test', { hello = 'world' })
]] end)
) )
end) end)
it('should override with config keys', function() it('should override with config keys', function()
eq( eq(
{ hello = 'universe', other = true }, { hello = 'universe', other = true },
exec_lua [[ exec_lua(function()
return vim.lsp._with_extend('test', { other = true, hello = 'world' }, { hello = 'universe' }) return vim.lsp._with_extend(
]] 'test',
{ other = true, hello = 'world' },
{ hello = 'universe' }
)
end)
) )
end) end)
it('should not allow invalid keys', function() it('should not allow invalid keys', function()
matches( matches(
'.*Invalid option for `test`.*', '.*Invalid option for `test`.*',
pcall_err( pcall_err(exec_lua, function()
exec_lua, return vim.lsp._with_extend('test', { hello = 'world' }, { invalid = true })
"return vim.lsp._with_extend('test', { hello = 'world' }, { invalid = true })" end)
)
) )
end) end)
end) end)

View File

@@ -10,11 +10,9 @@ local feed = n.feed
before_each(function() before_each(function()
clear() clear()
exec_lua [[ exec_lua(function()
local evname = ...
local sync = require('vim.lsp.sync') local sync = require('vim.lsp.sync')
local events = {} local events = {}
local buffer_cache = {}
-- local format_line_ending = { -- local format_line_ending = {
-- ["unix"] = '\n', -- ["unix"] = '\n',
@@ -24,19 +22,25 @@ before_each(function()
-- local line_ending = format_line_ending[vim.api.nvim_get_option_value('fileformat', {})] -- local line_ending = format_line_ending[vim.api.nvim_get_option_value('fileformat', {})]
--- @diagnostic disable-next-line:duplicate-set-field
function test_register(bufnr, id, offset_encoding, line_ending) function _G.test_register(bufnr, id, offset_encoding, line_ending)
local curr_lines
local prev_lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, true) local prev_lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, true)
local function callback(_, bufnr, changedtick, firstline, lastline, new_lastline) local function callback(_, bufnr0, _changedtick, firstline, lastline, new_lastline)
if test_unreg == id then if _G.test_unreg == id then
return true return true
end 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( 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) table.insert(events, incremental_change)
prev_lines = curr_lines prev_lines = curr_lines
@@ -45,14 +49,16 @@ before_each(function()
vim.api.nvim_buf_attach(bufnr, false, opts) vim.api.nvim_buf_attach(bufnr, false, opts)
end end
function get_events() --- @diagnostic disable-next-line:duplicate-set-field
function _G.get_events()
local ret_events = events local ret_events = events
events = {} events = {}
return ret_events return ret_events
end end
]] end)
end) end)
--- @param edit_operations string[]
local function test_edit( local function test_edit(
prev_buffer, prev_buffer,
edit_operations, edit_operations,
@@ -64,13 +70,22 @@ local function test_edit(
line_ending = line_ending or '\n' line_ending = line_ending or '\n'
api.nvim_buf_set_lines(0, 0, -1, true, prev_buffer) 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 for _, edit in ipairs(edit_operations) do
feed(edit) feed(edit)
end end
eq(expected_text_changes, exec_lua('return get_events(...)')) eq(
exec_lua("test_unreg = 'test1'") expected_text_changes,
exec_lua(function()
return _G.get_events()
end)
)
exec_lua(function()
_G.test_unreg = 'test1'
end)
end end
describe('incremental synchronization', function() describe('incremental synchronization', function()

View File

@@ -57,16 +57,22 @@ int main() {
--- @type test.functional.ui.screen --- @type test.functional.ui.screen
local screen local screen
--- @type integer
local client_id
--- @type integer
local bufnr
before_each(function() before_each(function()
clear_notrace() clear_notrace()
screen = Screen.new(50, 9) screen = Screen.new(50, 9)
screen:attach() screen:attach()
bufnr = n.api.nvim_get_current_buf()
exec_lua(create_server_definition) exec_lua(create_server_definition)
exec_lua( client_id = exec_lua(function()
[[ _G.server = _G._create_server({
local response = ...
server = _create_server({
capabilities = { capabilities = {
inlayHintProvider = true, inlayHintProvider = true,
}, },
@@ -74,19 +80,16 @@ int main() {
['textDocument/inlayHint'] = function(_, _, callback) ['textDocument/inlayHint'] = function(_, _, callback)
callback(nil, vim.json.decode(response)) callback(nil, vim.json.decode(response))
end, end,
} },
}) })
bufnr = vim.api.nvim_get_current_buf() return vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
vim.api.nvim_win_set_buf(0, bufnr) end)
client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
]],
response
)
insert(text) 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 }) screen:expect({ grid = grid_with_inlay_hints })
end) end)
@@ -95,13 +98,15 @@ int main() {
end) end)
it('clears inlay hints when sole client detaches', function() 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 }) screen:expect({ grid = grid_without_inlay_hints, unchanged = true })
end) end)
it('does not clear inlay hints when one of several clients detaches', function() it('does not clear inlay hints when one of several clients detaches', function()
exec_lua([[ local client_id2 = exec_lua(function()
server2 = _create_server({ _G.server2 = _G._create_server({
capabilities = { capabilities = {
inlayHintProvider = true, inlayHintProvider = true,
}, },
@@ -109,13 +114,16 @@ int main() {
['textDocument/inlayHint'] = function(_, _, callback) ['textDocument/inlayHint'] = function(_, _, callback)
callback(nil, {}) callback(nil, {})
end, 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 }) 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 }) screen:expect({ grid = grid_with_inlay_hints, unchanged = true })
end) end)
@@ -123,61 +131,85 @@ int main() {
it('validation', function() it('validation', function()
t.matches( t.matches(
'enable: expected boolean, got table', '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( t.matches(
'enable: expected boolean, got number', '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( t.matches(
'filter: expected table, got number', '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) end)
describe('clears/applies inlay hints when passed false/true/nil', function() describe('clears/applies inlay hints when passed false/true/nil', function()
local bufnr2 --- @type integer
before_each(function() before_each(function()
exec_lua([[ bufnr2 = exec_lua(function()
bufnr2 = vim.api.nvim_create_buf(true, false) local bufnr2_0 = vim.api.nvim_create_buf(true, false)
vim.lsp.buf_attach_client(bufnr2, client_id) vim.lsp.buf_attach_client(bufnr2_0, client_id)
vim.api.nvim_win_set_buf(0, bufnr2) vim.api.nvim_win_set_buf(0, bufnr2_0)
]]) return bufnr2_0
end)
insert(text) insert(text)
exec_lua([[vim.lsp.inlay_hint.enable(true, { bufnr = bufnr2 })]]) exec_lua(function()
exec_lua([[vim.api.nvim_win_set_buf(0, bufnr)]]) vim.lsp.inlay_hint.enable(true, { bufnr = bufnr2 })
end)
n.api.nvim_win_set_buf(0, bufnr)
screen:expect({ grid = grid_with_inlay_hints }) screen:expect({ grid = grid_with_inlay_hints })
end) end)
it('for one single buffer', function() it('for one single buffer', function()
exec_lua([[ exec_lua(function()
vim.lsp.inlay_hint.enable(false, { bufnr = bufnr }) vim.lsp.inlay_hint.enable(false, { bufnr = bufnr })
vim.api.nvim_win_set_buf(0, bufnr2) vim.api.nvim_win_set_buf(0, bufnr2)
]]) end)
screen:expect({ grid = grid_with_inlay_hints, unchanged = true }) 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 }) 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 }) screen:expect({ grid = grid_with_inlay_hints, unchanged = true })
exec_lua( exec_lua(function()
[[vim.lsp.inlay_hint.enable(not vim.lsp.inlay_hint.is_enabled({ bufnr = bufnr }), { bufnr = bufnr })]] 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 }) 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 }) screen:expect({ grid = grid_with_inlay_hints, unchanged = true })
end) end)
it('for all buffers', function() 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 }) 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 }) 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 }) 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 }) screen:expect({ grid = grid_with_inlay_hints, unchanged = true })
end) end)
end) end)
@@ -198,10 +230,8 @@ int main() {
paddingRight = false, paddingRight = false,
} }
exec_lua( exec_lua(function()
[[ _G.server2 = _G._create_server({
local expected2 = ...
server2 = _create_server({
capabilities = { capabilities = {
inlayHintProvider = true, inlayHintProvider = true,
}, },
@@ -209,52 +239,63 @@ int main() {
['textDocument/inlayHint'] = function(_, _, callback) ['textDocument/inlayHint'] = function(_, _, callback)
callback(nil, { expected2 }) callback(nil, { expected2 })
end, 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 }) vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })
]], end)
expected2
)
--- @type vim.lsp.inlay_hint.get.ret --- @type vim.lsp.inlay_hint.get.ret
local res = exec_lua([[return vim.lsp.inlay_hint.get()]]) eq(
eq({ {
{ bufnr = 1, client_id = 1, inlay_hint = expected[1] }, { 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[2] },
{ bufnr = 1, client_id = 1, inlay_hint = expected[3] }, { bufnr = 1, client_id = 1, inlay_hint = expected[3] },
{ bufnr = 1, client_id = 2, inlay_hint = expected2 }, { bufnr = 1, client_id = 2, inlay_hint = expected2 },
}, res) },
exec_lua(function()
return vim.lsp.inlay_hint.get()
end)
)
--- @type vim.lsp.inlay_hint.get.ret eq(
res = exec_lua([[return vim.lsp.inlay_hint.get({ {
{ bufnr = 1, client_id = 2, inlay_hint = expected2 },
},
exec_lua(function()
return vim.lsp.inlay_hint.get({
range = { range = {
start = { line = 2, character = 10 }, start = { line = 2, character = 10 },
["end"] = { line = 2, character = 10 }, ['end'] = { line = 2, character = 10 },
}, },
})]]) })
eq({ end)
{ bufnr = 1, client_id = 2, inlay_hint = expected2 }, )
}, res)
--- @type vim.lsp.inlay_hint.get.ret eq(
res = exec_lua([[return vim.lsp.inlay_hint.get({ {
{ bufnr = 1, client_id = 1, inlay_hint = expected[2] },
{ bufnr = 1, client_id = 1, inlay_hint = expected[3] },
},
exec_lua(function()
return vim.lsp.inlay_hint.get({
bufnr = vim.api.nvim_get_current_buf(), bufnr = vim.api.nvim_get_current_buf(),
range = { range = {
start = { line = 4, character = 18 }, start = { line = 4, character = 18 },
["end"] = { line = 5, character = 17 }, ['end'] = { line = 5, character = 17 },
}, },
})]]) })
eq({ end)
{ bufnr = 1, client_id = 1, inlay_hint = expected[2] }, )
{ bufnr = 1, client_id = 1, inlay_hint = expected[3] },
}, res)
--- @type vim.lsp.inlay_hint.get.ret eq(
res = exec_lua([[return vim.lsp.inlay_hint.get({ {},
exec_lua(function()
return vim.lsp.inlay_hint.get({
bufnr = vim.api.nvim_get_current_buf() + 1, bufnr = vim.api.nvim_get_current_buf() + 1,
})]]) })
eq({}, res) end)
)
end) end)
end) end)
end) end)
@@ -288,16 +329,22 @@ test text
--- @type test.functional.ui.screen --- @type test.functional.ui.screen
local screen local screen
--- @type integer
local client_id
--- @type integer
local bufnr
before_each(function() before_each(function()
clear_notrace() clear_notrace()
screen = Screen.new(50, 3) screen = Screen.new(50, 3)
screen:attach() screen:attach()
exec_lua(create_server_definition) exec_lua(create_server_definition)
exec_lua( bufnr = n.api.nvim_get_current_buf()
[[ client_id = exec_lua(function()
local response = ... _G.server = _G._create_server({
server = _create_server({
capabilities = { capabilities = {
inlayHintProvider = true, inlayHintProvider = true,
}, },
@@ -305,23 +352,22 @@ test text
['textDocument/inlayHint'] = function(_, _, callback) ['textDocument/inlayHint'] = function(_, _, callback)
callback(nil, vim.json.decode(response)) callback(nil, vim.json.decode(response))
end, 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 }) return vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
]], end)
response
)
insert(text) insert(text)
end) end)
it('renders hints with same position in received order', function() it('renders hints with same position in received order', function()
exec_lua([[vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })]]) exec_lua([[vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })]])
screen:expect({ grid = grid_with_inlay_hints }) 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 }) screen:expect({ grid = grid_without_inlay_hints, unchanged = true })
end) end)

View File

@@ -25,7 +25,7 @@ after_each(function()
end) end)
describe('semantic token highlighting', function() describe('semantic token highlighting', function()
local screen local screen --- @type test.functional.ui.screen
before_each(function() before_each(function()
screen = Screen.new(40, 16) screen = Screen.new(40, 16)
screen:attach() screen:attach()
@@ -84,10 +84,8 @@ describe('semantic token highlighting', function()
before_each(function() before_each(function()
exec_lua(create_server_definition) exec_lua(create_server_definition)
exec_lua( exec_lua(function()
[[ _G.server = _G._create_server({
local legend, response, edit_response = ...
server = _create_server({
capabilities = { capabilities = {
semanticTokensProvider = { semanticTokensProvider = {
full = { delta = true }, full = { delta = true },
@@ -101,23 +99,19 @@ describe('semantic token highlighting', function()
['textDocument/semanticTokens/full/delta'] = function(_, _, callback) ['textDocument/semanticTokens/full/delta'] = function(_, _, callback)
callback(nil, vim.fn.json_decode(edit_response)) callback(nil, vim.fn.json_decode(edit_response))
end, end,
} },
}) })
]], end, legend, response, edit_response)
legend,
response,
edit_response
)
end) end)
it('buffer is highlighted when attached', function() it('buffer is highlighted when attached', function()
insert(text) insert(text)
exec_lua([[ exec_lua(function()
bufnr = vim.api.nvim_get_current_buf() local bufnr = vim.api.nvim_get_current_buf()
vim.api.nvim_win_set_buf(0, bufnr) vim.api.nvim_win_set_buf(0, bufnr)
vim.bo[bufnr].filetype = 'some-filetype' 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 { screen:expect {
grid = [[ grid = [[
@@ -141,21 +135,19 @@ describe('semantic token highlighting', function()
it('use LspTokenUpdate and highlight_token', function() it('use LspTokenUpdate and highlight_token', function()
insert(text) insert(text)
exec_lua([[ exec_lua(function()
vim.api.nvim_create_autocmd("LspTokenUpdate", { vim.api.nvim_create_autocmd('LspTokenUpdate', {
callback = function(args) callback = function(args)
local token = args.data.token local token = args.data.token --- @type STTokenRange
if token.type == "function" and token.modifiers.declaration then if token.type == 'function' and token.modifiers.declaration then
vim.lsp.semantic_tokens.highlight_token( vim.lsp.semantic_tokens.highlight_token(token, args.buf, args.data.client_id, 'Macro')
token, args.buf, args.data.client_id, "Macro"
)
end end
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) 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 { screen:expect {
grid = [[ grid = [[
@@ -180,19 +172,21 @@ describe('semantic token highlighting', function()
it('buffer is unhighlighted when client is detached', function() it('buffer is unhighlighted when client is detached', function()
insert(text) insert(text)
exec_lua([[ local bufnr = n.api.nvim_get_current_buf()
bufnr = vim.api.nvim_get_current_buf() local client_id = exec_lua(function()
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 }) local client_id = vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
vim.wait(1000, function() vim.wait(1000, function()
return #server.messages > 1 return #_G.server.messages > 1
end)
return client_id
end) end)
]])
exec_lua([[ exec_lua(function()
--- @diagnostic disable-next-line:duplicate-set-field
vim.notify = function() end vim.notify = function() end
vim.lsp.buf_detach_client(bufnr, client_id) vim.lsp.buf_detach_client(bufnr, client_id)
]]) end)
screen:expect { screen:expect {
grid = [[ grid = [[
@@ -217,18 +211,19 @@ describe('semantic token highlighting', function()
it( it(
'buffer is highlighted and unhighlighted when semantic token highlighting is started and stopped', 'buffer is highlighted and unhighlighted when semantic token highlighting is started and stopped',
function() function()
exec_lua([[ local bufnr = n.api.nvim_get_current_buf()
bufnr = vim.api.nvim_get_current_buf() local client_id = exec_lua(function()
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 }) return vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
]]) end)
insert(text) insert(text)
exec_lua([[ exec_lua(function()
--- @diagnostic disable-next-line:duplicate-set-field
vim.notify = function() end vim.notify = function() end
vim.lsp.semantic_tokens.stop(bufnr, client_id) vim.lsp.semantic_tokens.stop(bufnr, client_id)
]]) end)
screen:expect { screen:expect {
grid = [[ grid = [[
@@ -249,9 +244,9 @@ describe('semantic token highlighting', function()
]], ]],
} }
exec_lua([[ exec_lua(function()
vim.lsp.semantic_tokens.start(bufnr, client_id) vim.lsp.semantic_tokens.start(bufnr, client_id)
]]) end)
screen:expect { screen:expect {
grid = [[ grid = [[
@@ -275,18 +270,17 @@ describe('semantic token highlighting', function()
) )
it('highlights start and stop when using "0" for current buffer', function() it('highlights start and stop when using "0" for current buffer', function()
exec_lua([[ local client_id = exec_lua(function()
bufnr = vim.api.nvim_get_current_buf() return vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
vim.api.nvim_win_set_buf(0, bufnr) end)
client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
]])
insert(text) insert(text)
exec_lua([[ exec_lua(function()
--- @diagnostic disable-next-line:duplicate-set-field
vim.notify = function() end vim.notify = function() end
vim.lsp.semantic_tokens.stop(0, client_id) vim.lsp.semantic_tokens.stop(0, client_id)
]]) end)
screen:expect { screen:expect {
grid = [[ grid = [[
@@ -307,9 +301,9 @@ describe('semantic token highlighting', function()
]], ]],
} }
exec_lua([[ exec_lua(function()
vim.lsp.semantic_tokens.start(0, client_id) vim.lsp.semantic_tokens.start(0, client_id)
]]) end)
screen:expect { screen:expect {
grid = [[ grid = [[
@@ -333,11 +327,9 @@ describe('semantic token highlighting', function()
it('buffer is re-highlighted when force refreshed', function() it('buffer is re-highlighted when force refreshed', function()
insert(text) insert(text)
exec_lua([[ exec_lua(function()
bufnr = vim.api.nvim_get_current_buf() vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
vim.api.nvim_win_set_buf(0, bufnr) end)
client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
]])
screen:expect { screen:expect {
grid = [[ grid = [[
@@ -358,9 +350,9 @@ describe('semantic token highlighting', function()
]], ]],
} }
exec_lua([[ exec_lua(function()
vim.lsp.semantic_tokens.force_refresh(bufnr) vim.lsp.semantic_tokens.force_refresh()
]]) end)
screen:expect { screen:expect {
grid = [[ grid = [[
@@ -384,7 +376,9 @@ describe('semantic token highlighting', function()
local messages = exec_lua('return server.messages') local messages = exec_lua('return server.messages')
local token_request_count = 0 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') assert(message.method ~= 'textDocument/semanticTokens/full/delta', 'delta request received')
if message.method == 'textDocument/semanticTokens/full' then if message.method == 'textDocument/semanticTokens/full' then
token_request_count = token_request_count + 1 token_request_count = token_request_count + 1
@@ -394,31 +388,28 @@ describe('semantic token highlighting', function()
end) end)
it('destroys the highlighter if the buffer is deleted', function() it('destroys the highlighter if the buffer is deleted', function()
exec_lua([[ exec_lua(function()
bufnr = vim.api.nvim_get_current_buf() vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
vim.api.nvim_win_set_buf(0, bufnr) end)
client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
]])
insert(text) insert(text)
local highlighters = exec_lua([[ eq(
{},
exec_lua(function()
local bufnr = vim.api.nvim_get_current_buf()
vim.api.nvim_buf_delete(bufnr, { force = true }) vim.api.nvim_buf_delete(bufnr, { force = true })
local semantic_tokens = vim.lsp.semantic_tokens return vim.lsp.semantic_tokens.__STHighlighter.active
return semantic_tokens.__STHighlighter.active end)
]]) )
eq({}, highlighters)
end) end)
it('updates highlights with delta request on buffer change', function() it('updates highlights with delta request on buffer change', function()
insert(text) insert(text)
exec_lua([[ exec_lua(function()
bufnr = vim.api.nvim_get_current_buf() vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
vim.api.nvim_win_set_buf(0, bufnr) end)
client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
]])
screen:expect { screen:expect {
grid = [[ grid = [[
@@ -460,45 +451,49 @@ describe('semantic token highlighting', function()
end) end)
it('prevents starting semantic token highlighting with invalid conditions', function() it('prevents starting semantic token highlighting with invalid conditions', function()
exec_lua([[ local client_id = exec_lua(function()
bufnr = vim.api.nvim_get_current_buf() _G.notifications = {}
vim.api.nvim_win_set_buf(0, bufnr) --- @diagnostic disable-next-line:duplicate-set-field
client_id = vim.lsp.start_client({ name = 'dummy', cmd = server.cmd }) vim.notify = function(...)
notifications = {} table.insert(_G.notifications, 1, { ... })
vim.notify = function(...) table.insert(notifications, 1, {...}) end end
]]) return vim.lsp.start_client({ name = 'dummy', cmd = _G.server.cmd })
eq(false, exec_lua('return vim.lsp.buf_is_attached(bufnr, client_id)')) end)
eq(false, exec_lua('return vim.lsp.buf_is_attached(0, ...)', client_id))
insert(text) insert(text)
local notifications = exec_lua([[ matches(
vim.lsp.semantic_tokens.start(bufnr, client_id) '%[LSP%] Client with id %d not attached to buffer %d',
return notifications exec_lua(function()
]]) vim.lsp.semantic_tokens.start(0, client_id)
matches('%[LSP%] Client with id %d not attached to buffer %d', notifications[1][1]) return _G.notifications[1][1]
end)
)
notifications = exec_lua([[ matches(
vim.lsp.semantic_tokens.start(bufnr, client_id + 1) '%[LSP%] No client with id %d',
return notifications exec_lua(function()
]]) vim.lsp.semantic_tokens.start(0, client_id + 1)
matches('%[LSP%] No client with id %d', notifications[1][1]) return _G.notifications[1][1]
end)
)
end) end)
it( it(
'opt-out: does not activate semantic token highlighting if disabled in client attach', 'opt-out: does not activate semantic token highlighting if disabled in client attach',
function() function()
exec_lua([[ local client_id = exec_lua(function()
bufnr = vim.api.nvim_get_current_buf() return vim.lsp.start({
vim.api.nvim_win_set_buf(0, bufnr)
client_id = vim.lsp.start({
name = 'dummy', name = 'dummy',
cmd = server.cmd, cmd = _G.server.cmd,
on_attach = vim.schedule_wrap(function(client, bufnr) --- @param client vim.lsp.Client
on_attach = vim.schedule_wrap(function(client, _bufnr)
client.server_capabilities.semanticTokensProvider = nil client.server_capabilities.semanticTokensProvider = nil
end), end),
}) })
]]) end)
eq(true, exec_lua('return vim.lsp.buf_is_attached(bufnr, client_id)')) eq(true, exec_lua('return vim.lsp.buf_is_attached(0, ...)', client_id))
insert(text) insert(text)
@@ -521,13 +516,18 @@ describe('semantic token highlighting', function()
]], ]],
} }
local notifications = exec_lua([[ eq(
'[LSP] Server does not support semantic tokens',
exec_lua(function()
local notifications = {} local notifications = {}
vim.notify = function(...) table.insert(notifications, 1, {...}) end --- @diagnostic disable-next-line:duplicate-set-field
vim.lsp.semantic_tokens.start(bufnr, client_id) vim.notify = function(...)
return notifications table.insert(notifications, 1, { ... })
]]) end
eq('[LSP] Server does not support semantic tokens', notifications[1][1]) vim.lsp.semantic_tokens.start(0, client_id)
return notifications[1][1]
end)
)
screen:expect { screen:expect {
grid = [[ grid = [[
@@ -552,28 +552,32 @@ describe('semantic token highlighting', function()
) )
it('ignores null responses from the server', function() it('ignores null responses from the server', function()
exec_lua([[ local client_id = exec_lua(function()
local legend, response, edit_response = ... _G.server2 = _G._create_server({
server2 = _create_server({
capabilities = { capabilities = {
semanticTokensProvider = { semanticTokensProvider = {
full = { delta = false }, full = { delta = false },
}, },
}, },
handlers = { handlers = {
--- @param callback function
['textDocument/semanticTokens/full'] = function(_, _, callback) ['textDocument/semanticTokens/full'] = function(_, _, callback)
callback(nil, nil) callback(nil, nil)
end, end,
['textDocument/semanticTokens/full/delta'] = function() --- @param callback function
['textDocument/semanticTokens/full/delta'] = function(_, _, callback)
callback(nil, nil) callback(nil, nil)
end, end,
} },
}) })
bufnr = vim.api.nvim_get_current_buf() return vim.lsp.start({ name = 'dummy', cmd = _G.server2.cmd })
vim.api.nvim_win_set_buf(0, bufnr) end)
client_id = vim.lsp.start({ name = 'dummy', cmd = server2.cmd }) eq(
]]) true,
eq(true, exec_lua('return vim.lsp.buf_is_attached(bufnr, client_id)')) exec_lua(function()
return vim.lsp.buf_is_attached(0, client_id)
end)
)
insert(text) insert(text)
@@ -599,10 +603,8 @@ describe('semantic token highlighting', function()
it('does not send delta requests if not supported by server', function() it('does not send delta requests if not supported by server', function()
insert(text) insert(text)
exec_lua( exec_lua(function()
[[ _G.server2 = _G._create_server({
local legend, response, edit_response = ...
server2 = _create_server({
capabilities = { capabilities = {
semanticTokensProvider = { semanticTokensProvider = {
full = { delta = false }, full = { delta = false },
@@ -616,16 +618,10 @@ describe('semantic token highlighting', function()
['textDocument/semanticTokens/full/delta'] = function(_, _, callback) ['textDocument/semanticTokens/full/delta'] = function(_, _, callback)
callback(nil, vim.fn.json_decode(edit_response)) callback(nil, vim.fn.json_decode(edit_response))
end, end,
} },
}) })
bufnr = vim.api.nvim_get_current_buf() return vim.lsp.start({ name = 'dummy', cmd = _G.server2.cmd })
vim.api.nvim_win_set_buf(0, bufnr) end)
client_id = vim.lsp.start({ name = 'dummy', cmd = server2.cmd })
]],
legend,
response,
edit_response
)
screen:expect { screen:expect {
grid = [[ grid = [[
@@ -670,7 +666,9 @@ describe('semantic token highlighting', function()
} }
local messages = exec_lua('return server2.messages') local messages = exec_lua('return server2.messages')
local token_request_count = 0 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') assert(message.method ~= 'textDocument/semanticTokens/full/delta', 'delta request received')
if message.method == 'textDocument/semanticTokens/full' then if message.method == 'textDocument/semanticTokens/full' then
token_request_count = token_request_count + 1 token_request_count = token_request_count + 1
@@ -1065,10 +1063,8 @@ b = "as"]],
}) do }) do
it(test.it, function() it(test.it, function()
exec_lua(create_server_definition) exec_lua(create_server_definition)
exec_lua( local client_id = exec_lua(function(legend, resp)
[[ _G.server = _G._create_server({
local legend, resp = ...
server = _create_server({
capabilities = { capabilities = {
semanticTokensProvider = { semanticTokensProvider = {
full = { delta = false }, full = { delta = false },
@@ -1079,25 +1075,22 @@ b = "as"]],
['textDocument/semanticTokens/full'] = function(_, _, callback) ['textDocument/semanticTokens/full'] = function(_, _, callback)
callback(nil, vim.fn.json_decode(resp)) callback(nil, vim.fn.json_decode(resp))
end, end,
} },
}) })
bufnr = vim.api.nvim_get_current_buf() return vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
vim.api.nvim_win_set_buf(0, bufnr) end, test.legend, test.response)
client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
]],
test.legend,
test.response
)
insert(test.text) insert(test.text)
test.expected_screen() test.expected_screen()
local highlights = exec_lua([[ eq(
local semantic_tokens = vim.lsp.semantic_tokens test.expected,
return semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights exec_lua(function()
]]) local bufnr = vim.api.nvim_get_current_buf()
eq(test.expected, highlights) return vim.lsp.semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights
end)
)
end) end)
end end
end) end)
@@ -1450,12 +1443,11 @@ int main()
}, },
}) do }) do
it(test.it, function() it(test.it, function()
local bufnr = n.api.nvim_get_current_buf()
insert(test.text1) insert(test.text1)
exec_lua(create_server_definition) exec_lua(create_server_definition)
exec_lua( local client_id = exec_lua(function(legend, resp1, resp2)
[[ _G.server = _G._create_server({
local legend, resp1, resp2 = ...
server = _create_server({
capabilities = { capabilities = {
semanticTokensProvider = { semanticTokensProvider = {
full = { delta = true }, full = { delta = true },
@@ -1469,52 +1461,44 @@ int main()
['textDocument/semanticTokens/full/delta'] = function(_, _, callback) ['textDocument/semanticTokens/full/delta'] = function(_, _, callback)
callback(nil, vim.fn.json_decode(resp2)) callback(nil, vim.fn.json_decode(resp2))
end, end,
} },
}) })
bufnr = vim.api.nvim_get_current_buf() local client_id = assert(vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd }))
vim.api.nvim_win_set_buf(0, bufnr)
client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
-- speed up vim.api.nvim_buf_set_lines calls by changing debounce to 10 for these tests -- 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() vim.schedule(function()
semantic_tokens.stop(bufnr, client_id) vim.lsp.semantic_tokens.stop(bufnr, client_id)
semantic_tokens.start(bufnr, client_id, { debounce = 10 }) vim.lsp.semantic_tokens.start(bufnr, client_id, { debounce = 10 })
end) end)
]], return client_id
test.legend, end, test.legend, test.response1, test.response2)
test.response1,
test.response2
)
test.expected_screen1() test.expected_screen1()
local highlights = exec_lua([[ eq(
return semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights test.expected1,
]]) exec_lua(function()
return vim.lsp.semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights
eq(test.expected1, highlights) end)
)
if test.edit then if test.edit then
feed(test.edit) feed(test.edit)
else else
exec_lua( exec_lua(function(text)
[[ vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, vim.fn.split(text, '\n'))
local text = ...
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, vim.fn.split(text, "\n"))
vim.wait(15) -- wait for debounce vim.wait(15) -- wait for debounce
]], end, test.text2)
test.text2
)
end end
test.expected_screen2() test.expected_screen2()
highlights = exec_lua([[ eq(
return semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights test.expected2,
]]) exec_lua(function()
return vim.lsp.semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights
eq(test.expected2, highlights) end)
)
end) end)
end end
end) end)

View File

@@ -108,20 +108,21 @@ M.fake_lsp_code = 'test/functional/fixtures/fake-lsp-server.lua'
M.fake_lsp_logfile = 'Xtest-fake-lsp.log' M.fake_lsp_logfile = 'Xtest-fake-lsp.log'
local function fake_lsp_server_setup(test_name, timeout_ms, options, settings) local function fake_lsp_server_setup(test_name, timeout_ms, options, settings)
exec_lua( exec_lua(function(fake_lsp_code, fake_lsp_logfile, timeout)
function(test_name0, fake_lsp_code0, fake_lsp_logfile0, timeout, options0, settings0) options = options or {}
settings = settings or {}
_G.lsp = require('vim.lsp') _G.lsp = require('vim.lsp')
_G.TEST_RPC_CLIENT_ID = _G.lsp.start_client { _G.TEST_RPC_CLIENT_ID = _G.lsp.start_client {
cmd_env = { cmd_env = {
NVIM_LOG_FILE = fake_lsp_logfile0, NVIM_LOG_FILE = fake_lsp_logfile,
NVIM_LUA_NOTRACK = '1', NVIM_LUA_NOTRACK = '1',
NVIM_APPNAME = 'nvim_lsp_test', NVIM_APPNAME = 'nvim_lsp_test',
}, },
cmd = { cmd = {
vim.v.progpath, vim.v.progpath,
'-l', '-l',
fake_lsp_code0, fake_lsp_code,
test_name0, test_name,
tostring(timeout), tostring(timeout),
}, },
handlers = setmetatable({}, { handlers = setmetatable({}, {
@@ -147,22 +148,15 @@ local function fake_lsp_server_setup(test_name, timeout_ms, options, settings)
vim.rpcrequest(1, 'init', result) vim.rpcrequest(1, 'init', result)
end, end,
flags = { flags = {
allow_incremental_sync = options0.allow_incremental_sync or false, allow_incremental_sync = options.allow_incremental_sync or false,
debounce_text_changes = options0.debounce_text_changes or 0, debounce_text_changes = options.debounce_text_changes or 0,
}, },
settings = settings0, settings = settings,
on_exit = function(...) on_exit = function(...)
vim.rpcnotify(1, 'exit', ...) vim.rpcnotify(1, 'exit', ...)
end, end,
} }
end, end, M.fake_lsp_code, M.fake_lsp_logfile, timeout_ms or 1e3)
test_name,
M.fake_lsp_code,
M.fake_lsp_logfile,
timeout_ms or 1e3,
options or {},
settings or {}
)
end end
--- @class test.lsp.Config --- @class test.lsp.Config
@@ -193,13 +187,12 @@ function M.test_rpc_server(config)
-- Otherwise I would just return the value here. -- Otherwise I would just return the value here.
return function(...) return function(...)
return exec_lua(function(...) return exec_lua(function(...)
local name0 = ... if type(_G.TEST_RPC_CLIENT[name]) == 'function' then
if type(_G.TEST_RPC_CLIENT[name0]) == 'function' then return _G.TEST_RPC_CLIENT[name](...)
return _G.TEST_RPC_CLIENT[name0](select(2, ...))
else else
return _G.TEST_RPC_CLIENT[name0] return _G.TEST_RPC_CLIENT[name]
end end
end, name, ...) end, ...)
end end
end, end,
}) })

View File

@@ -11,21 +11,11 @@ describe('vim.lsp.util', function()
describe('stylize_markdown', function() describe('stylize_markdown', function()
local stylize_markdown = function(content, opts) local stylize_markdown = function(content, opts)
return exec_lua( return exec_lua(function()
[[ local bufnr = vim.uri_to_bufnr('file:///fake/uri')
local bufnr = vim.uri_to_bufnr("file:///fake/uri")
vim.fn.bufload(bufnr) vim.fn.bufload(bufnr)
return vim.lsp.util.stylize_markdown(bufnr, content, opts)
local args = { ... } end)
local content = args[1]
local opts = args[2]
local stripped_content = vim.lsp.util.stylize_markdown(bufnr, content, opts)
return stripped_content
]],
content,
opts
)
end end
it('code fences', function() it('code fences', function()
@@ -95,7 +85,7 @@ describe('vim.lsp.util', function()
describe('normalize_markdown', function() describe('normalize_markdown', function()
it('collapses consecutive blank lines', function() it('collapses consecutive blank lines', function()
local result = exec_lua [[ local result = exec_lua(function()
local lines = { local lines = {
'foo', 'foo',
'', '',
@@ -103,25 +93,25 @@ describe('vim.lsp.util', function()
'', '',
'bar', 'bar',
'', '',
'baz' 'baz',
} }
return vim.lsp.util._normalize_markdown(lines) return vim.lsp.util._normalize_markdown(lines)
]] end)
local expected = { 'foo', '', 'bar', '', 'baz' } local expected = { 'foo', '', 'bar', '', 'baz' }
eq(expected, result) eq(expected, result)
end) end)
it('removes preceding and trailing empty lines', function() it('removes preceding and trailing empty lines', function()
local result = exec_lua [[ local result = exec_lua(function()
local lines = { local lines = {
'', '',
'foo', 'foo',
'bar', 'bar',
'', '',
'' '',
} }
return vim.lsp.util._normalize_markdown(lines) return vim.lsp.util._normalize_markdown(lines)
]] end)
local expected = { 'foo', 'bar' } local expected = { 'foo', 'bar' }
eq(expected, result) eq(expected, result)
end) end)
@@ -129,19 +119,14 @@ describe('vim.lsp.util', function()
describe('make_floating_popup_options', function() describe('make_floating_popup_options', function()
local function assert_anchor(anchor_bias, expected_anchor) local function assert_anchor(anchor_bias, expected_anchor)
local opts = exec_lua( local opts = exec_lua(function()
[[
local args = { ... }
local anchor_bias = args[1]
return vim.lsp.util.make_floating_popup_options(30, 10, { anchor_bias = anchor_bias }) return vim.lsp.util.make_floating_popup_options(30, 10, { anchor_bias = anchor_bias })
]], end)
anchor_bias
)
eq(expected_anchor, string.sub(opts.anchor, 1, 1)) eq(expected_anchor, string.sub(opts.anchor, 1, 1))
end end
local screen local screen --- @type test.functional.ui.screen
before_each(function() before_each(function()
n.clear() n.clear()
screen = Screen.new(80, 80) screen = Screen.new(80, 80)
@@ -221,9 +206,9 @@ describe('vim.lsp.util', function()
end) end)
it('bordered window truncates dimensions correctly', function() 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' }) return vim.lsp.util.make_floating_popup_options(100, 100, { border = 'single' })
]]) end)
eq(56, opts.height) eq(56, opts.height)
end) end)

File diff suppressed because it is too large Load Diff

View File

@@ -16,21 +16,20 @@ local is_ci = t.is_ci
-- Collects all names passed to find_path() after attempting ":Man foo". -- Collects all names passed to find_path() after attempting ":Man foo".
local function get_search_history(name) local function get_search_history(name)
return exec_lua(function()
local args = vim.split(name, ' ') local args = vim.split(name, ' ')
local code = [[
local args = ...
local man = require('man') local man = require('man')
local res = {} local res = {}
man.find_path = function(sect, name) --- @diagnostic disable-next-line:duplicate-set-field
table.insert(res, {sect, name}) man.find_path = function(sect, name0)
table.insert(res, { sect, name0 })
return nil return nil
end 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(not ok)
assert(rv and rv:match('no manual entry')) assert(rv and rv:match('no manual entry'))
return res return res
]] end)
return exec_lua(code, args)
end end
clear() clear()

View File

@@ -210,9 +210,7 @@ describe(':TOhtml', function()
exec('set termguicolors') exec('set termguicolors')
local bg = fn.synIDattr(fn.hlID('Normal'), 'bg#', 'gui') local bg = fn.synIDattr(fn.hlID('Normal'), 'bg#', 'gui')
local fg = fn.synIDattr(fn.hlID('Normal'), 'fg#', 'gui') local fg = fn.synIDattr(fn.hlID('Normal'), 'fg#', 'gui')
exec_lua [[ n.command('2,2TOhtml')
local html = vim.cmd'2,2TOhtml'
]]
local out_file = api.nvim_buf_get_name(api.nvim_get_current_buf()) local out_file = api.nvim_buf_get_name(api.nvim_get_current_buf())
eq({ eq({
'<!DOCTYPE html>', '<!DOCTYPE html>',
@@ -408,12 +406,12 @@ describe(':TOhtml', function()
local function run() local function run()
local buf = api.nvim_get_current_buf() local buf = api.nvim_get_current_buf()
run_tohtml_and_assert(screen, function() run_tohtml_and_assert(screen, function()
exec_lua [[ exec_lua(function()
local outfile = vim.fn.tempname() .. '.html' local outfile = vim.fn.tempname() .. '.html'
local html = require('tohtml').tohtml(0, { number_lines = true }) local html = require('tohtml').tohtml(0, { number_lines = true })
vim.fn.writefile(html, outfile) vim.fn.writefile(html, outfile)
vim.cmd.split(outfile) vim.cmd.split(outfile)
]] end)
end) end)
api.nvim_set_current_buf(buf) api.nvim_set_current_buf(buf)
end end

View File

@@ -837,21 +837,173 @@ function M.exec_capture(code)
return M.api.nvim_exec2(code, { output = true }).output return M.api.nvim_exec2(code, { output = true }).output
end end
--- @param code string|function --- @param f function
--- @return any --- @return table<string,any>
function M.exec_lua(code, ...) local function get_upvalues(f)
if type(code) == 'function' then local i = 1
return M.api.nvim_exec_lua( local upvalues = {} --- @type table<string,any>
[[ while true do
local code = ... local n, v = debug.getupvalue(f, i)
return loadstring(code)(select(2, ...)) if not n then
]], break
{ string.dump(code), ... } end
upvalues[n] = v
i = i + 1
end
return upvalues
end
--- @param f function
--- @param upvalues table<string,any>
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<string,any>
_G.__get_upvalues = nil
--- @type fun(f: function, upvalues: table<string,any>)
_G.__set_upvalues = nil
--- @param self table<string,function>
--- @param bytecode string
--- @param upvalues table<string,any>
--- @param ... any[]
--- @return any[] result
--- @return table<string,any> 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<string,any>
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
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) == 'string' then
return M.api.nvim_exec_lua(code, { ... }) return M.api.nvim_exec_lua(code, { ... })
end end
assert(session)
if not session.exec_lua_setup then
M.api.nvim_exec_lua(
[[
_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(get_upvalues), string.dump(set_upvalues), string.dump(exec_lua_handler) }
)
session.exec_lua_setup = true
end
--- @type any[], table<string,any>
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() function M.get_pathsep()
return is_os('win') and '\\' or '/' return is_os('win') and '\\' or '/'
end end

View File

@@ -187,10 +187,10 @@ describe('treesitter highlighting (C)', function()
-- legacy syntax highlighting is used by default -- legacy syntax highlighting is used by default
screen:expect(hl_grid_legacy_c) screen:expect(hl_grid_legacy_c)
exec_lua(function(hl_query) exec_lua(function()
vim.treesitter.query.set('c', 'highlights', hl_query) vim.treesitter.query.set('c', 'highlights', hl_query_c)
vim.treesitter.start() vim.treesitter.start()
end, hl_query_c) end)
-- treesitter highlighting is used -- treesitter highlighting is used
screen:expect(hl_grid_ts_c) 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 parser = vim.treesitter.get_parser(0, 'c')
local highlighter = vim.treesitter.highlighter local highlighter = vim.treesitter.highlighter
highlighter.new(parser, { queries = { c = hl_query } }) highlighter.new(parser, { queries = { c = hl_query_c } })
end, hl_query_c) end)
screen:expect(hl_grid_ts_c) screen:expect(hl_grid_ts_c)
feed('5Goc<esc>dd') feed('5Goc<esc>dd')
@@ -369,10 +369,10 @@ describe('treesitter highlighting (C)', function()
it('is updated with :sort', function() it('is updated with :sort', function()
insert(test_text_c) insert(test_text_c)
exec_lua(function(hl_query) exec_lua(function()
local parser = vim.treesitter.get_parser(0, 'c') local parser = vim.treesitter.get_parser(0, 'c')
vim.treesitter.highlighter.new(parser, { queries = { c = hl_query } }) vim.treesitter.highlighter.new(parser, { queries = { c = hl_query_c } })
end, hl_query_c) end)
screen:expect { screen:expect {
grid = [[ grid = [[
{3:int} width = {5:INT_MAX}, height = {5:INT_MAX}; | {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 } screen:expect { grid = injection_grid_c }
exec_lua(function(hl_query) exec_lua(function()
local parser = vim.treesitter.get_parser(0, 'c', { local parser = vim.treesitter.get_parser(0, 'c', {
injections = { injections = {
c = '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c")) (preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))', 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 local highlighter = vim.treesitter.highlighter
highlighter.new(parser, { queries = { c = hl_query } }) highlighter.new(parser, { queries = { c = hl_query_c } })
end, hl_query_c) end)
screen:expect { grid = injection_grid_expected_c } screen:expect { grid = injection_grid_expected_c }
end) end)
@@ -536,7 +536,7 @@ describe('treesitter highlighting (C)', function()
screen:expect { grid = injection_grid_c } screen:expect { grid = injection_grid_c }
exec_lua(function(hl_query) exec_lua(function()
vim.treesitter.language.register('c', 'foo') vim.treesitter.language.register('c', 'foo')
local parser = vim.treesitter.get_parser(0, 'c', { local parser = vim.treesitter.get_parser(0, 'c', {
injections = { injections = {
@@ -544,8 +544,8 @@ describe('treesitter highlighting (C)', function()
}, },
}) })
local highlighter = vim.treesitter.highlighter local highlighter = vim.treesitter.highlighter
highlighter.new(parser, { queries = { c = hl_query } }) highlighter.new(parser, { queries = { c = hl_query_c } })
end, hl_query_c) end)
screen:expect { grid = injection_grid_expected_c } screen:expect { grid = injection_grid_expected_c }
end) end)
@@ -559,14 +559,14 @@ describe('treesitter highlighting (C)', function()
} }
]]) ]])
exec_lua(function(hl_query) exec_lua(function()
local injection_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"))' '(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.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) end)
screen:expect { screen:expect {
grid = [[ grid = [[
@@ -586,10 +586,10 @@ describe('treesitter highlighting (C)', function()
insert(hl_text_c) insert(hl_text_c)
feed('gg') feed('gg')
exec_lua(function(hl_query) exec_lua(function()
local parser = vim.treesitter.get_parser(0, 'c') local parser = vim.treesitter.get_parser(0, 'c')
vim.treesitter.highlighter.new(parser, { queries = { c = hl_query } }) vim.treesitter.highlighter.new(parser, { queries = { c = hl_query_c } })
end, hl_query_c) end)
screen:expect(hl_grid_ts_c) 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') local parser = vim.treesitter.get_parser(0, 'c')
vim.treesitter.highlighter.new(parser, { vim.treesitter.highlighter.new(parser, {
queries = { 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 -- expect everything to have Constant highlight
screen:expect { screen:expect {
grid = [[ grid = [[
@@ -826,10 +826,10 @@ describe('treesitter highlighting (C)', function()
declarator: (pointer_declarator) @variable.parameter) declarator: (pointer_declarator) @variable.parameter)
]] ]]
exec_lua(function(query_str) exec_lua(function()
vim.treesitter.query.set('c', 'highlights', query_str) vim.treesitter.query.set('c', 'highlights', query)
vim.treesitter.highlighter.new(vim.treesitter.get_parser(0, 'c')) vim.treesitter.highlighter.new(vim.treesitter.get_parser(0, 'c'))
end, query) end)
screen:expect { screen:expect {
grid = [[ grid = [[

View File

@@ -156,10 +156,10 @@ describe('vim.treesitter.inspect_tree', function()
eq('', n.api.nvim_get_vvar('errmsg')) eq('', n.api.nvim_get_vvar('errmsg'))
-- close original tree window -- close original tree window
exec_lua([[ exec_lua(function()
vim.api.nvim_set_current_win(tree_win_copy_1) vim.api.nvim_set_current_win(_G.tree_win_copy_1)
vim.api.nvim_win_close(tree_win, false) vim.api.nvim_win_close(_G.tree_win, false)
]]) end)
-- navigates correctly to the remaining source buffer window -- navigates correctly to the remaining source buffer window
feed('<CR>') feed('<CR>')

View File

@@ -166,10 +166,10 @@ describe('treesitter language API', function()
it('retrieve an anonymous node given a range', function() it('retrieve an anonymous node given a range', function()
insert([[vim.fn.input()]]) insert([[vim.fn.input()]])
exec_lua([[ exec_lua(function()
langtree = vim.treesitter.get_parser(0, "lua") _G.langtree = vim.treesitter.get_parser(0, 'lua')
node = langtree:node_for_range({0, 3, 0, 3}) _G.node = _G.langtree:node_for_range({ 0, 3, 0, 3 })
]]) end)
eq('.', exec_lua('return node:type()')) eq('.', exec_lua('return node:type()'))
end) end)

View File

@@ -58,15 +58,15 @@ describe('treesitter node API', function()
it('get_node() with anonymous nodes included', function() it('get_node() with anonymous nodes included', function()
insert([[print('test')]]) insert([[print('test')]])
exec_lua([[ exec_lua(function()
parser = vim.treesitter.get_parser(0, 'lua') _G.parser = vim.treesitter.get_parser(0, 'lua')
tree = parser:parse()[1] _G.tree = _G.parser:parse()[1]
node = vim.treesitter.get_node({ _G.node = vim.treesitter.get_node({
bufnr = 0, bufnr = 0,
pos = { 0, 6 }, -- on the first apostrophe pos = { 0, 6 }, -- on the first apostrophe
include_anonymous = true, include_anonymous = true,
}) })
]]) end)
eq("'", lua_eval('node:type()')) eq("'", lua_eval('node:type()'))
eq(false, lua_eval('node:named()')) eq(false, lua_eval('node:named()'))
@@ -120,7 +120,7 @@ describe('treesitter node API', function()
local len = exec_lua(function() local len = exec_lua(function()
local tree = vim.treesitter.get_parser(0, 'c'):parse()[1] 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() _G.children = node:named_children()
return #_G.children return #_G.children

View File

@@ -660,8 +660,8 @@ print()
end) end)
local function run_query() local function run_query()
return exec_lua(function(query_str) return exec_lua(function()
local query = vim.treesitter.query.parse('c', query_str) local query = vim.treesitter.query.parse('c', query0)
local parser = vim.treesitter.get_parser() local parser = vim.treesitter.get_parser()
local tree = parser:parse()[1] local tree = parser:parse()[1]
local res = {} local res = {}
@@ -669,7 +669,7 @@ print()
table.insert(res, { query.captures[id], node:range() }) table.insert(res, { query.captures[id], node:range() })
end end
return res return res
end, query0) end)
end end
eq({ eq({
@@ -707,15 +707,15 @@ print()
]] ]]
]==] ]==]
local r = exec_lua(function(src) local r = exec_lua(function()
local parser = vim.treesitter.get_string_parser(src, 'lua') local parser = vim.treesitter.get_string_parser(source, 'lua')
parser:parse(true) parser:parse(true)
local ranges = {} local ranges = {}
parser:for_each_tree(function(tstree, tree) parser:for_each_tree(function(tstree, tree)
ranges[tree:lang()] = { tstree:root():range(true) } ranges[tree:lang()] = { tstree:root():range(true) }
end) end)
return ranges return ranges
end, source) end)
eq({ eq({
lua = { 0, 6, 6, 16, 4, 438 }, 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 -- the ranges but only provide a Range4. Strip the byte entries from the ranges and make sure
-- add_bytes() produces the same result. -- 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 local add_bytes = require('vim.treesitter._range').add_bytes
for lang, range in pairs(r0) do for lang, range in pairs(r) do
r0[lang] = { range[1], range[2], range[4], range[5] } r[lang] = { range[1], range[2], range[4], range[5] }
r0[lang] = add_bytes(source0, r0[lang]) r[lang] = add_bytes(source, r[lang])
end end
return r0 return r
end, r, source) end)
eq(rb, r) eq(rb, r)
end) end)

View File

@@ -82,17 +82,17 @@ void ui_refresh(void)
local long_query = test_query:rep(100) local long_query = test_query:rep(100)
---@return number ---@return number
local function q(_n) local function q(_n)
return exec_lua(function(query, n0) return exec_lua(function()
local before = vim.api.nvim__stats().ts_query_parse_count local before = vim.api.nvim__stats().ts_query_parse_count
collectgarbage('stop') collectgarbage('stop')
for _ = 1, n0, 1 do for _ = 1, _n, 1 do
vim.treesitter.query.parse('c', query, n0) vim.treesitter.query.parse('c', long_query, _n)
end end
collectgarbage('restart') collectgarbage('restart')
collectgarbage('collect') collectgarbage('collect')
local after = vim.api.nvim__stats().ts_query_parse_count local after = vim.api.nvim__stats().ts_query_parse_count
return after - before return after - before
end, long_query, _n) end)
end end
eq(1, q(1)) eq(1, q(1))
@@ -103,8 +103,8 @@ void ui_refresh(void)
it('supports query and iter by capture (iter_captures)', function() it('supports query and iter by capture (iter_captures)', function()
insert(test_text) insert(test_text)
local res = exec_lua(function(test_query0) local res = exec_lua(function()
local cquery = vim.treesitter.query.parse('c', test_query0) local cquery = vim.treesitter.query.parse('c', test_query)
local parser = vim.treesitter.get_parser(0, 'c') local parser = vim.treesitter.get_parser(0, 'c')
local tree = parser:parse()[1] local tree = parser:parse()[1]
local res = {} local res = {}
@@ -113,7 +113,7 @@ void ui_refresh(void)
table.insert(res, { '@' .. cquery.captures[cid], node:type(), node:range() }) table.insert(res, { '@' .. cquery.captures[cid], node:type(), node:range() })
end end
return res return res
end, test_query) end)
eq({ eq({
{ '@type', 'primitive_type', 8, 2, 8, 6 }, -- bool { '@type', 'primitive_type', 8, 2, 8, 6 }, -- bool
@@ -133,8 +133,8 @@ void ui_refresh(void)
insert(test_text) insert(test_text)
---@type table ---@type table
local res = exec_lua(function(test_query0) local res = exec_lua(function()
local cquery = vim.treesitter.query.parse('c', test_query0) local cquery = vim.treesitter.query.parse('c', test_query)
local parser = vim.treesitter.get_parser(0, 'c') local parser = vim.treesitter.get_parser(0, 'c')
local tree = parser:parse()[1] local tree = parser:parse()[1]
local res = {} local res = {}
@@ -149,7 +149,7 @@ void ui_refresh(void)
table.insert(res, { pattern, mrepr }) table.insert(res, { pattern, mrepr })
end end
return res return res
end, test_query) end)
eq({ eq({
{ 3, { { '@type', 'primitive_type', 8, 2, 8, 6 } } }, { 3, { { '@type', 'primitive_type', 8, 2, 8, 6 } } },
@@ -449,7 +449,7 @@ void ui_refresh(void)
local custom_query = '((identifier) @main (#is-main? @main))' local custom_query = '((identifier) @main (#is-main? @main))'
do do
local res = exec_lua(function(custom_query0) local res = exec_lua(function()
local query = vim.treesitter.query local query = vim.treesitter.query
local function is_main(match, _pattern, bufnr, predicate) local function is_main(match, _pattern, bufnr, predicate)
@@ -466,7 +466,7 @@ void ui_refresh(void)
query.add_predicate('is-main?', is_main) query.add_predicate('is-main?', is_main)
local query0 = query.parse('c', custom_query0) local query0 = query.parse('c', custom_query)
local nodes = {} local nodes = {}
for _, node in query0:iter_captures(parser:parse()[1]:root(), 0) do for _, node in query0:iter_captures(parser:parse()[1]:root(), 0) do
@@ -474,14 +474,14 @@ void ui_refresh(void)
end end
return nodes return nodes
end, custom_query) end)
eq({ { 0, 4, 0, 8 } }, res) eq({ { 0, 4, 0, 8 } }, res)
end end
-- Once with the old API. Remove this whole 'do' block in 0.12 -- Once with the old API. Remove this whole 'do' block in 0.12
do do
local res = exec_lua(function(custom_query0) local res = exec_lua(function()
local query = vim.treesitter.query local query = vim.treesitter.query
local function is_main(match, _pattern, bufnr, predicate) 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 }) 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 = {} local nodes = {}
for _, node in query0:iter_captures(parser:parse()[1]:root(), 0) do for _, node in query0:iter_captures(parser:parse()[1]:root(), 0) do
@@ -502,7 +502,7 @@ void ui_refresh(void)
end end
return nodes return nodes
end, custom_query) end)
-- Remove this 'do' block in 0.12 -- Remove this 'do' block in 0.12
eq(0, fn.has('nvim-0.12')) eq(0, fn.has('nvim-0.12'))
@@ -538,15 +538,15 @@ void ui_refresh(void)
local function test(input, query) local function test(input, query)
api.nvim_buf_set_lines(0, 0, -1, true, vim.split(dedent(input), '\n')) 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 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 = {} local nodes = {}
for _, node in query0:iter_captures(parser:parse()[1]:root(), 0) do for _, node in query0:iter_captures(parser:parse()[1]:root(), 0) do
nodes[#nodes + 1] = { node:range() } nodes[#nodes + 1] = { node:range() }
end end
return nodes return nodes
end, query) end)
end end
eq( eq(
@@ -641,8 +641,8 @@ void ui_refresh(void)
eq(0, fn.has('nvim-0.12')) eq(0, fn.has('nvim-0.12'))
insert(test_text) insert(test_text)
local res = exec_lua(function(test_query0) local res = exec_lua(function()
local cquery = vim.treesitter.query.parse('c', test_query0) local cquery = vim.treesitter.query.parse('c', test_query)
local parser = vim.treesitter.get_parser(0, 'c') local parser = vim.treesitter.get_parser(0, 'c')
local tree = parser:parse()[1] local tree = parser:parse()[1]
local res = {} local res = {}
@@ -654,7 +654,7 @@ void ui_refresh(void)
table.insert(res, { pattern, mrepr }) table.insert(res, { pattern, mrepr })
end end
return res return res
end, test_query) end)
eq({ eq({
{ 3, { { '@type', 'primitive_type', 8, 2, 8, 6 } } }, { 3, { { '@type', 'primitive_type', 8, 2, 8, 6 } } },
@@ -686,19 +686,19 @@ void ui_refresh(void)
int bar = 13; int bar = 13;
]] ]]
local ret = exec_lua(function(str) local ret = exec_lua(function()
local parser = vim.treesitter.get_string_parser(str, 'c') local parser = vim.treesitter.get_string_parser(txt, 'c')
local nodes = {} local nodes = {}
local query = vim.treesitter.query.parse('c', '((identifier) @foo)') 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() }) table.insert(nodes, { node:range() })
end end
return nodes return nodes
end, txt) end)
eq({ { 1, 10, 1, 13 } }, ret) eq({ { 1, 10, 1, 13 } }, ret)
end) end)
@@ -801,8 +801,8 @@ void ui_refresh(void)
(#eq? @function.name "foo")) (#eq? @function.name "foo"))
]] ]]
local result = exec_lua(function(query_str) local result = exec_lua(function()
local query0 = vim.treesitter.query.parse('c', query_str) local query0 = vim.treesitter.query.parse('c', query)
local match_preds = query0.match_preds local match_preds = query0.match_preds
local called = 0 local called = 0
function query0:match_preds(...) function query0:match_preds(...)
@@ -816,7 +816,7 @@ void ui_refresh(void)
captures[#captures + 1] = id captures[#captures + 1] = id
end end
return { called, captures } return { called, captures }
end, query) end)
eq({ 2, { 1, 1, 2, 2 } }, result) eq({ 2, { 1, 1, 2, 2 } }, result)
end) end)