nvim/lua/pack.lua
xfy 46e7269824 feat(statusline): 文件名段统一相对路径,不再显示绝对路径
覆盖 section_filename:默认宽窗口走 %F(绝对路径),改为宽窗口 %f
(相对路径)/ 窄窗口降级 %t(仅文件名)。
2026-06-22 17:49:52 +08:00

344 lines
14 KiB
Lua
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- =============================================================================
-- 插件管理与懒加载配置 (lua/pack.lua)
-- =============================================================================
-- 本文件使用 Neovim 0.12+ 内置的 vim.pack 管理插件,
-- 并结合自定义懒加载框架 (lua/lazy.lua) 延迟初始化重型插件。
--
-- 职责边界:
-- - 声明插件安装vim.pack.add
-- - 直接 setup 通用/轻量插件UI、编辑增强、补全、独立工具
-- - 功能域插件git/lsp/pick/files/treesitter/starter的配置与键位
-- 移至 lua/plugins/*.lua由本文件 require 调度
--
-- 拆分规则:
-- - 配置简单(纯 setup 或少量选项)→ 留在本文件
-- - 配置复杂(含多键位、自定义函数、交互逻辑)→ 移至 plugins/
--
-- 插件列表:
-- mini.nvim - 单体插件集starter、pick、extra、files、icons、
-- notify、cmdline、completion、snippets、surround、
-- clue、statusline
-- friendly-snippets - 社区代码片段集合
-- nvim-treesitter - 语法树解析与高亮
-- nvim-lspconfig - LSP 客户端配置
-- mason.nvim - LSP/DAP/格式化工具安装管理器
-- conform.nvim - 代码格式化(保存时自动格式化)
-- gitsigns.nvim - Git inline gutter + hunk 操作buffer 级)
-- neogit - Git status 客户端(仓库级,依赖 plenary
-- codediff.nvim - side-by-side diff 可视化(文件级)
-- grug-far.nvim - 搜索与替换
--
-- 懒加载策略:
-- InsertEnter → completion, snippets, pairs
-- BufReadPost → gitsigns, surround, ai, cursorword
-- VimEnter → treesitter, lsp, icons
-- 按键触发 → pick, neogit, codediff, files, grugfar
-- BufWritePre → conform
-- 命令触发 → ex-colors
-- =============================================================================
local lazy = require("lazy")
-- ---------------------------------------------------------------------------
-- 插件安装声明
-- ---------------------------------------------------------------------------
-- vim.pack.add(urls, { load = false }) 将插件下载到 pack 目录,
-- 但不自动加载load = false。后续通过 packadd 或 require 按需加载。
-- 所有插件的状态锁定在 nvim-pack-lock.json 中。
vim.pack.add({
"https://github.com/nvim-mini/mini.nvim", -- 核心 UI/功能插件集
"https://github.com/rafamadriz/friendly-snippets", -- 代码片段库
{ src = "https://github.com/nvim-treesitter/nvim-treesitter", branch = "main" }, -- 语法树
"https://github.com/neovim/nvim-lspconfig", -- LSP 配置
"https://github.com/mason-org/mason.nvim", -- 工具安装器
"https://github.com/stevearc/conform.nvim", -- 格式化
"https://github.com/lewis6991/gitsigns.nvim", -- Git inline gutter + hunk 操作
"https://github.com/nvim-lua/plenary.nvim", -- neogit 依赖
"https://github.com/NeogitOrg/neogit", -- Git status 客户端
"https://github.com/esmuellert/codediff.nvim", -- side-by-side diff 可视化
"https://github.com/MagicDuck/grug-far.nvim", -- 搜索替换
-- "https://github.com/aileot/ex-colors.nvim", -- colorscheme 提取与优化
}, { load = false })
-- ---------------------------------------------------------------------------
-- 功能域插件配置lua/plugins/*.lua
-- ---------------------------------------------------------------------------
-- 加载各功能域插件的配置模块(含键位映射与自定义逻辑)。
-- 必须在 vim.pack.add 之后,确保插件路径已注册到 runtimepath。
require("plugins.git")
require("plugins.pick")
require("plugins.files")
require("plugins.starter")
-- =============================================================================
-- UI 层:通知、命令行、图标
-- =============================================================================
-- mini.notify — 替换默认 vim.notify提供浮动通知窗口直接初始化轻量不阻塞
-- 使用 pcall 保护首次启动(插件可能尚未下载完成)
local ok_notify, notify = pcall(require, "mini.notify")
if ok_notify then
notify.setup({
content = {
-- 简化格式:只显示消息内容
format = function(notif)
return notif.msg
end,
},
})
vim.notify = notify.make_notify()
lazy.track("notify")
end
-- mini.cmdline — 增强命令行(首次按 : 时加载)
-- 使用 expr 映射:返回 ":" 让 Vim 继续处理
vim.keymap.set("n", ":", function()
-- 首次按下 : 时删除此映射,避免后续重复触发
vim.keymap.del("n", ":")
require("mini.cmdline").setup({
autocorrect = { enable = false },
})
lazy.track("cmdline")
return ":"
end, { expr = true, noremap = true })
-- mini.icons — 文件类型图标VimEnter 后延迟加载)
-- 供 mini.pick、mini.files、mini.statusline 等使用
vim.api.nvim_create_autocmd("VimEnter", {
once = true,
callback = function()
require("mini.icons").setup()
lazy.track("icons")
-- mini.statusline — 状态栏(依赖 mini.icons故同处 VimEnter
-- 最简配置:用内置 section 组合,自适应窗口宽度。
-- Git/diff 段回退到 gitsigns.nvim已启用无需 mini.git/mini.diff。
require("mini.statusline").setup({ use_icons = true })
-- 覆盖 section_git / section_diff / section_lsp 返回空串隐藏它们:
-- - section_git/diff默认读 gitsigns buffer 变量显示分支和增删改数
-- - section_lsp默认显示 '󰰎 +',加号数量 = attach 的 LSP client 数
-- combine_groups 会自动跳过空段,不留多余空格。
require("mini.statusline").section_git = function()
return ""
end
require("mini.statusline").section_diff = function()
return ""
end
require("mini.statusline").section_lsp = function()
return ""
end
-- 覆盖 section_filename原逻辑宽窗口返回 %F绝对路径
-- 这里改为宽窗口也用 %f相对路径。窄窗口降级到 %t仅文件名
require("mini.statusline").section_filename = function(args)
local ms = require("mini.statusline")
if vim.bo.buftype == "terminal" or ms.is_truncated(args.trunc_width) then
return "%t%m%r"
end
return "%f%m%r"
end
lazy.track("statusline")
end,
})
-- =============================================================================
-- 编辑增强括号配对、textobject、光标高亮、环绕操作
-- =============================================================================
-- mini.pairs — 自动括号配对InsertEnter 懒加载)
lazy.on_event("pairs", "InsertEnter", "*", function()
require("mini.pairs").setup()
end)
-- mini.ai — 扩展 a/i textobjectBufReadPost 懒加载)
lazy.on_event("ai", "BufReadPost", "*", function()
require("mini.ai").setup()
end)
-- mini.cursorword — 自动高亮光标下单词BufReadPost 懒加载)
lazy.on_event("cursorword", "BufReadPost", "*", function()
require("mini.cursorword").setup()
end)
-- mini.surround — 环绕文本操作BufReadPost 懒加载)
lazy.on_event("surround", "BufReadPost", "*", function()
require("mini.surround").setup()
end)
-- =============================================================================
-- 补全与代码片段InsertEnter 懒加载)
-- =============================================================================
-- mini.completion — 自动补全引擎LSP + Buffer
lazy.on_event("completion", "InsertEnter", "*", function()
require("mini.completion").setup({
lsp_completion = {
auto_setup = true,
},
})
end)
-- mini.snippets — 代码片段引擎
lazy.on_event("snippets", "InsertEnter", "*", function()
local MiniSnippets = require("mini.snippets")
MiniSnippets.setup({
snippets = {
MiniSnippets.gen_loader.from_lang(),
},
})
MiniSnippets.start_lsp_server({ match = false })
end)
-- =============================================================================
-- 重型模块VimEnter 延迟加载)
-- =============================================================================
-- treesitter 和 lsp 是启动时最耗时的模块,
-- 延迟到 VimEnter 事件触发后加载,让编辑器界面先渲染出来。
lazy.on_event("treesitter", "VimEnter", "*", function()
require("plugins.treesitter").setup()
end)
lazy.on_event("lsp", "VimEnter", "*", function()
require("plugins.lsp")
end)
-- =============================================================================
-- mini.clue — 按键提示浮窗VimEnter 后 setup
-- =============================================================================
-- 按下前缀键(<Leader>/g/z/<C-w>/[/])后弹出浮窗,列出后续可用键及描述。
-- 类 which-key 但更轻量,且独立于 'timeoutlen'。
--
-- 不走 lazy.on_keys 懒加载mini.clue 需自己把前缀键注册为 buffer-local
-- 触发器,与 on_keys 的"包装映射"机制互斥;且 setup 成本极低,无懒加载收益。
--
-- 时序要点(来自官方文档):触发器必须是 buffer 中最后创建的 buffer-local
-- 映射,否则会被后续 LSP/gitsigns 等的 buffer-local 映射"压住"而失灵。
-- 这里通过 VimEnter 延迟 setup此时全局映射已全部就位
-- 并在 LspAttach 中调用 ensure_buf_triggers 兜底。
vim.api.nvim_create_autocmd("VimEnter", {
once = true,
callback = function()
local ok_clue, miniclue = pcall(require, "mini.clue")
if not ok_clue then
return
end
miniclue.setup({
triggers = {
{ mode = { "n", "x" }, keys = "<Leader>" },
{ mode = { "n", "x" }, keys = "g" },
{ mode = { "n", "x" }, keys = "z" },
{ mode = "n", keys = "<C-w>" },
{ mode = "n", keys = "[" },
{ mode = "n", keys = "]" },
},
clues = {
-- 内置前缀键描述生成器g/z/窗口/方括号跳转)
miniclue.gen_clues.g(),
miniclue.gen_clues.z(),
miniclue.gen_clues.windows(),
miniclue.gen_clues.square_brackets(),
-- <Leader> 分组描述(与 keymaps.lua / plugins/*.lua 中的映射对齐)
{ mode = "n", keys = "<Leader>f", desc = "+文件" },
{ mode = "n", keys = "<Leader>g", desc = "+Git" },
{ mode = "n", keys = "<Leader>b", desc = "+Buffer" },
{ mode = "n", keys = "<Leader>c", desc = "+代码" },
{ mode = "n", keys = "<Leader>d", desc = "+诊断" },
{ mode = "n", keys = "<Leader>s", desc = "+搜索" },
{ mode = "n", keys = "<Leader>t", desc = "+标签/终端" },
{ mode = "n", keys = "<Leader>u", desc = "+用户" },
{ mode = "n", keys = "<Leader>y", desc = "+复制" },
},
window = {
delay = 300, -- 默认 1000ms 太慢300ms 接近 which-key 体验
config = { border = "rounded" },
},
})
-- LSP attach 后重新确保触发器排在最后LSP 可能创建 buffer-local 映射)
vim.api.nvim_create_autocmd("LspAttach", {
callback = function()
pcall(miniclue.ensure_buf_triggers)
end,
})
lazy.track("clue")
end,
})
-- =============================================================================
-- 独立工具(按键/命令触发懒加载)
-- =============================================================================
-- grug-far.nvim — 搜索与替换(按键触发懒加载)
-- 提供类似 VS Code 的查找替换界面,支持正则和文件过滤
local function load_grug_far()
vim.cmd.packadd("grug-far.nvim")
require("grug-far").setup({ headerMaxWidth = 80 })
end
local function open_grug_far()
local grug = require("grug-far")
-- 根据当前文件扩展名预填充文件过滤器
local ext = vim.bo.buftype == "" and vim.fn.expand("%:e")
local filesFilter = ext and ext ~= "" and "*." .. ext or nil
local prefills = { filesFilter = filesFilter }
-- Visual 模式用当前选中文本预填充搜索框Normal 模式直接打开
if vim.fn.mode():match("^[vV\22]$") then
grug.with_visual_selection({ prefills = prefills })
else
grug.open({ transient = true, prefills = prefills })
end
end
-- Normal 和 Visual 模式共用同一个映射,通过 mode 表一次性注册
lazy.on_keys("grugfar", "<leader>sr", { "n", "x" }, load_grug_far, open_grug_far, { desc = "搜索并替换" })
-- ex-colors.nvim — colorscheme 提取与优化(命令触发懒加载)
-- 仅在执行 :ExColors 时加载,不占用启动时间。
-- 生成的文件保存在 ~/.config/nvim/colors/ex-{colors_name}.lua
lazy.on_cmd("ex-colors", "ExColors", function()
vim.cmd.packadd("ex-colors.nvim")
require("ex-colors").setup({
colors_dir = vim.fn.stdpath("config") .. "/colors",
clear_highlight = false,
reset_syntax = false,
ignore_default_colors = true,
ignore_clear = true,
omit_default = true,
relinker = require("ex-colors.presets").recommended.relinker,
required_syntaxes = { "diff", "html", "markdown" },
included_hlgroups = require("ex-colors.presets").recommended.included_hlgroups,
excluded_hlgroups = require("ex-colors.presets").recommended.excluded_hlgroups,
included_patterns = require("ex-colors.presets").recommended.included_patterns,
excluded_patterns = require("ex-colors.presets").recommended.excluded_patterns,
autocmd_patterns = {
CmdlineEnter = {
["*"] = { "^debug%u", "^health%u" },
},
},
embedded_global_options = { "background" },
embedded_global_variables = {
"terminal_color_0",
"terminal_color_1",
"terminal_color_2",
"terminal_color_3",
"terminal_color_4",
"terminal_color_5",
"terminal_color_6",
"terminal_color_7",
"terminal_color_8",
"terminal_color_9",
"terminal_color_10",
"terminal_color_11",
"terminal_color_12",
"terminal_color_13",
"terminal_color_14",
"terminal_color_15",
},
})
end, { bang = true, desc = "提取当前 colorscheme 为优化版 ex-colors" })