diff options
Diffstat (limited to 'test/functional/plugin/lsp_spec.lua')
-rw-r--r-- | test/functional/plugin/lsp_spec.lua | 411 |
1 files changed, 222 insertions, 189 deletions
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 0fdcd0dd1d..0cb2b88948 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -205,8 +205,8 @@ describe('LSP', function() client.stop() end, on_exit = function(code, signal) - eq(0, code, 'exit code', fake_lsp_logfile) - eq(0, signal, 'exit signal', fake_lsp_logfile) + eq(0, code, 'exit code') + eq(0, signal, 'exit signal') end, settings = { dummy = 1, @@ -641,11 +641,11 @@ describe('LSP', function() vim.lsp.stop_client(client_id) return server.messages ]]) - eq(#messages, 4) - eq(messages[1].method, 'initialize') - eq(messages[2].method, 'initialized') - eq(messages[3].method, 'shutdown') - eq(messages[4].method, 'exit') + eq(4, #messages) + eq('initialize', messages[1].method) + eq('initialized', messages[2].method) + eq('shutdown', messages[3].method) + eq('exit', messages[4].method) end) it('BufWritePre sends willSave / willSaveWaitUntil, applies textEdits', function() @@ -2383,12 +2383,13 @@ describe('LSP', function() [[ local old = select(1, ...) local new = select(2, ...) + local old_bufnr = vim.fn.bufadd(old) + vim.fn.bufload(old_bufnr) vim.lsp.util.rename(old, new) - - -- after rename the target file must have the contents of the source file - local bufnr = vim.fn.bufadd(new) - vim.fn.bufload(new) - return vim.api.nvim_buf_get_lines(bufnr, 0, -1, true) + -- the existing buffer is renamed in-place and its contents is kept + 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 @@ -2400,87 +2401,6 @@ describe('LSP', function() eq(true, exists) os.remove(new) end) - it('Kills old buffer after renaming 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 oldbufnr = vim.fn.bufadd(old) - local new = select(2, ...) - vim.lsp.util.rename(old, new) - return vim.fn.bufloaded(oldbufnr) - ]], - old, - new - ) - eq(0, lines) - os.remove(new) - end) - it('new buffer remains unlisted and unloaded if the old was not in window before', 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 actual = exec_lua( - [[ - local old = select(1, ...) - local oldbufnr = vim.fn.bufadd(old) - local new = select(2, ...) - local newbufnr = vim.fn.bufadd(new) - vim.lsp.util.rename(old, new) - return { - buflisted = vim.bo[newbufnr].buflisted, - bufloaded = vim.api.nvim_buf_is_loaded(newbufnr) - } - ]], - old, - new - ) - - local expected = { - buflisted = false, - bufloaded = false, - } - - eq(expected, actual) - - os.remove(new) - end) - it('new buffer is listed and loaded if the old was in window before', 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 actual = exec_lua( - [[ - local win = vim.api.nvim_get_current_win() - local old = select(1, ...) - local oldbufnr = vim.fn.bufadd(old) - vim.api.nvim_win_set_buf(win, oldbufnr) - local new = select(2, ...) - vim.lsp.util.rename(old, new) - local newbufnr = vim.fn.bufadd(new) - return { - buflisted = vim.bo[newbufnr].buflisted, - bufloaded = vim.api.nvim_buf_is_loaded(newbufnr) - } - ]], - old, - new - ) - - local expected = { - buflisted = true, - bufloaded = true, - } - - eq(expected, actual) - - 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() @@ -2497,21 +2417,25 @@ describe('LSP', function() [[ local old_dir = select(1, ...) local new_dir = select(2, ...) - local pathsep = select(3, ...) - local oldbufnr = vim.fn.bufadd(old_dir .. pathsep .. 'file') - + local pathsep = select(3, ...) + local file = select(4, ...) + local old_bufnr = vim.fn.bufadd(old_dir .. pathsep .. file) + vim.fn.bufload(old_bufnr) vim.lsp.util.rename(old_dir, new_dir) - return vim.fn.bufloaded(oldbufnr) + -- the existing buffer is renamed in-place and its contents is kept + 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 + pathsep, + file ) - eq(0, lines) + eq({ 'Test content' }, lines) eq(false, exec_lua('return vim.uv.fs_stat(...) ~= nil', old_dir)) eq(true, exec_lua('return vim.uv.fs_stat(...) ~= nil', new_dir)) eq(true, exec_lua('return vim.uv.fs_stat(...) ~= nil', new_dir .. pathsep .. file)) - eq('Test content', read_file(new_dir .. pathsep .. file)) os.remove(new_dir) end) @@ -2593,6 +2517,88 @@ describe('LSP', function() eq('New file', read_file(new)) end ) + it('Maintains undo information for loaded buffer', function() + local old = tmpname() + write_file(old, 'line') + local new = tmpname() + os.remove(new) + + local undo_kept = exec_lua( + [[ + local old = select(1, ...) + local new = select(2, ...) + vim.opt.undofile = true + vim.cmd.edit(old) + vim.cmd.normal('dd') + vim.cmd.write() + local undotree = vim.fn.undotree() + vim.lsp.util.rename(old, new) + -- Renaming uses :saveas, which updates the "last write" information. + -- Other than that, the undotree should remain the same. + undotree.save_cur = undotree.save_cur + 1 + undotree.save_last = undotree.save_last + 1 + undotree.entries[1].save = undotree.entries[1].save + 1 + return vim.deep_equal(undotree, vim.fn.undotree()) + ]], + old, + new + ) + eq(false, exec_lua('return vim.uv.fs_stat(...) ~= nil', old)) + eq(true, exec_lua('return vim.uv.fs_stat(...) ~= nil', new)) + 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 undo_kept = exec_lua( + [[ + local old = select(1, ...) + local new = select(2, ...) + vim.opt.undofile = true + vim.cmd.split(old) + vim.cmd.normal('dd') + vim.cmd.write() + local undotree = vim.fn.undotree() + vim.cmd.bdelete() + vim.lsp.util.rename(old, new) + vim.cmd.edit(new) + return vim.deep_equal(undotree, vim.fn.undotree()) + ]], + old, + new + ) + eq(false, exec_lua('return vim.uv.fs_stat(...) ~= nil', old)) + eq(true, exec_lua('return vim.uv.fs_stat(...) ~= nil', new)) + 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 + ) + 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') @@ -4215,7 +4221,7 @@ describe('LSP', function() server:shutdown() return vim.json.decode(init) ]] - eq(result.method, 'initialize') + eq('initialize', result.method) end) it('can connect to lsp server via rpc.domain_socket_connect', function() local tmpfile @@ -4251,7 +4257,7 @@ describe('LSP', function() ]], tmpfile ) - eq(result.method, 'initialize') + eq('initialize', result.method) end) end) @@ -4438,113 +4444,140 @@ describe('LSP', function() end) describe('vim.lsp._watchfiles', function() - it('sends notifications when files change', function() - skip( - is_os('bsd'), - 'kqueue only reports events on watched folder itself, not contained files #26110' - ) - local root_dir = tmpname() - os.remove(root_dir) - mkdir(root_dir) + local function test_filechanges(watchfunc) + it( + string.format('sends notifications when files change (watchfunc=%s)', watchfunc), + function() + if watchfunc == 'fswatch' then + skip( + not is_ci() and fn.executable('fswatch') == 0, + 'fswatch not installed and not on CI' + ) + skip(is_os('win'), 'not supported on windows') + skip(is_os('mac'), 'flaky') + end - exec_lua(create_server_definition) - local result = exec_lua( - [[ - local root_dir = ... + skip( + is_os('bsd'), + 'kqueue only reports events on watched folder itself, not contained files #26110' + ) - 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 root_dir = tmpname() + os.remove(root_dir) + 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 expected_messages = 2 -- initialize, initialized + require('vim.lsp._watchfiles')._watchfunc = require('vim._watch')[watchfunc] - local watchfunc = require('vim.lsp._watchfiles')._watchfunc - local msg_wait_timeout = watchfunc == vim._watch.poll and 2500 or 200 - local function wait_for_messages() - 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 expected_messages = 0 - wait_for_messages() + local msg_wait_timeout = watchfunc == 'watch' and 200 or 2500 - vim.lsp.handlers['client/registerCapability'](nil, { - registrations = { - { - id = 'watchfiles-test-0', - method = 'workspace/didChangeWatchedFiles', - registerOptions = { - watchers = { - { - globPattern = '**/watch', - kind = 7, + 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 + + 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 == vim._watch.poll then - vim.wait(100) - end + if watchfunc ~= 'watch' then + vim.wait(100) + end - local path = root_dir .. '/watch' - local file = io.open(path, 'w') - file:close() + local path = root_dir .. '/watch' + local tmp = vim.fn.tempname() + io.open(tmp, 'w'):close() + vim.uv.fs_rename(tmp, path) - expected_messages = expected_messages + 1 - wait_for_messages() + wait_for_message() - os.remove(path) + os.remove(path) - expected_messages = expected_messages + 1 - wait_for_messages() + wait_for_message() - return server.messages - ]], - root_dir - ) + vim.lsp.stop_client(client_id) - local function watched_uri(fname) - return exec_lua( - [[ - local root_dir, fname = ... - return vim.uri_from_fname(root_dir .. '/' .. fname) - ]], - root_dir, - fname - ) - end + return server.messages + ]], + root_dir, + watchfunc + ) - eq(4, #result) - eq('workspace/didChangeWatchedFiles', result[3].method) - eq({ - changes = { - { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), - uri = watched_uri('watch'), - }, - }, - }, result[3].params) - eq('workspace/didChangeWatchedFiles', result[4].method) - eq({ - changes = { - { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]), - uri = watched_uri('watch'), - }, - }, - }, result[4].params) - end) + local uri = vim.uri_from_fname(root_dir .. '/watch') + + eq(6, #result) + + eq({ + method = 'workspace/didChangeWatchedFiles', + params = { + changes = { + { + type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), + uri = uri, + }, + }, + }, + }, result[3]) + + eq({ + method = 'workspace/didChangeWatchedFiles', + params = { + changes = { + { + type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]), + uri = uri, + }, + }, + }, + }, result[4]) + end + ) + end + + test_filechanges('watch') + test_filechanges('watchdirs') + test_filechanges('fswatch') it('correctly registers and unregisters', function() local root_dir = '/some_dir' |