Skip to content

Neovim Lua plugin that overrides vim.lsp.inlay_hint just to fill my desire to edit inlay hints.

License

Notifications You must be signed in to change notification settings

felpafel/inlay-hint.nvim

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 
 
 

Repository files navigation

inlay-hint.nvim

This plugin overrides vim.lsp.inlay_hint and expose a simple callback that permits the user to edit how inlay hints are displayed, without touching any native API or core logic.

Demo

demo

Motivation

Since inlay hints got integrated to Neovim many authors deprecated/archived their own implementations and started calling the vim.lsp.inlay_hint api. However, the native API doesn't expose any method to edit how hints are shown in the buffer, and there is an open issue #28261 discussing this topic. So, inspired by the display_callback implemented in nvim-dap-virtual-text I decide to create this plugin.

Prerequisites

Installation

{
  'felpafel/inlay-hint.nvim',
  event = 'LspAttach',
  config = true,
}

Configuration

The behavior of this plugin can be activated and controlled via a setup call.

require('inlay-hint').setup()
Or with additional options

In order to get better completions and type hints inside Neovim, please check folke/lazydev.nvim. completion demo

require('inlay-hint').setup({
  virt_text_pos = 'eol',
  highlight_group = 'LspInlayHint',
  hl_mode = 'combine',
  display_callback = function(line_hints, options, bufnr)
    if options.virt_text_pos == 'inline' then
      local lhint = {}
      for _, hint in pairs(line_hints) do
        local text = ''
        local label = hint.label
        if type(label) == 'string' then
          text = label
        else
          for _, part in ipairs(label) do
            text = text .. part.value
          end
        end
        if hint.paddingLeft then
          text = ' ' .. text
        end
        if hint.paddingRight then
          text = text .. ' '
        end
        lhint[#lhint + 1] =
        { text = text, col = hint.position.character }
      end
      return lhint
    elseif
      options.virt_text_pos == 'eol'
      or options.virt_text_pos == 'right_align'
    then
      local k1 = {}
      local k2 = {}
      table.sort(line_hints, function(a, b)
        return a.position.character < b.position.character
      end)
      for _, hint in pairs(line_hints) do
        local label = hint.label
        local kind = hint.kind
        local text = ''
        if type(label) == 'string' then
          text = label
        else
          for _, part in ipairs(label) do
            text = text .. part.value
          end
        end
        if kind == 1 then
          k1[#k1 + 1] = text:gsub('^:%s*', '')
        else
          k2[#k2 + 1] = text:gsub(':$', '')
        end
      end
      local text = ''
      if #k2 > 0 then
        text = '<- (' .. table.concat(k2, ',') .. ')'
      end
      if #text > 0 then
        text = text .. ' '
      end
      if #k1 > 0 then
        text = text .. '=> ' .. table.concat(k1, ',')
      end

      return text
    end
    return nil
  end,
})
Enable hints on LspAttach and toggle keymap
vim.api.nvim_create_autocmd('LspAttach', {
callback = function(args)
  local bufnr = args.buf ---@type number
  local client = vim.lsp.get_client_by_id(args.data.client_id)
  if client.supports_method('textDocument/inlayHint') then
    vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })
    vim.keymap.set('n', '<leader>i', function()
      vim.lsp.inlay_hint.enable(
        not vim.lsp.inlay_hint.is_enabled({ bufnr = bufnr }),
        { bufnr = bufnr }
      )
    end, { buffer = bufnr })
  end
end,
})
Using `vim.treesitter` to show variables and their types

demo

require('inlay-hint').setup({
virt_text_pos = 'eol',
display_callback = function(line_hints, options, bufnr)
  if options.virt_text_pos == 'eol' then
    local k1 = {}
    local k2 = {}
    table.sort(line_hints, function(a, b)
      return a.position.character < b.position.character
    end)
    for _, hint in pairs(line_hints) do
      local label = hint.label
      local kind = hint.kind
      local node = vim.treesitter.get_node({
        bufnr = bufnr,
        pos = {
          hint.position.line,
          kind == 1 and hint.position.character - 1
            or hint.position.character,
        },
      })
      local node_text = node
      and vim.treesitter.get_node_text(node, 0, {})
      or ''
      local text = ''
      if type(label) == 'string' then
        text = label
      else
        for _, part in ipairs(label) do
          text = text .. part.value
        end
      end
      if kind == 1 then
        k1[#k1 + 1] = node_text .. text:gsub(':%s*', ': ')
      else
        k2[#k2 + 1] = text:gsub(':$', '')
      end
    end
    local text = ''
    if #k2 > 0 then
      text = '<- (' .. table.concat(k2, ',') .. ')'
    end
    if #text > 0 then
      text = text .. ' '
    end
    if #k1 > 0 then
      text = text .. '=> ' .. table.concat(k1, ', ')
    end

    return text
  end
  return nil
end,
})

Credits

Neovim team: This plugin is literally a copy and paste of the original vim.lsp.inlay_hint implementation.

nvim-dap-virtual-text: Who inspired this plugin.

About

Neovim Lua plugin that overrides vim.lsp.inlay_hint just to fill my desire to edit inlay hints.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Languages