aboutsummaryrefslogtreecommitdiff
path: root/test/functional/plugin
diff options
context:
space:
mode:
authorJosh Rahm <rahm@google.com>2022-07-18 19:37:18 +0000
committerJosh Rahm <rahm@google.com>2022-07-18 19:37:18 +0000
commit308e1940dcd64aa6c344c403d4f9e0dda58d9c5c (patch)
tree35fe43e01755e0f312650667004487a44d6b7941 /test/functional/plugin
parent96a00c7c588b2f38a2424aeeb4ea3581d370bf2d (diff)
parente8c94697bcbe23a5c7b07c292b90a6b70aadfa87 (diff)
downloadrneovim-308e1940dcd64aa6c344c403d4f9e0dda58d9c5c.tar.gz
rneovim-308e1940dcd64aa6c344c403d4f9e0dda58d9c5c.tar.bz2
rneovim-308e1940dcd64aa6c344c403d4f9e0dda58d9c5c.zip
Merge remote-tracking branch 'upstream/master' into rahm
Diffstat (limited to 'test/functional/plugin')
-rw-r--r--test/functional/plugin/health_spec.lua35
-rw-r--r--test/functional/plugin/lsp/diagnostic_spec.lua42
-rw-r--r--test/functional/plugin/lsp/incremental_sync_spec.lua48
-rw-r--r--test/functional/plugin/lsp/snippet_spec.lua134
-rw-r--r--test/functional/plugin/lsp_spec.lua815
-rw-r--r--test/functional/plugin/man_spec.lua14
-rw-r--r--test/functional/plugin/matchparen_spec.lua2
-rw-r--r--test/functional/plugin/shada_spec.lua8
8 files changed, 886 insertions, 212 deletions
diff --git a/test/functional/plugin/health_spec.lua b/test/functional/plugin/health_spec.lua
index 37de5d0ce6..ba66117fb1 100644
--- a/test/functional/plugin/health_spec.lua
+++ b/test/functional/plugin/health_spec.lua
@@ -5,7 +5,7 @@ local Screen = require('test.functional.ui.screen')
local clear = helpers.clear
local curbuf_contents = helpers.curbuf_contents
local command = helpers.command
-local eq = helpers.eq
+local eq, neq = helpers.eq, helpers.neq
local getcompletion = helpers.funcs.getcompletion
describe(':checkhealth', function()
@@ -37,6 +37,7 @@ describe(':checkhealth', function()
eq('nvim', getcompletion('nvim', 'checkhealth')[1])
eq('provider', getcompletion('prov', 'checkhealth')[1])
eq('vim.lsp', getcompletion('vim.ls', 'checkhealth')[1])
+ neq('vim', getcompletion('^vim', 'checkhealth')[1]) -- should not complete vim.health
end)
end)
@@ -153,6 +154,10 @@ describe('health.vim', function()
## report 2
- OK: nothing to see here
+ test_plug.submodule_empty: require("test_plug.submodule_empty.health").check()
+ ========================================================================
+ - ERROR: The healthcheck report for "test_plug.submodule_empty" plugin is empty.
+
test_plug.submodule_failed: require("test_plug.submodule_failed.health").check()
========================================================================
- ERROR: Failed to run healthcheck for "test_plug.submodule_failed" plugin. Exception:
@@ -172,6 +177,16 @@ describe('health.vim', function()
]])
end)
+ it("... including empty reports", function()
+ command("checkhealth test_plug.submodule_empty")
+ helpers.expect([[
+
+ test_plug.submodule_empty: require("test_plug.submodule_empty.health").check()
+ ========================================================================
+ - ERROR: The healthcheck report for "test_plug.submodule_empty" plugin is empty.
+ ]])
+ end)
+
it("gracefully handles broken lua healthcheck", function()
command("checkhealth test_plug.submodule_failed")
local buf_lines = helpers.curbuf('get_lines', 0, -1, true)
@@ -228,5 +243,23 @@ describe('health.vim', function()
- ERROR: No healthcheck found for "non_existent_healthcheck" plugin.
]])
end)
+
+ it("does not use vim.health as a healtcheck", function()
+ -- vim.health is not a healthcheck
+ command("checkhealth vim")
+ helpers.expect([[
+ ERROR: No healthchecks found.]])
+ end)
+ end)
+end)
+
+describe(':checkhealth provider', function()
+ it("works correctly with a wrongly configured 'shell'", function()
+ clear()
+ command([[set shell=echo\ WRONG!!!]])
+ command('let g:loaded_perl_provider = 0')
+ command('let g:loaded_python3_provider = 0')
+ command('checkhealth provider')
+ eq(nil, string.match(curbuf_contents(), 'WRONG!!!'))
end)
end)
diff --git a/test/functional/plugin/lsp/diagnostic_spec.lua b/test/functional/plugin/lsp/diagnostic_spec.lua
index 1269a2350c..f73ffc29b0 100644
--- a/test/functional/plugin/lsp/diagnostic_spec.lua
+++ b/test/functional/plugin/lsp/diagnostic_spec.lua
@@ -3,6 +3,7 @@ local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear
local exec_lua = helpers.exec_lua
local eq = helpers.eq
+local neq = require('test.helpers').neq
describe('vim.lsp.diagnostic', function()
local fake_uri
@@ -110,6 +111,7 @@ describe('vim.lsp.diagnostic', function()
}
]]
eq({code = 42, tags = {"foo", "bar"}, data = "Hello world"}, result[1].user_data.lsp)
+ eq(42, result[1].code)
eq(42, result[2].code)
eq({"foo", "bar"}, result[2].tags)
eq("Hello world", result[2].data)
@@ -219,12 +221,50 @@ describe('vim.lsp.diagnostic', function()
local diags = vim.diagnostic.get(diagnostic_bufnr)
vim.lsp.stop_client(client_id)
- vim.lsp._vim_exit_handler()
+ vim.api.nvim_exec_autocmds('VimLeavePre', { modeline = false })
return diags
]], line)
eq(1, #result)
eq(exec_lua([[return vim.str_byteindex(..., 7, true)]], line), result[1].col)
eq(exec_lua([[return vim.str_byteindex(..., 8, true)]], line), result[1].end_col)
end)
+
+ it('does not create buffer on empty diagnostics', function()
+ local bufnr
+
+ -- No buffer is created without diagnostics
+ bufnr = exec_lua [[
+ vim.lsp.diagnostic.on_publish_diagnostics(nil, {
+ uri = "file:///fake/uri2",
+ diagnostics = {},
+ }, {client_id=client_id})
+ return vim.fn.bufnr(vim.uri_to_fname("file:///fake/uri2"))
+ ]]
+ eq(bufnr, -1)
+
+ -- Create buffer on diagnostics
+ bufnr = exec_lua [[
+ vim.lsp.diagnostic.on_publish_diagnostics(nil, {
+ uri = "file:///fake/uri2",
+ diagnostics = {
+ make_error('Diagnostic', 0, 0, 0, 0),
+ },
+ }, {client_id=client_id})
+ return vim.fn.bufnr(vim.uri_to_fname("file:///fake/uri2"))
+ ]]
+ neq(bufnr, -1)
+ eq(exec_lua([[return #vim.diagnostic.get(...)]], bufnr), 1)
+
+ -- Clear diagnostics after buffer was created
+ bufnr = exec_lua [[
+ vim.lsp.diagnostic.on_publish_diagnostics(nil, {
+ uri = "file:///fake/uri2",
+ diagnostics = {},
+ }, {client_id=client_id})
+ return vim.fn.bufnr(vim.uri_to_fname("file:///fake/uri2"))
+ ]]
+ neq(bufnr, -1)
+ eq(exec_lua([[return #vim.diagnostic.get(...)]], bufnr), 0)
+ end)
end)
end)
diff --git a/test/functional/plugin/lsp/incremental_sync_spec.lua b/test/functional/plugin/lsp/incremental_sync_spec.lua
index 4e3eddb960..4985da9cd7 100644
--- a/test/functional/plugin/lsp/incremental_sync_spec.lua
+++ b/test/functional/plugin/lsp/incremental_sync_spec.lua
@@ -207,16 +207,16 @@ describe('incremental synchronization', function()
{
range = {
['start'] = {
- character = 0,
- line = 1
+ character = 11,
+ line = 0,
},
['end'] = {
character = 0,
line = 1
}
},
- rangeLength = 0,
- text = 'hello world\n'
+ rangeLength = 1,
+ text = '\nhello world\n'
}
}
test_edit({"hello world"}, {"yyp"}, expected_text_changes, 'utf-16', '\n')
@@ -226,19 +226,57 @@ describe('incremental synchronization', function()
{
range = {
['start'] = {
+ character = 11,
+ line = 0
+ },
+ ['end'] = {
character = 0,
line = 1
+ }
+ },
+ rangeLength = 1,
+ text = '\n\n'
+ }
+ }
+ test_edit({"hello world"}, {"o"}, expected_text_changes, 'utf-16', '\n')
+ end)
+ it('adding a line to an empty buffer', function()
+ local expected_text_changes = {
+ {
+ range = {
+ ['start'] = {
+ character = 0,
+ line = 0
},
['end'] = {
character = 0,
line = 1
}
},
+ rangeLength = 1,
+ text = '\n\n'
+ }
+ }
+ test_edit({""}, {"o"}, expected_text_changes, 'utf-16', '\n')
+ end)
+ it('insert a line above the current line', function()
+ local expected_text_changes = {
+ {
+ range = {
+ ['start'] = {
+ character = 0,
+ line = 0
+ },
+ ['end'] = {
+ character = 0,
+ line = 0
+ }
+ },
rangeLength = 0,
text = '\n'
}
}
- test_edit({"hello world"}, {"o"}, expected_text_changes, 'utf-16', '\n')
+ test_edit({""}, {"O"}, expected_text_changes, 'utf-16', '\n')
end)
end)
describe('multi line edit', function()
diff --git a/test/functional/plugin/lsp/snippet_spec.lua b/test/functional/plugin/lsp/snippet_spec.lua
index 4e127743eb..7903885420 100644
--- a/test/functional/plugin/lsp/snippet_spec.lua
+++ b/test/functional/plugin/lsp/snippet_spec.lua
@@ -19,9 +19,9 @@ describe('vim.lsp._snippet', function()
{
type = snippet.NodeType.TEXT,
raw = 'TE\\$\\}XT',
- esc = 'TE$}XT'
- }
- }
+ esc = 'TE$}XT',
+ },
+ },
}, parse('TE\\$\\}XT'))
end)
@@ -36,8 +36,8 @@ describe('vim.lsp._snippet', function()
{
type = snippet.NodeType.TABSTOP,
tabstop = 2,
- }
- }
+ },
+ },
}, parse('$1${2}'))
end)
@@ -56,7 +56,7 @@ describe('vim.lsp._snippet', function()
{
type = snippet.NodeType.TEXT,
raw = 'TE\\$\\}XT',
- esc = 'TE$}XT'
+ esc = 'TE$}XT',
},
{
type = snippet.NodeType.TABSTOP,
@@ -73,21 +73,21 @@ describe('vim.lsp._snippet', function()
{
type = snippet.NodeType.FORMAT,
capture_index = 1,
- modifier = 'upcase'
- }
- }
+ modifier = 'upcase',
+ },
+ },
},
},
{
type = snippet.NodeType.TEXT,
raw = 'TE\\$\\}XT',
- esc = 'TE$}XT'
+ esc = 'TE$}XT',
},
- }
- }
- }
+ },
+ },
+ },
},
- }
+ },
}, parse('${1:${2:TE\\$\\}XT$3${1/regex/${1:/upcase}/i}TE\\$\\}XT}}'))
end)
@@ -110,8 +110,8 @@ describe('vim.lsp._snippet', function()
{
type = snippet.NodeType.TABSTOP,
tabstop = 1,
- }
- }
+ },
+ },
},
{
type = snippet.NodeType.VARIABLE,
@@ -124,11 +124,11 @@ describe('vim.lsp._snippet', function()
type = snippet.NodeType.FORMAT,
capture_index = 1,
modifier = 'upcase',
- }
- }
- }
+ },
+ },
+ },
},
- }
+ },
}, parse('$VAR${VAR}${VAR:$1}${VAR/regex/${1:/upcase}/}'))
end)
@@ -141,12 +141,96 @@ describe('vim.lsp._snippet', function()
tabstop = 1,
items = {
',',
- '|'
- }
- }
- }
+ '|',
+ },
+ },
+ },
}, parse('${1|\\,,\\||}'))
end)
-end)
+ it('should parse format', function()
+ eq({
+ type = snippet.NodeType.SNIPPET,
+ children = {
+ {
+ type = snippet.NodeType.VARIABLE,
+ name = 'VAR',
+ transform = {
+ type = snippet.NodeType.TRANSFORM,
+ pattern = 'regex',
+ format = {
+ {
+ type = snippet.NodeType.FORMAT,
+ capture_index = 1,
+ modifier = 'upcase',
+ },
+ {
+ type = snippet.NodeType.FORMAT,
+ capture_index = 1,
+ if_text = 'if_text',
+ else_text = '',
+ },
+ {
+ type = snippet.NodeType.FORMAT,
+ capture_index = 1,
+ if_text = '',
+ else_text = 'else_text',
+ },
+ {
+ type = snippet.NodeType.FORMAT,
+ capture_index = 1,
+ else_text = 'else_text',
+ if_text = 'if_text',
+ },
+ {
+ type = snippet.NodeType.FORMAT,
+ capture_index = 1,
+ if_text = '',
+ else_text = 'else_text',
+ },
+ },
+ },
+ },
+ },
+ }, parse('${VAR/regex/${1:/upcase}${1:+if_text}${1:-else_text}${1:?if_text:else_text}${1:else_text}/}'))
+ end)
+ it('should parse empty strings', function()
+ eq({
+ children = {
+ {
+ children = { {
+ esc = '',
+ raw = '',
+ type = 7,
+ } },
+ tabstop = 1,
+ type = 2,
+ },
+ {
+ esc = ' ',
+ raw = ' ',
+ type = 7,
+ },
+ {
+ name = 'VAR',
+ transform = {
+ format = {
+ {
+ capture_index = 1,
+ else_text = '',
+ if_text = '',
+ type = 6,
+ },
+ },
+ option = 'g',
+ pattern = 'erg',
+ type = 5,
+ },
+ type = 3,
+ },
+ },
+ type = 0,
+ }, parse('${1:} ${VAR/erg/${1:?:}/g}'))
+ end)
+end)
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index 7ad1a52fe3..c166982052 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -18,6 +18,7 @@ local NIL = helpers.NIL
local read_file = require('test.helpers').read_file
local write_file = require('test.helpers').write_file
local isCI = helpers.isCI
+local meths = helpers.meths
-- Use these to get access to a coroutine so that I can run async tests and use
-- yield.
@@ -44,10 +45,10 @@ local function clear_notrace()
end
-local function fake_lsp_server_setup(test_name, timeout_ms, options)
+local function fake_lsp_server_setup(test_name, timeout_ms, options, settings)
exec_lua([=[
lsp = require('vim.lsp')
- local test_name, fixture_filename, logfile, timeout, options = ...
+ local test_name, fixture_filename, logfile, timeout, options, settings = ...
TEST_RPC_CLIENT_ID = lsp.start_client {
cmd_env = {
NVIM_LOG_FILE = logfile;
@@ -78,17 +79,18 @@ local function fake_lsp_server_setup(test_name, timeout_ms, options)
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;
}
- ]=], test_name, fake_lsp_code, fake_lsp_logfile, timeout_ms or 1e3, options or {})
+ ]=], test_name, fake_lsp_code, fake_lsp_logfile, timeout_ms or 1e3, options or {}, settings or {})
end
local function test_rpc_server(config)
if config.test_name then
clear_notrace()
- fake_lsp_server_setup(config.test_name, config.timeout_ms or 1e3, config.options)
+ fake_lsp_server_setup(config.test_name, config.timeout_ms or 1e3, config.options, config.settings)
end
local client = setmetatable({}, {
__index = function(_, name)
@@ -135,7 +137,7 @@ local function test_rpc_server(config)
end
stop()
if config.test_name then
- exec_lua("lsp._vim_exit_handler()")
+ exec_lua("vim.api.nvim_exec_autocmds('VimLeavePre', { modeline = false })")
end
end
@@ -170,7 +172,7 @@ describe('LSP', function()
end)
after_each(function()
- exec_lua("lsp._vim_exit_handler()")
+ exec_lua("vim.api.nvim_exec_autocmds('VimLeavePre', { modeline = false })")
-- exec_lua("lsp.stop_all_clients(true)")
end)
@@ -221,11 +223,33 @@ describe('LSP', function()
end)
end)
+ describe('lsp._cmd_parts test', function()
+ local function _cmd_parts(input)
+ return exec_lua([[
+ lsp = require('vim.lsp')
+ return lsp._cmd_parts(...)
+ ]], input)
+ end
+ it('should valid cmd argument', function()
+ eq(true, pcall(_cmd_parts, {"nvim"}))
+ eq(true, pcall(_cmd_parts, {"nvim", "--head"}))
+ end)
+
+ it('should invalid cmd argument', function()
+ eq('Error executing lua: .../lsp.lua:0: cmd: expected list, got nvim',
+ pcall_err(_cmd_parts, 'nvim'))
+ eq('Error executing lua: .../lsp.lua:0: cmd argument: expected string, got number',
+ pcall_err(_cmd_parts, {'nvim', 1}))
+ end)
+ end)
+end)
+
+describe('LSP', function()
describe('basic_init test', function()
after_each(function()
stop()
- exec_lua("lsp.stop_client(lsp.get_active_clients())")
- exec_lua("lsp._vim_exit_handler()")
+ exec_lua("lsp.stop_client(lsp.get_active_clients(), true)")
+ exec_lua("vim.api.nvim_exec_autocmds('VimLeavePre', { modeline = false })")
end)
it('should run correctly', function()
@@ -242,8 +266,8 @@ describe('LSP', function()
end;
-- If the program timed out, then code will be nil.
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;
-- Note that NIL must be used here.
-- on_handler(err, method, result, client_id)
@@ -264,8 +288,8 @@ describe('LSP', function()
client.stop()
end;
on_exit = function(code, signal)
- eq(101, code, "exit code", fake_lsp_logfile) -- See fake-lsp-server.lua
- eq(0, signal, "exit signal", fake_lsp_logfile)
+ eq(101, code, "exit code") -- See fake-lsp-server.lua
+ eq(0, signal, "exit signal")
assert_log(pesc([[assert_eq failed: left == "\"shutdown\"", right == "\"test\""]]),
fake_lsp_logfile)
end;
@@ -275,6 +299,22 @@ describe('LSP', function()
}
end)
+ it('should send didChangeConfiguration after initialize if there are settings', function()
+ test_rpc_server({
+ test_name = 'basic_init_did_change_configuration',
+ on_init = function(client, _)
+ client.stop()
+ end,
+ on_exit = function(code, signal)
+ eq(0, code, 'exit code', fake_lsp_logfile)
+ eq(0, signal, 'exit signal', fake_lsp_logfile)
+ end,
+ settings = {
+ dummy = 1,
+ },
+ })
+ end)
+
it('should succeed with manual shutdown', function()
if isCI() then
pending('hangs the build on CI #14028, re-enable with freeze timeout #14204')
@@ -289,14 +329,14 @@ describe('LSP', function()
test_rpc_server {
test_name = "basic_init";
on_init = function(client)
- eq(0, client.resolved_capabilities().text_document_did_change)
+ eq(0, client.server_capabilities().textDocumentSync.change)
client.request('shutdown')
client.notify('exit')
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;
on_handler = function(...)
eq(table.remove(expected_handlers), {...}, "expected handler")
@@ -327,8 +367,8 @@ describe('LSP', function()
client.notify('finish')
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;
on_handler = function(err, result, ctx)
eq(table.remove(expected_handlers), {err, result, ctx}, "expected handler")
@@ -341,12 +381,51 @@ describe('LSP', function()
}
end)
+ it('should fire autocommands on attach and detach', function()
+ local client
+ test_rpc_server {
+ test_name = "basic_init";
+ on_setup = function()
+ exec_lua [[
+ 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
+ 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
+ end,
+ })
+ ]]
+ end;
+ on_init = function(_client)
+ client = _client
+ eq(true, exec_lua("return lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)"))
+ client.notify('finish')
+ end;
+ on_handler = function(_, _, ctx)
+ if ctx.method == 'finish' then
+ eq('basic_init', meths.get_var('lsp_attached'))
+ exec_lua("return lsp.buf_detach_client(BUFFER, TEST_RPC_CLIENT_ID)")
+ eq('basic_init', meths.get_var('lsp_detached'))
+ client.stop()
+ end
+ end;
+ }
+ end)
+
it('client should return settings via workspace/configuration handler', function()
local expected_handlers = {
{NIL, {}, {method="shutdown", client_id=1}};
{NIL, { items = {
{ section = "testSetting1" };
{ section = "testSetting2" };
+ { section = "test.Setting3" };
+ { section = "test.Setting4" };
}}, { method="workspace/configuration", client_id=1}};
{NIL, {}, {method="start", client_id=1}};
}
@@ -357,8 +436,8 @@ describe('LSP', function()
client = _client
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;
on_handler = function(err, result, ctx)
eq(table.remove(expected_handlers), {err, result, ctx}, "expected handler")
@@ -368,6 +447,7 @@ describe('LSP', function()
client.config.settings = {
testSetting1 = true;
testSetting2 = false;
+ test = {Setting3 = 'nested' };
}]=])
end
if ctx.method == 'workspace/configuration' then
@@ -383,16 +463,23 @@ describe('LSP', function()
}
end)
it('workspace/configuration returns NIL per section if client was started without config.settings', function()
- fake_lsp_server_setup('workspace/configuration no settings')
- eq({ NIL, NIL, }, exec_lua [[
- local result = {
- items = {
- {section = 'foo'},
- {section = 'bar'},
- }
- }
- return vim.lsp.handlers['workspace/configuration'](nil, result, {client_id=TEST_RPC_CLIENT_ID})
- ]])
+ local result = nil
+ test_rpc_server {
+ test_name = 'basic_init';
+ on_init = function(c) c.stop() end,
+ on_setup = function()
+ result = exec_lua [[
+ local result = {
+ items = {
+ {section = 'foo'},
+ {section = 'bar'},
+ }
+ }
+ return vim.lsp.handlers['workspace/configuration'](nil, result, {client_id=TEST_RPC_CLIENT_ID})
+ ]]
+ end
+ }
+ eq({ NIL, NIL }, result)
end)
it('should verify capabilities sent', function()
@@ -404,14 +491,13 @@ describe('LSP', function()
on_init = function(client)
client.stop()
local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
- eq(full_kind, client.resolved_capabilities().text_document_did_change)
- eq(true, client.resolved_capabilities().text_document_save)
- eq(false, client.resolved_capabilities().code_lens)
- eq(false, client.resolved_capabilities().code_lens_resolve)
+ eq(full_kind, client.server_capabilities().textDocumentSync.change)
+ eq({includeText = false}, client.server_capabilities().textDocumentSync.save)
+ eq(false, client.server_capabilities().codeLensProvider)
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;
on_handler = function(...)
eq(table.remove(expected_handlers), {...}, "expected handler")
@@ -419,6 +505,67 @@ describe('LSP', function()
}
end)
+ it('BufWritePost sends didSave with bool textDocumentSync.save', function()
+ local expected_handlers = {
+ {NIL, {}, {method="shutdown", client_id=1}};
+ {NIL, {}, {method="start", client_id=1}};
+ }
+ local client
+ test_rpc_server {
+ test_name = "text_document_sync_save_bool";
+ on_init = function(c)
+ client = c
+ end;
+ on_exit = function(code, signal)
+ eq(0, code, "exit code")
+ eq(0, signal, "exit signal")
+ end;
+ 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 })
+ ]=])
+ else
+ client.stop()
+ end
+ end;
+ }
+ end)
+
+ it('BufWritePost sends didSave including text if server capability is set', function()
+ local expected_handlers = {
+ {NIL, {}, {method="shutdown", client_id=1}};
+ {NIL, {}, {method="start", client_id=1}};
+ }
+ local client
+ test_rpc_server {
+ test_name = "text_document_sync_save_includeText";
+ on_init = function(c)
+ client = c
+ end;
+ on_exit = function(code, signal)
+ eq(0, code, "exit code")
+ eq(0, signal, "exit signal")
+ end;
+ 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 })
+ ]=])
+ else
+ client.stop()
+ end
+ end;
+ }
+ end)
+
it('client.supports_methods() should validate capabilities', function()
local expected_handlers = {
{NIL, {}, {method="shutdown", client_id=1}};
@@ -427,14 +574,19 @@ describe('LSP', function()
test_name = "capabilities_for_client_supports_method";
on_init = function(client)
client.stop()
- local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
- eq(full_kind, client.resolved_capabilities().text_document_did_change)
- eq(true, client.resolved_capabilities().completion)
- eq(true, client.resolved_capabilities().hover)
- eq(false, client.resolved_capabilities().goto_definition)
- eq(false, client.resolved_capabilities().rename)
- eq(true, client.resolved_capabilities().code_lens)
- eq(true, client.resolved_capabilities().code_lens_resolve)
+ local expected_sync_capabilities = {
+ change = 1,
+ openClose = true,
+ save = { includeText = false },
+ willSave = false,
+ willSaveWaitUntil = false,
+ }
+ eq(expected_sync_capabilities, client.server_capabilities().textDocumentSync)
+ eq(true, client.server_capabilities().completionProvider)
+ eq(true, client.server_capabilities().hoverProvider)
+ eq(false, client.server_capabilities().definitionProvider)
+ eq(false, client.server_capabilities().renameProvider)
+ eq(true, client.server_capabilities().codeLensProvider.resolveProvider)
-- known methods for resolved capabilities
eq(true, client.supports_method("textDocument/hover"))
@@ -444,8 +596,8 @@ describe('LSP', function()
eq(true, client.supports_method("unknown-method"))
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;
on_handler = function(...)
eq(table.remove(expected_handlers), {...}, "expected handler")
@@ -474,8 +626,8 @@ describe('LSP', function()
]]
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;
on_handler = function(...)
eq(table.remove(expected_handlers), {...}, "expected handler")
@@ -499,8 +651,8 @@ describe('LSP', function()
exec_lua("vim.lsp.buf.type_definition()")
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;
on_handler = function(...)
eq(table.remove(expected_handlers), {...}, "expected handler")
@@ -520,8 +672,8 @@ describe('LSP', function()
client = _client
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")
eq(0, #expected_handlers, "did not call expected handler")
end;
on_handler = function(err, _, ctx)
@@ -544,8 +696,8 @@ describe('LSP', function()
client = _client
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")
eq(0, #expected_handlers, "did not call expected handler")
end;
on_handler = function(err, _, ctx)
@@ -574,8 +726,8 @@ describe('LSP', function()
client.notify("release")
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")
eq(0, #expected_handlers, "did not call expected handler")
end;
on_handler = function(err, _, ctx)
@@ -607,8 +759,8 @@ describe('LSP', function()
client.notify("release")
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")
eq(0, #expected_handlers, "did not call expected handler")
end;
on_handler = function(err, _, ctx)
@@ -641,8 +793,8 @@ describe('LSP', function()
client.notify("release")
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")
eq(0, #expected_handlers, "did not call expected handler")
end;
on_handler = function(err, _, ctx)
@@ -676,8 +828,8 @@ describe('LSP', function()
client.notify("release")
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")
eq(0, #expected_handlers, "did not call expected handler")
eq(3, eval('g:requests'))
end;
@@ -717,13 +869,13 @@ describe('LSP', function()
on_init = function(_client)
client = _client
local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
- eq(full_kind, client.resolved_capabilities().text_document_did_change)
- eq(true, client.resolved_capabilities().text_document_open_close)
+ eq(full_kind, client.server_capabilities().textDocumentSync.change)
+ eq(true, client.server_capabilities().textDocumentSync.openClose)
client.notify('finish')
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;
on_handler = function(err, result, ctx)
eq(table.remove(expected_handlers), {err, result, ctx}, "expected handler")
@@ -758,15 +910,15 @@ describe('LSP', function()
on_init = function(_client)
client = _client
local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
- eq(full_kind, client.resolved_capabilities().text_document_did_change)
- eq(true, client.resolved_capabilities().text_document_open_close)
+ eq(full_kind, client.server_capabilities().textDocumentSync.change)
+ eq(true, client.server_capabilities().textDocumentSync.openClose)
exec_lua [[
assert(not lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID), "Shouldn't attach twice")
]]
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;
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
@@ -801,15 +953,15 @@ describe('LSP', function()
on_init = function(_client)
client = _client
local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
- eq(full_kind, client.resolved_capabilities().text_document_did_change)
- eq(true, client.resolved_capabilities().text_document_open_close)
+ 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))
]]
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;
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
@@ -844,15 +996,15 @@ describe('LSP', function()
on_init = function(_client)
client = _client
local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
- eq(full_kind, client.resolved_capabilities().text_document_did_change)
- eq(true, client.resolved_capabilities().text_document_open_close)
+ 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))
]]
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;
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
@@ -893,15 +1045,15 @@ describe('LSP', function()
on_init = function(_client)
client = _client
local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
- eq(full_kind, client.resolved_capabilities().text_document_did_change)
- eq(true, client.resolved_capabilities().text_document_open_close)
+ 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))
]]
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;
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
@@ -944,15 +1096,15 @@ describe('LSP', function()
on_init = function(_client)
client = _client
local sync_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Incremental")
- eq(sync_kind, client.resolved_capabilities().text_document_did_change)
- eq(true, client.resolved_capabilities().text_document_open_close)
+ 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))
]]
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;
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
@@ -995,15 +1147,15 @@ describe('LSP', function()
on_init = function(_client)
client = _client
local sync_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Incremental")
- eq(sync_kind, client.resolved_capabilities().text_document_did_change)
- eq(true, client.resolved_capabilities().text_document_open_close)
+ 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))
]]
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;
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
@@ -1044,15 +1196,15 @@ describe('LSP', function()
on_init = function(_client)
client = _client
local sync_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Incremental")
- eq(sync_kind, client.resolved_capabilities().text_document_did_change)
- eq(true, client.resolved_capabilities().text_document_open_close)
+ 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))
]]
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;
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
@@ -1088,15 +1240,15 @@ describe('LSP', function()
on_init = function(_client)
client = _client
local sync_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
- eq(sync_kind, client.resolved_capabilities().text_document_did_change)
- eq(true, client.resolved_capabilities().text_document_open_close)
+ 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))
]]
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;
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
@@ -1139,15 +1291,15 @@ describe('LSP', function()
on_init = function(_client)
client = _client
local sync_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
- eq(sync_kind, client.resolved_capabilities().text_document_did_change)
- eq(true, client.resolved_capabilities().text_document_open_close)
+ 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))
]]
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;
on_handler = function(err, result,ctx)
if ctx.method == 'start' then
@@ -1188,8 +1340,8 @@ describe('LSP', function()
client.stop(true)
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;
on_handler = function(err, result, ctx)
eq(table.remove(expected_handlers), {err, result, ctx}, "expected handler")
@@ -1227,8 +1379,8 @@ describe('LSP', function()
]]
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;
on_handler = function(err, result, ctx)
eq(table.remove(expected_handlers), {err, result, ctx}, "expected handler")
@@ -1239,25 +1391,6 @@ describe('LSP', function()
}
end)
end)
- describe('lsp._cmd_parts test', function()
- local function _cmd_parts(input)
- return exec_lua([[
- lsp = require('vim.lsp')
- return lsp._cmd_parts(...)
- ]], input)
- end
- it('should valid cmd argument', function()
- eq(true, pcall(_cmd_parts, {"nvim"}))
- eq(true, pcall(_cmd_parts, {"nvim", "--head"}))
- end)
-
- it('should invalid cmd argument', function()
- eq('Error executing lua: .../lsp.lua:0: cmd: expected list, got nvim',
- pcall_err(_cmd_parts, 'nvim'))
- eq('Error executing lua: .../lsp.lua:0: cmd argument: expected string, got number',
- pcall_err(_cmd_parts, {'nvim', 1}))
- end)
- end)
end)
describe('LSP', function()
@@ -1291,7 +1424,7 @@ describe('LSP', function()
make_edit(2, 0, 2, 2, {"3"});
make_edit(3, 2, 3, 4, {""});
}
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
eq({
'123First line of text';
'2econd line of text';
@@ -1311,7 +1444,7 @@ describe('LSP', function()
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)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
eq({
'';
'123';
@@ -1335,7 +1468,7 @@ describe('LSP', function()
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)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
eq({
'';
'123';
@@ -1352,7 +1485,7 @@ describe('LSP', function()
local edits = {
make_edit(4, 3, 4, 4, {"ä"});
}
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
eq({
'First line of text';
'Second line of text';
@@ -1365,7 +1498,7 @@ describe('LSP', function()
local edits = {
make_edit(5, 0, 5, 0, "foobar");
}
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
eq({
'First line of text';
'Second line of text';
@@ -1375,6 +1508,20 @@ 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")
+ eq({
+ 'First line of text';
+ 'Second line of text';
+ 'Third line of text';
+ 'Fourth line of text';
+ 'foobar';
+ }, buf_lines(1))
+ end)
describe('cursor position', function()
it('don\'t fix the cursor if the range contains the cursor', function()
@@ -1382,7 +1529,7 @@ describe('LSP', function()
local edits = {
make_edit(1, 0, 1, 19, 'Second line of text')
}
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
eq({
'First line of text';
'Second line of text';
@@ -1399,7 +1546,7 @@ describe('LSP', function()
make_edit(1, 0, 1, 6, ''),
make_edit(1, 6, 1, 19, '')
}
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
eq({
'First line of text';
'';
@@ -1416,7 +1563,7 @@ describe('LSP', function()
make_edit(1, 0, 1, 6, ''),
make_edit(0, 18, 5, 0, '')
}
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
eq({
'First line of text';
}, buf_lines(1))
@@ -1428,7 +1575,7 @@ describe('LSP', function()
local edits = {
make_edit(1, 0, 2, 0, '')
}
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
eq({
'First line of text';
'Third line of text';
@@ -1443,7 +1590,7 @@ describe('LSP', function()
local edits = {
make_edit(1, 7, 1, 11, '')
}
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
eq({
'First line of text';
'Second of text';
@@ -1459,7 +1606,7 @@ describe('LSP', function()
local edits = {
make_edit(0, 11, 1, 12, '')
}
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
eq({
'First line of text';
'Third line of text';
@@ -1475,21 +1622,21 @@ describe('LSP', function()
local edits = {
make_edit(0, 0, 5, 0, {"All replaced"});
}
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
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)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
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)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
eq({'All replaced'}, buf_lines(1))
end)
end)
@@ -1517,7 +1664,7 @@ describe('LSP', function()
]]
end)
it('correctly goes ahead with the edit if all is normal', function()
- exec_lua('vim.lsp.util.apply_text_document_edit(...)', text_document_edit(5))
+ exec_lua("vim.lsp.util.apply_text_document_edit(..., nil, 'utf-16')", text_document_edit(5))
eq({
'First ↥ 🤦 🦄 line of text';
'2nd line of 语text';
@@ -1529,7 +1676,7 @@ describe('LSP', function()
local bufnr = select(1, ...)
local text_edit = select(2, ...)
vim.lsp.util.buf_versions[bufnr] = 10
- vim.lsp.util.apply_text_document_edit(text_edit)
+ vim.lsp.util.apply_text_document_edit(text_edit, nil, 'utf-16')
]], target_bufnr, text_document_edit(0))
eq({
'First ↥ 🤦 🦄 line of text';
@@ -1542,7 +1689,7 @@ describe('LSP', function()
local args = {...}
local versionedBuf = args[2]
vim.lsp.util.buf_versions[versionedBuf.bufnr] = versionedBuf.currentVersion
- vim.lsp.util.apply_text_document_edit(args[1])
+ vim.lsp.util.apply_text_document_edit(args[1], nil, 'utf-16')
]], edit, versionedBuf)
end
@@ -1568,17 +1715,36 @@ describe('LSP', function()
describe('workspace_apply_edit', function()
it('workspace/applyEdit returns ApplyWorkspaceEditResponse', function()
- local expected = {
- applied = true;
- failureReason = nil;
+ local expected_handlers = {
+ {NIL, {}, {method="test", client_id=1}};
+ }
+ test_rpc_server {
+ test_name = "basic_init";
+ on_init = function(client, _)
+ client.stop()
+ end;
+ -- If the program timed out, then code will be nil.
+ on_exit = function(code, signal)
+ eq(0, code, "exit code")
+ eq(0, signal, "exit signal")
+ end;
+ -- Note that NIL must be used here.
+ -- on_handler(err, method, result, client_id)
+ on_handler = function(...)
+ local expected = {
+ applied = true;
+ failureReason = nil;
+ }
+ 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})
+ ]])
+ eq(table.remove(expected_handlers), {...})
+ end;
}
- eq(expected, exec_lua [[
- local apply_edit = {
- label = nil;
- edit = {};
- }
- return vim.lsp.handlers['workspace/applyEdit'](nil, apply_edit)
- ]])
end)
end)
@@ -1652,7 +1818,7 @@ describe('LSP', function()
local workspace_edits = args[1]
local target_bufnr = args[2]
- vim.lsp.util.apply_workspace_edit(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))
@@ -1674,7 +1840,7 @@ describe('LSP', function()
local workspace_edits = args[1]
local target_bufnr = args[2]
- vim.lsp.util.apply_workspace_edit(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))
@@ -1691,7 +1857,7 @@ describe('LSP', function()
},
}
}
- exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit)
+ exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit, 'utf-16')
eq(true, exec_lua('return vim.loop.fs_stat(...) ~= nil', tmpfile))
end)
it('createFile does not touch file if it exists and ignoreIfExists is set', function()
@@ -1709,7 +1875,7 @@ describe('LSP', function()
},
}
}
- exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit)
+ exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit, 'utf-16')
eq(true, exec_lua('return vim.loop.fs_stat(...) ~= nil', tmpfile))
eq('Dummy content', read_file(tmpfile))
end)
@@ -1729,7 +1895,7 @@ describe('LSP', function()
},
}
}
- exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit)
+ exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit, 'utf-16')
eq(true, exec_lua('return vim.loop.fs_stat(...) ~= nil', tmpfile))
eq('', read_file(tmpfile))
end)
@@ -1750,7 +1916,7 @@ describe('LSP', function()
}
}
}
- eq(true, pcall(exec_lua, 'vim.lsp.util.apply_workspace_edit(...)', edit))
+ eq(true, pcall(exec_lua, 'vim.lsp.util.apply_workspace_edit(...)', edit, 'utf-16'))
eq(false, exec_lua('return vim.loop.fs_stat(...) ~= nil', tmpfile))
eq(false, exec_lua('return vim.api.nvim_buf_is_loaded(vim.fn.bufadd(...))', tmpfile))
end)
@@ -1911,7 +2077,7 @@ describe('LSP', function()
}
},
}
- return vim.lsp.util.locations_to_items(locations)
+ return vim.lsp.util.locations_to_items(locations, 'utf-16')
]]
eq(expected, actual)
end)
@@ -1941,7 +2107,7 @@ describe('LSP', function()
}
},
}
- return vim.lsp.util.locations_to_items(locations)
+ return vim.lsp.util.locations_to_items(locations, 'utf-16')
]]
eq(expected, actual)
end)
@@ -2245,7 +2411,7 @@ describe('LSP', function()
end
local jump = function(msg)
- eq(true, exec_lua('return vim.lsp.util.jump_to_location(...)', msg))
+ eq(true, exec_lua('return vim.lsp.util.jump_to_location(...)', msg, "utf-16"))
eq(target_bufnr, exec_lua[[return vim.fn.bufnr('%')]])
return {
line = exec_lua[[return vim.fn.line('.')]],
@@ -2319,19 +2485,38 @@ describe('LSP', function()
end)
end)
+ describe('lsp.util.convert_signature_help_to_markdown_lines', function()
+ it('can handle negative activeSignature', function()
+ local result = exec_lua[[
+ local signature_help = {
+ activeParameter = 0,
+ activeSignature = -1,
+ signatures = {
+ {
+ documentation = "",
+ label = "TestEntity.TestEntity()",
+ parameters = {}
+ },
+ }
+ }
+ return vim.lsp.util.convert_signature_help_to_markdown_lines(signature_help, 'cs', {','})
+ ]]
+ local expected = {'```cs', 'TestEntity.TestEntity()', '```', ''}
+ eq(expected, result)
+ end)
+ end)
+
describe('lsp.util.get_effective_tabstop', function()
- local function test_tabstop(tabsize, softtabstop)
+ local function test_tabstop(tabsize, shiftwidth)
exec_lua(string.format([[
- vim.api.nvim_buf_set_option(0, 'softtabstop', %d)
+ vim.api.nvim_buf_set_option(0, 'shiftwidth', %d)
vim.api.nvim_buf_set_option(0, 'tabstop', 2)
- vim.api.nvim_buf_set_option(0, 'shiftwidth', 3)
- ]], softtabstop))
+ ]], shiftwidth))
eq(tabsize, exec_lua('return vim.lsp.util.get_effective_tabstop()'))
end
- it('with softtabstop = 1', function() test_tabstop(1, 1) end)
- it('with softtabstop = 0', function() test_tabstop(2, 0) end)
- it('with softtabstop = -1', function() test_tabstop(3, -1) end)
+ it('with shiftwidth = 1', function() test_tabstop(1, 1) end)
+ it('with shiftwidth = 0', function() test_tabstop(2, 0) end)
end)
describe('vim.lsp.buf.outgoing_calls', function()
@@ -2516,10 +2701,8 @@ describe('LSP', function()
name = "prepare_rename_error",
expected_handlers = {
{NIL, {}, {method="shutdown", client_id=1}};
- {NIL, NIL, {method="textDocument/rename", client_id=1, bufnr=1}};
{NIL, {}, {method="start", client_id=1}};
},
- expected_text = "two", -- see test case
},
}) do
it(test.it, function()
@@ -2528,7 +2711,7 @@ describe('LSP', function()
test_name = test.name;
on_init = function(_client)
client = _client
- eq(true, client.resolved_capabilities().rename)
+ eq(true, client.server_capabilities().renameProvider.prepareProvider)
end;
on_setup = function()
exec_lua([=[
@@ -2545,8 +2728,8 @@ describe('LSP', function()
]=])
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;
on_handler = function(err, result, ctx)
-- Don't compare & assert params, they're not relevant for the testcase
@@ -2585,8 +2768,8 @@ describe('LSP', function()
on_setup = function()
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,
on_handler = function(err, result, ctx)
eq(table.remove(expected_handlers), {err, result, ctx})
@@ -2610,6 +2793,102 @@ describe('LSP', function()
end
}
end)
+ it('Calls workspace/executeCommand if no client side command', function()
+ local client
+ local expected_handlers = {
+ { NIL, {}, { method = 'shutdown', client_id = 1 } },
+ {
+ NIL,
+ { command = 'dummy1', title = 'Command 1' },
+ { bufnr = 1, method = 'workspace/executeCommand', client_id = 1 },
+ },
+ { NIL, {}, { method = 'start', client_id = 1 } },
+ }
+ test_rpc_server({
+ test_name = 'code_action_server_side_command',
+ on_init = function(client_)
+ client = client_
+ end,
+ on_setup = function() end,
+ on_exit = function(code, signal)
+ eq(0, code, 'exit code', fake_lsp_logfile)
+ eq(0, signal, 'exit signal', fake_lsp_logfile)
+ end,
+ on_handler = function(err, result, ctx)
+ ctx.params = nil -- don't compare in assert
+ eq(table.remove(expected_handlers), { err, result, ctx })
+ if ctx.method == 'start' then
+ exec_lua([[
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID)
+ vim.fn.inputlist = function()
+ return 1
+ end
+ vim.lsp.buf.code_action()
+ ]])
+ elseif ctx.method == 'shutdown' then
+ client.stop()
+ end
+ end,
+ })
+ end)
+ it('Filters and automatically applies action if requested', function()
+ local client
+ local expected_handlers = {
+ {NIL, {}, {method="shutdown", client_id=1}};
+ {NIL, {}, {method="start", client_id=1}};
+ }
+ test_rpc_server {
+ test_name = 'code_action_filter',
+ on_init = function(client_)
+ client = client_
+ end,
+ on_setup = function()
+ end,
+ on_exit = function(code, signal)
+ eq(0, code, "exit code")
+ eq(0, signal, "exit signal")
+ end,
+ 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
+ end
+ vim.lsp.commands['quickfix_command'] = function(cmd)
+ vim.lsp.commands['executed_quickfix'] = 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.code_action({
+ -- expect to be returned actions 'quickfix' and 'quickfix.foo'
+ context = { only = {'quickfix'}, },
+ apply = true,
+ filter = function(a)
+ if a.kind == 'quickfix.foo' then
+ vim.lsp.commands['filtered_quickfix_foo'] = function() end
+ return false
+ elseif a.kind == 'quickfix' then
+ return true
+ else
+ assert(nil, 'unreachable')
+ 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_quickfix_foo'])]])
+ eq('function', exec_lua[[return type(vim.lsp.commands['executed_quickfix'])]])
+ client.stop()
+ end
+ end
+ }
+ end)
end)
describe('vim.lsp.commands', function()
it('Accepts only string keys', function()
@@ -2640,8 +2919,8 @@ describe('LSP', function()
on_setup = function()
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,
on_handler = function(err, result, ctx)
eq(table.remove(expected_handlers), {err, result, ctx})
@@ -2677,5 +2956,189 @@ describe('LSP', function()
end
}
end)
+
+ it('releases buffer refresh lock', function()
+ local client
+ local expected_handlers = {
+ {NIL, {}, {method="shutdown", client_id=1}};
+ {NIL, {}, {method="start", client_id=1}};
+ }
+ test_rpc_server {
+ test_name = 'codelens_refresh_lock',
+ on_init = function(client_)
+ 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
+ ]=])
+ end,
+ on_exit = function(code, signal)
+ eq(0, code, "exit code")
+ eq(0, signal, "exit signal")
+ end,
+ on_handler = function(err, result, ctx)
+ eq(table.remove(expected_handlers), {err, result, ctx})
+ if ctx.method == 'start' then
+ -- 1. first codelens request errors
+ local response = exec_lua([=[
+ CALLED = false
+ vim.lsp.codelens.refresh()
+ vim.wait(100, function () return CALLED end)
+ return RESPONSE
+ ]=])
+ 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
+ end
+ vim.lsp.codelens.refresh()
+ vim.wait(100, function () return CALLED end)
+ vim.lsp.codelens.run()
+ vim.wait(100, function () return cmd_called end)
+ return cmd_called
+ ]=])
+ 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
+ end
+ vim.lsp.codelens.refresh()
+ vim.wait(100, function () return CALLED end)
+ vim.lsp.codelens.run()
+ vim.wait(100, function () return cmd_called end)
+ return cmd_called
+ ]=])
+ eq( { command = "Dummy", title = "Lens2" }, response)
+ elseif ctx.method == 'shutdown' then
+ client.stop()
+ end
+ end
+ }
+ end)
+ end)
+
+ describe("vim.lsp.buf.format", function()
+ it("Aborts with notify if no client matches filter", function()
+ local client
+ test_rpc_server {
+ test_name = "basic_init",
+ on_init = function(c)
+ client = c
+ end,
+ on_handler = function()
+ local notify_msg = exec_lua([[
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID)
+ local notify_msg
+ local notify = vim.notify
+ vim.notify = function(msg, log_level)
+ notify_msg = msg
+ end
+ vim.lsp.buf.format({ name = 'does-not-exist' })
+ vim.notify = notify
+ return notify_msg
+ ]])
+ 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}};
+ {NIL, {}, {method="start", client_id=1}};
+ }
+ local client
+ test_rpc_server {
+ test_name = "basic_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([[
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID)
+ local notify_msg
+ local notify = vim.notify
+ vim.notify = function(msg, log_level)
+ notify_msg = msg
+ end
+ vim.lsp.buf.format({ bufnr = bufnr })
+ vim.notify = notify
+ return notify_msg
+ ]])
+ 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}};
+ {NIL, {}, {method="start", client_id=1}};
+ }
+ local client
+ test_rpc_server {
+ test_name = "basic_formatting",
+ on_init = function(c)
+ client = c
+ end,
+ on_handler = function(_, _, ctx)
+ table.remove(expected_handlers)
+ if ctx.method == "start" then
+ local result = exec_lua([[
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID)
+
+ local notify_msg
+ local notify = vim.notify
+ vim.notify = function(msg, log_level)
+ notify_msg = msg
+ end
+
+ local handler = vim.lsp.handlers['textDocument/formatting']
+ local handler_called = false
+ 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.notify = notify
+ vim.lsp.handlers['textDocument/formatting'] = handler
+ return {notify = notify_msg, handler_called = handler_called}
+ ]])
+ eq({handler_called=true}, result)
+ elseif ctx.method == "shutdown" then
+ client.stop()
+ end
+ end,
+ }
+ end)
end)
end)
diff --git a/test/functional/plugin/man_spec.lua b/test/functional/plugin/man_spec.lua
index e5b2e7dc1f..c8da5a711f 100644
--- a/test/functional/plugin/man_spec.lua
+++ b/test/functional/plugin/man_spec.lua
@@ -2,13 +2,19 @@ local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local command, eval, rawfeed = helpers.command, helpers.eval, helpers.rawfeed
local clear = helpers.clear
+local funcs = helpers.funcs
+local nvim_prog = helpers.nvim_prog
+local matches = helpers.matches
describe(':Man', function()
+ before_each(function()
+ clear()
+ end)
+
describe('man.lua: highlight_line()', function()
local screen
before_each(function()
- clear()
command('syntax on')
command('set filetype=man')
command('syntax off') -- Ignore syntax groups
@@ -137,4 +143,10 @@ describe(':Man', function()
]])
end)
end)
+
+ it('q quits in "$MANPAGER mode" (:Man!) #18281', function()
+ -- This will hang if #18281 regresses.
+ local args = {nvim_prog, '--headless', '+autocmd VimLeave * echo "quit works!!"', '+Man!', '+call nvim_input("q")'}
+ matches('quit works!!', funcs.system(args, {'manpage contents'}))
+ end)
end)
diff --git a/test/functional/plugin/matchparen_spec.lua b/test/functional/plugin/matchparen_spec.lua
index 13e1283e2c..2670734c1a 100644
--- a/test/functional/plugin/matchparen_spec.lua
+++ b/test/functional/plugin/matchparen_spec.lua
@@ -27,7 +27,7 @@ describe('matchparen', function()
feed('{<cr>')
feed('}')
- -- critical part: up + cr should result in an empty line inbetween the
+ -- critical part: up + cr should result in an empty line in between the
-- brackets... if the bug is there, the empty line will be before the '{'
feed('<up>')
feed('<cr>')
diff --git a/test/functional/plugin/shada_spec.lua b/test/functional/plugin/shada_spec.lua
index a4d78682ad..6f22f865e6 100644
--- a/test/functional/plugin/shada_spec.lua
+++ b/test/functional/plugin/shada_spec.lua
@@ -1,7 +1,7 @@
local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear
-local eq, nvim_eval, nvim_command, nvim, exc_exec, funcs, nvim_feed, curbuf =
- helpers.eq, helpers.eval, helpers.command, helpers.nvim, helpers.exc_exec,
+local eq, meths, nvim_eval, nvim_command, nvim, exc_exec, funcs, nvim_feed, curbuf =
+ helpers.eq, helpers.meths, helpers.eval, helpers.command, helpers.nvim, helpers.exc_exec,
helpers.funcs, helpers.feed, helpers.curbuf
local neq = helpers.neq
local read_file = helpers.read_file
@@ -2162,6 +2162,10 @@ describe('plugin/shada.vim', function()
wshada('\004\000\009\147\000\196\002ab\196\001a')
wshada_tmp('\004\000\009\147\000\196\002ab\196\001b')
+
+ local bufread_commands = meths.get_autocmds({ group = "ShaDaCommands", event = "BufReadCmd" })
+ eq(2, #bufread_commands--[[, vim.inspect(bufread_commands) ]])
+
-- Need to set nohidden so that the buffer containing 'fname' is not unloaded
-- after loading 'fname_tmp', otherwise the '++opt not supported' test below
-- won't work since the BufReadCmd autocmd won't be triggered.