Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 16 additions & 14 deletions lua/hover/providers.lua
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@ M.providers = {}

local id_cnt = 0

--- @param provider Hover.Provider.Resolved
--- @param provider Hover.Provider
--- @param mod string
--- @param group? Hover.ProviderGroup
local function add_provider(provider, mod, group)
function M.add_provider(provider, mod, group)
if not provider.execute then
error(
('error: hover provider %s does not provide an execute function'):format(
Expand All @@ -61,40 +61,42 @@ local function add_provider(provider, mod, group)
)
end

provider.id = id_cnt
local resolved = vim.deepcopy(provider) --[[@as Hover.Provider.Resolved]]

resolved.id = id_cnt
id_cnt = id_cnt + 1
provider.module = mod
resolved.module = mod

if group then
provider.priority = provider.priority or group.priority
resolved.priority = provider.priority or group.priority
if group.name then
provider.name = ('%s[%s]'):format(group.name, provider.name)
resolved.name = ('%s[%s]'):format(group.name, provider.name)
end
end

if provider.priority then
if resolved.priority then
for i, p in ipairs(M.providers) do
if not p.priority or p.priority < provider.priority then
table.insert(M.providers, i, provider)
if not p.priority or p.priority < resolved.priority then
table.insert(M.providers, i, resolved)
return
end
end
end
table.insert(M.providers, provider)
table.insert(M.providers, resolved)
end

--- @param provider_or_group Hover.Provider|Hover.ProviderGroup
--- @param module string
local function add_provider_or_group(provider_or_group, module)
if provider_or_group.providers then
local group = provider_or_group --[[@as Hover.ProviderGroup]]
local gproviders = group.providers --[[@as Hover.Provider.Resolved[] ]]
local gproviders = group.providers
for _, p in ipairs(gproviders) do
add_provider(p, module, group)
M.add_provider(p, module, group)
end
else
local provider = provider_or_group --[[@as Hover.Provider.Resolved]]
add_provider(provider, module)
local provider = provider_or_group --[[@as Hover.Provider]]
M.add_provider(provider, module)
end
end

Expand Down
106 changes: 90 additions & 16 deletions lua/hover/providers/lsp.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,32 @@
local config = require('hover.config')

local api = vim.api
local lsp = vim.lsp
local methods = vim.lsp.protocol.Methods
local register_capability = vim.lsp.handlers[methods.client_registerCapability]

local module = 'hover.providers.lsp'

---@type Hover.Config.Provider
local default_config = {
module = module,
name = 'LSP',
priority = 1000,
}

---@return Hover.Config.Provider
local function get_module_config()
local provider_configs = config.get().providers

for _, provider_config in ipairs(provider_configs) do
if type(provider_config) == 'table' and provider_config.module == module then
return provider_config
end
end
return default_config
end

local module_config = get_module_config()

--- @type table<integer, Hover.Provider?> -- client_id -> provider_id
local lsp_providers = {}
Expand All @@ -13,7 +40,7 @@ local function create_params(client, bufnr, pos)
local line = api.nvim_buf_get_lines(bufnr, row, row + 1, true)[1]

if not line then
if require('hover.config').get().dev_mode then
if config.get().dev_mode then
error(string.format('ERROR: row %d is out of range (col=%d)', row, col))
end
line = ''
Expand Down Expand Up @@ -67,10 +94,8 @@ function LSPProvider:execute(params, done)
end, params.bufnr)
end

--- @type Hover.Provider[]
local providers = {}

--- @param client vim.lsp.Client
--- @return Hover.Provider?
local function register_lsp_provider(client)
if not client:supports_method('textDocument/hover') then
return
Expand All @@ -86,16 +111,63 @@ local function register_lsp_provider(client)
lsp_provider:execute(params, done)
end,
}
providers[#providers + 1] = lsp_providers[client.id]
return lsp_providers[client.id]
end

---@param client_id integer
---@return boolean
local function is_registered(client_id)
return not not lsp_providers[client_id]
end

---@param providers? Hover.Provider[]
local function providers_group(providers)
return {
name = module_config.name,
priority = module_config.priority,
providers = providers or {},
}
end

---@param client_id integer
local function add_lsp_provider_by_id(client_id)
if not is_registered(client_id) then
local client = assert(lsp.get_client_by_id(client_id))
local provider = register_lsp_provider(client)
if provider then
require('hover.providers').add_provider(provider, module, providers_group())
end
end
end

---@param res lsp.RegistrationParams
---@param capability string
---@return boolean
local function has_capability(res, capability)
for _, registration in ipairs(res.registrations) do
if registration.method == capability then
return true
end
end
return false
end

---@param err? lsp.ResponseError
---@param res lsp.RegistrationParams
---@param ctx lsp.HandlerContext
vim.lsp.handlers[methods.client_registerCapability] = function(err, res, ctx)
local return_value = register_capability(err, res, ctx)

if has_capability(res, methods.textDocument_hover) then
add_lsp_provider_by_id(ctx.client_id)
end

return return_value
end

api.nvim_create_autocmd('LspAttach', {
callback = function(args)
local client_id = args.data.client_id
if not lsp_providers[client_id] then
local client = assert(lsp.get_client_by_id(client_id))
register_lsp_provider(client)
end
add_lsp_provider_by_id(args.data.client_id)
end,
})

Expand All @@ -108,12 +180,14 @@ api.nvim_create_autocmd('LspAttach', {
-- end,
-- })

--- @type Hover.Provider[]
local providers = {}

for _, client in pairs(lsp.get_clients()) do
register_lsp_provider(client)
local provider = register_lsp_provider(client)
if provider then
providers[#providers + 1] = provider
end
end

return {
name = 'LSP',
priority = 1000,
providers = providers,
}
return providers_group(providers)