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: The video demonstrates the first release and will become outdated.
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()
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 candidates: "", "", "", ""
-- default: icon nf-md-hook in nerdfont, unicode f06e2:
---@type string
icon = '', -- An empty string disables showing the icon
-- Harpoon:list(), when name is nil, retrieves the default list:
-- default_list_name: Configures the display name for the default list.
---@type string
default_list_name = '',
---@type "default" | "short"
formatter = 'default', -- use a built-in formatter
formatter_opts = {
default = {
inactive = ' %s ', -- including spaces
active = '[%s]',
-- Max number of slots to display:
max_slots = 4, -- Suggestion: as many as there are "select" keybindings
-- The number of items in the harpoon list exceeds max_slots:
more = '…', -- horizontal elipsis. Disable using empty string
},
short = {
inner_separator = '|',
},
},
---@type HarpoonlineFormatter
custom_formatter = nil, -- use this formatter when configured
---@type fun()|nil
on_update = nil, -- Recommended: trigger the client when the line has been rebuild.
}
Note: The icon does not display properly in the browser...
Scenario's:
Note: More examples can be found in ak.config.ui.harpoonline
Default options: config.formatter_opts.default
Output A: 1 2 3
Output B: 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: [3]
Output B: [2|3]
Harpoonline.setup({
-- config
formatter_opts = {
default = { -- remove all spaces...
inactive = "%s",
active = "[%s]",
},
},
-- more config
})
Output A: 123
Output B: 1[2]3
The following data is kept up-to-date internally, to be processed by formatters:
---@class HarpoonlineData
---@field list_name string|nil -- the name of the current list
---@field items HarpoonItem[] -- the items of the current list
---@field active_idx number|nil -- the harpoon index of the current buffer
Harpoonline.setup({
-- config
---@param data HarpoonlineData
---@param opts HarpoonLineConfig
---@return string
custom_formatter = function(data,opts)
return string.format( -- very short, without the length of the harpoon list
"%s%s%s",
opts.icon .. " ",
data.list_name and string.format("%s ", data.list_name) or "",
data.active_idx and string.format("%d", data.active_idx) or "-"
)
end
-- more config
})
Output A: -
Output B: 2
Harpoonline.setup({
-- config
---@param data HarpoonlineData
---@param opts HarpoonLineConfig
---@return string
custom_formatter = function(data, opts)
local letters = { "j", "k", "l", "h" }
local idx = data.active_idx
local slot = 0
local slots = vim.tbl_map(function(letter)
slot = slot + 1
return idx and idx == slot and string.upper(letter) or letter
end, vim.list_slice(letters, 1, math.min(#letters, #data.items)))
local name = data.list_name and data.list_name or opts.default_list_name
local header = string.format("%s%s%s", opts.icon, name == "" and "" or " ", name)
return header .. " " .. table.concat(slots)
end,
-- more config
})
Output A: jkl
Output B: jKl
Note:
harpoon
information inside each data.items
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