mirror of
https://github.com/neovim/neovim.git
synced 2026-08-28 01:51:52 +00:00
feat(lsp)!: reimplement textDocument/codeLens as decoration provider
This commit is contained in:
@@ -1,107 +1,248 @@
|
||||
local t = require('test.testutil')
|
||||
local n = require('test.functional.testnvim')()
|
||||
local t_lsp = require('test.functional.plugin.lsp.testutil')
|
||||
local Screen = require('test.functional.ui.screen')
|
||||
|
||||
local exec_lua = n.exec_lua
|
||||
local dedent = t.dedent
|
||||
local eq = t.eq
|
||||
|
||||
describe('vim.lsp.codelens', function()
|
||||
before_each(function()
|
||||
n.clear()
|
||||
exec_lua('require("vim.lsp")')
|
||||
end)
|
||||
local api = n.api
|
||||
local exec_lua = n.exec_lua
|
||||
local insert = n.insert
|
||||
|
||||
it('on_codelens_stores_and_displays_lenses', function()
|
||||
local fake_uri = 'file:///fake/uri'
|
||||
local bufnr = exec_lua(function()
|
||||
local bufnr = vim.uri_to_bufnr(fake_uri)
|
||||
local lines = { 'So', 'many', 'lines' }
|
||||
vim.fn.bufload(bufnr)
|
||||
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines)
|
||||
return bufnr
|
||||
local clear_notrace = t_lsp.clear_notrace
|
||||
local create_server_definition = t_lsp.create_server_definition
|
||||
|
||||
describe('vim.lsp.codelens', function()
|
||||
local text = dedent([[
|
||||
struct S {
|
||||
a: i32,
|
||||
b: String,
|
||||
}
|
||||
|
||||
impl S {
|
||||
fn new(a: i32, b: String) -> Self {
|
||||
S { a, b }
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let s = S::new(42, String::from("Hello, world!"));
|
||||
println!("S.a: {}, S.b: {}", s.a, s.b);
|
||||
}
|
||||
]])
|
||||
|
||||
local grid_with_lenses = dedent([[
|
||||
struct S { {1:1 implementation} |
|
||||
a: i32, |
|
||||
b: String, |
|
||||
} |
|
||||
|
|
||||
impl S { |
|
||||
fn new(a: i32, b: String) -> Self { |
|
||||
S { a, b } |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
fn main() { {1:▶︎ Run } |
|
||||
let s = S::new(42, String::from("Hello, world!"))|
|
||||
; |
|
||||
println!("S.a: {}, S.b: {}", s.a, s.b); |
|
||||
} |
|
||||
^ |
|
||||
{1:~ }|*2
|
||||
|
|
||||
]])
|
||||
|
||||
local grid_without_lenses = dedent([[
|
||||
struct S { |
|
||||
a: i32, |
|
||||
b: String, |
|
||||
} |
|
||||
|
|
||||
impl S { |
|
||||
fn new(a: i32, b: String) -> Self { |
|
||||
S { a, b } |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
fn main() { |
|
||||
let s = S::new(42, String::from("Hello, world!"))|
|
||||
; |
|
||||
println!("S.a: {}, S.b: {}", s.a, s.b); |
|
||||
} |
|
||||
^ |
|
||||
{1:~ }|*2
|
||||
|
|
||||
]])
|
||||
|
||||
--- @type test.functional.ui.screen
|
||||
local screen
|
||||
|
||||
--- @type integer
|
||||
local client_id
|
||||
|
||||
before_each(function()
|
||||
clear_notrace()
|
||||
exec_lua(create_server_definition)
|
||||
|
||||
screen = Screen.new(nil, 20)
|
||||
|
||||
client_id = exec_lua(function()
|
||||
_G.server = _G._create_server({
|
||||
capabilities = {
|
||||
codeLensProvider = {
|
||||
resolveProvider = true,
|
||||
},
|
||||
},
|
||||
handlers = {
|
||||
['textDocument/codeLens'] = function(_, _, callback)
|
||||
callback(nil, {
|
||||
{
|
||||
data = {
|
||||
kind = {
|
||||
impls = {
|
||||
position = {
|
||||
character = 7,
|
||||
line = 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
version = 0,
|
||||
},
|
||||
range = {
|
||||
['end'] = {
|
||||
character = 8,
|
||||
line = 0,
|
||||
},
|
||||
start = {
|
||||
character = 7,
|
||||
line = 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
command = {
|
||||
arguments = {},
|
||||
command = 'rust-analyzer.runSingle',
|
||||
title = '▶︎ Run ',
|
||||
},
|
||||
range = {
|
||||
['end'] = {
|
||||
character = 7,
|
||||
line = 11,
|
||||
},
|
||||
start = {
|
||||
character = 3,
|
||||
line = 11,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
end,
|
||||
['codeLens/resolve'] = function(_, _, callback)
|
||||
vim.schedule(function()
|
||||
callback(nil, {
|
||||
command = {
|
||||
arguments = {},
|
||||
command = 'rust-analyzer.showReferences',
|
||||
title = '1 implementation',
|
||||
},
|
||||
range = {
|
||||
['end'] = {
|
||||
character = 8,
|
||||
line = 0,
|
||||
},
|
||||
start = {
|
||||
character = 7,
|
||||
line = 0,
|
||||
},
|
||||
},
|
||||
})
|
||||
end)
|
||||
end,
|
||||
},
|
||||
})
|
||||
|
||||
return vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
|
||||
end)
|
||||
|
||||
insert(text)
|
||||
|
||||
exec_lua(function()
|
||||
local lenses = {
|
||||
{
|
||||
range = {
|
||||
start = { line = 0, character = 0 },
|
||||
['end'] = { line = 0, character = 0 },
|
||||
},
|
||||
command = { title = 'Lens1', command = 'Dummy' },
|
||||
},
|
||||
}
|
||||
vim.lsp.codelens.on_codelens(
|
||||
nil,
|
||||
lenses,
|
||||
{ method = 'textDocument/codeLens', client_id = 1, bufnr = bufnr }
|
||||
)
|
||||
vim.lsp.codelens.enable()
|
||||
end)
|
||||
|
||||
local stored_lenses = exec_lua(function()
|
||||
return vim.lsp.codelens.get(bufnr)
|
||||
screen:expect({ grid = grid_with_lenses })
|
||||
end)
|
||||
|
||||
it('clears code lenses when disabled', function()
|
||||
exec_lua(function()
|
||||
vim.lsp.codelens.enable(false)
|
||||
end)
|
||||
local expected = {
|
||||
|
||||
screen:expect({ grid = grid_without_lenses })
|
||||
end)
|
||||
|
||||
it('clears code lenses when sole client detaches', function()
|
||||
exec_lua(function()
|
||||
vim.lsp.get_client_by_id(client_id):stop()
|
||||
end)
|
||||
|
||||
screen:expect({ grid = grid_without_lenses })
|
||||
end)
|
||||
|
||||
it('get code lenses in the current buffer', function()
|
||||
local result = exec_lua(function()
|
||||
vim.api.nvim_win_set_cursor(0, { 12, 3 })
|
||||
return vim.lsp.codelens.get()
|
||||
end)
|
||||
|
||||
eq({
|
||||
{
|
||||
range = {
|
||||
start = { line = 0, character = 0 },
|
||||
['end'] = { line = 0, character = 0 },
|
||||
},
|
||||
command = {
|
||||
title = 'Lens1',
|
||||
command = 'Dummy',
|
||||
client_id = 1,
|
||||
lens = {
|
||||
command = {
|
||||
arguments = {},
|
||||
command = 'rust-analyzer.showReferences',
|
||||
title = '1 implementation',
|
||||
},
|
||||
range = {
|
||||
['end'] = {
|
||||
character = 8,
|
||||
line = 0,
|
||||
},
|
||||
start = {
|
||||
character = 7,
|
||||
line = 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
eq(expected, stored_lenses)
|
||||
|
||||
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
|
||||
end)
|
||||
|
||||
eq({ [1] = { 'Lens1', 'LspCodeLens' } }, virtual_text_chunks)
|
||||
{
|
||||
client_id = 1,
|
||||
lens = {
|
||||
command = {
|
||||
arguments = {},
|
||||
command = 'rust-analyzer.runSingle',
|
||||
title = '▶︎ Run ',
|
||||
},
|
||||
range = {
|
||||
['end'] = {
|
||||
character = 7,
|
||||
line = 11,
|
||||
},
|
||||
start = {
|
||||
character = 3,
|
||||
line = 11,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}, result)
|
||||
end)
|
||||
|
||||
it('can clear all lens', function()
|
||||
local fake_uri = 'file:///fake/uri'
|
||||
local bufnr = exec_lua(function()
|
||||
local bufnr = vim.uri_to_bufnr(fake_uri)
|
||||
local lines = { 'So', 'many', 'lines' }
|
||||
vim.fn.bufload(bufnr)
|
||||
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines)
|
||||
return bufnr
|
||||
end)
|
||||
|
||||
exec_lua(function()
|
||||
local lenses = {
|
||||
{
|
||||
range = {
|
||||
start = { line = 0, character = 0 },
|
||||
['end'] = { line = 0, character = 0 },
|
||||
},
|
||||
command = { title = 'Lens1', command = 'Dummy' },
|
||||
},
|
||||
}
|
||||
vim.lsp.codelens.on_codelens(
|
||||
nil,
|
||||
lenses,
|
||||
{ method = 'textDocument/codeLens', client_id = 1, bufnr = bufnr }
|
||||
)
|
||||
end)
|
||||
|
||||
local stored_lenses = exec_lua(function()
|
||||
return vim.lsp.codelens.get(bufnr)
|
||||
end)
|
||||
eq(1, #stored_lenses)
|
||||
|
||||
exec_lua(function()
|
||||
vim.lsp.codelens.clear()
|
||||
end)
|
||||
|
||||
stored_lenses = exec_lua(function()
|
||||
return vim.lsp.codelens.get(bufnr)
|
||||
end)
|
||||
eq(0, #stored_lenses)
|
||||
after_each(function()
|
||||
api.nvim_exec_autocmds('VimLeavePre', { modeline = false })
|
||||
end)
|
||||
end)
|
||||
|
||||
Reference in New Issue
Block a user