Skip to content

Commit e131d90

Browse files
committed
feat(recipes): add harpoon-bufsync recipe
1 parent 6cf7019 commit e131d90

2 files changed

Lines changed: 87 additions & 0 deletions

File tree

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Harpoon BufSync
2+
3+
Sync your AstroNvim buffer tabline to your Harpoon marks — close, open, and sort buffers based on your pinned files.
4+
5+
## Overview
6+
7+
Harpoon lets you pin frequently-used files for quick navigation. But your tabline (Heirline) doesn't reflect that order — it tracks buffers by open-time and internal buffer ID. This recipe bridges that gap: with a single keybind (`<Leader>bsh`), it closes non-Harpoon buffers, opens missing Harpoon files, and sorts the tabline to match your Harpoon order.
8+
9+
## Requirements
10+
11+
- [Harpoon v2](https://github.com/ThePrimeagen/harpoon) (branch `harpoon2`)
12+
- [AstroCore](https://github.com/AstroNvim/astrocore) (bundled with AstroNvim)
13+
- [Heirline](https://github.com/rebelot/heirline.nvim) (AstroNvim default tabline)
14+
15+
## Installation
16+
17+
Add to your `community.lua`:
18+
19+
```lua
20+
{ import = "astrocommunity.recipes.harpoon-bufsync" },
21+
```
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
return {
2+
{
3+
"AstroNvim/astrocore",
4+
---@param opts AstroCoreOpts
5+
opts = function(_, opts)
6+
opts.mappings = opts.mappings or {}
7+
opts.mappings.n = opts.mappings.n or {}
8+
9+
-- Sync tabline buffers to Harpoon mark order
10+
opts.mappings.n["<Leader>bsh"] = {
11+
function()
12+
local harpoon = require "harpoon"
13+
local harpoon_items = harpoon:list().items
14+
15+
-- Build path -> harpoon index map
16+
local harpoon_order = {}
17+
for i, item in ipairs(harpoon_items) do
18+
local path = vim.fn.fnamemodify(item.value, ":p")
19+
harpoon_order[path] = i
20+
end
21+
22+
-- Get current tab's buffer list (this IS the tabline order)
23+
local bufs = vim.t.bufs or {}
24+
25+
-- Close buffers NOT in Harpoon list
26+
for _, bufnr in ipairs(bufs) do
27+
if require("astrocore.buffer").is_valid(bufnr) then
28+
local buf_path = vim.fn.fnamemodify(vim.api.nvim_buf_get_name(bufnr), ":p")
29+
if not harpoon_order[buf_path] then require("astrocore.buffer").close(bufnr) end
30+
end
31+
end
32+
33+
-- Open Harpoon files that aren't open yet
34+
local open_paths = {}
35+
for _, bufnr in ipairs(vim.t.bufs or {}) do
36+
open_paths[vim.fn.fnamemodify(vim.api.nvim_buf_get_name(bufnr), ":p")] = true
37+
end
38+
39+
for _, item in ipairs(harpoon_items) do
40+
local path = vim.fn.fnamemodify(item.value, ":p")
41+
if not open_paths[path] and vim.fn.filereadable(path) == 1 then
42+
vim.cmd("edit " .. vim.fn.fnameescape(path))
43+
end
44+
end
45+
46+
-- Re-sort vim.t.bufs by Harpoon order
47+
local new_order = {}
48+
for _, bufnr in ipairs(vim.t.bufs or {}) do
49+
local buf_path = vim.fn.fnamemodify(vim.api.nvim_buf_get_name(bufnr), ":p")
50+
if harpoon_order[buf_path] then
51+
table.insert(new_order, { idx = harpoon_order[buf_path], bufnr = bufnr })
52+
end
53+
end
54+
table.sort(new_order, function(a, b) return a.idx < b.idx end)
55+
56+
-- Write back the sorted order
57+
vim.t.bufs = vim.tbl_map(function(item) return item.bufnr end, new_order)
58+
59+
-- Refresh the tabline
60+
vim.cmd "redrawtabline"
61+
end,
62+
desc = "Sort by Harpoon",
63+
}
64+
end,
65+
},
66+
}

0 commit comments

Comments
 (0)