diff --git a/README.md b/README.md index 09b4b9f..550a6f3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # lualine-harpoon.nvim -![](assets/img/2025-05-21_12-16-25.webp) +![](assets/img/2025-05-26_01-33-01.png) A tiny [Lualine](https://github.com/nvim-lualine/lualine.nvim) component for [ThePrimeagen/harpoon2](https://github.com/ThePrimeagen/harpoon). @@ -11,7 +11,6 @@ Displays your current Harpoon mark as `[x/y]` in your statusline. - Neovim 0.8+ - [nvim-lualine/lualine.nvim](https://github.com/nvim-lualine/lualine.nvim) - [ThePrimeagen/harpoon](https://github.com/ThePrimeagen/harpoon) (harpoon2 branch) -- [nvim-lua/plenary.nvim](https://github.com/nvim-lua/plenary.nvim) > [!IMPORTANT] > Make sure to install [harpoon2](https://github.com/ThePrimeagen/harpoon/tree/harpoon2), not harpoon on `master` branch. @@ -27,7 +26,6 @@ Displays your current Harpoon mark as `[x/y]` in your statusline. "kristoferssolo/lualine-harpoon.nvim", dependencies = { { "ThePrimeagen/harpoon", branch = "harpoon2" } - "nvim-lua/plenary.nvim", }, }, } @@ -39,40 +37,119 @@ Once installed, simply add `"harpoon"` to your `lualine.setup` sections. Lualine will auto-load `lua/lualine/components/harpoon.lua` for you: ```lua -require("lualine").setup({ +{ sections = { lualine_c = { "harpoon", }, }, -}) +} ``` -When you have Harpoon marks, you’ll see an indicator like `[2/5]` in your statusline. +When you have Harpoon marks, you'll see an indicator like `[2/5]` in your statusline. -## Default Options +## Configuration -You can pass options directly in your Lualine sections: +### Global Setup + +You can configure the plugin globally using the setup function: ```lua -require("lualine").setup({ +{ + -- Configure symbols used in the display + symbol = { + open = "[", + close = "]", + separator = "/", + unknown = "?", + }, + -- Icon displayed before the harpoon status + icon = "󰀱", + -- Show component even when there are no harpoon marks + show_when_empty = false, + -- Custom format function (overrides default formatting) + format = function(current, total) + return string.format("Harpoon: %s/%d", current or "?", total) + end, + -- Cache timeout in milliseconds for performance + cache_timeout = 100, +} +``` + +### Per-Component Configuration + +You can also pass options directly in your Lualine sections: + +```lua +{ + sections = { + lualine_c = { + { + "harpoon", + symbol = { + open = "(", + close = ")", + separator = "|", + unknown = "?", + }, + icon = "🎯", + show_when_empty = true, + }, + }, + }, +} +``` + +## Configuration Options + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `symbol.open` | `string` | `"["` | Opening bracket for the display | +| `symbol.close` | `string` | `"]"` | Closing bracket for the display | +| `symbol.separator` | `string` | `"/"` | Separator between current and total | +| `symbol.unknown` | `string` | `"?"` | Symbol when current position is unknown | +| `icon` | `string` | `"󰀱"` | Icon displayed before the status | +| `show_when_empty` | `boolean` | `false` | Show component when no harpoon marks exist | +| `format` | `function?` | `nil` | Custom format function `(current, total) -> string` | +| `cache_timeout` | `number` | `100` | Cache timeout in milliseconds for performance | + +## Custom Formatting + +You can provide a custom format function to completely control the display: + +```lua +{ sections = { lualine_c = { { "harpoon", - symbol = { - open = "[", - close = "]", - separator = "/", - unknown = "?", - }, - icon = "󰀱", + format = function(current, total) + if total == 0 then + return "No marks" + end + local mark = current and ("Mark " .. current) or "Not marked" + return string.format("%s (%d total)", mark, total) + end, }, }, }, -}) +} ``` +## Health Check + +Run `:checkhealth lualine-harpoon` to verify your setup and dependencies. + +## Performance + +The component includes caching to avoid unnecessary recalculation on every statusline update. The cache is automatically invalidated when: + +- You switch buffers +- Buffer content changes +- Harpoon marks are modified + +You can adjust the cache timeout via the `cache_timeout` option if needed. + ## Acknowledgments and alternatives This plugin was inspired by and serves as an alternative to [letieu/harpoon-lualine](https://github.com/letieu/harpoon-lualine). diff --git a/assets/img/2025-05-21_12-16-25.webp b/assets/img/2025-05-21_12-16-25.webp deleted file mode 100644 index c14e000..0000000 Binary files a/assets/img/2025-05-21_12-16-25.webp and /dev/null differ diff --git a/assets/img/2025-05-26_01-33-01.png b/assets/img/2025-05-26_01-33-01.png new file mode 100644 index 0000000..9ca47ff Binary files /dev/null and b/assets/img/2025-05-26_01-33-01.png differ diff --git a/lua/lualine-harpoon/component.lua b/lua/lualine-harpoon/component.lua index 90c2349..f101099 100644 --- a/lua/lualine-harpoon/component.lua +++ b/lua/lualine-harpoon/component.lua @@ -4,7 +4,7 @@ local cfg = require("lualine-harpoon.config") local req = require("lualine_require") local Component = req.require("lualine.component") ----@class LualineHarpoonComponent : lualine.Component +---@class LualineHarpoonComponent ---@field cache LualineHarpoonCache ---@field options LualineHarpoonConfig local M = Component:extend() @@ -16,25 +16,6 @@ local M = Component:extend() ---@field last_changedtick integer? ---@field last_status_hash string? ----@class LualineHarpoonConfig ----@field symbol LualineHarpoonSymbols ----@field icon string ----@field show_when_empty boolean ----@field show_icon boolean ----@field format function? ----@field colors LualineHarpoonColors ----@field cache_timeout integer - ----@class LualineHarpoonSymbols ----@field open string ----@field close string ----@field separator string ----@field unknown string - ----@class LualineHarpoonColors ----@field active string? ----@field inactive string? - ---@param opts table? function M:init(opts) M.super:init(opts) @@ -119,12 +100,21 @@ function M:update_status() local st = status.get_status() local result = "" + -- Handle custom format function if type(self.options.format) == "function" then result = self.options.format(st.current, st.total) elseif st.total > 0 then + -- Default formatting when we have marks local s = self.options.symbol local n = st.current and tostring(st.current) or s.unknown result = string.format("%s%s%s%d%s", s.open, n, s.separator, st.total, s.close) + elseif self.options.show_when_empty then + -- Show something when no marks exist, but only if show_when_empty is true + local s = self.options.symbol + if type(self.options.empty_text) == "string" then + result = self.options.empty_text + end + result = string.format("%s0%s0%s", s.open, s.separator, s.close) end self:update_cache(result) diff --git a/lua/lualine-harpoon/config.lua b/lua/lualine-harpoon/config.lua index c802974..794598b 100644 --- a/lua/lualine-harpoon/config.lua +++ b/lua/lualine-harpoon/config.lua @@ -2,9 +2,8 @@ ---@field symbol LualineHarpoonSymbols ---@field icon string ---@field show_when_empty boolean ----@field show_icon boolean ---@field format function? ----@field colors LualineHarpoonColors +---@field empty_text string? ---@field cache_timeout integer ---@class LualineHarpoonSymbols @@ -13,10 +12,6 @@ ---@field separator string ---@field unknown string ----@class LualineHarpoonColors ----@field active string? ----@field inactive string? - ---@type LualineHarpoonConfig local M = { symbol = { @@ -27,12 +22,8 @@ local M = { }, icon = "󰀱", show_when_empty = false, - show_icon = true, format = nil, - colors = { - active = nil, - inactive = nil, - }, + empty_text = nil, cache_timeout = 100, }