diff options
| author | Lewis Russell <lewis6991@gmail.com> | 2024-08-11 11:58:15 +0100 |
|---|---|---|
| committer | Lewis Russell <me@lewisr.dev> | 2024-08-11 15:14:14 +0100 |
| commit | 9b5ab66678f8efa1f5fe89205839fe053fe5efaf (patch) | |
| tree | 14018ce3d9f2f3cde76e65453c201664e5129d8a /test/functional/plugin | |
| parent | 8df6736ca14d09f87cf0a8486758ac5708819434 (diff) | |
| download | rneovim-9b5ab66678f8efa1f5fe89205839fe053fe5efaf.tar.gz rneovim-9b5ab66678f8efa1f5fe89205839fe053fe5efaf.tar.bz2 rneovim-9b5ab66678f8efa1f5fe89205839fe053fe5efaf.zip | |
test(lsp): refactor and tidy
- Merge all the top level 'LSP' describe blocks
- Refactor text edit tests
- Fix typing errors
- Add linebreaks between tests
Diffstat (limited to 'test/functional/plugin')
| -rw-r--r-- | test/functional/plugin/lsp/testutil.lua | 119 | ||||
| -rw-r--r-- | test/functional/plugin/lsp_spec.lua | 573 |
2 files changed, 362 insertions, 330 deletions
diff --git a/test/functional/plugin/lsp/testutil.lua b/test/functional/plugin/lsp/testutil.lua index 3430a1e1a3..2595f6ad09 100644 --- a/test/functional/plugin/lsp/testutil.lua +++ b/test/functional/plugin/lsp/testutil.lua @@ -21,8 +21,8 @@ function M.clear_notrace() } end -M.create_server_definition = [[ - function _create_server(opts) +M.create_server_definition = function() + function _G._create_server(opts) opts = opts or {} local server = {} server.messages = {} @@ -42,7 +42,7 @@ M.create_server_definition = [[ handler(method, params, callback) elseif method == 'initialize' then callback(nil, { - capabilities = opts.capabilities or {} + capabilities = opts.capabilities or {}, }) elseif method == 'shutdown' then callback(nil, nil) @@ -54,7 +54,7 @@ M.create_server_definition = [[ function srv.notify(method, params) table.insert(server.messages, { method = method, - params = params + params = params, }) if method == 'exit' then dispatchers.on_exit(0, 15) @@ -74,7 +74,7 @@ M.create_server_definition = [[ return server end -]] +end -- Fake LSP server. M.fake_lsp_code = 'test/functional/fixtures/fake-lsp-server.lua' @@ -82,48 +82,53 @@ M.fake_lsp_logfile = 'Xtest-fake-lsp.log' local function fake_lsp_server_setup(test_name, timeout_ms, options, settings) exec_lua( - [=[ - lsp = require('vim.lsp') - local test_name, fake_lsp_code, fake_lsp_logfile, timeout, options, settings = ... - TEST_RPC_CLIENT_ID = lsp.start_client { - cmd_env = { - NVIM_LOG_FILE = fake_lsp_logfile; - NVIM_LUA_NOTRACK = "1"; - NVIM_APPNAME = "nvim_lsp_test"; - }; - cmd = { - vim.v.progpath, '-l', fake_lsp_code, test_name, tostring(timeout), - }; - handlers = setmetatable({}, { - __index = function(t, method) - return function(...) - return vim.rpcrequest(1, 'handler', ...) - end - end; - }); - workspace_folders = {{ - uri = 'file://' .. vim.uv.cwd(), - name = 'test_folder', - }}; - before_init = function(params, config) - vim.schedule(function() - vim.rpcrequest(1, "setup") - end) - end, - on_init = function(client, result) - TEST_RPC_CLIENT = client - vim.rpcrequest(1, "init", result) - end; - flags = { - allow_incremental_sync = options.allow_incremental_sync or false; - debounce_text_changes = options.debounce_text_changes or 0; - }; - settings = settings; - on_exit = function(...) - vim.rpcnotify(1, "exit", ...) - end; - } - ]=], + function(test_name0, fake_lsp_code0, fake_lsp_logfile0, timeout, options0, settings0) + _G.lsp = require('vim.lsp') + _G.TEST_RPC_CLIENT_ID = _G.lsp.start_client { + cmd_env = { + NVIM_LOG_FILE = fake_lsp_logfile0, + NVIM_LUA_NOTRACK = '1', + NVIM_APPNAME = 'nvim_lsp_test', + }, + cmd = { + vim.v.progpath, + '-l', + fake_lsp_code0, + test_name0, + tostring(timeout), + }, + handlers = setmetatable({}, { + __index = function(_t, _method) + return function(...) + return vim.rpcrequest(1, 'handler', ...) + end + end, + }), + workspace_folders = { + { + uri = 'file://' .. vim.uv.cwd(), + name = 'test_folder', + }, + }, + before_init = function(_params, _config) + vim.schedule(function() + vim.rpcrequest(1, 'setup') + end) + end, + on_init = function(client, result) + _G.TEST_RPC_CLIENT = client + vim.rpcrequest(1, 'init', result) + end, + flags = { + allow_incremental_sync = options0.allow_incremental_sync or false, + debounce_text_changes = options0.debounce_text_changes or 0, + }, + settings = settings0, + on_exit = function(...) + vim.rpcnotify(1, 'exit', ...) + end, + } + end, test_name, M.fake_lsp_code, M.fake_lsp_logfile, @@ -160,18 +165,14 @@ function M.test_rpc_server(config) -- Workaround for not being able to yield() inside __index for Lua 5.1 :( -- Otherwise I would just return the value here. return function(...) - return exec_lua( - [=[ - local name = ... - if type(TEST_RPC_CLIENT[name]) == 'function' then - return TEST_RPC_CLIENT[name](select(2, ...)) - else - return TEST_RPC_CLIENT[name] - end - ]=], - name, - ... - ) + return exec_lua(function(...) + local name0 = ... + if type(_G.TEST_RPC_CLIENT[name0]) == 'function' then + return _G.TEST_RPC_CLIENT[name0](select(2, ...)) + else + return _G.TEST_RPC_CLIENT[name0] + end + end, name, ...) end end, }) diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 83db4f303c..06e286f872 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -41,54 +41,80 @@ local function get_buf_option(name, bufnr) ) end +local function make_edit(y_0, x_0, y_1, x_1, text) + return { + range = { + start = { line = y_0, character = x_0 }, + ['end'] = { line = y_1, character = x_1 }, + }, + newText = type(text) == 'table' and table.concat(text, '\n') or (text or ''), + } +end + +--- @param edits [integer, integer, integer, integer, string|string[]][] +--- @param encoding? string +local function apply_text_edits(edits, encoding) + local edits1 = vim.tbl_map( + --- @param edit [integer, integer, integer, integer, string|string[]] + function(edit) + return make_edit(unpack(edit)) + end, + edits + ) + exec_lua('vim.lsp.util.apply_text_edits(...)', edits1, 1, encoding or 'utf-16') +end + -- TODO(justinmk): hangs on Windows https://github.com/neovim/neovim/pull/11837 if skip(is_os('win')) then return end -teardown(function() - os.remove(fake_lsp_logfile) -end) - describe('LSP', function() before_each(function() clear_notrace() - - -- Run an instance of nvim on the file which contains our "scripts". - -- Pass TEST_NAME to pick the script. - local test_name = 'basic_init' - exec_lua(function(test_name0, fake_lsp_code0, fake_lsp_logfile0) - _G.lsp = require('vim.lsp') - function _G.test__start_client() - return vim.lsp.start_client { - cmd_env = { - NVIM_LOG_FILE = fake_lsp_logfile0, - NVIM_APPNAME = 'nvim_lsp_test', - }, - cmd = { - vim.v.progpath, - '-l', - fake_lsp_code0, - test_name0, - }, - workspace_folders = { - { - uri = 'file://' .. vim.uv.cwd(), - name = 'test_folder', - }, - }, - } - end - _G.TEST_CLIENT1 = _G.test__start_client() - end, test_name, fake_lsp_code, fake_lsp_logfile) end) after_each(function() + stop() + exec_lua('lsp.stop_client(lsp.get_clients(), true)') api.nvim_exec_autocmds('VimLeavePre', { modeline = false }) - -- exec_lua("lsp.stop_all_clients(true)") + end) + + teardown(function() + os.remove(fake_lsp_logfile) end) describe('server_name specified', function() + before_each(function() + -- Run an instance of nvim on the file which contains our "scripts". + -- Pass TEST_NAME to pick the script. + local test_name = 'basic_init' + exec_lua(function(test_name0, fake_lsp_code0, fake_lsp_logfile0) + _G.lsp = require('vim.lsp') + function _G.test__start_client() + return vim.lsp.start_client { + cmd_env = { + NVIM_LOG_FILE = fake_lsp_logfile0, + NVIM_APPNAME = 'nvim_lsp_test', + }, + cmd = { + vim.v.progpath, + '-l', + fake_lsp_code0, + test_name0, + }, + workspace_folders = { + { + uri = 'file://' .. vim.uv.cwd(), + name = 'test_folder', + }, + }, + } + end + _G.TEST_CLIENT1 = _G.test__start_client() + end, test_name, fake_lsp_code, fake_lsp_logfile) + end) + it('start_client(), stop_client()', function() retry(nil, 4000, function() eq(1, exec_lua('return #lsp.get_clients()')) @@ -140,16 +166,8 @@ describe('LSP', function() end) end) end) -end) -describe('LSP', function() describe('basic_init test', function() - after_each(function() - stop() - exec_lua('lsp.stop_client(lsp.get_clients(), true)') - api.nvim_exec_autocmds('VimLeavePre', { modeline = false }) - end) - it('should run correctly', function() local expected_handlers = { { NIL, {}, { method = 'test', client_id = 1 } }, @@ -321,13 +339,13 @@ describe('LSP', function() _G.BUFFER = vim.api.nvim_create_buf(false, true) vim.api.nvim_create_autocmd('LspAttach', { callback = function(args) - local client0 = vim.lsp.get_client_by_id(args.data.client_id) + local client0 = assert(vim.lsp.get_client_by_id(args.data.client_id)) vim.g.lsp_attached = client0.name end, }) vim.api.nvim_create_autocmd('LspDetach', { callback = function(args) - local client0 = vim.lsp.get_client_by_id(args.data.client_id) + local client0 = assert(vim.lsp.get_client_by_id(args.data.client_id)) vim.g.lsp_detached = client0.name end, }) @@ -482,7 +500,7 @@ describe('LSP', function() }) local client_id = vim.lsp.start({ name = 'detach-dummy', cmd = server.cmd }) assert(client_id, 'lsp.start must return client_id') - local client = vim.lsp.get_client_by_id(client_id) + local client = assert(vim.lsp.get_client_by_id(client_id)) local num_attached_before = vim.tbl_count(client.attached_buffers) vim.api.nvim_buf_delete(bufnr, { force = true }) local num_attached_after = vim.tbl_count(client.attached_buffers) @@ -515,14 +533,14 @@ describe('LSP', function() }) local bufnr = vim.api.nvim_create_buf(false, true) local on_init_called = false - local client_id = vim.lsp.start({ + local client_id = assert(vim.lsp.start({ name = 'detach-dummy', cmd = server.cmd, on_init = function() vim.api.nvim_buf_delete(bufnr, {}) on_init_called = true end, - }) + })) vim.lsp.buf_attach_client(bufnr, client_id) local ok = vim.wait(1000, function() return on_init_called @@ -616,6 +634,7 @@ describe('LSP', function() end, } end) + it( 'workspace/configuration returns NIL per section if client was started without config.settings', function() @@ -710,7 +729,7 @@ describe('LSP', function() }, }, }) - local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) + local client_id = assert(vim.lsp.start({ name = 'dummy', cmd = server.cmd })) local buf = vim.api.nvim_get_current_buf() vim.api.nvim_exec_autocmds('BufWritePre', { buffer = buf, modeline = false }) vim.lsp.stop_client(client_id) @@ -748,7 +767,7 @@ describe('LSP', function() }, }) local buf = vim.api.nvim_get_current_buf() - local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) + local client_id = assert(vim.lsp.start({ name = 'dummy', cmd = server.cmd })) vim.api.nvim_exec_autocmds('BufWritePre', { buffer = buf, modeline = false }) vim.lsp.stop_client(client_id) return { @@ -1487,6 +1506,7 @@ describe('LSP', function() end, } end) + it('should check the body and didChange incremental with debounce', function() local expected_handlers = { { NIL, {}, { method = 'shutdown', client_id = 1 } }, @@ -1761,75 +1781,59 @@ describe('LSP', function() } end) end) -end) - -describe('LSP', function() - before_each(function() - clear_notrace() - end) - - local function make_edit(y_0, x_0, y_1, x_1, text) - return { - range = { - start = { line = y_0, character = x_0 }, - ['end'] = { line = y_1, character = x_1 }, - }, - newText = type(text) == 'table' and table.concat(text, '\n') or (text or ''), - } - end describe('apply vscode text_edits', function() it('single replace', function() insert('012345678901234567890123456789') - local edits = { - make_edit(0, 3, 0, 6, { 'Hello' }), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 0, 3, 0, 6, { 'Hello' } }, + }) eq({ '012Hello678901234567890123456789' }, buf_lines(1)) end) + it('two replaces', function() insert('012345678901234567890123456789') - local edits = { - make_edit(0, 3, 0, 6, { 'Hello' }), - make_edit(0, 6, 0, 9, { 'World' }), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 0, 3, 0, 6, { 'Hello' } }, + { 0, 6, 0, 9, { 'World' } }, + }) eq({ '012HelloWorld901234567890123456789' }, buf_lines(1)) end) + it('same start pos insert are kept in order', function() insert('012345678901234567890123456789') - local edits1 = { - make_edit(0, 3, 0, 3, { 'World' }), - make_edit(0, 3, 0, 3, { 'Hello' }), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits1, 1, 'utf-16') + apply_text_edits({ + { 0, 3, 0, 3, { 'World' } }, + { 0, 3, 0, 3, { 'Hello' } }, + }) eq({ '012WorldHello345678901234567890123456789' }, buf_lines(1)) end) + it('same start pos insert and replace are kept in order', function() insert('012345678901234567890123456789') - local edits1 = { - make_edit(0, 3, 0, 3, { 'World' }), - make_edit(0, 3, 0, 3, { 'Hello' }), - make_edit(0, 3, 0, 8, { 'No' }), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits1, 1, 'utf-16') + apply_text_edits({ + { 0, 3, 0, 3, { 'World' } }, + { 0, 3, 0, 3, { 'Hello' } }, + { 0, 3, 0, 8, { 'No' } }, + }) eq({ '012WorldHelloNo8901234567890123456789' }, buf_lines(1)) end) + it('multiline', function() exec_lua(function() vim.api.nvim_buf_set_lines(1, 0, 0, true, { ' {', ' "foo": "bar"', ' }' }) end) eq({ ' {', ' "foo": "bar"', ' }', '' }, buf_lines(1)) - local edits = { - make_edit(0, 0, 3, 0, { '' }), - make_edit(3, 0, 3, 0, { '{\n' }), - make_edit(3, 0, 3, 0, { ' "foo": "bar"\n' }), - make_edit(3, 0, 3, 0, { '}\n' }), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 0, 0, 3, 0, { '' } }, + { 3, 0, 3, 0, { '{\n' } }, + { 3, 0, 3, 0, { ' "foo": "bar"\n' } }, + { 3, 0, 3, 0, { '}\n' } }, + }) eq({ '{', ' "foo": "bar"', '}', '' }, buf_lines(1)) end) end) + describe('apply_text_edits', function() before_each(function() insert(dedent([[ @@ -1839,14 +1843,14 @@ describe('LSP', function() Fourth line of text å å ɧ 汉语 ↥ 🤦 🦄]])) end) + it('applies simple edits', function() - local edits = { - make_edit(0, 0, 0, 0, { '123' }), - make_edit(1, 0, 1, 1, { '2' }), - make_edit(2, 0, 2, 2, { '3' }), - make_edit(3, 2, 3, 4, { '' }), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 0, 0, 0, 0, { '123' } }, + { 1, 0, 1, 1, { '2' } }, + { 2, 0, 2, 2, { '3' } }, + { 3, 2, 3, 4, { '' } }, + }) eq({ '123First line of text', '2econd line of text', @@ -1855,18 +1859,18 @@ describe('LSP', function() 'å å ɧ 汉语 ↥ 🤦 🦄', }, buf_lines(1)) end) + it('applies complex edits', function() - local edits = { - make_edit(0, 0, 0, 0, { '', '12' }), - make_edit(0, 0, 0, 0, { '3', 'foo' }), - make_edit(0, 1, 0, 1, { 'bar', '123' }), - make_edit(0, #'First ', 0, #'First line of text', { 'guy' }), - make_edit(1, 0, 1, #'Second', { 'baz' }), - make_edit(2, #'Th', 2, #'Third', { 'e next' }), - make_edit(3, #'', 3, #'Fourth', { 'another line of text', 'before this' }), - make_edit(3, #'Fourth', 3, #'Fourth line of text', { '!' }), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 0, 0, 0, 0, { '', '12' } }, + { 0, 0, 0, 0, { '3', 'foo' } }, + { 0, 1, 0, 1, { 'bar', '123' } }, + { 0, #'First ', 0, #'First line of text', { 'guy' } }, + { 1, 0, 1, #'Second', { 'baz' } }, + { 2, #'Th', 2, #'Third', { 'e next' } }, + { 3, #'', 3, #'Fourth', { 'another line of text', 'before this' } }, + { 3, #'Fourth', 3, #'Fourth line of text', { '!' } }, + }) eq({ '', '123', @@ -1879,18 +1883,18 @@ describe('LSP', function() 'å å ɧ 汉语 ↥ 🤦 🦄', }, buf_lines(1)) end) + it('applies complex edits (reversed range)', function() - local edits = { - make_edit(0, 0, 0, 0, { '', '12' }), - make_edit(0, 0, 0, 0, { '3', 'foo' }), - make_edit(0, 1, 0, 1, { 'bar', '123' }), - make_edit(0, #'First line of text', 0, #'First ', { 'guy' }), - make_edit(1, #'Second', 1, 0, { 'baz' }), - make_edit(2, #'Third', 2, #'Th', { 'e next' }), - make_edit(3, #'Fourth', 3, #'', { 'another line of text', 'before this' }), - make_edit(3, #'Fourth line of text', 3, #'Fourth', { '!' }), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 0, 0, 0, 0, { '', '12' } }, + { 0, 0, 0, 0, { '3', 'foo' } }, + { 0, 1, 0, 1, { 'bar', '123' } }, + { 0, #'First line of text', 0, #'First ', { 'guy' } }, + { 1, #'Second', 1, 0, { 'baz' } }, + { 2, #'Third', 2, #'Th', { 'e next' } }, + { 3, #'Fourth', 3, #'', { 'another line of text', 'before this' } }, + { 3, #'Fourth line of text', 3, #'Fourth', { '!' } }, + }) eq({ '', '123', @@ -1903,11 +1907,11 @@ describe('LSP', function() 'å å ɧ 汉语 ↥ 🤦 🦄', }, buf_lines(1)) end) + it('applies non-ASCII characters edits', function() - local edits = { - make_edit(4, 3, 4, 4, { 'ä' }), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 4, 3, 4, 4, { 'ä' } }, + }) eq({ 'First line of text', 'Second line of text', @@ -1916,11 +1920,11 @@ describe('LSP', function() 'å ä ɧ 汉语 ↥ 🤦 🦄', }, buf_lines(1)) end) + it('applies text edits at the end of the document', function() - local edits = { - make_edit(5, 0, 5, 0, 'foobar'), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 5, 0, 5, 0, 'foobar' }, + }) eq({ 'First line of text', 'Second line of text', @@ -1930,12 +1934,12 @@ describe('LSP', function() 'foobar', }, buf_lines(1)) end) + it('applies multiple text edits at the end of the document', function() - local edits = { - make_edit(4, 0, 5, 0, ''), - make_edit(5, 0, 5, 0, 'foobar'), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 4, 0, 5, 0, '' }, + { 5, 0, 5, 0, 'foobar' }, + }) eq({ 'First line of text', 'Second line of text', @@ -1944,62 +1948,56 @@ describe('LSP', function() 'foobar', }, buf_lines(1)) end) + it('it restores marks', function() - local edits = { - make_edit(1, 0, 2, 5, 'foobar'), - make_edit(4, 0, 5, 0, 'barfoo'), - } eq(true, api.nvim_buf_set_mark(1, 'a', 2, 1, {})) - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 1, 0, 2, 5, 'foobar' }, + { 4, 0, 5, 0, 'barfoo' }, + }) eq({ 'First line of text', 'foobar line of text', 'Fourth line of text', 'barfoo', }, buf_lines(1)) - local mark = api.nvim_buf_get_mark(1, 'a') - eq({ 2, 1 }, mark) + eq({ 2, 1 }, api.nvim_buf_get_mark(1, 'a')) end) it('it restores marks to last valid col', function() - local edits = { - make_edit(1, 0, 2, 15, 'foobar'), - make_edit(4, 0, 5, 0, 'barfoo'), - } eq(true, api.nvim_buf_set_mark(1, 'a', 2, 10, {})) - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 1, 0, 2, 15, 'foobar' }, + { 4, 0, 5, 0, 'barfoo' }, + }) eq({ 'First line of text', 'foobarext', 'Fourth line of text', 'barfoo', }, buf_lines(1)) - local mark = api.nvim_buf_get_mark(1, 'a') - eq({ 2, 9 }, mark) + eq({ 2, 9 }, api.nvim_buf_get_mark(1, 'a')) end) it('it restores marks to last valid line', function() - local edits = { - make_edit(1, 0, 4, 5, 'foobar'), - make_edit(4, 0, 5, 0, 'barfoo'), - } eq(true, api.nvim_buf_set_mark(1, 'a', 4, 1, {})) - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 1, 0, 4, 5, 'foobar' }, + { 4, 0, 5, 0, 'barfoo' }, + }) eq({ 'First line of text', 'foobaro', }, buf_lines(1)) - local mark = api.nvim_buf_get_mark(1, 'a') - eq({ 2, 1 }, mark) + eq({ 2, 1 }, api.nvim_buf_get_mark(1, 'a')) end) describe('cursor position', function() it("don't fix the cursor if the range contains the cursor", function() api.nvim_win_set_cursor(0, { 2, 6 }) - local edits = { - make_edit(1, 0, 1, 19, 'Second line of text'), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 1, 0, 1, 19, 'Second line of text' }, + }) eq({ 'First line of text', 'Second line of text', @@ -2012,11 +2010,10 @@ describe('LSP', function() it('fix the cursor to the valid col if the content was removed', function() api.nvim_win_set_cursor(0, { 2, 6 }) - local edits = { - make_edit(1, 0, 1, 6, ''), - make_edit(1, 6, 1, 19, ''), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 1, 0, 1, 6, '' }, + { 1, 6, 1, 19, '' }, + }) eq({ 'First line of text', '', @@ -2029,11 +2026,10 @@ describe('LSP', function() it('fix the cursor to the valid row if the content was removed', function() api.nvim_win_set_cursor(0, { 2, 6 }) - local edits = { - make_edit(1, 0, 1, 6, ''), - make_edit(0, 18, 5, 0, ''), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 1, 0, 1, 6, '' }, + { 0, 18, 5, 0, '' }, + }) eq({ 'First line of text', }, buf_lines(1)) @@ -2042,10 +2038,9 @@ describe('LSP', function() it('fix the cursor row', function() api.nvim_win_set_cursor(0, { 3, 0 }) - local edits = { - make_edit(1, 0, 2, 0, ''), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 1, 0, 2, 0, '' }, + }) eq({ 'First line of text', 'Third line of text', @@ -2060,10 +2055,9 @@ describe('LSP', function() api.nvim_buf_set_lines(1, -1, -1, true, { '' }) api.nvim_win_set_cursor(0, { 2, 11 }) - local edits = { - make_edit(1, 7, 1, 11, ''), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 1, 7, 1, 11, '' }, + }) eq({ 'First line of text', 'Second of text', @@ -2077,10 +2071,9 @@ describe('LSP', function() it('fix the cursor row and col', function() api.nvim_win_set_cursor(0, { 2, 12 }) - local edits = { - make_edit(0, 11, 1, 12, ''), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 0, 11, 1, 12, '' }, + }) eq({ 'First line of text', 'Third line of text', @@ -2093,24 +2086,23 @@ describe('LSP', function() describe('with LSP end line after what Vim considers to be the end line', function() it('applies edits when the last linebreak is considered a new line', function() - local edits = { - make_edit(0, 0, 5, 0, { 'All replaced' }), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 0, 0, 5, 0, { 'All replaced' } }, + }) eq({ 'All replaced' }, buf_lines(1)) end) + it("applies edits when the end line is 2 larger than vim's", function() - local edits = { - make_edit(0, 0, 6, 0, { 'All replaced' }), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 0, 0, 6, 0, { 'All replaced' } }, + }) eq({ 'All replaced' }, buf_lines(1)) end) + it('applies edits with a column offset', function() - local edits = { - make_edit(0, 0, 5, 2, { 'All replaced' }), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 0, 0, 5, 2, { 'All replaced' } }, + }) eq({ 'All replaced' }, buf_lines(1)) end) end) @@ -2122,38 +2114,38 @@ describe('LSP', function() Test line one Test line two 21 char]])) end) + describe('with LSP end column out of bounds and start column at 0', function() it('applies edits at the end of the buffer', function() - local edits = { - make_edit(0, 0, 1, 22, { '#include "whatever.h"\r\n#include <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) @@ -2164,6 +2156,7 @@ describe('LSP', function() describe('apply_text_document_edit', function() local target_bufnr --- @type integer + local text_document_edit = function(editVersion) return { edits = { @@ -2175,6 +2168,7 @@ describe('LSP', function() }, } end + before_each(function() target_bufnr = exec_lua(function() local bufnr = vim.uri_to_bufnr('file:///fake/uri') @@ -2183,6 +2177,7 @@ describe('LSP', function() return bufnr end) end) + it('correctly goes ahead with the edit if all is normal', function() exec_lua("vim.lsp.util.apply_text_document_edit(..., nil, 'utf-16')", text_document_edit(5)) eq({ @@ -2190,6 +2185,7 @@ describe('LSP', function() '2nd line of 语text', }, buf_lines(target_bufnr)) end) + it('always accepts edit with version = 0', function() exec_lua(function(bufnr, text_edit) vim.lsp.util.buf_versions[bufnr] = 10 @@ -2200,6 +2196,7 @@ describe('LSP', function() '2nd line of 语text', }, buf_lines(target_bufnr)) end) + it('skips the edit if the version of the edit is behind the local buffer ', function() local apply_edit_mocking_current_version = function(edit, versionedBuf) exec_lua(function(edit0, versionedBuf0) @@ -2371,6 +2368,7 @@ describe('LSP', function() end, make_workspace_edit(edits), target_bufnr) ) end) + it('Supports file creation with CreateFile payload', function() local tmpfile = tmpname() os.remove(tmpfile) -- Should not exist, only interested in a tmpname @@ -2386,6 +2384,7 @@ describe('LSP', function() exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit, 'utf-16') eq(true, vim.uv.fs_stat(tmpfile) ~= nil) end) + it( 'Supports file creation in folder that needs to be created with CreateFile payload', function() @@ -2405,6 +2404,7 @@ describe('LSP', function() eq(true, vim.uv.fs_stat(tmpfile) ~= nil) end ) + it('createFile does not touch file if it exists and ignoreIfExists is set', function() local tmpfile = tmpname() write_file(tmpfile, 'Dummy content') @@ -2424,6 +2424,7 @@ describe('LSP', function() eq(true, vim.uv.fs_stat(tmpfile) ~= nil) eq('Dummy content', read_file(tmpfile)) end) + it('createFile overrides file if overwrite is set', function() local tmpfile = tmpname() write_file(tmpfile, 'Dummy content') @@ -2444,6 +2445,7 @@ describe('LSP', function() eq(true, vim.uv.fs_stat(tmpfile) ~= nil) eq('', read_file(tmpfile)) end) + it('DeleteFile delete file and buffer', function() local tmpfile = tmpname() write_file(tmpfile, 'Be gone') @@ -2464,6 +2466,7 @@ describe('LSP', function() eq(false, vim.uv.fs_stat(tmpfile) ~= nil) eq(false, api.nvim_buf_is_loaded(fn.bufadd(tmpfile))) end) + it('DeleteFile fails if file does not exist and ignoreIfNotExists is false', function() local tmpfile = tmpname() os.remove(tmpfile) @@ -2508,6 +2511,7 @@ describe('LSP', function() eq(true, exists) os.remove(new) end) + it('Can rename a directory', function() -- only reserve the name, file must not exist for the test scenario local old_dir = tmpname() @@ -2536,6 +2540,7 @@ describe('LSP', function() os.remove(new_dir) end) + it('Does not touch buffers that do not match path prefix', function() local old = tmpname() local new = tmpname() @@ -2543,32 +2548,35 @@ describe('LSP', function() os.remove(new) n.mkdir_p(old) - local result = exec_lua(function(old0, new0) - local old_prefixed = 'explorer://' .. old0 - local old_suffixed = old0 .. '.bak' - local new_prefixed = 'explorer://' .. new0 - local new_suffixed = new0 .. '.bak' - - local old_prefixed_buf = vim.fn.bufadd(old_prefixed) - local old_suffixed_buf = vim.fn.bufadd(old_suffixed) - local new_prefixed_buf = vim.fn.bufadd(new_prefixed) - local new_suffixed_buf = vim.fn.bufadd(new_suffixed) - - vim.lsp.util.rename(old0, new0) - - return vim.api.nvim_buf_is_valid(old_prefixed_buf) - and vim.api.nvim_buf_is_valid(old_suffixed_buf) - and vim.api.nvim_buf_is_valid(new_prefixed_buf) - and vim.api.nvim_buf_is_valid(new_suffixed_buf) - and vim.api.nvim_buf_get_name(old_prefixed_buf) == old_prefixed - and vim.api.nvim_buf_get_name(old_suffixed_buf) == old_suffixed - and vim.api.nvim_buf_get_name(new_prefixed_buf) == new_prefixed - and vim.api.nvim_buf_get_name(new_suffixed_buf) == new_suffixed - end, old, new) - eq(true, result) + eq( + true, + exec_lua(function(old0, new0) + local old_prefixed = 'explorer://' .. old0 + local old_suffixed = old0 .. '.bak' + local new_prefixed = 'explorer://' .. new0 + local new_suffixed = new0 .. '.bak' + + local old_prefixed_buf = vim.fn.bufadd(old_prefixed) |