早在写 zettelkasten.nvim 插件的时候,我就想做一个日历试图,用来查看笔记的日期。可能是因为需求不是那么的迫切, 所以一直拖着没有写这样功能。
趁着这次假日,抽空写了这样一个日历插件 calendar.nvim,功能目前还是非常简单的,只是一个简单的日历月视图。 这算是 2026 年我的第一个 Neovim 插件,这篇文字主要介绍 calendar.nvim 插件的安装使用以及制作这一插件遇到的一些问题。
插件安装
calendar.nvim 是使用 Lua 实现的 Neovim 插件,零依赖,可以使用任意插件管理器直接安装,比如:nvim-plug
require('plug').add({
{
'wsdjeg/calendar.nvim',
},
})
基本使用
插件的默认配置如下:
require('calendar').setup({
mark_icon = '•',
keymap = {
next_month = 'L', -- 下个月
previous_month = 'H', -- 上个月
next_day = 'l', -- 后一天
previous_day = 'h', -- 前一天
next_week = 'j', -- 下一周
previous_week = 'k', -- 前一周
today = 't', -- 跳到今天
},
highlights = {
current = 'Visual',
today = 'Todo',
mark = 'Todo',
},
})
记录一些坑
-
nvim_buf_set_extmark函数中 col 等参数指的并不是屏幕 column 列表,而是字符串的字节, -
overlay virt_text 的高亮会清除掉当前位置的 extmark hl_group 高亮
最终解决逻辑是给每一个需要标记的位置按照如下逻辑添加 virt_text,其高亮参数传输一个高亮列表.
local hls = { highlights.mark }
if is_totay() then
table.insert(hls, highlights.today)
end
if is_current() then
table.insert(hls, highlights.current)
end
vim.api.nvim_buf_set_extmark(buf, ns, col, {
virt_text = { { mark_icon, hls } },
})
最终效果图
这里展示了一个添加了 zettelkasten 拓展的日历:
local zk_ext = {}
function zk_ext.get(year, month)
local notes = require('zettelkasten.browser').get_notes()
local marks = {}
for _, note in ipairs(notes) do
local t = vim.split(note.id, '-')
if tonumber(t[1]) == year and tonumber(t[2]) == month then
table.insert(
marks,
{
year = tonumber(t[1]),
month = tonumber(t[2]),
day = tonumber(t[3]),
}
)
end
end
return marks
end
require('calendar.extensions').register(zk_ext)
最终的效果图如下:
