diff options
Diffstat (limited to 'runtime/lua/vim/lsp/inlay_hint.lua')
-rw-r--r-- | runtime/lua/vim/lsp/inlay_hint.lua | 160 |
1 files changed, 94 insertions, 66 deletions
diff --git a/runtime/lua/vim/lsp/inlay_hint.lua b/runtime/lua/vim/lsp/inlay_hint.lua index 3d8b54ee3d..985cbef5ff 100644 --- a/runtime/lua/vim/lsp/inlay_hint.lua +++ b/runtime/lua/vim/lsp/inlay_hint.lua @@ -4,13 +4,26 @@ local ms = require('vim.lsp.protocol').Methods local api = vim.api local M = {} ----@class (private) vim.lsp.inlay_hint.bufstate +---@class (private) vim.lsp.inlay_hint.globalstate Global state for inlay hints +---@field enabled boolean Whether inlay hints are enabled for this scope +---@type vim.lsp.inlay_hint.globalstate +local globalstate = { + enabled = false, +} + +---@class (private) vim.lsp.inlay_hint.bufstate: vim.lsp.inlay_hint.globalstate Buffer local state for inlay hints ---@field version? integer ---@field client_hints? table<integer, table<integer, lsp.InlayHint[]>> client_id -> (lnum -> hints) ---@field applied table<integer, integer> Last version of hints applied to this line ----@field enabled boolean Whether inlay hints are enabled for this buffer ---@type table<integer, vim.lsp.inlay_hint.bufstate> -local bufstates = {} +local bufstates = vim.defaulttable(function(_) + return setmetatable({ applied = {} }, { + __index = globalstate, + __newindex = function(state, key, value) + rawset(state, key, (globalstate[key] ~= value) and value or nil) + end, + }) +end) local namespace = api.nvim_create_namespace('vim_lsp_inlayhint') local augroup = api.nvim_create_augroup('vim_lsp_inlayhint', {}) @@ -34,7 +47,7 @@ function M.on_inlayhint(err, result, ctx, _) return end local bufstate = bufstates[bufnr] - if not bufstate or not bufstate.enabled then + if not bufstate.enabled then return end if not (bufstate.client_hints and bufstate.version) then @@ -91,11 +104,7 @@ function M.on_refresh(err, _, ctx, _) for _, bufnr in ipairs(vim.lsp.get_buffers_by_client_id(ctx.client_id)) do for _, winid in ipairs(api.nvim_list_wins()) do if api.nvim_win_get_buf(winid) == bufnr then - local bufstate = bufstates[bufnr] - if bufstate then - util._refresh(ms.textDocument_inlayHint, { bufnr = bufnr }) - break - end + util._refresh(ms.textDocument_inlayHint, { bufnr = bufnr }) end end end @@ -154,7 +163,7 @@ function M.get(filter) end local bufstate = bufstates[bufnr] - if not (bufstate and bufstate.client_hints) then + if not bufstate.client_hints then return {} end @@ -203,12 +212,9 @@ end --- Clear inlay hints ---@param bufnr (integer) Buffer handle, or 0 for current local function clear(bufnr) - if bufnr == nil or bufnr == 0 then + if bufnr == 0 then bufnr = api.nvim_get_current_buf() end - if not bufstates[bufnr] then - return - end local bufstate = bufstates[bufnr] local client_lens = (bufstate or {}).client_hints or {} local client_ids = vim.tbl_keys(client_lens) --- @type integer[] @@ -222,15 +228,14 @@ local function clear(bufnr) end --- Disable inlay hints for a buffer ----@param bufnr (integer|nil) Buffer handle, or 0 or nil for current +---@param bufnr (integer) Buffer handle, or 0 for current local function _disable(bufnr) - if bufnr == nil or bufnr == 0 then + if bufnr == 0 then bufnr = api.nvim_get_current_buf() end clear(bufnr) - if bufstates[bufnr] then - bufstates[bufnr] = { enabled = false, applied = {} } - end + bufstates[bufnr] = nil + bufstates[bufnr].enabled = false end --- Refresh inlay hints, only if we have attached clients that support it @@ -244,30 +249,38 @@ local function _refresh(bufnr, opts) end --- Enable inlay hints for a buffer ----@param bufnr (integer|nil) Buffer handle, or 0 or nil for current +---@param bufnr (integer) Buffer handle, or 0 for current local function _enable(bufnr) - if bufnr == nil or bufnr == 0 then + if bufnr == 0 then bufnr = api.nvim_get_current_buf() end - local bufstate = bufstates[bufnr] - if not bufstate then - bufstates[bufnr] = { applied = {}, enabled = true } - api.nvim_create_autocmd('LspNotify', { - buffer = bufnr, - callback = function(opts) - if - opts.data.method ~= ms.textDocument_didChange - and opts.data.method ~= ms.textDocument_didOpen - then - return - end - if bufstates[bufnr] and bufstates[bufnr].enabled then - _refresh(bufnr, { client_id = opts.data.client_id }) - end - end, - group = augroup, - }) - _refresh(bufnr) + bufstates[bufnr] = nil + bufstates[bufnr].enabled = true + _refresh(bufnr) +end + +api.nvim_create_autocmd('LspNotify', { + callback = function(args) + ---@type integer + local bufnr = args.buf + + if + args.data.method ~= ms.textDocument_didChange + and args.data.method ~= ms.textDocument_didOpen + then + return + end + if bufstates[bufnr].enabled then + _refresh(bufnr, { client_id = args.data.client_id }) + end + end, + group = augroup, +}) +api.nvim_create_autocmd('LspAttach', { + callback = function(args) + ---@type integer + local bufnr = args.buf + api.nvim_buf_attach(bufnr, false, { on_reload = function(_, cb_bufnr) clear(cb_bufnr) @@ -278,32 +291,30 @@ local function _enable(bufnr) end, on_detach = function(_, cb_bufnr) _disable(cb_bufnr) + bufstates[cb_bufnr] = nil end, }) - api.nvim_create_autocmd('LspDetach', { - buffer = bufnr, - callback = function(args) - local clients = vim.lsp.get_clients({ bufnr = bufnr, method = ms.textDocument_inlayHint }) - - if - not vim.iter(clients):any(function(c) - return c.id ~= args.data.client_id - end) - then - _disable(bufnr) - end - end, - group = augroup, - }) - else - bufstate.enabled = true - _refresh(bufnr) - end -end + end, + group = augroup, +}) +api.nvim_create_autocmd('LspDetach', { + callback = function(args) + ---@type integer + local bufnr = args.buf + local clients = vim.lsp.get_clients({ bufnr = bufnr, method = ms.textDocument_inlayHint }) + if not vim.iter(clients):any(function(c) + return c.id ~= args.data.client_id + end) then + _disable(bufnr) + end + end, + group = augroup, +}) api.nvim_set_decoration_provider(namespace, { on_win = function(_, _, bufnr, topline, botline) - local bufstate = bufstates[bufnr] + ---@type vim.lsp.inlay_hint.bufstate + local bufstate = rawget(bufstates, bufnr) if not bufstate then return end @@ -361,13 +372,13 @@ function M.is_enabled(bufnr) if bufnr == nil or bufnr == 0 then bufnr = api.nvim_get_current_buf() end - return bufstates[bufnr] and bufstates[bufnr].enabled or false + return bufstates[bufnr].enabled end --- Optional filters |kwargs|, or `nil` for all. --- @class vim.lsp.inlay_hint.enable.Filter --- @inlinedoc ---- Buffer number, or 0/nil for current buffer. +--- Buffer number, or 0 for current buffer, or nil for all. --- @field bufnr integer? --- Enables or disables inlay hints for a buffer. @@ -392,11 +403,28 @@ function M.enable(enable, filter) end vim.validate({ enable = { enable, 'boolean', true }, filter = { filter, 'table', true } }) + enable = enable == nil or enable filter = filter or {} - if enable == false then - _disable(filter.bufnr) + + if filter.bufnr == nil then + globalstate.enabled = enable + for bufnr, _ in pairs(bufstates) do + if api.nvim_buf_is_loaded(bufnr) then + if enable == false then + _disable(bufnr) + else + _enable(bufnr) + end + else + bufstates[bufnr] = nil + end + end else - _enable(filter.bufnr) + if enable == false then + _disable(filter.bufnr) + else + _enable(filter.bufnr) + end end end |