Create up-to-date harpoon2 information for any place where that information can be useful. For example, in statuslines and the tabline.
https://github.com/abeldekat/harpoonline/assets/58370433/ec56eeb2-3cbf-46fe-bc9d-633f6aa8bb9b
Demo of the features. Using lualine and mini.statusline.
Heirline in AstroNvim v4
Custom statusline in NvChad v2.5
Note:
Without caching the info needed from harpoon must be retrieved whenever a status-line updates. Typically, this happens often:
Neovim
version or nightlyImportant: don't forget to call require('harpoonline').setup()
to enable the plugin. Without that call, the formatter will return
an empty string.
{
"nvim-lualine/lualine.nvim",
dependencies = { "abeldekat/harpoonline", version = "*" },
config = function()
local Harpoonline = require("harpoonline")
Harpoonline.setup({
on_update = function() require("lualine").refresh() end,
})
local lualine_c = { Harpoonline.format, "filename" }
require("lualine").setup({ sections = { lualine_c = lualine_c } })
end,
}
local function config()
local MiniStatusline = require("mini.statusline")
local HarpoonLine= require("harpoonline")
local function isnt_normal_buffer() return vim.bo.buftype ~= "" end
local function harpoon_highlight() -- using mini.hipatterns
return Harpoonline.is_buffer_harpooned() and "MiniHipatternsHack"
or "MiniStatuslineFilename"
end
local function section_harpoon(args)
if MiniStatusline.is_truncated(args.trunc_width) or isnt_normal_buffer() then
return ""
end
return Harpoonline.format() ----> produce the info
end
local function active() -- Hook, see mini.statusline setup
-- copy any lines from mini.statusline, H.default_content_active:
local harpoon_data = section_harpoon({ trunc_width = 75 })
return MiniStatusline.combine_groups({
-- copy any lines from mini.statusline, H.default_content_active:
{ hl = H.harpoon_highlight(), strings = { harpoon_data } },
})
end
HarpoonLine.setup({
on_update = function()
vim.wo.statusline = "%{%v:lua.MiniStatusline.active()%}"
end
})
MiniStatusline.setup({set_vim_settings = false, content = { active = active }})
end
local MiniDeps = require("mini.deps")
local add, now = MiniDeps.add, MiniDeps.now
now(function()
add({
source = "echasnovski/mini.statusline",
depends = {{ source = "abeldekat/harpoonline", checkout = "stable" }}
})
config()
end
A custom setup for mini.statusline can be found in ak.config.ui.mini_statusline
The following configuration is implied when calling setup
without arguments:
---@class HarpoonLineConfig
Harpoonline.config = {
-- other nice icons: "", "", ""
---@type string
icon = '', -- An empty string disables showing the icon
-- Harpoon:list(), without a name, retrieves the default list:
-- default_list_name: Configures the display name for the default list.
---@type string
default_list_name = '',
---@type "extended" | "short"
formatter = 'extended', -- use a built-in formatter
formatter_opts = {
extended = {
-- An indicator corresponds to a position in the harpoon list
-- Suggestion: Add an indicator for each configured "select" keybinding
indicators = { ' 1 ', ' 2 ', ' 3 ', ' 4 ' },
active_indicators = { '[1]', '[2]', '[3]', '[4]' },
-- 1 More indicators than items in the harpoon list:
empty_slot = '', -- ' · ', -- middledot. Disable using empty string
-- 2 Less indicators than items in the harpoon list
more_marks_indicator = ' … ', -- horizontal elipsis. Disable using empty string
more_marks_active_indicator = '[…]', -- Disable using empty string
},
short = {
inner_separator = '|',
},
},
---@type fun():string|nil
custom_formatter = nil, -- use this formatter when configured
---@type fun()|nil
on_update = nil, -- optional action to perform after update
}
Note: The icon does not display properly in the browser...
Scenario's:
This is the default formatter. Default options: config.formatter_opts.extended
Output A: :anchor: 1 2 3
Output B: :anchor: 1 [2] 3
Note: Five marks, the fifth mark is the active buffer:
Output B: 1 2 3 4 […]
Add to the config: formatter = 'short'
. Default options: config.formatter_opts.short
Output A: :anchor: [3]
Output B: :anchor: [2|3]
Harpoonline.setup({
-- formatter = "extended", -- configure the default formatter
formatter_opts = {
extended = { -- remove all spaces...
indicators = { "1", "2", "3", "4" },
empty_slot = "·",
more_marks_indicator = "…", -- horizontal elipsis. Disable with empty string
more_marks_active_indicator = "[…]", -- Disable with empty string
},
},
on_update = on_update,
})
Output A: :anchor: 123·
Output B: :anchor: 1[2]3·
The following data is kept up-to-date internally, to be processed by formatters:
---@class HarpoonLineData
H.data = {
-- Harpoon's default list is in use when list_name = nil
--- @type string|nil
list_name = nil, -- the name of the current list
--- @type number
list_length = 0, -- the length of the current list
--- @type number|nil
buffer_idx = nil, -- the mark of the current buffer if harpooned
}
Example:
local Harpoonline = require("harpoonline")
Harpoonline.setup({
custom_formatter = Harpoonline.gen_formatter(
---@param data HarpoonLineData
---@return string
function(data)
return string.format( -- very short, without the length of the harpoon list
"%s%s%s",
"➡️ ",
data.list_name and string.format("%s ", data.list_name) or "",
data.buffer_idx and string.format("%d", data.buffer_idx) or "-"
)
end
),
})
Output A: :arrow_right: -
Output B: :arrow_right: 2
Note: You can also use inner highlights in the formatter function. See the example recipe for NvChad.
This plugin supports working with multiple harpoon lists. The list in use when Neovim is started is assumed to be the default list
Important:
The plugin needs to be notified when switching to another list
using its custom HarpoonSwitchedList
event:
-- Starts with the default. Use this variable in harpoon:list(list_name)
local list_name = nil
vim.keymap.set("n", "<leader>J", function()
-- toggle between the default list(nil) and list "custom"
list_name = list_name ~= "custom" and "custom" or nil
vim.api.nvim_exec_autocmds("User",
{ pattern = "HarpoonSwitchedList", modeline = false, data = list_name })
end, { desc = "Switch harpoon list", silent = true })
A complete setup using two harpoon lists can be found in ak.config.editor.harpoon
Basic example:
local Harpoonline = require "harpoonline"
Harpoonline.setup({
on_update = function() vim.cmd.redrawstatus() end
})
local HarpoonComponent = {
provider = function() return " " .. Harpoonline.format() .. " " end,
hl = function()
if Harpoonline.is_buffer_harpooned() then
return "MiniHipatternsHack"-- example using mini.hipatterns
end
end,
}
-- A minimal statusline:
require("heirline").setup({ statusline = { HarpoonComponent }})
{
"rebelot/heirline.nvim",
dependencies = "abeldekat/harpoonline",
config = function(plugin, opts)
local Status = require "astroui.status"
local Harpoonline = require "harpoonline"
Harpoonline.setup {
on_update = function() vim.cmd.redrawstatus() end,
}
local HarpoonComponent = Status.component.builder {
{
provider = function()
local line = Harpoonline.format()
return Status.utils.stylize(line, { padding = { left = 1, right = 1 }})
end,
hl = function()
if Harpoonline.is_buffer_harpooned() then
return { bg = "command", fg = "bg" }
end
end,
},
}
table.insert(opts.statusline, 4, HarpoonComponent) -- after file_info component
require "astronvim.plugins.configs.heirline"(plugin, opts)
end,
}
---@type ChadrcConfig
local M = {} -- nvchad starter: lua.chadrc.lua
-- Add to config.plugins:
-- {
-- "nvchad/ui",
-- dependencies = {
-- "abeldekat/harpoonline",
-- config = function()
-- require("harpoonline").setup {
-- on_update = function() vim.cmd.redrawstatus() end,
-- }
-- end,
-- },
-- }
M.ui = {
theme = "flexoki-light",
statusline = {
theme = "vscode",
separator_style = "default",
-- Copy local "orders.vscode" from nvchad.stl.utils(plugin nvchad/ui)
-- Add string "harpoon" before "file"
order = { "mode", "harpoon", "file", "diagnostics", "git",
"%=", "lsp_msg", "%=", "lsp", "cursor", "cwd" },
modules = {
-- Add a custom harpoon module, using the file background.
harpoon = function()
return "%#St_file_bg# " .. require("harpoonline").format() .. " "
end,
},
},
}
return M
extended
formatter is inspired by plugin harpoon-lualine