-
Notifications
You must be signed in to change notification settings - Fork 3
Custimized Handlers
Jiahe Jiang edited this page Dec 22, 2024
·
4 revisions
This page guides you on how to add customized handlers to the Neominimap plugin. Handlers allow you to define how specific types of annotations (like TODO comments or diagnostic signs) are displayed on the minimap.
A handler is defined by the Neominimap.Map.Handler class, which includes several fields:
- name: A string that identifies the handler.
- mode: Defines how the annotations are displayed (icon, sign, background highlight...).
- namespace: Either an integer or string representing the namespace in which the handler operates.
-
autocmds: A list of autocommands that trigger the handler’s behavior. Each autocmd includes:
- event: The Vim event(s) that trigger the autocmd.
-
opts: Optional settings for the autocmd, including a callback function that applies the handler.
Note that the callback function takes an additional argument called
apply
. This function is for applying the handler to a specific buffer. See the following example.
- init: A function that initializes the handler.
- get_annotations: A function that retrieves a list of annotations for a given buffer.
the get_annotations
function returns a list of annotations, each defined by the Neominimap.Map.Handler.Annotation
type. This type includes the following fields:
- lnum: The starting line number (1-based index).
- end_lnum: The ending line number (1-based index).
- id: A unique identifier for the annotation within a single handler.
- priority: The priority level for displaying the annotation.
-
icon: (Optional) An icon associated with the annotation. Useful when
mode
isicon
. - highlight: The highlight group for rendering the annotation.
Here’s an example of a handler that integrates with todo-comments.nvim:
---@type Neominimap.Map.Handler
local extmark_handler = {
name = "Todo Comment",
mode = "icon",
namespace = vim.api.nvim_create_namespace("neominimap_todo_comment"),
init = function() end,
autocmds = {
{
event = { "TextChanged", "TextChangedI" },
opts = {
callback = function(apply, args)
local bufnr = tonumber(args.buf) ---@cast bufnr integer
vim.schedule(function()
apply(bufnr)
end)
end,
},
},
{
event = "WinScrolled",
opts = {
callback = function(apply)
local winid = vim.api.nvim_get_current_win()
if not winid or not vim.api.nvim_win_is_valid(winid) then
return
end
local bufnr = vim.api.nvim_win_get_buf(winid)
vim.schedule(function()
if bufnr and vim.api.nvim_buf_is_valid(bufnr) then
apply(bufnr)
end
end)
end,
},
},
},
get_annotations = function(bufnr)
local ok, _ = pcall(require, "todo-comments")
if not ok then
return {}
end
local ns_id = vim.api.nvim_get_namespaces()["todo-comments"]
local extmarks = vim.api.nvim_buf_get_extmarks(bufnr, ns_id, 0, -1, {
details = true,
})
local icons = {
FIX = " ",
TODO = " ",
HACK = " ",
WARN = " ",
PERF = " ",
NOTE = " ",
TEST = "⏲ ",
}
local id = { FIX = 1, TODO = 2, HACK = 3, WARN = 4, PERF = 5, NOTE = 6, TEST = 7 }
return vim.tbl_map(function(extmark) ---@param extmark vim.api.keyset.get_extmark_item
local detail = extmark[4] ---@type vim.api.keyset.extmark_details
local group = detail.hl_group ---@type string
local kind = string.sub(group, 7)
local icon = icons[kind]
---@type Neominimap.Map.Handler.Annotation
return {
lnum = extmark[2],
end_lnum = extmark[2],
id = id[kind],
highlight = "TodoFg" .. kind, --- You can customize the highlight here.
icon = icon,
priority = detail.priority,
}
end, extmarks)
end,
}
vim.g.neominimap = {
handlers = {
extmark_handler,
}
}
Here is an overview
For more exapmles, checkout the built-in handlers in source code.
Thanks to @TonyMiri
local word_highlights = {}
---@type Neominimap.Map.Handler
local word_handler = {
name = "Word Highlights",
mode = "line",
namespace = vim.api.nvim_create_namespace("neominimap_word"),
init = function()
-- Set up highlight groups
local base_color = "#404040" -- Default fallback color
local current_color = "#906060" -- Brighter color for current word
local hl = vim.api.nvim_get_hl(0, { name = "CursorLine", link = false })
if hl.bg then
base_color = string.format("#%06x", hl.bg)
-- Make current highlight 30% brighter
local r = bit.rshift(bit.band(hl.bg, 0xFF0000), 16)
local g = bit.rshift(bit.band(hl.bg, 0xFF00), 8)
local b = bit.band(hl.bg, 0xFF)
r = math.min(255, r + math.floor(r * 0.3))
g = math.min(255, g + math.floor(g * 0.3))
b = math.min(255, b + math.floor(b * 0.3))
current_color = string.format("#%02x%02x%02x", r, g, b)
end
-- Regular word highlights
vim.api.nvim_set_hl(0, "NeominimapWordLine", { bg = base_color, default = true })
vim.api.nvim_set_hl(0, "NeominimapWordSign", { fg = base_color, default = true })
vim.api.nvim_set_hl(0, "NeominimapWordIcon", { fg = base_color, default = true })
-- Current word highlights
vim.api.nvim_set_hl(0, "NeominimapCurrentWordLine", { bg = current_color, default = true })
vim.api.nvim_set_hl(0, "NeominimapCurrentWordSign", { fg = current_color, default = true })
vim.api.nvim_set_hl(0, "NeominimapCurrentWordIcon", { fg = current_color, default = true })
end,
autocmds = {
{
event = { "CursorHold", "CursorHoldI" },
opts = {
desc = "Update word highlights when cursor moves",
callback = function(apply)
local winid = vim.api.nvim_get_current_win()
if not winid or not vim.api.nvim_win_is_valid(winid) then
return
end
local bufnr = vim.api.nvim_win_get_buf(winid)
vim.schedule(function()
if bufnr and vim.api.nvim_buf_is_valid(bufnr) then
-- Cache current word and its positions
local word = vim.fn.expand("<cword>")
if word and word ~= "" then
local key = bufnr .. word
if
not word_highlights[key]
or word_highlights[key].tick ~= vim.b[bufnr].changedtick
then
local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, true)
local positions = {}
for lnum, line in ipairs(lines) do
if line:find(word, 1, true) then
table.insert(positions, lnum)
end
end
word_highlights[key] = {
positions = positions,
tick = vim.b[bufnr].changedtick,
}
end
end
apply(bufnr)
end
end)
end,
},
},
},
get_annotations = function(bufnr)
local word = vim.fn.expand("<cword>")
if not word or word == "" then
return {}
end
local key = bufnr .. word
local cached = word_highlights[key]
if not cached then
return {}
end
-- Get current cursor position
local current_line = vim.api.nvim_win_get_cursor(0)[1]
local annotations = {}
for _, lnum in ipairs(cached.positions) do
table.insert(annotations, {
lnum = lnum,
end_lnum = lnum,
priority = 25, -- Between search (20) and diagnostics (70-100)
id = 1,
highlight = (lnum == current_line) and "NeominimapCurrentWordLine" or "NeominimapWordLine",
})
end
return annotations
end,
}