mirror of
https://github.com/neovim/neovim.git
synced 2026-04-19 22:10:45 +00:00
fix(lsp): codelens text flickers #38782
Problem: When a new textDocument/codeLens response arrives with unresolved lenses, on_win clears the existing codelens row before codeLens/resolve completes. This causes the displayed codelens text to flicker while typing. Solution: Keep the current virtual lines if any of the refreshed lenses are still unresolved. Clear the old virtual lines only when the line no longer has lenses or all its lenses are resolved. A trade-off is that the user may temporarily see outdated codelenses. However, that's preferable to spamming updates on every refresh. AI-assisted: Codex
This commit is contained in:
@@ -227,11 +227,10 @@ function Provider:on_win(toprow, botrow)
|
||||
for client_id, state in pairs(self.client_state) do
|
||||
local bufnr = self.bufnr
|
||||
local namespace = state.namespace
|
||||
|
||||
api.nvim_buf_clear_namespace(bufnr, namespace, row, row + 1)
|
||||
|
||||
local lenses = state.row_lenses[row]
|
||||
if lenses then
|
||||
if not lenses then
|
||||
api.nvim_buf_clear_namespace(bufnr, namespace, row, row + 1)
|
||||
else
|
||||
table.sort(lenses, function(a, b)
|
||||
return a.range.start.character < b.range.start.character
|
||||
end)
|
||||
@@ -242,10 +241,12 @@ function Provider:on_win(toprow, botrow)
|
||||
local virt_text = {
|
||||
{ string.rep(' ', range.start_col), 'LspCodeLensSeparator' },
|
||||
}
|
||||
local has_unresolved = false
|
||||
|
||||
for _, lens in ipairs(lenses) do
|
||||
-- A code lens is unresolved when no command is associated to it.
|
||||
if not lens.command then
|
||||
has_unresolved = true
|
||||
self:resolve(client, lens)
|
||||
else
|
||||
vim.list_extend(virt_text, {
|
||||
@@ -254,25 +255,37 @@ function Provider:on_win(toprow, botrow)
|
||||
})
|
||||
end
|
||||
end
|
||||
-- Remove trailing separator.
|
||||
table.remove(virt_text)
|
||||
|
||||
-- Use a placeholder to prevent flickering caused by layout shifts.
|
||||
if #virt_text == 1 then
|
||||
table.insert(virt_text, { '', 'LspCodeLens' })
|
||||
end
|
||||
local had_extmark = #api.nvim_buf_get_extmarks(
|
||||
bufnr,
|
||||
namespace,
|
||||
{ row, 0 },
|
||||
{ row, -1 },
|
||||
{}
|
||||
) > 0
|
||||
|
||||
api.nvim_buf_set_extmark(bufnr, namespace, row, 0, {
|
||||
virt_lines = { virt_text },
|
||||
virt_lines_above = true,
|
||||
virt_lines_overflow = 'scroll',
|
||||
hl_mode = 'combine',
|
||||
})
|
||||
if not has_unresolved or not had_extmark then
|
||||
-- Remove trailing separator.
|
||||
table.remove(virt_text)
|
||||
|
||||
-- Fix https://github.com/neovim/neovim/issues/16166
|
||||
-- Make sure the code lens on the first line is visible when updating.
|
||||
if row == 0 then
|
||||
vim.fn.winrestview({ topfill = 1 })
|
||||
-- Use a placeholder to prevent flickering caused by layout shifts.
|
||||
if #virt_text == 1 then
|
||||
table.insert(virt_text, { '', 'LspCodeLens' })
|
||||
end
|
||||
|
||||
api.nvim_buf_clear_namespace(bufnr, namespace, row, row + 1)
|
||||
api.nvim_buf_set_extmark(bufnr, namespace, row, 0, {
|
||||
virt_lines = { virt_text },
|
||||
virt_lines_above = true,
|
||||
virt_lines_overflow = 'scroll',
|
||||
hl_mode = 'combine',
|
||||
})
|
||||
|
||||
-- Fix https://github.com/neovim/neovim/issues/16166
|
||||
-- Make sure the code lens on the first line is visible when updating.
|
||||
if row == 0 then
|
||||
vim.fn.winrestview({ topfill = 1 })
|
||||
end
|
||||
end
|
||||
end
|
||||
self.row_version[row] = self.version
|
||||
|
||||
Reference in New Issue
Block a user