diff options
author | LW <git@llllvvuu.dev> | 2023-11-12 04:54:27 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-11-12 04:54:27 -0800 |
commit | 448907f65d6709fa234d8366053e33311a01bdb9 (patch) | |
tree | 17dcb47f3f7481f7ded11e0675309461c7a15973 /test | |
parent | ad3568a70167ceb870931650afb7dcaed88640ec (diff) | |
download | rneovim-448907f65d6709fa234d8366053e33311a01bdb9.tar.gz rneovim-448907f65d6709fa234d8366053e33311a01bdb9.tar.bz2 rneovim-448907f65d6709fa234d8366053e33311a01bdb9.zip |
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
Diffstat (limited to 'test')
-rw-r--r-- | test/functional/helpers.lua | 7 | ||||
-rw-r--r-- | test/functional/plugin/lsp/inlay_hint_spec.lua | 363 | ||||
-rw-r--r-- | test/functional/plugin/lsp_spec.lua | 2 | ||||
-rw-r--r-- | test/functional/ui/screen.lua | 1 |
4 files changed, 172 insertions, 201 deletions
diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index 6f5397a089..761e7dc522 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -18,8 +18,7 @@ local sleep = global_helpers.sleep local tbl_contains = global_helpers.tbl_contains local fail = global_helpers.fail -local module = { -} +local module = {} local start_dir = luv.cwd() local runtime_set = 'set runtimepath^=./build/lib/nvim/' @@ -834,6 +833,8 @@ function module.exec_capture(code) return module.meths.exec2(code, { output = true }).output end +--- @param code string +--- @return any function module.exec_lua(code, ...) return module.meths.exec_lua(code, {...}) end @@ -948,8 +949,10 @@ function module.mkdir_p(path) or 'mkdir -p '..path)) end +--- @class test.functional.helpers: test.helpers module = global_helpers.tbl_extend('error', module, global_helpers) +--- @return test.functional.helpers return function(after_each) if after_each then after_each(function() diff --git a/test/functional/plugin/lsp/inlay_hint_spec.lua b/test/functional/plugin/lsp/inlay_hint_spec.lua index eec86fdb8e..d0d55df72b 100644 --- a/test/functional/plugin/lsp/inlay_hint_spec.lua +++ b/test/functional/plugin/lsp/inlay_hint_spec.lua @@ -10,228 +10,195 @@ 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('inlay hints', function() - local screen - before_each(function() - screen = Screen.new(50, 9) - screen:attach() +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('general', function() - local text = dedent([[ - auto add(int a, int b) { return a + b; } + 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 }) - int main() { - int x = 1; - int y = 2; - return add(x,y); - } - }]]) + 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 }) - 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} - ] - ]==] + 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, + } - before_each(function() - exec_lua(create_server_definition) exec_lua([[ - local response = ... - server = _create_server({ + local expected2 = ... + server2 = _create_server({ capabilities = { inlayHintProvider = true, }, handlers = { ['textDocument/inlayHint'] = function() - return vim.json.decode(response) + return { expected2 } end, } }) - ]], response) + 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) - - it( - 'inlay hints are applied when vim.lsp.inlay_hint(true) is called', - function() - local res = 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 = vim.lsp.get_client_by_id(client_id) - return { - supports_method = client.supports_method("textDocument/inlayHint") - } - ]]) - eq(res, { supports_method = true }) - - - insert(text) - exec_lua([[vim.lsp.inlay_hint(bufnr, true)]]) - screen:expect({ - grid = [[ - auto add(int a, int b)-> int { return a + b; } | - | - int main() { | - int x = 1; | - int y = 2; | - return add(a: x,b: y); | - } | - ^} | - | -]] - }) - end) - - it( - 'inlay hints are cleared when vim.lsp.inlay_hint(false) is called', - 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([[vim.lsp.inlay_hint(bufnr, true)]]) - screen:expect({ - grid = [[ - auto add(int a, int b)-> int { return a + b; } | - | - int main() { | - int x = 1; | - int y = 2; | - return add(a: x,b: y); | - } | - ^} | - | -]] - }) - exec_lua([[vim.lsp.inlay_hint(bufnr, false)]]) - screen:expect({ - grid = [[ - auto add(int a, int b) { return a + b; } | - | - int main() { | - int x = 1; | - int y = 2; | - return add(x,y); | - } | - ^} | - | -]], - unchanged = true - }) - end) - - it( - 'inlay hints are cleared when the client detaches', - 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([[vim.lsp.inlay_hint(bufnr, true)]]) - screen:expect({ - grid = [[ - auto add(int a, int b)-> int { return a + b; } | - | - int main() { | - int x = 1; | - int y = 2; | - return add(a: x,b: y); | - } | - ^} | - | -]] - }) - exec_lua([[vim.lsp.stop_client(client_id)]]) - screen:expect({ - grid = [[ - auto add(int a, int b) { return a + b; } | - | - int main() { | - int x = 1; | - int y = 2; | - return add(x,y); | - } | - ^} | - | -]], - unchanged = true - }) - end) - - it( - 'inlay hints are not cleared when one of several clients detaches', - function() - -- Start two clients - exec_lua([[ - bufnr = vim.api.nvim_get_current_buf() - vim.api.nvim_win_set_buf(0, bufnr) - server2 = _create_server({ - capabilities = { - inlayHintProvider = true, - }, - handlers = { - ['textDocument/inlayHint'] = function() - return {} - end, - } - }) - client1 = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) - client2 = vim.lsp.start({ name = 'dummy2', cmd = server2.cmd }) - ]]) - - insert(text) - exec_lua([[vim.lsp.inlay_hint(bufnr, true)]]) - screen:expect({ - grid = [[ - auto add(int a, int b)-> int { return a + b; } | - | - int main() { | - int x = 1; | - int y = 2; | - return add(a: x,b: y); | - } | - ^} | - | -]] - }) - - -- Now stop one client - exec_lua([[ vim.lsp.stop_client(client2) ]]) - - -- We should still see the hints - screen:expect({ - grid = [[ - auto add(int a, int b)-> int { return a + b; } | - | - int main() { | - int x = 1; | - int y = 2; | - return add(a: x,b: y); | - } | - ^} | - | -]], - unchanged = true - }) - end) end) end) diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index d56e5b4afa..bb8d775838 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -1291,7 +1291,7 @@ describe('LSP', function() on_handler = function(err, result, ctx) if ctx.method == 'start' then exec_lua [[ - vim.lsp.inlay_hint(BUFFER, true) + vim.lsp.inlay_hint.enable(BUFFER) ]] end if ctx.method == 'textDocument/inlayHint' then diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index d3ffb07749..810a68d387 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -88,6 +88,7 @@ local function isempty(v) return type(v) == 'table' and next(v) == nil end +--- @class test.functional.ui.screen local Screen = {} Screen.__index = Screen |