mirror of
https://github.com/kristoferssolo/lualine-harpoon.nvim.git
synced 2025-10-21 19:50:33 +00:00
refactor: optimize
This commit is contained in:
parent
97619e677c
commit
363f3e78a3
@ -4,23 +4,134 @@ local cfg = require("lualine-harpoon.config")
|
||||
local req = require("lualine_require")
|
||||
local Component = req.require("lualine.component")
|
||||
|
||||
---@class LualineHarpoonComponent : lualine.Component
|
||||
---@field cache LualineHarpoonCache
|
||||
---@field options LualineHarpoonConfig
|
||||
local M = Component:extend()
|
||||
|
||||
---@class LualineHarpoonCache
|
||||
---@field result string?
|
||||
---@field is_valid boolean
|
||||
---@field last_buf string?
|
||||
---@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(self, opts)
|
||||
M.super:init(opts)
|
||||
self.options = vim.tbl_deep_extend("force", cfg, self.options or {})
|
||||
|
||||
self.cache = {
|
||||
result = nil,
|
||||
is_valid = false,
|
||||
last_buf = nil,
|
||||
last_changedtick = nil,
|
||||
last_status_hash = nil,
|
||||
}
|
||||
|
||||
self:setup_cache_invalidation()
|
||||
end
|
||||
|
||||
function M:update_status()
|
||||
local st = status.get_status()
|
||||
if st.total == 0 then
|
||||
return ""
|
||||
---@private
|
||||
function M:setup_cache_invalidation()
|
||||
local group_name = "LualineHarpoon_" .. tostring(self)
|
||||
local group = vim.api.nvim_create_augroup(group_name, { clear = true })
|
||||
|
||||
vim.api.nvim_create_autocmd({
|
||||
"BufEnter",
|
||||
"BufWritePost",
|
||||
"User",
|
||||
}, {
|
||||
group = group,
|
||||
callback = function()
|
||||
self.cache.is_valid = false
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
---@param st HarpoonStatus
|
||||
---@return string
|
||||
function M:hash_status(st)
|
||||
return string.format("%s:%s", tostring(st.current or "nil"), st.total)
|
||||
end
|
||||
|
||||
---@return boolean
|
||||
function M:is_cache_valid()
|
||||
if not self.cache.is_valid then
|
||||
return false
|
||||
end
|
||||
local s = self.options.symbol
|
||||
local n = st.current and tostring(st.current) or s.unknown
|
||||
return string.format("%s%s%s%d%s", s.open, n, s.separator, st.total, s.close)
|
||||
|
||||
local current_buf = vim.api.nvim_buf_get_name(0)
|
||||
local current_changetick = vim.api.nvim_buf_get_changedtick(0)
|
||||
|
||||
if self.cache.last_buf ~= current_buf or self.cache.last_changedtick ~= current_changetick then
|
||||
return false
|
||||
end
|
||||
|
||||
local current_status = status.get_status()
|
||||
local current_hash = self:hash_status(current_status)
|
||||
|
||||
return self.cache.last_status_hash == current_hash
|
||||
end
|
||||
|
||||
---@param new_cfg LualineHarpoonConfig
|
||||
function M.upadte_config(new_cfg)
|
||||
cfg = new_cfg
|
||||
end
|
||||
|
||||
---@param result string
|
||||
---@private
|
||||
function M:update_cache(result)
|
||||
local current_status = status.get_status()
|
||||
|
||||
self.cache.result = result
|
||||
self.cache.is_valid = true
|
||||
self.cache.last_buf = vim.api.nvim_buf_get_name(0)
|
||||
self.cache.last_changedtick = vim.api.nvim_buf_get_changedtick(0)
|
||||
self.cache.last_status_hash = self:hash_status(current_status)
|
||||
end
|
||||
|
||||
---@return string
|
||||
function M:update_status()
|
||||
if self:is_cache_valid() then
|
||||
return self.cache.result
|
||||
end
|
||||
|
||||
local st = status.get_status()
|
||||
local result = ""
|
||||
|
||||
if type(self.options.format) == "function" then
|
||||
result = self.options.format(st.current, st.total)
|
||||
elseif st.total > 0 then
|
||||
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)
|
||||
end
|
||||
|
||||
self:update_cache(result)
|
||||
return result
|
||||
end
|
||||
|
||||
---@return string
|
||||
function M:draw_status()
|
||||
local text = self:update_status()
|
||||
if self.color_hl and text ~= "" then
|
||||
|
||||
@ -1,3 +1,23 @@
|
||||
---@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?
|
||||
|
||||
---@type LualineHarpoonConfig
|
||||
local M = {
|
||||
symbol = {
|
||||
open = "[",
|
||||
@ -6,6 +26,14 @@ local M = {
|
||||
unknown = "?",
|
||||
},
|
||||
icon = "",
|
||||
show_when_empty = false,
|
||||
show_icon = true,
|
||||
format = nil,
|
||||
colors = {
|
||||
active = nil,
|
||||
inactive = nil,
|
||||
},
|
||||
cache_timeout = 100,
|
||||
}
|
||||
|
||||
return M
|
||||
|
||||
@ -1,27 +1,40 @@
|
||||
---@class LualineHarpoonHealth
|
||||
local M = {}
|
||||
|
||||
---@return nil
|
||||
function M.check()
|
||||
vim.health.start("lualine-harpoon")
|
||||
|
||||
local has_lualine = pcall(require, "lualine")
|
||||
-- Check for required dependencies
|
||||
local has_lualine, lualine_version = pcall(require, "lualine")
|
||||
if has_lualine then
|
||||
vim.health.ok("lualine is installed")
|
||||
if lualine_version and lualine_version.version then
|
||||
vim.health.info("lualine version: " .. lualine_version.version)
|
||||
end
|
||||
else
|
||||
vim.health.error("lualine is not installed")
|
||||
end
|
||||
|
||||
local has_harpoon = pcall(require, "harpoon")
|
||||
local has_harpoon, harpoon_module = pcall(require, "harpoon")
|
||||
if has_harpoon then
|
||||
vim.health.ok("harpoon is installed")
|
||||
-- Check if it's harpoon 2.x
|
||||
if harpoon_module and harpoon_module.list then
|
||||
vim.health.info("harpoon 2.x detected")
|
||||
else
|
||||
vim.health.warn("harpoon 1.x detected - may not be fully compatible")
|
||||
end
|
||||
else
|
||||
vim.health.warn("harpoon is not installed - component will show empty")
|
||||
end
|
||||
|
||||
local has_plenary = pcall(require, "plenary.path")
|
||||
if has_plenary then
|
||||
vim.health.ok("plenary.nvim is installed (recommended)")
|
||||
-- Check Neovim version
|
||||
local nvim_version = vim.version()
|
||||
if nvim_version.major == 0 and nvim_version.minor < 8 then
|
||||
vim.health.error("Neovim 0.8+ is required")
|
||||
else
|
||||
vim.health.warn("plenary.nvim is not installed - path normalization disabled")
|
||||
vim.health.ok(string.format("Neovim %d.%d.%d", nvim_version.major, nvim_version.minor, nvim_version.patch))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@ -1,9 +1,32 @@
|
||||
local component = require("lualine-harpoon.component")
|
||||
local cfg = require("lualine-harpoon.config")
|
||||
|
||||
---@class LualineHarpoonPlugin
|
||||
---@field component LualineHarpoonComponent
|
||||
local M = {
|
||||
component = component,
|
||||
}
|
||||
|
||||
function M.setup(_opts) end
|
||||
---@param opts LualineHarpoonConfig?
|
||||
---@return nil
|
||||
function M.setup(opts)
|
||||
opts = opts or {}
|
||||
|
||||
-- Validate options
|
||||
if opts.cache_timeout and type(opts.cache_timeout) ~= "number" then
|
||||
vim.notify("lualine-harpoon: cache_timeout must be a number", vim.log.levels.WARN)
|
||||
opts.cache_timeout = nil
|
||||
end
|
||||
|
||||
if opts.format and type(opts.format) ~= "function" then
|
||||
vim.notify("lualine-harpoon: format must be a function", vim.log.levels.WARN)
|
||||
opts.format = nil
|
||||
end
|
||||
|
||||
---@type LualineHarpoonConfig
|
||||
local updated_cfg = vim.tbl_deep_extend("force", cfg, opts)
|
||||
|
||||
component.upadte_config(updated_cfg)
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
@ -1,27 +1,49 @@
|
||||
local ok, harpoon = pcall(require, "harpoon")
|
||||
local utils = require("lualine-harpoon.utils")
|
||||
|
||||
---@class HarpoonStatus
|
||||
---@field current integer? 1-based index of current file in harpoon list
|
||||
---@field total integer Total number of files in harpoon list
|
||||
|
||||
---@class LualineHarpoonStatus
|
||||
local M = {}
|
||||
|
||||
--- Get current 1-based index and total Harpoon marks
|
||||
---@return { current: integer?, total: integer }
|
||||
---@return HarpoonStatus
|
||||
function M.get_status()
|
||||
if not ok then
|
||||
return { current = nil, total = 0 }
|
||||
end
|
||||
|
||||
local list = harpoon:list()
|
||||
local total = list:length()
|
||||
local success, list = pcall(function()
|
||||
return harpoon:list()
|
||||
end)
|
||||
|
||||
if not success or not list then
|
||||
return { current = nil, total = 0 }
|
||||
end
|
||||
|
||||
local total = list:length()
|
||||
if total == 0 then
|
||||
return { current = nil, total = 0 }
|
||||
end
|
||||
|
||||
local root = list.config.get_root_dir()
|
||||
local success_root, root = pcall(function()
|
||||
return list.config.get_root_dir()
|
||||
end)
|
||||
|
||||
if not success_root then
|
||||
return { current = nil, total = 0 }
|
||||
end
|
||||
|
||||
local buf = vim.api.nvim_buf_get_name(0)
|
||||
local rel_buf = utils.normalize(buf, root)
|
||||
|
||||
local _, idx = list:get_by_value(rel_buf)
|
||||
if type(idx) ~= "number" or idx < 1 or idx > total then
|
||||
local success_get, idx = pcall(function()
|
||||
local _, index = list:get_by_value(rel_buf)
|
||||
return index
|
||||
end)
|
||||
if not success_get or type(idx) ~= "number" or idx < 1 or idx > total then
|
||||
idx = nil
|
||||
end
|
||||
return { current = idx, total = total }
|
||||
|
||||
@ -1,16 +1,37 @@
|
||||
local ok_path, Path = pcall(require, "plenary.path")
|
||||
---@class LualineHarpoonUtils
|
||||
local M = {}
|
||||
|
||||
--- Normalize `buf` relative to `root`, if plenary.path is available.
|
||||
---@param buf string
|
||||
---@param root string
|
||||
---@return string
|
||||
---Normalize `buf` relative to `root` using Neovim built-ins
|
||||
---@param buf string Absolute path to buffer
|
||||
---@param root string Root directory path
|
||||
---@return string Normalized path relative to root
|
||||
function M.normalize(buf, root)
|
||||
if ok_path then
|
||||
return Path:new(buf):make_relative(root)
|
||||
else
|
||||
if not buf or buf == "" then
|
||||
return ""
|
||||
end
|
||||
|
||||
if not root or root == "" then
|
||||
return buf
|
||||
end
|
||||
|
||||
-- Use vim.fs.normalize for consistent path separators (Neovim 0.8+)
|
||||
if vim.fs and vim.fs.normalize then
|
||||
buf = vim.fs.normalize(buf)
|
||||
root = vim.fs.normalize(root)
|
||||
end
|
||||
|
||||
-- Use vim.fn.fnamemodify to make path relative
|
||||
local relative = vim.fn.fnamemodify(buf, ":p:.")
|
||||
|
||||
-- If the buffer is within the root directory, make it relative to root
|
||||
if buf:find("^" .. vim.pesc(root), 1) then
|
||||
relative = buf:sub(#root + 1)
|
||||
-- Remove leading path separator
|
||||
relative = relative:gsub("^[/\\]", "")
|
||||
return relative ~= "" and relative or "."
|
||||
end
|
||||
|
||||
return relative
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
Loading…
Reference in New Issue
Block a user