Skip to content

Commit

Permalink
feat(lsp): inlay hints - implement auto refresh
Browse files Browse the repository at this point in the history
Implements debounced automatic refresh of inlay hints,
adds public functions in lsp.lua and docs

Closes neovim#18086
  • Loading branch information
p00f committed Jun 11, 2023
1 parent 26e3daf commit ebb4197
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 8 deletions.
18 changes: 18 additions & 0 deletions runtime/doc/lsp.txt
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,24 @@ buf_detach_client({bufnr}, {client_id}) *vim.lsp.buf_detach_client()*
{bufnr} (integer) Buffer handle, or 0 for current
• {client_id} (integer) Client id

buf_inlay_hint_disable({bufnr}) *vim.lsp.buf_inlay_hint_disable()*
Disable inlay hints for a buffer

Parameters: ~
{bufnr} (integer|nil) Buffer handle, or nil for current

buf_inlay_hint_enable({bufnr}) *vim.lsp.buf_inlay_hint_enable()*
Enable inlay hints for a buffer

Parameters: ~
{bufnr} (integer|nil) Buffer handle, or nil for current

buf_inlay_hint_toggle({bufnr}) *vim.lsp.buf_inlay_hint_toggle()*
Toggle inlay hints for a buffer

Parameters: ~
{bufnr} (integer|nil) Buffer handle, or nil for current

buf_is_attached({bufnr}, {client_id}) *vim.lsp.buf_is_attached()*
Checks if a buffer is attached for a particular client.

Expand Down
20 changes: 19 additions & 1 deletion runtime/lua/vim/lsp.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ local protocol = require('vim.lsp.protocol')
local util = require('vim.lsp.util')
local sync = require('vim.lsp.sync')
local semantic_tokens = require('vim.lsp.semantic_tokens')
local inlay_hint = require('vim.lsp._inlay_hint')

local api = vim.api
local nvim_err_writeln, nvim_buf_get_lines, nvim_command, nvim_exec_autocmds =
Expand All @@ -17,7 +18,6 @@ local if_nil = vim.F.if_nil

local lsp = {
protocol = protocol,
_inlay_hint = require('vim.lsp._inlay_hint'),

handlers = default_handlers,

Expand Down Expand Up @@ -2399,6 +2399,24 @@ function lsp.buf_get_clients(bufnr)
return result
end

--- Enable inlay hints for a buffer
---@param bufnr (integer|nil) Buffer handle, or nil for current
function lsp.buf_inlay_hint_enable(bufnr)
inlay_hint.enable(bufnr)
end

--- Disable inlay hints for a buffer
---@param bufnr (integer|nil) Buffer handle, or nil for current
function lsp.buf_inlay_hint_disable(bufnr)
inlay_hint.disable(bufnr)
end

--- Toggle inlay hints for a buffer
---@param bufnr (integer|nil) Buffer handle, or nil for current
function lsp.buf_inlay_hint_toggle(bufnr)
inlay_hint.toggle(bufnr)
end

-- Log level dictionary with reverse lookup as well.
--
-- Can be used to lookup the number from the name or the
Expand Down
73 changes: 68 additions & 5 deletions runtime/lua/vim/lsp/_inlay_hint.lua
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,10 @@ local hint_cache_by_buf = setmetatable({}, {

local namespace = api.nvim_create_namespace('vim_lsp_inlayhint')

M.__explicit_buffers = {}
M.__buffers = {}

--- |lsp-handler| for the method `textDocument/inlayHint`
--- Store hints for a specific buffer and client
--- Resolves unresolved hints
---@private
function M.on_inlayhint(err, result, ctx, _)
if err then
Expand Down Expand Up @@ -116,7 +115,11 @@ function M.refresh(opts)
local bufnr = opts.bufnr or 0
local only_visible = opts.only_visible or false
bufnr = resolve_bufnr(bufnr)
M.__explicit_buffers[bufnr] = true
if M.__buffers[bufnr] then
M.__buffers[bufnr].enabled = true
else
M.__buffers[bufnr] = { enabled = true }
end
local buffer_windows = {}
for _, winid in ipairs(api.nvim_list_wins()) do
if api.nvim_win_get_buf(winid) == bufnr then
Expand Down Expand Up @@ -152,10 +155,14 @@ end
---@param client_id integer|nil filter by client_id. All clients if nil
---@param bufnr integer|nil filter by buffer. All buffers if nil
---@private
function M.clear(client_id, bufnr)
local function clear(client_id, bufnr)
local buffers = bufnr and { resolve_bufnr(bufnr) } or vim.tbl_keys(hint_cache_by_buf)
for _, iter_bufnr in ipairs(buffers) do
M.__explicit_buffers[iter_bufnr] = false
if M.__buffers[bufnr] then
M.__buffers[iter_bufnr].enabled = false
else
M.__buffers[iter_bufnr] = { enabled = false }
end
local bufstate = hint_cache_by_buf[iter_bufnr]
local client_lens = (bufstate or {}).client_hint or {}
local client_ids = client_id and { client_id } or vim.tbl_keys(client_lens)
Expand All @@ -169,6 +176,62 @@ function M.clear(client_id, bufnr)
vim.cmd('redraw!')
end

---@private
local function reset_timer(reset_bufnr)
local timer = M.__buffers[reset_bufnr].timer
if timer then
M.__buffers[reset_bufnr].timer = nil
if not timer:is_closing() then
timer:stop()
timer:close()
end
end
end

---@private
local function make_request(request_bufnr)
reset_timer(request_bufnr)
M.refresh({ bufnr = request_bufnr })
end

---@private
function M.enable(bufnr)
bufnr = bufnr or api.nvim_get_current_buf()
if not (M.__buffers[bufnr] and M.__buffers[bufnr].enabled) then
M.refresh({ bufnr = bufnr })
M.__buffers[bufnr] = { enabled = true, timer = nil }
api.nvim_buf_attach(bufnr, true, {
on_lines = function(_, cb_bufnr)
if not M.__buffers[cb_bufnr].enabled then
return true
end
reset_timer(cb_bufnr)
M.__buffers[cb_bufnr].timer = vim.defer_fn(function()
make_request(cb_bufnr)
end, 200)
end,
})
end
end

---@private
function M.disable(bufnr)
bufnr = bufnr or api.nvim_get_current_buf()
M.__buffers[bufnr].enabled = false
M.__buffers[bufnr].timer = nil
clear(nil, bufnr)
end

---@private
function M.toggle(bufnr)
bufnr = bufnr or api.nvim_get_current_buf()
if M.__buffers and M.__buffers[bufnr].enabled then
M.disable(bufnr)
else
M.enable(bufnr)
end
end

api.nvim_set_decoration_provider(namespace, {
on_win = function(_, _, bufnr, topline, botline)
local bufstate = hint_cache_by_buf[bufnr]
Expand Down
2 changes: 1 addition & 1 deletion runtime/lua/vim/lsp/handlers.lua
Original file line number Diff line number Diff line change
Expand Up @@ -619,7 +619,7 @@ end
---@see https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspace_inlayHint_refresh
M['workspace/inlayHint/refresh'] = function(err, _, ctx)
local inlay_hint = require('vim.lsp._inlay_hint')
if not inlay_hint.__explicit_buffers[ctx.bufnr] then
if not (inlay_hint.__buffers[ctx.bufnr] and inlay_hint.__buffers[ctx.bufnr].enabled) then
return vim.NIL
end
if err then
Expand Down
1 change: 0 additions & 1 deletion scripts/gen_vimdoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,6 @@
'log.lua',
'rpc.lua',
'protocol.lua',
'inlay_hint.lua'
],
'files': [
'runtime/lua/vim/lsp',
Expand Down

0 comments on commit ebb4197

Please sign in to comment.