Files
neovim/test/functional/plugin/lsp/inlay_hint_spec.lua
LW 448907f65d feat(lsp)!: vim.lsp.inlay_hint.get(), enable(), is_enabled() #25512
refactor!: `vim.lsp.inlay_hint()` -> `vim.lsp.inlay_hint.enable()`

Problem:
The LSP specification allows inlay hints to include tooltips, clickable
label parts, and code actions; but Neovim provides no API to query for
these.

Solution:
Add minimal viable extension point from which plugins can query for
inlay hints in a range, in order to build functionality on top of.

Possible Next Steps
---

- Add `virt_text_idx` field to `vim.fn.getmousepos()` return value, for
  usage in mappings of `<LeftMouse>`, `<C-LeftMouse>`, etc
2023-11-12 04:54:27 -08:00

205 lines
6.3 KiB
Lua

local helpers = require('test.functional.helpers')(after_each)
local lsp_helpers = require('test.functional.plugin.lsp.helpers')
local Screen = require('test.functional.ui.screen')
local eq = helpers.eq
local dedent = helpers.dedent
local exec_lua = helpers.exec_lua
local insert = helpers.insert
local clear_notrace = lsp_helpers.clear_notrace
local create_server_definition = lsp_helpers.create_server_definition
local text = dedent([[
auto add(int a, int b) { return a + b; }
int main() {
int x = 1;
int y = 2;
return add(x,y);
}
}]])
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},
{"kind":2,"paddingLeft":false,"label":"b:","position":{"character":17,"line":5},"paddingRight":true}
]
]==]
local grid_without_inlay_hints = [[
auto add(int a, int b) { return a + b; } |
|
int main() { |
int x = 1; |
int y = 2; |
return add(x,y); |
} |
^} |
|
]]
local grid_with_inlay_hints = [[
auto add(int a, int b)-> int { return a + b; } |
|
int main() { |
int x = 1; |
int y = 2; |
return add(a: x,b: y); |
} |
^} |
|
]]
--- @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()
return vim.json.decode(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 = server.cmd })
]], response)
insert(text)
exec_lua([[vim.lsp.inlay_hint.enable(bufnr)]])
screen:expect({ grid = grid_with_inlay_hints })
end)
after_each(function()
exec_lua("vim.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)]])
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({
capabilities = {
inlayHintProvider = true,
},
handlers = {
['textDocument/inlayHint'] = function()
return {}
end,
}
})
client2 = vim.lsp.start({ name = 'dummy2', cmd = server2.cmd })
vim.lsp.inlay_hint.enable(bufnr)
]])
exec_lua([[ vim.lsp.stop_client(client2) ]])
screen:expect({ grid = grid_with_inlay_hints, unchanged = true })
end)
describe('enable()', function()
it('clears/applies inlay hints when passed false/true/nil', function()
exec_lua([[vim.lsp.inlay_hint.enable(bufnr, false)]])
screen:expect({ grid = grid_without_inlay_hints, unchanged = true })
exec_lua([[vim.lsp.inlay_hint.enable(bufnr, true)]])
screen:expect({ grid = grid_with_inlay_hints, unchanged = true })
exec_lua([[vim.lsp.inlay_hint.enable(bufnr, not vim.lsp.inlay_hint.is_enabled(bufnr))]])
screen:expect({ grid = grid_without_inlay_hints, unchanged = true })
exec_lua([[vim.lsp.inlay_hint.enable(bufnr)]])
screen:expect({ grid = grid_with_inlay_hints, unchanged = true })
end)
end)
describe('get()', function()
it('returns filtered inlay hints', function()
--- @type lsp.InlayHint[]
local expected = vim.json.decode(response)
local expected2 = {
kind = 1,
paddingLeft = false,
label = ': int',
position = {
character = 10,
line = 2,
},
paddingRight = false,
}
exec_lua([[
local expected2 = ...
server2 = _create_server({
capabilities = {
inlayHintProvider = true,
},
handlers = {
['textDocument/inlayHint'] = function()
return { expected2 }
end,
}
})
client2 = vim.lsp.start({ name = 'dummy2', cmd = server2.cmd })
vim.lsp.inlay_hint.enable(bufnr)
]], expected2)
--- @type vim.lsp.inlay_hint.get.ret
local res = exec_lua([[return vim.lsp.inlay_hint.get()]])
eq(res, {
{ 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 },
})
--- @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(res, {
{ bufnr = 1, client_id = 2, inlay_hint = expected2 },
})
--- @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(res, {
{ bufnr = 1, client_id = 1, inlay_hint = expected[2] },
{ bufnr = 1, client_id = 1, inlay_hint = expected[3] },
})
--- @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, {})
end)
end)
end)