A neovim plugin that enables inserting inlay hints as code.
Not all LSPs offer a native ability to insert inlay hints as code. This plugin can insert inlay hints from any LSP as code in a buffer.
I feel that the UX of LSPs that do offer the ability to insert inlay hints doesn't fit well with my workflow (such as needing to place the cursor where inlay hint will be inserted). This plugin offers a more streamlined UX for doing this task.
Important
Some LSPs use inlay hints that may not be valid syntax. This plugin doesn't check if the inserted syntax is valid.
insert-inlay-hints_demo.mp4
Install with your favorite package manager.
Example for lazy.nvim:
{
"AbysmalBiscuit/insert-inlay-hints.nvim",
keys = {
{
"<leader>ic",
function()
require("insert-inlay-hints").closest()
end,
desc = "Insert the colsest inline hint as code.",
},
{
"<leader>il",
function()
require("insert-inlay-hints").line()
end,
desc = "Insert all inline hints on current line as code.",
},
{
"<leader>i",
function()
require("insert-inlay-hints").visual()
end,
desc = "Insert all inlay hints in the current visual selection as code.",
mode = { "v" },
},
{
"<leader>ia",
function()
return require("insert-inlay-hints").all()
end,
desc = "Insert all inlay hints in the current buffer as code.",
},
},
}This plugin lazy loads by default when used with lazy.nvim.
It has its own specification, that declares the user commands.
Examples for other package managers:
vim.pack.add({
src = "AbysmalBiscuit/insert-inlay-hints.nvim",
data = {
cmd = {
"InsertHints",
"InsertHintsPlugin",
},
keys = {
{
"<leader>ic",
function()
require("insert-inlay-hints").closest()
end,
desc = "Insert the colsest inline hint as code.",
},
{
"<leader>il",
function()
require("insert-inlay-hints").line()
end,
desc = "Insert all inline hints on current line as code.",
},
{
"<leader>i",
function()
require("insert-inlay-hints").visual()
end,
desc = "Insert all inlay hints in the current visual selection as code.",
mode = { "v" },
},
{
"<leader>ia",
function()
return require("insert-inlay-hints").all()
end,
desc = "Insert all inlay hints in the current buffer as code.",
},
},
after = function(_)
require("insert-inlay-hints").setup({
-- Add config options here to change the defaults
})
end,
},
})Default configuration:
---@class insert-inlay-hints.Config
local defaults = {
---Whether to print debug messages.
---@type boolean
debug = false,
---Whether to enable the plugin by default.
---@type boolean
enable = true,
---List of filetypes for which to enable the plugin.
---When left empty it will be enabled for all filetypes, except for those defined in `disabled_filetypes`.
---When values are passed, it will only activate for those filetypes.
---@type Filetypes
enabled_filetypes = {},
---List of filetypes for which to disable the plugin.
---The disabled filetypes are applied after the enabled_filetypes.
---Use this to exclude filetypes.
---@type Filetypes
disabled_filetypes = { "lua", "javascript", "haskell" },
---List of LSPs for which to disable the plugin.
---Run `:LspInfo` to see the LSPs attached to a given buffer.
---@type string[]
disabled_lsps = {},
---Config options for `insert-inlay-hints.insert.closest`.
---@class InsertClosestConfig
insert_closest = {
---Will move the cursor to the end of the inlay hint that was just inserted.
---This imitates the end result of manually typing the inlay hint.
---@type boolean
move_cursor = true,
---Will prioritize hints on the current line if they're available.
---If no hints are available on the current line, then it will prioritize lines closer line-wise.
---@type boolean
prioritize_lines = true,
---Function to use for calculating the distance from the cursor to inlay hints.
---The closest inlay hint will be inserted.
---You can use one of the predefined functions, or define your own.
---The function needs to take four parameters and return a number:
---`fun(cursor_line: integer, cursor_character: integer, hint_line: integer, hint_character: integer): number`
---@type "euclidian" | "manhattan" | "chebyshev" | "minkowski" | DistanceFunction
distance_function = "euclidian",
---The exponent to use when calculating minkowski distance.
---Setting this to math.huge, will default to using the chebyshev distance.
---@type integer
minkowski_exponent = 5,
},
}The plugin defines two user commands and and several public-API functions (see init.lua).
User command to enable/disable/toggle the plugin:
InsertHintsPlugin: enable, disable, or toggle the plugin functionality. Takes one of the following arguments:enable: enable the insert-inlay-hints plugin.disable: disable the insert-inlay-hints plugin.toggle: toggle the insert-inlay-hints plugin.
User command to insert inlay hints as code:
InsertHints: insert inlay hints in various ways. Takes one of the following arguments:closest: insert the inlay hint closest to the cursor as code. See theinsert_closestpart of the configuration for how to configure how the closest inlay hint is determined.line: insert all inlay hints on the current line as code.visual: insert all inlay hints in the current visual selection as code.all: insert all inlay hints in the current buffer as code.
The insert-inlay-hints module offers four public-API functions for inserting hints:
insert-inlay-hints.closest: insert the inlay hint closest to the cursor as code. See theinsert_closestpart of the configuration for how to configure how the closest inlay hint is determined.line: insert all inlay hints on the current line as code.visual: insert all inlay hints in the current visual selection as code.all: insert all inlay hints in the current buffer as code.
These functions can be easily bound to keymaps and and are dot-repeatable.
I like to use the mnemonic <leader> [i]nsert [...].
For example:
<leader>il(insert [hints] line).<leader>i(insert all [hints] in visual selection)
local insert = require("insert-inlay-hints")
-- Create a non dot-repeatable command
vim.keymap.set(
"n",
"<leader>ic",
insert.closest,
{ noremap = true, desc = "Insert the inlay hint closest to the cursor as code." }
)
-- Alternative if you don't want to load the module before (no need to return something)
vim.keymap.set(
"n",
"<leader>ic",
function()
require("insert-inlay-hints").closest()
end,
{ noremap = true, desc = "Insert the inlay hint closest to the cursor as code." }
)The insert-inlay-hints.insert module offers the base functions that are not dot-repeatable.
local insert = require("insert-inlay-hints.insert")
-- Create a non dot-repeatable command
vim.keymap.set(
"n",
"<leader>ic",
insert.closest,
{ noremap = true, desc = "Insert the inlay hint closest to the cursor as code." }
)
-- Alternative if you don't want to load the module before (no need to return something)
vim.keymap.set(
"n",
"<leader>ic",
function()
require("insert-inlay-hints.insert").closest()
end,
{ noremap = true, desc = "Insert the inlay hint closest to the cursor as code." }
)