like moleskine, or a mole (that's watching your moves).
code annotation sessions for neovim. select code, jot a note, and build a markdown file of annotations as you debug or trace a complex flow in your code.
- start a session — a markdown file is created and shown in a side panel
- select code in visual mode and hit the annotate keybinding
- an inline popup appears — type your note and press
<CR>to save,<Esc>to cancel - annotations are appended to the session file as a markdown list -- hit
<CR>on an annotation in the side panel to jump to that location in your code - stop the session when you're done
each annotation records the file path and line range. press <Tab> in the input popup to toggle between location mode (reference only) and snippet mode (includes the selected code in a fenced block).
- neovim >= 0.9
- nui.nvim
{
"zion-off/mole.nvim",
dependencies = { "MunifTanjim/nui.nvim" },
opts = {},
}use {
"zion-off/mole.nvim",
requires = { "MunifTanjim/nui.nvim" },
config = function()
require("mole").setup({})
end,
}MiniDeps.add({
source = "zion-off/mole.nvim",
depends = { "MunifTanjim/nui.nvim" },
})
require("mole").setup({})clone the repo into your neovim packages directory:
git clone https://github.com/zion-off/mole.nvim \
~/.local/share/nvim/site/pack/plugins/start/mole.nvimthen add require("mole").setup({}) to your config. make sure nui.nvim is also installed.
these are the defaults — pass any overrides to setup():
require("mole").setup({
-- where session files are saved
session_dir = vim.fn.stdpath("data") .. "/mole", -- ~/.local/share/nvim/mole
-- "location" = file path + line range
-- "snippet" = file path + line range + selected text in a fenced code block
capture_mode = "snippet",
-- open the side panel automatically when starting a session
auto_open_panel = true,
-- custom session name: nil = timestamp, string = fixed name, function = called to get name
session_name = nil,
-- show vim.notify messages
notify = true,
-- picker for resume: "auto" (telescope → snacks → vim.ui.select), "telescope", "snacks", or "select"
picker = "auto",
-- keybindings
keys = {
annotate = "<leader>ma", -- visual mode
start_session = "<leader>ms", -- normal mode
stop_session = "<leader>mq", -- normal mode
resume_session = "<leader>mr", -- normal mode
toggle_window = "<leader>mw", -- normal mode
jump_to_location = { "<CR>", "gd" }, -- in side panel
next_annotation = "]a", -- in side panel
prev_annotation = "[a", -- in side panel
},
-- side panel
window = {
width = 0.3, -- fraction of editor width
},
-- inline input popup
input = {
width = 50,
border = "rounded",
},
-- callbacks that return lines written to the session file
-- each receives an info table and must return a table of strings (lines)
-- return {} to skip a section entirely
format = {
-- info: { title, file_path, cwd, timestamp }
header = function(info)
return {
"# " .. info.title,
"",
"**File:** " .. info.file_path,
"**Started:** " .. info.timestamp,
"**Project:** " .. info.cwd, -- used to resolve file paths when jumping to locations from a different project
"",
"---",
}
end,
-- info: { timestamp }
footer = function(info)
return {
"",
"---",
"",
"**Ended:** " .. info.timestamp,
}
end,
-- info: { timestamp }
resumed = function(info)
return {
"",
"---",
"",
"**Resumed:** " .. info.timestamp,
"",
"---",
"",
}
end,
},
})| command / key | mode | description |
|---|---|---|
:MoleStart |
normal | start a new annotation session |
:MoleStop |
normal | stop the current session |
:MoleResume |
normal | resume a previous session |
:MoleToggle |
normal | toggle the side panel |
<leader>ma |
visual | annotate the current selection |
<CR> / gd |
side panel | jump to annotation location |
]a |
side panel | next annotation |
[a |
side panel | previous annotation |
annotations are saved as markdown. in location mode:
- **`src/main.lua:12-18`** — TODO: refactor this loopin snippet mode:
- **`src/main.lua:12-18`** — TODO: refactor this loop
```lua
for i = 1, #items do
process(items[i])
end
```session files are stored in ~/.local/share/nvim/mole/ by default (follows XDG via stdpath("data")).
MIT