-- ============================================================================= -- 插件管理与懒加载配置 (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 textobject(BufReadPost 懒加载) 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) -- ============================================================================= -- 按下前缀键(/g/z//[/])后弹出浮窗,列出后续可用键及描述。 -- 类 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 = "" }, { mode = { "n", "x" }, keys = "g" }, { mode = { "n", "x" }, keys = "z" }, { mode = "n", keys = "" }, { 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(), -- 分组描述(与 keymaps.lua / plugins/*.lua 中的映射对齐) { mode = "n", keys = "f", desc = "+文件" }, { mode = "n", keys = "g", desc = "+Git" }, { mode = "n", keys = "b", desc = "+Buffer" }, { mode = "n", keys = "c", desc = "+代码" }, { mode = "n", keys = "d", desc = "+诊断" }, { mode = "n", keys = "s", desc = "+搜索" }, { mode = "n", keys = "t", desc = "+标签/终端" }, { mode = "n", keys = "u", desc = "+用户" }, { mode = "n", keys = "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", "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" })