移除 vim-fugitive 和 mini.diff,引入三层 Git 工具栈(对齐 nvchad 分支): - gitsigns.nvim:buffer 级 inline gutter + hunk 操作(BufReadPost 懒加载) - neogit:仓库级 status 客户端(<leader>gg,依赖 plenary) - codediff.nvim:文件级 side-by-side diff(<leader>gd/gD) 键位变更: - ghs/ghr/ghp/ghb/ghB/ghd/ghD + ]h/[h 改由 gitsigns 提供 - <leader>gg → Neogit、<leader>gd/gD → CodeDiff - 移除 <leader>gl(GcLog,由 neogit 内部 log 视图取代) 三个独立插件统一采用 load_X() → packadd → require().setup() 加载风格
182 lines
6.3 KiB
Lua
182 lines
6.3 KiB
Lua
-- =============================================================================
|
||
-- 自定义懒加载框架 (lua/lazy.lua)
|
||
-- =============================================================================
|
||
-- 本模块与 lazy.nvim 插件管理器完全无关,
|
||
-- 是一个约 35 行的轻量级懒加载原语封装,用于延迟加载重型插件模块。
|
||
--
|
||
-- 核心设计:
|
||
-- - 通过 _loaded 表跟踪已加载模块,避免重复初始化
|
||
-- - on_event:通过 autocmd 在特定事件(如 InsertEnter、BufReadPost)触发加载
|
||
-- - on_keys:通过键位映射触发加载,首次按键时初始化插件
|
||
-- - load:直接加载,用于手动触发或内部调用
|
||
-- =============================================================================
|
||
|
||
local M = {}
|
||
|
||
-- 已加载模块的标记表。
|
||
-- 键为模块标识名(如 "treesitter", "lsp", "completion"),
|
||
-- 值为 true 表示该模块已完成初始化。
|
||
-- 此表用于防止重复加载和重复执行 setup()。
|
||
M._loaded = {}
|
||
|
||
-- ---------------------------------------------------------------------------
|
||
-- 直接加载模块
|
||
-- ---------------------------------------------------------------------------
|
||
-- 参数:
|
||
-- name - 模块标识名(自定义字符串,用于 _loaded 去重)
|
||
-- fn - 可选的初始化函数,在首次加载时执行
|
||
--
|
||
-- 行为:
|
||
-- 1. 检查 _loaded[name] 是否为真,是则直接返回(幂等)
|
||
-- 2. 如果有 fn,执行 fn() 完成插件 setup
|
||
-- 3. 仅在 fn() 成功执行后,标记为已加载
|
||
--
|
||
-- 使用场景:
|
||
-- 在按键回调中手动触发加载,或在 on_event 回调中延迟初始化。
|
||
M.load = function(name, fn)
|
||
if M._loaded[name] then
|
||
return true
|
||
end
|
||
if fn then
|
||
local ok, err = pcall(fn)
|
||
if not ok then
|
||
vim.notify("[lazy] 加载 " .. name .. " 失败: " .. tostring(err), vim.log.levels.ERROR)
|
||
return false
|
||
end
|
||
end
|
||
M._loaded[name] = true
|
||
return true
|
||
end
|
||
|
||
-- 仅标记模块为已加载,不执行 setup(用于直接加载的插件)。
|
||
M.track = function(name)
|
||
if M._loaded[name] then
|
||
return true
|
||
end
|
||
M._loaded[name] = true
|
||
return true
|
||
end
|
||
|
||
-- ---------------------------------------------------------------------------
|
||
-- 事件触发懒加载
|
||
-- ---------------------------------------------------------------------------
|
||
-- 参数:
|
||
-- name - 模块标识名
|
||
-- event - Neovim autocmd 事件名(如 "InsertEnter", "BufReadPost", "VimEnter")
|
||
-- pattern - autocmd 匹配模式,默认为 "*"
|
||
-- fn - 初始化函数
|
||
--
|
||
-- 原理:
|
||
-- 创建一个一次性的 autocmd(once = true),
|
||
-- 当指定事件首次触发时,调用 M.load(name, fn) 完成初始化。
|
||
-- 由于 once = true,autocmd 在触发后自动销毁,不会重复执行。
|
||
--
|
||
-- 典型用法:
|
||
-- lazy.on_event("completion", "InsertEnter", "*", function()
|
||
-- require("mini.completion").setup({ ... })
|
||
-- end)
|
||
M.on_event = function(name, event, pattern, fn)
|
||
vim.api.nvim_create_autocmd(event, {
|
||
pattern = pattern or "*",
|
||
once = true,
|
||
callback = function()
|
||
M.load(name, fn)
|
||
end,
|
||
})
|
||
end
|
||
|
||
-- ---------------------------------------------------------------------------
|
||
-- 按键触发懒加载
|
||
-- ---------------------------------------------------------------------------
|
||
-- 参数:
|
||
-- name - 模块标识名
|
||
-- keys - 键位序列(如 "<leader>ff", "<leader>gg")
|
||
-- mode - 映射模式,默认为 "n"(normal)
|
||
-- fn - 初始化函数,在首次按键时执行
|
||
-- action - 可选的额外动作函数,在 fn 之后执行
|
||
-- opts - 键位映射选项(desc, buffer 等)
|
||
--
|
||
-- 原理:
|
||
-- 创建一个键位映射,首次按下时:
|
||
-- 1. 调用 M.load(name, fn) 完成插件初始化
|
||
-- 2. 如果 M.load 失败,直接返回,不执行 action
|
||
-- 3. 如果提供了 action 且加载成功,执行 action()
|
||
-- 4. 后续按键直接执行 action(因为 _loaded 已标记)
|
||
--
|
||
-- 注意:
|
||
-- 此设计使得首次按键稍慢(需要 setup),后续按键与直接映射无异。
|
||
-- 适合重型插件如 mini.pick、neogit。
|
||
M.on_keys = function(name, keys, mode, fn, action, opts)
|
||
mode = mode or "n"
|
||
opts = opts or {}
|
||
vim.keymap.set(mode, keys, function()
|
||
if not M.load(name, fn) then
|
||
return
|
||
end
|
||
if action then
|
||
action()
|
||
end
|
||
end, { desc = opts.desc, buffer = opts.buffer })
|
||
end
|
||
|
||
-- ---------------------------------------------------------------------------
|
||
-- 命令触发懒加载
|
||
-- ---------------------------------------------------------------------------
|
||
-- 参数:
|
||
-- name - 模块标识名
|
||
-- cmd - 命令名(如 "ExColors")
|
||
-- fn - 初始化函数,在首次执行命令时调用
|
||
-- opts - 用户命令选项(bang, nargs, range, desc 等)
|
||
--
|
||
-- 原理:
|
||
-- 创建一个同名的临时用户命令,首次执行时:
|
||
-- 1. 调用 M.load(name, fn) 完成插件初始化
|
||
-- 2. 如果加载失败,保留临时命令,让用户可以重试
|
||
-- 3. 加载成功后删除临时命令,避免与插件注册的命令冲突
|
||
-- 4. 按用户输入的完整形式(mods/range/bang/args)重新执行命令
|
||
--
|
||
-- 注意:
|
||
-- 插件初始化后通常会注册同名命令并覆盖临时命令;
|
||
-- 如果插件不注册命令,需要用 fn 手动处理命令逻辑。
|
||
M.on_cmd = function(name, cmd, fn, opts)
|
||
opts = opts or {}
|
||
vim.api.nvim_create_user_command(cmd, function(cmd_opts)
|
||
-- 先加载;只有加载成功才删除临时命令,否则保留重试机会
|
||
if not M.load(name, fn) then
|
||
return
|
||
end
|
||
vim.api.nvim_del_user_command(cmd)
|
||
|
||
-- 还原用户最初输入的完整命令(mods/range/cmd/bang/args)
|
||
local parts = {}
|
||
if cmd_opts.mods and cmd_opts.mods ~= "" then
|
||
table.insert(parts, cmd_opts.mods)
|
||
end
|
||
if cmd_opts.range == 2 then
|
||
table.insert(parts, cmd_opts.line1 .. "," .. cmd_opts.line2)
|
||
elseif cmd_opts.range == 1 then
|
||
table.insert(parts, cmd_opts.line1)
|
||
end
|
||
table.insert(parts, cmd)
|
||
if cmd_opts.bang then
|
||
table.insert(parts, "!")
|
||
end
|
||
if cmd_opts.args and cmd_opts.args ~= "" then
|
||
table.insert(parts, " " .. cmd_opts.args)
|
||
end
|
||
|
||
local full = table.concat(parts, "")
|
||
local ok, err = pcall(vim.cmd, full)
|
||
if not ok then
|
||
vim.notify("[lazy] 执行 " .. full .. " 失败: " .. tostring(err), vim.log.levels.ERROR)
|
||
end
|
||
end, {
|
||
bang = opts.bang,
|
||
nargs = opts.nargs,
|
||
range = opts.range,
|
||
desc = opts.desc,
|
||
})
|
||
end
|
||
|
||
return M
|