aboutsummaryrefslogtreecommitdiff
path: root/test/functional/plugin
diff options
context:
space:
mode:
Diffstat (limited to 'test/functional/plugin')
-rw-r--r--test/functional/plugin/editorconfig_spec.lua28
-rw-r--r--test/functional/plugin/health_spec.lua95
-rw-r--r--test/functional/plugin/lsp/codelens_spec.lua84
-rw-r--r--test/functional/plugin/lsp/completion_spec.lua547
-rw-r--r--test/functional/plugin/lsp/diagnostic_spec.lua536
-rw-r--r--test/functional/plugin/lsp/handler_spec.lua23
-rw-r--r--test/functional/plugin/lsp/incremental_sync_spec.lua91
-rw-r--r--test/functional/plugin/lsp/inlay_hint_spec.lua335
-rw-r--r--test/functional/plugin/lsp/semantic_tokens_spec.lua378
-rw-r--r--test/functional/plugin/lsp/testutil.lua125
-rw-r--r--test/functional/plugin/lsp/utils_spec.lua104
-rw-r--r--test/functional/plugin/lsp_spec.lua3807
-rw-r--r--test/functional/plugin/man_spec.lua42
-rw-r--r--test/functional/plugin/msgpack_spec.lua65
-rw-r--r--test/functional/plugin/shada_spec.lua77
-rw-r--r--test/functional/plugin/tohtml_spec.lua109
16 files changed, 3823 insertions, 2623 deletions
diff --git a/test/functional/plugin/editorconfig_spec.lua b/test/functional/plugin/editorconfig_spec.lua
index 839a723405..5f69b8938a 100644
--- a/test/functional/plugin/editorconfig_spec.lua
+++ b/test/functional/plugin/editorconfig_spec.lua
@@ -7,7 +7,6 @@ local eq = t.eq
local pathsep = n.get_pathsep()
local fn = n.fn
local api = n.api
-local exec_lua = n.exec_lua
local testdir = 'Xtest-editorconfig'
@@ -16,8 +15,16 @@ local testdir = 'Xtest-editorconfig'
local function test_case(name, expected)
local filename = testdir .. pathsep .. name
command('edit ' .. filename)
+
for opt, val in pairs(expected) do
- eq(val, api.nvim_get_option_value(opt, { buf = 0 }), name)
+ local opt_info = api.nvim_get_option_info2(opt, {})
+ if opt_info.scope == 'win' then
+ eq(val, api.nvim_get_option_value(opt, { win = 0 }), name)
+ elseif opt_info.scope == 'buf' then
+ eq(val, api.nvim_get_option_value(opt, { buf = 0 }), name)
+ else
+ eq(val, api.nvim_get_option_value(opt, {}), name)
+ end
end
end
@@ -93,6 +100,12 @@ setup(function()
[max_line_length.txt]
max_line_length = 42
+
+ [short_spelling_language.txt]
+ spelling_language = de
+
+ [long_spelling_language.txt]
+ spelling_language = en-NZ
]]
)
end)
@@ -213,13 +226,18 @@ But not this one
end)
it('does not operate on invalid buffers', function()
- local ok, err = unpack(exec_lua([[
+ local ok, err = unpack(n.exec_lua(function()
vim.cmd.edit('test.txt')
local bufnr = vim.api.nvim_get_current_buf()
vim.cmd.bwipeout(bufnr)
- return {pcall(require('editorconfig').config, bufnr)}
- ]]))
+ return { pcall(require('editorconfig').config, bufnr) }
+ end))
eq(true, ok, err)
end)
+
+ it('sets spelllang', function()
+ test_case('short_spelling_language.txt', { spelllang = 'de' })
+ test_case('long_spelling_language.txt', { spelllang = 'en_nz' })
+ end)
end)
diff --git a/test/functional/plugin/health_spec.lua b/test/functional/plugin/health_spec.lua
index 9c7c953fb0..7089313303 100644
--- a/test/functional/plugin/health_spec.lua
+++ b/test/functional/plugin/health_spec.lua
@@ -40,11 +40,22 @@ describe(':checkhealth', function()
matches('ERROR $VIM .* zub', curbuf_contents())
end)
- it('completions can be listed via getcompletion()', function()
- clear()
+ it('getcompletion()', function()
+ clear { args = { '-u', 'NORC', '+set runtimepath+=test/functional/fixtures' } }
+
eq('vim.deprecated', getcompletion('vim', 'checkhealth')[1])
eq('vim.provider', getcompletion('vim.prov', 'checkhealth')[1])
eq('vim.lsp', getcompletion('vim.ls', 'checkhealth')[1])
+
+ -- "test_plug/health/init.lua" should complete as "test_plug", not "test_plug.health". #30342
+ eq({
+ 'test_plug',
+ 'test_plug.full_render',
+ 'test_plug.submodule',
+ 'test_plug.submodule_empty',
+ 'test_plug.success1',
+ 'test_plug.success2',
+ }, getcompletion('test_plug', 'checkhealth'))
end)
it('completion checks for vim.health._complete() return type #28456', function()
@@ -57,11 +68,9 @@ describe(':checkhealth', function()
end)
end)
-describe('health.vim', function()
+describe('vim.health', function()
before_each(function()
- clear { args = { '-u', 'NORC' } }
- -- Provides healthcheck functions
- command('set runtimepath+=test/functional/fixtures')
+ clear { args = { '-u', 'NORC', '+set runtimepath+=test/functional/fixtures' } }
end)
describe(':checkhealth', function()
@@ -70,7 +79,7 @@ describe('health.vim', function()
n.expect([[
==============================================================================
- test_plug.full_render: require("test_plug.full_render.health").check()
+ test_plug.full_render: require("test_plug.full_render.health").check()
report 1 ~
- OK life is fine
@@ -93,7 +102,7 @@ describe('health.vim', function()
n.expect([[
==============================================================================
- test_plug: require("test_plug.health").check()
+ test_plug: require("test_plug.health").check()
report 1 ~
- OK everything is fine
@@ -102,7 +111,7 @@ describe('health.vim', function()
- OK nothing to see here
==============================================================================
- test_plug.success1: require("test_plug.success1.health").check()
+ test_plug.success1: require("test_plug.success1.health").check()
report 1 ~
- OK everything is fine
@@ -111,7 +120,7 @@ describe('health.vim', function()
- OK nothing to see here
==============================================================================
- test_plug.success2: require("test_plug.success2.health").check()
+ test_plug.success2: require("test_plug.success2.health").check()
another 1 ~
- OK ok
@@ -123,7 +132,7 @@ describe('health.vim', function()
n.expect([[
==============================================================================
- test_plug.submodule: require("test_plug.submodule.health").check()
+ test_plug.submodule: require("test_plug.submodule.health").check()
report 1 ~
- OK everything is fine
@@ -148,9 +157,10 @@ describe('health.vim', function()
local screen = Screen.new(50, 12)
screen:attach()
screen:set_default_attr_ids({
+ h1 = { reverse = true },
+ h2 = { foreground = tonumber('0x6a0dad') },
Ok = { foreground = Screen.colors.LightGreen },
Error = { foreground = Screen.colors.Red },
- Heading = { foreground = tonumber('0x6a0dad') },
Bar = { foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGrey },
})
command('checkhealth foo success1')
@@ -158,15 +168,15 @@ describe('health.vim', function()
screen:expect {
grid = [[
^ |
- {Bar:──────────────────────────────────────────────────}|
- {Heading:foo: } |
+ {Bar: }|
+ {h1:foo: }|
|
- {Error:ERROR} No healthcheck found for "foo" plugin. |
|
- {Bar:──────────────────────────────────────────────────}|
- {Heading:test_plug.success1: require("test_plug.success1.he}|
+ {Bar: }|
+ {h1:test_plug.success1: require("test_pl}|
|
- {Heading:report 1} |
+ {h2:report 1} |
- {Ok:OK} everything is fine |
|
]],
@@ -179,7 +189,7 @@ describe('health.vim', function()
n.expect([[
==============================================================================
- non_existent_healthcheck:
+ non_existent_healthcheck:
- ERROR No healthcheck found for "non_existent_healthcheck" plugin.
]])
@@ -207,18 +217,17 @@ end)
describe(':checkhealth window', function()
before_each(function()
- clear { args = { '-u', 'NORC' } }
- -- Provides healthcheck functions
- command('set runtimepath+=test/functional/fixtures')
+ clear { args = { '-u', 'NORC', '+set runtimepath+=test/functional/fixtures' } }
command('set nofoldenable nowrap laststatus=0')
end)
it('opens directly if no buffer created', function()
local screen = Screen.new(50, 12)
screen:set_default_attr_ids {
+ h1 = { reverse = true },
+ h2 = { foreground = tonumber('0x6a0dad') },
[1] = { foreground = Screen.colors.Blue, bold = true },
[14] = { foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGray },
- [31] = { foreground = tonumber('0x6a0dad') },
[32] = { foreground = Screen.colors.PaleGreen2 },
}
screen:attach({ ext_multigrid = true })
@@ -230,15 +239,15 @@ describe(':checkhealth window', function()
[3:--------------------------------------------------]|
## grid 2
^ |
- {14:──────────────────────────────────────────────────}|
- {14:────────────────────────────} |
- {31:test_plug.success1: require("test_plug.success1. }|
- {31:health").check()} |
+ {14: }|
+ {14: } |
+ {h1:test_plug.success1: }|
+ {h1:require("test_plug.success1.health").check()} |
|
- {31:report 1} |
+ {h2:report 1} |
- {32:OK} everything is fine |
|
- {31:report 2} |
+ {h2:report 2} |
- {32:OK} nothing to see here |
## grid 3
|
@@ -249,9 +258,10 @@ describe(':checkhealth window', function()
local function test_health_vsplit(left, emptybuf, mods)
local screen = Screen.new(50, 20)
screen:set_default_attr_ids {
+ h1 = { reverse = true },
+ h2 = { foreground = tonumber('0x6a0dad') },
[1] = { foreground = Screen.colors.Blue, bold = true },
[14] = { foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGray },
- [31] = { foreground = tonumber('0x6a0dad') },
[32] = { foreground = Screen.colors.PaleGreen2 },
}
screen:attach({ ext_multigrid = true })
@@ -271,19 +281,20 @@ describe(':checkhealth window', function()
|
## grid 4
^ |
- {14:─────────────────────────}|*3
- {14:───} |
- {31:test_plug.success1: }|
- {31:require("test_plug. }|
- {31:success1.health").check()}|
+ {14: }|*3
+ {14: } |
+ {h1:test_plug. }|
+ {h1:success1: }|
+ {h1:require("test_plug. }|
+ {h1:success1.health").check()}|
|
- {31:report 1} |
+ {h2:report 1} |
- {32:OK} everything is fine |
|
- {31:report 2} |
+ {h2:report 2} |
- {32:OK} nothing to see here |
|
- {1:~ }|*4
+ {1:~ }|*3
]]):format(
left and '[4:-------------------------]│[2:------------------------]|*19'
or '[2:------------------------]│[4:-------------------------]|*19',
@@ -330,10 +341,10 @@ describe(':checkhealth window', function()
|
## grid 4
^ |
- ──────────────────────────────────────────────────|
- ──────────────────────────── |
- test_plug.success1: require("test_plug.success1. |
- health").check() |
+ |
+ |
+ test_plug.success1: |
+ require("test_plug.success1.health").check() |
|
report 1 |
- OK everything is fine |
@@ -382,7 +393,7 @@ describe(':checkhealth window', function()
command('file my_buff')
command('checkhealth success1')
-- define a function that collects all buffers in each tab
- -- returns a dictionary like {tab1 = ["buf1", "buf2"], tab2 = ["buf3"]}
+ -- returns a dict like {tab1 = ["buf1", "buf2"], tab2 = ["buf3"]}
source([[
function CollectBuffersPerTab()
let buffs = {}
diff --git a/test/functional/plugin/lsp/codelens_spec.lua b/test/functional/plugin/lsp/codelens_spec.lua
index cd20e95dd1..20ef1cb49e 100644
--- a/test/functional/plugin/lsp/codelens_spec.lua
+++ b/test/functional/plugin/lsp/codelens_spec.lua
@@ -13,36 +13,34 @@ describe('vim.lsp.codelens', function()
it('on_codelens_stores_and_displays_lenses', function()
local fake_uri = 'file:///fake/uri'
- local bufnr = exec_lua(
- [[
- fake_uri = ...
+ local bufnr = exec_lua(function()
local bufnr = vim.uri_to_bufnr(fake_uri)
- local lines = {'So', 'many', 'lines'}
+ local lines = { 'So', 'many', 'lines' }
vim.fn.bufload(bufnr)
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines)
return bufnr
- ]],
- fake_uri
- )
+ end)
- exec_lua(
- [[
- local bufnr = ...
+ exec_lua(function()
local lenses = {
{
range = {
- start = { line = 0, character = 0, },
- ['end'] = { line = 0, character = 0 }
+ start = { line = 0, character = 0 },
+ ['end'] = { line = 0, character = 0 },
},
- command = { title = 'Lens1', command = 'Dummy' }
+ command = { title = 'Lens1', command = 'Dummy' },
},
}
- vim.lsp.codelens.on_codelens(nil, lenses, {method='textDocument/codeLens', client_id=1, bufnr=bufnr})
- ]],
- bufnr
- )
+ vim.lsp.codelens.on_codelens(
+ nil,
+ lenses,
+ { method = 'textDocument/codeLens', client_id = 1, bufnr = bufnr }
+ )
+ end)
- local stored_lenses = exec_lua('return vim.lsp.codelens.get(...)', bufnr)
+ local stored_lenses = exec_lua(function()
+ return vim.lsp.codelens.get(bufnr)
+ end)
local expected = {
{
range = {
@@ -57,58 +55,54 @@ describe('vim.lsp.codelens', function()
}
eq(expected, stored_lenses)
- local virtual_text_chunks = exec_lua(
- [[
- local bufnr = ...
+ local virtual_text_chunks = exec_lua(function()
local ns = vim.lsp.codelens.__namespaces[1]
local extmarks = vim.api.nvim_buf_get_extmarks(bufnr, ns, 0, -1, {})
return vim.api.nvim_buf_get_extmark_by_id(bufnr, ns, extmarks[1][1], { details = true })[3].virt_text
- ]],
- bufnr
- )
+ end)
eq({ [1] = { 'Lens1', 'LspCodeLens' } }, virtual_text_chunks)
end)
it('can clear all lens', function()
local fake_uri = 'file:///fake/uri'
- local bufnr = exec_lua(
- [[
- fake_uri = ...
+ local bufnr = exec_lua(function()
local bufnr = vim.uri_to_bufnr(fake_uri)
- local lines = {'So', 'many', 'lines'}
+ local lines = { 'So', 'many', 'lines' }
vim.fn.bufload(bufnr)
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines)
return bufnr
- ]],
- fake_uri
- )
+ end)
- exec_lua(
- [[
- local bufnr = ...
+ exec_lua(function()
local lenses = {
{
range = {
- start = { line = 0, character = 0, },
- ['end'] = { line = 0, character = 0 }
+ start = { line = 0, character = 0 },
+ ['end'] = { line = 0, character = 0 },
},
- command = { title = 'Lens1', command = 'Dummy' }
+ command = { title = 'Lens1', command = 'Dummy' },
},
}
- vim.lsp.codelens.on_codelens(nil, lenses, {method='textDocument/codeLens', client_id=1, bufnr=bufnr})
- ]],
- bufnr
- )
+ vim.lsp.codelens.on_codelens(
+ nil,
+ lenses,
+ { method = 'textDocument/codeLens', client_id = 1, bufnr = bufnr }
+ )
+ end)
- local stored_lenses = exec_lua('return vim.lsp.codelens.get(...)', bufnr)
+ local stored_lenses = exec_lua(function()
+ return vim.lsp.codelens.get(bufnr)
+ end)
eq(1, #stored_lenses)
- exec_lua([[
+ exec_lua(function()
vim.lsp.codelens.clear()
- ]])
+ end)
- stored_lenses = exec_lua('return vim.lsp.codelens.get(...)', bufnr)
+ stored_lenses = exec_lua(function()
+ return vim.lsp.codelens.get(bufnr)
+ end)
eq(0, #stored_lenses)
end)
end)
diff --git a/test/functional/plugin/lsp/completion_spec.lua b/test/functional/plugin/lsp/completion_spec.lua
index 2798d57381..4df8d77d44 100644
--- a/test/functional/plugin/lsp/completion_spec.lua
+++ b/test/functional/plugin/lsp/completion_spec.lua
@@ -1,9 +1,16 @@
---@diagnostic disable: no-unknown
local t = require('test.testutil')
+local t_lsp = require('test.functional.plugin.lsp.testutil')
local n = require('test.functional.testnvim')()
+local clear = n.clear
local eq = t.eq
+local neq = t.neq
local exec_lua = n.exec_lua
+local feed = n.feed
+local retry = t.retry
+
+local create_server_definition = t_lsp.create_server_definition
--- Convert completion results.
---
@@ -11,38 +18,32 @@ local exec_lua = n.exec_lua
---@param candidates lsp.CompletionList|lsp.CompletionItem[]
---@param lnum? integer 0-based, defaults to 0
---@return {items: table[], server_start_boundary: integer?}
-local function complete(line, candidates, lnum)
+local function complete(line, candidates, lnum, server_boundary)
lnum = lnum or 0
-- nvim_win_get_cursor returns 0 based column, line:find returns 1 based
local cursor_col = line:find('|') - 1
line = line:gsub('|', '')
- return exec_lua(
- [[
- local line, cursor_col, lnum, result = ...
+ return exec_lua(function(result)
local line_to_cursor = line:sub(1, cursor_col)
local client_start_boundary = vim.fn.match(line_to_cursor, '\\k*$')
- local items, server_start_boundary = require("vim.lsp._completion")._convert_results(
+ local items, new_server_boundary = require('vim.lsp.completion')._convert_results(
line,
lnum,
cursor_col,
+ 1,
client_start_boundary,
- nil,
+ server_boundary,
result,
- "utf-16"
+ 'utf-16'
)
return {
items = items,
- server_start_boundary = server_start_boundary
+ server_start_boundary = new_server_boundary,
}
- ]],
- line,
- cursor_col,
- lnum,
- candidates
- )
+ end, candidates)
end
-describe('vim.lsp._completion', function()
+describe('vim.lsp.completion: item conversion', function()
before_each(n.clear)
-- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
@@ -70,39 +71,24 @@ describe('vim.lsp._completion', function()
textEdit = { newText = 'foobar', range = range0 },
},
{ label = 'foocar', sortText = 'f', textEdit = { newText = 'foobar', range = range0 } },
- -- real-world snippet text
+ -- plain text
{
label = 'foocar',
sortText = 'g',
- insertText = 'foodar',
+ insertText = 'foodar(${1:var1})',
+ insertTextFormat = 1,
+ },
+ {
+ label = '•INT16_C(c)',
+ insertText = 'INT16_C(${1:c})',
insertTextFormat = 2,
+ filterText = 'INT16_C',
+ sortText = 'h',
textEdit = {
- newText = 'foobar(${1:place holder}, ${2:more ...holder{\\}})',
+ newText = 'INT16_C(${1:c})',
range = range0,
},
},
- {
- label = 'foocar',
- sortText = 'h',
- insertText = 'foodar(${1:var1} typ1, ${2:var2} *typ2) {$0\\}',
- insertTextFormat = 2,
- },
- -- nested snippet tokens
- {
- label = 'foocar',
- sortText = 'i',
- insertText = 'foodar(${1:${2|typ1,typ2|}}) {$0\\}',
- insertTextFormat = 2,
- },
- -- braced tabstop
- { label = 'foocar', sortText = 'j', insertText = 'foodar()${0}', insertTextFormat = 2 },
- -- plain text
- {
- label = 'foocar',
- sortText = 'k',
- insertText = 'foodar(${1:var1})',
- insertTextFormat = 1,
- },
}
local expected = {
{
@@ -131,23 +117,167 @@ describe('vim.lsp._completion', function()
},
{
abbr = 'foocar',
- word = 'foobar(place holder, more ...holder{})',
+ word = 'foodar(${1:var1})', -- marked as PlainText, text is used as is
},
{
- abbr = 'foocar',
- word = 'foodar(var1 typ1, var2 *typ2) {}',
+ abbr = '•INT16_C(c)',
+ word = 'INT16_C',
},
+ }
+ local result = complete('|', completion_list)
+ result = vim.tbl_map(function(x)
+ return {
+ abbr = x.abbr,
+ word = x.word,
+ }
+ end, result.items)
+ eq(expected, result)
+ end)
+
+ it('filters on label if filterText is missing', function()
+ local completion_list = {
+ { label = 'foo' },
+ { label = 'bar' },
+ }
+ local result = complete('fo|', completion_list)
+ local expected = {
{
- abbr = 'foocar',
- word = 'foodar(typ1) {}',
+ abbr = 'foo',
+ word = 'foo',
},
+ }
+ result = vim.tbl_map(function(x)
+ return {
+ abbr = x.abbr,
+ word = x.word,
+ }
+ end, result.items)
+ eq(expected, result)
+ end)
+
+ it('works on non word prefix', function()
+ local completion_list = {
+ { label = ' foo', insertText = '->foo' },
+ }
+ local result = complete('wp.|', completion_list, 0, 2)
+ local expected = {
{
- abbr = 'foocar',
- word = 'foodar()',
+ abbr = ' foo',
+ word = '->foo',
},
+ }
+ result = vim.tbl_map(function(x)
+ return {
+ abbr = x.abbr,
+ word = x.word,
+ }
+ end, result.items)
+ eq(expected, result)
+ end)
+
+ it('trims trailing newline or tab from textEdit', function()
+ local range0 = {
+ start = { line = 0, character = 0 },
+ ['end'] = { line = 0, character = 0 },
+ }
+ local items = {
{
- abbr = 'foocar',
- word = 'foodar(${1:var1})',
+ detail = 'ansible.builtin',
+ filterText = 'lineinfile ansible.builtin.lineinfile builtin ansible',
+ kind = 7,
+ label = 'ansible.builtin.lineinfile',
+ sortText = '2_ansible.builtin.lineinfile',
+ textEdit = {
+ newText = 'ansible.builtin.lineinfile:\n ',
+ range = range0,
+ },
+ },
+ }
+ local result = complete('|', items)
+ result = vim.tbl_map(function(x)
+ return {
+ abbr = x.abbr,
+ word = x.word,
+ }
+ end, result.items)
+
+ local expected = {
+ {
+ abbr = 'ansible.builtin.lineinfile',
+ word = 'ansible.builtin.lineinfile:',
+ },
+ }
+ eq(expected, result)
+ end)
+
+ it('prefers wordlike components for snippets', function()
+ -- There are two goals here:
+ --
+ -- 1. The `word` should match what the user started typing, so that vim.fn.complete() doesn't
+ -- filter it away, preventing snippet expansion
+ --
+ -- For example, if they type `items@ins`, luals returns `table.insert(items, $0)` as
+ -- textEdit.newText and `insert` as label.
+ -- There would be no prefix match if textEdit.newText is used as `word`
+ --
+ -- 2. If users do not expand a snippet, but continue typing, they should see a somewhat reasonable
+ -- `word` getting inserted.
+ --
+ -- For example in:
+ --
+ -- insertText: "testSuites ${1:Env}"
+ -- label: "testSuites"
+ --
+ -- "testSuites" should have priority as `word`, as long as the full snippet gets expanded on accept (<c-y>)
+ local range0 = {
+ start = { line = 0, character = 0 },
+ ['end'] = { line = 0, character = 0 },
+ }
+ local completion_list = {
+ -- luals postfix snippet (typed text: items@ins|)
+ {
+ label = 'insert',
+ insertTextFormat = 2,
+ textEdit = {
+ newText = 'table.insert(items, $0)',
+ range = range0,
+ },
+ },
+
+ -- eclipse.jdt.ls `new` snippet
+ {
+ label = 'new',
+ insertTextFormat = 2,
+ textEdit = {
+ newText = '${1:Object} ${2:foo} = new ${1}(${3});\n${0}',
+ range = range0,
+ },
+ textEditText = '${1:Object} ${2:foo} = new ${1}(${3});\n${0}',
+ },
+
+ -- eclipse.jdt.ls `List.copyO` function call completion
+ {
+ label = 'copyOf(Collection<? extends E> coll) : List<E>',
+ insertTextFormat = 2,
+ insertText = 'copyOf',
+ textEdit = {
+ newText = 'copyOf(${1:coll})',
+ range = range0,
+ },
+ },
+ }
+ local expected = {
+ {
+ abbr = 'copyOf(Collection<? extends E> coll) : List<E>',
+ word = 'copyOf',
+ },
+ {
+ abbr = 'insert',
+ word = 'insert',
+ },
+ {
+ abbr = 'new',
+ word = 'new',
},
}
local result = complete('|', completion_list)
@@ -159,6 +289,7 @@ describe('vim.lsp._completion', function()
end, result.items)
eq(expected, result)
end)
+
it('uses correct start boundary', function()
local completion_list = {
isIncomplete = false,
@@ -186,8 +317,10 @@ describe('vim.lsp._completion', function()
dup = 1,
empty = 1,
icase = 1,
+ info = '',
kind = 'Module',
menu = '',
+ hl_group = '',
word = 'this_thread',
}
local result = complete(' std::this|', completion_list)
@@ -218,7 +351,7 @@ describe('vim.lsp._completion', function()
},
},
{
- filterText = 'notthis_thread',
+ filterText = 'no_match',
insertText = 'notthis_thread',
insertTextFormat = 1,
kind = 9,
@@ -240,8 +373,10 @@ describe('vim.lsp._completion', function()
dup = 1,
empty = 1,
icase = 1,
+ info = '',
kind = 'Module',
menu = '',
+ hl_group = '',
word = 'this_thread',
}
local result = complete(' std::this|is', completion_list)
@@ -278,4 +413,316 @@ describe('vim.lsp._completion', function()
eq('item-property-has-priority', item.data)
eq({ line = 1, character = 1 }, item.textEdit.range.start)
end)
+
+ it(
+ 'uses insertText as textEdit.newText if there are editRange defaults but no textEditText',
+ function()
+ --- @type lsp.CompletionList
+ local completion_list = {
+ isIncomplete = false,
+ itemDefaults = {
+ editRange = {
+ start = { line = 1, character = 1 },
+ ['end'] = { line = 1, character = 4 },
+ },
+ insertTextFormat = 2,
+ data = 'foobar',
+ },
+ items = {
+ {
+ insertText = 'the-insertText',
+ label = 'hello',
+ data = 'item-property-has-priority',
+ },
+ },
+ }
+ local result = complete('|', completion_list)
+ eq(1, #result.items)
+ local text = result.items[1].user_data.nvim.lsp.completion_item.textEdit.newText
+ eq('the-insertText', text)
+ end
+ )
+
+ it(
+ 'defaults to label as textEdit.newText if insertText or textEditText are not present',
+ function()
+ local completion_list = {
+ isIncomplete = false,
+ itemDefaults = {
+ editRange = {
+ start = { line = 1, character = 1 },
+ ['end'] = { line = 1, character = 4 },
+ },
+ insertTextFormat = 2,
+ data = 'foobar',
+ },
+ items = {
+ {
+ label = 'hello',
+ data = 'item-property-has-priority',
+ },
+ },
+ }
+ local result = complete('|', completion_list)
+ eq(1, #result.items)
+ local text = result.items[1].user_data.nvim.lsp.completion_item.textEdit.newText
+ eq('hello', text)
+ end
+ )
+end)
+
+describe('vim.lsp.completion: protocol', function()
+ before_each(function()
+ clear()
+ exec_lua(create_server_definition)
+ exec_lua(function()
+ _G.capture = {}
+ --- @diagnostic disable-next-line:duplicate-set-field
+ vim.fn.complete = function(col, matches)
+ _G.capture.col = col
+ _G.capture.matches = matches
+ end
+ end)
+ end)
+
+ after_each(clear)
+
+ --- @param completion_result lsp.CompletionList
+ --- @return integer
+ local function create_server(completion_result)
+ return exec_lua(function()
+ local server = _G._create_server({
+ capabilities = {
+ completionProvider = {
+ triggerCharacters = { '.' },
+ },
+ },
+ handlers = {
+ ['textDocument/completion'] = function(_, _, callback)
+ callback(nil, completion_result)
+ end,
+ },
+ })
+
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.api.nvim_win_set_buf(0, bufnr)
+ return vim.lsp.start({
+ name = 'dummy',
+ cmd = server.cmd,
+ on_attach = function(client, bufnr0)
+ vim.lsp.completion.enable(true, client.id, bufnr0, {
+ convert = function(item)
+ return { abbr = item.label:gsub('%b()', '') }
+ end,
+ })
+ end,
+ })
+ end)
+ end
+
+ local function assert_matches(fn)
+ retry(nil, nil, function()
+ fn(exec_lua('return _G.capture.matches'))
+ end)
+ end
+
+ --- @param pos [integer, integer]
+ local function trigger_at_pos(pos)
+ exec_lua(function()
+ local win = vim.api.nvim_get_current_win()
+ vim.api.nvim_win_set_cursor(win, pos)
+ vim.lsp.completion.trigger()
+ end)
+
+ retry(nil, nil, function()
+ neq(nil, exec_lua('return _G.capture.col'))
+ end)
+ end
+
+ it('fetches completions and shows them using complete on trigger', function()
+ create_server({
+ isIncomplete = false,
+ items = {
+ {
+ label = 'hello',
+ },
+ {
+ label = 'hercules',
+ tags = { 1 }, -- 1 represents Deprecated tag
+ },
+ {
+ label = 'hero',
+ deprecated = true,
+ },
+ },
+ })
+
+ feed('ih')
+ trigger_at_pos({ 1, 1 })
+
+ assert_matches(function(matches)
+ eq({
+ {
+ abbr = 'hello',
+ dup = 1,
+ empty = 1,
+ icase = 1,
+ info = '',
+ kind = 'Unknown',
+ menu = '',
+ hl_group = '',
+ user_data = {
+ nvim = {
+ lsp = {
+ client_id = 1,
+ completion_item = {
+ label = 'hello',
+ },
+ },
+ },
+ },
+ word = 'hello',
+ },
+ {
+ abbr = 'hercules',
+ dup = 1,
+ empty = 1,
+ icase = 1,
+ info = '',
+ kind = 'Unknown',
+ menu = '',
+ hl_group = 'DiagnosticDeprecated',
+ user_data = {
+ nvim = {
+ lsp = {
+ client_id = 1,
+ completion_item = {
+ label = 'hercules',
+ tags = { 1 },
+ },
+ },
+ },
+ },
+ word = 'hercules',
+ },
+ {
+ abbr = 'hero',
+ dup = 1,
+ empty = 1,
+ icase = 1,
+ info = '',
+ kind = 'Unknown',
+ menu = '',
+ hl_group = 'DiagnosticDeprecated',
+ user_data = {
+ nvim = {
+ lsp = {
+ client_id = 1,
+ completion_item = {
+ label = 'hero',
+ deprecated = true,
+ },
+ },
+ },
+ },
+ word = 'hero',
+ },
+ }, matches)
+ end)
+ end)
+
+ it('merges results from multiple clients', function()
+ create_server({
+ isIncomplete = false,
+ items = {
+ {
+ label = 'hello',
+ },
+ },
+ })
+ create_server({
+ isIncomplete = false,
+ items = {
+ {
+ label = 'hallo',
+ },
+ },
+ })
+
+ feed('ih')
+ trigger_at_pos({ 1, 1 })
+
+ assert_matches(function(matches)
+ eq(2, #matches)
+ eq('hello', matches[1].word)
+ eq('hallo', matches[2].word)
+ end)
+ end)
+
+ it('executes commands', function()
+ local completion_list = {
+ isIncomplete = false,
+ items = {
+ {
+ label = 'hello',
+ command = {
+ arguments = { '1', '0' },
+ command = 'dummy',
+ title = '',
+ },
+ },
+ },
+ }
+ local client_id = create_server(completion_list)
+
+ exec_lua(function()
+ _G.called = false
+ local client = assert(vim.lsp.get_client_by_id(client_id))
+ client.commands.dummy = function()
+ _G.called = true
+ end
+ end)
+
+ feed('ih')
+ trigger_at_pos({ 1, 1 })
+
+ local item = completion_list.items[1]
+ exec_lua(function()
+ vim.v.completed_item = {
+ user_data = {
+ nvim = {
+ lsp = {
+ client_id = client_id,
+ completion_item = item,
+ },
+ },
+ },
+ }
+ end)
+
+ feed('<C-x><C-o><C-y>')
+
+ assert_matches(function(matches)
+ eq(1, #matches)
+ eq('hello', matches[1].word)
+ eq(true, exec_lua('return _G.called'))
+ end)
+ end)
+
+ it('enable(…,{convert=fn}) custom word/abbr format', function()
+ create_server({
+ isIncomplete = false,
+ items = {
+ {
+ label = 'foo(bar)',
+ },
+ },
+ })
+
+ feed('ifo')
+ trigger_at_pos({ 1, 1 })
+ assert_matches(function(matches)
+ eq('foo', matches[1].abbr)
+ end)
+ end)
end)
diff --git a/test/functional/plugin/lsp/diagnostic_spec.lua b/test/functional/plugin/lsp/diagnostic_spec.lua
index c5e14ffdc2..78c684083b 100644
--- a/test/functional/plugin/lsp/diagnostic_spec.lua
+++ b/test/functional/plugin/lsp/diagnostic_spec.lua
@@ -11,7 +11,9 @@ local neq = t.neq
local create_server_definition = t_lsp.create_server_definition
describe('vim.lsp.diagnostic', function()
- local fake_uri
+ local fake_uri --- @type string
+ local client_id --- @type integer
+ local diagnostic_bufnr --- @type integer
before_each(function()
clear { env = {
@@ -19,198 +21,174 @@ describe('vim.lsp.diagnostic', function()
VIMRUNTIME = os.getenv 'VIMRUNTIME',
} }
- exec_lua [[
+ exec_lua(function()
require('vim.lsp')
- make_range = function(x1, y1, x2, y2)
+ _G.make_range = function(x1, y1, x2, y2)
return { start = { line = x1, character = y1 }, ['end'] = { line = x2, character = y2 } }
end
- make_error = function(msg, x1, y1, x2, y2)
+ _G.make_error = function(msg, x1, y1, x2, y2)
return {
- range = make_range(x1, y1, x2, y2),
+ range = _G.make_range(x1, y1, x2, y2),
message = msg,
severity = 1,
}
end
- make_warning = function(msg, x1, y1, x2, y2)
+ _G.make_warning = function(msg, x1, y1, x2, y2)
return {
- range = make_range(x1, y1, x2, y2),
+ range = _G.make_range(x1, y1, x2, y2),
message = msg,
severity = 2,
}
end
- make_information = function(msg, x1, y1, x2, y2)
+ _G.make_information = function(msg, x1, y1, x2, y2)
return {
- range = make_range(x1, y1, x2, y2),
+ range = _G.make_range(x1, y1, x2, y2),
message = msg,
severity = 3,
}
end
- function get_extmarks(bufnr, client_id)
- local namespace = vim.lsp.diagnostic.get_namespace(client_id)
+ function _G.get_extmarks(bufnr, client_id0)
+ local namespace = vim.lsp.diagnostic.get_namespace(client_id0)
local ns = vim.diagnostic.get_namespace(namespace)
local extmarks = {}
if ns.user_data.virt_text_ns then
- for _, e in pairs(vim.api.nvim_buf_get_extmarks(bufnr, ns.user_data.virt_text_ns, 0, -1, {details=true})) do
+ for _, e in
+ pairs(
+ vim.api.nvim_buf_get_extmarks(
+ bufnr,
+ ns.user_data.virt_text_ns,
+ 0,
+ -1,
+ { details = true }
+ )
+ )
+ do
table.insert(extmarks, e)
end
end
if ns.user_data.underline_ns then
- for _, e in pairs(vim.api.nvim_buf_get_extmarks(bufnr, ns.user_data.underline_ns, 0, -1, {details=true})) do
+ for _, e in
+ pairs(
+ vim.api.nvim_buf_get_extmarks(
+ bufnr,
+ ns.user_data.underline_ns,
+ 0,
+ -1,
+ { details = true }
+ )
+ )
+ do
table.insert(extmarks, e)
end
end
return extmarks
end
- client_id = vim.lsp.start_client {
+ client_id = assert(vim.lsp.start_client {
cmd_env = {
- NVIM_LUA_NOTRACK = "1";
- };
+ NVIM_LUA_NOTRACK = '1',
+ },
cmd = {
- vim.v.progpath, '-es', '-u', 'NONE', '--headless'
- };
- offset_encoding = "utf-16";
- }
- ]]
+ vim.v.progpath,
+ '-es',
+ '-u',
+ 'NONE',
+ '--headless',
+ },
+ offset_encoding = 'utf-16',
+ })
+ end)
fake_uri = 'file:///fake/uri'
- exec_lua(
- [[
- fake_uri = ...
+ exec_lua(function()
diagnostic_bufnr = vim.uri_to_bufnr(fake_uri)
- local lines = {"1st line of text", "2nd line of text", "wow", "cool", "more", "lines"}
+ local lines = { '1st line of text', '2nd line of text', 'wow', 'cool', 'more', 'lines' }
vim.fn.bufload(diagnostic_bufnr)
vim.api.nvim_buf_set_lines(diagnostic_bufnr, 0, 1, false, lines)
vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
- return diagnostic_bufnr
- ]],
- fake_uri
- )
+ end)
end)
after_each(function()
clear()
end)
- describe('vim.lsp.diagnostic', function()
- it('maintains LSP information when translating diagnostics', function()
- local result = exec_lua [[
- local diagnostics = {
- make_error("Error 1", 1, 1, 1, 5),
- }
-
- diagnostics[1].code = 42
- diagnostics[1].data = "Hello world"
-
- vim.lsp.diagnostic.on_publish_diagnostics(nil, {
- uri = fake_uri,
- diagnostics = diagnostics,
- }, {client_id=client_id})
-
- return {
- vim.diagnostic.get(diagnostic_bufnr, {lnum=1})[1],
- vim.lsp.diagnostic.get_line_diagnostics(diagnostic_bufnr, 1)[1],
- }
- ]]
- eq({ code = 42, data = 'Hello world' }, result[1].user_data.lsp)
- eq(42, result[1].code)
- eq(42, result[2].code)
- eq('Hello world', result[2].data)
- end)
- end)
-
describe('vim.lsp.diagnostic.on_publish_diagnostics', function()
it('allows configuring the virtual text via vim.lsp.with', function()
local expected_spacing = 10
- local extmarks = exec_lua(
- [[
- PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
+ local extmarks = exec_lua(function()
+ _G.PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
virtual_text = {
- spacing = ...,
+ spacing = expected_spacing,
},
})
- PublishDiagnostics(nil, {
- uri = fake_uri,
- diagnostics = {
- make_error('Delayed Diagnostic', 4, 4, 4, 4),
- }
- }, {client_id=client_id}
- )
+ _G.PublishDiagnostics(nil, {
+ uri = fake_uri,
+ diagnostics = {
+ _G.make_error('Delayed Diagnostic', 4, 4, 4, 4),
+ },
+ }, { client_id = client_id })
- return get_extmarks(diagnostic_bufnr, client_id)
- ]],
- expected_spacing
- )
+ return _G.get_extmarks(diagnostic_bufnr, client_id)
+ end)
- local virt_text = extmarks[1][4].virt_text
- local spacing = virt_text[1][1]
+ local spacing = extmarks[1][4].virt_text[1][1]
eq(expected_spacing, #spacing)
end)
it('allows configuring the virtual text via vim.lsp.with using a function', function()
local expected_spacing = 10
- local extmarks = exec_lua(
- [[
- spacing = ...
-
- PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
+ local extmarks = exec_lua(function()
+ _G.PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
virtual_text = function()
return {
- spacing = spacing,
+ spacing = expected_spacing,
}
end,
})
- PublishDiagnostics(nil, {
- uri = fake_uri,
- diagnostics = {
- make_error('Delayed Diagnostic', 4, 4, 4, 4),
- }
- }, {client_id=client_id}
- )
+ _G.PublishDiagnostics(nil, {
+ uri = fake_uri,
+ diagnostics = {
+ _G.make_error('Delayed Diagnostic', 4, 4, 4, 4),
+ },
+ }, { client_id = client_id })
- return get_extmarks(diagnostic_bufnr, client_id)
- ]],
- expected_spacing
- )
+ return _G.get_extmarks(diagnostic_bufnr, client_id)
+ end)
- local virt_text = extmarks[1][4].virt_text
- local spacing = virt_text[1][1]
+ local spacing = extmarks[1][4].virt_text[1][1]
eq(expected_spacing, #spacing)
end)
it('allows filtering via severity limit', function()
local get_extmark_count_with_severity = function(severity_limit)
- return exec_lua(
- [[
- PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
+ return exec_lua(function()
+ _G.PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
underline = false,
virtual_text = {
- severity = { min = ... }
+ severity = { min = severity_limit },
},
})
- PublishDiagnostics(nil, {
- uri = fake_uri,
- diagnostics = {
- make_warning('Delayed Diagnostic', 4, 4, 4, 4),
- }
- }, {client_id=client_id}
- )
-
- return #get_extmarks(diagnostic_bufnr, client_id)
- ]],
- severity_limit
- )
+ _G.PublishDiagnostics(nil, {
+ uri = fake_uri,
+ diagnostics = {
+ _G.make_warning('Delayed Diagnostic', 4, 4, 4, 4),
+ },
+ }, { client_id = client_id })
+
+ return #_G.get_extmarks(diagnostic_bufnr, client_id)
+ end, client_id, fake_uri, severity_limit)
end
-- No messages with Error or higher
@@ -223,218 +201,284 @@ describe('vim.lsp.diagnostic', function()
it('correctly handles UTF-16 offsets', function()
local line = 'All 💼 and no 🎉 makes Jack a dull 👦'
- local result = exec_lua(
- [[
- local line = ...
- vim.api.nvim_buf_set_lines(diagnostic_bufnr, 0, -1, false, {line})
+ local result = exec_lua(function()
+ vim.api.nvim_buf_set_lines(diagnostic_bufnr, 0, -1, false, { line })
vim.lsp.diagnostic.on_publish_diagnostics(nil, {
- uri = fake_uri,
- diagnostics = {
- make_error('UTF-16 Diagnostic', 0, 7, 0, 8),
- }
- }, {client_id=client_id}
- )
+ uri = fake_uri,
+ diagnostics = {
+ _G.make_error('UTF-16 Diagnostic', 0, 7, 0, 8),
+ },
+ }, { client_id = client_id })
local diags = vim.diagnostic.get(diagnostic_bufnr)
vim.lsp.stop_client(client_id)
vim.api.nvim_exec_autocmds('VimLeavePre', { modeline = false })
return diags
- ]],
- line
- )
+ end)
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)
+ eq(
+ exec_lua(function()
+ return vim.str_byteindex(line, 7, true)
+ end),
+ result[1].col
+ )
+ eq(
+ exec_lua(function()
+ return vim.str_byteindex(line, 8, true)
+ end),
+ 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(-1, bufnr)
+ eq(
+ -1,
+ exec_lua(function()
+ 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'))
+ end)
+ )
-- 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(-1, bufnr)
- eq(1, exec_lua([[return #vim.diagnostic.get(...)]], bufnr))
+ neq(
+ -1,
+ exec_lua(function()
+ vim.lsp.diagnostic.on_publish_diagnostics(nil, {
+ uri = 'file:///fake/uri2',
+ diagnostics = {
+ _G.make_error('Diagnostic', 0, 0, 0, 0),
+ },
+ }, { client_id = client_id })
+ return vim.fn.bufnr(vim.uri_to_fname('file:///fake/uri2'))
+ end)
+ )
+ eq(
+ 1,
+ exec_lua(function()
+ return #vim.diagnostic.get(_G.bufnr)
+ end)
+ )
-- 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(-1, bufnr)
- eq(0, exec_lua([[return #vim.diagnostic.get(...)]], bufnr))
+ neq(
+ -1,
+ exec_lua(function()
+ 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'))
+ end)
+ )
+ eq(
+ 0,
+ exec_lua(function()
+ return #vim.diagnostic.get(_G.bufnr)
+ end)
+ )
end)
end)
describe('vim.lsp.diagnostic.on_diagnostic', function()
before_each(function()
exec_lua(create_server_definition)
- exec_lua([[
- server = _create_server({
+ exec_lua(function()
+ _G.server = _G._create_server({
capabilities = {
- diagnosticProvider = {
- }
- }
+ diagnosticProvider = {},
+ },
})
- function get_extmarks(bufnr, client_id)
- local namespace = vim.lsp.diagnostic.get_namespace(client_id, true)
+ function _G.get_extmarks(bufnr, client_id0)
+ local namespace = vim.lsp.diagnostic.get_namespace(client_id0, true)
local ns = vim.diagnostic.get_namespace(namespace)
local extmarks = {}
if ns.user_data.virt_text_ns then
- for _, e in pairs(vim.api.nvim_buf_get_extmarks(bufnr, ns.user_data.virt_text_ns, 0, -1, {details=true})) do
+ for _, e in
+ pairs(
+ vim.api.nvim_buf_get_extmarks(
+ bufnr,
+ ns.user_data.virt_text_ns,
+ 0,
+ -1,
+ { details = true }
+ )
+ )
+ do
table.insert(extmarks, e)
end
end
if ns.user_data.underline_ns then
- for _, e in pairs(vim.api.nvim_buf_get_extmarks(bufnr, ns.user_data.underline_ns, 0, -1, {details=true})) do
+ for _, e in
+ pairs(
+ vim.api.nvim_buf_get_extmarks(
+ bufnr,
+ ns.user_data.underline_ns,
+ 0,
+ -1,
+ { details = true }
+ )
+ )
+ do
table.insert(extmarks, e)
end
end
return extmarks
end
- client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
- ]])
+ client_id = vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
+ end)
end)
it('adds diagnostics to vim.diagnostics', function()
- local diags = exec_lua([[
- vim.lsp.diagnostic.on_diagnostic(nil,
- {
- kind = 'full',
- items = {
- make_error('Pull Diagnostic', 4, 4, 4, 4),
- }
+ local diags = exec_lua(function()
+ vim.lsp.diagnostic.on_diagnostic(nil, {
+ kind = 'full',
+ items = {
+ _G.make_error('Pull Diagnostic', 4, 4, 4, 4),
},
- {
- params = {
- textDocument = { uri = fake_uri },
- },
- uri = fake_uri,
- client_id = client_id,
+ }, {
+ params = {
+ textDocument = { uri = fake_uri },
},
- {}
- )
+ uri = fake_uri,
+ client_id = client_id,
+ }, {})
return vim.diagnostic.get(diagnostic_bufnr)
- ]])
+ end)
eq(1, #diags)
eq('Pull Diagnostic', diags[1].message)
end)
+ it('severity defaults to error if missing', function()
+ ---@type vim.Diagnostic[]
+ local diagnostics = exec_lua(function()
+ vim.lsp.diagnostic.on_diagnostic(nil, {
+ kind = 'full',
+ items = {
+ {
+ range = _G.make_range(4, 4, 4, 4),
+ message = 'bad!',
+ },
+ },
+ }, {
+ params = {
+ textDocument = { uri = fake_uri },
+ },
+ uri = fake_uri,
+ client_id = client_id,
+ }, {})
+ return vim.diagnostic.get(diagnostic_bufnr)
+ end)
+ eq(1, #diagnostics)
+ eq(1, diagnostics[1].severity)
+ end)
+
it('allows configuring the virtual text via vim.lsp.with', function()
local expected_spacing = 10
- local extmarks = exec_lua(
- [[
- Diagnostic = vim.lsp.with(vim.lsp.diagnostic.on_diagnostic, {
+ local extmarks = exec_lua(function()
+ _G.Diagnostic = vim.lsp.with(vim.lsp.diagnostic.on_diagnostic, {
virtual_text = {
- spacing = ...,
+ spacing = expected_spacing,
},
})
- Diagnostic(nil,
- {
- kind = 'full',
- items = {
- make_error('Pull Diagnostic', 4, 4, 4, 4),
- }
+ _G.Diagnostic(nil, {
+ kind = 'full',
+ items = {
+ _G.make_error('Pull Diagnostic', 4, 4, 4, 4),
},
- {
- params = {
- textDocument = { uri = fake_uri },
- },
- uri = fake_uri,
- client_id = client_id,
+ }, {
+ params = {
+ textDocument = { uri = fake_uri },
},
- {}
- )
+ uri = fake_uri,
+ client_id = client_id,
+ }, {})
- return get_extmarks(diagnostic_bufnr, client_id)
- ]],
- expected_spacing
- )
+ return _G.get_extmarks(diagnostic_bufnr, client_id)
+ end)
eq(2, #extmarks)
eq(expected_spacing, #extmarks[1][4].virt_text[1][1])
end)
it('clears diagnostics when client detaches', function()
- exec_lua([[
- vim.lsp.diagnostic.on_diagnostic(nil,
- {
- kind = 'full',
- items = {
- make_error('Pull Diagnostic', 4, 4, 4, 4),
- }
+ exec_lua(function()
+ vim.lsp.diagnostic.on_diagnostic(nil, {
+ kind = 'full',
+ items = {
+ _G.make_error('Pull Diagnostic', 4, 4, 4, 4),
},
- {
- params = {
- textDocument = { uri = fake_uri },
- },
- uri = fake_uri,
- client_id = client_id,
+ }, {
+ params = {
+ textDocument = { uri = fake_uri },
},
- {}
- )
- ]])
- local diags = exec_lua([[return vim.diagnostic.get(diagnostic_bufnr)]])
- eq(1, #diags)
+ uri = fake_uri,
+ client_id = client_id,
+ }, {})
+ end)
+
+ eq(
+ 1,
+ exec_lua(function()
+ return #vim.diagnostic.get(diagnostic_bufnr)
+ end)
+ )
- exec_lua([[ vim.lsp.stop_client(client_id) ]])
+ exec_lua(function()
+ vim.lsp.stop_client(client_id)
+ end)
- diags = exec_lua([[return vim.diagnostic.get(diagnostic_bufnr)]])
- eq(0, #diags)
+ eq(
+ 0,
+ exec_lua(function()
+ return #vim.diagnostic.get(diagnostic_bufnr)
+ end)
+ )
end)
it('keeps diagnostics when one client detaches and others still are attached', function()
- exec_lua([[
- client_id2 = vim.lsp.start({ name = 'dummy2', cmd = server.cmd })
-
- vim.lsp.diagnostic.on_diagnostic(nil,
- {
- kind = 'full',
- items = {
- make_error('Pull Diagnostic', 4, 4, 4, 4),
- }
+ local client_id2
+ exec_lua(function()
+ client_id2 = vim.lsp.start({ name = 'dummy2', cmd = _G.server.cmd })
+
+ vim.lsp.diagnostic.on_diagnostic(nil, {
+ kind = 'full',
+ items = {
+ _G.make_error('Pull Diagnostic', 4, 4, 4, 4),
},
- {
- params = {
- textDocument = { uri = fake_uri },
- },
- uri = fake_uri,
- client_id = client_id,
+ }, {
+ params = {
+ textDocument = { uri = fake_uri },
},
- {}
- )
- ]])
- local diags = exec_lua([[return vim.diagnostic.get(diagnostic_bufnr)]])
- eq(1, #diags)
+ uri = fake_uri,
+ client_id = client_id,
+ }, {})
+ end)
+
+ eq(
+ 1,
+ exec_lua(function()
+ return #vim.diagnostic.get(diagnostic_bufnr)
+ end)
+ )
- exec_lua([[ vim.lsp.stop_client(client_id2) ]])
+ exec_lua(function()
+ vim.lsp.stop_client(client_id2)
+ end)
- diags = exec_lua([[return vim.diagnostic.get(diagnostic_bufnr)]])
- eq(1, #diags)
+ eq(
+ 1,
+ exec_lua(function()
+ return #vim.diagnostic.get(diagnostic_bufnr)
+ end)
+ )
end)
end)
end)
diff --git a/test/functional/plugin/lsp/handler_spec.lua b/test/functional/plugin/lsp/handler_spec.lua
index 013a5fb5e7..4b05b676a8 100644
--- a/test/functional/plugin/lsp/handler_spec.lua
+++ b/test/functional/plugin/lsp/handler_spec.lua
@@ -11,28 +11,31 @@ describe('lsp-handlers', function()
it('should return a table with the default keys', function()
eq(
{ hello = 'world' },
- exec_lua [[
- return vim.lsp._with_extend('test', { hello = 'world' })
- ]]
+ exec_lua(function()
+ return vim.lsp._with_extend('test', { hello = 'world' })
+ end)
)
end)
it('should override with config keys', function()
eq(
{ hello = 'universe', other = true },
- exec_lua [[
- return vim.lsp._with_extend('test', { other = true, hello = 'world' }, { hello = 'universe' })
- ]]
+ exec_lua(function()
+ return vim.lsp._with_extend(
+ 'test',
+ { other = true, hello = 'world' },
+ { hello = 'universe' }
+ )
+ end)
)
end)
it('should not allow invalid keys', function()
matches(
'.*Invalid option for `test`.*',
- pcall_err(
- exec_lua,
- "return vim.lsp._with_extend('test', { hello = 'world' }, { invalid = true })"
- )
+ pcall_err(exec_lua, function()
+ return vim.lsp._with_extend('test', { hello = 'world' }, { invalid = true })
+ end)
)
end)
end)
diff --git a/test/functional/plugin/lsp/incremental_sync_spec.lua b/test/functional/plugin/lsp/incremental_sync_spec.lua
index 238b90b57d..f60e159d64 100644
--- a/test/functional/plugin/lsp/incremental_sync_spec.lua
+++ b/test/functional/plugin/lsp/incremental_sync_spec.lua
@@ -10,11 +10,9 @@ local feed = n.feed
before_each(function()
clear()
- exec_lua [[
- local evname = ...
+ exec_lua(function()
local sync = require('vim.lsp.sync')
local events = {}
- local buffer_cache = {}
-- local format_line_ending = {
-- ["unix"] = '\n',
@@ -24,35 +22,43 @@ before_each(function()
-- local line_ending = format_line_ending[vim.api.nvim_get_option_value('fileformat', {})]
-
- function test_register(bufnr, id, offset_encoding, line_ending)
- local curr_lines
+ --- @diagnostic disable-next-line:duplicate-set-field
+ function _G.test_register(bufnr, id, offset_encoding, line_ending)
local prev_lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, true)
- local function callback(_, bufnr, changedtick, firstline, lastline, new_lastline)
- if test_unreg == id then
+ local function callback(_, bufnr0, _changedtick, firstline, lastline, new_lastline)
+ if _G.test_unreg == id then
return true
end
- local curr_lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, true)
+ local curr_lines = vim.api.nvim_buf_get_lines(bufnr0, 0, -1, true)
local incremental_change = sync.compute_diff(
- prev_lines, curr_lines, firstline, lastline, new_lastline, offset_encoding, line_ending)
+ prev_lines,
+ curr_lines,
+ firstline,
+ lastline,
+ new_lastline,
+ offset_encoding,
+ line_ending
+ )
table.insert(events, incremental_change)
prev_lines = curr_lines
end
- local opts = {on_lines=callback, on_detach=callback, on_reload=callback}
+ local opts = { on_lines = callback, on_detach = callback, on_reload = callback }
vim.api.nvim_buf_attach(bufnr, false, opts)
end
- function get_events()
+ --- @diagnostic disable-next-line:duplicate-set-field
+ function _G.get_events()
local ret_events = events
events = {}
return ret_events
end
- ]]
+ end)
end)
+--- @param edit_operations string[]
local function test_edit(
prev_buffer,
edit_operations,
@@ -64,13 +70,22 @@ local function test_edit(
line_ending = line_ending or '\n'
api.nvim_buf_set_lines(0, 0, -1, true, prev_buffer)
- exec_lua('return test_register(...)', 0, 'test1', offset_encoding, line_ending)
+ exec_lua(function()
+ return _G.test_register(0, 'test1', offset_encoding, line_ending)
+ end)
for _, edit in ipairs(edit_operations) do
feed(edit)
end
- eq(expected_text_changes, exec_lua('return get_events(...)'))
- exec_lua("test_unreg = 'test1'")
+ eq(
+ expected_text_changes,
+ exec_lua(function()
+ return _G.get_events()
+ end)
+ )
+ exec_lua(function()
+ _G.test_unreg = 'test1'
+ end)
end
describe('incremental synchronization', function()
@@ -170,7 +185,7 @@ describe('incremental synchronization', function()
}
test_edit({ 'a' }, { 'rb' }, expected_text_changes, 'utf-16', '\n')
end)
- it('deleting a line', function()
+ it('deleting the first line', function()
local expected_text_changes = {
{
range = {
@@ -183,11 +198,49 @@ describe('incremental synchronization', function()
line = 1,
},
},
- rangeLength = 12,
+ rangeLength = 6,
+ text = '',
+ },
+ }
+ test_edit({ 'hello', 'world' }, { 'ggdd' }, expected_text_changes, 'utf-16', '\n')
+ end)
+ it('deleting the last line', function()
+ local expected_text_changes = {
+ {
+ range = {
+ ['start'] = {
+ character = 0,
+ line = 1,
+ },
+ ['end'] = {
+ character = 0,
+ line = 2,
+ },
+ },
+ rangeLength = 6,
+ text = '',
+ },
+ }
+ test_edit({ 'hello', 'world' }, { '2ggdd' }, expected_text_changes, 'utf-16', '\n')
+ end)
+ it('deleting all lines', function()
+ local expected_text_changes = {
+ {
+ range = {
+ ['start'] = {
+ character = 0,
+ line = 0,
+ },
+ ['end'] = {
+ character = 5,
+ line = 1,
+ },
+ },
+ rangeLength = 11,
text = '',
},
}
- test_edit({ 'hello world' }, { 'dd' }, expected_text_changes, 'utf-16', '\n')
+ test_edit({ 'hello', 'world' }, { 'ggdG' }, expected_text_changes, 'utf-16', '\n')
end)
it('deleting an empty line', function()
local expected_text_changes = {
diff --git a/test/functional/plugin/lsp/inlay_hint_spec.lua b/test/functional/plugin/lsp/inlay_hint_spec.lua
index d3b5ae0e4e..471f2cc3e8 100644
--- a/test/functional/plugin/lsp/inlay_hint_spec.lua
+++ b/test/functional/plugin/lsp/inlay_hint_spec.lua
@@ -12,7 +12,8 @@ local api = n.api
local clear_notrace = t_lsp.clear_notrace
local create_server_definition = t_lsp.create_server_definition
-local text = dedent([[
+describe('vim.lsp.inlay_hint', function()
+ local text = dedent([[
auto add(int a, int b) { return a + b; }
int main() {
@@ -22,7 +23,7 @@ int main() {
}
}]])
-local response = [==[
+ local response = [==[
[
{"kind":1,"paddingLeft":false,"label":"-> int","position":{"character":22,"line":0},"paddingRight":false},
{"kind":2,"paddingLeft":false,"label":"a:","position":{"character":15,"line":5},"paddingRight":true},
@@ -30,7 +31,7 @@ local response = [==[
]
]==]
-local grid_without_inlay_hints = [[
+ local grid_without_inlay_hints = [[
auto add(int a, int b) { return a + b; } |
|
int main() { |
@@ -42,7 +43,7 @@ local grid_without_inlay_hints = [[
|
]]
-local grid_with_inlay_hints = [[
+ local grid_with_inlay_hints = [[
auto add(int a, int b){1:-> int} { return a + b; } |
|
int main() { |
@@ -54,54 +55,58 @@ local grid_with_inlay_hints = [[
|
]]
---- @type test.functional.ui.screen
-local screen
-before_each(function()
- clear_notrace()
- screen = Screen.new(50, 9)
- screen:attach()
-
- exec_lua(create_server_definition)
- exec_lua(
- [[
- local response = ...
- server = _create_server({
- capabilities = {
- inlayHintProvider = true,
- },
- handlers = {
- ['textDocument/inlayHint'] = function(_, _, callback)
- callback(nil, vim.json.decode(response))
- end,
- }
- })
+ --- @type test.functional.ui.screen
+ local screen
- bufnr = vim.api.nvim_get_current_buf()
- vim.api.nvim_win_set_buf(0, bufnr)
+ --- @type integer
+ local client_id
- client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
- ]],
- response
- )
+ --- @type integer
+ local bufnr
- insert(text)
- exec_lua([[vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })]])
- screen:expect({ grid = grid_with_inlay_hints })
-end)
+ before_each(function()
+ clear_notrace()
+ screen = Screen.new(50, 9)
+ screen:attach()
-after_each(function()
- api.nvim_exec_autocmds('VimLeavePre', { modeline = false })
-end)
+ bufnr = n.api.nvim_get_current_buf()
+ exec_lua(create_server_definition)
+ client_id = exec_lua(function()
+ _G.server = _G._create_server({
+ capabilities = {
+ inlayHintProvider = true,
+ },
+ handlers = {
+ ['textDocument/inlayHint'] = function(_, _, callback)
+ callback(nil, vim.json.decode(response))
+ end,
+ },
+ })
+
+ return vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
+ end)
+
+ insert(text)
+ exec_lua(function()
+ vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })
+ end)
+ screen:expect({ grid = grid_with_inlay_hints })
+ end)
+
+ after_each(function()
+ api.nvim_exec_autocmds('VimLeavePre', { modeline = false })
+ end)
-describe('vim.lsp.inlay_hint', function()
it('clears inlay hints when sole client detaches', function()
- exec_lua([[vim.lsp.stop_client(client_id)]])
+ exec_lua(function()
+ vim.lsp.stop_client(client_id)
+ end)
screen:expect({ grid = grid_without_inlay_hints, unchanged = true })
end)
it('does not clear inlay hints when one of several clients detaches', function()
- exec_lua([[
- server2 = _create_server({
+ local client_id2 = exec_lua(function()
+ _G.server2 = _G._create_server({
capabilities = {
inlayHintProvider = true,
},
@@ -109,13 +114,16 @@ describe('vim.lsp.inlay_hint', function()
['textDocument/inlayHint'] = function(_, _, callback)
callback(nil, {})
end,
- }
+ },
})
- client2 = vim.lsp.start({ name = 'dummy2', cmd = server2.cmd })
+ local client_id2 = vim.lsp.start({ name = 'dummy2', cmd = _G.server2.cmd })
vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })
- ]])
+ return client_id2
+ end)
- exec_lua([[ vim.lsp.stop_client(client2) ]])
+ exec_lua(function()
+ vim.lsp.stop_client(client_id2)
+ end)
screen:expect({ grid = grid_with_inlay_hints, unchanged = true })
end)
@@ -123,61 +131,85 @@ describe('vim.lsp.inlay_hint', function()
it('validation', function()
t.matches(
'enable: expected boolean, got table',
- t.pcall_err(exec_lua, [[vim.lsp.inlay_hint.enable({}, { bufnr = bufnr })]])
+ t.pcall_err(exec_lua, function()
+ --- @diagnostic disable-next-line:param-type-mismatch
+ vim.lsp.inlay_hint.enable({}, { bufnr = bufnr })
+ end)
)
t.matches(
'enable: expected boolean, got number',
- t.pcall_err(exec_lua, [[vim.lsp.inlay_hint.enable(42)]])
+ t.pcall_err(exec_lua, function()
+ --- @diagnostic disable-next-line:param-type-mismatch
+ vim.lsp.inlay_hint.enable(42)
+ end)
)
t.matches(
'filter: expected table, got number',
- t.pcall_err(exec_lua, [[vim.lsp.inlay_hint.enable(true, 42)]])
+ t.pcall_err(exec_lua, function()
+ --- @diagnostic disable-next-line:param-type-mismatch
+ vim.lsp.inlay_hint.enable(true, 42)
+ end)
)
end)
describe('clears/applies inlay hints when passed false/true/nil', function()
+ local bufnr2 --- @type integer
before_each(function()
- exec_lua([[
- bufnr2 = vim.api.nvim_create_buf(true, false)
- vim.lsp.buf_attach_client(bufnr2, client_id)
- vim.api.nvim_win_set_buf(0, bufnr2)
- ]])
+ bufnr2 = exec_lua(function()
+ local bufnr2_0 = vim.api.nvim_create_buf(true, false)
+ vim.lsp.buf_attach_client(bufnr2_0, client_id)
+ vim.api.nvim_win_set_buf(0, bufnr2_0)
+ return bufnr2_0
+ end)
insert(text)
- exec_lua([[vim.lsp.inlay_hint.enable(true, { bufnr = bufnr2 })]])
- exec_lua([[vim.api.nvim_win_set_buf(0, bufnr)]])
+ exec_lua(function()
+ vim.lsp.inlay_hint.enable(true, { bufnr = bufnr2 })
+ end)
+ n.api.nvim_win_set_buf(0, bufnr)
screen:expect({ grid = grid_with_inlay_hints })
end)
it('for one single buffer', function()
- exec_lua([[
+ exec_lua(function()
vim.lsp.inlay_hint.enable(false, { bufnr = bufnr })
vim.api.nvim_win_set_buf(0, bufnr2)
- ]])
+ end)
screen:expect({ grid = grid_with_inlay_hints, unchanged = true })
- exec_lua([[vim.api.nvim_win_set_buf(0, bufnr)]])
+ n.api.nvim_win_set_buf(0, bufnr)
screen:expect({ grid = grid_without_inlay_hints, unchanged = true })
- exec_lua([[vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })]])
+ exec_lua(function()
+ vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })
+ end)
screen:expect({ grid = grid_with_inlay_hints, unchanged = true })
- exec_lua(
- [[vim.lsp.inlay_hint.enable(not vim.lsp.inlay_hint.is_enabled({ bufnr = bufnr }), { bufnr = bufnr })]]
- )
+ exec_lua(function()
+ vim.lsp.inlay_hint.enable(
+ not vim.lsp.inlay_hint.is_enabled({ bufnr = bufnr }),
+ { bufnr = bufnr }
+ )
+ end)
screen:expect({ grid = grid_without_inlay_hints, unchanged = true })
- exec_lua([[vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })]])
+ exec_lua(function()
+ vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })
+ end)
screen:expect({ grid = grid_with_inlay_hints, unchanged = true })
end)
it('for all buffers', function()
- exec_lua([[vim.lsp.inlay_hint.enable(false)]])
+ exec_lua(function()
+ vim.lsp.inlay_hint.enable(false)
+ end)
screen:expect({ grid = grid_without_inlay_hints, unchanged = true })
- exec_lua([[vim.api.nvim_win_set_buf(0, bufnr2)]])
+ n.api.nvim_win_set_buf(0, bufnr2)
screen:expect({ grid = grid_without_inlay_hints, unchanged = true })
- exec_lua([[vim.lsp.inlay_hint.enable(true)]])
+ exec_lua(function()
+ vim.lsp.inlay_hint.enable(true)
+ end)
screen:expect({ grid = grid_with_inlay_hints, unchanged = true })
- exec_lua([[vim.api.nvim_win_set_buf(0, bufnr)]])
+ n.api.nvim_win_set_buf(0, bufnr)
screen:expect({ grid = grid_with_inlay_hints, unchanged = true })
end)
end)
@@ -198,10 +230,8 @@ describe('vim.lsp.inlay_hint', function()
paddingRight = false,
}
- exec_lua(
- [[
- local expected2 = ...
- server2 = _create_server({
+ exec_lua(function()
+ _G.server2 = _G._create_server({
capabilities = {
inlayHintProvider = true,
},
@@ -209,52 +239,139 @@ describe('vim.lsp.inlay_hint', function()
['textDocument/inlayHint'] = function(_, _, callback)
callback(nil, { expected2 })
end,
- }
+ },
})
- client2 = vim.lsp.start({ name = 'dummy2', cmd = server2.cmd })
+ _G.client2 = vim.lsp.start({ name = 'dummy2', cmd = _G.server2.cmd })
vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })
- ]],
- expected2
- )
+ end)
--- @type vim.lsp.inlay_hint.get.ret
- local res = exec_lua([[return vim.lsp.inlay_hint.get()]])
- eq({
- { bufnr = 1, client_id = 1, inlay_hint = expected[1] },
- { bufnr = 1, client_id = 1, inlay_hint = expected[2] },
- { bufnr = 1, client_id = 1, inlay_hint = expected[3] },
- { bufnr = 1, client_id = 2, inlay_hint = expected2 },
- }, res)
+ eq(
+ {
+ { bufnr = 1, client_id = 1, inlay_hint = expected[1] },
+ { bufnr = 1, client_id = 1, inlay_hint = expected[2] },
+ { bufnr = 1, client_id = 1, inlay_hint = expected[3] },
+ { bufnr = 1, client_id = 2, inlay_hint = expected2 },
+ },
+ exec_lua(function()
+ return vim.lsp.inlay_hint.get()
+ end)
+ )
- --- @type vim.lsp.inlay_hint.get.ret
- res = exec_lua([[return vim.lsp.inlay_hint.get({
- range = {
- start = { line = 2, character = 10 },
- ["end"] = { line = 2, character = 10 },
+ eq(
+ {
+ { bufnr = 1, client_id = 2, inlay_hint = expected2 },
},
- })]])
- eq({
- { bufnr = 1, client_id = 2, inlay_hint = expected2 },
- }, res)
+ exec_lua(function()
+ return vim.lsp.inlay_hint.get({
+ range = {
+ start = { line = 2, character = 10 },
+ ['end'] = { line = 2, character = 10 },
+ },
+ })
+ end)
+ )
- --- @type vim.lsp.inlay_hint.get.ret
- res = exec_lua([[return vim.lsp.inlay_hint.get({
- bufnr = vim.api.nvim_get_current_buf(),
- range = {
- start = { line = 4, character = 18 },
- ["end"] = { line = 5, character = 17 },
+ eq(
+ {
+ { bufnr = 1, client_id = 1, inlay_hint = expected[2] },
+ { bufnr = 1, client_id = 1, inlay_hint = expected[3] },
},
- })]])
- eq({
- { bufnr = 1, client_id = 1, inlay_hint = expected[2] },
- { bufnr = 1, client_id = 1, inlay_hint = expected[3] },
- }, res)
+ exec_lua(function()
+ return vim.lsp.inlay_hint.get({
+ bufnr = vim.api.nvim_get_current_buf(),
+ range = {
+ start = { line = 4, character = 18 },
+ ['end'] = { line = 5, character = 17 },
+ },
+ })
+ end)
+ )
- --- @type vim.lsp.inlay_hint.get.ret
- res = exec_lua([[return vim.lsp.inlay_hint.get({
- bufnr = vim.api.nvim_get_current_buf() + 1,
- })]])
- eq({}, res)
+ eq(
+ {},
+ exec_lua(function()
+ return vim.lsp.inlay_hint.get({
+ bufnr = vim.api.nvim_get_current_buf() + 1,
+ })
+ end)
+ )
+ end)
+ end)
+end)
+
+describe('Inlay hints handler', function()
+ local text = dedent([[
+test text
+ ]])
+
+ local response = [==[
+ [
+ { "position": { "line": 0, "character": 0 }, "label": "0" },
+ { "position": { "line": 0, "character": 0 }, "label": "1" },
+ { "position": { "line": 0, "character": 0 }, "label": "2" },
+ { "position": { "line": 0, "character": 0 }, "label": "3" },
+ { "position": { "line": 0, "character": 0 }, "label": "4" }
+ ]
+ ]==]
+
+ local grid_without_inlay_hints = [[
+ test text |
+ ^ |
+ |
+]]
+
+ local grid_with_inlay_hints = [[
+ {1:01234}test text |
+ ^ |
+ |
+]]
+
+ --- @type test.functional.ui.screen
+ local screen
+
+ --- @type integer
+ local client_id
+
+ --- @type integer
+ local bufnr
+
+ before_each(function()
+ clear_notrace()
+ screen = Screen.new(50, 3)
+ screen:attach()
+
+ exec_lua(create_server_definition)
+ bufnr = n.api.nvim_get_current_buf()
+ client_id = exec_lua(function()
+ _G.server = _G._create_server({
+ capabilities = {
+ inlayHintProvider = true,
+ },
+ handlers = {
+ ['textDocument/inlayHint'] = function(_, _, callback)
+ callback(nil, vim.json.decode(response))
+ end,
+ },
+ })
+
+ vim.api.nvim_win_set_buf(0, bufnr)
+
+ return vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
+ end)
+ insert(text)
+ end)
+
+ it('renders hints with same position in received order', function()
+ exec_lua([[vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })]])
+ screen:expect({ grid = grid_with_inlay_hints })
+ exec_lua(function()
+ vim.lsp.stop_client(client_id)
end)
+ screen:expect({ grid = grid_without_inlay_hints, unchanged = true })
+ end)
+
+ after_each(function()
+ api.nvim_exec_autocmds('VimLeavePre', { modeline = false })
end)
end)
diff --git a/test/functional/plugin/lsp/semantic_tokens_spec.lua b/test/functional/plugin/lsp/semantic_tokens_spec.lua
index 7908c5d2e7..f72aab7e0b 100644
--- a/test/functional/plugin/lsp/semantic_tokens_spec.lua
+++ b/test/functional/plugin/lsp/semantic_tokens_spec.lua
@@ -25,7 +25,7 @@ after_each(function()
end)
describe('semantic token highlighting', function()
- local screen
+ local screen --- @type test.functional.ui.screen
before_each(function()
screen = Screen.new(40, 16)
screen:attach()
@@ -84,10 +84,8 @@ describe('semantic token highlighting', function()
before_each(function()
exec_lua(create_server_definition)
- exec_lua(
- [[
- local legend, response, edit_response = ...
- server = _create_server({
+ exec_lua(function()
+ _G.server = _G._create_server({
capabilities = {
semanticTokensProvider = {
full = { delta = true },
@@ -101,24 +99,19 @@ describe('semantic token highlighting', function()
['textDocument/semanticTokens/full/delta'] = function(_, _, callback)
callback(nil, vim.fn.json_decode(edit_response))
end,
- }
+ },
})
- ]],
- legend,
- response,
- edit_response
- )
+ end, legend, response, edit_response)
end)
it('buffer is highlighted when attached', function()
- exec_lua([[
- bufnr = vim.api.nvim_get_current_buf()
+ insert(text)
+ exec_lua(function()
+ local bufnr = vim.api.nvim_get_current_buf()
vim.api.nvim_win_set_buf(0, bufnr)
vim.bo[bufnr].filetype = 'some-filetype'
- client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
- ]])
-
- insert(text)
+ vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
+ end)
screen:expect {
grid = [[
@@ -141,23 +134,20 @@ describe('semantic token highlighting', function()
end)
it('use LspTokenUpdate and highlight_token', function()
- exec_lua([[
- vim.api.nvim_create_autocmd("LspTokenUpdate", {
+ insert(text)
+ exec_lua(function()
+ vim.api.nvim_create_autocmd('LspTokenUpdate', {
callback = function(args)
- local token = args.data.token
- if token.type == "function" and token.modifiers.declaration then
- vim.lsp.semantic_tokens.highlight_token(
- token, args.buf, args.data.client_id, "Macro"
- )
+ local token = args.data.token --- @type STTokenRange
+ if token.type == 'function' and token.modifiers.declaration then
+ vim.lsp.semantic_tokens.highlight_token(token, args.buf, args.data.client_id, 'Macro')
end
end,
})
- bufnr = vim.api.nvim_get_current_buf()
+ local bufnr = vim.api.nvim_get_current_buf()
vim.api.nvim_win_set_buf(0, bufnr)
- client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
- ]])
-
- insert(text)
+ vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
+ end)
screen:expect {
grid = [[
@@ -180,18 +170,23 @@ describe('semantic token highlighting', function()
end)
it('buffer is unhighlighted when client is detached', function()
- exec_lua([[
- bufnr = vim.api.nvim_get_current_buf()
- vim.api.nvim_win_set_buf(0, bufnr)
- client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
- ]])
-
insert(text)
- exec_lua([[
+ local bufnr = n.api.nvim_get_current_buf()
+ local client_id = exec_lua(function()
+ vim.api.nvim_win_set_buf(0, bufnr)
+ local client_id = vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
+ vim.wait(1000, function()
+ return #_G.server.messages > 1
+ end)
+ return client_id
+ end)
+
+ exec_lua(function()
+ --- @diagnostic disable-next-line:duplicate-set-field
vim.notify = function() end
vim.lsp.buf_detach_client(bufnr, client_id)
- ]])
+ end)
screen:expect {
grid = [[
@@ -216,18 +211,19 @@ describe('semantic token highlighting', function()
it(
'buffer is highlighted and unhighlighted when semantic token highlighting is started and stopped',
function()
- exec_lua([[
- bufnr = vim.api.nvim_get_current_buf()
- vim.api.nvim_win_set_buf(0, bufnr)
- client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
- ]])
+ local bufnr = n.api.nvim_get_current_buf()
+ local client_id = exec_lua(function()
+ vim.api.nvim_win_set_buf(0, bufnr)
+ return vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
+ end)
insert(text)
- exec_lua([[
- vim.notify = function() end
- vim.lsp.semantic_tokens.stop(bufnr, client_id)
- ]])
+ exec_lua(function()
+ --- @diagnostic disable-next-line:duplicate-set-field
+ vim.notify = function() end
+ vim.lsp.semantic_tokens.stop(bufnr, client_id)
+ end)
screen:expect {
grid = [[
@@ -248,9 +244,9 @@ describe('semantic token highlighting', function()
]],
}
- exec_lua([[
- vim.lsp.semantic_tokens.start(bufnr, client_id)
- ]])
+ exec_lua(function()
+ vim.lsp.semantic_tokens.start(bufnr, client_id)
+ end)
screen:expect {
grid = [[
@@ -274,18 +270,17 @@ describe('semantic token highlighting', function()
)
it('highlights start and stop when using "0" for current buffer', function()
- exec_lua([[
- bufnr = vim.api.nvim_get_current_buf()
- vim.api.nvim_win_set_buf(0, bufnr)
- client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
- ]])
+ local client_id = exec_lua(function()
+ return vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
+ end)
insert(text)
- exec_lua([[
+ exec_lua(function()
+ --- @diagnostic disable-next-line:duplicate-set-field
vim.notify = function() end
vim.lsp.semantic_tokens.stop(0, client_id)
- ]])
+ end)
screen:expect {
grid = [[
@@ -306,9 +301,9 @@ describe('semantic token highlighting', function()
]],
}
- exec_lua([[
+ exec_lua(function()
vim.lsp.semantic_tokens.start(0, client_id)
- ]])
+ end)
screen:expect {
grid = [[
@@ -331,13 +326,10 @@ describe('semantic token highlighting', function()
end)
it('buffer is re-highlighted when force refreshed', function()
- exec_lua([[
- bufnr = vim.api.nvim_get_current_buf()
- vim.api.nvim_win_set_buf(0, bufnr)
- client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
- ]])
-
insert(text)
+ exec_lua(function()
+ vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
+ end)
screen:expect {
grid = [[
@@ -358,9 +350,9 @@ describe('semantic token highlighting', function()
]],
}
- exec_lua([[
- vim.lsp.semantic_tokens.force_refresh(bufnr)
- ]])
+ exec_lua(function()
+ vim.lsp.semantic_tokens.force_refresh()
+ end)
screen:expect {
grid = [[
@@ -384,7 +376,9 @@ describe('semantic token highlighting', function()
local messages = exec_lua('return server.messages')
local token_request_count = 0
- for _, message in ipairs(messages) do
+ for _, message in
+ ipairs(messages --[[@as {method:string,params:table}[] ]])
+ do
assert(message.method ~= 'textDocument/semanticTokens/full/delta', 'delta request received')
if message.method == 'textDocument/semanticTokens/full' then
token_request_count = token_request_count + 1
@@ -394,31 +388,29 @@ describe('semantic token highlighting', function()
end)
it('destroys the highlighter if the buffer is deleted', function()
- exec_lua([[
- bufnr = vim.api.nvim_get_current_buf()
- vim.api.nvim_win_set_buf(0, bufnr)
- client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
- ]])
+ exec_lua(function()
+ vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
+ end)
insert(text)
- local highlighters = exec_lua([[
- vim.api.nvim_buf_delete(bufnr, { force = true })
- local semantic_tokens = vim.lsp.semantic_tokens
- return semantic_tokens.__STHighlighter.active
- ]])
-
- eq({}, highlighters)
+ eq(
+ {},
+ exec_lua(function()
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.api.nvim_buf_delete(bufnr, { force = true })
+ return vim.lsp.semantic_tokens.__STHighlighter.active
+ end)
+ )
end)
it('updates highlights with delta request on buffer change', function()
- exec_lua([[
- bufnr = vim.api.nvim_get_current_buf()
- vim.api.nvim_win_set_buf(0, bufnr)
- client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
- ]])
-
insert(text)
+
+ exec_lua(function()
+ vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
+ end)
+
screen:expect {
grid = [[
#include <iostream> |
@@ -459,45 +451,49 @@ describe('semantic token highlighting', function()
end)
it('prevents starting semantic token highlighting with invalid conditions', function()
- exec_lua([[
- bufnr = vim.api.nvim_get_current_buf()
- vim.api.nvim_win_set_buf(0, bufnr)
- client_id = vim.lsp.start_client({ name = 'dummy', cmd = server.cmd })
- notifications = {}
- vim.notify = function(...) table.insert(notifications, 1, {...}) end
- ]])
- eq(false, exec_lua('return vim.lsp.buf_is_attached(bufnr, client_id)'))
+ local client_id = exec_lua(function()
+ _G.notifications = {}
+ --- @diagnostic disable-next-line:duplicate-set-field
+ vim.notify = function(...)
+ table.insert(_G.notifications, 1, { ... })
+ end
+ return vim.lsp.start_client({ name = 'dummy', cmd = _G.server.cmd })
+ end)
+ eq(false, exec_lua('return vim.lsp.buf_is_attached(0, ...)', client_id))
insert(text)
- local notifications = exec_lua([[
- vim.lsp.semantic_tokens.start(bufnr, client_id)
- return notifications
- ]])
- matches('%[LSP%] Client with id %d not attached to buffer %d', notifications[1][1])
-
- notifications = exec_lua([[
- vim.lsp.semantic_tokens.start(bufnr, client_id + 1)
- return notifications
- ]])
- matches('%[LSP%] No client with id %d', notifications[1][1])
+ matches(
+ '%[LSP%] Client with id %d not attached to buffer %d',
+ exec_lua(function()
+ vim.lsp.semantic_tokens.start(0, client_id)
+ return _G.notifications[1][1]
+ end)
+ )
+
+ matches(
+ '%[LSP%] No client with id %d',
+ exec_lua(function()
+ vim.lsp.semantic_tokens.start(0, client_id + 1)
+ return _G.notifications[1][1]
+ end)
+ )
end)
it(
'opt-out: does not activate semantic token highlighting if disabled in client attach',
function()
- exec_lua([[
- bufnr = vim.api.nvim_get_current_buf()
- vim.api.nvim_win_set_buf(0, bufnr)
- client_id = vim.lsp.start({
+ local client_id = exec_lua(function()
+ return vim.lsp.start({
name = 'dummy',
- cmd = server.cmd,
- on_attach = vim.schedule_wrap(function(client, bufnr)
+ cmd = _G.server.cmd,
+ --- @param client vim.lsp.Client
+ on_attach = vim.schedule_wrap(function(client, _bufnr)
client.server_capabilities.semanticTokensProvider = nil
end),
})
- ]])
- eq(true, exec_lua('return vim.lsp.buf_is_attached(bufnr, client_id)'))
+ end)
+ eq(true, exec_lua('return vim.lsp.buf_is_attached(0, ...)', client_id))
insert(text)
@@ -520,13 +516,18 @@ describe('semantic token highlighting', function()
]],
}
- local notifications = exec_lua([[
- local notifications = {}
- vim.notify = function(...) table.insert(notifications, 1, {...}) end
- vim.lsp.semantic_tokens.start(bufnr, client_id)
- return notifications
- ]])
- eq('[LSP] Server does not support semantic tokens', notifications[1][1])
+ eq(
+ '[LSP] Server does not support semantic tokens',
+ exec_lua(function()
+ local notifications = {}
+ --- @diagnostic disable-next-line:duplicate-set-field
+ vim.notify = function(...)
+ table.insert(notifications, 1, { ... })
+ end
+ vim.lsp.semantic_tokens.start(0, client_id)
+ return notifications[1][1]
+ end)
+ )
screen:expect {
grid = [[
@@ -551,28 +552,32 @@ describe('semantic token highlighting', function()
)
it('ignores null responses from the server', function()
- exec_lua([[
- local legend, response, edit_response = ...
- server2 = _create_server({
+ local client_id = exec_lua(function()
+ _G.server2 = _G._create_server({
capabilities = {
semanticTokensProvider = {
full = { delta = false },
},
},
handlers = {
+ --- @param callback function
['textDocument/semanticTokens/full'] = function(_, _, callback)
callback(nil, nil)
end,
- ['textDocument/semanticTokens/full/delta'] = function()
+ --- @param callback function
+ ['textDocument/semanticTokens/full/delta'] = function(_, _, callback)
callback(nil, nil)
end,
- }
+ },
})
- bufnr = vim.api.nvim_get_current_buf()
- vim.api.nvim_win_set_buf(0, bufnr)
- client_id = vim.lsp.start({ name = 'dummy', cmd = server2.cmd })
- ]])
- eq(true, exec_lua('return vim.lsp.buf_is_attached(bufnr, client_id)'))
+ return vim.lsp.start({ name = 'dummy', cmd = _G.server2.cmd })
+ end)
+ eq(
+ true,
+ exec_lua(function()
+ return vim.lsp.buf_is_attached(0, client_id)
+ end)
+ )
insert(text)
@@ -597,10 +602,9 @@ describe('semantic token highlighting', function()
end)
it('does not send delta requests if not supported by server', function()
- exec_lua(
- [[
- local legend, response, edit_response = ...
- server2 = _create_server({
+ insert(text)
+ exec_lua(function()
+ _G.server2 = _G._create_server({
capabilities = {
semanticTokensProvider = {
full = { delta = false },
@@ -614,18 +618,11 @@ describe('semantic token highlighting', function()
['textDocument/semanticTokens/full/delta'] = function(_, _, callback)
callback(nil, vim.fn.json_decode(edit_response))
end,
- }
+ },
})
- bufnr = vim.api.nvim_get_current_buf()
- vim.api.nvim_win_set_buf(0, bufnr)
- client_id = vim.lsp.start({ name = 'dummy', cmd = server2.cmd })
- ]],
- legend,
- response,
- edit_response
- )
+ return vim.lsp.start({ name = 'dummy', cmd = _G.server2.cmd })
+ end)
- insert(text)
screen:expect {
grid = [[
#include <iostream> |
@@ -669,7 +666,9 @@ describe('semantic token highlighting', function()
}
local messages = exec_lua('return server2.messages')
local token_request_count = 0
- for _, message in ipairs(messages) do
+ for _, message in
+ ipairs(messages --[[@as {method:string,params:table}[] ]])
+ do
assert(message.method ~= 'textDocument/semanticTokens/full/delta', 'delta request received')
if message.method == 'textDocument/semanticTokens/full' then
token_request_count = token_request_count + 1
@@ -1064,10 +1063,8 @@ b = "as"]],
}) do
it(test.it, function()
exec_lua(create_server_definition)
- exec_lua(
- [[
- local legend, resp = ...
- server = _create_server({
+ local client_id = exec_lua(function(legend, resp)
+ _G.server = _G._create_server({
capabilities = {
semanticTokensProvider = {
full = { delta = false },
@@ -1078,25 +1075,22 @@ b = "as"]],
['textDocument/semanticTokens/full'] = function(_, _, callback)
callback(nil, vim.fn.json_decode(resp))
end,
- }
+ },
})
- bufnr = vim.api.nvim_get_current_buf()
- vim.api.nvim_win_set_buf(0, bufnr)
- client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
- ]],
- test.legend,
- test.response
- )
+ return vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
+ end, test.legend, test.response)
insert(test.text)
test.expected_screen()
- local highlights = exec_lua([[
- local semantic_tokens = vim.lsp.semantic_tokens
- return semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights
- ]])
- eq(test.expected, highlights)
+ eq(
+ test.expected,
+ exec_lua(function()
+ local bufnr = vim.api.nvim_get_current_buf()
+ return vim.lsp.semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights
+ end)
+ )
end)
end
end)
@@ -1449,11 +1443,11 @@ int main()
},
}) do
it(test.it, function()
+ local bufnr = n.api.nvim_get_current_buf()
+ insert(test.text1)
exec_lua(create_server_definition)
- exec_lua(
- [[
- local legend, resp1, resp2 = ...
- server = _create_server({
+ local client_id = exec_lua(function(legend, resp1, resp2)
+ _G.server = _G._create_server({
capabilities = {
semanticTokensProvider = {
full = { delta = true },
@@ -1467,54 +1461,44 @@ int main()
['textDocument/semanticTokens/full/delta'] = function(_, _, callback)
callback(nil, vim.fn.json_decode(resp2))
end,
- }
+ },
})
- bufnr = vim.api.nvim_get_current_buf()
- vim.api.nvim_win_set_buf(0, bufnr)
- client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
+ local client_id = assert(vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd }))
-- speed up vim.api.nvim_buf_set_lines calls by changing debounce to 10 for these tests
- semantic_tokens = vim.lsp.semantic_tokens
vim.schedule(function()
- semantic_tokens.stop(bufnr, client_id)
- semantic_tokens.start(bufnr, client_id, { debounce = 10 })
+ vim.lsp.semantic_tokens.stop(bufnr, client_id)
+ vim.lsp.semantic_tokens.start(bufnr, client_id, { debounce = 10 })
end)
- ]],
- test.legend,
- test.response1,
- test.response2
- )
-
- insert(test.text1)
+ return client_id
+ end, test.legend, test.response1, test.response2)
test.expected_screen1()
- local highlights = exec_lua([[
- return semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights
- ]])
-
- eq(test.expected1, highlights)
+ eq(
+ test.expected1,
+ exec_lua(function()
+ return vim.lsp.semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights
+ end)
+ )
if test.edit then
feed(test.edit)
else
- exec_lua(
- [[
- local text = ...
- vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, vim.fn.split(text, "\n"))
+ exec_lua(function(text)
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, vim.fn.split(text, '\n'))
vim.wait(15) -- wait for debounce
- ]],
- test.text2
- )
+ end, test.text2)
end
test.expected_screen2()
- highlights = exec_lua([[
- return semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights
- ]])
-
- eq(test.expected2, highlights)
+ eq(
+ test.expected2,
+ exec_lua(function()
+ return vim.lsp.semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights
+ end)
+ )
end)
end
end)
diff --git a/test/functional/plugin/lsp/testutil.lua b/test/functional/plugin/lsp/testutil.lua
index 3430a1e1a3..a36cbac568 100644
--- a/test/functional/plugin/lsp/testutil.lua
+++ b/test/functional/plugin/lsp/testutil.lua
@@ -21,8 +21,35 @@ function M.clear_notrace()
}
end
-M.create_server_definition = [[
- function _create_server(opts)
+M.create_tcp_echo_server = function()
+ --- Create a TCP server that echos the first message it receives.
+ --- @param host string
+ ---@return uv.uv_tcp_t
+ ---@return integer
+ ---@return fun():string|nil
+ function _G._create_tcp_server(host)
+ local uv = vim.uv
+ local server = assert(uv.new_tcp())
+ local init = nil
+ server:bind(host, 0)
+ server:listen(127, function(err)
+ assert(not err, err)
+ local socket = assert(uv.new_tcp())
+ server:accept(socket)
+ socket:read_start(require('vim.lsp.rpc').create_read_loop(function(body)
+ init = body
+ socket:close()
+ end))
+ end)
+ local port = server:getsockname().port
+ return server, port, function()
+ return init
+ end
+ end
+end
+
+M.create_server_definition = function()
+ function _G._create_server(opts)
opts = opts or {}
local server = {}
server.messages = {}
@@ -42,7 +69,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 +81,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,63 +101,62 @@ M.create_server_definition = [[
return server
end
-]]
+end
-- Fake LSP server.
M.fake_lsp_code = 'test/functional/fixtures/fake-lsp-server.lua'
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 {
+ exec_lua(function(fake_lsp_code, fake_lsp_logfile, timeout)
+ options = options or {}
+ settings = settings or {}
+ _G.lsp = require('vim.lsp')
+ _G.TEST_RPC_CLIENT_ID = _G.lsp.start_client {
cmd_env = {
- NVIM_LOG_FILE = fake_lsp_logfile;
- NVIM_LUA_NOTRACK = "1";
- NVIM_APPNAME = "nvim_lsp_test";
- };
+ 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),
- };
+ vim.v.progpath,
+ '-l',
+ fake_lsp_code,
+ test_name,
+ tostring(timeout),
+ },
handlers = setmetatable({}, {
- __index = function(t, method)
+ __index = function(_t, _method)
return function(...)
return vim.rpcrequest(1, 'handler', ...)
end
- end;
- });
- workspace_folders = {{
+ end,
+ }),
+ workspace_folders = {
+ {
uri = 'file://' .. vim.uv.cwd(),
name = 'test_folder',
- }};
- before_init = function(params, config)
+ },
+ },
+ before_init = function(_params, _config)
vim.schedule(function()
- vim.rpcrequest(1, "setup")
+ vim.rpcrequest(1, 'setup')
end)
end,
on_init = function(client, result)
- TEST_RPC_CLIENT = client
- vim.rpcrequest(1, "init", result)
- end;
+ _G.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;
+ 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;
+ vim.rpcnotify(1, 'exit', ...)
+ end,
}
- ]=],
- test_name,
- M.fake_lsp_code,
- M.fake_lsp_logfile,
- timeout_ms or 1e3,
- options or {},
- settings or {}
- )
+ end, M.fake_lsp_code, M.fake_lsp_logfile, timeout_ms or 1e3)
end
--- @class test.lsp.Config
@@ -160,18 +186,13 @@ 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(...)
+ if type(_G.TEST_RPC_CLIENT[name]) == 'function' then
+ return _G.TEST_RPC_CLIENT[name](...)
+ else
+ return _G.TEST_RPC_CLIENT[name]
+ end
+ end, ...)
end
end,
})
diff --git a/test/functional/plugin/lsp/utils_spec.lua b/test/functional/plugin/lsp/utils_spec.lua
index 6c6dec0667..64d58eeffd 100644
--- a/test/functional/plugin/lsp/utils_spec.lua
+++ b/test/functional/plugin/lsp/utils_spec.lua
@@ -11,21 +11,11 @@ describe('vim.lsp.util', function()
describe('stylize_markdown', function()
local stylize_markdown = function(content, opts)
- return exec_lua(
- [[
- local bufnr = vim.uri_to_bufnr("file:///fake/uri")
+ return exec_lua(function()
+ local bufnr = vim.uri_to_bufnr('file:///fake/uri')
vim.fn.bufload(bufnr)
-
- local args = { ... }
- local content = args[1]
- local opts = args[2]
- local stripped_content = vim.lsp.util.stylize_markdown(bufnr, content, opts)
-
- return stripped_content
- ]],
- content,
- opts
- )
+ return vim.lsp.util.stylize_markdown(bufnr, content, opts)
+ end)
end
it('code fences', function()
@@ -93,9 +83,64 @@ describe('vim.lsp.util', function()
end)
end)
- describe('normalize_markdown', function()
+ it('convert_input_to_markdown_lines', function()
+ local r = exec_lua(function()
+ local hover_data = {
+ kind = 'markdown',
+ value = '```lua\nfunction vim.api.nvim_buf_attach(buffer: integer, send_buffer: boolean, opts: vim.api.keyset.buf_attach)\n -> boolean\n```\n\n---\n\n Activates buffer-update events. Example:\n\n\n\n ```lua\n events = {}\n vim.api.nvim_buf_attach(0, false, {\n on_lines = function(...)\n table.insert(events, {...})\n end,\n })\n ```\n\n\n @see `nvim_buf_detach()`\n @see `api-buffer-updates-lua`\n@*param* `buffer` — Buffer handle, or 0 for current buffer\n\n\n\n@*param* `send_buffer` — True if whole buffer.\n Else the first notification will be `nvim_buf_changedtick_event`.\n\n\n@*param* `opts` — Optional parameters.\n\n - on_lines: Lua callback. Args:\n - the string "lines"\n - buffer handle\n - b:changedtick\n@*return* — False if foo;\n\n otherwise True.\n\n@see foo\n@see bar\n\n',
+ }
+ return vim.lsp.util.convert_input_to_markdown_lines(hover_data)
+ end)
+ local expected = {
+ '```lua',
+ 'function vim.api.nvim_buf_attach(buffer: integer, send_buffer: boolean, opts: vim.api.keyset.buf_attach)',
+ ' -> boolean',
+ '```',
+ '',
+ '---',
+ '',
+ ' Activates buffer-update events. Example:',
+ '',
+ '',
+ '',
+ ' ```lua',
+ ' events = {}',
+ ' vim.api.nvim_buf_attach(0, false, {',
+ ' on_lines = function(...)',
+ ' table.insert(events, {...})',
+ ' end,',
+ ' })',
+ ' ```',
+ '',
+ '',
+ ' @see `nvim_buf_detach()`',
+ ' @see `api-buffer-updates-lua`',
+ '',
+ -- For each @param/@return: #30695
+ -- - Separate each by one empty line.
+ -- - Remove all other blank lines.
+ '@*param* `buffer` — Buffer handle, or 0 for current buffer',
+ '',
+ '@*param* `send_buffer` — True if whole buffer.',
+ ' Else the first notification will be `nvim_buf_changedtick_event`.',
+ '',
+ '@*param* `opts` — Optional parameters.',
+ ' - on_lines: Lua callback. Args:',
+ ' - the string "lines"',
+ ' - buffer handle',
+ ' - b:changedtick',
+ '',
+ '@*return* — False if foo;',
+ ' otherwise True.',
+ '@see foo',
+ '@see bar',
+ }
+ eq(expected, r)
+ end)
+
+ describe('_normalize_markdown', function()
it('collapses consecutive blank lines', function()
- local result = exec_lua [[
+ local result = exec_lua(function()
local lines = {
'foo',
'',
@@ -103,25 +148,25 @@ describe('vim.lsp.util', function()
'',
'bar',
'',
- 'baz'
+ 'baz',
}
return vim.lsp.util._normalize_markdown(lines)
- ]]
+ end)
local expected = { 'foo', '', 'bar', '', 'baz' }
eq(expected, result)
end)
it('removes preceding and trailing empty lines', function()
- local result = exec_lua [[
+ local result = exec_lua(function()
local lines = {
'',
'foo',
'bar',
'',
- ''
+ '',
}
return vim.lsp.util._normalize_markdown(lines)
- ]]
+ end)
local expected = { 'foo', 'bar' }
eq(expected, result)
end)
@@ -129,19 +174,14 @@ describe('vim.lsp.util', function()
describe('make_floating_popup_options', function()
local function assert_anchor(anchor_bias, expected_anchor)
- local opts = exec_lua(
- [[
- local args = { ... }
- local anchor_bias = args[1]
- return vim.lsp.util.make_floating_popup_options(30, 10, { anchor_bias = anchor_bias })
- ]],
- anchor_bias
- )
+ local opts = exec_lua(function()
+ return vim.lsp.util.make_floating_popup_options(30, 10, { anchor_bias = anchor_bias })
+ end)
eq(expected_anchor, string.sub(opts.anchor, 1, 1))
end
- local screen
+ local screen --- @type test.functional.ui.screen
before_each(function()
n.clear()
screen = Screen.new(80, 80)
@@ -221,9 +261,9 @@ describe('vim.lsp.util', function()
end)
it('bordered window truncates dimensions correctly', function()
- local opts = exec_lua([[
+ local opts = exec_lua(function()
return vim.lsp.util.make_floating_popup_options(100, 100, { border = 'single' })
- ]])
+ end)
eq(56, opts.height)
end)
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index c95a96baca..9956fdf628 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -33,12 +33,38 @@ local create_server_definition = t_lsp.create_server_definition
local fake_lsp_code = t_lsp.fake_lsp_code
local fake_lsp_logfile = t_lsp.fake_lsp_logfile
local test_rpc_server = t_lsp.test_rpc_server
+local create_tcp_echo_server = t_lsp.create_tcp_echo_server
local function get_buf_option(name, bufnr)
- bufnr = bufnr or 'BUFFER'
- return exec_lua(
- string.format("return vim.api.nvim_get_option_value('%s', { buf = %s })", name, bufnr)
+ return exec_lua(function()
+ bufnr = bufnr or _G.BUFFER
+ return vim.api.nvim_get_option_value(name, { buf = bufnr })
+ end)
+end
+
+local function make_edit(y_0, x_0, y_1, x_1, text)
+ return {
+ range = {
+ start = { line = y_0, character = x_0 },
+ ['end'] = { line = y_1, character = x_1 },
+ },
+ newText = type(text) == 'table' and table.concat(text, '\n') or (text or ''),
+ }
+end
+
+--- @param edits [integer, integer, integer, integer, string|string[]][]
+--- @param encoding? string
+local function apply_text_edits(edits, encoding)
+ local edits1 = vim.tbl_map(
+ --- @param edit [integer, integer, integer, integer, string|string[]]
+ function(edit)
+ return make_edit(unpack(edit))
+ end,
+ edits
)
+ exec_lua(function()
+ vim.lsp.util.apply_text_edits(edits1, 1, encoding or 'utf-16')
+ end)
end
-- TODO(justinmk): hangs on Windows https://github.com/neovim/neovim/pull/11837
@@ -46,111 +72,156 @@ if skip(is_os('win')) then
return
end
-teardown(function()
- os.remove(fake_lsp_logfile)
-end)
-
describe('LSP', function()
before_each(function()
clear_notrace()
-
- -- Run an instance of nvim on the file which contains our "scripts".
- -- Pass TEST_NAME to pick the script.
- local test_name = 'basic_init'
- exec_lua(
- [=[
- lsp = require('vim.lsp')
- local test_name, fake_lsp_code, fake_lsp_logfile = ...
- function test__start_client()
- return lsp.start_client {
- cmd_env = {
- NVIM_LOG_FILE = fake_lsp_logfile;
- NVIM_APPNAME = "nvim_lsp_test";
- };
- cmd = {
- vim.v.progpath, '-l', fake_lsp_code, test_name;
- };
- workspace_folders = {{
- uri = 'file://' .. vim.uv.cwd(),
- name = 'test_folder',
- }};
- }
- end
- TEST_CLIENT1 = test__start_client()
- ]=],
- test_name,
- fake_lsp_code,
- fake_lsp_logfile
- )
end)
after_each(function()
+ stop()
+ exec_lua('lsp.stop_client(lsp.get_clients(), true)')
api.nvim_exec_autocmds('VimLeavePre', { modeline = false })
- -- exec_lua("lsp.stop_all_clients(true)")
+ end)
+
+ teardown(function()
+ os.remove(fake_lsp_logfile)
end)
describe('server_name specified', function()
+ before_each(function()
+ -- Run an instance of nvim on the file which contains our "scripts".
+ -- Pass TEST_NAME to pick the script.
+ local test_name = 'basic_init'
+ exec_lua(function()
+ _G.lsp = require('vim.lsp')
+ function _G.test__start_client()
+ return vim.lsp.start_client {
+ cmd_env = {
+ NVIM_LOG_FILE = fake_lsp_logfile,
+ NVIM_APPNAME = 'nvim_lsp_test',
+ },
+ cmd = {
+ vim.v.progpath,
+ '-l',
+ fake_lsp_code,
+ test_name,
+ },
+ workspace_folders = {
+ {
+ uri = 'file://' .. vim.uv.cwd(),
+ name = 'test_folder',
+ },
+ },
+ }
+ end
+ _G.TEST_CLIENT1 = _G.test__start_client()
+ end)
+ end)
+
it('start_client(), stop_client()', function()
retry(nil, 4000, function()
- eq(1, exec_lua('return #lsp.get_clients()'))
+ eq(
+ 1,
+ exec_lua(function()
+ return #vim.lsp.get_clients()
+ end)
+ )
end)
eq(
2,
- exec_lua([[
- TEST_CLIENT2 = test__start_client()
- return TEST_CLIENT2
- ]])
+ exec_lua(function()
+ _G.TEST_CLIENT2 = _G.test__start_client()
+ return _G.TEST_CLIENT2
+ end)
)
eq(
3,
- exec_lua([[
- TEST_CLIENT3 = test__start_client()
- return TEST_CLIENT3
- ]])
+ exec_lua(function()
+ _G.TEST_CLIENT3 = _G.test__start_client()
+ return _G.TEST_CLIENT3
+ end)
)
retry(nil, 4000, function()
- eq(3, exec_lua('return #lsp.get_clients()'))
+ eq(
+ 3,
+ exec_lua(function()
+ return #vim.lsp.get_clients()
+ end)
+ )
end)
- eq(false, exec_lua('return lsp.get_client_by_id(TEST_CLIENT1) == nil'))
- eq(false, exec_lua('return lsp.get_client_by_id(TEST_CLIENT1).is_stopped()'))
- exec_lua('return lsp.get_client_by_id(TEST_CLIENT1).stop()')
+ eq(
+ false,
+ exec_lua(function()
+ return vim.lsp.get_client_by_id(_G.TEST_CLIENT1) == nil
+ end)
+ )
+ eq(
+ false,
+ exec_lua(function()
+ return vim.lsp.get_client_by_id(_G.TEST_CLIENT1).is_stopped()
+ end)
+ )
+ exec_lua(function()
+ return vim.lsp.get_client_by_id(_G.TEST_CLIENT1).stop()
+ end)
retry(nil, 4000, function()
- eq(2, exec_lua('return #lsp.get_clients()'))
+ eq(
+ 2,
+ exec_lua(function()
+ return #vim.lsp.get_clients()
+ end)
+ )
end)
- eq(true, exec_lua('return lsp.get_client_by_id(TEST_CLIENT1) == nil'))
+ eq(
+ true,
+ exec_lua(function()
+ return vim.lsp.get_client_by_id(_G.TEST_CLIENT1) == nil
+ end)
+ )
- exec_lua('lsp.stop_client({TEST_CLIENT2, TEST_CLIENT3})')
+ exec_lua(function()
+ vim.lsp.stop_client({ _G.TEST_CLIENT2, _G.TEST_CLIENT3 })
+ end)
retry(nil, 4000, function()
- eq(0, exec_lua('return #lsp.get_clients()'))
+ eq(
+ 0,
+ exec_lua(function()
+ return #vim.lsp.get_clients()
+ end)
+ )
end)
end)
it('stop_client() also works on client objects', function()
- exec_lua([[
- TEST_CLIENT2 = test__start_client()
- TEST_CLIENT3 = test__start_client()
- ]])
+ exec_lua(function()
+ _G.TEST_CLIENT2 = _G.test__start_client()
+ _G.TEST_CLIENT3 = _G.test__start_client()
+ end)
retry(nil, 4000, function()
- eq(3, exec_lua('return #lsp.get_clients()'))
+ eq(
+ 3,
+ exec_lua(function()
+ return #vim.lsp.get_clients()
+ end)
+ )
end)
-- Stop all clients.
- exec_lua('lsp.stop_client(lsp.get_clients())')
+ exec_lua(function()
+ vim.lsp.stop_client(vim.lsp.get_clients())
+ end)
retry(nil, 4000, function()
- eq(0, exec_lua('return #lsp.get_clients()'))
+ eq(
+ 0,
+ exec_lua(function()
+ return #vim.lsp.get_clients()
+ end)
+ )
end)
end)
end)
-end)
-describe('LSP', function()
describe('basic_init test', function()
- after_each(function()
- stop()
- exec_lua('lsp.stop_client(lsp.get_clients(), true)')
- api.nvim_exec_autocmds('VimLeavePre', { modeline = false })
- end)
-
it('should run correctly', function()
local expected_handlers = {
{ NIL, {}, { method = 'test', client_id = 1 } },
@@ -221,28 +292,28 @@ describe('LSP', function()
function()
clear()
exec_lua(create_server_definition)
- local result = exec_lua([[
- local server = _create_server({
- capabilities = {
- positionEncoding = "utf-8"
- },
- })
+ local result = exec_lua(function()
+ local server = _G._create_server({
+ capabilities = {
+ positionEncoding = 'utf-8',
+ },
+ })
- local client_id = vim.lsp.start({
- name = 'dummy',
- cmd = server.cmd,
- })
+ local client_id = vim.lsp.start({
+ name = 'dummy',
+ cmd = server.cmd,
+ })
- if not client_id then
- return 'vim.lsp.start did not return client_id'
- end
+ if not client_id then
+ return 'vim.lsp.start did not return client_id'
+ end
- local client = vim.lsp.get_client_by_id(client_id)
- if not client then
- return 'No client found with id ' .. client_id
- end
- return client.offset_encoding
- ]])
+ local client = vim.lsp.get_client_by_id(client_id)
+ if not client then
+ return 'No client found with id ' .. client_id
+ end
+ return client.offset_encoding
+ end)
eq('utf-8', result)
end
)
@@ -255,7 +326,7 @@ describe('LSP', function()
return
end
local expected_handlers = {
- { NIL, {}, { method = 'shutdown', bufnr = 1, client_id = 1 } },
+ { NIL, {}, { method = 'shutdown', bufnr = 1, client_id = 1, version = 0 } },
{ NIL, {}, { method = 'test', client_id = 1 } },
}
test_rpc_server {
@@ -285,14 +356,24 @@ describe('LSP', function()
test_rpc_server {
test_name = 'basic_finish',
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- ]]
- eq(true, exec_lua('return lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)'))
- eq(true, exec_lua('return lsp.buf_is_attached(BUFFER, TEST_RPC_CLIENT_ID)'))
- exec_lua [[
- vim.api.nvim_command(BUFFER.."bwipeout")
- ]]
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ end)
+ eq(
+ true,
+ exec_lua(function()
+ return vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
+ end)
+ )
+ eq(
+ true,
+ exec_lua(function()
+ return vim.lsp.buf_is_attached(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
+ end)
+ )
+ exec_lua(function()
+ vim.cmd(_G.BUFFER .. 'bwipeout')
+ end)
end,
on_init = function(_client)
client = _client
@@ -305,8 +386,15 @@ describe('LSP', function()
on_handler = function(err, result, ctx)
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'finish' then
- exec_lua('return lsp.buf_detach_client(BUFFER, TEST_RPC_CLIENT_ID)')
- eq(false, exec_lua('return lsp.buf_is_attached(BUFFER, TEST_RPC_CLIENT_ID)'))
+ exec_lua(function()
+ return vim.lsp.buf_detach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
+ end)
+ eq(
+ false,
+ exec_lua(function()
+ return vim.lsp.buf_is_attached(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
+ end)
+ )
client.stop()
end
end,
@@ -318,31 +406,38 @@ describe('LSP', function()
test_rpc_server {
test_name = 'basic_init',
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
vim.api.nvim_create_autocmd('LspAttach', {
callback = function(args)
- local client = vim.lsp.get_client_by_id(args.data.client_id)
- vim.g.lsp_attached = client.name
+ local client0 = assert(vim.lsp.get_client_by_id(args.data.client_id))
+ vim.g.lsp_attached = client0.name
end,
})
vim.api.nvim_create_autocmd('LspDetach', {
callback = function(args)
- local client = vim.lsp.get_client_by_id(args.data.client_id)
- vim.g.lsp_detached = client.name
+ local client0 = assert(vim.lsp.get_client_by_id(args.data.client_id))
+ vim.g.lsp_detached = client0.name
end,
})
- ]]
+ end)
end,
on_init = function(_client)
client = _client
- eq(true, exec_lua('return lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)'))
+ eq(
+ true,
+ exec_lua(function()
+ return vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
+ end)
+ )
client.notify('finish')
end,
on_handler = function(_, _, ctx)
if ctx.method == 'finish' then
eq('basic_init', api.nvim_get_var('lsp_attached'))
- exec_lua('return lsp.buf_detach_client(BUFFER, TEST_RPC_CLIENT_ID)')
+ exec_lua(function()
+ return vim.lsp.buf_detach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
+ end)
eq('basic_init', api.nvim_get_var('lsp_detached'))
client.stop()
end
@@ -356,10 +451,10 @@ describe('LSP', function()
test_name = 'set_defaults_all_capabilities',
on_init = function(_client)
client = _client
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)
- ]]
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
+ end)
end,
on_handler = function(_, _, ctx)
if ctx.method == 'test' then
@@ -369,13 +464,13 @@ describe('LSP', function()
eq('', get_buf_option('keywordprg'))
eq(
true,
- exec_lua [[
- local keymap
- vim.api.nvim_buf_call(BUFFER, function()
- keymap = vim.fn.maparg("K", "n", false, true)
+ exec_lua(function()
+ local keymap --- @type table<string,any>
+ vim._with({ buf = _G.BUFFER }, function()
+ keymap = vim.fn.maparg('K', 'n', false, true)
+ end)
+ return keymap.callback == vim.lsp.buf.hover
end)
- return keymap.callback == vim.lsp.buf.hover
- ]]
)
client.stop()
end
@@ -386,13 +481,13 @@ describe('LSP', function()
eq('', get_buf_option('formatexpr'))
eq(
'',
- exec_lua [[
- local keymap
- vim.api.nvim_buf_call(BUFFER, function()
- keymap = vim.fn.maparg("K", "n", false, false)
+ exec_lua(function()
+ local keymap --- @type string
+ vim._with({ buf = _G.BUFFER }, function()
+ keymap = vim.fn.maparg('K', 'n', false, false)
+ end)
+ return keymap
end)
- return keymap
- ]]
)
end,
}
@@ -400,40 +495,42 @@ describe('LSP', function()
it('should overwrite options set by ftplugins', function()
local client --- @type vim.lsp.Client
+ local BUFFER_1 --- @type integer
+ local BUFFER_2 --- @type integer
test_rpc_server {
test_name = 'set_defaults_all_capabilities',
on_init = function(_client)
client = _client
- exec_lua [[
+ exec_lua(function()
vim.api.nvim_command('filetype plugin on')
BUFFER_1 = vim.api.nvim_create_buf(false, true)
BUFFER_2 = vim.api.nvim_create_buf(false, true)
vim.api.nvim_set_option_value('filetype', 'man', { buf = BUFFER_1 })
vim.api.nvim_set_option_value('filetype', 'xml', { buf = BUFFER_2 })
- ]]
+ end)
-- Sanity check to ensure that some values are set after setting filetype.
- eq("v:lua.require'man'.goto_tag", get_buf_option('tagfunc', 'BUFFER_1'))
- eq('xmlcomplete#CompleteTags', get_buf_option('omnifunc', 'BUFFER_2'))
- eq('xmlformat#Format()', get_buf_option('formatexpr', 'BUFFER_2'))
+ eq("v:lua.require'man'.goto_tag", get_buf_option('tagfunc', BUFFER_1))
+ eq('xmlcomplete#CompleteTags', get_buf_option('omnifunc', BUFFER_2))
+ eq('xmlformat#Format()', get_buf_option('formatexpr', BUFFER_2))
- exec_lua [[
- lsp.buf_attach_client(BUFFER_1, TEST_RPC_CLIENT_ID)
- lsp.buf_attach_client(BUFFER_2, TEST_RPC_CLIENT_ID)
- ]]
+ exec_lua(function()
+ vim.lsp.buf_attach_client(BUFFER_1, _G.TEST_RPC_CLIENT_ID)
+ vim.lsp.buf_attach_client(BUFFER_2, _G.TEST_RPC_CLIENT_ID)
+ end)
end,
on_handler = function(_, _, ctx)
if ctx.method == 'test' then
- eq('v:lua.vim.lsp.tagfunc', get_buf_option('tagfunc', 'BUFFER_1'))
- eq('v:lua.vim.lsp.omnifunc', get_buf_option('omnifunc', 'BUFFER_2'))
- eq('v:lua.vim.lsp.formatexpr()', get_buf_option('formatexpr', 'BUFFER_2'))
+ eq('v:lua.vim.lsp.tagfunc', get_buf_option('tagfunc', BUFFER_1))
+ eq('v:lua.vim.lsp.omnifunc', get_buf_option('omnifunc', BUFFER_2))
+ eq('v:lua.vim.lsp.formatexpr()', get_buf_option('formatexpr', BUFFER_2))
client.stop()
end
end,
on_exit = function(_, _)
- eq('', get_buf_option('tagfunc', 'BUFFER_1'))
- eq('', get_buf_option('omnifunc', 'BUFFER_2'))
- eq('', get_buf_option('formatexpr', 'BUFFER_2'))
+ eq('', get_buf_option('tagfunc', BUFFER_1))
+ eq('', get_buf_option('omnifunc', BUFFER_2))
+ eq('', get_buf_option('formatexpr', BUFFER_2))
end,
}
end)
@@ -444,13 +541,13 @@ describe('LSP', function()
test_name = 'set_defaults_all_capabilities',
on_init = function(_client)
client = _client
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- vim.api.nvim_set_option_value('tagfunc', 'tfu', { buf = BUFFER })
- vim.api.nvim_set_option_value('omnifunc', 'ofu', { buf = BUFFER })
- vim.api.nvim_set_option_value('formatexpr', 'fex', { buf = BUFFER })
- lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)
- ]]
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_set_option_value('tagfunc', 'tfu', { buf = _G.BUFFER })
+ vim.api.nvim_set_option_value('omnifunc', 'ofu', { buf = _G.BUFFER })
+ vim.api.nvim_set_option_value('formatexpr', 'fex', { buf = _G.BUFFER })
+ vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
+ end)
end,
on_handler = function(_, _, ctx)
if ctx.method == 'test' then
@@ -471,19 +568,19 @@ describe('LSP', function()
it('should detach buffer on bufwipe', function()
clear()
exec_lua(create_server_definition)
- local result = exec_lua([[
- local server = _create_server()
+ local result = exec_lua(function()
+ local server = _G._create_server()
local bufnr = vim.api.nvim_create_buf(false, true)
vim.api.nvim_set_current_buf(bufnr)
local detach_called = false
- vim.api.nvim_create_autocmd("LspDetach", {
+ vim.api.nvim_create_autocmd('LspDetach', {
callback = function()
detach_called = true
- end
+ end,
})
local client_id = vim.lsp.start({ name = 'detach-dummy', cmd = server.cmd })
- assert(client_id, "lsp.start must return client_id")
- local client = vim.lsp.get_client_by_id(client_id)
+ assert(client_id, 'lsp.start must return client_id')
+ local client = assert(vim.lsp.get_client_by_id(client_id))
local num_attached_before = vim.tbl_count(client.attached_buffers)
vim.api.nvim_buf_delete(bufnr, { force = true })
local num_attached_after = vim.tbl_count(client.attached_buffers)
@@ -494,7 +591,7 @@ describe('LSP', function()
num_attached_after = num_attached_after,
detach_called = detach_called,
}
- ]])
+ end)
eq(true, result ~= nil, 'exec_lua must return result')
eq(1, result.num_attached_before)
eq(0, result.num_attached_after)
@@ -504,30 +601,62 @@ describe('LSP', function()
it('should not re-attach buffer if it was deleted in on_init #28575', function()
clear()
exec_lua(create_server_definition)
- exec_lua([[
- local server = _create_server({
+ exec_lua(function()
+ local server = _G._create_server({
handlers = {
- initialize = function(method, params, callback)
+ initialize = function(_, _, callback)
vim.schedule(function()
callback(nil, { capabilities = {} })
end)
- end
- }
+ end,
+ },
})
local bufnr = vim.api.nvim_create_buf(false, true)
local on_init_called = false
- local client_id = vim.lsp.start({
+ local client_id = assert(vim.lsp.start({
name = 'detach-dummy',
cmd = server.cmd,
on_init = function()
vim.api.nvim_buf_delete(bufnr, {})
on_init_called = true
- end
- })
+ end,
+ }))
vim.lsp.buf_attach_client(bufnr, client_id)
- local ok = vim.wait(1000, function() return on_init_called end)
- assert(ok, "on_init was not called")
- ]])
+ local ok = vim.wait(1000, function()
+ return on_init_called
+ end)
+ assert(ok, 'on_init was not called')
+ end)
+ end)
+
+ it('should allow on_lines + nvim_buf_delete during LSP initialization #28575', function()
+ clear()
+ exec_lua(create_server_definition)
+ exec_lua(function()
+ local initialized = false
+ local server = _G._create_server({
+ handlers = {
+ initialize = function(_, _, callback)
+ vim.schedule(function()
+ callback(nil, { capabilities = {} })
+ initialized = true
+ end)
+ end,
+ },
+ })
+ local bufnr = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_set_current_buf(bufnr)
+ vim.lsp.start({
+ name = 'detach-dummy',
+ cmd = server.cmd,
+ })
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { 'hello' })
+ vim.api.nvim_buf_delete(bufnr, {})
+ local ok = vim.wait(1000, function()
+ return initialized
+ end)
+ assert(ok, 'lsp did not initialize')
+ end)
end)
it('client should return settings via workspace/configuration handler', function()
@@ -560,19 +689,25 @@ describe('LSP', function()
on_handler = function(err, result, ctx)
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'start' then
- exec_lua([=[
- local client = vim.lsp.get_client_by_id(TEST_RPC_CLIENT_ID)
- client.settings = {
- testSetting1 = true;
- testSetting2 = false;
- test = {Setting3 = 'nested' };
- }]=])
+ exec_lua(function()
+ local client0 = vim.lsp.get_client_by_id(_G.TEST_RPC_CLIENT_ID)
+ client0.settings = {
+ testSetting1 = true,
+ testSetting2 = false,
+ test = { Setting3 = 'nested' },
+ }
+ end)
end
if ctx.method == 'workspace/configuration' then
local server_result = exec_lua(
- [=[
+ [[
local method, params = ...
- return require'vim.lsp.handlers'['workspace/configuration'](err, params, {method=method, client_id=TEST_RPC_CLIENT_ID})]=],
+ return require 'vim.lsp.handlers'['workspace/configuration'](
+ err,
+ params,
+ { method = method, client_id = _G.TEST_RPC_CLIENT_ID }
+ )
+ ]],
ctx.method,
result
)
@@ -584,6 +719,7 @@ describe('LSP', function()
end,
}
end)
+
it(
'workspace/configuration returns NIL per section if client was started without config.settings',
function()
@@ -594,15 +730,19 @@ describe('LSP', function()
c.stop()
end,
on_setup = function()
- result = exec_lua [[
- local result = {
- items = {
- {section = 'foo'},
- {section = 'bar'},
+ result = exec_lua(function()
+ local result0 = {
+ items = {
+ { section = 'foo' },
+ { section = 'bar' },
+ },
}
- }
- return vim.lsp.handlers['workspace/configuration'](nil, result, {client_id=TEST_RPC_CLIENT_ID})
- ]]
+ return vim.lsp.handlers['workspace/configuration'](
+ nil,
+ result0,
+ { client_id = _G.TEST_RPC_CLIENT_ID }
+ )
+ end)
end,
}
eq({ NIL, NIL }, result)
@@ -617,7 +757,9 @@ describe('LSP', function()
test_name = 'basic_check_capabilities',
on_init = function(client)
client.stop()
- local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
+ local full_kind = exec_lua(function()
+ return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full
+ end)
eq(full_kind, client.server_capabilities().textDocumentSync.change)
eq({ includeText = false }, client.server_capabilities().textDocumentSync.save)
eq(false, client.server_capabilities().codeLensProvider)
@@ -650,11 +792,11 @@ describe('LSP', function()
on_handler = function(err, result, ctx)
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'start' then
- exec_lua([=[
- BUFFER = vim.api.nvim_get_current_buf()
- lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)
- vim.api.nvim_exec_autocmds('BufWritePost', { buffer = BUFFER, modeline = false })
- ]=])
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_get_current_buf()
+ vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
+ vim.api.nvim_exec_autocmds('BufWritePost', { buffer = _G.BUFFER, modeline = false })
+ end)
else
client.stop()
end
@@ -665,21 +807,21 @@ describe('LSP', function()
it('BufWritePre does not send notifications if server lacks willSave capabilities', function()
clear()
exec_lua(create_server_definition)
- local messages = exec_lua([[
- local server = _create_server({
+ local messages = exec_lua(function()
+ local server = _G._create_server({
capabilities = {
textDocumentSync = {
willSave = false,
willSaveWaitUntil = false,
- }
+ },
},
})
- local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
+ local client_id = assert(vim.lsp.start({ name = 'dummy', cmd = server.cmd }))
local buf = vim.api.nvim_get_current_buf()
vim.api.nvim_exec_autocmds('BufWritePre', { buffer = buf, modeline = false })
vim.lsp.stop_client(client_id)
return server.messages
- ]])
+ end)
eq(4, #messages)
eq('initialize', messages[1].method)
eq('initialized', messages[2].method)
@@ -690,13 +832,13 @@ describe('LSP', function()
it('BufWritePre sends willSave / willSaveWaitUntil, applies textEdits', function()
clear()
exec_lua(create_server_definition)
- local result = exec_lua([[
- local server = _create_server({
+ local result = exec_lua(function()
+ local server = _G._create_server({
capabilities = {
textDocumentSync = {
willSave = true,
willSaveWaitUntil = true,
- }
+ },
},
handlers = {
['textDocument/willSaveWaitUntil'] = function(_, _, callback)
@@ -705,21 +847,21 @@ describe('LSP', function()
start = { line = 0, character = 0 },
['end'] = { line = 0, character = 0 },
},
- newText = 'Hello'
+ newText = 'Hello',
}
- callback(nil, { text_edit, })
- end
+ callback(nil, { text_edit })
+ end,
},
})
local buf = vim.api.nvim_get_current_buf()
- local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
+ local client_id = assert(vim.lsp.start({ name = 'dummy', cmd = server.cmd }))
vim.api.nvim_exec_autocmds('BufWritePre', { buffer = buf, modeline = false })
vim.lsp.stop_client(client_id)
return {
messages = server.messages,
- lines = vim.api.nvim_buf_get_lines(buf, 0, -1, true)
+ lines = vim.api.nvim_buf_get_lines(buf, 0, -1, true),
}
- ]])
+ end)
local messages = result.messages
eq('textDocument/willSave', messages[3].method)
eq('textDocument/willSaveWaitUntil', messages[4].method)
@@ -745,20 +887,16 @@ describe('LSP', function()
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'start' then
local tmpfile_old = tmpname()
- local tmpfile_new = tmpname()
- os.remove(tmpfile_new)
- exec_lua(
- [=[
- local oldname, newname = ...
- BUFFER = vim.api.nvim_get_current_buf()
- vim.api.nvim_buf_set_name(BUFFER, oldname)
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, true, {"help me"})
- lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)
- vim.api.nvim_buf_call(BUFFER, function() vim.cmd('saveas ' .. newname) end)
- ]=],
- tmpfile_old,
- tmpfile_new
- )
+ local tmpfile_new = tmpname(false)
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_get_current_buf()
+ vim.api.nvim_buf_set_name(_G.BUFFER, tmpfile_old)
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, true, { 'help me' })
+ vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
+ vim._with({ buf = _G.BUFFER }, function()
+ vim.cmd('saveas ' .. tmpfile_new)
+ end)
+ end)
else
client.stop()
end
@@ -784,12 +922,12 @@ describe('LSP', function()
on_handler = function(err, result, ctx)
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'start' then
- exec_lua([=[
- BUFFER = vim.api.nvim_get_current_buf()
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, true, {"help me"})
- lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)
- vim.api.nvim_exec_autocmds('BufWritePost', { buffer = BUFFER, modeline = false })
- ]=])
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_get_current_buf()
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, true, { 'help me' })
+ vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
+ vim.api.nvim_exec_autocmds('BufWritePost', { buffer = _G.BUFFER, modeline = false })
+ end)
else
client.stop()
end
@@ -843,16 +981,18 @@ describe('LSP', function()
test_rpc_server {
test_name = 'capabilities_for_client_supports_method',
on_setup = function()
- exec_lua([=[
- BUFFER = vim.api.nvim_get_current_buf()
- lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)
- vim.lsp.handlers['textDocument/typeDefinition'] = function() end
- vim.cmd(BUFFER.."bwipeout")
- ]=])
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_get_current_buf()
+ vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
+ vim.lsp.handlers['textDocument/typeDefinition'] = function() end
+ vim.cmd(_G.BUFFER .. 'bwipeout')
+ end)
end,
on_init = function(client)
client.stop()
- exec_lua('vim.lsp.buf.type_definition()')
+ exec_lua(function()
+ vim.lsp.buf.type_definition()
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -873,13 +1013,15 @@ describe('LSP', function()
test_rpc_server {
test_name = 'capabilities_for_client_supports_method',
on_setup = function()
- exec_lua([=[
+ exec_lua(function()
vim.lsp.handlers['textDocument/typeDefinition'] = function() end
- ]=])
+ end)
end,
on_init = function(client)
client.stop()
- exec_lua('vim.lsp.buf.type_definition()')
+ exec_lua(function()
+ vim.lsp.buf.type_definition()
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -920,7 +1062,11 @@ describe('LSP', function()
it('should forward ContentModified to callback', function()
local expected_handlers = {
{ NIL, {}, { method = 'finish', client_id = 1 } },
- { { code = -32801 }, NIL, { method = 'error_code_test', bufnr = 1, client_id = 1 } },
+ {
+ { code = -32801 },
+ NIL,
+ { method = 'error_code_test', bufnr = 1, client_id = 1, version = 0 },
+ },
}
local client --- @type vim.lsp.Client
test_rpc_server {
@@ -950,7 +1096,7 @@ describe('LSP', function()
it('should track pending requests to the language server', function()
local expected_handlers = {
{ NIL, {}, { method = 'finish', client_id = 1 } },
- { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1 } },
+ { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1, version = 0 } },
}
local client --- @type vim.lsp.Client
test_rpc_server {
@@ -958,7 +1104,9 @@ describe('LSP', function()
on_init = function(_client)
client = _client
client.request('slow_request')
- local request = exec_lua([=[ return TEST_RPC_CLIENT.requests[2] ]=])
+ local request = exec_lua(function()
+ return _G.TEST_RPC_CLIENT.requests[2]
+ end)
eq('slow_request', request.method)
eq('pending', request.type)
client.notify('release')
@@ -971,8 +1119,10 @@ describe('LSP', function()
on_handler = function(err, _, ctx)
eq(table.remove(expected_handlers), { err, {}, ctx }, 'expected handler')
if ctx.method == 'slow_request' then
- local request = exec_lua([=[ return TEST_RPC_CLIENT.requests[2] ]=])
- eq(NIL, request)
+ local request = exec_lua(function()
+ return _G.TEST_RPC_CLIENT.requests[2]
+ end)
+ eq(nil, request)
client.notify('finish')
end
if ctx.method == 'finish' then
@@ -993,7 +1143,9 @@ describe('LSP', function()
client = _client
client.request('slow_request')
client.cancel_request(2)
- local request = exec_lua([=[ return TEST_RPC_CLIENT.requests[2] ]=])
+ local request = exec_lua(function()
+ return _G.TEST_RPC_CLIENT.requests[2]
+ end)
eq('slow_request', request.method)
eq('cancel', request.type)
client.notify('release')
@@ -1005,8 +1157,10 @@ describe('LSP', function()
end,
on_handler = function(err, _, ctx)
eq(table.remove(expected_handlers), { err, {}, ctx }, 'expected handler')
- local request = exec_lua([=[ return TEST_RPC_CLIENT.requests[2] ]=])
- eq(NIL, request)
+ local request = exec_lua(function()
+ return _G.TEST_RPC_CLIENT.requests[2]
+ end)
+ eq(nil, request)
if ctx.method == 'finish' then
client.stop()
end
@@ -1017,7 +1171,7 @@ describe('LSP', function()
it('should clear pending and cancel requests on reply', function()
local expected_handlers = {
{ NIL, {}, { method = 'finish', client_id = 1 } },
- { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1 } },
+ { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1, version = 0 } },
}
local client --- @type vim.lsp.Client
test_rpc_server {
@@ -1025,11 +1179,15 @@ describe('LSP', function()
on_init = function(_client)
client = _client
client.request('slow_request')
- local request = exec_lua([=[ return TEST_RPC_CLIENT.requests[2] ]=])
+ local request = exec_lua(function()
+ return _G.TEST_RPC_CLIENT.requests[2]
+ end)
eq('slow_request', request.method)
eq('pending', request.type)
client.cancel_request(2)
- request = exec_lua([=[ return TEST_RPC_CLIENT.requests[2] ]=])
+ request = exec_lua(function()
+ return _G.TEST_RPC_CLIENT.requests[2]
+ end)
eq('slow_request', request.method)
eq('cancel', request.type)
client.notify('release')
@@ -1042,8 +1200,10 @@ describe('LSP', function()
on_handler = function(err, _, ctx)
eq(table.remove(expected_handlers), { err, {}, ctx }, 'expected handler')
if ctx.method == 'slow_request' then
- local request = exec_lua([=[ return TEST_RPC_CLIENT.requests[2] ]=])
- eq(NIL, request)
+ local request = exec_lua(function()
+ return _G.TEST_RPC_CLIENT.requests[2]
+ end)
+ eq(nil, request)
client.notify('finish')
end
if ctx.method == 'finish' then
@@ -1056,7 +1216,7 @@ describe('LSP', function()
it('should trigger LspRequest autocmd when requests table changes', function()
local expected_handlers = {
{ NIL, {}, { method = 'finish', client_id = 1 } },
- { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1 } },
+ { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1, version = 0 } },
}
local client --- @type vim.lsp.Client
test_rpc_server {
@@ -1098,21 +1258,23 @@ describe('LSP', function()
test_rpc_server {
test_name = 'basic_finish',
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, {
- "testing";
- "123";
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, {
+ 'testing',
+ '123',
})
- assert(TEST_RPC_CLIENT_ID == 1)
- assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
- assert(lsp.buf_is_attached(BUFFER, TEST_RPC_CLIENT_ID))
- vim.cmd(BUFFER.."bwipeout")
- ]]
+ assert(_G.TEST_RPC_CLIENT_ID == 1)
+ assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
+ assert(vim.lsp.buf_is_attached(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
+ vim.cmd(_G.BUFFER .. 'bwipeout')
+ end)
end,
on_init = function(_client)
client = _client
- local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
+ local full_kind = exec_lua(function()
+ return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full
+ end)
eq(full_kind, client.server_capabilities().textDocumentSync.change)
eq(true, client.server_capabilities().textDocumentSync.openClose)
client.notify('finish')
@@ -1140,25 +1302,30 @@ describe('LSP', function()
test_rpc_server {
test_name = 'basic_check_buffer_open',
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, {
- "testing";
- "123";
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, {
+ 'testing',
+ '123',
})
- ]]
- exec_lua [[
- assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
- ]]
+ end)
+ exec_lua(function()
+ assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
+ end)
end,
on_init = function(_client)
client = _client
- local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
+ local full_kind = exec_lua(function()
+ return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full
+ end)
eq(full_kind, client.server_capabilities().textDocumentSync.change)
eq(true, client.server_capabilities().textDocumentSync.openClose)
- exec_lua [[
- assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID), "Already attached, returns true")
- ]]
+ exec_lua(function()
+ assert(
+ vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID),
+ 'Already attached, returns true'
+ )
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1186,22 +1353,24 @@ describe('LSP', function()
test_rpc_server {
test_name = 'basic_check_buffer_open',
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, {
- "testing";
- "123";
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, {
+ 'testing',
+ '123',
})
- ]]
+ end)
end,
on_init = function(_client)
client = _client
- local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
+ local full_kind = exec_lua(function()
+ return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full
+ end)
eq(full_kind, client.server_capabilities().textDocumentSync.change)
eq(true, client.server_capabilities().textDocumentSync.openClose)
- exec_lua [[
- assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
- ]]
+ exec_lua(function()
+ assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1229,22 +1398,24 @@ describe('LSP', function()
test_rpc_server {
test_name = 'basic_check_buffer_open_and_change',
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, {
- "testing";
- "123";
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, {
+ 'testing',
+ '123',
})
- ]]
+ end)
end,
on_init = function(_client)
client = _client
- local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
+ local full_kind = exec_lua(function()
+ return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full
+ end)
eq(full_kind, client.server_capabilities().textDocumentSync.change)
eq(true, client.server_capabilities().textDocumentSync.openClose)
- exec_lua [[
- assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
- ]]
+ exec_lua(function()
+ assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1252,11 +1423,11 @@ describe('LSP', function()
end,
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
- exec_lua [[
- vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, {
- "boop";
+ exec_lua(function()
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 1, 2, false, {
+ 'boop',
})
- ]]
+ end)
client.notify('finish')
end
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
@@ -1277,23 +1448,25 @@ describe('LSP', function()
test_rpc_server {
test_name = 'basic_check_buffer_open_and_change_noeol',
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, {
- "testing";
- "123";
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, {
+ 'testing',
+ '123',
})
- vim.bo[BUFFER].eol = false
- ]]
+ vim.bo[_G.BUFFER].eol = false
+ end)
end,
on_init = function(_client)
client = _client
- local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
+ local full_kind = exec_lua(function()
+ return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full
+ end)
eq(full_kind, client.server_capabilities().textDocumentSync.change)
eq(true, client.server_capabilities().textDocumentSync.openClose)
- exec_lua [[
- assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
- ]]
+ exec_lua(function()
+ assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1301,11 +1474,11 @@ describe('LSP', function()
end,
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
- exec_lua [[
- vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, {
- "boop";
+ exec_lua(function()
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 1, 2, false, {
+ 'boop',
})
- ]]
+ end)
client.notify('finish')
end
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
@@ -1336,6 +1509,7 @@ describe('LSP', function()
},
bufnr = 2,
client_id = 1,
+ version = 0,
},
},
{ NIL, {}, { method = 'start', client_id = 1 } },
@@ -1344,21 +1518,21 @@ describe('LSP', function()
test_rpc_server {
test_name = 'inlay_hint',
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, {
- "testing";
- "123";
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, {
+ 'testing',
+ '123',
})
- vim.bo[BUFFER].eol = false
- ]]
+ vim.bo[_G.BUFFER].eol = false
+ end)
end,
on_init = function(_client)
client = _client
eq(true, client.supports_method('textDocument/inlayHint'))
- exec_lua [[
- assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
- ]]
+ exec_lua(function()
+ assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1366,9 +1540,9 @@ describe('LSP', function()
end,
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
- exec_lua [[
- vim.lsp.inlay_hint.enable(true, { bufnr = BUFFER })
- ]]
+ exec_lua(function()
+ vim.lsp.inlay_hint.enable(true, { bufnr = _G.BUFFER })
+ end)
end
if ctx.method == 'textDocument/inlayHint' then
client.notify('finish')
@@ -1394,23 +1568,24 @@ describe('LSP', function()
allow_incremental_sync = true,
},
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, {
- "testing";
- "123";
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, {
+ 'testing',
+ '123',
})
- ]]
+ end)
end,
on_init = function(_client)
client = _client
- local sync_kind =
- exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Incremental")
+ local sync_kind = exec_lua(function()
+ return require 'vim.lsp.protocol'.TextDocumentSyncKind.Incremental
+ end)
eq(sync_kind, client.server_capabilities().textDocumentSync.change)
eq(true, client.server_capabilities().textDocumentSync.openClose)
- exec_lua [[
- assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
- ]]
+ exec_lua(function()
+ assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1418,11 +1593,11 @@ describe('LSP', function()
end,
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
- exec_lua [[
- vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, {
- "123boop";
+ exec_lua(function()
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 1, 2, false, {
+ '123boop',
})
- ]]
+ end)
client.notify('finish')
end
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
@@ -1432,6 +1607,7 @@ describe('LSP', function()
end,
}
end)
+
it('should check the body and didChange incremental with debounce', function()
local expected_handlers = {
{ NIL, {}, { method = 'shutdown', client_id = 1 } },
@@ -1446,23 +1622,24 @@ describe('LSP', function()
debounce_text_changes = 5,
},
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, {
- "testing";
- "123";
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, {
+ 'testing',
+ '123',
})
- ]]
+ end)
end,
on_init = function(_client)
client = _client
- local sync_kind =
- exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Incremental")
+ local sync_kind = exec_lua(function()
+ return require 'vim.lsp.protocol'.TextDocumentSyncKind.Incremental
+ end)
eq(sync_kind, client.server_capabilities().textDocumentSync.change)
eq(true, client.server_capabilities().textDocumentSync.openClose)
- exec_lua [[
- assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
- ]]
+ exec_lua(function()
+ assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1470,11 +1647,11 @@ describe('LSP', function()
end,
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
- exec_lua [[
- vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, {
- "123boop";
+ exec_lua(function()
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 1, 2, false, {
+ '123boop',
})
- ]]
+ end)
client.notify('finish')
end
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
@@ -1496,23 +1673,24 @@ describe('LSP', function()
test_rpc_server {
test_name = 'basic_check_buffer_open_and_change_incremental_editing',
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, {
- "testing";
- "123";
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, {
+ 'testing',
+ '123',
})
- ]]
+ end)
end,
on_init = function(_client)
client = _client
- local sync_kind =
- exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Incremental")
+ local sync_kind = exec_lua(function()
+ return require 'vim.lsp.protocol'.TextDocumentSyncKind.Incremental
+ end)
eq(sync_kind, client.server_capabilities().textDocumentSync.change)
eq(true, client.server_capabilities().textDocumentSync.openClose)
- exec_lua [[
- assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
- ]]
+ exec_lua(function()
+ assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1541,22 +1719,24 @@ describe('LSP', function()
test_rpc_server {
test_name = 'basic_check_buffer_open_and_change_multi',
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, {
- "testing";
- "123";
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, {
+ 'testing',
+ '123',
})
- ]]
+ end)
end,
on_init = function(_client)
client = _client
- local sync_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
+ local sync_kind = exec_lua(function()
+ return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full
+ end)
eq(sync_kind, client.server_capabilities().textDocumentSync.change)
eq(true, client.server_capabilities().textDocumentSync.openClose)
- exec_lua [[
- assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
- ]]
+ exec_lua(function()
+ assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1564,14 +1744,14 @@ describe('LSP', function()
end,
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
- exec_lua [[
- vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, {
- "321";
+ exec_lua(function()
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 1, 2, false, {
+ '321',
})
- vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, {
- "boop";
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 1, 2, false, {
+ 'boop',
})
- ]]
+ end)
client.notify('finish')
end
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
@@ -1592,22 +1772,24 @@ describe('LSP', function()
test_rpc_server {
test_name = 'basic_check_buffer_open_and_change_multi_and_close',
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, {
- "testing";
- "123";
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, {
+ 'testing',
+ '123',
})
- ]]
+ end)
end,
on_init = function(_client)
client = _client
- local sync_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
+ local sync_kind = exec_lua(function()
+ return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full
+ end)
eq(sync_kind, client.server_capabilities().textDocumentSync.change)
eq(true, client.server_capabilities().textDocumentSync.openClose)
- exec_lua [[
- assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
- ]]
+ exec_lua(function()
+ assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1615,15 +1797,15 @@ describe('LSP', function()
end,
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
- exec_lua [[
- vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, {
- "321";
+ exec_lua(function()
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 1, 2, false, {
+ '321',
})
- vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, {
- "boop";
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 1, 2, false, {
+ 'boop',
})
- vim.api.nvim_command(BUFFER.."bwipeout")
- ]]
+ vim.api.nvim_command(_G.BUFFER .. 'bwipeout')
+ end)
client.notify('finish')
end
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
@@ -1679,19 +1861,19 @@ describe('LSP', function()
test_rpc_server {
test_name = 'decode_nil',
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, {
- "testing";
- "123";
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, {
+ 'testing',
+ '123',
})
- ]]
+ end)
end,
on_init = function(_client)
client = _client
- exec_lua [[
- assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
- ]]
+ exec_lua(function()
+ assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1706,22 +1888,58 @@ describe('LSP', function()
}
end)
end)
-end)
-describe('LSP', function()
- before_each(function()
- clear_notrace()
- end)
+ describe('apply vscode text_edits', function()
+ it('single replace', function()
+ insert('012345678901234567890123456789')
+ apply_text_edits({
+ { 0, 3, 0, 6, { 'Hello' } },
+ })
+ eq({ '012Hello678901234567890123456789' }, buf_lines(1))
+ end)
- local function make_edit(y_0, x_0, y_1, x_1, text)
- return {
- range = {
- start = { line = y_0, character = x_0 },
- ['end'] = { line = y_1, character = x_1 },
- },
- newText = type(text) == 'table' and table.concat(text, '\n') or (text or ''),
- }
- end
+ it('two replaces', function()
+ insert('012345678901234567890123456789')
+ apply_text_edits({
+ { 0, 3, 0, 6, { 'Hello' } },
+ { 0, 6, 0, 9, { 'World' } },
+ })
+ eq({ '012HelloWorld901234567890123456789' }, buf_lines(1))
+ end)
+
+ it('same start pos insert are kept in order', function()
+ insert('012345678901234567890123456789')
+ apply_text_edits({
+ { 0, 3, 0, 3, { 'World' } },
+ { 0, 3, 0, 3, { 'Hello' } },
+ })
+ eq({ '012WorldHello345678901234567890123456789' }, buf_lines(1))
+ end)
+
+ it('same start pos insert and replace are kept in order', function()
+ insert('012345678901234567890123456789')
+ apply_text_edits({
+ { 0, 3, 0, 3, { 'World' } },
+ { 0, 3, 0, 3, { 'Hello' } },
+ { 0, 3, 0, 8, { 'No' } },
+ })
+ eq({ '012WorldHelloNo8901234567890123456789' }, buf_lines(1))
+ end)
+
+ it('multiline', function()
+ exec_lua(function()
+ vim.api.nvim_buf_set_lines(1, 0, 0, true, { ' {', ' "foo": "bar"', ' }' })
+ end)
+ eq({ ' {', ' "foo": "bar"', ' }', '' }, buf_lines(1))
+ apply_text_edits({
+ { 0, 0, 3, 0, { '' } },
+ { 3, 0, 3, 0, { '{\n' } },
+ { 3, 0, 3, 0, { ' "foo": "bar"\n' } },
+ { 3, 0, 3, 0, { '}\n' } },
+ })
+ eq({ '{', ' "foo": "bar"', '}', '' }, buf_lines(1))
+ end)
+ end)
describe('apply_text_edits', function()
before_each(function()
@@ -1732,14 +1950,14 @@ describe('LSP', function()
Fourth line of text
å å ɧ 汉语 ↥ 🤦 🦄]]))
end)
+
it('applies simple edits', function()
- local edits = {
- make_edit(0, 0, 0, 0, { '123' }),
- make_edit(1, 0, 1, 1, { '2' }),
- make_edit(2, 0, 2, 2, { '3' }),
- make_edit(3, 2, 3, 4, { '' }),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 0, 0, 0, 0, { '123' } },
+ { 1, 0, 1, 1, { '2' } },
+ { 2, 0, 2, 2, { '3' } },
+ { 3, 2, 3, 4, { '' } },
+ })
eq({
'123First line of text',
'2econd line of text',
@@ -1748,18 +1966,18 @@ describe('LSP', function()
'å å ɧ 汉语 ↥ 🤦 🦄',
}, buf_lines(1))
end)
+
it('applies complex edits', function()
- local edits = {
- make_edit(0, 0, 0, 0, { '', '12' }),
- make_edit(0, 0, 0, 0, { '3', 'foo' }),
- make_edit(0, 1, 0, 1, { 'bar', '123' }),
- make_edit(0, #'First ', 0, #'First line of text', { 'guy' }),
- make_edit(1, 0, 1, #'Second', { 'baz' }),
- make_edit(2, #'Th', 2, #'Third', { 'e next' }),
- make_edit(3, #'', 3, #'Fourth', { 'another line of text', 'before this' }),
- make_edit(3, #'Fourth', 3, #'Fourth line of text', { '!' }),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 0, 0, 0, 0, { '', '12' } },
+ { 0, 0, 0, 0, { '3', 'foo' } },
+ { 0, 1, 0, 1, { 'bar', '123' } },
+ { 0, #'First ', 0, #'First line of text', { 'guy' } },
+ { 1, 0, 1, #'Second', { 'baz' } },
+ { 2, #'Th', 2, #'Third', { 'e next' } },
+ { 3, #'', 3, #'Fourth', { 'another line of text', 'before this' } },
+ { 3, #'Fourth', 3, #'Fourth line of text', { '!' } },
+ })
eq({
'',
'123',
@@ -1772,18 +1990,18 @@ describe('LSP', function()
'å å ɧ 汉语 ↥ 🤦 🦄',
}, buf_lines(1))
end)
+
it('applies complex edits (reversed range)', function()
- local edits = {
- make_edit(0, 0, 0, 0, { '', '12' }),
- make_edit(0, 0, 0, 0, { '3', 'foo' }),
- make_edit(0, 1, 0, 1, { 'bar', '123' }),
- make_edit(0, #'First line of text', 0, #'First ', { 'guy' }),
- make_edit(1, #'Second', 1, 0, { 'baz' }),
- make_edit(2, #'Third', 2, #'Th', { 'e next' }),
- make_edit(3, #'Fourth', 3, #'', { 'another line of text', 'before this' }),
- make_edit(3, #'Fourth line of text', 3, #'Fourth', { '!' }),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 0, 0, 0, 0, { '', '12' } },
+ { 0, 0, 0, 0, { '3', 'foo' } },
+ { 0, 1, 0, 1, { 'bar', '123' } },
+ { 0, #'First line of text', 0, #'First ', { 'guy' } },
+ { 1, #'Second', 1, 0, { 'baz' } },
+ { 2, #'Third', 2, #'Th', { 'e next' } },
+ { 3, #'Fourth', 3, #'', { 'another line of text', 'before this' } },
+ { 3, #'Fourth line of text', 3, #'Fourth', { '!' } },
+ })
eq({
'',
'123',
@@ -1796,11 +2014,11 @@ describe('LSP', function()
'å å ɧ 汉语 ↥ 🤦 🦄',
}, buf_lines(1))
end)
+
it('applies non-ASCII characters edits', function()
- local edits = {
- make_edit(4, 3, 4, 4, { 'ä' }),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 4, 3, 4, 4, { 'ä' } },
+ })
eq({
'First line of text',
'Second line of text',
@@ -1809,11 +2027,11 @@ describe('LSP', function()
'å ä ɧ 汉语 ↥ 🤦 🦄',
}, buf_lines(1))
end)
+
it('applies text edits at the end of the document', function()
- local edits = {
- make_edit(5, 0, 5, 0, 'foobar'),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 5, 0, 5, 0, 'foobar' },
+ })
eq({
'First line of text',
'Second line of text',
@@ -1823,12 +2041,12 @@ describe('LSP', function()
'foobar',
}, buf_lines(1))
end)
+
it('applies multiple text edits at the end of the document', function()
- local edits = {
- make_edit(4, 0, 5, 0, ''),
- make_edit(5, 0, 5, 0, 'foobar'),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 4, 0, 5, 0, '' },
+ { 5, 0, 5, 0, 'foobar' },
+ })
eq({
'First line of text',
'Second line of text',
@@ -1837,62 +2055,56 @@ describe('LSP', function()
'foobar',
}, buf_lines(1))
end)
+
it('it restores marks', function()
- local edits = {
- make_edit(1, 0, 2, 5, 'foobar'),
- make_edit(4, 0, 5, 0, 'barfoo'),
- }
eq(true, api.nvim_buf_set_mark(1, 'a', 2, 1, {}))
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 1, 0, 2, 5, 'foobar' },
+ { 4, 0, 5, 0, 'barfoo' },
+ })
eq({
'First line of text',
'foobar line of text',
'Fourth line of text',
'barfoo',
}, buf_lines(1))
- local mark = api.nvim_buf_get_mark(1, 'a')
- eq({ 2, 1 }, mark)
+ eq({ 2, 1 }, api.nvim_buf_get_mark(1, 'a'))
end)
it('it restores marks to last valid col', function()
- local edits = {
- make_edit(1, 0, 2, 15, 'foobar'),
- make_edit(4, 0, 5, 0, 'barfoo'),
- }
eq(true, api.nvim_buf_set_mark(1, 'a', 2, 10, {}))
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 1, 0, 2, 15, 'foobar' },
+ { 4, 0, 5, 0, 'barfoo' },
+ })
eq({
'First line of text',
'foobarext',
'Fourth line of text',
'barfoo',
}, buf_lines(1))
- local mark = api.nvim_buf_get_mark(1, 'a')
- eq({ 2, 9 }, mark)
+ eq({ 2, 9 }, api.nvim_buf_get_mark(1, 'a'))
end)
it('it restores marks to last valid line', function()
- local edits = {
- make_edit(1, 0, 4, 5, 'foobar'),
- make_edit(4, 0, 5, 0, 'barfoo'),
- }
eq(true, api.nvim_buf_set_mark(1, 'a', 4, 1, {}))
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 1, 0, 4, 5, 'foobar' },
+ { 4, 0, 5, 0, 'barfoo' },
+ })
eq({
'First line of text',
'foobaro',
}, buf_lines(1))
- local mark = api.nvim_buf_get_mark(1, 'a')
- eq({ 2, 1 }, mark)
+ eq({ 2, 1 }, api.nvim_buf_get_mark(1, 'a'))
end)
describe('cursor position', function()
it("don't fix the cursor if the range contains the cursor", function()
api.nvim_win_set_cursor(0, { 2, 6 })
- local edits = {
- make_edit(1, 0, 1, 19, 'Second line of text'),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 1, 0, 1, 19, 'Second line of text' },
+ })
eq({
'First line of text',
'Second line of text',
@@ -1905,11 +2117,10 @@ describe('LSP', function()
it('fix the cursor to the valid col if the content was removed', function()
api.nvim_win_set_cursor(0, { 2, 6 })
- local edits = {
- make_edit(1, 0, 1, 6, ''),
- make_edit(1, 6, 1, 19, ''),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 1, 0, 1, 6, '' },
+ { 1, 6, 1, 19, '' },
+ })
eq({
'First line of text',
'',
@@ -1922,11 +2133,10 @@ describe('LSP', function()
it('fix the cursor to the valid row if the content was removed', function()
api.nvim_win_set_cursor(0, { 2, 6 })
- local edits = {
- make_edit(1, 0, 1, 6, ''),
- make_edit(0, 18, 5, 0, ''),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 1, 0, 1, 6, '' },
+ { 0, 18, 5, 0, '' },
+ })
eq({
'First line of text',
}, buf_lines(1))
@@ -1935,10 +2145,9 @@ describe('LSP', function()
it('fix the cursor row', function()
api.nvim_win_set_cursor(0, { 3, 0 })
- local edits = {
- make_edit(1, 0, 2, 0, ''),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 1, 0, 2, 0, '' },
+ })
eq({
'First line of text',
'Third line of text',
@@ -1953,10 +2162,9 @@ describe('LSP', function()
api.nvim_buf_set_lines(1, -1, -1, true, { '' })
api.nvim_win_set_cursor(0, { 2, 11 })
- local edits = {
- make_edit(1, 7, 1, 11, ''),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 1, 7, 1, 11, '' },
+ })
eq({
'First line of text',
'Second of text',
@@ -1970,10 +2178,9 @@ describe('LSP', function()
it('fix the cursor row and col', function()
api.nvim_win_set_cursor(0, { 2, 12 })
- local edits = {
- make_edit(0, 11, 1, 12, ''),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 0, 11, 1, 12, '' },
+ })
eq({
'First line of text',
'Third line of text',
@@ -1986,24 +2193,23 @@ describe('LSP', function()
describe('with LSP end line after what Vim considers to be the end line', function()
it('applies edits when the last linebreak is considered a new line', function()
- local edits = {
- make_edit(0, 0, 5, 0, { 'All replaced' }),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 0, 0, 5, 0, { 'All replaced' } },
+ })
eq({ 'All replaced' }, buf_lines(1))
end)
+
it("applies edits when the end line is 2 larger than vim's", function()
- local edits = {
- make_edit(0, 0, 6, 0, { 'All replaced' }),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 0, 0, 6, 0, { 'All replaced' } },
+ })
eq({ 'All replaced' }, buf_lines(1))
end)
+
it('applies edits with a column offset', function()
- local edits = {
- make_edit(0, 0, 5, 2, { 'All replaced' }),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 0, 0, 5, 2, { 'All replaced' } },
+ })
eq({ 'All replaced' }, buf_lines(1))
end)
end)
@@ -2015,38 +2221,38 @@ describe('LSP', function()
Test line one
Test line two 21 char]]))
end)
+
describe('with LSP end column out of bounds and start column at 0', function()
it('applies edits at the end of the buffer', function()
- local edits = {
- make_edit(0, 0, 1, 22, { '#include "whatever.h"\r\n#include <algorithm>\r' }),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-8')
+ apply_text_edits({
+ { 0, 0, 1, 22, { '#include "whatever.h"\r\n#include <algorithm>\r' } },
+ }, 'utf-8')
eq({ '#include "whatever.h"', '#include <algorithm>' }, buf_lines(1))
end)
+
it('applies edits in the middle of the buffer', function()
- local edits = {
- make_edit(0, 0, 0, 22, { '#include "whatever.h"\r\n#include <algorithm>\r' }),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-8')
+ apply_text_edits({
+ { 0, 0, 0, 22, { '#include "whatever.h"\r\n#include <algorithm>\r' } },
+ }, 'utf-8')
eq(
{ '#include "whatever.h"', '#include <algorithm>', 'Test line two 21 char' },
buf_lines(1)
)
end)
end)
+
describe('with LSP end column out of bounds and start column NOT at 0', function()
it('applies edits at the end of the buffer', function()
- local edits = {
- make_edit(0, 2, 1, 22, { '#include "whatever.h"\r\n#include <algorithm>\r' }),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-8')
+ apply_text_edits({
+ { 0, 2, 1, 22, { '#include "whatever.h"\r\n#include <algorithm>\r' } },
+ }, 'utf-8')
eq({ 'Te#include "whatever.h"', '#include <algorithm>' }, buf_lines(1))
end)
+
it('applies edits in the middle of the buffer', function()
- local edits = {
- make_edit(0, 2, 0, 22, { '#include "whatever.h"\r\n#include <algorithm>\r' }),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-8')
+ apply_text_edits({
+ { 0, 2, 0, 22, { '#include "whatever.h"\r\n#include <algorithm>\r' } },
+ }, 'utf-8')
eq(
{ 'Te#include "whatever.h"', '#include <algorithm>', 'Test line two 21 char' },
buf_lines(1)
@@ -2057,6 +2263,7 @@ describe('LSP', function()
describe('apply_text_document_edit', function()
local target_bufnr --- @type integer
+
local text_document_edit = function(editVersion)
return {
edits = {
@@ -2068,50 +2275,43 @@ describe('LSP', function()
},
}
end
+
before_each(function()
- target_bufnr = exec_lua [[
- local bufnr = vim.uri_to_bufnr("file:///fake/uri")
- local lines = {"1st line of text", "2nd line of 语text"}
+ target_bufnr = exec_lua(function()
+ local bufnr = vim.uri_to_bufnr('file:///fake/uri')
+ local lines = { '1st line of text', '2nd line of 语text' }
vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines)
return bufnr
- ]]
+ end)
end)
+
it('correctly goes ahead with the edit if all is normal', function()
- exec_lua("vim.lsp.util.apply_text_document_edit(..., nil, 'utf-16')", text_document_edit(5))
+ exec_lua(function(text_edit)
+ vim.lsp.util.apply_text_document_edit(text_edit, nil, 'utf-16')
+ end, text_document_edit(5))
eq({
'First ↥ 🤦 🦄 line of text',
'2nd line of 语text',
}, buf_lines(target_bufnr))
end)
+
it('always accepts edit with version = 0', function()
- exec_lua(
- [[
- local args = {...}
- local bufnr = select(1, ...)
- local text_edit = select(2, ...)
- vim.lsp.util.buf_versions[bufnr] = 10
+ exec_lua(function(text_edit)
+ vim.lsp.util.buf_versions[target_bufnr] = 10
vim.lsp.util.apply_text_document_edit(text_edit, nil, 'utf-16')
- ]],
- target_bufnr,
- text_document_edit(0)
- )
+ end, text_document_edit(0))
eq({
'First ↥ 🤦 🦄 line of text',
'2nd line of 语text',
}, buf_lines(target_bufnr))
end)
+
it('skips the edit if the version of the edit is behind the local buffer ', function()
local apply_edit_mocking_current_version = function(edit, versionedBuf)
- exec_lua(
- [[
- local args = {...}
- local versionedBuf = args[2]
+ exec_lua(function()
vim.lsp.util.buf_versions[versionedBuf.bufnr] = versionedBuf.currentVersion
- vim.lsp.util.apply_text_document_edit(args[1], nil, 'utf-16')
- ]],
- edit,
- versionedBuf
- )
+ vim.lsp.util.apply_text_document_edit(edit, nil, 'utf-16')
+ end)
end
local baseText = {
@@ -2164,13 +2364,17 @@ describe('LSP', function()
}
eq(
expected,
- exec_lua [[
- local apply_edit = {
- label = nil;
- edit = {};
- }
- return vim.lsp.handlers['workspace/applyEdit'](nil, apply_edit, {client_id = TEST_RPC_CLIENT_ID})
- ]]
+ exec_lua(function()
+ local apply_edit = {
+ label = nil,
+ edit = {},
+ }
+ return vim.lsp.handlers['workspace/applyEdit'](
+ nil,
+ apply_edit,
+ { client_id = _G.TEST_RPC_CLIENT_ID }
+ )
+ end)
)
eq(table.remove(expected_handlers), { ... })
end,
@@ -2200,34 +2404,30 @@ describe('LSP', function()
}
end
- local target_bufnr, changedtick = nil, nil
+ local target_bufnr --- @type integer
+ local changedtick --- @type integer
before_each(function()
- local ret = exec_lua [[
- local bufnr = vim.uri_to_bufnr("file:///fake/uri")
+ exec_lua(function()
+ target_bufnr = vim.uri_to_bufnr('file:///fake/uri')
local lines = {
- "Original Line #1",
- "Original Line #2"
+ 'Original Line #1',
+ 'Original Line #2',
}
- vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines)
+ vim.api.nvim_buf_set_lines(target_bufnr, 0, -1, false, lines)
- local update_changed_tick = function()
- vim.lsp.util.buf_versions[bufnr] = vim.api.nvim_buf_get_var(bufnr, 'changedtick')
+ local function update_changed_tick()
+ vim.lsp.util.buf_versions[target_bufnr] = vim.b[target_bufnr].changedtick
end
update_changed_tick()
- vim.api.nvim_buf_attach(bufnr, false, {
- on_changedtick = function()
- update_changed_tick()
- end
+ vim.api.nvim_buf_attach(target_bufnr, false, {
+ on_changedtick = update_changed_tick,
})
- return {bufnr, vim.api.nvim_buf_get_var(bufnr, 'changedtick')}
- ]]
-
- target_bufnr = ret[1]
- changedtick = ret[2]
+ changedtick = vim.b[target_bufnr].changedtick
+ end)
end)
it('apply_workspace_edit applies a single edit', function()
@@ -2245,19 +2445,11 @@ describe('LSP', function()
'First Line',
'Original Line #2',
},
- exec_lua(
- [[
- local args = {...}
- local workspace_edits = args[1]
- local target_bufnr = args[2]
-
- vim.lsp.util.apply_workspace_edit(workspace_edits, 'utf-16')
+ exec_lua(function(workspace_edits)
+ vim.lsp.util.apply_workspace_edit(workspace_edits, 'utf-16')
- return vim.api.nvim_buf_get_lines(target_bufnr, 0, -1, false)
- ]],
- make_workspace_edit(edits),
- target_bufnr
- )
+ return vim.api.nvim_buf_get_lines(target_bufnr, 0, -1, false)
+ end, make_workspace_edit(edits))
)
end)
@@ -2274,24 +2466,15 @@ describe('LSP', function()
eq(
new_lines,
- exec_lua(
- [[
- local args = {...}
- local workspace_edits = args[1]
- local target_bufnr = args[2]
-
- vim.lsp.util.apply_workspace_edit(workspace_edits, 'utf-16')
-
- return vim.api.nvim_buf_get_lines(target_bufnr, 0, -1, false)
- ]],
- make_workspace_edit(edits),
- target_bufnr
- )
+ exec_lua(function(workspace_edits)
+ vim.lsp.util.apply_workspace_edit(workspace_edits, 'utf-16')
+ return vim.api.nvim_buf_get_lines(target_bufnr, 0, -1, false)
+ end, make_workspace_edit(edits))
)
end)
+
it('Supports file creation with CreateFile payload', function()
- local tmpfile = tmpname()
- os.remove(tmpfile) -- Should not exist, only interested in a tmpname
+ local tmpfile = tmpname(false)
local uri = exec_lua('return vim.uri_from_fname(...)', tmpfile)
local edit = {
documentChanges = {
@@ -2301,15 +2484,16 @@ describe('LSP', function()
},
},
}
- exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit, 'utf-16')
+ exec_lua(function()
+ vim.lsp.util.apply_workspace_edit(edit, 'utf-16')
+ end)
eq(true, vim.uv.fs_stat(tmpfile) ~= nil)
end)
+
it(
'Supports file creation in folder that needs to be created with CreateFile payload',
function()
- local tmpfile = tmpname()
- os.remove(tmpfile) -- Should not exist, only interested in a tmpname
- tmpfile = tmpfile .. '/dummy/x/'
+ local tmpfile = tmpname(false) .. '/dummy/x/'
local uri = exec_lua('return vim.uri_from_fname(...)', tmpfile)
local edit = {
documentChanges = {
@@ -2319,10 +2503,13 @@ describe('LSP', function()
},
},
}
- exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit, 'utf-16')
+ exec_lua(function()
+ vim.lsp.util.apply_workspace_edit(edit, 'utf-16')
+ end)
eq(true, vim.uv.fs_stat(tmpfile) ~= nil)
end
)
+
it('createFile does not touch file if it exists and ignoreIfExists is set', function()
local tmpfile = tmpname()
write_file(tmpfile, 'Dummy content')
@@ -2342,6 +2529,7 @@ describe('LSP', function()
eq(true, vim.uv.fs_stat(tmpfile) ~= nil)
eq('Dummy content', read_file(tmpfile))
end)
+
it('createFile overrides file if overwrite is set', function()
local tmpfile = tmpname()
write_file(tmpfile, 'Dummy content')
@@ -2362,18 +2550,15 @@ describe('LSP', function()
eq(true, vim.uv.fs_stat(tmpfile) ~= nil)
eq('', read_file(tmpfile))
end)
+
it('DeleteFile delete file and buffer', function()
local tmpfile = tmpname()
write_file(tmpfile, 'Be gone')
- local uri = exec_lua(
- [[
- local fname = select(1, ...)
- local bufnr = vim.fn.bufadd(fname)
+ local uri = exec_lua(function()
+ local bufnr = vim.fn.bufadd(tmpfile)
vim.fn.bufload(bufnr)
- return vim.uri_from_fname(fname)
- ]],
- tmpfile
- )
+ return vim.uri_from_fname(tmpfile)
+ end)
local edit = {
documentChanges = {
{
@@ -2386,9 +2571,9 @@ describe('LSP', function()
eq(false, vim.uv.fs_stat(tmpfile) ~= nil)
eq(false, api.nvim_buf_is_loaded(fn.bufadd(tmpfile)))
end)
+
it('DeleteFile fails if file does not exist and ignoreIfNotExists is false', function()
- local tmpfile = tmpname()
- os.remove(tmpfile)
+ local tmpfile = tmpname(false)
local uri = exec_lua('return vim.uri_from_fname(...)', tmpfile)
local edit = {
documentChanges = {
@@ -2412,12 +2597,8 @@ describe('LSP', function()
it('Can rename an existing file', function()
local old = tmpname()
write_file(old, 'Test content')
- local new = tmpname()
- os.remove(new) -- only reserve the name, file must not exist for the test scenario
- local lines = exec_lua(
- [[
- local old = select(1, ...)
- local new = select(2, ...)
+ local new = tmpname(false)
+ local lines = exec_lua(function()
local old_bufnr = vim.fn.bufadd(old)
vim.fn.bufload(old_bufnr)
vim.lsp.util.rename(old, new)
@@ -2425,10 +2606,7 @@ describe('LSP', function()
local new_bufnr = vim.fn.bufadd(new)
vim.fn.bufload(new_bufnr)
return (old_bufnr == new_bufnr) and vim.api.nvim_buf_get_lines(new_bufnr, 0, -1, true)
- ]],
- old,
- new
- )
+ end)
eq({ 'Test content' }, lines)
local exists = vim.uv.fs_stat(old) ~= nil
eq(false, exists)
@@ -2436,24 +2614,18 @@ describe('LSP', function()
eq(true, exists)
os.remove(new)
end)
+
it('Can rename a directory', function()
-- only reserve the name, file must not exist for the test scenario
- local old_dir = tmpname()
- local new_dir = tmpname()
- os.remove(old_dir)
- os.remove(new_dir)
+ local old_dir = tmpname(false)
+ local new_dir = tmpname(false)
n.mkdir_p(old_dir)
local file = 'file.txt'
write_file(old_dir .. pathsep .. file, 'Test content')
- local lines = exec_lua(
- [[
- local old_dir = select(1, ...)
- local new_dir = select(2, ...)
- local pathsep = select(3, ...)
- local file = select(4, ...)
+ local lines = exec_lua(function()
local old_bufnr = vim.fn.bufadd(old_dir .. pathsep .. file)
vim.fn.bufload(old_bufnr)
vim.lsp.util.rename(old_dir, new_dir)
@@ -2461,12 +2633,7 @@ describe('LSP', function()
local new_bufnr = vim.fn.bufadd(new_dir .. pathsep .. file)
vim.fn.bufload(new_bufnr)
return (old_bufnr == new_bufnr) and vim.api.nvim_buf_get_lines(new_bufnr, 0, -1, true)
- ]],
- old_dir,
- new_dir,
- pathsep,
- file
- )
+ end)
eq({ 'Test content' }, lines)
eq(false, vim.uv.fs_stat(old_dir) ~= nil)
eq(true, vim.uv.fs_stat(new_dir) ~= nil)
@@ -2474,47 +2641,41 @@ describe('LSP', function()
os.remove(new_dir)
end)
+
it('Does not touch buffers that do not match path prefix', function()
- local old = tmpname()
- local new = tmpname()
- os.remove(old)
- os.remove(new)
+ local old = tmpname(false)
+ local new = tmpname(false)
n.mkdir_p(old)
- local result = exec_lua(
- [[
- local old = select(1, ...)
- local new = select(2, ...)
-
- local old_prefixed = 'explorer://' .. old
- local old_suffixed = old .. '.bak'
- local new_prefixed = 'explorer://' .. new
- local new_suffixed = new .. '.bak'
+ eq(
+ true,
+ exec_lua(function()
+ local old_prefixed = 'explorer://' .. old
+ local old_suffixed = old .. '.bak'
+ local new_prefixed = 'explorer://' .. new
+ local new_suffixed = new .. '.bak'
- local old_prefixed_buf = vim.fn.bufadd(old_prefixed)
- local old_suffixed_buf = vim.fn.bufadd(old_suffixed)
- local new_prefixed_buf = vim.fn.bufadd(new_prefixed)
- local new_suffixed_buf = vim.fn.bufadd(new_suffixed)
+ local old_prefixed_buf = vim.fn.bufadd(old_prefixed)
+ local old_suffixed_buf = vim.fn.bufadd(old_suffixed)
+ local new_prefixed_buf = vim.fn.bufadd(new_prefixed)
+ local new_suffixed_buf = vim.fn.bufadd(new_suffixed)
- vim.lsp.util.rename(old, new)
+ vim.lsp.util.rename(old, new)
- return
- vim.api.nvim_buf_is_valid(old_prefixed_buf) and
- vim.api.nvim_buf_is_valid(old_suffixed_buf) and
- vim.api.nvim_buf_is_valid(new_prefixed_buf) and
- vim.api.nvim_buf_is_valid(new_suffixed_buf) and
- vim.api.nvim_buf_get_name(old_prefixed_buf) == old_prefixed and
- vim.api.nvim_buf_get_name(old_suffixed_buf) == old_suffixed and
- vim.api.nvim_buf_get_name(new_prefixed_buf) == new_prefixed and
- vim.api.nvim_buf_get_name(new_suffixed_buf) == new_suffixed
- ]],
- old,
- new
+ return vim.api.nvim_buf_is_valid(old_prefixed_buf)
+ and vim.api.nvim_buf_is_valid(old_suffixed_buf)
+ and vim.api.nvim_buf_is_valid(new_prefixed_buf)
+ and vim.api.nvim_buf_is_valid(new_suffixed_buf)
+ and vim.api.nvim_buf_get_name(old_prefixed_buf) == old_prefixed
+ and vim.api.nvim_buf_get_name(old_suffixed_buf) == old_suffixed
+ and vim.api.nvim_buf_get_name(new_prefixed_buf) == new_prefixed
+ and vim.api.nvim_buf_get_name(new_suffixed_buf) == new_suffixed
+ end)
)
- eq(true, result)
os.remove(new)
end)
+
it(
'Does not rename file if target exists and ignoreIfExists is set or overwrite is false',
function()
@@ -2523,45 +2684,28 @@ describe('LSP', function()
local new = tmpname()
write_file(new, 'New file')
- exec_lua(
- [[
- local old = select(1, ...)
- local new = select(2, ...)
-
- vim.lsp.util.rename(old, new, { ignoreIfExists = true })
- ]],
- old,
- new
- )
+ exec_lua(function()
+ vim.lsp.util.rename(old, new, { ignoreIfExists = true })
+ end)
eq(true, vim.uv.fs_stat(old) ~= nil)
eq('New file', read_file(new))
- exec_lua(
- [[
- local old = select(1, ...)
- local new = select(2, ...)
-
- vim.lsp.util.rename(old, new, { overwrite = false })
- ]],
- old,
- new
- )
+ exec_lua(function()
+ vim.lsp.util.rename(old, new, { overwrite = false })
+ end)
eq(true, vim.uv.fs_stat(old) ~= nil)
eq('New file', read_file(new))
end
)
+
it('Maintains undo information for loaded buffer', function()
local old = tmpname()
write_file(old, 'line')
- local new = tmpname()
- os.remove(new)
+ local new = tmpname(false)
- local undo_kept = exec_lua(
- [[
- local old = select(1, ...)
- local new = select(2, ...)
+ local undo_kept = exec_lua(function()
vim.opt.undofile = true
vim.cmd.edit(old)
vim.cmd.normal('dd')
@@ -2574,24 +2718,18 @@ describe('LSP', function()
undotree.save_last = undotree.save_last + 1
undotree.entries[1].save = undotree.entries[1].save + 1
return vim.deep_equal(undotree, vim.fn.undotree())
- ]],
- old,
- new
- )
+ end)
eq(false, vim.uv.fs_stat(old) ~= nil)
eq(true, vim.uv.fs_stat(new) ~= nil)
eq(true, undo_kept)
end)
+
it('Maintains undo information for unloaded buffer', function()
local old = tmpname()
write_file(old, 'line')
- local new = tmpname()
- os.remove(new)
+ local new = tmpname(false)
- local undo_kept = exec_lua(
- [[
- local old = select(1, ...)
- local new = select(2, ...)
+ local undo_kept = exec_lua(function()
vim.opt.undofile = true
vim.cmd.split(old)
vim.cmd.normal('dd')
@@ -2601,54 +2739,39 @@ describe('LSP', function()
vim.lsp.util.rename(old, new)
vim.cmd.edit(new)
return vim.deep_equal(undotree, vim.fn.undotree())
- ]],
- old,
- new
- )
+ end)
eq(false, vim.uv.fs_stat(old) ~= nil)
eq(true, vim.uv.fs_stat(new) ~= nil)
eq(true, undo_kept)
end)
+
it('Does not rename file when it conflicts with a buffer without file', function()
local old = tmpname()
write_file(old, 'Old File')
- local new = tmpname()
- os.remove(new)
-
- local lines = exec_lua(
- [[
- local old = select(1, ...)
- local new = select(2, ...)
- local old_buf = vim.fn.bufadd(old)
- vim.fn.bufload(old_buf)
- local conflict_buf = vim.api.nvim_create_buf(true, false)
- vim.api.nvim_buf_set_name(conflict_buf, new)
- vim.api.nvim_buf_set_lines(conflict_buf, 0, -1, true, {'conflict'})
- vim.api.nvim_win_set_buf(0, conflict_buf)
- vim.lsp.util.rename(old, new)
- return vim.api.nvim_buf_get_lines(conflict_buf, 0, -1, true)
- ]],
- old,
- new
- )
+ local new = tmpname(false)
+
+ local lines = exec_lua(function()
+ local old_buf = vim.fn.bufadd(old)
+ vim.fn.bufload(old_buf)
+ local conflict_buf = vim.api.nvim_create_buf(true, false)
+ vim.api.nvim_buf_set_name(conflict_buf, new)
+ vim.api.nvim_buf_set_lines(conflict_buf, 0, -1, true, { 'conflict' })
+ vim.api.nvim_win_set_buf(0, conflict_buf)
+ vim.lsp.util.rename(old, new)
+ return vim.api.nvim_buf_get_lines(conflict_buf, 0, -1, true)
+ end)
eq({ 'conflict' }, lines)
eq('Old File', read_file(old))
end)
+
it('Does override target if overwrite is true', function()
local old = tmpname()
write_file(old, 'Old file')
local new = tmpname()
write_file(new, 'New file')
- exec_lua(
- [[
- local old = select(1, ...)
- local new = select(2, ...)
-
+ exec_lua(function()
vim.lsp.util.rename(old, new, { overwrite = true })
- ]],
- old,
- new
- )
+ end)
eq(false, vim.uv.fs_stat(old) ~= nil)
eq(true, vim.uv.fs_stat(new) ~= nil)
@@ -2658,44 +2781,59 @@ describe('LSP', function()
describe('lsp.util.locations_to_items', function()
it('Convert Location[] to items', function()
- local expected = {
+ local expected_template = {
{
filename = '/fake/uri',
lnum = 1,
+ end_lnum = 2,
col = 3,
+ end_col = 4,
text = 'testing',
- user_data = {
+ user_data = {},
+ },
+ }
+ local test_params = {
+ {
+ {
uri = 'file:///fake/uri',
range = {
start = { line = 0, character = 2 },
- ['end'] = { line = 0, character = 3 },
+ ['end'] = { line = 1, character = 3 },
},
},
},
- }
- local actual = exec_lua [[
- local bufnr = vim.uri_to_bufnr("file:///fake/uri")
- local lines = {"testing", "123"}
- vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines)
- local locations = {
+ {
{
uri = 'file:///fake/uri',
range = {
start = { line = 0, character = 2 },
- ['end'] = { line = 0, character = 3 },
- }
+ -- LSP spec: if character > line length, default to the line length.
+ ['end'] = { line = 1, character = 10000 },
+ },
},
- }
- return vim.lsp.util.locations_to_items(locations, 'utf-16')
- ]]
- eq(expected, actual)
+ },
+ }
+ for _, params in ipairs(test_params) do
+ local actual = exec_lua(function(params0)
+ local bufnr = vim.uri_to_bufnr('file:///fake/uri')
+ local lines = { 'testing', '123' }
+ vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines)
+ return vim.lsp.util.locations_to_items(params0, 'utf-16')
+ end, params)
+ local expected = vim.deepcopy(expected_template)
+ expected[1].user_data = params[1]
+ eq(expected, actual)
+ end
end)
+
it('Convert LocationLink[] to items', function()
local expected = {
{
filename = '/fake/uri',
lnum = 1,
+ end_lnum = 1,
col = 3,
+ end_col = 4,
text = 'testing',
user_data = {
targetUri = 'file:///fake/uri',
@@ -2710,9 +2848,9 @@ describe('LSP', function()
},
},
}
- local actual = exec_lua [[
- local bufnr = vim.uri_to_bufnr("file:///fake/uri")
- local lines = {"testing", "123"}
+ local actual = exec_lua(function()
+ local bufnr = vim.uri_to_bufnr('file:///fake/uri')
+ local lines = { 'testing', '123' }
vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines)
local locations = {
{
@@ -2724,11 +2862,11 @@ describe('LSP', function()
targetSelectionRange = {
start = { line = 0, character = 2 },
['end'] = { line = 0, character = 3 },
- }
+ },
},
}
return vim.lsp.util.locations_to_items(locations, 'utf-16')
- ]]
+ end)
eq(expected, actual)
end)
end)
@@ -2761,94 +2899,95 @@ describe('LSP', function()
}
eq(
expected,
- exec_lua [[
- local doc_syms = {
- {
- deprecated = false,
- detail = "A",
- kind = 1,
- name = "TestA",
- range = {
- start = {
- character = 0,
- line = 1
+ exec_lua(function()
+ local doc_syms = {
+ {
+ deprecated = false,
+ detail = 'A',
+ kind = 1,
+ name = 'TestA',
+ range = {
+ start = {
+ character = 0,
+ line = 1,
+ },
+ ['end'] = {
+ character = 0,
+ line = 2,
+ },
},
- ["end"] = {
- character = 0,
- line = 2
- }
- },
- selectionRange = {
- start = {
- character = 0,
- line = 1
+ selectionRange = {
+ start = {
+ character = 0,
+ line = 1,
+ },
+ ['end'] = {
+ character = 4,
+ line = 1,
+ },
},
- ["end"] = {
- character = 4,
- line = 1
- }
- },
- children = {
- {
- children = {},
- deprecated = false,
- detail = "B",
- kind = 2,
- name = "TestB",
- range = {
- start = {
- character = 0,
- line = 3
+ children = {
+ {
+ children = {},
+ deprecated = false,
+ detail = 'B',
+ kind = 2,
+ name = 'TestB',
+ range = {
+ start = {
+ character = 0,
+ line = 3,
+ },
+ ['end'] = {
+ character = 0,
+ line = 4,
+ },
},
- ["end"] = {
- character = 0,
- line = 4
- }
- },
- selectionRange = {
- start = {
- character = 0,
- line = 3
+ selectionRange = {
+ start = {
+ character = 0,
+ line = 3,
+ },
+ ['end'] = {
+ character = 4,
+ line = 3,
+ },
},
- ["end"] = {
- character = 4,
- line = 3
- }
- }
- }
- }
- },
- {
- deprecated = false,
- detail = "C",
- kind = 3,
- name = "TestC",
- range = {
- start = {
- character = 0,
- line = 5
+ },
},
- ["end"] = {
- character = 0,
- line = 6
- }
},
- selectionRange = {
- start = {
- character = 0,
- line = 5
+ {
+ deprecated = false,
+ detail = 'C',
+ kind = 3,
+ name = 'TestC',
+ range = {
+ start = {
+ character = 0,
+ line = 5,
+ },
+ ['end'] = {
+ character = 0,
+ line = 6,
+ },
},
- ["end"] = {
- character = 4,
- line = 5
- }
- }
+ selectionRange = {
+ start = {
+ character = 0,
+ line = 5,
+ },
+ ['end'] = {
+ character = 4,
+ line = 5,
+ },
+ },
+ },
}
- }
- return vim.lsp.util.symbols_to_items(doc_syms, nil)
- ]]
+ return vim.lsp.util.symbols_to_items(doc_syms, nil)
+ end)
)
end)
+
it('DocumentSymbol has no children', function()
local expected = {
{
@@ -2868,66 +3007,67 @@ describe('LSP', function()
}
eq(
expected,
- exec_lua [[
- local doc_syms = {
- {
- deprecated = false,
- detail = "A",
- kind = 1,
- name = "TestA",
- range = {
- start = {
- character = 0,
- line = 1
+ exec_lua(function()
+ local doc_syms = {
+ {
+ deprecated = false,
+ detail = 'A',
+ kind = 1,
+ name = 'TestA',
+ range = {
+ start = {
+ character = 0,
+ line = 1,
+ },
+ ['end'] = {
+ character = 0,
+ line = 2,
+ },
},
- ["end"] = {
- character = 0,
- line = 2
- }
- },
- selectionRange = {
- start = {
- character = 0,
- line = 1
+ selectionRange = {
+ start = {
+ character = 0,
+ line = 1,
+ },
+ ['end'] = {
+ character = 4,
+ line = 1,
+ },
},
- ["end"] = {
- character = 4,
- line = 1
- }
},
- },
- {
- deprecated = false,
- detail = "C",
- kind = 3,
- name = "TestC",
- range = {
- start = {
- character = 0,
- line = 5
+ {
+ deprecated = false,
+ detail = 'C',
+ kind = 3,
+ name = 'TestC',
+ range = {
+ start = {
+ character = 0,
+ line = 5,
+ },
+ ['end'] = {
+ character = 0,
+ line = 6,
+ },
},
- ["end"] = {
- character = 0,
- line = 6
- }
- },
- selectionRange = {
- start = {
- character = 0,
- line = 5
+ selectionRange = {
+ start = {
+ character = 0,
+ line = 5,
+ },
+ ['end'] = {
+ character = 4,
+ line = 5,
+ },
},
- ["end"] = {
- character = 4,
- line = 5
- }
- }
+ },
}
- }
- return vim.lsp.util.symbols_to_items(doc_syms, nil)
- ]]
+ return vim.lsp.util.symbols_to_items(doc_syms, nil)
+ end)
)
end)
end)
+
it('convert SymbolInformation[] to items', function()
local expected = {
{
@@ -2947,62 +3087,88 @@ describe('LSP', function()
}
eq(
expected,
- exec_lua [[
+ exec_lua(function()
local sym_info = {
{
deprecated = false,
kind = 1,
- name = "TestA",
+ name = 'TestA',
location = {
range = {
start = {
character = 0,
- line = 1
+ line = 1,
},
- ["end"] = {
+ ['end'] = {
character = 0,
- line = 2
- }
+ line = 2,
+ },
},
- uri = "file:///test_a"
+ uri = 'file:///test_a',
},
- containerName = "TestAContainer"
+ containerName = 'TestAContainer',
},
{
deprecated = false,
kind = 2,
- name = "TestB",
+ name = 'TestB',
location = {
range = {
start = {
character = 0,
- line = 3
+ line = 3,
},
- ["end"] = {
+ ['end'] = {
character = 0,
- line = 4
- }
+ line = 4,
+ },
},
- uri = "file:///test_b"
+ uri = 'file:///test_b',
},
- containerName = "TestBContainer"
- }
+ containerName = 'TestBContainer',
+ },
}
return vim.lsp.util.symbols_to_items(sym_info, nil)
- ]]
+ end)
)
end)
end)
describe('lsp.util._get_symbol_kind_name', function()
it('returns the name specified by protocol', function()
- eq('File', exec_lua('return vim.lsp.util._get_symbol_kind_name(1)'))
- eq('TypeParameter', exec_lua('return vim.lsp.util._get_symbol_kind_name(26)'))
+ eq(
+ 'File',
+ exec_lua(function()
+ return vim.lsp.util._get_symbol_kind_name(1)
+ end)
+ )
+ eq(
+ 'TypeParameter',
+ exec_lua(function()
+ return vim.lsp.util._get_symbol_kind_name(26)
+ end)
+ )
end)
+
it('returns the name not specified by protocol', function()
- eq('Unknown', exec_lua('return vim.lsp.util._get_symbol_kind_name(nil)'))
- eq('Unknown', exec_lua('return vim.lsp.util._get_symbol_kind_name(vim.NIL)'))
- eq('Unknown', exec_lua('return vim.lsp.util._get_symbol_kind_name(1000)'))
+ eq(
+ 'Unknown',
+ exec_lua(function()
+ return vim.lsp.util._get_symbol_kind_name(nil)
+ end)
+ )
+ eq(
+ 'Unknown',
+ exec_lua(function()
+ return vim.lsp.util._get_symbol_kind_name(vim.NIL)
+ end)
+ )
+ eq(
+ 'Unknown',
+ exec_lua(function()
+ return vim.lsp.util._get_symbol_kind_name(1000)
+ end)
+ )
end)
end)
@@ -3010,12 +3176,12 @@ describe('LSP', function()
local target_bufnr --- @type integer
before_each(function()
- target_bufnr = exec_lua [[
- local bufnr = vim.uri_to_bufnr("file:///fake/uri")
- local lines = {"1st line of text", "å å ɧ 汉语 ↥ 🤦 🦄"}
+ target_bufnr = exec_lua(function()
+ local bufnr = vim.uri_to_bufnr('file:///fake/uri')
+ local lines = { '1st line of text', 'å å ɧ 汉语 ↥ 🤦 🦄' }
vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines)
return bufnr
- ]]
+ end)
end)
local location = function(start_line, start_char, end_line, end_char)
@@ -3084,19 +3250,19 @@ describe('LSP', function()
local target_bufnr2 --- @type integer
before_each(function()
- target_bufnr = exec_lua([[
- local bufnr = vim.uri_to_bufnr("file:///fake/uri")
- local lines = {"1st line of text", "å å ɧ 汉语 ↥ 🤦 🦄"}
+ target_bufnr = exec_lua(function()
+ local bufnr = vim.uri_to_bufnr('file:///fake/uri')
+ local lines = { '1st line of text', 'å å ɧ 汉语 ↥ 🤦 🦄' }
vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines)
return bufnr
- ]])
+ end)
- target_bufnr2 = exec_lua([[
- local bufnr = vim.uri_to_bufnr("file:///fake/uri2")
- local lines = {"1st line of text", "å å ɧ 汉语 ↥ 🤦 🦄"}
+ target_bufnr2 = exec_lua(function()
+ local bufnr = vim.uri_to_bufnr('file:///fake/uri2')
+ local lines = { '1st line of text', 'å å ɧ 汉语 ↥ 🤦 🦄' }
vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines)
return bufnr
- ]])
+ end)
end)
local location = function(start_line, start_char, end_line, end_char, second_uri)
@@ -3136,14 +3302,14 @@ describe('LSP', function()
it('jumps to a Location if focus is true via handler', function()
exec_lua(create_server_definition)
- local result = exec_lua([[
- local server = _create_server()
- local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
+ local result = exec_lua(function()
+ local server = _G._create_server()
+ local client_id = assert(vim.lsp.start({ name = 'dummy', cmd = server.cmd }))
local result = {
uri = 'file:///fake/uri',
selection = {
start = { line = 0, character = 9 },
- ['end'] = { line = 0, character = 9 }
+ ['end'] = { line = 0, character = 9 },
},
takeFocus = true,
}
@@ -3154,9 +3320,9 @@ describe('LSP', function()
vim.lsp.handlers['window/showDocument'](nil, result, ctx)
vim.lsp.stop_client(client_id)
return {
- cursor = vim.api.nvim_win_get_cursor(0)
+ cursor = vim.api.nvim_win_get_cursor(0),
}
- ]])
+ end)
eq(1, result.cursor[1])
eq(9, result.cursor[2])
end)
@@ -3231,7 +3397,9 @@ describe('LSP', function()
api.nvim_win_set_buf(0, target_bufnr)
api.nvim_win_set_cursor(0, { 2, 3 })
- exec_lua([[vim.cmd.new()]])
+ exec_lua(function()
+ vim.cmd.new()
+ end)
api.nvim_win_set_buf(0, target_bufnr2)
api.nvim_win_set_cursor(0, { 2, 3 })
@@ -3247,7 +3415,9 @@ describe('LSP', function()
api.nvim_win_set_buf(0, target_bufnr)
local win = api.nvim_get_current_win()
- exec_lua([[vim.cmd.new()]])
+ exec_lua(function()
+ vim.cmd.new()
+ end)
api.nvim_win_set_buf(0, target_bufnr2)
api.nvim_win_set_cursor(0, { 2, 3 })
local split = api.nvim_get_current_win()
@@ -3268,34 +3438,53 @@ describe('LSP', function()
describe('lsp.util._make_floating_popup_size', function()
before_each(function()
- exec_lua [[ contents =
- {"text tαxt txtα tex",
- "text tααt tααt text",
- "text tαxt tαxt"}
- ]]
+ exec_lua(function()
+ _G.contents = { 'text tαxt txtα tex', 'text tααt tααt text', 'text tαxt tαxt' }
+ end)
end)
it('calculates size correctly', function()
- eq({ 19, 3 }, exec_lua [[ return {vim.lsp.util._make_floating_popup_size(contents)} ]])
+ eq(
+ { 19, 3 },
+ exec_lua(function()
+ return { vim.lsp.util._make_floating_popup_size(_G.contents) }
+ end)
+ )
end)
it('calculates size correctly with wrapping', function()
eq(
{ 15, 5 },
- exec_lua [[ return {vim.lsp.util._make_floating_popup_size(contents,{width = 15, wrap_at = 14})} ]]
+ exec_lua(function()
+ return {
+ vim.lsp.util._make_floating_popup_size(_G.contents, { width = 15, wrap_at = 14 }),
+ }
+ end)
)
end)
it('handles NUL bytes in text', function()
- exec_lua([[ contents = {
- '\000\001\002\003\004\005\006\007\008\009',
- '\010\011\012\013\014\015\016\017\018\019',
- '\020\021\022\023\024\025\026\027\028\029',
- } ]])
+ exec_lua(function()
+ _G.contents = {
+ '\000\001\002\003\004\005\006\007\008\009',
+ '\010\011\012\013\014\015\016\017\018\019',
+ '\020\021\022\023\024\025\026\027\028\029',
+ }
+ end)
command('set list listchars=')
- eq({ 20, 3 }, exec_lua [[ return {vim.lsp.util._make_floating_popup_size(contents)} ]])
+ eq(
+ { 20, 3 },
+ exec_lua(function()
+ return { vim.lsp.util._make_floating_popup_size(_G.contents) }
+ end)
+ )
command('set display+=uhex')
- eq({ 40, 3 }, exec_lua [[ return {vim.lsp.util._make_floating_popup_size(contents)} ]])
+ eq(
+ { 40, 3 },
+ exec_lua(function()
+ return { vim.lsp.util._make_floating_popup_size(_G.contents) }
+ end)
+ )
end)
end)
@@ -3303,27 +3492,30 @@ describe('LSP', function()
it('properly trims empty lines', function()
eq(
{ { 'foo', 'bar' } },
- exec_lua [[ return vim.lsp.util.trim_empty_lines({{ "foo", "bar" }, nil}) ]]
+ exec_lua(function()
+ --- @diagnostic disable-next-line:deprecated
+ return vim.lsp.util.trim_empty_lines({ { 'foo', 'bar' }, nil })
+ end)
)
end)
end)
describe('lsp.util.convert_signature_help_to_markdown_lines', function()
it('can handle negative activeSignature', function()
- local result = exec_lua [[
+ local result = exec_lua(function()
local signature_help = {
activeParameter = 0,
activeSignature = -1,
signatures = {
{
- documentation = "some doc",
- label = "TestEntity.TestEntity()",
- parameters = {}
+ documentation = 'some doc',
+ label = 'TestEntity.TestEntity()',
+ parameters = {},
},
- }
+ },
}
- return vim.lsp.util.convert_signature_help_to_markdown_lines(signature_help, 'cs', {','})
- ]]
+ return vim.lsp.util.convert_signature_help_to_markdown_lines(signature_help, 'cs', { ',' })
+ end)
local expected = { '```cs', 'TestEntity.TestEntity()', '```', 'some doc' }
eq(expected, result)
end)
@@ -3338,12 +3530,18 @@ describe('LSP', function()
]],
shiftwidth
))
- eq(tabsize, exec_lua('return vim.lsp.util.get_effective_tabstop()'))
+ eq(
+ tabsize,
+ exec_lua(function()
+ return vim.lsp.util.get_effective_tabstop()
+ end)
+ )
end
it('with shiftwidth = 1', function()
test_tabstop(1, 1)
end)
+
it('with shiftwidth = 0', function()
test_tabstop(2, 0)
end)
@@ -3351,57 +3549,61 @@ describe('LSP', function()
describe('vim.lsp.buf.outgoing_calls', function()
it('does nothing for an empty response', function()
- local qflist_count = exec_lua([=[
- require'vim.lsp.handlers'['callHierarchy/outgoingCalls'](nil, nil, {}, nil)
+ local qflist_count = exec_lua(function()
+ require 'vim.lsp.handlers'['callHierarchy/outgoingCalls'](nil, nil, {}, nil)
return #vim.fn.getqflist()
- ]=])
+ end)
eq(0, qflist_count)
end)
it('opens the quickfix list with the right caller', function()
- local qflist = exec_lua([=[
- local rust_analyzer_response = { {
- fromRanges = { {
- ['end'] = {
- character = 7,
- line = 3
- },
- start = {
- character = 4,
- line = 3
- }
- } },
- to = {
- detail = "fn foo()",
- kind = 12,
- name = "foo",
- range = {
- ['end'] = {
- character = 11,
- line = 0
+ local qflist = exec_lua(function()
+ local rust_analyzer_response = {
+ {
+ fromRanges = {
+ {
+ ['end'] = {
+ character = 7,
+ line = 3,
+ },
+ start = {
+ character = 4,
+ line = 3,
+ },
},
- start = {
- character = 0,
- line = 0
- }
},
- selectionRange = {
- ['end'] = {
- character = 6,
- line = 0
+ to = {
+ detail = 'fn foo()',
+ kind = 12,
+ name = 'foo',
+ range = {
+ ['end'] = {
+ character = 11,
+ line = 0,
+ },
+ start = {
+ character = 0,
+ line = 0,
+ },
},
- start = {
- character = 3,
- line = 0
- }
+ selectionRange = {
+ ['end'] = {
+ character = 6,
+ line = 0,
+ },
+ start = {
+ character = 3,
+ line = 0,
+ },
+ },
+ uri = 'file:///src/main.rs',
},
- uri = "file:///src/main.rs"
- }
- } }
- local handler = require'vim.lsp.handlers'['callHierarchy/outgoingCalls']
+ },
+ }
+ local handler = require 'vim.lsp.handlers'['callHierarchy/outgoingCalls']
handler(nil, rust_analyzer_response, {})
return vim.fn.getqflist()
- ]=])
+ end)
local expected = {
{
@@ -3426,58 +3628,62 @@ describe('LSP', function()
describe('vim.lsp.buf.incoming_calls', function()
it('does nothing for an empty response', function()
- local qflist_count = exec_lua([=[
- require'vim.lsp.handlers'['callHierarchy/incomingCalls'](nil, nil, {})
+ local qflist_count = exec_lua(function()
+ require 'vim.lsp.handlers'['callHierarchy/incomingCalls'](nil, nil, {})
return #vim.fn.getqflist()
- ]=])
+ end)
eq(0, qflist_count)
end)
it('opens the quickfix list with the right callee', function()
- local qflist = exec_lua([=[
- local rust_analyzer_response = { {
- from = {
- detail = "fn main()",
- kind = 12,
- name = "main",
- range = {
- ['end'] = {
- character = 1,
- line = 4
+ local qflist = exec_lua(function()
+ local rust_analyzer_response = {
+ {
+ from = {
+ detail = 'fn main()',
+ kind = 12,
+ name = 'main',
+ range = {
+ ['end'] = {
+ character = 1,
+ line = 4,
+ },
+ start = {
+ character = 0,
+ line = 2,
+ },
},
- start = {
- character = 0,
- line = 2
- }
+ selectionRange = {
+ ['end'] = {
+ character = 7,
+ line = 2,
+ },
+ start = {
+ character = 3,
+ line = 2,
+ },
+ },
+ uri = 'file:///src/main.rs',
},
- selectionRange = {
- ['end'] = {
- character = 7,
- line = 2
+ fromRanges = {
+ {
+ ['end'] = {
+ character = 7,
+ line = 3,
+ },
+ start = {
+ character = 4,
+ line = 3,
+ },
},
- start = {
- character = 3,
- line = 2
- }
},
- uri = "file:///src/main.rs"
},
- fromRanges = { {
- ['end'] = {
- character = 7,
- line = 3
- },
- start = {
- character = 4,
- line = 3
- }
- } }
- } }
+ }
- local handler = require'vim.lsp.handlers'['callHierarchy/incomingCalls']
+ local handler = require 'vim.lsp.handlers'['callHierarchy/incomingCalls']
handler(nil, rust_analyzer_response, {})
return vim.fn.getqflist()
- ]=])
+ end)
local expected = {
{
@@ -3502,103 +3708,126 @@ describe('LSP', function()
describe('vim.lsp.buf.typehierarchy subtypes', function()
it('does nothing for an empty response', function()
- local qflist_count = exec_lua([=[
- require'vim.lsp.handlers'['typeHierarchy/subtypes'](nil, nil, {})
+ local qflist_count = exec_lua(function()
+ require 'vim.lsp.handlers'['typeHierarchy/subtypes'](nil, nil, {})
return #vim.fn.getqflist()
- ]=])
+ end)
eq(0, qflist_count)
end)
it('opens the quickfix list with the right subtypes', function()
clear()
exec_lua(create_server_definition)
- local qflist = exec_lua([=[
- local clangd_response = { {
- data = {
- parents = { {
- parents = { {
- parents = { {
- parents = {},
- symbolID = "62B3D268A01B9978"
- } },
- symbolID = "DC9B0AD433B43BEC"
- } },
- symbolID = "06B5F6A19BA9F6A8"
- } },
- symbolID = "EDC336589C09ABB2"
- },
- kind = 5,
- name = "D2",
- range = {
- ["end"] = {
- character = 8,
- line = 9
+ local qflist = exec_lua(function()
+ local clangd_response = {
+ {
+ data = {
+ parents = {
+ {
+ parents = {
+ {
+ parents = {
+ {
+ parents = {},
+ symbolID = '62B3D268A01B9978',
+ },
+ },
+ symbolID = 'DC9B0AD433B43BEC',
+ },
+ },
+ symbolID = '06B5F6A19BA9F6A8',
+ },
+ },
+ symbolID = 'EDC336589C09ABB2',
},
- start = {
- character = 6,
- line = 9
- }
- },
- selectionRange = {
- ["end"] = {
- character = 8,
- line = 9
+ kind = 5,
+ name = 'D2',
+ range = {
+ ['end'] = {
+ character = 8,
+ line = 3,
+ },
+ start = {
+ character = 6,
+ line = 3,
+ },
},
- start = {
- character = 6,
- line = 9
- }
- },
- uri = "file:///home/jiangyinzuo/hello.cpp"
- }, {
- data = {
- parents = { {
- parents = { {
- parents = { {
- parents = {},
- symbolID = "62B3D268A01B9978"
- } },
- symbolID = "DC9B0AD433B43BEC"
- } },
- symbolID = "06B5F6A19BA9F6A8"
- } },
- symbolID = "AFFCAED15557EF08"
- },
- kind = 5,
- name = "D1",
- range = {
- ["end"] = {
- character = 8,
- line = 8
+ selectionRange = {
+ ['end'] = {
+ character = 8,
+ line = 3,
+ },
+ start = {
+ character = 6,
+ line = 3,
+ },
},
- start = {
- character = 6,
- line = 8
- }
+ uri = 'file:///home/jiangyinzuo/hello.cpp',
},
- selectionRange = {
- ["end"] = {
- character = 8,
- line = 8
+ {
+ data = {
+ parents = {
+ {
+ parents = {
+ {
+ parents = {
+ {
+ parents = {},
+ symbolID = '62B3D268A01B9978',
+ },
+ },
+ symbolID = 'DC9B0AD433B43BEC',
+ },
+ },
+ symbolID = '06B5F6A19BA9F6A8',
+ },
+ },
+ symbolID = 'AFFCAED15557EF08',
},
- start = {
- character = 6,
- line = 8
- }
+ kind = 5,
+ name = 'D1',
+ range = {
+ ['end'] = {
+ character = 8,
+ line = 2,
+ },
+ start = {
+ character = 6,
+ line = 2,
+ },
+ },
+ selectionRange = {
+ ['end'] = {
+ character = 8,
+ line = 2,
+ },
+ start = {
+ character = 6,
+ line = 2,
+ },
+ },
+ uri = 'file:///home/jiangyinzuo/hello.cpp',
},
- uri = "file:///home/jiangyinzuo/hello.cpp"
- } }
+ }
- local server = _create_server({
+ local server = _G._create_server({
capabilities = {
- positionEncoding = "utf-8"
+ positionEncoding = 'utf-8',
},
})
local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
- local handler = require'vim.lsp.handlers'['typeHierarchy/subtypes']
- handler(nil, clangd_response, { client_id = client_id, bufnr = 1 })
+ local handler = require 'vim.lsp.handlers'['typeHierarchy/subtypes']
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {
+ 'class B : public A{};',
+ 'class C : public B{};',
+ 'class D1 : public C{};',
+ 'class D2 : public C{};',
+ 'class E : public D1, D2 {};',
+ })
+ handler(nil, clangd_response, { client_id = client_id, bufnr = bufnr })
return vim.fn.getqflist()
- ]=])
+ end)
local expected = {
{
@@ -3606,7 +3835,7 @@ describe('LSP', function()
col = 7,
end_col = 0,
end_lnum = 0,
- lnum = 10,
+ lnum = 4,
module = '',
nr = 0,
pattern = '',
@@ -3620,7 +3849,7 @@ describe('LSP', function()
col = 7,
end_col = 0,
end_lnum = 0,
- lnum = 9,
+ lnum = 3,
module = '',
nr = 0,
pattern = '',
@@ -3637,7 +3866,7 @@ describe('LSP', function()
it('opens the quickfix list with the right subtypes and details', function()
clear()
exec_lua(create_server_definition)
- local qflist = exec_lua([=[
+ local qflist = exec_lua(function()
local jdtls_response = {
{
data = { element = '=hello-java_ed323c3c/_<{Main.java[Main[A' },
@@ -3673,16 +3902,24 @@ describe('LSP', function()
},
}
- local server = _create_server({
+ local server = _G._create_server({
capabilities = {
- positionEncoding = "utf-8"
+ positionEncoding = 'utf-8',
},
})
local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
- local handler = require'vim.lsp.handlers'['typeHierarchy/subtypes']
- handler(nil, jdtls_response, { client_id = client_id, bufnr = 1 })
+ local handler = require 'vim.lsp.handlers'['typeHierarchy/subtypes']
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {
+ 'package mylist;',
+ '',
+ 'public class MyList {',
+ ' static class Inner extends MyList{}',
+ '~}',
+ })
+ handler(nil, jdtls_response, { client_id = client_id, bufnr = bufnr })
return vim.fn.getqflist()
- ]=])
+ end)
local expected = {
{
@@ -3720,103 +3957,127 @@ describe('LSP', function()
describe('vim.lsp.buf.typehierarchy supertypes', function()
it('does nothing for an empty response', function()
- local qflist_count = exec_lua([=[
- require'vim.lsp.handlers'['typeHierarchy/supertypes'](nil, nil, {})
+ local qflist_count = exec_lua(function()
+ require 'vim.lsp.handlers'['typeHierarchy/supertypes'](nil, nil, {})
return #vim.fn.getqflist()
- ]=])
+ end)
eq(0, qflist_count)
end)
it('opens the quickfix list with the right supertypes', function()
clear()
exec_lua(create_server_definition)
- local qflist = exec_lua([=[
- local clangd_response = { {
- data = {
- parents = { {
- parents = { {
- parents = { {
- parents = {},
- symbolID = "62B3D268A01B9978"
- } },
- symbolID = "DC9B0AD433B43BEC"
- } },
- symbolID = "06B5F6A19BA9F6A8"
- } },
- symbolID = "EDC336589C09ABB2"
- },
- kind = 5,
- name = "D2",
- range = {
- ["end"] = {
- character = 8,
- line = 9
+ local qflist = exec_lua(function()
+ local clangd_response = {
+ {
+ data = {
+ parents = {
+ {
+ parents = {
+ {
+ parents = {
+ {
+ parents = {},
+ symbolID = '62B3D268A01B9978',
+ },
+ },
+ symbolID = 'DC9B0AD433B43BEC',
+ },
+ },
+ symbolID = '06B5F6A19BA9F6A8',
+ },
+ },
+ symbolID = 'EDC336589C09ABB2',
},
- start = {
- character = 6,
- line = 9
- }
- },
- selectionRange = {
- ["end"] = {
- character = 8,
- line = 9
+ kind = 5,
+ name = 'D2',
+ range = {
+ ['end'] = {
+ character = 8,
+ line = 3,
+ },
+ start = {
+ character = 6,
+ line = 3,
+ },
},
- start = {
- character = 6,
- line = 9
- }
- },
- uri = "file:///home/jiangyinzuo/hello.cpp"
- }, {
- data = {
- parents = { {
- parents = { {
- parents = { {
- parents = {},
- symbolID = "62B3D268A01B9978"
- } },
- symbolID = "DC9B0AD433B43BEC"
- } },
- symbolID = "06B5F6A19BA9F6A8"
- } },
- symbolID = "AFFCAED15557EF08"
- },
- kind = 5,
- name = "D1",
- range = {
- ["end"] = {
- character = 8,
- line = 8
+ selectionRange = {
+ ['end'] = {
+ character = 8,
+ line = 3,
+ },
+ start = {
+ character = 6,
+ line = 3,
+ },
},
- start = {
- character = 6,
- line = 8
- }
+ uri = 'file:///home/jiangyinzuo/hello.cpp',
},
- selectionRange = {
- ["end"] = {
- character = 8,
- line = 8
+ {
+ data = {
+ parents = {
+ {
+ parents = {
+ {
+ parents = {
+ {
+ parents = {},
+ symbolID = '62B3D268A01B9978',
+ },
+ },
+ symbolID = 'DC9B0AD433B43BEC',
+ },
+ },
+ symbolID = '06B5F6A19BA9F6A8',
+ },
+ },
+ symbolID = 'AFFCAED15557EF08',
},
- start = {
- character = 6,
- line = 8
- }
+ kind = 5,
+ name = 'D1',
+ range = {
+ ['end'] = {
+ character = 8,
+ line = 2,
+ },
+ start = {
+ character = 6,
+ line = 2,
+ },
+ },
+ selectionRange = {
+ ['end'] = {
+ character = 8,
+ line = 2,
+ },
+ start = {
+ character = 6,
+ line = 2,
+ },
+ },
+ uri = 'file:///home/jiangyinzuo/hello.cpp',
},
- uri = "file:///home/jiangyinzuo/hello.cpp"
- } }
+ }
- local server = _create_server({
+ local server = _G._create_server({
capabilities = {
- positionEncoding = "utf-8"
+ positionEncoding = 'utf-8',
},
})
local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
- local handler = require'vim.lsp.handlers'['typeHierarchy/supertypes']
- handler(nil, clangd_response, { client_id = client_id, bufnr = 1 })
+ local handler = require 'vim.lsp.handlers'['typeHierarchy/supertypes']
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {
+ 'class B : public A{};',
+ 'class C : public B{};',
+ 'class D1 : public C{};',
+ 'class D2 : public C{};',
+ 'class E : public D1, D2 {};',
+ })
+
+ handler(nil, clangd_response, { client_id = client_id, bufnr = bufnr })
return vim.fn.getqflist()
- ]=])
+ end)
local expected = {
{
@@ -3824,7 +4085,7 @@ describe('LSP', function()
col = 7,
end_col = 0,
end_lnum = 0,
- lnum = 10,
+ lnum = 4,
module = '',
nr = 0,
pattern = '',
@@ -3838,7 +4099,7 @@ describe('LSP', function()
col = 7,
end_col = 0,
end_lnum = 0,
- lnum = 9,
+ lnum = 3,
module = '',
nr = 0,
pattern = '',
@@ -3855,7 +4116,7 @@ describe('LSP', function()
it('opens the quickfix list with the right supertypes and details', function()
clear()
exec_lua(create_server_definition)
- local qflist = exec_lua([=[
+ local qflist = exec_lua(function()
local jdtls_response = {
{
data = { element = '=hello-java_ed323c3c/_<{Main.java[Main[A' },
@@ -3891,16 +4152,24 @@ describe('LSP', function()
},
}
- local server = _create_server({
+ local server = _G._create_server({
capabilities = {
- positionEncoding = "utf-8"
+ positionEncoding = 'utf-8',
},
})
local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
- local handler = require'vim.lsp.handlers'['typeHierarchy/supertypes']
- handler(nil, jdtls_response, { client_id = client_id, bufnr = 1 })
+ local handler = require 'vim.lsp.handlers'['typeHierarchy/supertypes']
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {
+ 'package mylist;',
+ '',
+ 'public class MyList {',
+ ' static class Inner extends MyList{}',
+ '~}',
+ })
+ handler(nil, jdtls_response, { client_id = client_id, bufnr = bufnr })
return vim.fn.getqflist()
- ]=])
+ end)
local expected = {
{
@@ -3984,18 +4253,19 @@ describe('LSP', function()
eq(true, client.server_capabilities().renameProvider.prepareProvider)
end,
on_setup = function()
- exec_lua([=[
- local bufnr = vim.api.nvim_get_current_buf()
- lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID)
- vim.lsp._stubs = {}
- vim.fn.input = function(opts, on_confirm)
- vim.lsp._stubs.input_prompt = opts.prompt
- vim.lsp._stubs.input_text = opts.default
- return 'renameto' -- expect this value in fake lsp
- end
- vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {'', 'this is line two'})
- vim.fn.cursor(2, 13) -- the space between "line" and "two"
- ]=])
+ exec_lua(function()
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID)
+ vim.lsp._stubs = {}
+ --- @diagnostic disable-next-line:duplicate-set-field
+ vim.fn.input = function(opts, _)
+ vim.lsp._stubs.input_prompt = opts.prompt
+ vim.lsp._stubs.input_text = opts.default
+ return 'renameto' -- expect this value in fake lsp
+ end
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { '', 'this is line two' })
+ vim.fn.cursor(2, 13) -- the space between "line" and "two"
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -4009,12 +4279,24 @@ describe('LSP', function()
eq(table.remove(test.expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'start' then
- exec_lua('vim.lsp.buf.rename()')
+ exec_lua(function()
+ vim.lsp.buf.rename()
+ end)
end
if ctx.method == 'shutdown' then
if test.expected_text then
- eq('New Name: ', exec_lua('return vim.lsp._stubs.input_prompt'))
- eq(test.expected_text, exec_lua('return vim.lsp._stubs.input_text'))
+ eq(
+ 'New Name: ',
+ exec_lua(function()
+ return vim.lsp._stubs.input_prompt
+ end)
+ )
+ eq(
+ test.expected_text,
+ exec_lua(function()
+ return vim.lsp._stubs.input_text
+ end)
+ )
end
client.stop()
end
@@ -4044,25 +4326,31 @@ describe('LSP', function()
on_handler = function(err, result, ctx)
eq(table.remove(expected_handlers), { err, result, ctx })
if ctx.method == 'start' then
- exec_lua([[
- vim.lsp.commands['dummy1'] = function(cmd)
- vim.lsp.commands['dummy2'] = function()
- end
+ exec_lua(function()
+ vim.lsp.commands['dummy1'] = function(_)
+ vim.lsp.commands['dummy2'] = function() end
end
local bufnr = vim.api.nvim_get_current_buf()
- vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID)
+ vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID)
+ --- @diagnostic disable-next-line:duplicate-set-field
vim.fn.inputlist = function()
return 1
end
vim.lsp.buf.code_action()
- ]])
+ end)
elseif ctx.method == 'shutdown' then
- eq('function', exec_lua [[return type(vim.lsp.commands['dummy2'])]])
+ eq(
+ 'function',
+ exec_lua(function()
+ return type(vim.lsp.commands['dummy2'])
+ end)
+ )
client.stop()
end
end,
}
end)
+
it('Calls workspace/executeCommand if no client side command', function()
local client --- @type vim.lsp.Client
local expected_handlers = {
@@ -4089,20 +4377,21 @@ describe('LSP', function()
ctx.version = nil
eq(table.remove(expected_handlers), { err, result, ctx })
if ctx.method == 'start' then
- exec_lua([[
+ exec_lua(function()
local bufnr = vim.api.nvim_get_current_buf()
- vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID)
+ vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID)
vim.fn.inputlist = function()
return 1
end
vim.lsp.buf.code_action()
- ]])
+ end)
elseif ctx.method == 'shutdown' then
client.stop()
end
end,
})
end)
+
it('Filters and automatically applies action if requested', function()
local client --- @type vim.lsp.Client
local expected_handlers = {
@@ -4122,83 +4411,102 @@ describe('LSP', function()
on_handler = function(err, result, ctx)
eq(table.remove(expected_handlers), { err, result, ctx })
if ctx.method == 'start' then
- exec_lua([[
- vim.lsp.commands['preferred_command'] = function(cmd)
- vim.lsp.commands['executed_preferred'] = function()
- end
+ exec_lua(function()
+ vim.lsp.commands['preferred_command'] = function(_)
+ vim.lsp.commands['executed_preferred'] = function() end
end
- vim.lsp.commands['type_annotate_command'] = function(cmd)
- vim.lsp.commands['executed_type_annotate'] = function()
- end
+ vim.lsp.commands['type_annotate_command'] = function(_)
+ vim.lsp.commands['executed_type_annotate'] = function() end
end
local bufnr = vim.api.nvim_get_current_buf()
- vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID)
- vim.lsp.buf.code_action({ filter = function(a) return a.isPreferred end, apply = true, })
+ vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID)
+ vim.lsp.buf.code_action({
+ filter = function(a)
+ return a.isPreferred
+ end,
+ apply = true,
+ })
vim.lsp.buf.code_action({
- -- expect to be returned actions 'type-annotate' and 'type-annotate.foo'
- context = { only = { 'type-annotate' }, },
- apply = true,
- filter = function(a)
- if a.kind == 'type-annotate.foo' then
- vim.lsp.commands['filtered_type_annotate_foo'] = function() end
- return false
- elseif a.kind == 'type-annotate' then
- return true
- else
- assert(nil, 'unreachable')
- end
- end,
+ -- expect to be returned actions 'type-annotate' and 'type-annotate.foo'
+ context = { only = { 'type-annotate' } },
+ apply = true,
+ filter = function(a)
+ if a.kind == 'type-annotate.foo' then
+ vim.lsp.commands['filtered_type_annotate_foo'] = function() end
+ return false
+ elseif a.kind == 'type-annotate' then
+ return true
+ else
+ assert(nil, 'unreachable')
+ end
+ end,
})
- ]])
+ end)
elseif ctx.method == 'shutdown' then
- eq('function', exec_lua [[return type(vim.lsp.commands['executed_preferred'])]])
- eq('function', exec_lua [[return type(vim.lsp.commands['filtered_type_annotate_foo'])]])
- eq('function', exec_lua [[return type(vim.lsp.commands['executed_type_annotate'])]])
+ eq(
+ 'function',
+ exec_lua(function()
+ return type(vim.lsp.commands['executed_preferred'])
+ end)
+ )
+ eq(
+ 'function',
+ exec_lua(function()
+ return type(vim.lsp.commands['filtered_type_annotate_foo'])
+ end)
+ )
+ eq(
+ 'function',
+ exec_lua(function()
+ return type(vim.lsp.commands['executed_type_annotate'])
+ end)
+ )
client.stop()
end
end,
}
end)
+
it('Fallback to command execution on resolve error', function()
clear()
exec_lua(create_server_definition)
- local result = exec_lua([[
- local server = _create_server({
+ local result = exec_lua(function()
+ local server = _G._create_server({
capabilities = {
executeCommandProvider = {
- commands = {"command:1"},
+ commands = { 'command:1' },
},
codeActionProvider = {
- resolveProvider = true
- }
+ resolveProvider = true,
+ },
},
handlers = {
- ["textDocument/codeAction"] = function(_, _, callback)
+ ['textDocument/codeAction'] = function(_, _, callback)
callback(nil, {
{
- title = "Code Action 1",
+ title = 'Code Action 1',
command = {
- title = "Command 1",
- command = "command:1",
- }
- }
+ title = 'Command 1',
+ command = 'command:1',
+ },
+ },
})
end,
- ["codeAction/resolve"] = function(_, _, callback)
- callback("resolve failed", nil)
+ ['codeAction/resolve'] = function(_, _, callback)
+ callback('resolve failed', nil)
end,
- }
+ },
})
- local client_id = vim.lsp.start({
- name = "dummy",
+ local client_id = assert(vim.lsp.start({
+ name = 'dummy',
cmd = server.cmd,
- })
+ }))
vim.lsp.buf.code_action({ apply = true })
vim.lsp.stop_client(client_id)
return server.messages
- ]])
+ end)
eq('codeAction/resolve', result[4].method)
eq('workspace/executeCommand', result[5].method)
eq('command:1', result[5].params.command)
@@ -4212,6 +4520,7 @@ describe('LSP', function()
pcall_err(exec_lua, 'vim.lsp.commands[1] = function() end')
)
end)
+
it('Accepts only function values', function()
matches(
'.*Command added to `vim.lsp.commands` must be a function',
@@ -4241,32 +4550,32 @@ describe('LSP', function()
eq(table.remove(expected_handlers), { err, result, ctx })
if ctx.method == 'start' then
local fake_uri = 'file:///fake/uri'
- local cmd = exec_lua(
- [[
- fake_uri = ...
+ local cmd = exec_lua(function()
local bufnr = vim.uri_to_bufnr(fake_uri)
vim.fn.bufload(bufnr)
- vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {'One line'})
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { 'One line' })
local lenses = {
{
range = {
- start = { line = 0, character = 0, },
- ['end'] = { line = 0, character = 8 }
+ start = { line = 0, character = 0 },
+ ['end'] = { line = 0, character = 8 },
},
- command = { title = 'Lens1', command = 'Dummy' }
+ command = { title = 'Lens1', command = 'Dummy' },
},
}
- vim.lsp.codelens.on_codelens(nil, lenses, {method='textDocument/codeLens', client_id=1, bufnr=bufnr})
+ vim.lsp.codelens.on_codelens(
+ nil,
+ lenses,
+ { method = 'textDocument/codeLens', client_id = 1, bufnr = bufnr }
+ )
local cmd_called = nil
- vim.lsp.commands['Dummy'] = function(command)
- cmd_called = command
+ vim.lsp.commands['Dummy'] = function(command0)
+ cmd_called = command0
end
vim.api.nvim_set_current_buf(bufnr)
vim.lsp.codelens.run()
return cmd_called
- ]],
- fake_uri
- )
+ end)
eq({ command = 'Dummy', title = 'Lens1' }, cmd)
elseif ctx.method == 'shutdown' then
client.stop()
@@ -4287,20 +4596,20 @@ describe('LSP', function()
client = client_
end,
on_setup = function()
- exec_lua([=[
- local bufnr = vim.api.nvim_get_current_buf()
- vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {'One line'})
- vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID)
-
- CALLED = false
- RESPONSE = nil
- local on_codelens = vim.lsp.codelens.on_codelens
- vim.lsp.codelens.on_codelens = function (err, result, ...)
- CALLED = true
- RESPONSE = { err = err, result = result }
- return on_codelens(err, result, ...)
- end
- ]=])
+ exec_lua(function()
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { 'One line' })
+ vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID)
+
+ _G.CALLED = false
+ _G.RESPONSE = nil
+ local on_codelens = vim.lsp.codelens.on_codelens
+ vim.lsp.codelens.on_codelens = function(err, result, ...)
+ _G.CALLED = true
+ _G.RESPONSE = { err = err, result = result }
+ return on_codelens(err, result, ...)
+ end
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -4310,42 +4619,52 @@ describe('LSP', function()
eq(table.remove(expected_handlers), { err, result, ctx })
if ctx.method == 'start' then
-- 1. first codelens request errors
- local response = exec_lua([=[
- CALLED = false
+ local response = exec_lua(function()
+ _G.CALLED = false
vim.lsp.codelens.refresh()
- vim.wait(100, function () return CALLED end)
- return RESPONSE
- ]=])
+ vim.wait(100, function()
+ return _G.CALLED
+ end)
+ return _G.RESPONSE
+ end)
eq({ err = { code = -32002, message = 'ServerNotInitialized' } }, response)
-- 2. second codelens request runs
- response = exec_lua([=[
- CALLED = false
- local cmd_called = nil
- vim.lsp.commands["Dummy"] = function (command)
- cmd_called = command
+ response = exec_lua(function()
+ _G.CALLED = false
+ local cmd_called --- @type string?
+ vim.lsp.commands['Dummy'] = function(command0)
+ cmd_called = command0
end
vim.lsp.codelens.refresh()
- vim.wait(100, function () return CALLED end)
+ vim.wait(100, function()
+ return _G.CALLED
+ end)
vim.lsp.codelens.run()
- vim.wait(100, function () return cmd_called end)
+ vim.wait(100, function()
+ return cmd_called ~= nil
+ end)
return cmd_called
- ]=])
+ end)
eq({ command = 'Dummy', title = 'Lens1' }, response)
-- 3. third codelens request runs
- response = exec_lua([=[
- CALLED = false
- local cmd_called = nil
- vim.lsp.commands["Dummy"] = function (command)
- cmd_called = command
+ response = exec_lua(function()
+ _G.CALLED = false
+ local cmd_called --- @type string?
+ vim.lsp.commands['Dummy'] = function(command0)
+ cmd_called = command0
end
vim.lsp.codelens.refresh()
- vim.wait(100, function () return CALLED end)
+ vim.wait(100, function()
+ return _G.CALLED
+ end)
vim.lsp.codelens.run()
- vim.wait(100, function () return cmd_called end)
+ vim.wait(100, function()
+ return cmd_called ~= nil
+ end)
return cmd_called
- ]=])
+ end)
eq({ command = 'Dummy', title = 'Lens2' }, response)
elseif ctx.method == 'shutdown' then
client.stop()
@@ -4363,79 +4682,73 @@ describe('LSP', function()
exec_lua(create_server_definition)
-- setup lsp
- exec_lua(
- [[
- local lens_title_per_fake_uri = ...
- local server = _create_server({
- capabilities = {
- codeLensProvider = {
- resolveProvider = true
- },
+ exec_lua(function()
+ local server = _G._create_server({
+ capabilities = {
+ codeLensProvider = {
+ resolveProvider = true,
},
- handlers = {
- ["textDocument/codeLens"] = function(method, params, callback)
- local lenses = {
- {
- range = {
- start = { line = 0, character = 0 },
- ['end'] = { line = 0, character = 0 },
- },
- command = {
- title = lens_title_per_fake_uri[params.textDocument.uri],
- command = 'Dummy',
- },
+ },
+ handlers = {
+ ['textDocument/codeLens'] = function(_, params, callback)
+ local lenses = {
+ {
+ range = {
+ start = { line = 0, character = 0 },
+ ['end'] = { line = 0, character = 0 },
},
- }
- callback(nil, lenses)
- end,
- }
- })
+ command = {
+ title = lens_title_per_fake_uri[params.textDocument.uri],
+ command = 'Dummy',
+ },
+ },
+ }
+ callback(nil, lenses)
+ end,
+ },
+ })
- CLIENT_ID = vim.lsp.start({
- name = "dummy",
- cmd = server.cmd,
- })
- ]],
- lens_title_per_fake_uri
- )
+ _G.CLIENT_ID = vim.lsp.start({
+ name = 'dummy',
+ cmd = server.cmd,
+ })
+ end)
-- create buffers and setup handler
- exec_lua(
- [[
- local lens_title_per_fake_uri = ...
- local default_buf = vim.api.nvim_get_current_buf()
- for fake_uri, _ in pairs(lens_title_per_fake_uri) do
- local bufnr = vim.uri_to_bufnr(fake_uri)
- vim.api.nvim_set_current_buf(bufnr)
- vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {'Some contents'})
- vim.lsp.buf_attach_client(bufnr, CLIENT_ID)
- end
- vim.api.nvim_buf_delete(default_buf, {force = true})
-
- REQUEST_COUNT = vim.tbl_count(lens_title_per_fake_uri)
- RESPONSES = {}
- local on_codelens = vim.lsp.codelens.on_codelens
- vim.lsp.codelens.on_codelens = function (err, result, ctx, ...)
- table.insert(RESPONSES, { err = err, result = result, ctx = ctx })
- return on_codelens(err, result, ctx, ...)
- end
- ]],
- lens_title_per_fake_uri
- )
+ exec_lua(function()
+ local default_buf = vim.api.nvim_get_current_buf()
+ for fake_uri in pairs(lens_title_per_fake_uri) do
+ local bufnr = vim.uri_to_bufnr(fake_uri)
+ vim.api.nvim_set_current_buf(bufnr)
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { 'Some contents' })
+ vim.lsp.buf_attach_client(bufnr, _G.CLIENT_ID)
+ end
+ vim.api.nvim_buf_delete(default_buf, { force = true })
+
+ _G.REQUEST_COUNT = vim.tbl_count(lens_title_per_fake_uri)
+ _G.RESPONSES = {}
+ local on_codelens = vim.lsp.codelens.on_codelens
+ vim.lsp.codelens.on_codelens = function(err, result, ctx, ...)
+ table.insert(_G.RESPONSES, { err = err, result = result, ctx = ctx })
+ return on_codelens(err, result, ctx, ...)
+ end
+ end)
-- call codelens refresh
- local cmds = exec_lua([[
- RESPONSES = {}
+ local cmds = exec_lua(function()
+ _G.RESPONSES = {}
vim.lsp.codelens.refresh()
- vim.wait(100, function () return #RESPONSES >= REQUEST_COUNT end)
+ vim.wait(100, function()
+ return #_G.RESPONSES >= _G.REQUEST_COUNT
+ end)
local cmds = {}
- for _, resp in ipairs(RESPONSES) do
+ for _, resp in ipairs(_G.RESPONSES) do
local uri = resp.ctx.params.textDocument.uri
cmds[uri] = resp.result[1].command
end
return cmds
- ]])
+ end)
eq({ command = 'Dummy', title = 'Lens1' }, cmds['file:///fake/uri1'])
eq({ command = 'Dummy', title = 'Lens2' }, cmds['file:///fake/uri2'])
end)
@@ -4450,23 +4763,24 @@ describe('LSP', function()
client = c
end,
on_handler = function()
- local notify_msg = exec_lua([[
+ local notify_msg = exec_lua(function()
local bufnr = vim.api.nvim_get_current_buf()
- vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID)
- local notify_msg
+ vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID)
+ local notify_msg --- @type string?
local notify = vim.notify
- vim.notify = function(msg, log_level)
+ vim.notify = function(msg, _)
notify_msg = msg
end
vim.lsp.buf.format({ name = 'does-not-exist' })
vim.notify = notify
return notify_msg
- ]])
+ end)
eq('[LSP] Format request failed, no matching language servers.', notify_msg)
client.stop()
end,
}
end)
+
it('Sends textDocument/formatting request to format buffer', function()
local expected_handlers = {
{ NIL, {}, { method = 'shutdown', client_id = 1 } },
@@ -4481,25 +4795,114 @@ describe('LSP', function()
on_handler = function(_, _, ctx)
table.remove(expected_handlers)
if ctx.method == 'start' then
- local notify_msg = exec_lua([[
+ local notify_msg = exec_lua(function()
local bufnr = vim.api.nvim_get_current_buf()
- vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID)
- local notify_msg
+ vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID)
+ local notify_msg --- @type string?
local notify = vim.notify
- vim.notify = function(msg, log_level)
+ vim.notify = function(msg, _)
notify_msg = msg
end
vim.lsp.buf.format({ bufnr = bufnr })
vim.notify = notify
return notify_msg
- ]])
- eq(NIL, notify_msg)
+ end)
+ eq(nil, notify_msg)
+ elseif ctx.method == 'shutdown' then
+ client.stop()
+ end
+ end,
+ }
+ end)
+
+ it('Sends textDocument/rangeFormatting request to format a range', function()
+ local expected_handlers = {
+ { NIL, {}, { method = 'shutdown', client_id = 1 } },
+ { NIL, {}, { method = 'start', client_id = 1 } },
+ }
+ local client --- @type vim.lsp.Client
+ test_rpc_server {
+ test_name = 'range_formatting',
+ on_init = function(c)
+ client = c
+ end,
+ on_handler = function(_, _, ctx)
+ table.remove(expected_handlers)
+ if ctx.method == 'start' then
+ local notify_msg = exec_lua(function()
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, { 'foo', 'bar' })
+ vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID)
+ local notify_msg --- @type string?
+ local notify = vim.notify
+ vim.notify = function(msg, _)
+ notify_msg = msg
+ end
+ vim.lsp.buf.format({
+ bufnr = bufnr,
+ range = {
+ start = { 1, 1 },
+ ['end'] = { 1, 1 },
+ },
+ })
+ vim.notify = notify
+ return notify_msg
+ end)
+ eq(nil, notify_msg)
+ elseif ctx.method == 'shutdown' then
+ client.stop()
+ end
+ end,
+ }
+ end)
+
+ it('Sends textDocument/rangesFormatting request to format multiple ranges', function()
+ local expected_handlers = {
+ { NIL, {}, { method = 'shutdown', client_id = 1 } },
+ { NIL, {}, { method = 'start', client_id = 1 } },
+ }
+ local client --- @type vim.lsp.Client
+ test_rpc_server {
+ test_name = 'ranges_formatting',
+ on_init = function(c)
+ client = c
+ end,
+ on_handler = function(_, _, ctx)
+ table.remove(expected_handlers)
+ if ctx.method == 'start' then
+ local notify_msg = exec_lua(function()
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, { 'foo', 'bar', 'baz' })
+ vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID)
+ local notify_msg --- @type string?
+ local notify = vim.notify
+ vim.notify = function(msg, _)
+ notify_msg = msg
+ end
+ vim.lsp.buf.format({
+ bufnr = bufnr,
+ range = {
+ {
+ start = { 1, 1 },
+ ['end'] = { 1, 1 },
+ },
+ {
+ start = { 2, 2 },
+ ['end'] = { 2, 2 },
+ },
+ },
+ })
+ vim.notify = notify
+ return notify_msg
+ end)
+ eq(nil, notify_msg)
elseif ctx.method == 'shutdown' then
client.stop()
end
end,
}
end)
+
it('Can format async', function()
local expected_handlers = {
{ NIL, {}, { method = 'shutdown', client_id = 1 } },
@@ -4514,29 +4917,31 @@ describe('LSP', function()
on_handler = function(_, _, ctx)
table.remove(expected_handlers)
if ctx.method == 'start' then
- local result = exec_lua([[
+ local result = exec_lua(function()
local bufnr = vim.api.nvim_get_current_buf()
- vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID)
+ vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID)
- local notify_msg
+ local notify_msg --- @type string?
local notify = vim.notify
- vim.notify = function(msg, log_level)
+ vim.notify = function(msg, _)
notify_msg = msg
end
local handler = vim.lsp.handlers['textDocument/formatting']
local handler_called = false
- vim.lsp.handlers['textDocument/formatting'] = function(...)
+ vim.lsp.handlers['textDocument/formatting'] = function()
handler_called = true
end
vim.lsp.buf.format({ bufnr = bufnr, async = true })
- vim.wait(1000, function() return handler_called end)
+ vim.wait(1000, function()
+ return handler_called
+ end)
vim.notify = notify
vim.lsp.handlers['textDocument/formatting'] = handler
- return {notify = notify_msg, handler_called = handler_called}
- ]])
+ return { notify = notify_msg, handler_called = handler_called }
+ end)
eq({ handler_called = true }, result)
elseif ctx.method == 'shutdown' then
client.stop()
@@ -4544,24 +4949,27 @@ describe('LSP', function()
end,
}
end)
+
it('format formats range in visual mode', function()
exec_lua(create_server_definition)
- local result = exec_lua([[
- local server = _create_server({ capabilities = {
- documentFormattingProvider = true,
- documentRangeFormattingProvider = true,
- }})
+ local result = exec_lua(function()
+ local server = _G._create_server({
+ capabilities = {
+ documentFormattingProvider = true,
+ documentRangeFormattingProvider = true,
+ },
+ })
local bufnr = vim.api.nvim_get_current_buf()
- local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
+ local client_id = assert(vim.lsp.start({ name = 'dummy', cmd = server.cmd }))
vim.api.nvim_win_set_buf(0, bufnr)
- vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, {'foo', 'bar'})
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, { 'foo', 'bar' })
vim.api.nvim_win_set_cursor(0, { 1, 0 })
vim.cmd.normal('v')
vim.api.nvim_win_set_cursor(0, { 2, 3 })
vim.lsp.buf.format({ bufnr = bufnr, false })
vim.lsp.stop_client(client_id)
return server.messages
- ]])
+ end)
eq('textDocument/rangeFormatting', result[3].method)
local expected_range = {
start = { line = 0, character = 0 },
@@ -4569,17 +4977,20 @@ describe('LSP', function()
}
eq(expected_range, result[3].params.range)
end)
+
it('format formats range in visual line mode', function()
exec_lua(create_server_definition)
- local result = exec_lua([[
- local server = _create_server({ capabilities = {
- documentFormattingProvider = true,
- documentRangeFormattingProvider = true,
- }})
+ local result = exec_lua(function()
+ local server = _G._create_server({
+ capabilities = {
+ documentFormattingProvider = true,
+ documentRangeFormattingProvider = true,
+ },
+ })
local bufnr = vim.api.nvim_get_current_buf()
- local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
+ local client_id = assert(vim.lsp.start({ name = 'dummy', cmd = server.cmd }))
vim.api.nvim_win_set_buf(0, bufnr)
- vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, {'foo', 'bar baz'})
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, { 'foo', 'bar baz' })
vim.api.nvim_win_set_cursor(0, { 1, 2 })
vim.cmd.normal('V')
vim.api.nvim_win_set_cursor(0, { 2, 1 })
@@ -4587,7 +4998,7 @@ describe('LSP', function()
-- Format again with visual lines going from bottom to top
-- Must result in same formatting
- vim.cmd.normal("<ESC>")
+ vim.cmd.normal('<ESC>')
vim.api.nvim_win_set_cursor(0, { 2, 1 })
vim.cmd.normal('V')
vim.api.nvim_win_set_cursor(0, { 1, 2 })
@@ -4595,7 +5006,7 @@ describe('LSP', function()
vim.lsp.stop_client(client_id)
return server.messages
- ]])
+ end)
local expected_methods = {
'initialize',
'initialized',
@@ -4620,40 +5031,57 @@ describe('LSP', function()
eq(expected_range, result[3].params.range)
eq(expected_range, result[5].params.range)
end)
+
it('Aborts with notify if no clients support requested method', function()
exec_lua(create_server_definition)
- exec_lua([[
+ exec_lua(function()
vim.notify = function(msg, _)
- notify_msg = msg
+ _G.notify_msg = msg
end
- ]])
+ end)
local fail_msg = '[LSP] Format request failed, no matching language servers.'
--- @param name string
--- @param formatting boolean
--- @param range_formatting boolean
local function check_notify(name, formatting, range_formatting)
local timeout_msg = '[LSP][' .. name .. '] timeout'
- exec_lua(
- [[
- local formatting, range_formatting, name = ...
- local server = _create_server({ capabilities = {
- documentFormattingProvider = formatting,
- documentRangeFormattingProvider = range_formatting,
- }})
+ exec_lua(function()
+ local server = _G._create_server({
+ capabilities = {
+ documentFormattingProvider = formatting,
+ documentRangeFormattingProvider = range_formatting,
+ },
+ })
vim.lsp.start({ name = name, cmd = server.cmd })
- notify_msg = nil
+ _G.notify_msg = nil
vim.lsp.buf.format({ name = name, timeout_ms = 1 })
- ]],
- formatting,
- range_formatting,
- name
+ end)
+ eq(
+ formatting and timeout_msg or fail_msg,
+ exec_lua(function()
+ return _G.notify_msg
+ end)
+ )
+ exec_lua(function()
+ _G.notify_msg = nil
+ vim.lsp.buf.format({
+ name = name,
+ timeout_ms = 1,
+ range = {
+ start = { 1, 0 },
+ ['end'] = {
+ 1,
+ 0,
+ },
+ },
+ })
+ end)
+ eq(
+ range_formatting and timeout_msg or fail_msg,
+ exec_lua(function()
+ return _G.notify_msg
+ end)
)
- eq(formatting and timeout_msg or fail_msg, exec_lua('return notify_msg'))
- exec_lua([[
- notify_msg = nil
- vim.lsp.buf.format({ name = name, timeout_ms = 1, range = {start={1, 0}, ['end']={1, 0}}})
- ]])
- eq(range_formatting and timeout_msg or fail_msg, exec_lua('return notify_msg'))
end
check_notify('none', false, false)
check_notify('formatting', true, false)
@@ -4683,10 +5111,9 @@ describe('LSP', function()
},
}
exec_lua(create_server_definition)
- exec_lua(
- [[
- _G.mock_locations = ...
- _G.server = _create_server({
+ exec_lua(function()
+ _G.mock_locations = mock_locations
+ _G.server = _G._create_server({
---@type lsp.ServerCapabilities
capabilities = {
definitionProvider = true,
@@ -4710,26 +5137,25 @@ describe('LSP', function()
name = 'vim.foobar',
kind = 12, ---@type lsp.SymbolKind
location = _G.mock_locations[2],
- }
+ },
})
end,
},
})
- _G.client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
- ]],
- mock_locations
- )
+ _G.client_id = vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
+ end)
end)
+
after_each(function()
- exec_lua [[
+ exec_lua(function()
vim.lsp.stop_client(_G.client_id)
- ]]
+ end)
end)
it('with flags=c, returns matching tags using textDocument/definition', function()
- local result = exec_lua [[
+ local result = exec_lua(function()
return vim.lsp.tagfunc('foobar', 'c')
- ]]
+ end)
eq({
{
cmd = '/\\%6l\\%1c/', -- for location (5, 23)
@@ -4740,9 +5166,9 @@ describe('LSP', function()
end)
it('without flags=c, returns all matching tags using workspace/symbol', function()
- local result = exec_lua [[
+ local result = exec_lua(function()
return vim.lsp.tagfunc('foobar', '')
- ]]
+ end)
eq({
{
cmd = '/\\%6l\\%1c/', -- for location (5, 23)
@@ -4761,80 +5187,81 @@ describe('LSP', function()
end)
describe('cmd', function()
- it('can connect to lsp server via rpc.connect', function()
- local result = exec_lua [[
- local uv = vim.uv
- local server = uv.new_tcp()
- local init = nil
- server:bind('127.0.0.1', 0)
- server:listen(127, function(err)
- assert(not err, err)
- local socket = uv.new_tcp()
- server:accept(socket)
- socket:read_start(require('vim.lsp.rpc').create_read_loop(function(body)
- init = body
- socket:close()
- end))
- end)
- local port = server:getsockname().port
+ it('connects to lsp server via rpc.connect using ip address', function()
+ exec_lua(create_tcp_echo_server)
+ local result = exec_lua(function()
+ local server, port, last_message = _G._create_tcp_server('127.0.0.1')
vim.lsp.start({ name = 'dummy', cmd = vim.lsp.rpc.connect('127.0.0.1', port) })
- vim.wait(1000, function() return init ~= nil end)
- assert(init, "server must receive `initialize` request")
+ vim.wait(1000, function()
+ return last_message() ~= nil
+ end)
+ local init = last_message()
+ assert(init, 'server must receive `initialize` request')
+ server:close()
+ server:shutdown()
+ return vim.json.decode(init)
+ end)
+ eq('initialize', result.method)
+ end)
+
+ it('connects to lsp server via rpc.connect using hostname', function()
+ skip(is_os('bsd'), 'issue with host resolution in ci')
+ exec_lua(create_tcp_echo_server)
+ local result = exec_lua(function()
+ local server, port, last_message = _G._create_tcp_server('::1')
+ vim.lsp.start({ name = 'dummy', cmd = vim.lsp.rpc.connect('localhost', port) })
+ vim.wait(1000, function()
+ return last_message() ~= nil
+ end)
+ local init = last_message()
+ assert(init, 'server must receive `initialize` request')
server:close()
server:shutdown()
return vim.json.decode(init)
- ]]
+ end)
eq('initialize', result.method)
end)
+
it('can connect to lsp server via pipe or domain_socket', function()
- local tmpfile --- @type string
- if is_os('win') then
- tmpfile = '\\\\.\\\\pipe\\pipe.test'
- else
- tmpfile = tmpname()
- os.remove(tmpfile)
- end
- local result = exec_lua(
- [[
- local SOCK = ...
+ local tmpfile = is_os('win') and '\\\\.\\\\pipe\\pipe.test' or tmpname(false)
+ local result = exec_lua(function()
local uv = vim.uv
- local server = uv.new_pipe(false)
- server:bind(SOCK)
+ local server = assert(uv.new_pipe(false))
+ server:bind(tmpfile)
local init = nil
server:listen(127, function(err)
- assert(not err, err)
- local client = uv.new_pipe()
- server:accept(client)
- client:read_start(require("vim.lsp.rpc").create_read_loop(function(body)
- init = body
- client:close()
- end))
+ assert(not err, err)
+ local client = assert(vim.uv.new_pipe())
+ server:accept(client)
+ client:read_start(require('vim.lsp.rpc').create_read_loop(function(body)
+ init = body
+ client:close()
+ end))
+ end)
+ vim.lsp.start({ name = 'dummy', cmd = vim.lsp.rpc.connect(tmpfile) })
+ vim.wait(1000, function()
+ return init ~= nil
end)
- vim.lsp.start({ name = "dummy", cmd = vim.lsp.rpc.connect(SOCK) })
- vim.wait(1000, function() return init ~= nil end)
- assert(init, "server must receive `initialize` request")
+ assert(init, 'server must receive `initialize` request')
server:close()
server:shutdown()
return vim.json.decode(init)
- ]],
- tmpfile
- )
+ end)
eq('initialize', result.method)
end)
end)
describe('handlers', function()
it('handler can return false as response', function()
- local result = exec_lua [[
- local uv = vim.uv
- local server = uv.new_tcp()
+ local result = exec_lua(function()
+ local server = assert(vim.uv.new_tcp())
local messages = {}
local responses = {}
server:bind('127.0.0.1', 0)
server:listen(127, function(err)
assert(not err, err)
- local socket = uv.new_tcp()
+ local socket = assert(vim.uv.new_tcp())
server:accept(socket)
socket:read_start(require('vim.lsp.rpc').create_read_loop(function(body)
local payload = vim.json.decode(body)
@@ -4845,10 +5272,10 @@ describe('LSP', function()
id = payload.id,
jsonrpc = '2.0',
result = {
- capabilities = {}
+ capabilities = {},
},
})
- socket:write(table.concat({'Content-Length: ', tostring(#msg), '\r\n\r\n', msg}))
+ socket:write(table.concat({ 'Content-Length: ', tostring(#msg), '\r\n\r\n', msg }))
elseif payload.method == 'initialized' then
local msg = vim.json.encode({
id = 10,
@@ -4856,7 +5283,7 @@ describe('LSP', function()
method = 'dummy',
params = {},
})
- socket:write(table.concat({'Content-Length: ', tostring(#msg), '\r\n\r\n', msg}))
+ socket:write(table.concat({ 'Content-Length: ', tostring(#msg), '\r\n\r\n', msg }))
end
else
table.insert(responses, payload)
@@ -4866,20 +5293,24 @@ describe('LSP', function()
end)
local port = server:getsockname().port
local handler_called = false
- vim.lsp.handlers['dummy'] = function(err, result)
+ vim.lsp.handlers['dummy'] = function(_, _)
handler_called = true
return false
end
- local client_id = vim.lsp.start({ name = 'dummy', cmd = vim.lsp.rpc.connect('127.0.0.1', port) })
- local client = vim.lsp.get_client_by_id(client_id)
- vim.wait(1000, function() return #messages == 2 and handler_called and #responses == 1 end)
+ local client_id =
+ assert(vim.lsp.start({ name = 'dummy', cmd = vim.lsp.rpc.connect('127.0.0.1', port) }))
+ vim.lsp.get_client_by_id(client_id)
+ vim.wait(1000, function()
+ return #messages == 2 and handler_called and #responses == 1
+ end)
server:close()
server:shutdown()
return {
messages = messages,
handler_called = handler_called,
- responses = responses }
- ]]
+ responses = responses,
+ }
+ end)
local expected = {
messages = { 'initialize', 'initialized' },
handler_called = true,
@@ -4897,9 +5328,7 @@ describe('LSP', function()
describe('#dynamic vim.lsp._dynamic', function()
it('supports dynamic registration', function()
- ---@type string
- local root_dir = tmpname()
- os.remove(root_dir)
+ local root_dir = tmpname(false)
mkdir(root_dir)
local tmpfile = root_dir .. '/dynamic.foo'
local file = io.open(tmpfile, 'w')
@@ -4908,17 +5337,14 @@ describe('LSP', function()
end
exec_lua(create_server_definition)
- local result = exec_lua(
- [[
- local root_dir, tmpfile = ...
-
- local server = _create_server()
- local client_id = vim.lsp.start({
+ local result = exec_lua(function()
+ local server = _G._create_server()
+ local client_id = assert(vim.lsp.start({
name = 'dynamic-test',
cmd = server.cmd,
root_dir = root_dir,
get_language_id = function()
- return "dummy-lang"
+ return 'dummy-lang'
end,
capabilities = {
textDocument = {
@@ -4930,9 +5356,7 @@ describe('LSP', function()
},
},
},
- })
-
- local expected_messages = 2 -- initialize, initialized
+ }))
vim.lsp.handlers['client/registerCapability'](nil, {
registrations = {
@@ -4940,9 +5364,11 @@ describe('LSP', function()
id = 'formatting',
method = 'textDocument/formatting',
registerOptions = {
- documentSelector = {{
- pattern = root_dir .. '/*.foo',
- }},
+ documentSelector = {
+ {
+ pattern = root_dir .. '/*.foo',
+ },
+ },
},
},
},
@@ -4954,12 +5380,12 @@ describe('LSP', function()
id = 'range-formatting',
method = 'textDocument/rangeFormatting',
registerOptions = {
- documentSelector = {
+ documentSelector = {
{
- language = "dummy-lang"
+ language = 'dummy-lang',
},
- }
- }
+ },
+ },
},
},
}, { client_id = client_id })
@@ -4976,26 +5402,22 @@ describe('LSP', function()
local result = {}
local function check(method, fname)
local bufnr = fname and vim.fn.bufadd(fname) or nil
- local client = vim.lsp.get_client_by_id(client_id)
+ local client = assert(vim.lsp.get_client_by_id(client_id))
result[#result + 1] = {
method = method,
fname = fname,
- supported = client.supports_method(method, {bufnr = bufnr})
+ supported = client.supports_method(method, { bufnr = bufnr }),
}
end
-
- check("textDocument/formatting")
- check("textDocument/formatting", tmpfile)
- check("textDocument/rangeFormatting")
- check("textDocument/rangeFormatting", tmpfile)
- check("textDocument/completion")
+ check('textDocument/formatting')
+ check('textDocument/formatting', tmpfile)
+ check('textDocument/rangeFormatting')
+ check('textDocument/rangeFormatting', tmpfile)
+ check('textDocument/completion')
return result
- ]],
- root_dir,
- tmpfile
- )
+ end)
eq(5, #result)
eq({ method = 'textDocument/formatting', supported = false }, result[1])
@@ -5007,16 +5429,26 @@ describe('LSP', function()
end)
describe('vim.lsp._watchfiles', function()
+ --- @type integer, integer, integer
+ local created, changed, deleted
+
+ setup(function()
+ clear()
+ created = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]])
+ changed = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]])
+ deleted = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]])
+ end)
+
local function test_filechanges(watchfunc)
it(
string.format('sends notifications when files change (watchfunc=%s)', watchfunc),
function()
- if watchfunc == 'fswatch' then
+ if watchfunc == 'inotify' then
skip(is_os('win'), 'not supported on windows')
skip(is_os('mac'), 'flaky test on mac')
skip(
- not is_ci() and fn.executable('fswatch') == 0,
- 'fswatch not installed and not on CI'
+ not is_ci() and fn.executable('inotifywait') == 0,
+ 'inotify-tools not installed and not on CI'
)
end
@@ -5033,87 +5465,80 @@ describe('LSP', function()
)
end
- local root_dir = tmpname()
- os.remove(root_dir)
+ local root_dir = tmpname(false)
mkdir(root_dir)
exec_lua(create_server_definition)
- local result = exec_lua(
- [[
- local root_dir, watchfunc = ...
-
- local server = _create_server()
- local client_id = vim.lsp.start({
- name = 'watchfiles-test',
- cmd = server.cmd,
- root_dir = root_dir,
- capabilities = {
- workspace = {
- didChangeWatchedFiles = {
- dynamicRegistration = true,
+ local result = exec_lua(function()
+ local server = _G._create_server()
+ local client_id = assert(vim.lsp.start({
+ name = 'watchfiles-test',
+ cmd = server.cmd,
+ root_dir = root_dir,
+ capabilities = {
+ workspace = {
+ didChangeWatchedFiles = {
+ dynamicRegistration = true,
+ },
},
},
- },
- })
+ }))
- require('vim.lsp._watchfiles')._watchfunc = require('vim._watch')[watchfunc]
+ require('vim.lsp._watchfiles')._watchfunc = require('vim._watch')[watchfunc]
- local expected_messages = 0
+ local expected_messages = 0
- local msg_wait_timeout = watchfunc == 'watch' and 200 or 2500
+ local msg_wait_timeout = watchfunc == 'watch' and 200 or 2500
- local function wait_for_message(incr)
- expected_messages = expected_messages + (incr or 1)
- assert(
- vim.wait(msg_wait_timeout, function()
- return #server.messages == expected_messages
- end),
- 'Timed out waiting for expected number of messages. Current messages seen so far: '
- .. vim.inspect(server.messages)
- )
- end
+ local function wait_for_message(incr)
+ expected_messages = expected_messages + (incr or 1)
+ assert(
+ vim.wait(msg_wait_timeout, function()
+ return #server.messages == expected_messages
+ end),
+ 'Timed out waiting for expected number of messages. Current messages seen so far: '
+ .. vim.inspect(server.messages)
+ )
+ end
- wait_for_message(2) -- initialize, initialized
+ wait_for_message(2) -- initialize, initialized
- vim.lsp.handlers['client/registerCapability'](nil, {
- registrations = {
- {
- id = 'watchfiles-test-0',
- method = 'workspace/didChangeWatchedFiles',
- registerOptions = {
- watchers = {
- {
- globPattern = '**/watch',
- kind = 7,
+ vim.lsp.handlers['client/registerCapability'](nil, {
+ registrations = {
+ {
+ id = 'watchfiles-test-0',
+ method = 'workspace/didChangeWatchedFiles',
+ registerOptions = {
+ watchers = {
+ {
+ globPattern = '**/watch',
+ kind = 7,
+ },
},
},
},
},
- },
- }, { client_id = client_id })
+ }, { client_id = client_id })
- if watchfunc ~= 'watch' then
- vim.wait(100)
- end
+ if watchfunc ~= 'watch' then
+ vim.wait(100)
+ end
- local path = root_dir .. '/watch'
- local tmp = vim.fn.tempname()
- io.open(tmp, 'w'):close()
- vim.uv.fs_rename(tmp, path)
+ local path = root_dir .. '/watch'
+ local tmp = vim.fn.tempname()
+ io.open(tmp, 'w'):close()
+ vim.uv.fs_rename(tmp, path)
- wait_for_message()
+ wait_for_message()
- os.remove(path)
+ os.remove(path)
- wait_for_message()
+ wait_for_message()
- vim.lsp.stop_client(client_id)
+ vim.lsp.stop_client(client_id)
- return server.messages
- ]],
- root_dir,
- watchfunc
- )
+ return server.messages
+ end)
local uri = vim.uri_from_fname(root_dir .. '/watch')
@@ -5124,7 +5549,7 @@ describe('LSP', function()
params = {
changes = {
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]),
+ type = created,
uri = uri,
},
},
@@ -5136,7 +5561,7 @@ describe('LSP', function()
params = {
changes = {
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]),
+ type = deleted,
uri = uri,
},
},
@@ -5148,17 +5573,14 @@ describe('LSP', function()
test_filechanges('watch')
test_filechanges('watchdirs')
- test_filechanges('fswatch')
+ test_filechanges('inotify')
it('correctly registers and unregisters', function()
local root_dir = '/some_dir'
exec_lua(create_server_definition)
- local result = exec_lua(
- [[
- local root_dir = ...
-
- local server = _create_server()
- local client_id = vim.lsp.start({
+ local result = exec_lua(function()
+ local server = _G._create_server()
+ local client_id = assert(vim.lsp.start({
name = 'watchfiles-test',
cmd = server.cmd,
root_dir = root_dir,
@@ -5169,16 +5591,22 @@ describe('LSP', function()
},
},
},
- })
+ }))
local expected_messages = 2 -- initialize, initialized
local function wait_for_messages()
- assert(vim.wait(200, function() return #server.messages == expected_messages end), 'Timed out waiting for expected number of messages. Current messages seen so far: ' .. vim.inspect(server.messages))
+ assert(
+ vim.wait(200, function()
+ return #server.messages == expected_messages
+ end),
+ 'Timed out waiting for expected number of messages. Current messages seen so far: '
+ .. vim.inspect(server.messages)
+ )
end
wait_for_messages()
- local send_event
+ local send_event --- @type function
require('vim.lsp._watchfiles')._watchfunc = function(_, _, callback)
local stopped = false
send_event = function(...)
@@ -5245,9 +5673,7 @@ describe('LSP', function()
wait_for_messages()
return server.messages
- ]],
- root_dir
- )
+ end)
local function watched_uri(fname)
return vim.uri_from_fname(root_dir .. '/' .. fname)
@@ -5258,7 +5684,7 @@ describe('LSP', function()
eq({
changes = {
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]),
+ type = created,
uri = watched_uri('file.watch0'),
},
},
@@ -5267,7 +5693,7 @@ describe('LSP', function()
eq({
changes = {
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]),
+ type = created,
uri = watched_uri('file.watch1'),
},
},
@@ -5277,12 +5703,9 @@ describe('LSP', function()
it('correctly handles the registered watch kind', function()
local root_dir = 'some_dir'
exec_lua(create_server_definition)
- local result = exec_lua(
- [[
- local root_dir = ...
-
- local server = _create_server()
- local client_id = vim.lsp.start({
+ local result = exec_lua(function()
+ local server = _G._create_server()
+ local client_id = assert(vim.lsp.start({
name = 'watchfiles-test',
cmd = server.cmd,
root_dir = root_dir,
@@ -5293,16 +5716,22 @@ describe('LSP', function()
},
},
},
- })
+ }))
local expected_messages = 2 -- initialize, initialized
local function wait_for_messages()
- assert(vim.wait(200, function() return #server.messages == expected_messages end), 'Timed out waiting for expected number of messages. Current messages seen so far: ' .. vim.inspect(server.messages))
+ assert(
+ vim.wait(200, function()
+ return #server.messages == expected_messages
+ end),
+ 'Timed out waiting for expected number of messages. Current messages seen so far: '
+ .. vim.inspect(server.messages)
+ )
end
wait_for_messages()
- local watch_callbacks = {}
+ local watch_callbacks = {} --- @type function[]
local function send_event(...)
for _, cb in ipairs(watch_callbacks) do
cb(...)
@@ -5318,12 +5747,14 @@ describe('LSP', function()
local protocol = require('vim.lsp.protocol')
local watchers = {}
- local max_kind = protocol.WatchKind.Create + protocol.WatchKind.Change + protocol.WatchKind.Delete
+ local max_kind = protocol.WatchKind.Create
+ + protocol.WatchKind.Change
+ + protocol.WatchKind.Delete
for i = 0, max_kind do
table.insert(watchers, {
globPattern = {
baseUri = vim.uri_from_fname('/dir'),
- pattern = 'watch'..tostring(i),
+ pattern = 'watch' .. tostring(i),
},
kind = i,
})
@@ -5351,9 +5782,7 @@ describe('LSP', function()
wait_for_messages()
return server.messages
- ]],
- root_dir
- )
+ end)
local function watched_uri(fname)
return vim.uri_from_fname('/dir/' .. fname)
@@ -5364,51 +5793,51 @@ describe('LSP', function()
eq({
changes = {
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]),
+ type = created,
uri = watched_uri('watch1'),
},
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]),
+ type = changed,
uri = watched_uri('watch2'),
},
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]),
+ type = created,
uri = watched_uri('watch3'),
},
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]),
+ type = changed,
uri = watched_uri('watch3'),
},
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]),
+ type = deleted,
uri = watched_uri('watch4'),
},
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]),
+ type = created,
uri = watched_uri('watch5'),
},
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]),
+ type = deleted,
uri = watched_uri('watch5'),
},
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]),
+ type = changed,
uri = watched_uri('watch6'),
},
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]),
+ type = deleted,
uri = watched_uri('watch6'),
},
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]),
+ type = created,
uri = watched_uri('watch7'),
},
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]),
+ type = changed,
uri = watched_uri('watch7'),
},
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]),
+ type = deleted,
uri = watched_uri('watch7'),
},
},
@@ -5418,12 +5847,9 @@ describe('LSP', function()
it('prunes duplicate events', function()
local root_dir = 'some_dir'
exec_lua(create_server_definition)
- local result = exec_lua(
- [[
- local root_dir = ...
-
- local server = _create_server()
- local client_id = vim.lsp.start({
+ local result = exec_lua(function()
+ local server = _G._create_server()
+ local client_id = assert(vim.lsp.start({
name = 'watchfiles-test',
cmd = server.cmd,
root_dir = root_dir,
@@ -5434,16 +5860,22 @@ describe('LSP', function()
},
},
},
- })
+ }))
local expected_messages = 2 -- initialize, initialized
local function wait_for_messages()
- assert(vim.wait(200, function() return #server.messages == expected_messages end), 'Timed out waiting for expected number of messages. Current messages seen so far: ' .. vim.inspect(server.messages))
+ assert(
+ vim.wait(200, function()
+ return #server.messages == expected_messages
+ end),
+ 'Timed out waiting for expected number of messages. Current messages seen so far: '
+ .. vim.inspect(server.messages)
+ )
end
wait_for_messages()
- local send_event
+ local send_event --- @type function
require('vim.lsp._watchfiles')._watchfunc = function(_, _, callback)
send_event = callback
return function()
@@ -5477,24 +5909,22 @@ describe('LSP', function()
wait_for_messages()
return server.messages
- ]],
- root_dir
- )
+ end)
eq(3, #result)
eq('workspace/didChangeWatchedFiles', result[3].method)
eq({
changes = {
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]),
+ type = created,
uri = vim.uri_from_fname('file1'),
},
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]),
+ type = changed,
uri = vim.uri_from_fname('file1'),
},
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]),
+ type = created,
uri = vim.uri_from_fname('file2'),
},
},
@@ -5503,27 +5933,28 @@ describe('LSP', function()
it("ignores registrations by servers when the client doesn't advertise support", function()
exec_lua(create_server_definition)
- exec_lua([[
- server = _create_server()
- require('vim.lsp._watchfiles')._watchfunc = function(_, _, callback)
+ exec_lua(function()
+ _G.server = _G._create_server()
+ require('vim.lsp._watchfiles')._watchfunc = function(_, _, _)
-- Since the registration is ignored, this should not execute and `watching` should stay false
- watching = true
+ _G.watching = true
return function() end
end
- ]])
+ end)
local function check_registered(capabilities)
- return exec_lua(
- [[
- watching = false
- local client_id = vim.lsp.start({
+ return exec_lua(function()
+ _G.watching = false
+ local client_id = assert(vim.lsp.start({
name = 'watchfiles-test',
- cmd = server.cmd,
+ cmd = _G.server.cmd,
root_dir = 'some_dir',
- capabilities = ...,
+ capabilities = capabilities,
}, {
- reuse_client = function() return false end,
- })
+ reuse_client = function()
+ return false
+ end,
+ }))
vim.lsp.handlers['client/registerCapability'](nil, {
registrations = {
@@ -5552,10 +5983,8 @@ describe('LSP', function()
}, { client_id = client_id })
vim.lsp.stop_client(client_id, true)
- return watching
- ]],
- capabilities
- )
+ return _G.watching
+ end)
end
eq(is_os('mac') or is_os('win'), check_registered(nil)) -- start{_client}() defaults to make_client_capabilities().
diff --git a/test/functional/plugin/man_spec.lua b/test/functional/plugin/man_spec.lua
index 978178191c..6f0eeff748 100644
--- a/test/functional/plugin/man_spec.lua
+++ b/test/functional/plugin/man_spec.lua
@@ -8,7 +8,6 @@ local exec_lua = n.exec_lua
local fn = n.fn
local nvim_prog = n.nvim_prog
local matches = t.matches
-local write_file = t.write_file
local tmpname = t.tmpname
local eq = t.eq
local pesc = vim.pesc
@@ -17,21 +16,20 @@ local is_ci = t.is_ci
-- Collects all names passed to find_path() after attempting ":Man foo".
local function get_search_history(name)
- local args = vim.split(name, ' ')
- local code = [[
- local args = ...
- local man = require('runtime.lua.man')
+ return exec_lua(function()
+ local args = vim.split(name, ' ')
+ local man = require('man')
local res = {}
- man.find_path = function(sect, name)
- table.insert(res, {sect, name})
+ --- @diagnostic disable-next-line:duplicate-set-field
+ man.find_path = function(sect, name0)
+ table.insert(res, { sect, name0 })
return nil
end
- local ok, rv = pcall(man.open_page, -1, {tab = 0}, args)
+ local ok, rv = pcall(man.open_page, -1, { tab = 0 }, args)
assert(not ok)
assert(rv and rv:match('no manual entry'))
return res
- ]]
- return exec_lua(code, args)
+ end)
end
clear()
@@ -117,6 +115,29 @@ describe(':Man', function()
]])
end)
+ it('clears OSC 8 hyperlink markup from text', function()
+ feed(
+ [[
+ ithis <C-v><ESC>]8;;http://example.com<C-v><ESC>\Link Title<C-v><ESC>]8;;<C-v><ESC>\<ESC>]]
+ )
+
+ screen:expect {
+ grid = [=[
+ this {c:^[}]8;;http://example.com{c:^[}\Link Title{c:^[}]8;;{c:^[}^\ |
+ {eob:~ }|*3
+ |
+ ]=],
+ }
+
+ exec_lua [[require'man'.init_pager()]]
+
+ screen:expect([[
+ ^this Link Title |
+ {eob:~ }|*3
+ |
+ ]])
+ end)
+
it('highlights multibyte text', function()
feed(
[[
@@ -203,7 +224,6 @@ describe(':Man', function()
local actual_file = tmpname()
-- actual_file must be an absolute path to an existent file for us to test against it
matches('^/.+', actual_file)
- write_file(actual_file, '')
local args = { nvim_prog, '--headless', '+:Man ' .. actual_file, '+q' }
matches(
('Error detected while processing command line:\r\n' .. 'man.lua: "no manual entry for %s"'):format(
diff --git a/test/functional/plugin/msgpack_spec.lua b/test/functional/plugin/msgpack_spec.lua
index 1d5d20ec02..61ab730da8 100644
--- a/test/functional/plugin/msgpack_spec.lua
+++ b/test/functional/plugin/msgpack_spec.lua
@@ -58,23 +58,11 @@ describe('autoload/msgpack.vim', function()
msgpack_eq(1, '"abc\\ndef"', '"abc\\ndef"')
msgpack_eq(0, '"abc\\ndef"', '"abc\\nghi"')
end)
- it('compares binary specials correctly', function()
- msgpack_eq(1, sp('binary', '["abc\\n", "def"]'), sp('binary', '["abc\\n", "def"]'))
- msgpack_eq(0, sp('binary', '["abc", "def"]'), sp('binary', '["abc\\n", "def"]'))
- end)
- it('compares binary specials with raw binaries correctly', function()
- msgpack_eq(1, sp('binary', '["abc", "def"]'), '"abc\\ndef"')
- msgpack_eq(0, sp('binary', '["abc", "def"]'), '"abcdef"')
- end)
it('compares string specials correctly', function()
msgpack_eq(1, sp('string', '["abc\\n", "def"]'), sp('string', '["abc\\n", "def"]'))
msgpack_eq(0, sp('string', '["abc", "def"]'), sp('string', '["abc\\n", "def"]'))
- end)
- it('compares string specials with binary correctly', function()
- msgpack_eq(0, sp('string', '["abc\\n", "def"]'), sp('binary', '["abc\\n", "def"]'))
- msgpack_eq(0, sp('string', '["abc", "def"]'), '"abc\\ndef"')
- msgpack_eq(0, sp('binary', '["abc\\n", "def"]'), sp('string', '["abc\\n", "def"]'))
- msgpack_eq(0, '"abc\\ndef"', sp('string', '["abc", "def"]'))
+ msgpack_eq(1, sp('string', '["abc", "def"]'), '"abc\\ndef"')
+ msgpack_eq(1, '"abc\\ndef"', sp('string', '["abc", "def"]'))
end)
it('compares ext specials correctly', function()
msgpack_eq(1, sp('ext', '[1, ["", "ac"]]'), sp('ext', '[1, ["", "ac"]]'))
@@ -92,20 +80,16 @@ describe('autoload/msgpack.vim', function()
end)
it('compares map specials correctly', function()
msgpack_eq(1, mapsp(), mapsp())
- msgpack_eq(1, mapsp(sp('binary', '[""]'), '""'), mapsp(sp('binary', '[""]'), '""'))
msgpack_eq(
1,
mapsp(mapsp('1', '1'), mapsp('1', '1')),
mapsp(mapsp('1', '1'), mapsp('1', '1'))
)
msgpack_eq(0, mapsp(), mapsp('1', '1'))
- msgpack_eq(0, mapsp(sp('binary', '["a"]'), '""'), mapsp(sp('binary', '[""]'), '""'))
- msgpack_eq(0, mapsp(sp('binary', '[""]'), '"a"'), mapsp(sp('binary', '[""]'), '""'))
- msgpack_eq(0, mapsp(sp('binary', '["a"]'), '"a"'), mapsp(sp('binary', '[""]'), '""'))
msgpack_eq(
0,
mapsp(mapsp('1', '1'), mapsp('1', '1')),
- mapsp(sp('binary', '[""]'), mapsp('1', '1'))
+ mapsp(sp('string', '[""]'), mapsp('1', '1'))
)
msgpack_eq(
0,
@@ -138,7 +122,7 @@ describe('autoload/msgpack.vim', function()
msgpack_eq(1, mapsp(sp('string', '["1"]'), '1'), '{"1": 1}')
msgpack_eq(1, mapsp(sp('string', '["1"]'), sp('integer', '[1, 0, 0, 1]')), '{"1": 1}')
msgpack_eq(0, mapsp(sp('integer', '[1, 0, 0, 1]'), sp('string', '["1"]')), '{1: "1"}')
- msgpack_eq(0, mapsp('"1"', sp('integer', '[1, 0, 0, 1]')), '{"1": 1}')
+ msgpack_eq(1, mapsp('"1"', sp('integer', '[1, 0, 0, 1]')), '{"1": 1}')
msgpack_eq(0, mapsp(sp('string', '["1"]'), '1', sp('string', '["2"]'), '2'), '{"1": 1}')
msgpack_eq(0, mapsp(sp('string', '["1"]'), '1'), '{"1": 1, "2": 2}')
end)
@@ -290,7 +274,6 @@ describe('autoload/msgpack.vim', function()
it('works for special dictionaries', function()
type_eq('string', sp('string', '[""]'))
- type_eq('binary', sp('binary', '[""]'))
type_eq('ext', sp('ext', '[1, [""]]'))
type_eq('array', sp('array', '[]'))
type_eq('map', sp('map', '[]'))
@@ -301,7 +284,7 @@ describe('autoload/msgpack.vim', function()
end)
it('works for regular values', function()
- type_eq('binary', '""')
+ type_eq('string', '""')
type_eq('array', '[]')
type_eq('map', '{}')
type_eq('integer', '1')
@@ -319,7 +302,6 @@ describe('autoload/msgpack.vim', function()
it('works for special dictionaries', function()
sp_type_eq('string', sp('string', '[""]'))
- sp_type_eq('binary', sp('binary', '[""]'))
sp_type_eq('ext', sp('ext', '[1, [""]]'))
sp_type_eq('array', sp('array', '[]'))
sp_type_eq('map', sp('map', '[]'))
@@ -347,12 +329,9 @@ describe('autoload/msgpack.vim', function()
end
it('works for special dictionaries', function()
- string_eq('=""', sp('string', '[""]'))
- string_eq('="\\n"', sp('string', '["", ""]'))
- string_eq('="ab\\0c\\nde"', sp('string', '["ab\\nc", "de"]'))
- string_eq('""', sp('binary', '[""]'))
- string_eq('"\\n"', sp('binary', '["", ""]'))
- string_eq('"ab\\0c\\nde"', sp('binary', '["ab\\nc", "de"]'))
+ string_eq('""', sp('string', '[""]'))
+ string_eq('"\\n"', sp('string', '["", ""]'))
+ string_eq('"ab\\0c\\nde"', sp('string', '["ab\\nc", "de"]'))
string_eq('+(2)""', sp('ext', '[2, [""]]'))
string_eq('+(2)"\\n"', sp('ext', '[2, ["", ""]]'))
string_eq('+(2)"ab\\0c\\nde"', sp('ext', '[2, ["ab\\nc", "de"]]'))
@@ -397,8 +376,8 @@ describe('autoload/msgpack.vim', function()
string_eq('[]', '[]')
string_eq('[[[{}]]]', '[[[{}]]]')
string_eq('{}', '{}')
- string_eq('{="2": 10}', '{2: 10}')
- string_eq('{="2": [{}]}', '{2: [{}]}')
+ string_eq('{"2": 10}', '{2: 10}')
+ string_eq('{"2": [{}]}', '{2: [{}]}')
string_eq('1', '1')
string_eq('0.0', '0.0')
string_eq('inf', '(1.0/0.0)')
@@ -422,7 +401,6 @@ describe('autoload/msgpack.vim', function()
nvim_command('let spflt = ' .. sp('float', '1.0'))
nvim_command('let spext = ' .. sp('ext', '[2, ["abc", "def"]]'))
nvim_command('let spstr = ' .. sp('string', '["abc", "def"]'))
- nvim_command('let spbin = ' .. sp('binary', '["abc", "def"]'))
nvim_command('let spbln = ' .. sp('boolean', '0'))
nvim_command('let spnil = ' .. sp('nil', '0'))
@@ -432,7 +410,6 @@ describe('autoload/msgpack.vim', function()
nvim_command('let spflt2 = msgpack#deepcopy(spflt)')
nvim_command('let spext2 = msgpack#deepcopy(spext)')
nvim_command('let spstr2 = msgpack#deepcopy(spstr)')
- nvim_command('let spbin2 = msgpack#deepcopy(spbin)')
nvim_command('let spbln2 = msgpack#deepcopy(spbln)')
nvim_command('let spnil2 = msgpack#deepcopy(spnil)')
@@ -442,7 +419,6 @@ describe('autoload/msgpack.vim', function()
eq('float', nvim_eval('msgpack#type(spflt2)'))
eq('ext', nvim_eval('msgpack#type(spext2)'))
eq('string', nvim_eval('msgpack#type(spstr2)'))
- eq('binary', nvim_eval('msgpack#type(spbin2)'))
eq('boolean', nvim_eval('msgpack#type(spbln2)'))
eq('nil', nvim_eval('msgpack#type(spnil2)'))
@@ -457,7 +433,6 @@ describe('autoload/msgpack.vim', function()
nvim_command('let spext._VAL[0] = 3')
nvim_command('let spext._VAL[1][0] = "gh"')
nvim_command('let spstr._VAL[0] = "gh"')
- nvim_command('let spbin._VAL[0] = "gh"')
nvim_command('let spbln._VAL = 1')
nvim_command('let spnil._VAL = 1')
@@ -467,7 +442,6 @@ describe('autoload/msgpack.vim', function()
eq({ _TYPE = {}, _VAL = 1.0 }, nvim_eval('spflt2'))
eq({ _TYPE = {}, _VAL = { 2, { 'abc', 'def' } } }, nvim_eval('spext2'))
eq({ _TYPE = {}, _VAL = { 'abc', 'def' } }, nvim_eval('spstr2'))
- eq({ _TYPE = {}, _VAL = { 'abc', 'def' } }, nvim_eval('spbin2'))
eq({ _TYPE = {}, _VAL = 0 }, nvim_eval('spbln2'))
eq({ _TYPE = {}, _VAL = 0 }, nvim_eval('spnil2'))
@@ -477,7 +451,6 @@ describe('autoload/msgpack.vim', function()
nvim_command('let spflt._TYPE = []')
nvim_command('let spext._TYPE = []')
nvim_command('let spstr._TYPE = []')
- nvim_command('let spbin._TYPE = []')
nvim_command('let spbln._TYPE = []')
nvim_command('let spnil._TYPE = []')
@@ -487,7 +460,6 @@ describe('autoload/msgpack.vim', function()
eq('float', nvim_eval('msgpack#special_type(spflt2)'))
eq('ext', nvim_eval('msgpack#special_type(spext2)'))
eq('string', nvim_eval('msgpack#special_type(spstr2)'))
- eq('binary', nvim_eval('msgpack#special_type(spbin2)'))
eq('boolean', nvim_eval('msgpack#special_type(spbln2)'))
eq('nil', nvim_eval('msgpack#special_type(spnil2)'))
end)
@@ -509,7 +481,7 @@ describe('autoload/msgpack.vim', function()
eq('map', nvim_eval('msgpack#type(map2)'))
eq('integer', nvim_eval('msgpack#type(int2)'))
eq('float', nvim_eval('msgpack#type(flt2)'))
- eq('binary', nvim_eval('msgpack#type(bin2)'))
+ eq('string', nvim_eval('msgpack#type(bin2)'))
nvim_command('call add(arr, 0)')
nvim_command('call add(arr[0], 0)')
@@ -566,21 +538,6 @@ describe('autoload/msgpack.vim', function()
nvim_command('unlet g:__val')
end
- it('correctly loads binary strings', function()
- eval_eq('binary', { 'abcdef' }, '"abcdef"')
- eval_eq('binary', { 'abc', 'def' }, '"abc\\ndef"')
- eval_eq('binary', { 'abc\ndef' }, '"abc\\0def"')
- eval_eq('binary', { '\nabc\ndef\n' }, '"\\0abc\\0def\\0"')
- eval_eq('binary', { 'abc\n\n\ndef' }, '"abc\\0\\0\\0def"')
- eval_eq('binary', { 'abc\n', '\ndef' }, '"abc\\0\\n\\0def"')
- eval_eq('binary', { 'abc', '', '', 'def' }, '"abc\\n\\n\\ndef"')
- eval_eq('binary', { 'abc', '', '', 'def', '' }, '"abc\\n\\n\\ndef\\n"')
- eval_eq('binary', { '', 'abc', '', '', 'def' }, '"\\nabc\\n\\n\\ndef"')
- eval_eq('binary', { '' }, '""')
- eval_eq('binary', { '"' }, '"\\""')
- eval_eq('binary', { 'py3 print(sys.version_info)' }, '"py3 print(sys.version_info)"')
- end)
-
it('correctly loads strings', function()
eval_eq('string', { 'abcdef' }, '="abcdef"')
eval_eq('string', { 'abc', 'def' }, '="abc\\ndef"')
diff --git a/test/functional/plugin/shada_spec.lua b/test/functional/plugin/shada_spec.lua
index 1c2bcbd497..c9d49f7d01 100644
--- a/test/functional/plugin/shada_spec.lua
+++ b/test/functional/plugin/shada_spec.lua
@@ -68,7 +68,7 @@ describe('autoload/shada.vim', function()
endfor
return ret
elseif type(a:val) == type('')
- return {'_TYPE': v:msgpack_types.binary, '_VAL': split(a:val, "\n", 1)}
+ return {'_TYPE': v:msgpack_types.string, '_VAL': split(a:val, "\n", 1)}
else
return a:val
endif
@@ -253,8 +253,7 @@ describe('autoload/shada.vim', function()
' + sm magic value "TRUE"',
' # Expected integer',
' + so offset value "TRUE"',
- ' # Expected binary string',
- ' + sp pattern ="abc"',
+ ' + sp pattern "abc"',
},
([[ [{'type': 1, 'timestamp': 0, 'data': {
'sm': 'TRUE',
@@ -267,7 +266,7 @@ describe('autoload/shada.vim', function()
'n': -0x40,
'l': -10,
'c': 'abc',
- 'f': {'_TYPE': v:msgpack_types.binary, '_VAL': ["abc\ndef"]},
+ 'f': {'_TYPE': v:msgpack_types.string, '_VAL': ["abc\ndef"]},
}}] ]]):gsub('\n', '')
)
sd2strings_eq(
@@ -276,15 +275,14 @@ describe('autoload/shada.vim', function()
' % Key Description Value',
' # Expected no NUL bytes',
' + f file name "abc\\0def"',
- ' # Expected array of binary strings',
- ' + rc contents ["abc", ="abc"]',
+ ' + rc contents ["abc", "abc"]',
' # Expected integer',
' + rt type "ABC"',
},
([[ [{'type': 1, 'timestamp': 0, 'data': {
'rt': 'ABC',
'rc': ["abc", {'_TYPE': v:msgpack_types.string, '_VAL': ["abc"]}],
- 'f': {'_TYPE': v:msgpack_types.binary, '_VAL': ["abc\ndef"]},
+ 'f': {'_TYPE': v:msgpack_types.string, '_VAL': ["abc\ndef"]},
}}] ]]):gsub('\n', '')
)
sd2strings_eq(
@@ -295,7 +293,7 @@ describe('autoload/shada.vim', function()
' + rc contents ["abc", "a\\nd\\0"]',
},
([[ [{'type': 1, 'timestamp': 0, 'data': {
- 'rc': ["abc", {'_TYPE': v:msgpack_types.binary, '_VAL': ["a", "d\n"]}],
+ 'rc': ["abc", {'_TYPE': v:msgpack_types.string, '_VAL': ["a", "d\n"]}],
}}] ]]):gsub('\n', '')
)
end)
@@ -468,7 +466,7 @@ describe('autoload/shada.vim', function()
sd2strings_eq({
'Replacement string with timestamp ' .. epoch .. ':',
' # Unexpected type: map instead of array',
- ' = {="a": [10]}',
+ ' = {"a": [10]}',
}, { { type = 3, timestamp = 0, data = { a = { 10 } } } })
sd2strings_eq(
{
@@ -498,7 +496,7 @@ describe('autoload/shada.vim', function()
' - :s replacement string "abc\\0def"',
},
([[ [{'type': 3, 'timestamp': 0, 'data': [
- {'_TYPE': v:msgpack_types.binary, '_VAL': ["abc\ndef"]},
+ {'_TYPE': v:msgpack_types.string, '_VAL': ["abc\ndef"]},
]}] ]]):gsub('\n', '')
)
sd2strings_eq(
@@ -508,7 +506,7 @@ describe('autoload/shada.vim', function()
' - :s replacement string "abc\\ndef"',
},
([[ [{'type': 3, 'timestamp': 0, 'data': [
- {'_TYPE': v:msgpack_types.binary, '_VAL': ["abc", "def"]},
+ {'_TYPE': v:msgpack_types.string, '_VAL': ["abc", "def"]},
]}] ]]):gsub('\n', '')
)
sd2strings_eq(
@@ -519,7 +517,7 @@ describe('autoload/shada.vim', function()
' - 0',
},
([[ [{'type': 3, 'timestamp': 0, 'data': [
- {'_TYPE': v:msgpack_types.binary, '_VAL': ["abc", "def"]},
+ {'_TYPE': v:msgpack_types.string, '_VAL': ["abc", "def"]},
0,
]}] ]]):gsub('\n', '')
)
@@ -529,7 +527,7 @@ describe('autoload/shada.vim', function()
sd2strings_eq({
'History entry with timestamp ' .. epoch .. ':',
' # Unexpected type: map instead of array',
- ' = {="a": [10]}',
+ ' = {"a": [10]}',
}, { { type = 4, timestamp = 0, data = { a = { 10 } } } })
sd2strings_eq(
{
@@ -682,7 +680,7 @@ describe('autoload/shada.vim', function()
},
([[ [{'type': 4, 'timestamp': 0, 'data': [
4,
- {'_TYPE': v:msgpack_types.binary, '_VAL': ["abc\ndef"]},
+ {'_TYPE': v:msgpack_types.string, '_VAL': ["abc\ndef"]},
]}] ]]):gsub('\n', '')
)
sd2strings_eq(
@@ -909,7 +907,7 @@ describe('autoload/shada.vim', function()
sd2strings_eq({
'Variable with timestamp ' .. epoch .. ':',
' # Unexpected type: map instead of array',
- ' = {="a": [10]}',
+ ' = {"a": [10]}',
}, { { type = 6, timestamp = 0, data = { a = { 10 } } } })
sd2strings_eq(
{
@@ -941,7 +939,7 @@ describe('autoload/shada.vim', function()
' # Expected more elements in list',
},
([[ [{'type': 6, 'timestamp': 0, 'data': [
- {'_TYPE': v:msgpack_types.binary, '_VAL': ["\n"]},
+ {'_TYPE': v:msgpack_types.string, '_VAL': ["\n"]},
]}] ]]):gsub('\n', '')
)
sd2strings_eq(
@@ -952,7 +950,7 @@ describe('autoload/shada.vim', function()
' # Expected more elements in list',
},
([[ [{'type': 6, 'timestamp': 0, 'data': [
- {'_TYPE': v:msgpack_types.binary, '_VAL': ["foo"]},
+ {'_TYPE': v:msgpack_types.string, '_VAL': ["foo"]},
]}] ]]):gsub('\n', '')
)
sd2strings_eq(
@@ -963,7 +961,7 @@ describe('autoload/shada.vim', function()
' - value NIL',
},
([[ [{'type': 6, 'timestamp': 0, 'data': [
- {'_TYPE': v:msgpack_types.binary, '_VAL': ["foo"]},
+ {'_TYPE': v:msgpack_types.string, '_VAL': ["foo"]},
{'_TYPE': v:msgpack_types.nil, '_VAL': ["foo"]},
]}] ]]):gsub('\n', '')
)
@@ -976,7 +974,7 @@ describe('autoload/shada.vim', function()
' - NIL',
},
([[ [{'type': 6, 'timestamp': 0, 'data': [
- {'_TYPE': v:msgpack_types.binary, '_VAL': ["foo"]},
+ {'_TYPE': v:msgpack_types.string, '_VAL': ["foo"]},
{'_TYPE': v:msgpack_types.nil, '_VAL': ["foo"]},
{'_TYPE': v:msgpack_types.nil, '_VAL': ["foo"]},
]}] ]]):gsub('\n', '')
@@ -1041,7 +1039,7 @@ describe('autoload/shada.vim', function()
},
([[ [{'type': 7, 'timestamp': 0, 'data': {
'n': -10,
- 'f': {'_TYPE': v:msgpack_types.binary, '_VAL': ["\n"]},
+ 'f': {'_TYPE': v:msgpack_types.string, '_VAL': ["\n"]},
}}] ]]):gsub('\n', '')
)
sd2strings_eq(
@@ -1174,7 +1172,7 @@ describe('autoload/shada.vim', function()
},
([[ [{'type': 8, 'timestamp': 0, 'data': {
'n': -10,
- 'f': {'_TYPE': v:msgpack_types.binary, '_VAL': ["\n"]},
+ 'f': {'_TYPE': v:msgpack_types.string, '_VAL': ["\n"]},
}}] ]]):gsub('\n', '')
)
sd2strings_eq(
@@ -1237,7 +1235,7 @@ describe('autoload/shada.vim', function()
sd2strings_eq({
'Buffer list with timestamp ' .. epoch .. ':',
' # Unexpected type: map instead of array',
- ' = {="a": [10]}',
+ ' = {"a": [10]}',
}, { { type = 9, timestamp = 0, data = { a = { 10 } } } })
sd2strings_eq({
'Buffer list with timestamp ' .. epoch .. ':',
@@ -1247,7 +1245,7 @@ describe('autoload/shada.vim', function()
sd2strings_eq({
'Buffer list with timestamp ' .. epoch .. ':',
' # Expected array of maps',
- ' = [{="a": 10}, []]',
+ ' = [{"a": 10}, []]',
}, { { type = 9, timestamp = 0, data = { { a = 10 }, {} } } })
sd2strings_eq({
'Buffer list with timestamp ' .. epoch .. ':',
@@ -1322,7 +1320,7 @@ describe('autoload/shada.vim', function()
},
([[ [{'type': 9, 'timestamp': 0, 'data': [
{'f': 10},
- {'f': {'_TYPE': v:msgpack_types.binary, '_VAL': ["\n"]}},
+ {'f': {'_TYPE': v:msgpack_types.string, '_VAL': ["\n"]}},
]}] ]]):gsub('\n', '')
)
end)
@@ -1385,7 +1383,7 @@ describe('autoload/shada.vim', function()
},
([[ [{'type': 10, 'timestamp': 0, 'data': {
'n': -10,
- 'f': {'_TYPE': v:msgpack_types.binary, '_VAL': ["\n"]},
+ 'f': {'_TYPE': v:msgpack_types.string, '_VAL': ["\n"]},
}}] ]]):gsub('\n', '')
)
sd2strings_eq(
@@ -1504,7 +1502,7 @@ describe('autoload/shada.vim', function()
},
([[ [{'type': 11, 'timestamp': 0, 'data': {
'n': -10,
- 'f': {'_TYPE': v:msgpack_types.binary, '_VAL': ["\n"]},
+ 'f': {'_TYPE': v:msgpack_types.string, '_VAL': ["\n"]},
}}] ]]):gsub('\n', '')
)
sd2strings_eq(
@@ -1616,7 +1614,7 @@ describe('autoload/shada.vim', function()
timestamp = 0,
data = {
c = 'abc',
- f = { '!binary', { 'abc\ndef' } },
+ f = { '!string', { 'abc\ndef' } },
l = -10,
n = -64,
rc = '10',
@@ -1711,7 +1709,7 @@ describe('autoload/shada.vim', function()
timestamp = 0,
data = {
c = 'abc',
- f = { '!binary', { 'abc\ndef' } },
+ f = { '!string', { 'abc\ndef' } },
l = -10,
n = -64,
rc = '10',
@@ -1892,7 +1890,7 @@ describe('autoload/shada.vim', function()
} } }, {
'Replacement string with timestamp ' .. epoch .. ':',
' # Unexpected type: map instead of array',
- ' = {="a": [10]}',
+ ' = {"a": [10]}',
})
strings2sd_eq({ { type = 3, timestamp = 0, data = {} } }, {
'Replacement string with timestamp ' .. epoch .. ':',
@@ -1934,7 +1932,7 @@ describe('autoload/shada.vim', function()
} } }, {
'History entry with timestamp ' .. epoch .. ':',
' # Unexpected type: map instead of array',
- ' = {="a": [10]}',
+ ' = {"a": [10]}',
})
strings2sd_eq({ { type = 4, timestamp = 0, data = {} } }, {
'History entry with timestamp ' .. epoch .. ':',
@@ -2184,7 +2182,7 @@ describe('autoload/shada.vim', function()
} } }, {
'Variable with timestamp ' .. epoch .. ':',
' # Unexpected type: map instead of array',
- ' = {="a": [10]}',
+ ' = {"a": [10]}',
})
strings2sd_eq({ { type = 6, timestamp = 0, data = {} } }, {
'Variable with timestamp ' .. epoch .. ':',
@@ -2315,7 +2313,7 @@ describe('autoload/shada.vim', function()
} } }, {
'Buffer list with timestamp ' .. epoch .. ':',
' # Unexpected type: map instead of array',
- ' = {="a": [10]}',
+ ' = {"a": [10]}',
})
strings2sd_eq(
{ { type = 9, timestamp = 0, data = {
@@ -2325,7 +2323,7 @@ describe('autoload/shada.vim', function()
{
'Buffer list with timestamp ' .. epoch .. ':',
' # Expected array of maps',
- ' = [{="a": 10}, []]',
+ ' = [{"a": 10}, []]',
}
)
strings2sd_eq({ { type = 9, timestamp = 0, data = {
@@ -2421,7 +2419,7 @@ describe('autoload/shada.vim', function()
timestamp = 0,
data = {
{ f = 10 },
- { f = { '!binary', { '\n' } } },
+ { f = { '!string', { '\n' } } },
},
},
}, {
@@ -2955,7 +2953,7 @@ describe('ftplugin/shada.vim', function()
' - :s replacement string "abc\\ndef"',
' Buffer list with timestamp ' .. epoch .. ':',
' # Expected array of maps',
- '= [{="a": 10}, []]',
+ '= [{"a": 10}, []]',
' Buffer list with timestamp ' .. epoch .. ':',
' % Key Description Value',
' # Expected binary string',
@@ -2992,7 +2990,7 @@ describe('ftplugin/shada.vim', function()
' - :s replacement string "abc\\ndef"',
'Buffer list with timestamp ' .. epoch .. ':',
' # Expected array of maps',
- ' = [{="a": 10}, []]',
+ ' = [{"a": 10}, []]',
'Buffer list with timestamp ' .. epoch .. ':',
' % Key Description Value',
' # Expected binary string',
@@ -3083,7 +3081,7 @@ describe('syntax/shada.vim', function()
' - :s replacement string DEBUG',
'Buffer list with timestamp ' .. epoch .. ':',
' # Expected array of maps',
- ' = [{="a": +(10)"ac\\0df\\ngi\\"tt\\.", TRUE: FALSE}, [NIL, +(-10)""]]',
+ ' = [{"a": +(10)"ac\\0df\\ngi\\"tt\\.", TRUE: FALSE}, [NIL, +(-10)""]]',
'Buffer list with timestamp ' .. epoch .. ':',
' % Key Description Value',
'',
@@ -3119,8 +3117,8 @@ describe('syntax/shada.vim', function()
{1: -} {4::s replacement string} {1:DEBUG} |
{1:Buffer list} with timestamp 1970{1:-}01{1:-}01{1:T}00{1::}00{1::}00: |
{4: # Expected array of maps} |
- = {1:[{="}{3:a}{1:":} {1:+(}{5:10}{1:)"}{3:ac}{6:\0}{3:df}{6:\n}{3:gi}{6:\"}{3:tt\.}{1:",} {1:TRUE:} {1:FALSE},} {1:[NIL,} {1:+(}{5:-}|
- {5:10}{1:)""]]} |
+ = {1:[{"}{3:a}{1:":} {1:+(}{5:10}{1:)"}{3:ac}{6:\0}{3:df}{6:\n}{3:gi}{6:\"}{3:tt\.}{1:",} {1:TRUE:} {1:FALSE},} {1:[NIL,} {1:+(}{5:-1}|
+ {5:0}{1:)""]]} |
{1:Buffer list} with timestamp 1970{1:-}01{1:-}01{1:T}00{1::}00{1::}00: |
{2: % Key Description Value} |
|
@@ -3464,7 +3462,6 @@ describe('syntax/shada.vim', function()
{ { 'ShaDaEntryRawMsgpack' }, ' = ' },
{ { 'ShaDaMsgpackArray', 'ShaDaMsgpackArrayBraces' }, '[' },
{ { 'ShaDaMsgpackArray', 'ShaDaMsgpackMap', 'ShaDaMsgpackMapBraces' }, '{' },
- { { 'ShaDaMsgpackArray', 'ShaDaMsgpackMap', 'ShaDaMsgpackString' }, '=' },
{
{
'ShaDaMsgpackArray',
diff --git a/test/functional/plugin/tohtml_spec.lua b/test/functional/plugin/tohtml_spec.lua
index 200a5f34b2..1d05f4d6b4 100644
--- a/test/functional/plugin/tohtml_spec.lua
+++ b/test/functional/plugin/tohtml_spec.lua
@@ -33,6 +33,10 @@ local function html_syntax_match()
attr.underline = nil
attr.undercurl = true
end
+ attr.sp = style:match('text%-decoration%-color: #(%x+)')
+ if attr.sp then
+ attr.sp = tonumber(attr.sp, 16)
+ end
attr.bg = style:match('background%-color: #(%x+)')
if attr.bg then
attr.bg = tonumber(attr.bg, 16)
@@ -49,7 +53,7 @@ local function html_syntax_match()
local whitelist = {
'fg',
'bg',
- --'sp',
+ 'sp',
--'blend',
'bold',
--'standout',
@@ -132,6 +136,50 @@ local function run_tohtml_and_assert(screen, func)
screen:expect({ grid = expected.grid, attr_ids = expected.attr_ids })
end
+---@param guifont boolean
+local function test_generates_html(guifont, expect_font)
+ insert([[line]])
+ exec('set termguicolors')
+ local bg = fn.synIDattr(fn.hlID('Normal'), 'bg#', 'gui')
+ local fg = fn.synIDattr(fn.hlID('Normal'), 'fg#', 'gui')
+ local tmpfile = t.tmpname()
+
+ exec_lua(
+ [[
+ local guifont, outfile = ...
+ local html = (guifont
+ and require('tohtml').tohtml(0,{title="title"})
+ or require('tohtml').tohtml(0,{title="title",font={ "dumyfont","anotherfont" }}))
+ vim.fn.writefile(html, outfile)
+ vim.cmd.split(outfile)
+ ]],
+ guifont,
+ tmpfile
+ )
+
+ local out_file = api.nvim_buf_get_name(api.nvim_get_current_buf())
+ eq({
+ '<!DOCTYPE html>',
+ '<html>',
+ '<head>',
+ '<meta charset="UTF-8">',
+ '<title>title</title>',
+ ('<meta name="colorscheme" content="%s"></meta>'):format(api.nvim_get_var('colors_name')),
+ '<style>',
+ ('* {font-family: %s,monospace}'):format(expect_font),
+ ('body {background-color: %s; color: %s}'):format(bg, fg),
+ '</style>',
+ '</head>',
+ '<body style="display: flex">',
+ '<pre>',
+ 'line',
+ '',
+ '</pre>',
+ '</body>',
+ '</html>',
+ }, fn.readfile(out_file))
+end
+
describe(':TOhtml', function()
--- @type test.functional.ui.screen
local screen
@@ -142,33 +190,44 @@ describe(':TOhtml', function()
exec('colorscheme default')
end)
- it('expected internal html generated', function()
- insert([[line]])
+ it('generates html with given font', function()
+ test_generates_html(false, '"dumyfont","anotherfont"')
+ end)
+
+ it("generates html, respects 'guifont'", function()
+ exec_lua [[vim.o.guifont='Font,Escape\\,comma, Ignore space after comma']]
+ test_generates_html(true, '"Font","Escape,comma","Ignore space after comma"')
+ end)
+
+ it('generates html from range', function()
+ insert([[
+ line1
+ line2
+ line3
+ ]])
+ local ns = api.nvim_create_namespace ''
+ api.nvim_buf_set_extmark(0, ns, 0, 0, { end_col = 1, end_row = 1, hl_group = 'Visual' })
exec('set termguicolors')
local bg = fn.synIDattr(fn.hlID('Normal'), 'bg#', 'gui')
local fg = fn.synIDattr(fn.hlID('Normal'), 'fg#', 'gui')
- exec_lua [[
- local outfile = vim.fn.tempname() .. '.html'
- local html = require('tohtml').tohtml(0,{title="title",font="dumyfont"})
- vim.fn.writefile(html, outfile)
- vim.cmd.split(outfile)
- ]]
+ n.command('2,2TOhtml')
local out_file = api.nvim_buf_get_name(api.nvim_get_current_buf())
eq({
'<!DOCTYPE html>',
'<html>',
'<head>',
'<meta charset="UTF-8">',
- '<title>title</title>',
+ '<title></title>',
('<meta name="colorscheme" content="%s"></meta>'):format(api.nvim_get_var('colors_name')),
'<style>',
- '* {font-family: dumyfont,monospace}',
+ '* {font-family: monospace}',
('body {background-color: %s; color: %s}'):format(bg, fg),
+ '.Visual {background-color: #9b9ea4}',
'</style>',
'</head>',
'<body style="display: flex">',
- '<pre>',
- 'line',
+ '<pre><span class="Visual">',
+ 'l</span>ine2',
'',
'</pre>',
'</body>',
@@ -176,9 +235,9 @@ describe(':TOhtml', function()
}, fn.readfile(out_file))
end)
- it('highlight attributes generated', function()
+ it('generates highlight attributes', function()
--Make sure to uncomment the attribute in `html_syntax_match()`
- exec('hi LINE gui=' .. table.concat({
+ exec('hi LINE guisp=#00ff00 gui=' .. table.concat({
'bold',
'underline',
'italic',
@@ -287,7 +346,13 @@ describe(':TOhtml', function()
0,
{ virt_text = { { 'foo' } }, virt_text_pos = 'overlay' }
)
- api.nvim_buf_set_extmark(0, ns, 2, 0, { virt_text = { { 'foo' } }, virt_text_pos = 'inline' })
+ api.nvim_buf_set_extmark(
+ 0,
+ ns,
+ 2,
+ 0,
+ { virt_text = { { 'fo┊o', { 'Conceal', 'Comment' } } }, virt_text_pos = 'inline' }
+ )
--api.nvim_buf_set_extmark(0,ns,3,0,{virt_text={{'foo'}},virt_text_pos='right_align'})
run_tohtml_and_assert(screen)
end)
@@ -341,12 +406,12 @@ describe(':TOhtml', function()
local function run()
local buf = api.nvim_get_current_buf()
run_tohtml_and_assert(screen, function()
- exec_lua [[
- local outfile = vim.fn.tempname() .. '.html'
- local html = require('tohtml').tohtml(0,{number_lines=true})
- vim.fn.writefile(html, outfile)
- vim.cmd.split(outfile)
- ]]
+ exec_lua(function()
+ local outfile = vim.fn.tempname() .. '.html'
+ local html = require('tohtml').tohtml(0, { number_lines = true })
+ vim.fn.writefile(html, outfile)
+ vim.cmd.split(outfile)
+ end)
end)
api.nvim_set_current_buf(buf)
end