aboutsummaryrefslogtreecommitdiff
path: root/test/functional/plugin/lsp_spec.lua
diff options
context:
space:
mode:
Diffstat (limited to 'test/functional/plugin/lsp_spec.lua')
-rw-r--r--test/functional/plugin/lsp_spec.lua3807
1 files changed, 2118 insertions, 1689 deletions
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index c95a96baca..9956fdf628 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -33,12 +33,38 @@ local create_server_definition = t_lsp.create_server_definition
local fake_lsp_code = t_lsp.fake_lsp_code
local fake_lsp_logfile = t_lsp.fake_lsp_logfile
local test_rpc_server = t_lsp.test_rpc_server
+local create_tcp_echo_server = t_lsp.create_tcp_echo_server
local function get_buf_option(name, bufnr)
- bufnr = bufnr or 'BUFFER'
- return exec_lua(
- string.format("return vim.api.nvim_get_option_value('%s', { buf = %s })", name, bufnr)
+ return exec_lua(function()
+ bufnr = bufnr or _G.BUFFER
+ return vim.api.nvim_get_option_value(name, { buf = bufnr })
+ end)
+end
+
+local function make_edit(y_0, x_0, y_1, x_1, text)
+ return {
+ range = {
+ start = { line = y_0, character = x_0 },
+ ['end'] = { line = y_1, character = x_1 },
+ },
+ newText = type(text) == 'table' and table.concat(text, '\n') or (text or ''),
+ }
+end
+
+--- @param edits [integer, integer, integer, integer, string|string[]][]
+--- @param encoding? string
+local function apply_text_edits(edits, encoding)
+ local edits1 = vim.tbl_map(
+ --- @param edit [integer, integer, integer, integer, string|string[]]
+ function(edit)
+ return make_edit(unpack(edit))
+ end,
+ edits
)
+ exec_lua(function()
+ vim.lsp.util.apply_text_edits(edits1, 1, encoding or 'utf-16')
+ end)
end
-- TODO(justinmk): hangs on Windows https://github.com/neovim/neovim/pull/11837
@@ -46,111 +72,156 @@ if skip(is_os('win')) then
return
end
-teardown(function()
- os.remove(fake_lsp_logfile)
-end)
-
describe('LSP', function()
before_each(function()
clear_notrace()
-
- -- Run an instance of nvim on the file which contains our "scripts".
- -- Pass TEST_NAME to pick the script.
- local test_name = 'basic_init'
- exec_lua(
- [=[
- lsp = require('vim.lsp')
- local test_name, fake_lsp_code, fake_lsp_logfile = ...
- function test__start_client()
- return lsp.start_client {
- cmd_env = {
- NVIM_LOG_FILE = fake_lsp_logfile;
- NVIM_APPNAME = "nvim_lsp_test";
- };
- cmd = {
- vim.v.progpath, '-l', fake_lsp_code, test_name;
- };
- workspace_folders = {{
- uri = 'file://' .. vim.uv.cwd(),
- name = 'test_folder',
- }};
- }
- end
- TEST_CLIENT1 = test__start_client()
- ]=],
- test_name,
- fake_lsp_code,
- fake_lsp_logfile
- )
end)
after_each(function()
+ stop()
+ exec_lua('lsp.stop_client(lsp.get_clients(), true)')
api.nvim_exec_autocmds('VimLeavePre', { modeline = false })
- -- exec_lua("lsp.stop_all_clients(true)")
+ end)
+
+ teardown(function()
+ os.remove(fake_lsp_logfile)
end)
describe('server_name specified', function()
+ before_each(function()
+ -- Run an instance of nvim on the file which contains our "scripts".
+ -- Pass TEST_NAME to pick the script.
+ local test_name = 'basic_init'
+ exec_lua(function()
+ _G.lsp = require('vim.lsp')
+ function _G.test__start_client()
+ return vim.lsp.start_client {
+ cmd_env = {
+ NVIM_LOG_FILE = fake_lsp_logfile,
+ NVIM_APPNAME = 'nvim_lsp_test',
+ },
+ cmd = {
+ vim.v.progpath,
+ '-l',
+ fake_lsp_code,
+ test_name,
+ },
+ workspace_folders = {
+ {
+ uri = 'file://' .. vim.uv.cwd(),
+ name = 'test_folder',
+ },
+ },
+ }
+ end
+ _G.TEST_CLIENT1 = _G.test__start_client()
+ end)
+ end)
+
it('start_client(), stop_client()', function()
retry(nil, 4000, function()
- eq(1, exec_lua('return #lsp.get_clients()'))
+ eq(
+ 1,
+ exec_lua(function()
+ return #vim.lsp.get_clients()
+ end)
+ )
end)
eq(
2,
- exec_lua([[
- TEST_CLIENT2 = test__start_client()
- return TEST_CLIENT2
- ]])
+ exec_lua(function()
+ _G.TEST_CLIENT2 = _G.test__start_client()
+ return _G.TEST_CLIENT2
+ end)
)
eq(
3,
- exec_lua([[
- TEST_CLIENT3 = test__start_client()
- return TEST_CLIENT3
- ]])
+ exec_lua(function()
+ _G.TEST_CLIENT3 = _G.test__start_client()
+ return _G.TEST_CLIENT3
+ end)
)
retry(nil, 4000, function()
- eq(3, exec_lua('return #lsp.get_clients()'))
+ eq(
+ 3,
+ exec_lua(function()
+ return #vim.lsp.get_clients()
+ end)
+ )
end)
- eq(false, exec_lua('return lsp.get_client_by_id(TEST_CLIENT1) == nil'))
- eq(false, exec_lua('return lsp.get_client_by_id(TEST_CLIENT1).is_stopped()'))
- exec_lua('return lsp.get_client_by_id(TEST_CLIENT1).stop()')
+ eq(
+ false,
+ exec_lua(function()
+ return vim.lsp.get_client_by_id(_G.TEST_CLIENT1) == nil
+ end)
+ )
+ eq(
+ false,
+ exec_lua(function()
+ return vim.lsp.get_client_by_id(_G.TEST_CLIENT1).is_stopped()
+ end)
+ )
+ exec_lua(function()
+ return vim.lsp.get_client_by_id(_G.TEST_CLIENT1).stop()
+ end)
retry(nil, 4000, function()
- eq(2, exec_lua('return #lsp.get_clients()'))
+ eq(
+ 2,
+ exec_lua(function()
+ return #vim.lsp.get_clients()
+ end)
+ )
end)
- eq(true, exec_lua('return lsp.get_client_by_id(TEST_CLIENT1) == nil'))
+ eq(
+ true,
+ exec_lua(function()
+ return vim.lsp.get_client_by_id(_G.TEST_CLIENT1) == nil
+ end)
+ )
- exec_lua('lsp.stop_client({TEST_CLIENT2, TEST_CLIENT3})')
+ exec_lua(function()
+ vim.lsp.stop_client({ _G.TEST_CLIENT2, _G.TEST_CLIENT3 })
+ end)
retry(nil, 4000, function()
- eq(0, exec_lua('return #lsp.get_clients()'))
+ eq(
+ 0,
+ exec_lua(function()
+ return #vim.lsp.get_clients()
+ end)
+ )
end)
end)
it('stop_client() also works on client objects', function()
- exec_lua([[
- TEST_CLIENT2 = test__start_client()
- TEST_CLIENT3 = test__start_client()
- ]])
+ exec_lua(function()
+ _G.TEST_CLIENT2 = _G.test__start_client()
+ _G.TEST_CLIENT3 = _G.test__start_client()
+ end)
retry(nil, 4000, function()
- eq(3, exec_lua('return #lsp.get_clients()'))
+ eq(
+ 3,
+ exec_lua(function()
+ return #vim.lsp.get_clients()
+ end)
+ )
end)
-- Stop all clients.
- exec_lua('lsp.stop_client(lsp.get_clients())')
+ exec_lua(function()
+ vim.lsp.stop_client(vim.lsp.get_clients())
+ end)
retry(nil, 4000, function()
- eq(0, exec_lua('return #lsp.get_clients()'))
+ eq(
+ 0,
+ exec_lua(function()
+ return #vim.lsp.get_clients()
+ end)
+ )
end)
end)
end)
-end)
-describe('LSP', function()
describe('basic_init test', function()
- after_each(function()
- stop()
- exec_lua('lsp.stop_client(lsp.get_clients(), true)')
- api.nvim_exec_autocmds('VimLeavePre', { modeline = false })
- end)
-
it('should run correctly', function()
local expected_handlers = {
{ NIL, {}, { method = 'test', client_id = 1 } },
@@ -221,28 +292,28 @@ describe('LSP', function()
function()
clear()
exec_lua(create_server_definition)
- local result = exec_lua([[
- local server = _create_server({
- capabilities = {
- positionEncoding = "utf-8"
- },
- })
+ local result = exec_lua(function()
+ local server = _G._create_server({
+ capabilities = {
+ positionEncoding = 'utf-8',
+ },
+ })
- local client_id = vim.lsp.start({
- name = 'dummy',
- cmd = server.cmd,
- })
+ local client_id = vim.lsp.start({
+ name = 'dummy',
+ cmd = server.cmd,
+ })
- if not client_id then
- return 'vim.lsp.start did not return client_id'
- end
+ if not client_id then
+ return 'vim.lsp.start did not return client_id'
+ end
- local client = vim.lsp.get_client_by_id(client_id)
- if not client then
- return 'No client found with id ' .. client_id
- end
- return client.offset_encoding
- ]])
+ local client = vim.lsp.get_client_by_id(client_id)
+ if not client then
+ return 'No client found with id ' .. client_id
+ end
+ return client.offset_encoding
+ end)
eq('utf-8', result)
end
)
@@ -255,7 +326,7 @@ describe('LSP', function()
return
end
local expected_handlers = {
- { NIL, {}, { method = 'shutdown', bufnr = 1, client_id = 1 } },
+ { NIL, {}, { method = 'shutdown', bufnr = 1, client_id = 1, version = 0 } },
{ NIL, {}, { method = 'test', client_id = 1 } },
}
test_rpc_server {
@@ -285,14 +356,24 @@ describe('LSP', function()
test_rpc_server {
test_name = 'basic_finish',
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- ]]
- eq(true, exec_lua('return lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)'))
- eq(true, exec_lua('return lsp.buf_is_attached(BUFFER, TEST_RPC_CLIENT_ID)'))
- exec_lua [[
- vim.api.nvim_command(BUFFER.."bwipeout")
- ]]
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ end)
+ eq(
+ true,
+ exec_lua(function()
+ return vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
+ end)
+ )
+ eq(
+ true,
+ exec_lua(function()
+ return vim.lsp.buf_is_attached(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
+ end)
+ )
+ exec_lua(function()
+ vim.cmd(_G.BUFFER .. 'bwipeout')
+ end)
end,
on_init = function(_client)
client = _client
@@ -305,8 +386,15 @@ describe('LSP', function()
on_handler = function(err, result, ctx)
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'finish' then
- exec_lua('return lsp.buf_detach_client(BUFFER, TEST_RPC_CLIENT_ID)')
- eq(false, exec_lua('return lsp.buf_is_attached(BUFFER, TEST_RPC_CLIENT_ID)'))
+ exec_lua(function()
+ return vim.lsp.buf_detach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
+ end)
+ eq(
+ false,
+ exec_lua(function()
+ return vim.lsp.buf_is_attached(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
+ end)
+ )
client.stop()
end
end,
@@ -318,31 +406,38 @@ describe('LSP', function()
test_rpc_server {
test_name = 'basic_init',
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
vim.api.nvim_create_autocmd('LspAttach', {
callback = function(args)
- local client = vim.lsp.get_client_by_id(args.data.client_id)
- vim.g.lsp_attached = client.name
+ local client0 = assert(vim.lsp.get_client_by_id(args.data.client_id))
+ vim.g.lsp_attached = client0.name
end,
})
vim.api.nvim_create_autocmd('LspDetach', {
callback = function(args)
- local client = vim.lsp.get_client_by_id(args.data.client_id)
- vim.g.lsp_detached = client.name
+ local client0 = assert(vim.lsp.get_client_by_id(args.data.client_id))
+ vim.g.lsp_detached = client0.name
end,
})
- ]]
+ end)
end,
on_init = function(_client)
client = _client
- eq(true, exec_lua('return lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)'))
+ eq(
+ true,
+ exec_lua(function()
+ return vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
+ end)
+ )
client.notify('finish')
end,
on_handler = function(_, _, ctx)
if ctx.method == 'finish' then
eq('basic_init', api.nvim_get_var('lsp_attached'))
- exec_lua('return lsp.buf_detach_client(BUFFER, TEST_RPC_CLIENT_ID)')
+ exec_lua(function()
+ return vim.lsp.buf_detach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
+ end)
eq('basic_init', api.nvim_get_var('lsp_detached'))
client.stop()
end
@@ -356,10 +451,10 @@ describe('LSP', function()
test_name = 'set_defaults_all_capabilities',
on_init = function(_client)
client = _client
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)
- ]]
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
+ end)
end,
on_handler = function(_, _, ctx)
if ctx.method == 'test' then
@@ -369,13 +464,13 @@ describe('LSP', function()
eq('', get_buf_option('keywordprg'))
eq(
true,
- exec_lua [[
- local keymap
- vim.api.nvim_buf_call(BUFFER, function()
- keymap = vim.fn.maparg("K", "n", false, true)
+ exec_lua(function()
+ local keymap --- @type table<string,any>
+ vim._with({ buf = _G.BUFFER }, function()
+ keymap = vim.fn.maparg('K', 'n', false, true)
+ end)
+ return keymap.callback == vim.lsp.buf.hover
end)
- return keymap.callback == vim.lsp.buf.hover
- ]]
)
client.stop()
end
@@ -386,13 +481,13 @@ describe('LSP', function()
eq('', get_buf_option('formatexpr'))
eq(
'',
- exec_lua [[
- local keymap
- vim.api.nvim_buf_call(BUFFER, function()
- keymap = vim.fn.maparg("K", "n", false, false)
+ exec_lua(function()
+ local keymap --- @type string
+ vim._with({ buf = _G.BUFFER }, function()
+ keymap = vim.fn.maparg('K', 'n', false, false)
+ end)
+ return keymap
end)
- return keymap
- ]]
)
end,
}
@@ -400,40 +495,42 @@ describe('LSP', function()
it('should overwrite options set by ftplugins', function()
local client --- @type vim.lsp.Client
+ local BUFFER_1 --- @type integer
+ local BUFFER_2 --- @type integer
test_rpc_server {
test_name = 'set_defaults_all_capabilities',
on_init = function(_client)
client = _client
- exec_lua [[
+ exec_lua(function()
vim.api.nvim_command('filetype plugin on')
BUFFER_1 = vim.api.nvim_create_buf(false, true)
BUFFER_2 = vim.api.nvim_create_buf(false, true)
vim.api.nvim_set_option_value('filetype', 'man', { buf = BUFFER_1 })
vim.api.nvim_set_option_value('filetype', 'xml', { buf = BUFFER_2 })
- ]]
+ end)
-- Sanity check to ensure that some values are set after setting filetype.
- eq("v:lua.require'man'.goto_tag", get_buf_option('tagfunc', 'BUFFER_1'))
- eq('xmlcomplete#CompleteTags', get_buf_option('omnifunc', 'BUFFER_2'))
- eq('xmlformat#Format()', get_buf_option('formatexpr', 'BUFFER_2'))
+ eq("v:lua.require'man'.goto_tag", get_buf_option('tagfunc', BUFFER_1))
+ eq('xmlcomplete#CompleteTags', get_buf_option('omnifunc', BUFFER_2))
+ eq('xmlformat#Format()', get_buf_option('formatexpr', BUFFER_2))
- exec_lua [[
- lsp.buf_attach_client(BUFFER_1, TEST_RPC_CLIENT_ID)
- lsp.buf_attach_client(BUFFER_2, TEST_RPC_CLIENT_ID)
- ]]
+ exec_lua(function()
+ vim.lsp.buf_attach_client(BUFFER_1, _G.TEST_RPC_CLIENT_ID)
+ vim.lsp.buf_attach_client(BUFFER_2, _G.TEST_RPC_CLIENT_ID)
+ end)
end,
on_handler = function(_, _, ctx)
if ctx.method == 'test' then
- eq('v:lua.vim.lsp.tagfunc', get_buf_option('tagfunc', 'BUFFER_1'))
- eq('v:lua.vim.lsp.omnifunc', get_buf_option('omnifunc', 'BUFFER_2'))
- eq('v:lua.vim.lsp.formatexpr()', get_buf_option('formatexpr', 'BUFFER_2'))
+ eq('v:lua.vim.lsp.tagfunc', get_buf_option('tagfunc', BUFFER_1))
+ eq('v:lua.vim.lsp.omnifunc', get_buf_option('omnifunc', BUFFER_2))
+ eq('v:lua.vim.lsp.formatexpr()', get_buf_option('formatexpr', BUFFER_2))
client.stop()
end
end,
on_exit = function(_, _)
- eq('', get_buf_option('tagfunc', 'BUFFER_1'))
- eq('', get_buf_option('omnifunc', 'BUFFER_2'))
- eq('', get_buf_option('formatexpr', 'BUFFER_2'))
+ eq('', get_buf_option('tagfunc', BUFFER_1))
+ eq('', get_buf_option('omnifunc', BUFFER_2))
+ eq('', get_buf_option('formatexpr', BUFFER_2))
end,
}
end)
@@ -444,13 +541,13 @@ describe('LSP', function()
test_name = 'set_defaults_all_capabilities',
on_init = function(_client)
client = _client
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- vim.api.nvim_set_option_value('tagfunc', 'tfu', { buf = BUFFER })
- vim.api.nvim_set_option_value('omnifunc', 'ofu', { buf = BUFFER })
- vim.api.nvim_set_option_value('formatexpr', 'fex', { buf = BUFFER })
- lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)
- ]]
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_set_option_value('tagfunc', 'tfu', { buf = _G.BUFFER })
+ vim.api.nvim_set_option_value('omnifunc', 'ofu', { buf = _G.BUFFER })
+ vim.api.nvim_set_option_value('formatexpr', 'fex', { buf = _G.BUFFER })
+ vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
+ end)
end,
on_handler = function(_, _, ctx)
if ctx.method == 'test' then
@@ -471,19 +568,19 @@ describe('LSP', function()
it('should detach buffer on bufwipe', function()
clear()
exec_lua(create_server_definition)
- local result = exec_lua([[
- local server = _create_server()
+ local result = exec_lua(function()
+ local server = _G._create_server()
local bufnr = vim.api.nvim_create_buf(false, true)
vim.api.nvim_set_current_buf(bufnr)
local detach_called = false
- vim.api.nvim_create_autocmd("LspDetach", {
+ vim.api.nvim_create_autocmd('LspDetach', {
callback = function()
detach_called = true
- end
+ end,
})
local client_id = vim.lsp.start({ name = 'detach-dummy', cmd = server.cmd })
- assert(client_id, "lsp.start must return client_id")
- local client = vim.lsp.get_client_by_id(client_id)
+ assert(client_id, 'lsp.start must return client_id')
+ local client = assert(vim.lsp.get_client_by_id(client_id))
local num_attached_before = vim.tbl_count(client.attached_buffers)
vim.api.nvim_buf_delete(bufnr, { force = true })
local num_attached_after = vim.tbl_count(client.attached_buffers)
@@ -494,7 +591,7 @@ describe('LSP', function()
num_attached_after = num_attached_after,
detach_called = detach_called,
}
- ]])
+ end)
eq(true, result ~= nil, 'exec_lua must return result')
eq(1, result.num_attached_before)
eq(0, result.num_attached_after)
@@ -504,30 +601,62 @@ describe('LSP', function()
it('should not re-attach buffer if it was deleted in on_init #28575', function()
clear()
exec_lua(create_server_definition)
- exec_lua([[
- local server = _create_server({
+ exec_lua(function()
+ local server = _G._create_server({
handlers = {
- initialize = function(method, params, callback)
+ initialize = function(_, _, callback)
vim.schedule(function()
callback(nil, { capabilities = {} })
end)
- end
- }
+ end,
+ },
})
local bufnr = vim.api.nvim_create_buf(false, true)
local on_init_called = false
- local client_id = vim.lsp.start({
+ local client_id = assert(vim.lsp.start({
name = 'detach-dummy',
cmd = server.cmd,
on_init = function()
vim.api.nvim_buf_delete(bufnr, {})
on_init_called = true
- end
- })
+ end,
+ }))
vim.lsp.buf_attach_client(bufnr, client_id)
- local ok = vim.wait(1000, function() return on_init_called end)
- assert(ok, "on_init was not called")
- ]])
+ local ok = vim.wait(1000, function()
+ return on_init_called
+ end)
+ assert(ok, 'on_init was not called')
+ end)
+ end)
+
+ it('should allow on_lines + nvim_buf_delete during LSP initialization #28575', function()
+ clear()
+ exec_lua(create_server_definition)
+ exec_lua(function()
+ local initialized = false
+ local server = _G._create_server({
+ handlers = {
+ initialize = function(_, _, callback)
+ vim.schedule(function()
+ callback(nil, { capabilities = {} })
+ initialized = true
+ end)
+ end,
+ },
+ })
+ local bufnr = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_set_current_buf(bufnr)
+ vim.lsp.start({
+ name = 'detach-dummy',
+ cmd = server.cmd,
+ })
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { 'hello' })
+ vim.api.nvim_buf_delete(bufnr, {})
+ local ok = vim.wait(1000, function()
+ return initialized
+ end)
+ assert(ok, 'lsp did not initialize')
+ end)
end)
it('client should return settings via workspace/configuration handler', function()
@@ -560,19 +689,25 @@ describe('LSP', function()
on_handler = function(err, result, ctx)
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'start' then
- exec_lua([=[
- local client = vim.lsp.get_client_by_id(TEST_RPC_CLIENT_ID)
- client.settings = {
- testSetting1 = true;
- testSetting2 = false;
- test = {Setting3 = 'nested' };
- }]=])
+ exec_lua(function()
+ local client0 = vim.lsp.get_client_by_id(_G.TEST_RPC_CLIENT_ID)
+ client0.settings = {
+ testSetting1 = true,
+ testSetting2 = false,
+ test = { Setting3 = 'nested' },
+ }
+ end)
end
if ctx.method == 'workspace/configuration' then
local server_result = exec_lua(
- [=[
+ [[
local method, params = ...
- return require'vim.lsp.handlers'['workspace/configuration'](err, params, {method=method, client_id=TEST_RPC_CLIENT_ID})]=],
+ return require 'vim.lsp.handlers'['workspace/configuration'](
+ err,
+ params,
+ { method = method, client_id = _G.TEST_RPC_CLIENT_ID }
+ )
+ ]],
ctx.method,
result
)
@@ -584,6 +719,7 @@ describe('LSP', function()
end,
}
end)
+
it(
'workspace/configuration returns NIL per section if client was started without config.settings',
function()
@@ -594,15 +730,19 @@ describe('LSP', function()
c.stop()
end,
on_setup = function()
- result = exec_lua [[
- local result = {
- items = {
- {section = 'foo'},
- {section = 'bar'},
+ result = exec_lua(function()
+ local result0 = {
+ items = {
+ { section = 'foo' },
+ { section = 'bar' },
+ },
}
- }
- return vim.lsp.handlers['workspace/configuration'](nil, result, {client_id=TEST_RPC_CLIENT_ID})
- ]]
+ return vim.lsp.handlers['workspace/configuration'](
+ nil,
+ result0,
+ { client_id = _G.TEST_RPC_CLIENT_ID }
+ )
+ end)
end,
}
eq({ NIL, NIL }, result)
@@ -617,7 +757,9 @@ describe('LSP', function()
test_name = 'basic_check_capabilities',
on_init = function(client)
client.stop()
- local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
+ local full_kind = exec_lua(function()
+ return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full
+ end)
eq(full_kind, client.server_capabilities().textDocumentSync.change)
eq({ includeText = false }, client.server_capabilities().textDocumentSync.save)
eq(false, client.server_capabilities().codeLensProvider)
@@ -650,11 +792,11 @@ describe('LSP', function()
on_handler = function(err, result, ctx)
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'start' then
- exec_lua([=[
- BUFFER = vim.api.nvim_get_current_buf()
- lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)
- vim.api.nvim_exec_autocmds('BufWritePost', { buffer = BUFFER, modeline = false })
- ]=])
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_get_current_buf()
+ vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
+ vim.api.nvim_exec_autocmds('BufWritePost', { buffer = _G.BUFFER, modeline = false })
+ end)
else
client.stop()
end
@@ -665,21 +807,21 @@ describe('LSP', function()
it('BufWritePre does not send notifications if server lacks willSave capabilities', function()
clear()
exec_lua(create_server_definition)
- local messages = exec_lua([[
- local server = _create_server({
+ local messages = exec_lua(function()
+ local server = _G._create_server({
capabilities = {
textDocumentSync = {
willSave = false,
willSaveWaitUntil = false,
- }
+ },
},
})
- local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
+ local client_id = assert(vim.lsp.start({ name = 'dummy', cmd = server.cmd }))
local buf = vim.api.nvim_get_current_buf()
vim.api.nvim_exec_autocmds('BufWritePre', { buffer = buf, modeline = false })
vim.lsp.stop_client(client_id)
return server.messages
- ]])
+ end)
eq(4, #messages)
eq('initialize', messages[1].method)
eq('initialized', messages[2].method)
@@ -690,13 +832,13 @@ describe('LSP', function()
it('BufWritePre sends willSave / willSaveWaitUntil, applies textEdits', function()
clear()
exec_lua(create_server_definition)
- local result = exec_lua([[
- local server = _create_server({
+ local result = exec_lua(function()
+ local server = _G._create_server({
capabilities = {
textDocumentSync = {
willSave = true,
willSaveWaitUntil = true,
- }
+ },
},
handlers = {
['textDocument/willSaveWaitUntil'] = function(_, _, callback)
@@ -705,21 +847,21 @@ describe('LSP', function()
start = { line = 0, character = 0 },
['end'] = { line = 0, character = 0 },
},
- newText = 'Hello'
+ newText = 'Hello',
}
- callback(nil, { text_edit, })
- end
+ callback(nil, { text_edit })
+ end,
},
})
local buf = vim.api.nvim_get_current_buf()
- local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
+ local client_id = assert(vim.lsp.start({ name = 'dummy', cmd = server.cmd }))
vim.api.nvim_exec_autocmds('BufWritePre', { buffer = buf, modeline = false })
vim.lsp.stop_client(client_id)
return {
messages = server.messages,
- lines = vim.api.nvim_buf_get_lines(buf, 0, -1, true)
+ lines = vim.api.nvim_buf_get_lines(buf, 0, -1, true),
}
- ]])
+ end)
local messages = result.messages
eq('textDocument/willSave', messages[3].method)
eq('textDocument/willSaveWaitUntil', messages[4].method)
@@ -745,20 +887,16 @@ describe('LSP', function()
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'start' then
local tmpfile_old = tmpname()
- local tmpfile_new = tmpname()
- os.remove(tmpfile_new)
- exec_lua(
- [=[
- local oldname, newname = ...
- BUFFER = vim.api.nvim_get_current_buf()
- vim.api.nvim_buf_set_name(BUFFER, oldname)
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, true, {"help me"})
- lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)
- vim.api.nvim_buf_call(BUFFER, function() vim.cmd('saveas ' .. newname) end)
- ]=],
- tmpfile_old,
- tmpfile_new
- )
+ local tmpfile_new = tmpname(false)
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_get_current_buf()
+ vim.api.nvim_buf_set_name(_G.BUFFER, tmpfile_old)
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, true, { 'help me' })
+ vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
+ vim._with({ buf = _G.BUFFER }, function()
+ vim.cmd('saveas ' .. tmpfile_new)
+ end)
+ end)
else
client.stop()
end
@@ -784,12 +922,12 @@ describe('LSP', function()
on_handler = function(err, result, ctx)
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'start' then
- exec_lua([=[
- BUFFER = vim.api.nvim_get_current_buf()
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, true, {"help me"})
- lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)
- vim.api.nvim_exec_autocmds('BufWritePost', { buffer = BUFFER, modeline = false })
- ]=])
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_get_current_buf()
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, true, { 'help me' })
+ vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
+ vim.api.nvim_exec_autocmds('BufWritePost', { buffer = _G.BUFFER, modeline = false })
+ end)
else
client.stop()
end
@@ -843,16 +981,18 @@ describe('LSP', function()
test_rpc_server {
test_name = 'capabilities_for_client_supports_method',
on_setup = function()
- exec_lua([=[
- BUFFER = vim.api.nvim_get_current_buf()
- lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)
- vim.lsp.handlers['textDocument/typeDefinition'] = function() end
- vim.cmd(BUFFER.."bwipeout")
- ]=])
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_get_current_buf()
+ vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
+ vim.lsp.handlers['textDocument/typeDefinition'] = function() end
+ vim.cmd(_G.BUFFER .. 'bwipeout')
+ end)
end,
on_init = function(client)
client.stop()
- exec_lua('vim.lsp.buf.type_definition()')
+ exec_lua(function()
+ vim.lsp.buf.type_definition()
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -873,13 +1013,15 @@ describe('LSP', function()
test_rpc_server {
test_name = 'capabilities_for_client_supports_method',
on_setup = function()
- exec_lua([=[
+ exec_lua(function()
vim.lsp.handlers['textDocument/typeDefinition'] = function() end
- ]=])
+ end)
end,
on_init = function(client)
client.stop()
- exec_lua('vim.lsp.buf.type_definition()')
+ exec_lua(function()
+ vim.lsp.buf.type_definition()
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -920,7 +1062,11 @@ describe('LSP', function()
it('should forward ContentModified to callback', function()
local expected_handlers = {
{ NIL, {}, { method = 'finish', client_id = 1 } },
- { { code = -32801 }, NIL, { method = 'error_code_test', bufnr = 1, client_id = 1 } },
+ {
+ { code = -32801 },
+ NIL,
+ { method = 'error_code_test', bufnr = 1, client_id = 1, version = 0 },
+ },
}
local client --- @type vim.lsp.Client
test_rpc_server {
@@ -950,7 +1096,7 @@ describe('LSP', function()
it('should track pending requests to the language server', function()
local expected_handlers = {
{ NIL, {}, { method = 'finish', client_id = 1 } },
- { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1 } },
+ { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1, version = 0 } },
}
local client --- @type vim.lsp.Client
test_rpc_server {
@@ -958,7 +1104,9 @@ describe('LSP', function()
on_init = function(_client)
client = _client
client.request('slow_request')
- local request = exec_lua([=[ return TEST_RPC_CLIENT.requests[2] ]=])
+ local request = exec_lua(function()
+ return _G.TEST_RPC_CLIENT.requests[2]
+ end)
eq('slow_request', request.method)
eq('pending', request.type)
client.notify('release')
@@ -971,8 +1119,10 @@ describe('LSP', function()
on_handler = function(err, _, ctx)
eq(table.remove(expected_handlers), { err, {}, ctx }, 'expected handler')
if ctx.method == 'slow_request' then
- local request = exec_lua([=[ return TEST_RPC_CLIENT.requests[2] ]=])
- eq(NIL, request)
+ local request = exec_lua(function()
+ return _G.TEST_RPC_CLIENT.requests[2]
+ end)
+ eq(nil, request)
client.notify('finish')
end
if ctx.method == 'finish' then
@@ -993,7 +1143,9 @@ describe('LSP', function()
client = _client
client.request('slow_request')
client.cancel_request(2)
- local request = exec_lua([=[ return TEST_RPC_CLIENT.requests[2] ]=])
+ local request = exec_lua(function()
+ return _G.TEST_RPC_CLIENT.requests[2]
+ end)
eq('slow_request', request.method)
eq('cancel', request.type)
client.notify('release')
@@ -1005,8 +1157,10 @@ describe('LSP', function()
end,
on_handler = function(err, _, ctx)
eq(table.remove(expected_handlers), { err, {}, ctx }, 'expected handler')
- local request = exec_lua([=[ return TEST_RPC_CLIENT.requests[2] ]=])
- eq(NIL, request)
+ local request = exec_lua(function()
+ return _G.TEST_RPC_CLIENT.requests[2]
+ end)
+ eq(nil, request)
if ctx.method == 'finish' then
client.stop()
end
@@ -1017,7 +1171,7 @@ describe('LSP', function()
it('should clear pending and cancel requests on reply', function()
local expected_handlers = {
{ NIL, {}, { method = 'finish', client_id = 1 } },
- { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1 } },
+ { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1, version = 0 } },
}
local client --- @type vim.lsp.Client
test_rpc_server {
@@ -1025,11 +1179,15 @@ describe('LSP', function()
on_init = function(_client)
client = _client
client.request('slow_request')
- local request = exec_lua([=[ return TEST_RPC_CLIENT.requests[2] ]=])
+ local request = exec_lua(function()
+ return _G.TEST_RPC_CLIENT.requests[2]
+ end)
eq('slow_request', request.method)
eq('pending', request.type)
client.cancel_request(2)
- request = exec_lua([=[ return TEST_RPC_CLIENT.requests[2] ]=])
+ request = exec_lua(function()
+ return _G.TEST_RPC_CLIENT.requests[2]
+ end)
eq('slow_request', request.method)
eq('cancel', request.type)
client.notify('release')
@@ -1042,8 +1200,10 @@ describe('LSP', function()
on_handler = function(err, _, ctx)
eq(table.remove(expected_handlers), { err, {}, ctx }, 'expected handler')
if ctx.method == 'slow_request' then
- local request = exec_lua([=[ return TEST_RPC_CLIENT.requests[2] ]=])
- eq(NIL, request)
+ local request = exec_lua(function()
+ return _G.TEST_RPC_CLIENT.requests[2]
+ end)
+ eq(nil, request)
client.notify('finish')
end
if ctx.method == 'finish' then
@@ -1056,7 +1216,7 @@ describe('LSP', function()
it('should trigger LspRequest autocmd when requests table changes', function()
local expected_handlers = {
{ NIL, {}, { method = 'finish', client_id = 1 } },
- { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1 } },
+ { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1, version = 0 } },
}
local client --- @type vim.lsp.Client
test_rpc_server {
@@ -1098,21 +1258,23 @@ describe('LSP', function()
test_rpc_server {
test_name = 'basic_finish',
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, {
- "testing";
- "123";
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, {
+ 'testing',
+ '123',
})
- assert(TEST_RPC_CLIENT_ID == 1)
- assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
- assert(lsp.buf_is_attached(BUFFER, TEST_RPC_CLIENT_ID))
- vim.cmd(BUFFER.."bwipeout")
- ]]
+ assert(_G.TEST_RPC_CLIENT_ID == 1)
+ assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
+ assert(vim.lsp.buf_is_attached(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
+ vim.cmd(_G.BUFFER .. 'bwipeout')
+ end)
end,
on_init = function(_client)
client = _client
- local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
+ local full_kind = exec_lua(function()
+ return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full
+ end)
eq(full_kind, client.server_capabilities().textDocumentSync.change)
eq(true, client.server_capabilities().textDocumentSync.openClose)
client.notify('finish')
@@ -1140,25 +1302,30 @@ describe('LSP', function()
test_rpc_server {
test_name = 'basic_check_buffer_open',
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, {
- "testing";
- "123";
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, {
+ 'testing',
+ '123',
})
- ]]
- exec_lua [[
- assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
- ]]
+ end)
+ exec_lua(function()
+ assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
+ end)
end,
on_init = function(_client)
client = _client
- local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
+ local full_kind = exec_lua(function()
+ return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full
+ end)
eq(full_kind, client.server_capabilities().textDocumentSync.change)
eq(true, client.server_capabilities().textDocumentSync.openClose)
- exec_lua [[
- assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID), "Already attached, returns true")
- ]]
+ exec_lua(function()
+ assert(
+ vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID),
+ 'Already attached, returns true'
+ )
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1186,22 +1353,24 @@ describe('LSP', function()
test_rpc_server {
test_name = 'basic_check_buffer_open',
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, {
- "testing";
- "123";
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, {
+ 'testing',
+ '123',
})
- ]]
+ end)
end,
on_init = function(_client)
client = _client
- local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
+ local full_kind = exec_lua(function()
+ return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full
+ end)
eq(full_kind, client.server_capabilities().textDocumentSync.change)
eq(true, client.server_capabilities().textDocumentSync.openClose)
- exec_lua [[
- assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
- ]]
+ exec_lua(function()
+ assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1229,22 +1398,24 @@ describe('LSP', function()
test_rpc_server {
test_name = 'basic_check_buffer_open_and_change',
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, {
- "testing";
- "123";
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, {
+ 'testing',
+ '123',
})
- ]]
+ end)
end,
on_init = function(_client)
client = _client
- local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
+ local full_kind = exec_lua(function()
+ return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full
+ end)
eq(full_kind, client.server_capabilities().textDocumentSync.change)
eq(true, client.server_capabilities().textDocumentSync.openClose)
- exec_lua [[
- assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
- ]]
+ exec_lua(function()
+ assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1252,11 +1423,11 @@ describe('LSP', function()
end,
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
- exec_lua [[
- vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, {
- "boop";
+ exec_lua(function()
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 1, 2, false, {
+ 'boop',
})
- ]]
+ end)
client.notify('finish')
end
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
@@ -1277,23 +1448,25 @@ describe('LSP', function()
test_rpc_server {
test_name = 'basic_check_buffer_open_and_change_noeol',
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, {
- "testing";
- "123";
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, {
+ 'testing',
+ '123',
})
- vim.bo[BUFFER].eol = false
- ]]
+ vim.bo[_G.BUFFER].eol = false
+ end)
end,
on_init = function(_client)
client = _client
- local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
+ local full_kind = exec_lua(function()
+ return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full
+ end)
eq(full_kind, client.server_capabilities().textDocumentSync.change)
eq(true, client.server_capabilities().textDocumentSync.openClose)
- exec_lua [[
- assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
- ]]
+ exec_lua(function()
+ assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1301,11 +1474,11 @@ describe('LSP', function()
end,
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
- exec_lua [[
- vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, {
- "boop";
+ exec_lua(function()
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 1, 2, false, {
+ 'boop',
})
- ]]
+ end)
client.notify('finish')
end
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
@@ -1336,6 +1509,7 @@ describe('LSP', function()
},
bufnr = 2,
client_id = 1,
+ version = 0,
},
},
{ NIL, {}, { method = 'start', client_id = 1 } },
@@ -1344,21 +1518,21 @@ describe('LSP', function()
test_rpc_server {
test_name = 'inlay_hint',
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, {
- "testing";
- "123";
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, {
+ 'testing',
+ '123',
})
- vim.bo[BUFFER].eol = false
- ]]
+ vim.bo[_G.BUFFER].eol = false
+ end)
end,
on_init = function(_client)
client = _client
eq(true, client.supports_method('textDocument/inlayHint'))
- exec_lua [[
- assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
- ]]
+ exec_lua(function()
+ assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1366,9 +1540,9 @@ describe('LSP', function()
end,
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
- exec_lua [[
- vim.lsp.inlay_hint.enable(true, { bufnr = BUFFER })
- ]]
+ exec_lua(function()
+ vim.lsp.inlay_hint.enable(true, { bufnr = _G.BUFFER })
+ end)
end
if ctx.method == 'textDocument/inlayHint' then
client.notify('finish')
@@ -1394,23 +1568,24 @@ describe('LSP', function()
allow_incremental_sync = true,
},
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, {
- "testing";
- "123";
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, {
+ 'testing',
+ '123',
})
- ]]
+ end)
end,
on_init = function(_client)
client = _client
- local sync_kind =
- exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Incremental")
+ local sync_kind = exec_lua(function()
+ return require 'vim.lsp.protocol'.TextDocumentSyncKind.Incremental
+ end)
eq(sync_kind, client.server_capabilities().textDocumentSync.change)
eq(true, client.server_capabilities().textDocumentSync.openClose)
- exec_lua [[
- assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
- ]]
+ exec_lua(function()
+ assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1418,11 +1593,11 @@ describe('LSP', function()
end,
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
- exec_lua [[
- vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, {
- "123boop";
+ exec_lua(function()
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 1, 2, false, {
+ '123boop',
})
- ]]
+ end)
client.notify('finish')
end
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
@@ -1432,6 +1607,7 @@ describe('LSP', function()
end,
}
end)
+
it('should check the body and didChange incremental with debounce', function()
local expected_handlers = {
{ NIL, {}, { method = 'shutdown', client_id = 1 } },
@@ -1446,23 +1622,24 @@ describe('LSP', function()
debounce_text_changes = 5,
},
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, {
- "testing";
- "123";
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, {
+ 'testing',
+ '123',
})
- ]]
+ end)
end,
on_init = function(_client)
client = _client
- local sync_kind =
- exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Incremental")
+ local sync_kind = exec_lua(function()
+ return require 'vim.lsp.protocol'.TextDocumentSyncKind.Incremental
+ end)
eq(sync_kind, client.server_capabilities().textDocumentSync.change)
eq(true, client.server_capabilities().textDocumentSync.openClose)
- exec_lua [[
- assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
- ]]
+ exec_lua(function()
+ assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1470,11 +1647,11 @@ describe('LSP', function()
end,
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
- exec_lua [[
- vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, {
- "123boop";
+ exec_lua(function()
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 1, 2, false, {
+ '123boop',
})
- ]]
+ end)
client.notify('finish')
end
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
@@ -1496,23 +1673,24 @@ describe('LSP', function()
test_rpc_server {
test_name = 'basic_check_buffer_open_and_change_incremental_editing',
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, {
- "testing";
- "123";
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, {
+ 'testing',
+ '123',
})
- ]]
+ end)
end,
on_init = function(_client)
client = _client
- local sync_kind =
- exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Incremental")
+ local sync_kind = exec_lua(function()
+ return require 'vim.lsp.protocol'.TextDocumentSyncKind.Incremental
+ end)
eq(sync_kind, client.server_capabilities().textDocumentSync.change)
eq(true, client.server_capabilities().textDocumentSync.openClose)
- exec_lua [[
- assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
- ]]
+ exec_lua(function()
+ assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1541,22 +1719,24 @@ describe('LSP', function()
test_rpc_server {
test_name = 'basic_check_buffer_open_and_change_multi',
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, {
- "testing";
- "123";
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, {
+ 'testing',
+ '123',
})
- ]]
+ end)
end,
on_init = function(_client)
client = _client
- local sync_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
+ local sync_kind = exec_lua(function()
+ return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full
+ end)
eq(sync_kind, client.server_capabilities().textDocumentSync.change)
eq(true, client.server_capabilities().textDocumentSync.openClose)
- exec_lua [[
- assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
- ]]
+ exec_lua(function()
+ assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1564,14 +1744,14 @@ describe('LSP', function()
end,
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
- exec_lua [[
- vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, {
- "321";
+ exec_lua(function()
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 1, 2, false, {
+ '321',
})
- vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, {
- "boop";
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 1, 2, false, {
+ 'boop',
})
- ]]
+ end)
client.notify('finish')
end
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
@@ -1592,22 +1772,24 @@ describe('LSP', function()
test_rpc_server {
test_name = 'basic_check_buffer_open_and_change_multi_and_close',
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, {
- "testing";
- "123";
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, {
+ 'testing',
+ '123',
})
- ]]
+ end)
end,
on_init = function(_client)
client = _client
- local sync_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
+ local sync_kind = exec_lua(function()
+ return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full
+ end)
eq(sync_kind, client.server_capabilities().textDocumentSync.change)
eq(true, client.server_capabilities().textDocumentSync.openClose)
- exec_lua [[
- assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
- ]]
+ exec_lua(function()
+ assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1615,15 +1797,15 @@ describe('LSP', function()
end,
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
- exec_lua [[
- vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, {
- "321";
+ exec_lua(function()
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 1, 2, false, {
+ '321',
})
- vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, {
- "boop";
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 1, 2, false, {
+ 'boop',
})
- vim.api.nvim_command(BUFFER.."bwipeout")
- ]]
+ vim.api.nvim_command(_G.BUFFER .. 'bwipeout')
+ end)
client.notify('finish')
end
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
@@ -1679,19 +1861,19 @@ describe('LSP', function()
test_rpc_server {
test_name = 'decode_nil',
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, {
- "testing";
- "123";
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, {
+ 'testing',
+ '123',
})
- ]]
+ end)
end,
on_init = function(_client)
client = _client
- exec_lua [[
- assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
- ]]
+ exec_lua(function()
+ assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1706,22 +1888,58 @@ describe('LSP', function()
}
end)
end)
-end)
-describe('LSP', function()
- before_each(function()
- clear_notrace()
- end)
+ describe('apply vscode text_edits', function()
+ it('single replace', function()
+ insert('012345678901234567890123456789')
+ apply_text_edits({
+ { 0, 3, 0, 6, { 'Hello' } },
+ })
+ eq({ '012Hello678901234567890123456789' }, buf_lines(1))
+ end)
- local function make_edit(y_0, x_0, y_1, x_1, text)
- return {
- range = {
- start = { line = y_0, character = x_0 },
- ['end'] = { line = y_1, character = x_1 },
- },
- newText = type(text) == 'table' and table.concat(text, '\n') or (text or ''),
- }
- end
+ it('two replaces', function()
+ insert('012345678901234567890123456789')
+ apply_text_edits({
+ { 0, 3, 0, 6, { 'Hello' } },
+ { 0, 6, 0, 9, { 'World' } },
+ })
+ eq({ '012HelloWorld901234567890123456789' }, buf_lines(1))
+ end)
+
+ it('same start pos insert are kept in order', function()
+ insert('012345678901234567890123456789')
+ apply_text_edits({
+ { 0, 3, 0, 3, { 'World' } },
+ { 0, 3, 0, 3, { 'Hello' } },
+ })
+ eq({ '012WorldHello345678901234567890123456789' }, buf_lines(1))
+ end)
+
+ it('same start pos insert and replace are kept in order', function()
+ insert('012345678901234567890123456789')
+ apply_text_edits({
+ { 0, 3, 0, 3, { 'World' } },
+ { 0, 3, 0, 3, { 'Hello' } },
+ { 0, 3, 0, 8, { 'No' } },
+ })
+ eq({ '012WorldHelloNo8901234567890123456789' }, buf_lines(1))
+ end)
+
+ it('multiline', function()
+ exec_lua(function()
+ vim.api.nvim_buf_set_lines(1, 0, 0, true, { ' {', ' "foo": "bar"', ' }' })
+ end)
+ eq({ ' {', ' "foo": "bar"', ' }', '' }, buf_lines(1))
+ apply_text_edits({
+ { 0, 0, 3, 0, { '' } },
+ { 3, 0, 3, 0, { '{\n' } },
+ { 3, 0, 3, 0, { ' "foo": "bar"\n' } },
+ { 3, 0, 3, 0, { '}\n' } },
+ })
+ eq({ '{', ' "foo": "bar"', '}', '' }, buf_lines(1))
+ end)
+ end)
describe('apply_text_edits', function()
before_each(function()
@@ -1732,14 +1950,14 @@ describe('LSP', function()
Fourth line of text
å å ɧ 汉语 ↥ 🤦 🦄]]))
end)
+
it('applies simple edits', function()
- local edits = {
- make_edit(0, 0, 0, 0, { '123' }),
- make_edit(1, 0, 1, 1, { '2' }),
- make_edit(2, 0, 2, 2, { '3' }),
- make_edit(3, 2, 3, 4, { '' }),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 0, 0, 0, 0, { '123' } },
+ { 1, 0, 1, 1, { '2' } },
+ { 2, 0, 2, 2, { '3' } },
+ { 3, 2, 3, 4, { '' } },
+ })
eq({
'123First line of text',
'2econd line of text',
@@ -1748,18 +1966,18 @@ describe('LSP', function()
'å å ɧ 汉语 ↥ 🤦 🦄',
}, buf_lines(1))
end)
+
it('applies complex edits', function()
- local edits = {
- make_edit(0, 0, 0, 0, { '', '12' }),
- make_edit(0, 0, 0, 0, { '3', 'foo' }),
- make_edit(0, 1, 0, 1, { 'bar', '123' }),
- make_edit(0, #'First ', 0, #'First line of text', { 'guy' }),
- make_edit(1, 0, 1, #'Second', { 'baz' }),
- make_edit(2, #'Th', 2, #'Third', { 'e next' }),
- make_edit(3, #'', 3, #'Fourth', { 'another line of text', 'before this' }),
- make_edit(3, #'Fourth', 3, #'Fourth line of text', { '!' }),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 0, 0, 0, 0, { '', '12' } },
+ { 0, 0, 0, 0, { '3', 'foo' } },
+ { 0, 1, 0, 1, { 'bar', '123' } },
+ { 0, #'First ', 0, #'First line of text', { 'guy' } },
+ { 1, 0, 1, #'Second', { 'baz' } },
+ { 2, #'Th', 2, #'Third', { 'e next' } },
+ { 3, #'', 3, #'Fourth', { 'another line of text', 'before this' } },
+ { 3, #'Fourth', 3, #'Fourth line of text', { '!' } },
+ })
eq({
'',
'123',
@@ -1772,18 +1990,18 @@ describe('LSP', function()
'å å ɧ 汉语 ↥ 🤦 🦄',
}, buf_lines(1))
end)
+
it('applies complex edits (reversed range)', function()
- local edits = {
- make_edit(0, 0, 0, 0, { '', '12' }),
- make_edit(0, 0, 0, 0, { '3', 'foo' }),
- make_edit(0, 1, 0, 1, { 'bar', '123' }),
- make_edit(0, #'First line of text', 0, #'First ', { 'guy' }),
- make_edit(1, #'Second', 1, 0, { 'baz' }),
- make_edit(2, #'Third', 2, #'Th', { 'e next' }),
- make_edit(3, #'Fourth', 3, #'', { 'another line of text', 'before this' }),
- make_edit(3, #'Fourth line of text', 3, #'Fourth', { '!' }),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 0, 0, 0, 0, { '', '12' } },
+ { 0, 0, 0, 0, { '3', 'foo' } },
+ { 0, 1, 0, 1, { 'bar', '123' } },
+ { 0, #'First line of text', 0, #'First ', { 'guy' } },
+ { 1, #'Second', 1, 0, { 'baz' } },
+ { 2, #'Third', 2, #'Th', { 'e next' } },
+ { 3, #'Fourth', 3, #'', { 'another line of text', 'before this' } },
+ { 3, #'Fourth line of text', 3, #'Fourth', { '!' } },
+ })
eq({
'',
'123',
@@ -1796,11 +2014,11 @@ describe('LSP', function()
'å å ɧ 汉语 ↥ 🤦 🦄',
}, buf_lines(1))
end)
+
it('applies non-ASCII characters edits', function()
- local edits = {
- make_edit(4, 3, 4, 4, { 'ä' }),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 4, 3, 4, 4, { 'ä' } },
+ })
eq({
'First line of text',
'Second line of text',
@@ -1809,11 +2027,11 @@ describe('LSP', function()
'å ä ɧ 汉语 ↥ 🤦 🦄',
}, buf_lines(1))
end)
+
it('applies text edits at the end of the document', function()
- local edits = {
- make_edit(5, 0, 5, 0, 'foobar'),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 5, 0, 5, 0, 'foobar' },
+ })
eq({
'First line of text',
'Second line of text',
@@ -1823,12 +2041,12 @@ describe('LSP', function()
'foobar',
}, buf_lines(1))
end)
+
it('applies multiple text edits at the end of the document', function()
- local edits = {
- make_edit(4, 0, 5, 0, ''),
- make_edit(5, 0, 5, 0, 'foobar'),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 4, 0, 5, 0, '' },
+ { 5, 0, 5, 0, 'foobar' },
+ })
eq({
'First line of text',
'Second line of text',
@@ -1837,62 +2055,56 @@ describe('LSP', function()
'foobar',
}, buf_lines(1))
end)
+
it('it restores marks', function()
- local edits = {
- make_edit(1, 0, 2, 5, 'foobar'),
- make_edit(4, 0, 5, 0, 'barfoo'),
- }
eq(true, api.nvim_buf_set_mark(1, 'a', 2, 1, {}))
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 1, 0, 2, 5, 'foobar' },
+ { 4, 0, 5, 0, 'barfoo' },
+ })
eq({
'First line of text',
'foobar line of text',
'Fourth line of text',
'barfoo',
}, buf_lines(1))
- local mark = api.nvim_buf_get_mark(1, 'a')
- eq({ 2, 1 }, mark)
+ eq({ 2, 1 }, api.nvim_buf_get_mark(1, 'a'))
end)
it('it restores marks to last valid col', function()
- local edits = {
- make_edit(1, 0, 2, 15, 'foobar'),
- make_edit(4, 0, 5, 0, 'barfoo'),
- }
eq(true, api.nvim_buf_set_mark(1, 'a', 2, 10, {}))
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 1, 0, 2, 15, 'foobar' },
+ { 4, 0, 5, 0, 'barfoo' },
+ })
eq({
'First line of text',
'foobarext',
'Fourth line of text',
'barfoo',
}, buf_lines(1))
- local mark = api.nvim_buf_get_mark(1, 'a')
- eq({ 2, 9 }, mark)
+ eq({ 2, 9 }, api.nvim_buf_get_mark(1, 'a'))
end)
it('it restores marks to last valid line', function()
- local edits = {
- make_edit(1, 0, 4, 5, 'foobar'),
- make_edit(4, 0, 5, 0, 'barfoo'),
- }
eq(true, api.nvim_buf_set_mark(1, 'a', 4, 1, {}))
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 1, 0, 4, 5, 'foobar' },
+ { 4, 0, 5, 0, 'barfoo' },
+ })
eq({
'First line of text',
'foobaro',
}, buf_lines(1))
- local mark = api.nvim_buf_get_mark(1, 'a')
- eq({ 2, 1 }, mark)
+ eq({ 2, 1 }, api.nvim_buf_get_mark(1, 'a'))
end)
describe('cursor position', function()
it("don't fix the cursor if the range contains the cursor", function()
api.nvim_win_set_cursor(0, { 2, 6 })
- local edits = {
- make_edit(1, 0, 1, 19, 'Second line of text'),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 1, 0, 1, 19, 'Second line of text' },
+ })
eq({
'First line of text',
'Second line of text',
@@ -1905,11 +2117,10 @@ describe('LSP', function()
it('fix the cursor to the valid col if the content was removed', function()
api.nvim_win_set_cursor(0, { 2, 6 })
- local edits = {
- make_edit(1, 0, 1, 6, ''),
- make_edit(1, 6, 1, 19, ''),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 1, 0, 1, 6, '' },
+ { 1, 6, 1, 19, '' },
+ })
eq({
'First line of text',
'',
@@ -1922,11 +2133,10 @@ describe('LSP', function()
it('fix the cursor to the valid row if the content was removed', function()
api.nvim_win_set_cursor(0, { 2, 6 })
- local edits = {
- make_edit(1, 0, 1, 6, ''),
- make_edit(0, 18, 5, 0, ''),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 1, 0, 1, 6, '' },
+ { 0, 18, 5, 0, '' },
+ })
eq({
'First line of text',
}, buf_lines(1))
@@ -1935,10 +2145,9 @@ describe('LSP', function()
it('fix the cursor row', function()
api.nvim_win_set_cursor(0, { 3, 0 })
- local edits = {
- make_edit(1, 0, 2, 0, ''),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 1, 0, 2, 0, '' },
+ })
eq({
'First line of text',
'Third line of text',
@@ -1953,10 +2162,9 @@ describe('LSP', function()
api.nvim_buf_set_lines(1, -1, -1, true, { '' })
api.nvim_win_set_cursor(0, { 2, 11 })
- local edits = {
- make_edit(1, 7, 1, 11, ''),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 1, 7, 1, 11, '' },
+ })
eq({
'First line of text',
'Second of text',
@@ -1970,10 +2178,9 @@ describe('LSP', function()
it('fix the cursor row and col', function()
api.nvim_win_set_cursor(0, { 2, 12 })
- local edits = {
- make_edit(0, 11, 1, 12, ''),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 0, 11, 1, 12, '' },
+ })
eq({
'First line of text',
'Third line of text',
@@ -1986,24 +2193,23 @@ describe('LSP', function()
describe('with LSP end line after what Vim considers to be the end line', function()
it('applies edits when the last linebreak is considered a new line', function()
- local edits = {
- make_edit(0, 0, 5, 0, { 'All replaced' }),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 0, 0, 5, 0, { 'All replaced' } },
+ })
eq({ 'All replaced' }, buf_lines(1))
end)
+
it("applies edits when the end line is 2 larger than vim's", function()
- local edits = {
- make_edit(0, 0, 6, 0, { 'All replaced' }),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 0, 0, 6, 0, { 'All replaced' } },
+ })
eq({ 'All replaced' }, buf_lines(1))
end)
+
it('applies edits with a column offset', function()
- local edits = {
- make_edit(0, 0, 5, 2, { 'All replaced' }),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 0, 0, 5, 2, { 'All replaced' } },
+ })
eq({ 'All replaced' }, buf_lines(1))
end)
end)
@@ -2015,38 +2221,38 @@ describe('LSP', function()
Test line one
Test line two 21 char]]))
end)
+
describe('with LSP end column out of bounds and start column at 0', function()
it('applies edits at the end of the buffer', function()
- local edits = {
- make_edit(0, 0, 1, 22, { '#include "whatever.h"\r\n#include <algorithm>\r' }),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-8')
+ apply_text_edits({
+ { 0, 0, 1, 22, { '#include "whatever.h"\r\n#include <algorithm>\r' } },
+ }, 'utf-8')
eq({ '#include "whatever.h"', '#include <algorithm>' }, buf_lines(1))
end)
+
it('applies edits in the middle of the buffer', function()
- local edits = {
- make_edit(0, 0, 0, 22, { '#include "whatever.h"\r\n#include <algorithm>\r' }),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-8')
+ apply_text_edits({
+ { 0, 0, 0, 22, { '#include "whatever.h"\r\n#include <algorithm>\r' } },
+ }, 'utf-8')
eq(
{ '#include "whatever.h"', '#include <algorithm>', 'Test line two 21 char' },
buf_lines(1)
)
end)
end)
+
describe('with LSP end column out of bounds and start column NOT at 0', function()
it('applies edits at the end of the buffer', function()
- local edits = {
- make_edit(0, 2, 1, 22, { '#include "whatever.h"\r\n#include <algorithm>\r' }),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-8')
+ apply_text_edits({
+ { 0, 2, 1, 22, { '#include "whatever.h"\r\n#include <algorithm>\r' } },
+ }, 'utf-8')
eq({ 'Te#include "whatever.h"', '#include <algorithm>' }, buf_lines(1))
end)
+
it('applies edits in the middle of the buffer', function()
- local edits = {
- make_edit(0, 2, 0, 22, { '#include "whatever.h"\r\n#include <algorithm>\r' }),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-8')
+ apply_text_edits({
+ { 0, 2, 0, 22, { '#include "whatever.h"\r\n#include <algorithm>\r' } },
+ }, 'utf-8')
eq(
{ 'Te#include "whatever.h"', '#include <algorithm>', 'Test line two 21 char' },
buf_lines(1)
@@ -2057,6 +2263,7 @@ describe('LSP', function()
describe('apply_text_document_edit', function()
local target_bufnr --- @type integer
+
local text_document_edit = function(editVersion)
return {
edits = {
@@ -2068,50 +2275,43 @@ describe('LSP', function()
},
}
end
+
before_each(function()
- target_bufnr = exec_lua [[
- local bufnr = vim.uri_to_bufnr("file:///fake/uri")
- local lines = {"1st line of text", "2nd line of 语text"}
+ target_bufnr = exec_lua(function()
+ local bufnr = vim.uri_to_bufnr('file:///fake/uri')
+ local lines = { '1st line of text', '2nd line of 语text' }
vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines)
return bufnr
- ]]
+ end)
end)
+
it('correctly goes ahead with the edit if all is normal', function()
- exec_lua("vim.lsp.util.apply_text_document_edit(..., nil, 'utf-16')", text_document_edit(5))
+ exec_lua(function(text_edit)
+ vim.lsp.util.apply_text_document_edit(text_edit, nil, 'utf-16')
+ end, text_document_edit(5))
eq({
'First ↥ 🤦 🦄 line of text',
'2nd line of 语text',
}, buf_lines(target_bufnr))
end)
+
it('always accepts edit with version = 0', function()
- exec_lua(
- [[
- local args = {...}
- local bufnr = select(1, ...)
- local text_edit = select(2, ...)
- vim.lsp.util.buf_versions[bufnr] = 10
+ exec_lua(function(text_edit)
+ vim.lsp.util.buf_versions[target_bufnr] = 10
vim.lsp.util.apply_text_document_edit(text_edit, nil, 'utf-16')
- ]],
- target_bufnr,
- text_document_edit(0)
- )
+ end, text_document_edit(0))
eq({
'First ↥ 🤦 🦄 line of text',
'2nd line of 语text',
}, buf_lines(target_bufnr))
end)
+
it('skips the edit if the version of the edit is behind the local buffer ', function()
local apply_edit_mocking_current_version = function(edit, versionedBuf)
- exec_lua(
- [[
- local args = {...}
- local versionedBuf = args[2]
+ exec_lua(function()
vim.lsp.util.buf_versions[versionedBuf.bufnr] = versionedBuf.currentVersion
- vim.lsp.util.apply_text_document_edit(args[1], nil, 'utf-16')
- ]],
- edit,
- versionedBuf
- )
+ vim.lsp.util.apply_text_document_edit(edit, nil, 'utf-16')
+ end)
end
local baseText = {
@@ -2164,13 +2364,17 @@ describe('LSP', function()
}
eq(
expected,
- exec_lua [[
- local apply_edit = {
- label = nil;
- edit = {};
- }
- return vim.lsp.handlers['workspace/applyEdit'](nil, apply_edit, {client_id = TEST_RPC_CLIENT_ID})
- ]]
+ exec_lua(function()
+ local apply_edit = {
+ label = nil,
+ edit = {},
+ }
+ return vim.lsp.handlers['workspace/applyEdit'](
+ nil,
+ apply_edit,
+ { client_id = _G.TEST_RPC_CLIENT_ID }
+ )
+ end)
)
eq(table.remove(expected_handlers), { ... })
end,
@@ -2200,34 +2404,30 @@ describe('LSP', function()
}
end
- local target_bufnr, changedtick = nil, nil
+ local target_bufnr --- @type integer
+ local changedtick --- @type integer
before_each(function()
- local ret = exec_lua [[
- local bufnr = vim.uri_to_bufnr("file:///fake/uri")
+ exec_lua(function()
+ target_bufnr = vim.uri_to_bufnr('file:///fake/uri')
local lines = {
- "Original Line #1",
- "Original Line #2"
+ 'Original Line #1',
+ 'Original Line #2',
}
- vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines)
+ vim.api.nvim_buf_set_lines(target_bufnr, 0, -1, false, lines)
- local update_changed_tick = function()
- vim.lsp.util.buf_versions[bufnr] = vim.api.nvim_buf_get_var(bufnr, 'changedtick')
+ local function update_changed_tick()
+ vim.lsp.util.buf_versions[target_bufnr] = vim.b[target_bufnr].changedtick
end
update_changed_tick()
- vim.api.nvim_buf_attach(bufnr, false, {
- on_changedtick = function()
- update_changed_tick()
- end
+ vim.api.nvim_buf_attach(target_bufnr, false, {
+ on_changedtick = update_changed_tick,
})
- return {bufnr, vim.api.nvim_buf_get_var(bufnr, 'changedtick')}
- ]]
-
- target_bufnr = ret[1]
- changedtick = ret[2]
+ changedtick = vim.b[target_bufnr].changedtick
+ end)
end)
it('apply_workspace_edit applies a single edit', function()
@@ -2245,19 +2445,11 @@ describe('LSP', function()
'First Line',
'Original Line #2',
},
- exec_lua(
- [[
- local args = {...}
- local workspace_edits = args[1]
- local target_bufnr = args[2]
-
- vim.lsp.util.apply_workspace_edit(workspace_edits, 'utf-16')
+ exec_lua(function(workspace_edits)
+ vim.lsp.util.apply_workspace_edit(workspace_edits, 'utf-16')
- return vim.api.nvim_buf_get_lines(target_bufnr, 0, -1, false)
- ]],
- make_workspace_edit(edits),
- target_bufnr
- )
+ return vim.api.nvim_buf_get_lines(target_bufnr, 0, -1, false)
+ end, make_workspace_edit(edits))
)
end)
@@ -2274,24 +2466,15 @@ describe('LSP', function()
eq(
new_lines,
- exec_lua(
- [[
- local args = {...}
- local workspace_edits = args[1]
- local target_bufnr = args[2]
-
- vim.lsp.util.apply_workspace_edit(workspace_edits, 'utf-16')
-
- return vim.api.nvim_buf_get_lines(target_bufnr, 0, -1, false)
- ]],
- make_workspace_edit(edits),
- target_bufnr
- )
+ exec_lua(function(workspace_edits)
+ vim.lsp.util.apply_workspace_edit(workspace_edits, 'utf-16')
+ return vim.api.nvim_buf_get_lines(target_bufnr, 0, -1, false)
+ end, make_workspace_edit(edits))
)
end)
+
it('Supports file creation with CreateFile payload', function()
- local tmpfile = tmpname()
- os.remove(tmpfile) -- Should not exist, only interested in a tmpname
+ local tmpfile = tmpname(false)
local uri = exec_lua('return vim.uri_from_fname(...)', tmpfile)
local edit = {
documentChanges = {
@@ -2301,15 +2484,16 @@ describe('LSP', function()
},
},
}
- exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit, 'utf-16')
+ exec_lua(function()
+ vim.lsp.util.apply_workspace_edit(edit, 'utf-16')
+ end)
eq(true, vim.uv.fs_stat(tmpfile) ~= nil)
end)
+
it(
'Supports file creation in folder that needs to be created with CreateFile payload',
function()
- local tmpfile = tmpname()
- os.remove(tmpfile) -- Should not exist, only interested in a tmpname
- tmpfile = tmpfile .. '/dummy/x/'
+ local tmpfile = tmpname(false) .. '/dummy/x/'
local uri = exec_lua('return vim.uri_from_fname(...)', tmpfile)
local edit = {
documentChanges = {
@@ -2319,10 +2503,13 @@ describe('LSP', function()
},
},
}
- exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit, 'utf-16')
+ exec_lua(function()
+ vim.lsp.util.apply_workspace_edit(edit, 'utf-16')
+ end)
eq(true, vim.uv.fs_stat(tmpfile) ~= nil)
end
)
+
it('createFile does not touch file if it exists and ignoreIfExists is set', function()
local tmpfile = tmpname()
write_file(tmpfile, 'Dummy content')
@@ -2342,6 +2529,7 @@ describe('LSP', function()
eq(true, vim.uv.fs_stat(tmpfile) ~= nil)
eq('Dummy content', read_file(tmpfile))
end)
+
it('createFile overrides file if overwrite is set', function()
local tmpfile = tmpname()
write_file(tmpfile, 'Dummy content')
@@ -2362,18 +2550,15 @@ describe('LSP', function()
eq(true, vim.uv.fs_stat(tmpfile) ~= nil)
eq('', read_file(tmpfile))
end)
+
it('DeleteFile delete file and buffer', function()
local tmpfile = tmpname()
write_file(tmpfile, 'Be gone')
- local uri = exec_lua(
- [[
- local fname = select(1, ...)
- local bufnr = vim.fn.bufadd(fname)
+ local uri = exec_lua(function()
+ local bufnr = vim.fn.bufadd(tmpfile)
vim.fn.bufload(bufnr)
- return vim.uri_from_fname(fname)
- ]],
- tmpfile
- )
+ return vim.uri_from_fname(tmpfile)
+ end)
local edit = {
documentChanges = {
{
@@ -2386,9 +2571,9 @@ describe('LSP', function()
eq(false, vim.uv.fs_stat(tmpfile) ~= nil)
eq(false, api.nvim_buf_is_loaded(fn.bufadd(tmpfile)))
end)
+
it('DeleteFile fails if file does not exist and ignoreIfNotExists is false', function()
- local tmpfile = tmpname()
- os.remove(tmpfile)
+ local tmpfile = tmpname(false)
local uri = exec_lua('return vim.uri_from_fname(...)', tmpfile)
local edit = {
documentChanges = {
@@ -2412,12 +2597,8 @@ describe('LSP', function()
it('Can rename an existing file', function()
local old = tmpname()
write_file(old, 'Test content')
- local new = tmpname()
- os.remove(new) -- only reserve the name, file must not exist for the test scenario
- local lines = exec_lua(
- [[
- local old = select(1, ...)
- local new = select(2, ...)
+ local new = tmpname(false)
+ local lines = exec_lua(function()
local old_bufnr = vim.fn.bufadd(old)
vim.fn.bufload(old_bufnr)
vim.lsp.util.rename(old, new)
@@ -2425,10 +2606,7 @@ describe('LSP', function()
local new_bufnr = vim.fn.bufadd(new)
vim.fn.bufload(new_bufnr)
return (old_bufnr == new_bufnr) and vim.api.nvim_buf_get_lines(new_bufnr, 0, -1, true)
- ]],
- old,
- new
- )
+ end)
eq({ 'Test content' }, lines)
local exists = vim.uv.fs_stat(old) ~= nil
eq(false, exists)
@@ -2436,24 +2614,18 @@ describe('LSP', function()
eq(true, exists)
os.remove(new)
end)
+
it('Can rename a directory', function()
-- only reserve the name, file must not exist for the test scenario
- local old_dir = tmpname()
- local new_dir = tmpname()
- os.remove(old_dir)
- os.remove(new_dir)
+ local old_dir = tmpname(false)
+ local new_dir = tmpname(false)
n.mkdir_p(old_dir)
local file = 'file.txt'
write_file(old_dir .. pathsep .. file, 'Test content')
- local lines = exec_lua(
- [[
- local old_dir = select(1, ...)
- local new_dir = select(2, ...)
- local pathsep = select(3, ...)
- local file = select(4, ...)
+ local lines = exec_lua(function()
local old_bufnr = vim.fn.bufadd(old_dir .. pathsep .. file)
vim.fn.bufload(old_bufnr)
vim.lsp.util.rename(old_dir, new_dir)
@@ -2461,12 +2633,7 @@ describe('LSP', function()
local new_bufnr = vim.fn.bufadd(new_dir .. pathsep .. file)
vim.fn.bufload(new_bufnr)
return (old_bufnr == new_bufnr) and vim.api.nvim_buf_get_lines(new_bufnr, 0, -1, true)
- ]],
- old_dir,
- new_dir,
- pathsep,
- file
- )
+ end)
eq({ 'Test content' }, lines)
eq(false, vim.uv.fs_stat(old_dir) ~= nil)
eq(true, vim.uv.fs_stat(new_dir) ~= nil)
@@ -2474,47 +2641,41 @@ describe('LSP', function()
os.remove(new_dir)
end)
+
it('Does not touch buffers that do not match path prefix', function()
- local old = tmpname()
- local new = tmpname()
- os.remove(old)
- os.remove(new)
+ local old = tmpname(false)
+ local new = tmpname(false)
n.mkdir_p(old)
- local result = exec_lua(
- [[
- local old = select(1, ...)
- local new = select(2, ...)
-
- local old_prefixed = 'explorer://' .. old
- local old_suffixed = old .. '.bak'
- local new_prefixed = 'explorer://' .. new
- local new_suffixed = new .. '.bak'
+ eq(
+ true,
+ exec_lua(function()
+ local old_prefixed = 'explorer://' .. old
+ local old_suffixed = old .. '.bak'
+ local new_prefixed = 'explorer://' .. new
+ local new_suffixed = new .. '.bak'
- local old_prefixed_buf = vim.fn.bufadd(old_prefixed)
- local old_suffixed_buf = vim.fn.bufadd(old_suffixed)
- local new_prefixed_buf = vim.fn.bufadd(new_prefixed)
- local new_suffixed_buf = vim.fn.bufadd(new_suffixed)
+ local old_prefixed_buf = vim.fn.bufadd(old_prefixed)
+ local old_suffixed_buf = vim.fn.bufadd(old_suffixed)
+ local new_prefixed_buf = vim.fn.bufadd(new_prefixed)
+ local new_suffixed_buf = vim.fn.bufadd(new_suffixed)
- vim.lsp.util.rename(old, new)
+ vim.lsp.util.rename(old, new)
- return
- vim.api.nvim_buf_is_valid(old_prefixed_buf) and
- vim.api.nvim_buf_is_valid(old_suffixed_buf) and
- vim.api.nvim_buf_is_valid(new_prefixed_buf) and
- vim.api.nvim_buf_is_valid(new_suffixed_buf) and
- vim.api.nvim_buf_get_name(old_prefixed_buf) == old_prefixed and
- vim.api.nvim_buf_get_name(old_suffixed_buf) == old_suffixed and
- vim.api.nvim_buf_get_name(new_prefixed_buf) == new_prefixed and
- vim.api.nvim_buf_get_name(new_suffixed_buf) == new_suffixed
- ]],
- old,
- new
+ return vim.api.nvim_buf_is_valid(old_prefixed_buf)
+ and vim.api.nvim_buf_is_valid(old_suffixed_buf)
+ and vim.api.nvim_buf_is_valid(new_prefixed_buf)
+ and vim.api.nvim_buf_is_valid(new_suffixed_buf)
+ and vim.api.nvim_buf_get_name(old_prefixed_buf) == old_prefixed
+ and vim.api.nvim_buf_get_name(old_suffixed_buf) == old_suffixed
+ and vim.api.nvim_buf_get_name(new_prefixed_buf) == new_prefixed
+ and vim.api.nvim_buf_get_name(new_suffixed_buf) == new_suffixed
+ end)
)
- eq(true, result)
os.remove(new)
end)
+
it(
'Does not rename file if target exists and ignoreIfExists is set or overwrite is false',
function()
@@ -2523,45 +2684,28 @@ describe('LSP', function()
local new = tmpname()
write_file(new, 'New file')
- exec_lua(
- [[
- local old = select(1, ...)
- local new = select(2, ...)
-
- vim.lsp.util.rename(old, new, { ignoreIfExists = true })
- ]],
- old,
- new
- )
+ exec_lua(function()
+ vim.lsp.util.rename(old, new, { ignoreIfExists = true })
+ end)
eq(true, vim.uv.fs_stat(old) ~= nil)
eq('New file', read_file(new))
- exec_lua(
- [[
- local old = select(1, ...)
- local new = select(2, ...)
-
- vim.lsp.util.rename(old, new, { overwrite = false })
- ]],
- old,
- new
- )
+ exec_lua(function()
+ vim.lsp.util.rename(old, new, { overwrite = false })
+ end)
eq(true, vim.uv.fs_stat(old) ~= nil)
eq('New file', read_file(new))
end
)
+
it('Maintains undo information for loaded buffer', function()
local old = tmpname()
write_file(old, 'line')
- local new = tmpname()
- os.remove(new)
+ local new = tmpname(false)
- local undo_kept = exec_lua(
- [[
- local old = select(1, ...)
- local new = select(2, ...)
+ local undo_kept = exec_lua(function()
vim.opt.undofile = true
vim.cmd.edit(old)
vim.cmd.normal('dd')
@@ -2574,24 +2718,18 @@ describe('LSP', function()
undotree.save_last = undotree.save_last + 1
undotree.entries[1].save = undotree.entries[1].save + 1
return vim.deep_equal(undotree, vim.fn.undotree())
- ]],
- old,
- new
- )
+ end)
eq(false, vim.uv.fs_stat(old) ~= nil)
eq(true, vim.uv.fs_stat(new) ~= nil)
eq(true, undo_kept)
end)
+
it('Maintains undo information for unloaded buffer', function()
local old = tmpname()
write_file(old, 'line')
- local new = tmpname()
- os.remove(new)
+ local new = tmpname(false)
- local undo_kept = exec_lua(
- [[
- local old = select(1, ...)
- local new = select(2, ...)
+ local undo_kept = exec_lua(function()
vim.opt.undofile = true
vim.cmd.split(old)
vim.cmd.normal('dd')
@@ -2601,54 +2739,39 @@ describe('LSP', function()
vim.lsp.util.rename(old, new)
vim.cmd.edit(new)
return vim.deep_equal(undotree, vim.fn.undotree())
- ]],
- old,
- new
- )
+ end)
eq(false, vim.uv.fs_stat(old) ~= nil)
eq(true, vim.uv.fs_stat(new) ~= nil)
eq(true, undo_kept)
end)
+
it('Does not rename file when it conflicts with a buffer without file', function()
local old = tmpname()
write_file(old, 'Old File')
- local new = tmpname()
- os.remove(new)
-
- local lines = exec_lua(
- [[
- local old = select(1, ...)
- local new = select(2, ...)
- local old_buf = vim.fn.bufadd(old)
- vim.fn.bufload(old_buf)
- local conflict_buf = vim.api.nvim_create_buf(true, false)
- vim.api.nvim_buf_set_name(conflict_buf, new)
- vim.api.nvim_buf_set_lines(conflict_buf, 0, -1, true, {'conflict'})
- vim.api.nvim_win_set_buf(0, conflict_buf)
- vim.lsp.util.rename(old, new)
- return vim.api.nvim_buf_get_lines(conflict_buf, 0, -1, true)
- ]],
- old,
- new
- )
+ local new = tmpname(false)
+
+ local lines = exec_lua(function()
+ local old_buf = vim.fn.bufadd(old)
+ vim.fn.bufload(old_buf)
+ local conflict_buf = vim.api.nvim_create_buf(true, false)
+ vim.api.nvim_buf_set_name(conflict_buf, new)
+ vim.api.nvim_buf_set_lines(conflict_buf, 0, -1, true, { 'conflict' })
+ vim.api.nvim_win_set_buf(0, conflict_buf)
+ vim.lsp.util.rename(old, new)
+ return vim.api.nvim_buf_get_lines(conflict_buf, 0, -1, true)
+ end)
eq({ 'conflict' }, lines)
eq('Old File', read_file(old))
end)
+
it('Does override target if overwrite is true', function()
local old = tmpname()
write_file(old, 'Old file')
local new = tmpname()
write_file(new, 'New file')
- exec_lua(
- [[
- local old = select(1, ...)
- local new = select(2, ...)
-
+ exec_lua(function()
vim.lsp.util.rename(old, new, { overwrite = true })
- ]],
- old,
- new
- )
+ end)
eq(false, vim.uv.fs_stat(old) ~= nil)
eq(true, vim.uv.fs_stat(new) ~= nil)
@@ -2658,44 +2781,59 @@ describe('LSP', function()
describe('lsp.util.locations_to_items', function()
it('Convert Location[] to items', function()
- local expected = {
+ local expected_template = {
{
filename = '/fake/uri',
lnum = 1,
+ end_lnum = 2,
col = 3,
+ end_col = 4,
text = 'testing',
- user_data = {
+ user_data = {},
+ },
+ }
+ local test_params = {
+ {
+ {
uri = 'file:///fake/uri',
range = {
start = { line = 0, character = 2 },
- ['end'] = { line = 0, character = 3 },
+ ['end'] = { line = 1, character = 3 },
},
},
},
- }
- local actual = exec_lua [[
- local bufnr = vim.uri_to_bufnr("file:///fake/uri")
- local lines = {"testing", "123"}
- vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines)
- local locations = {
+ {
{
uri = 'file:///fake/uri',
range = {
start = { line = 0, character = 2 },
- ['end'] = { line = 0, character = 3 },
- }
+ -- LSP spec: if character > line length, default to the line length.
+ ['end'] = { line = 1, character = 10000 },
+ },
},
- }
- return vim.lsp.util.locations_to_items(locations, 'utf-16')
- ]]
- eq(expected, actual)
+ },
+ }
+ for _, params in ipairs(test_params) do
+ local actual = exec_lua(function(params0)
+ local bufnr = vim.uri_to_bufnr('file:///fake/uri')
+ local lines = { 'testing', '123' }
+ vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines)
+ return vim.lsp.util.locations_to_items(params0, 'utf-16')
+ end, params)
+ local expected = vim.deepcopy(expected_template)
+ expected[1].user_data = params[1]
+ eq(expected, actual)
+ end
end)
+
it('Convert LocationLink[] to items', function()
local expected = {
{
filename = '/fake/uri',
lnum = 1,
+ end_lnum = 1,
col = 3,
+ end_col = 4,
text = 'testing',
user_data = {
targetUri = 'file:///fake/uri',
@@ -2710,9 +2848,9 @@ describe('LSP', function()
},
},
}
- local actual = exec_lua [[
- local bufnr = vim.uri_to_bufnr("file:///fake/uri")
- local lines = {"testing", "123"}
+ local actual = exec_lua(function()
+ local bufnr = vim.uri_to_bufnr('file:///fake/uri')
+ local lines = { 'testing', '123' }
vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines)
local locations = {
{
@@ -2724,11 +2862,11 @@ describe('LSP', function()
targetSelectionRange = {
start = { line = 0, character = 2 },
['end'] = { line = 0, character = 3 },
- }
+ },
},
}
return vim.lsp.util.locations_to_items(locations, 'utf-16')
- ]]
+ end)
eq(expected, actual)
end)
end)
@@ -2761,94 +2899,95 @@ describe('LSP', function()
}
eq(
expected,
- exec_lua [[
- local doc_syms = {
- {
- deprecated = false,
- detail = "A",
- kind = 1,
- name = "TestA",
- range = {
- start = {
- character = 0,
- line = 1
+ exec_lua(function()
+ local doc_syms = {
+ {
+ deprecated = false,
+ detail = 'A',
+ kind = 1,
+ name = 'TestA',
+ range = {
+ start = {
+ character = 0,
+ line = 1,
+ },
+ ['end'] = {
+ character = 0,
+ line = 2,
+ },
},
- ["end"] = {
- character = 0,
- line = 2
- }
- },
- selectionRange = {
- start = {
- character = 0,
- line = 1
+ selectionRange = {
+ start = {
+ character = 0,
+ line = 1,
+ },
+ ['end'] = {
+ character = 4,
+ line = 1,
+ },
},
- ["end"] = {
- character = 4,
- line = 1
- }
- },
- children = {
- {
- children = {},
- deprecated = false,
- detail = "B",
- kind = 2,
- name = "TestB",
- range = {
- start = {
- character = 0,
- line = 3
+ children = {
+ {
+ children = {},
+ deprecated = false,
+ detail = 'B',
+ kind = 2,
+ name = 'TestB',
+ range = {
+ start = {
+ character = 0,
+ line = 3,
+ },
+ ['end'] = {
+ character = 0,
+ line = 4,
+ },
},
- ["end"] = {
- character = 0,
- line = 4
- }
- },
- selectionRange = {
- start = {
- character = 0,
- line = 3
+ selectionRange = {
+ start = {
+ character = 0,
+ line = 3,
+ },
+ ['end'] = {
+ character = 4,
+ line = 3,
+ },
},
- ["end"] = {
- character = 4,
- line = 3
- }
- }
- }
- }
- },
- {
- deprecated = false,
- detail = "C",
- kind = 3,
- name = "TestC",
- range = {
- start = {
- character = 0,
- line = 5
+ },
},
- ["end"] = {
- character = 0,
- line = 6
- }
},
- selectionRange = {
- start = {
- character = 0,
- line = 5
+ {
+ deprecated = false,
+ detail = 'C',
+ kind = 3,
+ name = 'TestC',
+ range = {
+ start = {
+ character = 0,
+ line = 5,
+ },
+ ['end'] = {
+ character = 0,
+ line = 6,
+ },
},
- ["end"] = {
- character = 4,
- line = 5
- }
- }
+ selectionRange = {
+ start = {
+ character = 0,
+ line = 5,
+ },
+ ['end'] = {
+ character = 4,
+ line = 5,
+ },
+ },
+ },
}
- }
- return vim.lsp.util.symbols_to_items(doc_syms, nil)
- ]]
+ return vim.lsp.util.symbols_to_items(doc_syms, nil)
+ end)
)
end)
+
it('DocumentSymbol has no children', function()
local expected = {
{
@@ -2868,66 +3007,67 @@ describe('LSP', function()
}
eq(
expected,
- exec_lua [[
- local doc_syms = {
- {
- deprecated = false,
- detail = "A",
- kind = 1,
- name = "TestA",
- range = {
- start = {
- character = 0,
- line = 1
+ exec_lua(function()
+ local doc_syms = {
+ {
+ deprecated = false,
+ detail = 'A',
+ kind = 1,
+ name = 'TestA',
+ range = {
+ start = {
+ character = 0,
+ line = 1,
+ },
+ ['end'] = {
+ character = 0,
+ line = 2,
+ },
},
- ["end"] = {
- character = 0,
- line = 2
- }
- },
- selectionRange = {
- start = {
- character = 0,
- line = 1
+ selectionRange = {
+ start = {
+ character = 0,
+ line = 1,
+ },
+ ['end'] = {
+ character = 4,
+ line = 1,
+ },
},
- ["end"] = {
- character = 4,
- line = 1
- }
},
- },
- {
- deprecated = false,
- detail = "C",
- kind = 3,
- name = "TestC",
- range = {
- start = {
- character = 0,
- line = 5
+ {
+ deprecated = false,
+ detail = 'C',
+ kind = 3,
+ name = 'TestC',
+ range = {
+ start = {
+ character = 0,
+ line = 5,
+ },
+ ['end'] = {
+ character = 0,
+ line = 6,
+ },
},
- ["end"] = {
- character = 0,
- line = 6
- }
- },
- selectionRange = {
- start = {
- character = 0,
- line = 5
+ selectionRange = {
+ start = {
+ character = 0,
+ line = 5,
+ },
+ ['end'] = {
+ character = 4,
+ line = 5,
+ },
},
- ["end"] = {
- character = 4,
- line = 5
- }
- }
+ },
}
- }
- return vim.lsp.util.symbols_to_items(doc_syms, nil)
- ]]
+ return vim.lsp.util.symbols_to_items(doc_syms, nil)
+ end)
)
end)
end)
+
it('convert SymbolInformation[] to items', function()
local expected = {
{
@@ -2947,62 +3087,88 @@ describe('LSP', function()
}
eq(
expected,
- exec_lua [[
+ exec_lua(function()
local sym_info = {
{
deprecated = false,
kind = 1,
- name = "TestA",
+ name = 'TestA',
location = {
range = {
start = {
character = 0,
- line = 1
+ line = 1,
},
- ["end"] = {
+ ['end'] = {
character = 0,
- line = 2
- }
+ line = 2,
+ },
},
- uri = "file:///test_a"
+ uri = 'file:///test_a',
},
- containerName = "TestAContainer"
+ containerName = 'TestAContainer',
},
{
deprecated = false,
kind = 2,
- name = "TestB",
+ name = 'TestB',
location = {
range = {
start = {
character = 0,
- line = 3
+ line = 3,
},
- ["end"] = {
+ ['end'] = {
character = 0,
- line = 4
- }
+ line = 4,
+ },
},
- uri = "file:///test_b"
+ uri = 'file:///test_b',
},
- containerName = "TestBContainer"
- }
+ containerName = 'TestBContainer',
+ },
}
return vim.lsp.util.symbols_to_items(sym_info, nil)
- ]]
+ end)
)
end)
end)
describe('lsp.util._get_symbol_kind_name', function()
it('returns the name specified by protocol', function()
- eq('File', exec_lua('return vim.lsp.util._get_symbol_kind_name(1)'))
- eq('TypeParameter', exec_lua('return vim.lsp.util._get_symbol_kind_name(26)'))
+ eq(
+ 'File',
+ exec_lua(function()
+ return vim.lsp.util._get_symbol_kind_name(1)
+ end)
+ )
+ eq(
+ 'TypeParameter',
+ exec_lua(function()
+ return vim.lsp.util._get_symbol_kind_name(26)
+ end)
+ )
end)
+
it('returns the name not specified by protocol', function()
- eq('Unknown', exec_lua('return vim.lsp.util._get_symbol_kind_name(nil)'))
- eq('Unknown', exec_lua('return vim.lsp.util._get_symbol_kind_name(vim.NIL)'))
- eq('Unknown', exec_lua('return vim.lsp.util._get_symbol_kind_name(1000)'))
+ eq(
+ 'Unknown',
+ exec_lua(function()
+ return vim.lsp.util._get_symbol_kind_name(nil)
+ end)
+ )
+ eq(
+ 'Unknown',
+ exec_lua(function()
+ return vim.lsp.util._get_symbol_kind_name(vim.NIL)
+ end)
+ )
+ eq(
+ 'Unknown',
+ exec_lua(function()
+ return vim.lsp.util._get_symbol_kind_name(1000)
+ end)
+ )
end)
end)
@@ -3010,12 +3176,12 @@ describe('LSP', function()
local target_bufnr --- @type integer
before_each(function()
- target_bufnr = exec_lua [[
- local bufnr = vim.uri_to_bufnr("file:///fake/uri")
- local lines = {"1st line of text", "å å ɧ 汉语 ↥ 🤦 🦄"}
+ target_bufnr = exec_lua(function()
+ local bufnr = vim.uri_to_bufnr('file:///fake/uri')
+ local lines = { '1st line of text', 'å å ɧ 汉语 ↥ 🤦 🦄' }
vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines)
return bufnr
- ]]
+ end)
end)
local location = function(start_line, start_char, end_line, end_char)
@@ -3084,19 +3250,19 @@ describe('LSP', function()
local target_bufnr2 --- @type integer
before_each(function()
- target_bufnr = exec_lua([[
- local bufnr = vim.uri_to_bufnr("file:///fake/uri")
- local lines = {"1st line of text", "å å ɧ 汉语 ↥ 🤦 🦄"}
+ target_bufnr = exec_lua(function()
+ local bufnr = vim.uri_to_bufnr('file:///fake/uri')
+ local lines = { '1st line of text', 'å å ɧ 汉语 ↥ 🤦 🦄' }
vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines)
return bufnr
- ]])
+ end)
- target_bufnr2 = exec_lua([[
- local bufnr = vim.uri_to_bufnr("file:///fake/uri2")
- local lines = {"1st line of text", "å å ɧ 汉语 ↥ 🤦 🦄"}
+ target_bufnr2 = exec_lua(function()
+ local bufnr = vim.uri_to_bufnr('file:///fake/uri2')
+ local lines = { '1st line of text', 'å å ɧ 汉语 ↥ 🤦 🦄' }
vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines)
return bufnr
- ]])
+ end)
end)
local location = function(start_line, start_char, end_line, end_char, second_uri)
@@ -3136,14 +3302,14 @@ describe('LSP', function()
it('jumps to a Location if focus is true via handler', function()
exec_lua(create_server_definition)
- local result = exec_lua([[
- local server = _create_server()
- local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
+ local result = exec_lua(function()
+ local server = _G._create_server()
+ local client_id = assert(vim.lsp.start({ name = 'dummy', cmd = server.cmd }))
local result = {
uri = 'file:///fake/uri',
selection = {
start = { line = 0, character = 9 },
- ['end'] = { line = 0, character = 9 }
+ ['end'] = { line = 0, character = 9 },
},
takeFocus = true,
}
@@ -3154,9 +3320,9 @@ describe('LSP', function()
vim.lsp.handlers['window/showDocument'](nil, result, ctx)
vim.lsp.stop_client(client_id)
return {
- cursor = vim.api.nvim_win_get_cursor(0)
+ cursor = vim.api.nvim_win_get_cursor(0),
}
- ]])
+ end)
eq(1, result.cursor[1])
eq(9, result.cursor[2])
end)
@@ -3231,7 +3397,9 @@ describe('LSP', function()
api.nvim_win_set_buf(0, target_bufnr)
api.nvim_win_set_cursor(0, { 2, 3 })
- exec_lua([[vim.cmd.new()]])
+ exec_lua(function()
+ vim.cmd.new()
+ end)
api.nvim_win_set_buf(0, target_bufnr2)
api.nvim_win_set_cursor(0, { 2, 3 })
@@ -3247,7 +3415,9 @@ describe('LSP', function()
api.nvim_win_set_buf(0, target_bufnr)
local win = api.nvim_get_current_win()
- exec_lua([[vim.cmd.new()]])
+ exec_lua(function()
+ vim.cmd.new()
+ end)
api.nvim_win_set_buf(0, target_bufnr2)
api.nvim_win_set_cursor(0, { 2, 3 })
local split = api.nvim_get_current_win()
@@ -3268,34 +3438,53 @@ describe('LSP', function()
describe('lsp.util._make_floating_popup_size', function()
before_each(function()
- exec_lua [[ contents =
- {"text tαxt txtα tex",
- "text tααt tααt text",
- "text tαxt tαxt"}
- ]]
+ exec_lua(function()
+ _G.contents = { 'text tαxt txtα tex', 'text tααt tααt text', 'text tαxt tαxt' }
+ end)
end)
it('calculates size correctly', function()
- eq({ 19, 3 }, exec_lua [[ return {vim.lsp.util._make_floating_popup_size(contents)} ]])
+ eq(
+ { 19, 3 },
+ exec_lua(function()
+ return { vim.lsp.util._make_floating_popup_size(_G.contents) }
+ end)
+ )
end)
it('calculates size correctly with wrapping', function()
eq(
{ 15, 5 },
- exec_lua [[ return {vim.lsp.util._make_floating_popup_size(contents,{width = 15, wrap_at = 14})} ]]
+ exec_lua(function()
+ return {
+ vim.lsp.util._make_floating_popup_size(_G.contents, { width = 15, wrap_at = 14 }),
+ }
+ end)
)
end)
it('handles NUL bytes in text', function()
- exec_lua([[ contents = {
- '\000\001\002\003\004\005\006\007\008\009',
- '\010\011\012\013\014\015\016\017\018\019',
- '\020\021\022\023\024\025\026\027\028\029',
- } ]])
+ exec_lua(function()
+ _G.contents = {
+ '\000\001\002\003\004\005\006\007\008\009',
+ '\010\011\012\013\014\015\016\017\018\019',
+ '\020\021\022\023\024\025\026\027\028\029',
+ }
+ end)
command('set list listchars=')
- eq({ 20, 3 }, exec_lua [[ return {vim.lsp.util._make_floating_popup_size(contents)} ]])
+ eq(
+ { 20, 3 },
+ exec_lua(function()
+ return { vim.lsp.util._make_floating_popup_size(_G.contents) }
+ end)
+ )
command('set display+=uhex')
- eq({ 40, 3 }, exec_lua [[ return {vim.lsp.util._make_floating_popup_size(contents)} ]])
+ eq(
+ { 40, 3 },
+ exec_lua(function()
+ return { vim.lsp.util._make_floating_popup_size(_G.contents) }
+ end)
+ )
end)
end)
@@ -3303,27 +3492,30 @@ describe('LSP', function()
it('properly trims empty lines', function()
eq(
{ { 'foo', 'bar' } },
- exec_lua [[ return vim.lsp.util.trim_empty_lines({{ "foo", "bar" }, nil}) ]]
+ exec_lua(function()
+ --- @diagnostic disable-next-line:deprecated
+ return vim.lsp.util.trim_empty_lines({ { 'foo', 'bar' }, nil })
+ end)
)
end)
end)
describe('lsp.util.convert_signature_help_to_markdown_lines', function()
it('can handle negative activeSignature', function()
- local result = exec_lua [[
+ local result = exec_lua(function()
local signature_help = {
activeParameter = 0,
activeSignature = -1,
signatures = {
{
- documentation = "some doc",
- label = "TestEntity.TestEntity()",
- parameters = {}
+ documentation = 'some doc',
+ label = 'TestEntity.TestEntity()',
+ parameters = {},
},
- }
+ },
}
- return vim.lsp.util.convert_signature_help_to_markdown_lines(signature_help, 'cs', {','})
- ]]
+ return vim.lsp.util.convert_signature_help_to_markdown_lines(signature_help, 'cs', { ',' })
+ end)
local expected = { '```cs', 'TestEntity.TestEntity()', '```', 'some doc' }
eq(expected, result)
end)
@@ -3338,12 +3530,18 @@ describe('LSP', function()
]],
shiftwidth
))
- eq(tabsize, exec_lua('return vim.lsp.util.get_effective_tabstop()'))
+ eq(
+ tabsize,
+ exec_lua(function()
+ return vim.lsp.util.get_effective_tabstop()
+ end)
+ )
end
it('with shiftwidth = 1', function()
test_tabstop(1, 1)
end)
+
it('with shiftwidth = 0', function()
test_tabstop(2, 0)
end)
@@ -3351,57 +3549,61 @@ describe('LSP', function()
describe('vim.lsp.buf.outgoing_calls', function()
it('does nothing for an empty response', function()
- local qflist_count = exec_lua([=[
- require'vim.lsp.handlers'['callHierarchy/outgoingCalls'](nil, nil, {}, nil)
+ local qflist_count = exec_lua(function()
+ require 'vim.lsp.handlers'['callHierarchy/outgoingCalls'](nil, nil, {}, nil)
return #vim.fn.getqflist()
- ]=])
+ end)
eq(0, qflist_count)
end)
it('opens the quickfix list with the right caller', function()
- local qflist = exec_lua([=[
- local rust_analyzer_response = { {
- fromRanges = { {
- ['end'] = {
- character = 7,
- line = 3
- },
- start = {
- character = 4,
- line = 3
- }
- } },
- to = {
- detail = "fn foo()",
- kind = 12,
- name = "foo",
- range = {
- ['end'] = {
- character = 11,
- line = 0
+ local qflist = exec_lua(function()
+ local rust_analyzer_response = {
+ {
+ fromRanges = {
+ {
+ ['end'] = {
+ character = 7,
+ line = 3,
+ },
+ start = {
+ character = 4,
+ line = 3,
+ },
},
- start = {
- character = 0,
- line = 0
- }
},
- selectionRange = {
- ['end'] = {
- character = 6,
- line = 0
+ to = {
+ detail = 'fn foo()',
+ kind = 12,
+ name = 'foo',
+ range = {
+ ['end'] = {
+ character = 11,
+ line = 0,
+ },
+ start = {
+ character = 0,
+ line = 0,
+ },
},
- start = {
- character = 3,
- line = 0
- }
+ selectionRange = {
+ ['end'] = {
+ character = 6,
+ line = 0,
+ },
+ start = {
+ character = 3,
+ line = 0,
+ },
+ },
+ uri = 'file:///src/main.rs',
},
- uri = "file:///src/main.rs"
- }
- } }
- local handler = require'vim.lsp.handlers'['callHierarchy/outgoingCalls']
+ },
+ }
+ local handler = require 'vim.lsp.handlers'['callHierarchy/outgoingCalls']
handler(nil, rust_analyzer_response, {})
return vim.fn.getqflist()
- ]=])
+ end)
local expected = {
{
@@ -3426,58 +3628,62 @@ describe('LSP', function()
describe('vim.lsp.buf.incoming_calls', function()
it('does nothing for an empty response', function()
- local qflist_count = exec_lua([=[
- require'vim.lsp.handlers'['callHierarchy/incomingCalls'](nil, nil, {})
+ local qflist_count = exec_lua(function()
+ require 'vim.lsp.handlers'['callHierarchy/incomingCalls'](nil, nil, {})
return #vim.fn.getqflist()
- ]=])
+ end)
eq(0, qflist_count)
end)
it('opens the quickfix list with the right callee', function()
- local qflist = exec_lua([=[
- local rust_analyzer_response = { {
- from = {
- detail = "fn main()",
- kind = 12,
- name = "main",
- range = {
- ['end'] = {
- character = 1,
- line = 4
+ local qflist = exec_lua(function()
+ local rust_analyzer_response = {
+ {
+ from = {
+ detail = 'fn main()',
+ kind = 12,
+ name = 'main',
+ range = {
+ ['end'] = {
+ character = 1,
+ line = 4,
+ },
+ start = {
+ character = 0,
+ line = 2,
+ },
},
- start = {
- character = 0,
- line = 2
- }
+ selectionRange = {
+ ['end'] = {
+ character = 7,
+ line = 2,
+ },
+ start = {
+ character = 3,
+ line = 2,
+ },
+ },
+ uri = 'file:///src/main.rs',
},
- selectionRange = {
- ['end'] = {
- character = 7,
- line = 2
+ fromRanges = {
+ {
+ ['end'] = {
+ character = 7,
+ line = 3,
+ },
+ start = {
+ character = 4,
+ line = 3,
+ },
},
- start = {
- character = 3,
- line = 2
- }
},
- uri = "file:///src/main.rs"
},
- fromRanges = { {
- ['end'] = {
- character = 7,
- line = 3
- },
- start = {
- character = 4,
- line = 3
- }
- } }
- } }
+ }
- local handler = require'vim.lsp.handlers'['callHierarchy/incomingCalls']
+ local handler = require 'vim.lsp.handlers'['callHierarchy/incomingCalls']
handler(nil, rust_analyzer_response, {})
return vim.fn.getqflist()
- ]=])
+ end)
local expected = {
{
@@ -3502,103 +3708,126 @@ describe('LSP', function()
describe('vim.lsp.buf.typehierarchy subtypes', function()
it('does nothing for an empty response', function()
- local qflist_count = exec_lua([=[
- require'vim.lsp.handlers'['typeHierarchy/subtypes'](nil, nil, {})
+ local qflist_count = exec_lua(function()
+ require 'vim.lsp.handlers'['typeHierarchy/subtypes'](nil, nil, {})
return #vim.fn.getqflist()
- ]=])
+ end)
eq(0, qflist_count)
end)
it('opens the quickfix list with the right subtypes', function()
clear()
exec_lua(create_server_definition)
- local qflist = exec_lua([=[
- local clangd_response = { {
- data = {
- parents = { {
- parents = { {
- parents = { {
- parents = {},
- symbolID = "62B3D268A01B9978"
- } },
- symbolID = "DC9B0AD433B43BEC"
- } },
- symbolID = "06B5F6A19BA9F6A8"
- } },
- symbolID = "EDC336589C09ABB2"
- },
- kind = 5,
- name = "D2",
- range = {
- ["end"] = {
- character = 8,
- line = 9
+ local qflist = exec_lua(function()
+ local clangd_response = {
+ {
+ data = {
+ parents = {
+ {
+ parents = {
+ {
+ parents = {
+ {
+ parents = {},
+ symbolID = '62B3D268A01B9978',
+ },
+ },
+ symbolID = 'DC9B0AD433B43BEC',
+ },
+ },
+ symbolID = '06B5F6A19BA9F6A8',
+ },
+ },
+ symbolID = 'EDC336589C09ABB2',
},
- start = {
- character = 6,
- line = 9
- }
- },
- selectionRange = {
- ["end"] = {
- character = 8,
- line = 9
+ kind = 5,
+ name = 'D2',
+ range = {
+ ['end'] = {
+ character = 8,
+ line = 3,
+ },
+ start = {
+ character = 6,
+ line = 3,
+ },
},
- start = {
- character = 6,
- line = 9
- }
- },
- uri = "file:///home/jiangyinzuo/hello.cpp"
- }, {
- data = {
- parents = { {
- parents = { {
- parents = { {
- parents = {},
- symbolID = "62B3D268A01B9978"
- } },
- symbolID = "DC9B0AD433B43BEC"
- } },
- symbolID = "06B5F6A19BA9F6A8"
- } },
- symbolID = "AFFCAED15557EF08"
- },
- kind = 5,
- name = "D1",
- range = {
- ["end"] = {
- character = 8,
- line = 8
+ selectionRange = {
+ ['end'] = {
+ character = 8,
+ line = 3,
+ },
+ start = {
+ character = 6,
+ line = 3,
+ },
},
- start = {
- character = 6,
- line = 8
- }
+ uri = 'file:///home/jiangyinzuo/hello.cpp',
},
- selectionRange = {
- ["end"] = {
- character = 8,
- line = 8
+ {
+ data = {
+ parents = {
+ {
+ parents = {
+ {
+ parents = {
+ {
+ parents = {},
+ symbolID = '62B3D268A01B9978',
+ },
+ },
+ symbolID = 'DC9B0AD433B43BEC',
+ },
+ },
+ symbolID = '06B5F6A19BA9F6A8',
+ },
+ },
+ symbolID = 'AFFCAED15557EF08',
},
- start = {
- character = 6,
- line = 8
- }
+ kind = 5,
+ name = 'D1',
+ range = {
+ ['end'] = {
+ character = 8,
+ line = 2,
+ },
+ start = {
+ character = 6,
+ line = 2,
+ },
+ },
+ selectionRange = {
+ ['end'] = {
+ character = 8,
+ line = 2,
+ },
+ start = {
+ character = 6,
+ line = 2,
+ },
+ },
+ uri = 'file:///home/jiangyinzuo/hello.cpp',
},
- uri = "file:///home/jiangyinzuo/hello.cpp"
- } }
+ }
- local server = _create_server({
+ local server = _G._create_server({
capabilities = {
- positionEncoding = "utf-8"
+ positionEncoding = 'utf-8',
},
})
local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
- local handler = require'vim.lsp.handlers'['typeHierarchy/subtypes']
- handler(nil, clangd_response, { client_id = client_id, bufnr = 1 })
+ local handler = require 'vim.lsp.handlers'['typeHierarchy/subtypes']
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {
+ 'class B : public A{};',
+ 'class C : public B{};',
+ 'class D1 : public C{};',
+ 'class D2 : public C{};',
+ 'class E : public D1, D2 {};',
+ })
+ handler(nil, clangd_response, { client_id = client_id, bufnr = bufnr })
return vim.fn.getqflist()
- ]=])
+ end)
local expected = {
{
@@ -3606,7 +3835,7 @@ describe('LSP', function()
col = 7,
end_col = 0,
end_lnum = 0,
- lnum = 10,
+ lnum = 4,
module = '',
nr = 0,
pattern = '',
@@ -3620,7 +3849,7 @@ describe('LSP', function()
col = 7,
end_col = 0,
end_lnum = 0,
- lnum = 9,
+ lnum = 3,
module = '',
nr = 0,
pattern = '',
@@ -3637,7 +3866,7 @@ describe('LSP', function()
it('opens the quickfix list with the right subtypes and details', function()
clear()
exec_lua(create_server_definition)
- local qflist = exec_lua([=[
+ local qflist = exec_lua(function()
local jdtls_response = {
{
data = { element = '=hello-java_ed323c3c/_<{Main.java[Main[A' },
@@ -3673,16 +3902,24 @@ describe('LSP', function()
},
}
- local server = _create_server({
+ local server = _G._create_server({
capabilities = {
- positionEncoding = "utf-8"
+ positionEncoding = 'utf-8',
},
})
local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
- local handler = require'vim.lsp.handlers'['typeHierarchy/subtypes']
- handler(nil, jdtls_response, { client_id = client_id, bufnr = 1 })
+ local handler = require 'vim.lsp.handlers'['typeHierarchy/subtypes']
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {
+ 'package mylist;',
+ '',
+ 'public class MyList {',
+ ' static class Inner extends MyList{}',
+ '~}',
+ })
+ handler(nil, jdtls_response, { client_id = client_id, bufnr = bufnr })
return vim.fn.getqflist()
- ]=])
+ end)
local expected = {
{
@@ -3720,103 +3957,127 @@ describe('LSP', function()
describe('vim.lsp.buf.typehierarchy supertypes', function()
it('does nothing for an empty response', function()
- local qflist_count = exec_lua([=[
- require'vim.lsp.handlers'['typeHierarchy/supertypes'](nil, nil, {})
+ local qflist_count = exec_lua(function()
+ require 'vim.lsp.handlers'['typeHierarchy/supertypes'](nil, nil, {})
return #vim.fn.getqflist()
- ]=])
+ end)
eq(0, qflist_count)
end)
it('opens the quickfix list with the right supertypes', function()
clear()
exec_lua(create_server_definition)
- local qflist = exec_lua([=[
- local clangd_response = { {
- data = {
- parents = { {
- parents = { {
- parents = { {
- parents = {},
- symbolID = "62B3D268A01B9978"
- } },
- symbolID = "DC9B0AD433B43BEC"
- } },
- symbolID = "06B5F6A19BA9F6A8"
- } },
- symbolID = "EDC336589C09ABB2"
- },
- kind = 5,
- name = "D2",
- range = {
- ["end"] = {
- character = 8,
- line = 9
+ local qflist = exec_lua(function()
+ local clangd_response = {
+ {
+ data = {
+ parents = {
+ {
+ parents = {
+ {
+ parents = {
+ {
+ parents = {},
+ symbolID = '62B3D268A01B9978',
+ },
+ },
+ symbolID = 'DC9B0AD433B43BEC',
+ },
+ },
+ symbolID = '06B5F6A19BA9F6A8',
+ },
+ },
+ symbolID = 'EDC336589C09ABB2',
},
- start = {
- character = 6,
- line = 9
- }
- },
- selectionRange = {
- ["end"] = {
- character = 8,
- line = 9
+ kind = 5,
+ name = 'D2',
+ range = {
+ ['end'] = {
+ character = 8,
+ line = 3,
+ },
+ start = {
+ character = 6,
+ line = 3,
+ },
},
- start = {
- character = 6,
- line = 9
- }
- },
- uri = "file:///home/jiangyinzuo/hello.cpp"
- }, {
- data = {
- parents = { {
- parents = { {
- parents = { {
- parents = {},
- symbolID = "62B3D268A01B9978"
- } },
- symbolID = "DC9B0AD433B43BEC"
- } },
- symbolID = "06B5F6A19BA9F6A8"
- } },
- symbolID = "AFFCAED15557EF08"
- },
- kind = 5,
- name = "D1",
- range = {
- ["end"] = {
- character = 8,
- line = 8
+ selectionRange = {
+ ['end'] = {
+ character = 8,
+ line = 3,
+ },
+ start = {
+ character = 6,
+ line = 3,
+ },
},
- start = {
- character = 6,
- line = 8
- }
+ uri = 'file:///home/jiangyinzuo/hello.cpp',
},
- selectionRange = {
- ["end"] = {
- character = 8,
- line = 8
+ {
+ data = {
+ parents = {
+ {
+ parents = {
+ {
+ parents = {
+ {
+ parents = {},
+ symbolID = '62B3D268A01B9978',
+ },
+ },
+ symbolID = 'DC9B0AD433B43BEC',
+ },
+ },
+ symbolID = '06B5F6A19BA9F6A8',
+ },
+ },
+ symbolID = 'AFFCAED15557EF08',
},
- start = {
- character = 6,
- line = 8
- }
+ kind = 5,
+ name = 'D1',
+ range = {
+ ['end'] = {
+ character = 8,
+ line = 2,
+ },
+ start = {
+ character = 6,
+ line = 2,
+ },
+ },
+ selectionRange = {
+ ['end'] = {
+ character = 8,
+ line = 2,
+ },
+ start = {
+ character = 6,
+ line = 2,
+ },
+ },
+ uri = 'file:///home/jiangyinzuo/hello.cpp',
},
- uri = "file:///home/jiangyinzuo/hello.cpp"
- } }
+ }
- local server = _create_server({
+ local server = _G._create_server({
capabilities = {
- positionEncoding = "utf-8"
+ positionEncoding = 'utf-8',
},
})
local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
- local handler = require'vim.lsp.handlers'['typeHierarchy/supertypes']
- handler(nil, clangd_response, { client_id = client_id, bufnr = 1 })
+ local handler = require 'vim.lsp.handlers'['typeHierarchy/supertypes']
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {
+ 'class B : public A{};',
+ 'class C : public B{};',
+ 'class D1 : public C{};',
+ 'class D2 : public C{};',
+ 'class E : public D1, D2 {};',
+ })
+
+ handler(nil, clangd_response, { client_id = client_id, bufnr = bufnr })
return vim.fn.getqflist()
- ]=])
+ end)
local expected = {
{
@@ -3824,7 +4085,7 @@ describe('LSP', function()
col = 7,
end_col = 0,
end_lnum = 0,
- lnum = 10,
+ lnum = 4,
module = '',
nr = 0,
pattern = '',
@@ -3838,7 +4099,7 @@ describe('LSP', function()
col = 7,
end_col = 0,
end_lnum = 0,
- lnum = 9,
+ lnum = 3,
module = '',
nr = 0,
pattern = '',
@@ -3855,7 +4116,7 @@ describe('LSP', function()
it('opens the quickfix list with the right supertypes and details', function()
clear()
exec_lua(create_server_definition)
- local qflist = exec_lua([=[
+ local qflist = exec_lua(function()
local jdtls_response = {
{
data = { element = '=hello-java_ed323c3c/_<{Main.java[Main[A' },
@@ -3891,16 +4152,24 @@ describe('LSP', function()
},
}
- local server = _create_server({
+ local server = _G._create_server({
capabilities = {
- positionEncoding = "utf-8"
+ positionEncoding = 'utf-8',
},
})
local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
- local handler = require'vim.lsp.handlers'['typeHierarchy/supertypes']
- handler(nil, jdtls_response, { client_id = client_id, bufnr = 1 })
+ local handler = require 'vim.lsp.handlers'['typeHierarchy/supertypes']
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {
+ 'package mylist;',
+ '',
+ 'public class MyList {',
+ ' static class Inner extends MyList{}',
+ '~}',
+ })
+ handler(nil, jdtls_response, { client_id = client_id, bufnr = bufnr })
return vim.fn.getqflist()
- ]=])
+ end)
local expected = {
{
@@ -3984,18 +4253,19 @@ describe('LSP', function()
eq(true, client.server_capabilities().renameProvider.prepareProvider)
end,
on_setup = function()
- exec_lua([=[
- local bufnr = vim.api.nvim_get_current_buf()
- lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID)
- vim.lsp._stubs = {}
- vim.fn.input = function(opts, on_confirm)
- vim.lsp._stubs.input_prompt = opts.prompt
- vim.lsp._stubs.input_text = opts.default
- return 'renameto' -- expect this value in fake lsp
- end
- vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {'', 'this is line two'})
- vim.fn.cursor(2, 13) -- the space between "line" and "two"
- ]=])
+ exec_lua(function()
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID)
+ vim.lsp._stubs = {}
+ --- @diagnostic disable-next-line:duplicate-set-field
+ vim.fn.input = function(opts, _)
+ vim.lsp._stubs.input_prompt = opts.prompt
+ vim.lsp._stubs.input_text = opts.default
+ return 'renameto' -- expect this value in fake lsp
+ end
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { '', 'this is line two' })
+ vim.fn.cursor(2, 13) -- the space between "line" and "two"
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -4009,12 +4279,24 @@ describe('LSP', function()
eq(table.remove(test.expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'start' then
- exec_lua('vim.lsp.buf.rename()')
+ exec_lua(function()
+ vim.lsp.buf.rename()
+ end)
end
if ctx.method == 'shutdown' then
if test.expected_text then
- eq('New Name: ', exec_lua('return vim.lsp._stubs.input_prompt'))
- eq(test.expected_text, exec_lua('return vim.lsp._stubs.input_text'))
+ eq(
+ 'New Name: ',
+ exec_lua(function()
+ return vim.lsp._stubs.input_prompt
+ end)
+ )
+ eq(
+ test.expected_text,
+ exec_lua(function()
+ return vim.lsp._stubs.input_text
+ end)
+ )
end
client.stop()
end
@@ -4044,25 +4326,31 @@ describe('LSP', function()
on_handler = function(err, result, ctx)
eq(table.remove(expected_handlers), { err, result, ctx })
if ctx.method == 'start' then
- exec_lua([[
- vim.lsp.commands['dummy1'] = function(cmd)
- vim.lsp.commands['dummy2'] = function()
- end
+ exec_lua(function()
+ vim.lsp.commands['dummy1'] = function(_)
+ vim.lsp.commands['dummy2'] = function() end
end
local bufnr = vim.api.nvim_get_current_buf()
- vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID)
+ vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID)
+ --- @diagnostic disable-next-line:duplicate-set-field
vim.fn.inputlist = function()
return 1
end
vim.lsp.buf.code_action()
- ]])
+ end)
elseif ctx.method == 'shutdown' then
- eq('function', exec_lua [[return type(vim.lsp.commands['dummy2'])]])
+ eq(
+ 'function',
+ exec_lua(function()
+ return type(vim.lsp.commands['dummy2'])
+ end)
+ )
client.stop()
end
end,
}
end)
+
it('Calls workspace/executeCommand if no client side command', function()
local client --- @type vim.lsp.Client
local expected_handlers = {
@@ -4089,20 +4377,21 @@ describe('LSP', function()
ctx.version = nil
eq(table.remove(expected_handlers), { err, result, ctx })
if ctx.method == 'start' then
- exec_lua([[
+ exec_lua(function()
local bufnr = vim.api.nvim_get_current_buf()
- vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID)
+ vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID)
vim.fn.inputlist = function()
return 1
end
vim.lsp.buf.code_action()
- ]])
+ end)
elseif ctx.method == 'shutdown' then
client.stop()
end
end,
})
end)
+
it('Filters and automatically applies action if requested', function()
local client --- @type vim.lsp.Client
local expected_handlers = {
@@ -4122,83 +4411,102 @@ describe('LSP', function()
on_handler = function(err, result, ctx)
eq(table.remove(expected_handlers), { err, result, ctx })
if ctx.method == 'start' then
- exec_lua([[
- vim.lsp.commands['preferred_command'] = function(cmd)
- vim.lsp.commands['executed_preferred'] = function()
- end
+ exec_lua(function()
+ vim.lsp.commands['preferred_command'] = function(_)
+ vim.lsp.commands['executed_preferred'] = function() end
end
- vim.lsp.commands['type_annotate_command'] = function(cmd)
- vim.lsp.commands['executed_type_annotate'] = function()
- end
+ vim.lsp.commands['type_annotate_command'] = function(_)
+ vim.lsp.commands['executed_type_annotate'] = function() end
end
local bufnr = vim.api.nvim_get_current_buf()
- vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID)
- vim.lsp.buf.code_action({ filter = function(a) return a.isPreferred end, apply = true, })
+ vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID)
+ vim.lsp.buf.code_action({
+ filter = function(a)
+ return a.isPreferred
+ end,
+ apply = true,
+ })
vim.lsp.buf.code_action({
- -- expect to be returned actions 'type-annotate' and 'type-annotate.foo'
- context = { only = { 'type-annotate' }, },
- apply = true,
- filter = function(a)
- if a.kind == 'type-annotate.foo' then
- vim.lsp.commands['filtered_type_annotate_foo'] = function() end
- return false
- elseif a.kind == 'type-annotate' then
- return true
- else
- assert(nil, 'unreachable')
- end
- end,
+ -- expect to be returned actions 'type-annotate' and 'type-annotate.foo'
+ context = { only = { 'type-annotate' } },
+ apply = true,
+ filter = function(a)
+ if a.kind == 'type-annotate.foo' then
+ vim.lsp.commands['filtered_type_annotate_foo'] = function() end
+ return false
+ elseif a.kind == 'type-annotate' then
+ return true
+ else
+ assert(nil, 'unreachable')
+ end
+ end,
})
- ]])
+ end)
elseif ctx.method == 'shutdown' then
- eq('function', exec_lua [[return type(vim.lsp.commands['executed_preferred'])]])
- eq('function', exec_lua [[return type(vim.lsp.commands['filtered_type_annotate_foo'])]])
- eq('function', exec_lua [[return type(vim.lsp.commands['executed_type_annotate'])]])
+ eq(
+ 'function',
+ exec_lua(function()
+ return type(vim.lsp.commands['executed_preferred'])
+ end)
+ )
+ eq(
+ 'function',
+ exec_lua(function()
+ return type(vim.lsp.commands['filtered_type_annotate_foo'])
+ end)
+ )
+ eq(
+ 'function',
+ exec_lua(function()
+ return type(vim.lsp.commands['executed_type_annotate'])
+ end)
+ )
client.stop()
end
end,
}
end)
+
it('Fallback to command execution on resolve error', function()
clear()
exec_lua(create_server_definition)
- local result = exec_lua([[
- local server = _create_server({
+ local result = exec_lua(function()
+ local server = _G._create_server({
capabilities = {
executeCommandProvider = {
- commands = {"command:1"},
+ commands = { 'command:1' },
},
codeActionProvider = {
- resolveProvider = true
- }
+ resolveProvider = true,
+ },
},
handlers = {
- ["textDocument/codeAction"] = function(_, _, callback)
+ ['textDocument/codeAction'] = function(_, _, callback)
callback(nil, {
{
- title = "Code Action 1",
+ title = 'Code Action 1',
command = {
- title = "Command 1",
- command = "command:1",
- }
- }
+ title = 'Command 1',
+ command = 'command:1',
+ },
+ },
})
end,
- ["codeAction/resolve"] = function(_, _, callback)
- callback("resolve failed", nil)
+ ['codeAction/resolve'] = function(_, _, callback)
+ callback('resolve failed', nil)
end,
- }
+ },
})
- local client_id = vim.lsp.start({
- name = "dummy",
+ local client_id = assert(vim.lsp.start({
+ name = 'dummy',
cmd = server.cmd,
- })
+ }))
vim.lsp.buf.code_action({ apply = true })
vim.lsp.stop_client(client_id)
return server.messages
- ]])
+ end)
eq('codeAction/resolve', result[4].method)
eq('workspace/executeCommand', result[5].method)
eq('command:1', result[5].params.command)
@@ -4212,6 +4520,7 @@ describe('LSP', function()
pcall_err(exec_lua, 'vim.lsp.commands[1] = function() end')
)
end)
+
it('Accepts only function values', function()
matches(
'.*Command added to `vim.lsp.commands` must be a function',
@@ -4241,32 +4550,32 @@ describe('LSP', function()
eq(table.remove(expected_handlers), { err, result, ctx })
if ctx.method == 'start' then
local fake_uri = 'file:///fake/uri'
- local cmd = exec_lua(
- [[
- fake_uri = ...
+ local cmd = exec_lua(function()
local bufnr = vim.uri_to_bufnr(fake_uri)
vim.fn.bufload(bufnr)
- vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {'One line'})
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { 'One line' })
local lenses = {
{
range = {
- start = { line = 0, character = 0, },
- ['end'] = { line = 0, character = 8 }
+ start = { line = 0, character = 0 },
+ ['end'] = { line = 0, character = 8 },
},
- command = { title = 'Lens1', command = 'Dummy' }
+ command = { title = 'Lens1', command = 'Dummy' },
},
}
- vim.lsp.codelens.on_codelens(nil, lenses, {method='textDocument/codeLens', client_id=1, bufnr=bufnr})
+ vim.lsp.codelens.on_codelens(
+ nil,
+ lenses,
+ { method = 'textDocument/codeLens', client_id = 1, bufnr = bufnr }
+ )
local cmd_called = nil
- vim.lsp.commands['Dummy'] = function(command)
- cmd_called = command
+ vim.lsp.commands['Dummy'] = function(command0)
+ cmd_called = command0
end
vim.api.nvim_set_current_buf(bufnr)
vim.lsp.codelens.run()
return cmd_called
- ]],
- fake_uri
- )
+ end)
eq({ command = 'Dummy', title = 'Lens1' }, cmd)
elseif ctx.method == 'shutdown' then
client.stop()
@@ -4287,20 +4596,20 @@ describe('LSP', function()
client = client_
end,
on_setup = function()
- exec_lua([=[
- local bufnr = vim.api.nvim_get_current_buf()
- vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {'One line'})
- vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID)
-
- CALLED = false
- RESPONSE = nil
- local on_codelens = vim.lsp.codelens.on_codelens
- vim.lsp.codelens.on_codelens = function (err, result, ...)
- CALLED = true
- RESPONSE = { err = err, result = result }
- return on_codelens(err, result, ...)
- end
- ]=])
+ exec_lua(function()
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { 'One line' })
+ vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID)
+
+ _G.CALLED = false
+ _G.RESPONSE = nil
+ local on_codelens = vim.lsp.codelens.on_codelens
+ vim.lsp.codelens.on_codelens = function(err, result, ...)
+ _G.CALLED = true
+ _G.RESPONSE = { err = err, result = result }
+ return on_codelens(err, result, ...)
+ end
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -4310,42 +4619,52 @@ describe('LSP', function()
eq(table.remove(expected_handlers), { err, result, ctx })
if ctx.method == 'start' then
-- 1. first codelens request errors
- local response = exec_lua([=[
- CALLED = false
+ local response = exec_lua(function()
+ _G.CALLED = false
vim.lsp.codelens.refresh()
- vim.wait(100, function () return CALLED end)
- return RESPONSE
- ]=])
+ vim.wait(100, function()
+ return _G.CALLED
+ end)
+ return _G.RESPONSE
+ end)
eq({ err = { code = -32002, message = 'ServerNotInitialized' } }, response)
-- 2. second codelens request runs
- response = exec_lua([=[
- CALLED = false
- local cmd_called = nil
- vim.lsp.commands["Dummy"] = function (command)
- cmd_called = command
+ response = exec_lua(function()
+ _G.CALLED = false
+ local cmd_called --- @type string?
+ vim.lsp.commands['Dummy'] = function(command0)
+ cmd_called = command0
end
vim.lsp.codelens.refresh()
- vim.wait(100, function () return CALLED end)
+ vim.wait(100, function()
+ return _G.CALLED
+ end)
vim.lsp.codelens.run()
- vim.wait(100, function () return cmd_called end)
+ vim.wait(100, function()
+ return cmd_called ~= nil
+ end)
return cmd_called
- ]=])
+ end)
eq({ command = 'Dummy', title = 'Lens1' }, response)
-- 3. third codelens request runs
- response = exec_lua([=[
- CALLED = false
- local cmd_called = nil
- vim.lsp.commands["Dummy"] = function (command)
- cmd_called = command
+ response = exec_lua(function()
+ _G.CALLED = false
+ local cmd_called --- @type string?
+ vim.lsp.commands['Dummy'] = function(command0)
+ cmd_called = command0
end
vim.lsp.codelens.refresh()
- vim.wait(100, function () return CALLED end)
+ vim.wait(100, function()
+ return _G.CALLED
+ end)
vim.lsp.codelens.run()
- vim.wait(100, function () return cmd_called end)
+ vim.wait(100, function()
+ return cmd_called ~= nil
+ end)
return cmd_called
- ]=])
+ end)
eq({ command = 'Dummy', title = 'Lens2' }, response)
elseif ctx.method == 'shutdown' then
client.stop()
@@ -4363,79 +4682,73 @@ describe('LSP', function()
exec_lua(create_server_definition)
-- setup lsp
- exec_lua(
- [[
- local lens_title_per_fake_uri = ...
- local server = _create_server({
- capabilities = {
- codeLensProvider = {
- resolveProvider = true
- },
+ exec_lua(function()
+ local server = _G._create_server({
+ capabilities = {
+ codeLensProvider = {
+ resolveProvider = true,
},
- handlers = {
- ["textDocument/codeLens"] = function(method, params, callback)
- local lenses = {
- {
- range = {
- start = { line = 0, character = 0 },
- ['end'] = { line = 0, character = 0 },
- },
- command = {
- title = lens_title_per_fake_uri[params.textDocument.uri],
- command = 'Dummy',
- },
+ },
+ handlers = {
+ ['textDocument/codeLens'] = function(_, params, callback)
+ local lenses = {
+ {
+ range = {
+ start = { line = 0, character = 0 },
+ ['end'] = { line = 0, character = 0 },
},
- }
- callback(nil, lenses)
- end,
- }
- })
+ command = {
+ title = lens_title_per_fake_uri[params.textDocument.uri],
+ command = 'Dummy',
+ },
+ },
+ }
+ callback(nil, lenses)
+ end,
+ },
+ })
- CLIENT_ID = vim.lsp.start({
- name = "dummy",
- cmd = server.cmd,
- })
- ]],
- lens_title_per_fake_uri
- )
+ _G.CLIENT_ID = vim.lsp.start({
+ name = 'dummy',
+ cmd = server.cmd,
+ })
+ end)
-- create buffers and setup handler
- exec_lua(
- [[
- local lens_title_per_fake_uri = ...
- local default_buf = vim.api.nvim_get_current_buf()
- for fake_uri, _ in pairs(lens_title_per_fake_uri) do
- local bufnr = vim.uri_to_bufnr(fake_uri)
- vim.api.nvim_set_current_buf(bufnr)
- vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {'Some contents'})
- vim.lsp.buf_attach_client(bufnr, CLIENT_ID)
- end
- vim.api.nvim_buf_delete(default_buf, {force = true})
-
- REQUEST_COUNT = vim.tbl_count(lens_title_per_fake_uri)
- RESPONSES = {}
- local on_codelens = vim.lsp.codelens.on_codelens
- vim.lsp.codelens.on_codelens = function (err, result, ctx, ...)
- table.insert(RESPONSES, { err = err, result = result, ctx = ctx })
- return on_codelens(err, result, ctx, ...)
- end
- ]],
- lens_title_per_fake_uri
- )
+ exec_lua(function()
+ local default_buf = vim.api.nvim_get_current_buf()
+ for fake_uri in pairs(lens_title_per_fake_uri) do
+ local bufnr = vim.uri_to_bufnr(fake_uri)
+ vim.api.nvim_set_current_buf(bufnr)
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { 'Some contents' })
+ vim.lsp.buf_attach_client(bufnr, _G.CLIENT_ID)
+ end
+ vim.api.nvim_buf_delete(default_buf, { force = true })
+
+ _G.REQUEST_COUNT = vim.tbl_count(lens_title_per_fake_uri)
+ _G.RESPONSES = {}
+ local on_codelens = vim.lsp.codelens.on_codelens
+ vim.lsp.codelens.on_codelens = function(err, result, ctx, ...)
+ table.insert(_G.RESPONSES, { err = err, result = result, ctx = ctx })
+ return on_codelens(err, result, ctx, ...)
+ end
+ end)
-- call codelens refresh
- local cmds = exec_lua([[
- RESPONSES = {}
+ local cmds = exec_lua(function()
+ _G.RESPONSES = {}
vim.lsp.codelens.refresh()
- vim.wait(100, function () return #RESPONSES >= REQUEST_COUNT end)
+ vim.wait(100, function()
+ return #_G.RESPONSES >= _G.REQUEST_COUNT
+ end)
local cmds = {}
- for _, resp in ipairs(RESPONSES) do
+ for _, resp in ipairs(_G.RESPONSES) do
local uri = resp.ctx.params.textDocument.uri
cmds[uri] = resp.result[1].command
end
return cmds
- ]])
+ end)
eq({ command = 'Dummy', title = 'Lens1' }, cmds['file:///fake/uri1'])
eq({ command = 'Dummy', title = 'Lens2' }, cmds['file:///fake/uri2'])
end)
@@ -4450,23 +4763,24 @@ describe('LSP', function()
client = c
end,
on_handler = function()
- local notify_msg = exec_lua([[
+ local notify_msg = exec_lua(function()
local bufnr = vim.api.nvim_get_current_buf()
- vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID)
- local notify_msg
+ vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID)
+ local notify_msg --- @type string?
local notify = vim.notify
- vim.notify = function(msg, log_level)
+ vim.notify = function(msg, _)
notify_msg = msg
end
vim.lsp.buf.format({ name = 'does-not-exist' })
vim.notify = notify
return notify_msg
- ]])
+ end)
eq('[LSP] Format request failed, no matching language servers.', notify_msg)
client.stop()
end,
}
end)
+
it('Sends textDocument/formatting request to format buffer', function()
local expected_handlers = {
{ NIL, {}, { method = 'shutdown', client_id = 1 } },
@@ -4481,25 +4795,114 @@ describe('LSP', function()
on_handler = function(_, _, ctx)
table.remove(expected_handlers)
if ctx.method == 'start' then
- local notify_msg = exec_lua([[
+ local notify_msg = exec_lua(function()
local bufnr = vim.api.nvim_get_current_buf()
- vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID)
- local notify_msg
+ vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID)
+ local notify_msg --- @type string?
local notify = vim.notify
- vim.notify = function(msg, log_level)
+ vim.notify = function(msg, _)
notify_msg = msg
end
vim.lsp.buf.format({ bufnr = bufnr })
vim.notify = notify
return notify_msg
- ]])
- eq(NIL, notify_msg)
+ end)
+ eq(nil, notify_msg)
+ elseif ctx.method == 'shutdown' then
+ client.stop()
+ end
+ end,
+ }
+ end)
+
+ it('Sends textDocument/rangeFormatting request to format a range', function()
+ local expected_handlers = {
+ { NIL, {}, { method = 'shutdown', client_id = 1 } },
+ { NIL, {}, { method = 'start', client_id = 1 } },
+ }
+ local client --- @type vim.lsp.Client
+ test_rpc_server {
+ test_name = 'range_formatting',
+ on_init = function(c)
+ client = c
+ end,
+ on_handler = function(_, _, ctx)
+ table.remove(expected_handlers)
+ if ctx.method == 'start' then
+ local notify_msg = exec_lua(function()
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, { 'foo', 'bar' })
+ vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID)
+ local notify_msg --- @type string?
+ local notify = vim.notify
+ vim.notify = function(msg, _)
+ notify_msg = msg
+ end
+ vim.lsp.buf.format({
+ bufnr = bufnr,
+ range = {
+ start = { 1, 1 },
+ ['end'] = { 1, 1 },
+ },
+ })
+ vim.notify = notify
+ return notify_msg
+ end)
+ eq(nil, notify_msg)
+ elseif ctx.method == 'shutdown' then
+ client.stop()
+ end
+ end,
+ }
+ end)
+
+ it('Sends textDocument/rangesFormatting request to format multiple ranges', function()
+ local expected_handlers = {
+ { NIL, {}, { method = 'shutdown', client_id = 1 } },
+ { NIL, {}, { method = 'start', client_id = 1 } },
+ }
+ local client --- @type vim.lsp.Client
+ test_rpc_server {
+ test_name = 'ranges_formatting',
+ on_init = function(c)
+ client = c
+ end,
+ on_handler = function(_, _, ctx)
+ table.remove(expected_handlers)
+ if ctx.method == 'start' then
+ local notify_msg = exec_lua(function()
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, { 'foo', 'bar', 'baz' })
+ vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID)
+ local notify_msg --- @type string?
+ local notify = vim.notify
+ vim.notify = function(msg, _)
+ notify_msg = msg
+ end
+ vim.lsp.buf.format({
+ bufnr = bufnr,
+ range = {
+ {
+ start = { 1, 1 },
+ ['end'] = { 1, 1 },
+ },
+ {
+ start = { 2, 2 },
+ ['end'] = { 2, 2 },
+ },
+ },
+ })
+ vim.notify = notify
+ return notify_msg
+ end)
+ eq(nil, notify_msg)
elseif ctx.method == 'shutdown' then
client.stop()
end
end,
}
end)
+
it('Can format async', function()
local expected_handlers = {
{ NIL, {}, { method = 'shutdown', client_id = 1 } },
@@ -4514,29 +4917,31 @@ describe('LSP', function()
on_handler = function(_, _, ctx)
table.remove(expected_handlers)
if ctx.method == 'start' then
- local result = exec_lua([[
+ local result = exec_lua(function()
local bufnr = vim.api.nvim_get_current_buf()
- vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID)
+ vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID)
- local notify_msg
+ local notify_msg --- @type string?
local notify = vim.notify
- vim.notify = function(msg, log_level)
+ vim.notify = function(msg, _)
notify_msg = msg
end
local handler = vim.lsp.handlers['textDocument/formatting']
local handler_called = false
- vim.lsp.handlers['textDocument/formatting'] = function(...)
+ vim.lsp.handlers['textDocument/formatting'] = function()
handler_called = true
end
vim.lsp.buf.format({ bufnr = bufnr, async = true })
- vim.wait(1000, function() return handler_called end)
+ vim.wait(1000, function()
+ return handler_called
+ end)
vim.notify = notify
vim.lsp.handlers['textDocument/formatting'] = handler
- return {notify = notify_msg, handler_called = handler_called}
- ]])
+ return { notify = notify_msg, handler_called = handler_called }
+ end)
eq({ handler_called = true }, result)
elseif ctx.method == 'shutdown' then
client.stop()
@@ -4544,24 +4949,27 @@ describe('LSP', function()
end,
}
end)
+
it('format formats range in visual mode', function()
exec_lua(create_server_definition)
- local result = exec_lua([[
- local server = _create_server({ capabilities = {
- documentFormattingProvider = true,
- documentRangeFormattingProvider = true,
- }})
+ local result = exec_lua(function()
+ local server = _G._create_server({
+ capabilities = {
+ documentFormattingProvider = true,
+ documentRangeFormattingProvider = true,
+ },
+ })
local bufnr = vim.api.nvim_get_current_buf()
- local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
+ local client_id = assert(vim.lsp.start({ name = 'dummy', cmd = server.cmd }))
vim.api.nvim_win_set_buf(0, bufnr)
- vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, {'foo', 'bar'})
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, { 'foo', 'bar' })
vim.api.nvim_win_set_cursor(0, { 1, 0 })
vim.cmd.normal('v')
vim.api.nvim_win_set_cursor(0, { 2, 3 })
vim.lsp.buf.format({ bufnr = bufnr, false })
vim.lsp.stop_client(client_id)
return server.messages
- ]])
+ end)
eq('textDocument/rangeFormatting', result[3].method)
local expected_range = {
start = { line = 0, character = 0 },
@@ -4569,17 +4977,20 @@ describe('LSP', function()
}
eq(expected_range, result[3].params.range)
end)
+
it('format formats range in visual line mode', function()
exec_lua(create_server_definition)
- local result = exec_lua([[
- local server = _create_server({ capabilities = {
- documentFormattingProvider = true,
- documentRangeFormattingProvider = true,
- }})
+ local result = exec_lua(function()
+ local server = _G._create_server({
+ capabilities = {
+ documentFormattingProvider = true,
+ documentRangeFormattingProvider = true,
+ },
+ })
local bufnr = vim.api.nvim_get_current_buf()
- local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
+ local client_id = assert(vim.lsp.start({ name = 'dummy', cmd = server.cmd }))
vim.api.nvim_win_set_buf(0, bufnr)
- vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, {'foo', 'bar baz'})
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, { 'foo', 'bar baz' })
vim.api.nvim_win_set_cursor(0, { 1, 2 })
vim.cmd.normal('V')
vim.api.nvim_win_set_cursor(0, { 2, 1 })
@@ -4587,7 +4998,7 @@ describe('LSP', function()
-- Format again with visual lines going from bottom to top
-- Must result in same formatting
- vim.cmd.normal("<ESC>")
+ vim.cmd.normal('<ESC>')
vim.api.nvim_win_set_cursor(0, { 2, 1 })
vim.cmd.normal('V')
vim.api.nvim_win_set_cursor(0, { 1, 2 })
@@ -4595,7 +5006,7 @@ describe('LSP', function()
vim.lsp.stop_client(client_id)
return server.messages
- ]])
+ end)
local expected_methods = {
'initialize',
'initialized',
@@ -4620,40 +5031,57 @@ describe('LSP', function()
eq(expected_range, result[3].params.range)
eq(expected_range, result[5].params.range)
end)
+
it('Aborts with notify if no clients support requested method', function()
exec_lua(create_server_definition)
- exec_lua([[
+ exec_lua(function()
vim.notify = function(msg, _)
- notify_msg = msg
+ _G.notify_msg = msg
end
- ]])
+ end)
local fail_msg = '[LSP] Format request failed, no matching language servers.'
--- @param name string
--- @param formatting boolean
--- @param range_formatting boolean
local function check_notify(name, formatting, range_formatting)
local timeout_msg = '[LSP][' .. name .. '] timeout'
- exec_lua(
- [[
- local formatting, range_formatting, name = ...
- local server = _create_server({ capabilities = {
- documentFormattingProvider = formatting,
- documentRangeFormattingProvider = range_formatting,
- }})
+ exec_lua(function()
+ local server = _G._create_server({
+ capabilities = {
+ documentFormattingProvider = formatting,
+ documentRangeFormattingProvider = range_formatting,
+ },
+ })
vim.lsp.start({ name = name, cmd = server.cmd })
- notify_msg = nil
+ _G.notify_msg = nil
vim.lsp.buf.format({ name = name, timeout_ms = 1 })
- ]],
- formatting,
- range_formatting,
- name
+ end)
+ eq(
+ formatting and timeout_msg or fail_msg,
+ exec_lua(function()
+ return _G.notify_msg
+ end)
+ )
+ exec_lua(function()
+ _G.notify_msg = nil
+ vim.lsp.buf.format({
+ name = name,
+ timeout_ms = 1,
+ range = {
+ start = { 1, 0 },
+ ['end'] = {
+ 1,
+ 0,
+ },
+ },
+ })
+ end)
+ eq(
+ range_formatting and timeout_msg or fail_msg,
+ exec_lua(function()
+ return _G.notify_msg
+ end)
)
- eq(formatting and timeout_msg or fail_msg, exec_lua('return notify_msg'))
- exec_lua([[
- notify_msg = nil
- vim.lsp.buf.format({ name = name, timeout_ms = 1, range = {start={1, 0}, ['end']={1, 0}}})
- ]])
- eq(range_formatting and timeout_msg or fail_msg, exec_lua('return notify_msg'))
end
check_notify('none', false, false)
check_notify('formatting', true, false)
@@ -4683,10 +5111,9 @@ describe('LSP', function()
},
}
exec_lua(create_server_definition)
- exec_lua(
- [[
- _G.mock_locations = ...
- _G.server = _create_server({
+ exec_lua(function()
+ _G.mock_locations = mock_locations
+ _G.server = _G._create_server({
---@type lsp.ServerCapabilities
capabilities = {
definitionProvider = true,
@@ -4710,26 +5137,25 @@ describe('LSP', function()
name = 'vim.foobar',
kind = 12, ---@type lsp.SymbolKind
location = _G.mock_locations[2],
- }
+ },
})
end,
},
})
- _G.client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
- ]],
- mock_locations
- )
+ _G.client_id = vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
+ end)
end)
+
after_each(function()
- exec_lua [[
+ exec_lua(function()
vim.lsp.stop_client(_G.client_id)
- ]]
+ end)
end)
it('with flags=c, returns matching tags using textDocument/definition', function()
- local result = exec_lua [[
+ local result = exec_lua(function()
return vim.lsp.tagfunc('foobar', 'c')
- ]]
+ end)
eq({
{
cmd = '/\\%6l\\%1c/', -- for location (5, 23)
@@ -4740,9 +5166,9 @@ describe('LSP', function()
end)
it('without flags=c, returns all matching tags using workspace/symbol', function()
- local result = exec_lua [[
+ local result = exec_lua(function()
return vim.lsp.tagfunc('foobar', '')
- ]]
+ end)
eq({
{
cmd = '/\\%6l\\%1c/', -- for location (5, 23)
@@ -4761,80 +5187,81 @@ describe('LSP', function()
end)
describe('cmd', function()
- it('can connect to lsp server via rpc.connect', function()
- local result = exec_lua [[
- local uv = vim.uv
- local server = uv.new_tcp()
- local init = nil
- server:bind('127.0.0.1', 0)
- server:listen(127, function(err)
- assert(not err, err)
- local socket = uv.new_tcp()
- server:accept(socket)
- socket:read_start(require('vim.lsp.rpc').create_read_loop(function(body)
- init = body
- socket:close()
- end))
- end)
- local port = server:getsockname().port
+ it('connects to lsp server via rpc.connect using ip address', function()
+ exec_lua(create_tcp_echo_server)
+ local result = exec_lua(function()
+ local server, port, last_message = _G._create_tcp_server('127.0.0.1')
vim.lsp.start({ name = 'dummy', cmd = vim.lsp.rpc.connect('127.0.0.1', port) })
- vim.wait(1000, function() return init ~= nil end)
- assert(init, "server must receive `initialize` request")
+ vim.wait(1000, function()
+ return last_message() ~= nil
+ end)
+ local init = last_message()
+ assert(init, 'server must receive `initialize` request')
+ server:close()
+ server:shutdown()
+ return vim.json.decode(init)
+ end)
+ eq('initialize', result.method)
+ end)
+
+ it('connects to lsp server via rpc.connect using hostname', function()
+ skip(is_os('bsd'), 'issue with host resolution in ci')
+ exec_lua(create_tcp_echo_server)
+ local result = exec_lua(function()
+ local server, port, last_message = _G._create_tcp_server('::1')
+ vim.lsp.start({ name = 'dummy', cmd = vim.lsp.rpc.connect('localhost', port) })
+ vim.wait(1000, function()
+ return last_message() ~= nil
+ end)
+ local init = last_message()
+ assert(init, 'server must receive `initialize` request')
server:close()
server:shutdown()
return vim.json.decode(init)
- ]]
+ end)
eq('initialize', result.method)
end)
+
it('can connect to lsp server via pipe or domain_socket', function()
- local tmpfile --- @type string
- if is_os('win') then
- tmpfile = '\\\\.\\\\pipe\\pipe.test'
- else
- tmpfile = tmpname()
- os.remove(tmpfile)
- end
- local result = exec_lua(
- [[
- local SOCK = ...
+ local tmpfile = is_os('win') and '\\\\.\\\\pipe\\pipe.test' or tmpname(false)
+ local result = exec_lua(function()
local uv = vim.uv
- local server = uv.new_pipe(false)
- server:bind(SOCK)
+ local server = assert(uv.new_pipe(false))
+ server:bind(tmpfile)
local init = nil
server:listen(127, function(err)
- assert(not err, err)
- local client = uv.new_pipe()
- server:accept(client)
- client:read_start(require("vim.lsp.rpc").create_read_loop(function(body)
- init = body
- client:close()
- end))
+ assert(not err, err)
+ local client = assert(vim.uv.new_pipe())
+ server:accept(client)
+ client:read_start(require('vim.lsp.rpc').create_read_loop(function(body)
+ init = body
+ client:close()
+ end))
+ end)
+ vim.lsp.start({ name = 'dummy', cmd = vim.lsp.rpc.connect(tmpfile) })
+ vim.wait(1000, function()
+ return init ~= nil
end)
- vim.lsp.start({ name = "dummy", cmd = vim.lsp.rpc.connect(SOCK) })
- vim.wait(1000, function() return init ~= nil end)
- assert(init, "server must receive `initialize` request")
+ assert(init, 'server must receive `initialize` request')
server:close()
server:shutdown()
return vim.json.decode(init)
- ]],
- tmpfile
- )
+ end)
eq('initialize', result.method)
end)
end)
describe('handlers', function()
it('handler can return false as response', function()
- local result = exec_lua [[
- local uv = vim.uv
- local server = uv.new_tcp()
+ local result = exec_lua(function()
+ local server = assert(vim.uv.new_tcp())
local messages = {}
local responses = {}
server:bind('127.0.0.1', 0)
server:listen(127, function(err)
assert(not err, err)
- local socket = uv.new_tcp()
+ local socket = assert(vim.uv.new_tcp())
server:accept(socket)
socket:read_start(require('vim.lsp.rpc').create_read_loop(function(body)
local payload = vim.json.decode(body)
@@ -4845,10 +5272,10 @@ describe('LSP', function()
id = payload.id,
jsonrpc = '2.0',
result = {
- capabilities = {}
+ capabilities = {},
},
})
- socket:write(table.concat({'Content-Length: ', tostring(#msg), '\r\n\r\n', msg}))
+ socket:write(table.concat({ 'Content-Length: ', tostring(#msg), '\r\n\r\n', msg }))
elseif payload.method == 'initialized' then
local msg = vim.json.encode({
id = 10,
@@ -4856,7 +5283,7 @@ describe('LSP', function()
method = 'dummy',
params = {},
})
- socket:write(table.concat({'Content-Length: ', tostring(#msg), '\r\n\r\n', msg}))
+ socket:write(table.concat({ 'Content-Length: ', tostring(#msg), '\r\n\r\n', msg }))
end
else
table.insert(responses, payload)
@@ -4866,20 +5293,24 @@ describe('LSP', function()
end)
local port = server:getsockname().port
local handler_called = false
- vim.lsp.handlers['dummy'] = function(err, result)
+ vim.lsp.handlers['dummy'] = function(_, _)
handler_called = true
return false
end
- local client_id = vim.lsp.start({ name = 'dummy', cmd = vim.lsp.rpc.connect('127.0.0.1', port) })
- local client = vim.lsp.get_client_by_id(client_id)
- vim.wait(1000, function() return #messages == 2 and handler_called and #responses == 1 end)
+ local client_id =
+ assert(vim.lsp.start({ name = 'dummy', cmd = vim.lsp.rpc.connect('127.0.0.1', port) }))
+ vim.lsp.get_client_by_id(client_id)
+ vim.wait(1000, function()
+ return #messages == 2 and handler_called and #responses == 1
+ end)
server:close()
server:shutdown()
return {
messages = messages,
handler_called = handler_called,
- responses = responses }
- ]]
+ responses = responses,
+ }
+ end)
local expected = {
messages = { 'initialize', 'initialized' },
handler_called = true,
@@ -4897,9 +5328,7 @@ describe('LSP', function()
describe('#dynamic vim.lsp._dynamic', function()
it('supports dynamic registration', function()
- ---@type string
- local root_dir = tmpname()
- os.remove(root_dir)
+ local root_dir = tmpname(false)
mkdir(root_dir)
local tmpfile = root_dir .. '/dynamic.foo'
local file = io.open(tmpfile, 'w')
@@ -4908,17 +5337,14 @@ describe('LSP', function()
end
exec_lua(create_server_definition)
- local result = exec_lua(
- [[
- local root_dir, tmpfile = ...
-
- local server = _create_server()
- local client_id = vim.lsp.start({
+ local result = exec_lua(function()
+ local server = _G._create_server()
+ local client_id = assert(vim.lsp.start({
name = 'dynamic-test',
cmd = server.cmd,
root_dir = root_dir,
get_language_id = function()
- return "dummy-lang"
+ return 'dummy-lang'
end,
capabilities = {
textDocument = {
@@ -4930,9 +5356,7 @@ describe('LSP', function()
},
},
},
- })
-
- local expected_messages = 2 -- initialize, initialized
+ }))
vim.lsp.handlers['client/registerCapability'](nil, {
registrations = {
@@ -4940,9 +5364,11 @@ describe('LSP', function()
id = 'formatting',
method = 'textDocument/formatting',
registerOptions = {
- documentSelector = {{
- pattern = root_dir .. '/*.foo',
- }},
+ documentSelector = {
+ {
+ pattern = root_dir .. '/*.foo',
+ },
+ },
},
},
},
@@ -4954,12 +5380,12 @@ describe('LSP', function()
id = 'range-formatting',
method = 'textDocument/rangeFormatting',
registerOptions = {
- documentSelector = {
+ documentSelector = {
{
- language = "dummy-lang"
+ language = 'dummy-lang',
},
- }
- }
+ },
+ },
},
},
}, { client_id = client_id })
@@ -4976,26 +5402,22 @@ describe('LSP', function()
local result = {}
local function check(method, fname)
local bufnr = fname and vim.fn.bufadd(fname) or nil
- local client = vim.lsp.get_client_by_id(client_id)
+ local client = assert(vim.lsp.get_client_by_id(client_id))
result[#result + 1] = {
method = method,
fname = fname,
- supported = client.supports_method(method, {bufnr = bufnr})
+ supported = client.supports_method(method, { bufnr = bufnr }),
}
end
-
- check("textDocument/formatting")
- check("textDocument/formatting", tmpfile)
- check("textDocument/rangeFormatting")
- check("textDocument/rangeFormatting", tmpfile)
- check("textDocument/completion")
+ check('textDocument/formatting')
+ check('textDocument/formatting', tmpfile)
+ check('textDocument/rangeFormatting')
+ check('textDocument/rangeFormatting', tmpfile)
+ check('textDocument/completion')
return result
- ]],
- root_dir,
- tmpfile
- )
+ end)
eq(5, #result)
eq({ method = 'textDocument/formatting', supported = false }, result[1])
@@ -5007,16 +5429,26 @@ describe('LSP', function()
end)
describe('vim.lsp._watchfiles', function()
+ --- @type integer, integer, integer
+ local created, changed, deleted
+
+ setup(function()
+ clear()
+ created = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]])
+ changed = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]])
+ deleted = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]])
+ end)
+
local function test_filechanges(watchfunc)
it(
string.format('sends notifications when files change (watchfunc=%s)', watchfunc),
function()
- if watchfunc == 'fswatch' then
+ if watchfunc == 'inotify' then
skip(is_os('win'), 'not supported on windows')
skip(is_os('mac'), 'flaky test on mac')
skip(
- not is_ci() and fn.executable('fswatch') == 0,
- 'fswatch not installed and not on CI'
+ not is_ci() and fn.executable('inotifywait') == 0,
+ 'inotify-tools not installed and not on CI'
)
end
@@ -5033,87 +5465,80 @@ describe('LSP', function()
)
end
- local root_dir = tmpname()
- os.remove(root_dir)
+ local root_dir = tmpname(false)
mkdir(root_dir)
exec_lua(create_server_definition)
- local result = exec_lua(
- [[
- local root_dir, watchfunc = ...
-
- local server = _create_server()
- local client_id = vim.lsp.start({
- name = 'watchfiles-test',
- cmd = server.cmd,
- root_dir = root_dir,
- capabilities = {
- workspace = {
- didChangeWatchedFiles = {
- dynamicRegistration = true,
+ local result = exec_lua(function()
+ local server = _G._create_server()
+ local client_id = assert(vim.lsp.start({
+ name = 'watchfiles-test',
+ cmd = server.cmd,
+ root_dir = root_dir,
+ capabilities = {
+ workspace = {
+ didChangeWatchedFiles = {
+ dynamicRegistration = true,
+ },
},
},
- },
- })
+ }))
- require('vim.lsp._watchfiles')._watchfunc = require('vim._watch')[watchfunc]
+ require('vim.lsp._watchfiles')._watchfunc = require('vim._watch')[watchfunc]
- local expected_messages = 0
+ local expected_messages = 0
- local msg_wait_timeout = watchfunc == 'watch' and 200 or 2500
+ local msg_wait_timeout = watchfunc == 'watch' and 200 or 2500
- local function wait_for_message(incr)
- expected_messages = expected_messages + (incr or 1)
- assert(
- vim.wait(msg_wait_timeout, function()
- return #server.messages == expected_messages
- end),
- 'Timed out waiting for expected number of messages. Current messages seen so far: '
- .. vim.inspect(server.messages)
- )
- end
+ local function wait_for_message(incr)
+ expected_messages = expected_messages + (incr or 1)
+ assert(
+ vim.wait(msg_wait_timeout, function()
+ return #server.messages == expected_messages
+ end),
+ 'Timed out waiting for expected number of messages. Current messages seen so far: '
+ .. vim.inspect(server.messages)
+ )
+ end
- wait_for_message(2) -- initialize, initialized
+ wait_for_message(2) -- initialize, initialized
- vim.lsp.handlers['client/registerCapability'](nil, {
- registrations = {
- {
- id = 'watchfiles-test-0',
- method = 'workspace/didChangeWatchedFiles',
- registerOptions = {
- watchers = {
- {
- globPattern = '**/watch',
- kind = 7,
+ vim.lsp.handlers['client/registerCapability'](nil, {
+ registrations = {
+ {
+ id = 'watchfiles-test-0',
+ method = 'workspace/didChangeWatchedFiles',
+ registerOptions = {
+ watchers = {
+ {
+ globPattern = '**/watch',
+ kind = 7,
+ },
},
},
},
},
- },
- }, { client_id = client_id })
+ }, { client_id = client_id })
- if watchfunc ~= 'watch' then
- vim.wait(100)
- end
+ if watchfunc ~= 'watch' then
+ vim.wait(100)
+ end
- local path = root_dir .. '/watch'
- local tmp = vim.fn.tempname()
- io.open(tmp, 'w'):close()
- vim.uv.fs_rename(tmp, path)
+ local path = root_dir .. '/watch'
+ local tmp = vim.fn.tempname()
+ io.open(tmp, 'w'):close()
+ vim.uv.fs_rename(tmp, path)
- wait_for_message()
+ wait_for_message()
- os.remove(path)
+ os.remove(path)
- wait_for_message()
+ wait_for_message()
- vim.lsp.stop_client(client_id)
+ vim.lsp.stop_client(client_id)
- return server.messages
- ]],
- root_dir,
- watchfunc
- )
+ return server.messages
+ end)
local uri = vim.uri_from_fname(root_dir .. '/watch')
@@ -5124,7 +5549,7 @@ describe('LSP', function()
params = {
changes = {
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]),
+ type = created,
uri = uri,
},
},
@@ -5136,7 +5561,7 @@ describe('LSP', function()
params = {
changes = {
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]),
+ type = deleted,
uri = uri,
},
},
@@ -5148,17 +5573,14 @@ describe('LSP', function()
test_filechanges('watch')
test_filechanges('watchdirs')
- test_filechanges('fswatch')
+ test_filechanges('inotify')
it('correctly registers and unregisters', function()
local root_dir = '/some_dir'
exec_lua(create_server_definition)
- local result = exec_lua(
- [[
- local root_dir = ...
-
- local server = _create_server()
- local client_id = vim.lsp.start({
+ local result = exec_lua(function()
+ local server = _G._create_server()
+ local client_id = assert(vim.lsp.start({
name = 'watchfiles-test',
cmd = server.cmd,
root_dir = root_dir,
@@ -5169,16 +5591,22 @@ describe('LSP', function()
},
},
},
- })
+ }))
local expected_messages = 2 -- initialize, initialized
local function wait_for_messages()
- assert(vim.wait(200, function() return #server.messages == expected_messages end), 'Timed out waiting for expected number of messages. Current messages seen so far: ' .. vim.inspect(server.messages))
+ assert(
+ vim.wait(200, function()
+ return #server.messages == expected_messages
+ end),
+ 'Timed out waiting for expected number of messages. Current messages seen so far: '
+ .. vim.inspect(server.messages)
+ )
end
wait_for_messages()
- local send_event
+ local send_event --- @type function
require('vim.lsp._watchfiles')._watchfunc = function(_, _, callback)
local stopped = false
send_event = function(...)
@@ -5245,9 +5673,7 @@ describe('LSP', function()
wait_for_messages()
return server.messages
- ]],
- root_dir
- )
+ end)
local function watched_uri(fname)
return vim.uri_from_fname(root_dir .. '/' .. fname)
@@ -5258,7 +5684,7 @@ describe('LSP', function()
eq({
changes = {
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]),
+ type = created,
uri = watched_uri('file.watch0'),
},
},
@@ -5267,7 +5693,7 @@ describe('LSP', function()
eq({
changes = {
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]),
+ type = created,
uri = watched_uri('file.watch1'),
},
},
@@ -5277,12 +5703,9 @@ describe('LSP', function()
it('correctly handles the registered watch kind', function()
local root_dir = 'some_dir'
exec_lua(create_server_definition)
- local result = exec_lua(
- [[
- local root_dir = ...
-
- local server = _create_server()
- local client_id = vim.lsp.start({
+ local result = exec_lua(function()
+ local server = _G._create_server()
+ local client_id = assert(vim.lsp.start({
name = 'watchfiles-test',
cmd = server.cmd,
root_dir = root_dir,
@@ -5293,16 +5716,22 @@ describe('LSP', function()
},
},
},
- })
+ }))
local expected_messages = 2 -- initialize, initialized
local function wait_for_messages()
- assert(vim.wait(200, function() return #server.messages == expected_messages end), 'Timed out waiting for expected number of messages. Current messages seen so far: ' .. vim.inspect(server.messages))
+ assert(
+ vim.wait(200, function()
+ return #server.messages == expected_messages
+ end),
+ 'Timed out waiting for expected number of messages. Current messages seen so far: '
+ .. vim.inspect(server.messages)
+ )
end
wait_for_messages()
- local watch_callbacks = {}
+ local watch_callbacks = {} --- @type function[]
local function send_event(...)
for _, cb in ipairs(watch_callbacks) do
cb(...)
@@ -5318,12 +5747,14 @@ describe('LSP', function()
local protocol = require('vim.lsp.protocol')
local watchers = {}
- local max_kind = protocol.WatchKind.Create + protocol.WatchKind.Change + protocol.WatchKind.Delete
+ local max_kind = protocol.WatchKind.Create
+ + protocol.WatchKind.Change
+ + protocol.WatchKind.Delete
for i = 0, max_kind do
table.insert(watchers, {
globPattern = {
baseUri = vim.uri_from_fname('/dir'),
- pattern = 'watch'..tostring(i),
+ pattern = 'watch' .. tostring(i),
},
kind = i,
})
@@ -5351,9 +5782,7 @@ describe('LSP', function()
wait_for_messages()
return server.messages
- ]],
- root_dir
- )
+ end)
local function watched_uri(fname)
return vim.uri_from_fname('/dir/' .. fname)
@@ -5364,51 +5793,51 @@ describe('LSP', function()
eq({
changes = {
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]),
+ type = created,
uri = watched_uri('watch1'),
},
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]),
+ type = changed,
uri = watched_uri('watch2'),
},
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]),
+ type = created,
uri = watched_uri('watch3'),
},
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]),
+ type = changed,
uri = watched_uri('watch3'),
},
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]),
+ type = deleted,
uri = watched_uri('watch4'),
},
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]),
+ type = created,
uri = watched_uri('watch5'),
},
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]),
+ type = deleted,
uri = watched_uri('watch5'),
},
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]),
+ type = changed,
uri = watched_uri('watch6'),
},
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]),
+ type = deleted,
uri = watched_uri('watch6'),
},
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]),
+ type = created,
uri = watched_uri('watch7'),
},
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]),
+ type = changed,
uri = watched_uri('watch7'),
},
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]),
+ type = deleted,
uri = watched_uri('watch7'),
},
},
@@ -5418,12 +5847,9 @@ describe('LSP', function()
it('prunes duplicate events', function()
local root_dir = 'some_dir'
exec_lua(create_server_definition)
- local result = exec_lua(
- [[
- local root_dir = ...
-
- local server = _create_server()
- local client_id = vim.lsp.start({
+ local result = exec_lua(function()
+ local server = _G._create_server()
+ local client_id = assert(vim.lsp.start({
name = 'watchfiles-test',
cmd = server.cmd,
root_dir = root_dir,
@@ -5434,16 +5860,22 @@ describe('LSP', function()
},
},
},
- })
+ }))
local expected_messages = 2 -- initialize, initialized
local function wait_for_messages()
- assert(vim.wait(200, function() return #server.messages == expected_messages end), 'Timed out waiting for expected number of messages. Current messages seen so far: ' .. vim.inspect(server.messages))
+ assert(
+ vim.wait(200, function()
+ return #server.messages == expected_messages
+ end),
+ 'Timed out waiting for expected number of messages. Current messages seen so far: '
+ .. vim.inspect(server.messages)
+ )
end
wait_for_messages()
- local send_event
+ local send_event --- @type function
require('vim.lsp._watchfiles')._watchfunc = function(_, _, callback)
send_event = callback
return function()
@@ -5477,24 +5909,22 @@ describe('LSP', function()
wait_for_messages()
return server.messages
- ]],
- root_dir
- )
+ end)
eq(3, #result)
eq('workspace/didChangeWatchedFiles', result[3].method)
eq({
changes = {
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]),
+ type = created,
uri = vim.uri_from_fname('file1'),
},
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]),
+ type = changed,
uri = vim.uri_from_fname('file1'),
},
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]),
+ type = created,
uri = vim.uri_from_fname('file2'),
},
},
@@ -5503,27 +5933,28 @@ describe('LSP', function()
it("ignores registrations by servers when the client doesn't advertise support", function()
exec_lua(create_server_definition)
- exec_lua([[
- server = _create_server()
- require('vim.lsp._watchfiles')._watchfunc = function(_, _, callback)
+ exec_lua(function()
+ _G.server = _G._create_server()
+ require('vim.lsp._watchfiles')._watchfunc = function(_, _, _)
-- Since the registration is ignored, this should not execute and `watching` should stay false
- watching = true
+ _G.watching = true
return function() end
end
- ]])
+ end)
local function check_registered(capabilities)
- return exec_lua(
- [[
- watching = false
- local client_id = vim.lsp.start({
+ return exec_lua(function()
+ _G.watching = false
+ local client_id = assert(vim.lsp.start({
name = 'watchfiles-test',
- cmd = server.cmd,
+ cmd = _G.server.cmd,
root_dir = 'some_dir',
- capabilities = ...,
+ capabilities = capabilities,
}, {
- reuse_client = function() return false end,
- })
+ reuse_client = function()
+ return false
+ end,
+ }))
vim.lsp.handlers['client/registerCapability'](nil, {
registrations = {
@@ -5552,10 +5983,8 @@ describe('LSP', function()
}, { client_id = client_id })
vim.lsp.stop_client(client_id, true)
- return watching
- ]],
- capabilities
- )
+ return _G.watching
+ end)
end
eq(is_os('mac') or is_os('win'), check_registered(nil)) -- start{_client}() defaults to make_client_capabilities().