Minimal Harpoon-like plugin for Neovim. Zero deps, tiny API, optional per-cwd persistence.
Inspired by (and giving full credit to) Harpoon by ThePrimeagen. If you want a richer feature set (lists, terminals, advanced UI), check out Harpoon2.
- File marks.
- Auto-remembers last cursor position in each marked file when you switch buffers.
- Jump next/prev or directly to a saved position from anywhere.
- Per-cwd persistence with
autoload/autosave(defaults on). - Tiny floating list UI:
- Shows compact file names plus parent paths.
- Marks and highlights the current file in the loop.
- Tracks ordinary buffer and window focus changes, even outside Miniharp mappings.
- Can open centered or in any editor corner.
- Can open focused or leave you in the current window.
- Can hide temporarily when it covers the editor cursor.
- Optional close hints; closes with
q,<Esc>,<C-c>, or by callingshow_list()again. - Can also be explicitly entered/focused with
enter_list()without toggling it closed first. - When focused, supports
<CR>to jump,ddto remove, and<Tab>to select/swap mark positions. - Optional auto-show after autoload via
show_on_autoload(default: off).
- Quieter default flow:
- No info notification when a cwd has no saved session yet.
- Mark/unmark actions show a short command-line status message.
next()/prev()/go_to(number)show compact loop feedback likeminiharp 2/3.- Missing files are removed automatically when encountered during navigation.
vim.pack.add({
{
src = 'https://github.com/vieitesss/miniharp.nvim',
version = vim.version.range("v*"), -- latest stable release
-- version = 'nightly', -- latest changes from main
}
})
require('miniharp').setup({
autoload = true, -- load marks for this cwd on startup (default: true)
autosave = true, -- save marks for this cwd on exit (default: true)
show_on_autoload = false, -- show popup list after a successful autoload (default: false)
notifications = true, -- enable notification and status messages (default: true)
ui = {
position = 'center', -- 'center' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'
show_hints = true, -- show close hints in the floating list (default: true)
enter = true, -- enter the floating window when it opens (default: true)
auto_hide = false, -- hide while the list covers the editor cursor (default: false)
},
}){
'vieitesss/miniharp.nvim',
version = '*', -- latest stable release
-- branch = 'main', -- latest nightly version
opts = {
autoload = true,
autosave = true,
show_on_autoload = false,
notifications = true,
ui = {
position = 'center', -- `top-left`, `top-right`, `bottom-left`, `bottom-right`.
show_hints = true,
enter = true, -- Whether to enter the floating window or not
auto_hide = false, -- Hide while the list covers the editor cursor
},
},
}miniharp doesn’t force maps. Here are some defaults you might like:
local miniharp = require('miniharp')
vim.keymap.set('n', '<leader>m', miniharp.toggle_file, { desc = 'miniharp: toggle file mark' })
vim.keymap.set('n', '<C-n>', miniharp.next, { desc = 'miniharp: next file mark' })
vim.keymap.set('n', '<C-p>', miniharp.prev, { desc = 'miniharp: prev file mark' })
vim.keymap.set('n', '<leader>l', miniharp.show_list, { desc = 'miniharp: toggle marks list' })
vim.keymap.set('n', '<leader>L', miniharp.enter_list, { desc = 'miniharp: enter marks list' })
vim.keymap.set('n', '<leader>1', function() miniharp.go_to(1) end, { desc = 'miniharp: go to mark 1' })
vim.keymap.set('n', '<leader>2', function() miniharp.go_to(2) end, { desc = 'miniharp: go to mark 2' })
vim.keymap.set('n', '<leader>3', function() miniharp.go_to(3) end, { desc = 'miniharp: go to mark 3' })
vim.keymap.set('n', '<leader>4', function() miniharp.go_to(4) end, { desc = 'miniharp: go to mark 4' })Typical flow:
- In a file you care about, hit
<leader>mto toggle a file mark. - Work as usual. When you leave that file, its last cursor spot is auto-saved.
- From anywhere, use
<C-n>/<C-p>to jump around marked files, or direct maps like<leader>1/<leader>2to jump straight to a saved position. - On a new Neovim session in the same cwd, marks auto-load (if
autoload = true).
Toggle the list on demand with<leader>l, or enableshow_on_autoload = trueto open it automatically after restore.
All functions are exposed from require('miniharp'):
-
setup(opts?)– Initialize the plugin.---@class MiniharpOpts ---@field autoload? boolean @Load saved marks for this cwd on startup (default: true) ---@field autosave? boolean @Save marks for this cwd on exit (default: true) ---@field show_on_autoload? boolean @Show the marks list UI after a successful autoload (default: false) ---@field notifications? boolean @Enable notification and status messages (default: true) ---@field ui? MiniharpUIOpts @Floating list UI options ---@class MiniharpUIOpts ---@field position? string @'center', 'top-left', 'top-right', 'bottom-left', or 'bottom-right' (default: 'center') ---@field show_hints? boolean @Show close hints in the floating list (default: true) ---@field enter? boolean @Enter the floating list window when opening it (default: true) ---@field auto_hide? boolean @Hide the list while it covers the editor cursor (default: false)
-
toggle_file()– Toggle a file mark for the current file. -
add_file()– Add/update a file mark for the current file at the current cursor. -
next()/prev()– Jump to next/previous file mark (wraps). -
go_to(number)– Jump directly to the 1-based file mark position. Invalid positions warn without changing state, and missing files are removed the same way asnext()/prev(). -
list()– Returns a deep copy of the marks table:{ { file, lnum, col }, ... }. -
clear()– Remove all marks. -
show_list()– Toggle the floating list UI. Ifui.enter = true, you can close it withq,<Esc>, or<C-c>. In all cases, callingshow_list()again closes it. -
enter_list()– Open the floating list and enter it. If the list is already open, focus the existing list window instead of closing and reopening it. Inside the focused list, use<CR>to jump to the cursor line,ddto remove a mark, and<Tab>twice to swap two mark positions. -
save()– Manually persist marks for the current cwd. -
restore()– Manually restore marks for the current cwd (if present).
- Minimalism first. Small surface area and simple behavior; no dependencies.
- Per-cwd persistence. Keeps things project-scoped. Disable by setting
autoload = falseand/orautosave = false. - UI stays out of the way. The popup stays lightweight, optimized for a tiny loop of files, and configurable enough to match different workflows; auto-show is opt-in.
- Single-key toggle flow. With
ui.enter = false, the list behaves like a glanceable overlay that can be shown and dismissed with the same mapping.
See CONTRIBUTING.md for local development, formatting, manual testing, and commit message conventions.
