repositories / dotfiles
dotfiles
bugabingas dorkfiles
owned by admin
neovim/lua/bugabinga/inlay.lua
Rawlocal table = require 'std.table'
local icon = require 'std.icon'
-- display inlay hints at the END of the line, instead of
-- mixed with the source code
--
-- stolen from: https://github.com/chrisgrieser/nvim-lsp-endhints/blob/main/lua/lsp-endhints/override-handler.lua
local config = {
icons = {
type = icon.type,
parameter = icon.parameter,
offspec = icon.offspec,
unknown = icon.unknown,
},
label = {
truncateAtChars = 20,
padding = 1,
marginLeft = 0,
sameKindSeparator = ', ',
},
extmark = {
priority = 50,
},
}
local ns = vim.api.nvim_create_namespace 'bugabinga-inlay'
local function changedRefreshHandler( err, result, ctx, _ )
-- GUARD
if not vim.lsp.inlay_hint.is_enabled() then return end
local bufnr = ctx.bufnr or -1
if not vim.api.nvim_buf_is_valid( bufnr ) then return end
if not result then return end
local client = vim.lsp.get_client_by_id( ctx.client_id )
if not client then return end
local inlayHintProvider = client.server_capabilities.inlayHintProvider
if not inlayHintProvider then return end
if err then
vim.notify( vim.inspect( err ), vim.log.levels.ERROR )
return
end
local padding = (' '):rep( config.label.padding )
local marginLeft = (' '):rep( config.label.marginLeft )
vim.api.nvim_buf_clear_namespace( bufnr, ns, 0, -1 )
-- Collect all hints for each line, so we can sort them by column in the loop
-- below. This ensures that the hints are displayed in the correct order.
local hintLines = vim.iter( result ):fold( {}, function ( acc, hint )
local lnum = hint.position.line
local col = hint.position.character
-- LABEL
local label = hint.label
if type( label ) ~= 'string' then
-- label can be string or `InlayHintLabelPart[]` https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#inlayHint
label = vim.iter( hint.label ):map( function ( labelPart ) return labelPart.value end ):join ''
end
label = vim.trim( label:gsub( '^:', '' ):gsub( ':$', '' ) )
if config.label.truncateAtChars and #label > config.label.truncateAtChars then
label = label:sub( 1, config.label.truncateAtChars ) .. '…'
end
-- KIND
-- 1: type, 2: parameter -- https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#inlayHintKind
local kind
if hint.kind == 1 then
kind = 'type'
elseif hint.kind == 2 then
kind = 'parameter'
elseif hint.kind == nil then
kind = 'unknown'
else
kind = 'offspec'
end
if not acc[lnum] then acc[lnum] = {} end
table.insert( acc[lnum], { label = label, col = col, kind = kind } )
return acc
end )
-- loop: add hints as extmarks for each line
for lnum, hints in pairs( hintLines ) do
table.sort( hints, function ( a, b ) return a.col < b.col end )
-- merge hints of same kind
-- add icon only when parameter kind is different from the previous one
local hintsMerged = ''
for i = 1, #hints do
local hint = hints[i]
local lastKind = hints[i - 1] and hints[i - 1].kind
if lastKind == hint.kind then
hintsMerged = hintsMerged .. config.label.sameKindSeparator .. hint.label
else
local hint_icon = config.icons[hint.kind]
local pad = i ~= 1 and ' ' or ''
hintsMerged = hintsMerged .. pad .. hint_icon .. hint.label
end
end
-- add padding & margin
local virtText = {
{ padding .. hintsMerged .. padding, 'LspInlayHint' },
}
if marginLeft ~= '' then table.insert( virtText, 1, { marginLeft } ) end
-- add extmark for the line
vim.api.nvim_buf_set_extmark( bufnr, ns, lnum, 0, {
virt_text = virtText,
virt_text_pos = 'eol',
hl_mode = 'combine', -- ensures highlights are combined with the background, see #2
strict = false, -- prevents error on quick buffer changes (e.g. quick series of undos)
priority = config.extmark.priority,
} )
end
end
vim.lsp.handlers['textDocument/inlayHint'] = changedRefreshHandler