diff options
| author | Josh Rahm <joshuarahm@gmail.com> | 2024-11-19 22:57:13 +0000 |
|---|---|---|
| committer | Josh Rahm <joshuarahm@gmail.com> | 2024-11-19 22:57:13 +0000 |
| commit | 9be89f131f87608f224f0ee06d199fcd09d32176 (patch) | |
| tree | 11022dcfa9e08cb4ac5581b16734196128688d48 /test/functional/plugin/lsp_spec.lua | |
| parent | ff7ed8f586589d620a806c3758fac4a47a8e7e15 (diff) | |
| parent | 88085c2e80a7e3ac29aabb6b5420377eed99b8b6 (diff) | |
| download | rneovim-9be89f131f87608f224f0ee06d199fcd09d32176.tar.gz rneovim-9be89f131f87608f224f0ee06d199fcd09d32176.tar.bz2 rneovim-9be89f131f87608f224f0ee06d199fcd09d32176.zip | |
Merge remote-tracking branch 'upstream/master' into mix_20240309
Diffstat (limited to 'test/functional/plugin/lsp_spec.lua')
| -rw-r--r-- | test/functional/plugin/lsp_spec.lua | 3807 |
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(_cl |