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 req = require("lualine_require")
|
||||||
local Component = req.require("lualine.component")
|
local Component = req.require("lualine.component")
|
||||||
|
|
||||||
|
---@class LualineHarpoonComponent : lualine.Component
|
||||||
|
---@field cache LualineHarpoonCache
|
||||||
|
---@field options LualineHarpoonConfig
|
||||||
local M = Component:extend()
|
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)
|
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.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
|
end
|
||||||
|
|
||||||
function M:update_status()
|
---@private
|
||||||
local st = status.get_status()
|
function M:setup_cache_invalidation()
|
||||||
if st.total == 0 then
|
local group_name = "LualineHarpoon_" .. tostring(self)
|
||||||
return ""
|
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
|
end
|
||||||
|
|
||||||
|
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 s = self.options.symbol
|
||||||
local n = st.current and tostring(st.current) or s.unknown
|
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)
|
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
|
end
|
||||||
|
|
||||||
|
---@return string
|
||||||
function M:draw_status()
|
function M:draw_status()
|
||||||
local text = self:update_status()
|
local text = self:update_status()
|
||||||
if self.color_hl and text ~= "" then
|
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 = {
|
local M = {
|
||||||
symbol = {
|
symbol = {
|
||||||
open = "[",
|
open = "[",
|
||||||
@ -6,6 +26,14 @@ local M = {
|
|||||||
unknown = "?",
|
unknown = "?",
|
||||||
},
|
},
|
||||||
icon = "",
|
icon = "",
|
||||||
|
show_when_empty = false,
|
||||||
|
show_icon = true,
|
||||||
|
format = nil,
|
||||||
|
colors = {
|
||||||
|
active = nil,
|
||||||
|
inactive = nil,
|
||||||
|
},
|
||||||
|
cache_timeout = 100,
|
||||||
}
|
}
|
||||||
|
|
||||||
return M
|
return M
|
||||||
|
|||||||
@ -1,27 +1,40 @@
|
|||||||
|
---@class LualineHarpoonHealth
|
||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
|
---@return nil
|
||||||
function M.check()
|
function M.check()
|
||||||
vim.health.start("lualine-harpoon")
|
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
|
if has_lualine then
|
||||||
vim.health.ok("lualine is installed")
|
vim.health.ok("lualine is installed")
|
||||||
|
if lualine_version and lualine_version.version then
|
||||||
|
vim.health.info("lualine version: " .. lualine_version.version)
|
||||||
|
end
|
||||||
else
|
else
|
||||||
vim.health.error("lualine is not installed")
|
vim.health.error("lualine is not installed")
|
||||||
end
|
end
|
||||||
|
|
||||||
local has_harpoon = pcall(require, "harpoon")
|
local has_harpoon, harpoon_module = pcall(require, "harpoon")
|
||||||
if has_harpoon then
|
if has_harpoon then
|
||||||
vim.health.ok("harpoon is installed")
|
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
|
else
|
||||||
vim.health.warn("harpoon is not installed - component will show empty")
|
vim.health.warn("harpoon is not installed - component will show empty")
|
||||||
end
|
end
|
||||||
|
|
||||||
local has_plenary = pcall(require, "plenary.path")
|
-- Check Neovim version
|
||||||
if has_plenary then
|
local nvim_version = vim.version()
|
||||||
vim.health.ok("plenary.nvim is installed (recommended)")
|
if nvim_version.major == 0 and nvim_version.minor < 8 then
|
||||||
|
vim.health.error("Neovim 0.8+ is required")
|
||||||
else
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,32 @@
|
|||||||
local component = require("lualine-harpoon.component")
|
local component = require("lualine-harpoon.component")
|
||||||
|
local cfg = require("lualine-harpoon.config")
|
||||||
|
|
||||||
|
---@class LualineHarpoonPlugin
|
||||||
|
---@field component LualineHarpoonComponent
|
||||||
local M = {
|
local M = {
|
||||||
component = component,
|
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
|
return M
|
||||||
|
|||||||
@ -1,27 +1,49 @@
|
|||||||
local ok, harpoon = pcall(require, "harpoon")
|
local ok, harpoon = pcall(require, "harpoon")
|
||||||
local utils = require("lualine-harpoon.utils")
|
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 = {}
|
local M = {}
|
||||||
|
|
||||||
--- Get current 1-based index and total Harpoon marks
|
--- Get current 1-based index and total Harpoon marks
|
||||||
---@return { current: integer?, total: integer }
|
---@return HarpoonStatus
|
||||||
function M.get_status()
|
function M.get_status()
|
||||||
if not ok then
|
if not ok then
|
||||||
return { current = nil, total = 0 }
|
return { current = nil, total = 0 }
|
||||||
end
|
end
|
||||||
|
|
||||||
local list = harpoon:list()
|
local success, list = pcall(function()
|
||||||
local total = list:length()
|
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
|
if total == 0 then
|
||||||
return { current = nil, total = 0 }
|
return { current = nil, total = 0 }
|
||||||
end
|
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 buf = vim.api.nvim_buf_get_name(0)
|
||||||
local rel_buf = utils.normalize(buf, root)
|
local rel_buf = utils.normalize(buf, root)
|
||||||
|
|
||||||
local _, idx = list:get_by_value(rel_buf)
|
local success_get, idx = pcall(function()
|
||||||
if type(idx) ~= "number" or idx < 1 or idx > total then
|
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
|
idx = nil
|
||||||
end
|
end
|
||||||
return { current = idx, total = total }
|
return { current = idx, total = total }
|
||||||
|
|||||||
@ -1,16 +1,37 @@
|
|||||||
local ok_path, Path = pcall(require, "plenary.path")
|
---@class LualineHarpoonUtils
|
||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
--- Normalize `buf` relative to `root`, if plenary.path is available.
|
---Normalize `buf` relative to `root` using Neovim built-ins
|
||||||
---@param buf string
|
---@param buf string Absolute path to buffer
|
||||||
---@param root string
|
---@param root string Root directory path
|
||||||
---@return string
|
---@return string Normalized path relative to root
|
||||||
function M.normalize(buf, root)
|
function M.normalize(buf, root)
|
||||||
if ok_path then
|
if not buf or buf == "" then
|
||||||
return Path:new(buf):make_relative(root)
|
return ""
|
||||||
else
|
end
|
||||||
|
|
||||||
|
if not root or root == "" then
|
||||||
return buf
|
return buf
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
return M
|
return M
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user