{"id":13681375,"url":"https://github.com/abeldekat/harpoonline","last_synced_at":"2025-10-02T23:35:34.373Z","repository":{"id":228088145,"uuid":"773126263","full_name":"abeldekat/harpoonline","owner":"abeldekat","description":"Harpoon info for any statusline","archived":true,"fork":false,"pushed_at":"2024-07-28T17:08:39.000Z","size":89,"stargazers_count":44,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-11-15T10:57:08.397Z","etag":null,"topics":["harpoon","lua","neovim","neovim-plugin","nvim","nvim-plugin"],"latest_commit_sha":null,"homepage":"","language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/abeldekat.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-03-16T20:24:13.000Z","updated_at":"2024-11-04T14:11:16.000Z","dependencies_parsed_at":"2024-06-19T03:03:31.307Z","dependency_job_id":"5bec2903-ea4e-445f-a24d-2554cc8f8cee","html_url":"https://github.com/abeldekat/harpoonline","commit_stats":null,"previous_names":["abeldekat/harpoon-line","abeldekat/harpoonline"],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abeldekat%2Fharpoonline","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abeldekat%2Fharpoonline/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abeldekat%2Fharpoonline/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abeldekat%2Fharpoonline/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/abeldekat","download_url":"https://codeload.github.com/abeldekat/harpoonline/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":235051537,"owners_count":18928181,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["harpoon","lua","neovim","neovim-plugin","nvim","nvim-plugin"],"created_at":"2024-08-02T13:01:30.040Z","updated_at":"2025-10-02T23:35:29.039Z","avatar_url":"https://github.com/abeldekat.png","language":"Lua","funding_links":[],"categories":["Lua"],"sub_categories":[],"readme":"# Harpoonline\n\n:exclamation: **Update**: This repository has been archived on 2024.07.28\n\nCreate up-to-date [harpoon2] information for any place where\nthat information can be useful. For example, in statuslines and the tabline.\n\n## Demo\n\n\u003chttps://github.com/abeldekat/harpoonline/assets/58370433/ec56eeb2-3cbf-46fe-bc9d-633f6aa8bb9b\u003e\n\n*Demo of the features. Using lualine and mini.statusline.*\n\n![1710845846](https://github.com/abeldekat/harpoonline/assets/58370433/9a6ac3fa-2f64-40f1-a3bf-1e5702b49ccc)\n*Heirline in AstroNvim v4*\n\n![1710925071](https://github.com/abeldekat/harpoonline/assets/58370433/4b911ed1-428d-4a64-ba9d-f67ba6438ce7)\n*Custom statusline in NvChad v2.5*\n\n*Note*: The video demonstrates the first release and will become outdated.\n\n## Features\n\n- Supports multiple [harpoon2] lists.\n- Highly configurable: Use or modify default formatters or supply a custom formatter\n- Decoupled from status-line: Can be used anywhere.\n- Resilience: The formatter will return an empty string when harpoon is not present.\n- Performance/efficiency: The data is cached and *only* updated when needed.\n\n*Note*:\n\nWithout caching the info needed from harpoon must be retrieved whenever\na status-line updates. Typically, this happens often:\n\n- When navigating inside a buffer\n- When editing text inside a buffer\n\n## Requirements\n\n- Latest stable `Neovim` version or nightly\n- [harpoon2]\n- A statusline. Examples: [mini.statusline], [lualine], [heirline] or a custom implementation\n\n## Setup\n\n**Important**: don't forget to call `require('harpoonline').setup()`\nto enable the plugin. Without that call, the formatter will return\nan empty string.\n\n### Using lazy.nvim and lualine\n\n```lua\n{\n    \"nvim-lualine/lualine.nvim\",\n    dependencies =  { \"abeldekat/harpoonline\", version = \"*\" },\n    config = function()\n      local Harpoonline = require(\"harpoonline\")\n      Harpoonline.setup({\n        on_update = function() require(\"lualine\").refresh() end,\n      })\n\n      local lualine_c = { Harpoonline.format, \"filename\" }\n      require(\"lualine\").setup({ sections = { lualine_c = lualine_c } })\n    end,\n}\n```\n\n### Using mini.deps and mini.statusline\n\n```lua\nlocal function config()\n  local MiniStatusline = require(\"mini.statusline\")\n  local HarpoonLine= require(\"harpoonline\")\n\n  local function isnt_normal_buffer() return vim.bo.buftype ~= \"\" end\n  local function harpoon_highlight() -- using mini.hipatterns\n    return Harpoonline.is_buffer_harpooned() and \"MiniHipatternsHack\"\n      or \"MiniStatuslineFilename\"\n  end\n  local function section_harpoon(args)\n    if MiniStatusline.is_truncated(args.trunc_width) or isnt_normal_buffer() then\n      return \"\"\n    end\n    return Harpoonline.format()\n  end\n  local function active() -- Hook, see mini.statusline setup\n    -- copy any lines from mini.statusline, H.default_content_active:\n    local harpoon_data = section_harpoon({ trunc_width = 75 })\n    return MiniStatusline.combine_groups({\n      -- copy any lines from mini.statusline, H.default_content_active:\n      { hl = H.harpoon_highlight(), strings = { harpoon_data } },\n    })\n  end\n\n  HarpoonLine.setup({\n    on_update = function()\n      vim.wo.statusline = \"%{%v:lua.MiniStatusline.active()%}\"\n    end\n  })\n  MiniStatusline.setup({set_vim_settings = false, content = { active = active }})\nend\n\nlocal MiniDeps = require(\"mini.deps\")\nlocal add, now = MiniDeps.add, MiniDeps.now\nnow(function()\n  add({\n    source = \"echasnovski/mini.statusline\",\n    depends = {{ source = \"abeldekat/harpoonline\", checkout = \"stable\" }}\n  })\n  config()\nend\n```\n\nA custom setup for mini.statusline can be found in [ak.config.ui.mini_statusline]\n\n## Configuration\n\nThe following configuration is implied when calling `setup` without arguments:\n\n```lua\n---@class HarpoonLineConfig\nHarpoonline.config = {\n  -- other candidates: \"󰀱\", \"\", \"󱡅\", \"󰶳\"\n  -- default: icon nf-md-hook in nerdfont, unicode f06e2:\n  ---@type string\n  icon = '󰛢', -- An empty string disables showing the icon\n\n  -- Harpoon:list(), when name is nil, retrieves the default list:\n  -- default_list_name: Configures the display name for the default list.\n  ---@type string\n  default_list_name = '',\n\n  ---@type \"default\" | \"short\"\n  formatter = 'default', -- use a built-in formatter\n\n  formatter_opts = {\n    default = {\n      inactive = ' %s ', -- including spaces\n      active = '[%s]',\n      -- Max number of slots to display:\n      max_slots = 4, -- Suggestion: as many as there are \"select\" keybindings\n      -- The number of items in the harpoon list exceeds max_slots:\n      more = '…', -- horizontal elipsis. Disable using empty string\n    },\n    short = {\n      inner_separator = '|',\n    },\n  },\n\n  ---@type HarpoonlineFormatter\n  custom_formatter = nil, -- use this formatter when configured\n\n  ---@type fun()|nil\n  on_update = nil, -- Recommended: trigger the client when the line has been rebuild.\n}\n```\n\n*Note*: The icon does not display properly in the browser...\n\n## Formatters\n\nScenario's:\n\n- A: 3 marks, the current buffer is not harpooned\n- B: 3 marks, the current buffer is harpooned on mark 2\n\n*Note*: More examples can be found in [ak.config.ui.harpoonline]\n\n### The \"default\" built-in\n\nDefault options: `config.formatter_opts.default`\n\nOutput A: 󰛢  ` 1  2  3 `\n\nOutput B: 󰛢  ` 1 [2] 3 `\n\n**Note**: Five marks, the fifth mark is the active buffer:\n\nOutput B: 󰛢  ` 1  2  3  4 […] `\n\n### The \"short\" built-in\n\nAdd to the config: `formatter = 'short'`. Default options: `config.formatter_opts.short`\n\nOutput A: 󰛢  `[3]`\n\nOutput B: 󰛢  `[2|3]`\n\n### Customize a built-in\n\n```lua\nHarpoonline.setup({\n  -- config\n  formatter_opts = {\n    default = { -- remove all spaces...\n      inactive = \"%s\",\n      active = \"[%s]\",\n    },\n  },\n  -- more config\n})\n```\n\nOutput A: 󰛢  `123`\n\nOutput B: 󰛢  `1[2]3`\n\n### Use a custom formatter\n\nThe following data is kept up-to-date internally, to be processed by formatters:\n\n```lua\n---@class HarpoonlineData\n---@field list_name string|nil -- the name of the current list\n---@field items HarpoonItem[] -- the items of the current list\n---@field active_idx number|nil -- the harpoon index of the current buffer\n```\n\n#### Example \"very short\"\n\n```lua\nHarpoonline.setup({\n  -- config\n  ---@param data HarpoonlineData\n  ---@param opts HarpoonLineConfig\n  ---@return string\n  custom_formatter = function(data,opts)\n    return string.format( -- very short, without the length of the harpoon list\n      \"%s%s%s\",\n      opts.icon .. \" \",\n      data.list_name and string.format(\"%s \", data.list_name) or \"\",\n      data.active_idx and string.format(\"%d\", data.active_idx) or \"-\"\n    )\n  end\n  -- more config\n})\n```\n\nOutput A: 󰛢  `-`\n\nOutput B: 󰛢  `2`\n\n#### Example \"letters\"\n\n```lua\nHarpoonline.setup({\n  -- config\n  ---@param data HarpoonlineData\n  ---@param opts HarpoonLineConfig\n  ---@return string\n  custom_formatter = function(data, opts)\n    local letters = { \"j\", \"k\", \"l\", \"h\" }\n    local idx = data.active_idx\n    local slot = 0\n    local slots = vim.tbl_map(function(letter)\n      slot = slot + 1\n      return idx and idx == slot and string.upper(letter) or letter\n    end, vim.list_slice(letters, 1, math.min(#letters, #data.items)))\n\n    local name = data.list_name and data.list_name or opts.default_list_name\n    local header = string.format(\"%s%s%s\", opts.icon, name == \"\" and \"\" or \" \", name)\n    return header .. \" \" .. table.concat(slots)\n  end,\n  -- more config\n})\n```\n\nOutput A: 󰛢  `jkl`\n\nOutput B: 󰛢  `jKl`\n\n*Note*:\n\n- It is possible to also use inner highlights in the formatter function.\nSee the example recipe for NvChad.\n- It is possible to use the `harpoon` information inside each `data.items`\n\n## Harpoon lists\n\nThis plugin supports working with multiple harpoon lists.\nThe list in use when Neovim is started is assumed to be the default list\n\n**Important**:\n\nThe plugin needs to be notified when switching to another list\nusing its custom `HarpoonSwitchedList` event:\n\n```lua\n -- Starts with the default. Use this variable in harpoon:list(list_name)\nlocal list_name = nil\n\nvim.keymap.set(\"n\", \"\u003cleader\u003eJ\", function()\n  -- toggle between the default list(nil) and list \"custom\"\n  list_name = list_name ~= \"custom\" and \"custom\" or nil\n  vim.api.nvim_exec_autocmds(\"User\",\n    { pattern = \"HarpoonSwitchedList\", modeline = false, data = list_name })\nend, { desc = \"Switch harpoon list\", silent = true })\n```\n\nA complete setup using two harpoon lists can be found in [ak.config.editor.harpoon]\n\n## Recipes\n\n### Heirline\n\nBasic example:\n\n```lua\nlocal Harpoonline = require \"harpoonline\"\nHarpoonline.setup({\n  on_update = function() vim.cmd.redrawstatus() end\n})\nlocal HarpoonComponent = {\n  provider = function() return \" \" .. Harpoonline.format() .. \" \" end,\n  hl = function()\n    if Harpoonline.is_buffer_harpooned() then \n      return \"MiniHipatternsHack\"-- example using mini.hipatterns\n    end\n  end,\n}\n-- A minimal statusline:\nrequire(\"heirline\").setup({ statusline = { HarpoonComponent }})\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eA proof of concept for AstroNvim v4\u003c/summary\u003e\n\n```lua\n{\n  \"rebelot/heirline.nvim\",\n  dependencies = \"abeldekat/harpoonline\",\n  config = function(plugin, opts)\n    local Status = require \"astroui.status\"\n    local Harpoonline = require \"harpoonline\"\n    Harpoonline.setup {\n      on_update = function() vim.cmd.redrawstatus() end,\n    }\n    local HarpoonComponent = Status.component.builder {\n      {\n        provider = function()\n          local line = Harpoonline.format()\n          return Status.utils.stylize(line, { padding = { left = 1, right = 1 }})\n        end,\n        hl = function()\n          if Harpoonline.is_buffer_harpooned() then\n              return { bg = \"command\", fg = \"bg\" }\n          end\n        end,\n      },\n    }\n    table.insert(opts.statusline, 4, HarpoonComponent) -- after file_info component\n    require \"astronvim.plugins.configs.heirline\"(plugin, opts)\n  end,\n}\n```\n\n\u003c/details\u003e\n\n### NvChad statusline\n\n\u003cdetails\u003e\n\u003csummary\u003eA proof of concept for NvChad v2.5\u003c/summary\u003e\n\n```lua\n---@type ChadrcConfig\nlocal M = {} -- nvchad starter: lua.chadrc.lua\n\n-- Add to config.plugins:\n-- {\n--     \"nvchad/ui\",\n--     dependencies = {\n--       \"abeldekat/harpoonline\",\n--       config = function()\n--         require(\"harpoonline\").setup {\n--           on_update = function() vim.cmd.redrawstatus() end,\n--         }\n--       end,\n--     },\n-- }\n\nM.ui = {\n  theme = \"flexoki-light\",\n\n  statusline = {\n    theme = \"vscode\",\n    separator_style = \"default\",\n    -- Copy local \"orders.vscode\" from nvchad.stl.utils(plugin nvchad/ui)\n    -- Add string \"harpoon\" before \"file\"\n    order = { \"mode\", \"harpoon\", \"file\", \"diagnostics\", \"git\",\n      \"%=\", \"lsp_msg\", \"%=\", \"lsp\", \"cursor\", \"cwd\" },\n    modules = {\n      -- Add a custom harpoon module, using the file background.\n      harpoon = function()\n        return \"%#St_file_bg# \" .. require(\"harpoonline\").format() .. \" \"\n      end,\n    },\n  },\n}\n\nreturn M\n```\n\n\u003c/details\u003e\n\n## Related plugins\n\n[harpoon-lualine]\n\n- Dedicated to [lualine]\n- A single, customizable formatting algorithm\n- No caching\n- No support for other lists than the default\n\n## Acknowledgements\n\n- @theprimeagen: Harpoon is the most important part of my workflow.\n- @echasnovski: The structure of this plugin is heavily based on [mini.nvim]\n\n[harpoon2]: https://github.com/ThePrimeagen/harpoon/tree/harpoon2\n[lualine]: https://github.com/nvim-lualine/lualine.nvim\n[mini.statusline]: https://github.com/echasnovski/mini.statusline\n[heirline]: https://github.com/rebelot/heirline.nvim\n[mini.nvim]: https://github.com/echasnovski/mini.nvim\n[harpoon-lualine]: https://github.com/letieu/harpoon-lualine\n[ak.config.editor.harpoon]: https://github.com/abeldekat/nvim_pde/blob/main/lua/ak/config/editor/harpoon.lua\n[ak.config.ui.harpoonline]: https://github.com/abeldekat/nvim_pde/blob/main/lua/ak/config/ui/harpoonline.lua\n[ak.config.ui.mini_statusline]: https://github.com/abeldekat/nvim_pde/blob/main/lua/ak/config/ui/mini_statusline.lua\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fabeldekat%2Fharpoonline","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fabeldekat%2Fharpoonline","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fabeldekat%2Fharpoonline/lists"}