refactor(git): 替换 vim-fugitive 为 neogit 工具栈

移除 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() 加载风格
This commit is contained in:
xfy 2026-06-16 09:33:14 +08:00
parent de477f3476
commit 2afb5315ce
11 changed files with 211 additions and 296 deletions

View File

@ -23,7 +23,7 @@ lua/plugins/
lsp.lua -- LSP config (nvim-lspconfig + mason), conform.nvim formatter
treesitter.lua -- Treesitter setup: deferred parser install, per-buffer attach
pick.lua -- mini.pick wrappers: buffer picker, filetype picker
git.lua -- Custom git utilities: hunk preview, blame line, fugitive keymaps
git.lua -- Git toolstack: gitsigns (buffer), neogit (repo), codediff (file)
colors/ -- Catppuccin colorscheme variants (frappe, latte, macchiato, mocha)
nvim-pack-lock.json -- Lock file for vim.pack managed plugins
```
@ -44,10 +44,10 @@ Plugins are loaded lazily via the custom framework in `lua/lazy.lua`:
Key lazy-loading points in `pack.lua`:
- `mini.completion` / `mini.snippets``InsertEnter`
- `mini.diff` / `mini.surround``BufReadPost`
- `gitsigns` / `mini.surround``BufReadPost`
- `treesitter` / `lsp``VimEnter`
- `mini.pick` / `mini.extra` — key trigger (`<leader>ff`, etc.)
- `vim-fugitive` — key trigger (`<leader>gg`)
- `neogit` / `codediff` — key trigger (`<leader>gg`, `<leader>gd`)
- `conform.nvim``BufWritePre`
## LSP and Formatting
@ -85,12 +85,14 @@ Common bindings defined across files:
- `_` — open at project root (git root)
**Git:**
- `<leader>gg` — fugitive (fullscreen new tab)
- `<leader>gd` — git diff vertical split
- `<leader>ghp` — preview current hunk
- `<leader>ghb` — blame current line
- `<leader>gB` — blame entire file
- `<leader>gD` — file git history
- `<leader>gg` — neogit status (new tab)
- `<leader>gd` — codediff git status
- `<leader>gD` — codediff file history
- `<leader>ghp` — preview hunk (gitsigns)
- `<leader>ghb` — blame current line (gitsigns)
- `<leader>ghB` — blame entire file (gitsigns)
- `<leader>ghs` — stage hunk (gitsigns)
- `<leader>ghr` — reset hunk (gitsigns)
- `<leader>sr` — search and replace (grug-far)
**LSP & diagnostics:**
@ -154,6 +156,6 @@ nvim --startuptime /tmp/startup.log +q
2. **Custom lazy-loading in `lua/lazy.lua`**. Do not confuse with the lazy.nvim plugin manager — this is a ~35-line custom module. When adding new plugins that should load lazily, use `lazy.on_event()` or `lazy.on_keys()`.
3. **mini.nvim monorepo**. Most UI/functionality comes from the single `mini.nvim` package (starter, pick, extra, files, icons, notify, cmdline, completion, snippets, diff, surround). These are configured individually in `pack.lua` or on-demand.
3. **mini.nvim monorepo**. Most UI/functionality comes from the single `mini.nvim` package (starter, pick, extra, files, icons, notify, cmdline, completion, snippets, surround). These are configured individually in `pack.lua` or on-demand.
4. **Colorscheme**. The active colorscheme is `catppuccin-mocha`, defined in `colors/catppuccin-mocha.lua`. The `moonflyTransparent` variable is still set in `init.lua` for compatibility but the moonfly theme was removed.

View File

@ -6,7 +6,7 @@ This is a personal Neovim configuration targeting **Neovim 0.12+**. It lives at
- **Plugin manager**: Neovim 0.12+ built-in `vim.pack` (not lazy.nvim / packer). Plugins are declared in `lua/pack.lua` via `vim.pack.add({ urls }, { load = false })` and tracked in `nvim-pack-lock.json`.
- **Custom lazy-loading**: `lua/lazy.lua` is a ~35-line custom framework (unrelated to lazy.nvim). It provides `load()`, `on_event()`, `on_keys()`, `on_cmd()` and tracks loaded modules in `M._loaded`.
- **Mini.nvim monorepo**: Most UI/functionality comes from the single `mini.nvim` package. Its submodules (starter, pick, extra, files, icons, notify, cmdline, completion, snippets, diff, surround, ai, cursorword, pairs) are configured individually in `lua/pack.lua` or on-demand.
- **Mini.nvim monorepo**: Most UI/functionality comes from the single `mini.nvim` package. Its submodules (starter, pick, extra, files, icons, notify, cmdline, completion, snippets, surround, ai, cursorword, pairs) are configured individually in `lua/pack.lua` or on-demand.
## File Loading Order
@ -54,9 +54,9 @@ When adding new plugins that should load lazily, use the custom framework in `lu
|---------------|--------------------------------------|
| `VimEnter` | treesitter, lsp, icons |
| `InsertEnter` | completion, snippets, pairs |
| `BufReadPost` | diff, surround, ai, cursorword |
| `BufReadPost` | gitsigns, surround, ai, cursorword |
| `BufWritePre` | conform (format-on-save) |
| Key press | pick, files, fugitive, grugfar |
| Key press | pick, files, neogit, codediff, grugfar |
| Command | ex-colors (`:ExColors`) |
## LSP & Formatting

27
MAPS.md
View File

@ -25,15 +25,24 @@
## Git
| 键位 | 动作 |
|----------------|--------------------------|
| `<leader>gg` | Fugitive全屏新标签页 |
| `<leader>gd` | Git diff 垂直分割 |
| `<leader>ghp` | 预览当前 hunk |
| `<leader>ghb` | Blame 当前行 |
| `<leader>gB` | Blame 整个文件 |
| `<leader>gD` | 查看文件 Git 历史 |
| `<leader>sr` | 搜索并替换grug-far |
| 键位 | 动作 |
|----------------|-----------------------------------|
| `<leader>gg` | Neogit status新标签页 |
| `<leader>gd` | CodeDiff 工作区 diff |
| `<leader>gD` | CodeDiff 文件历史 |
| `<leader>ghp` | 预览当前 hunkgitsigns |
| `<leader>ghb` | Blame 当前行gitsigns |
| `<leader>ghB` | Blame 整个文件gitsigns |
| `<leader>ghs` | Stage hunkgitsigns |
| `<leader>ghr` | Reset hunkgitsigns |
| `<leader>ghS` | Stage 整个 buffergitsigns |
| `<leader>ghR` | Reset 整个 buffergitsigns |
| `<leader>ghu` | 撤销 stage hunkgitsigns |
| `<leader>ghd` | Diff thisvs index |
| `<leader>ghD` | Diff this ~vs HEAD |
| `]h` / `[h` | 下一个 / 上一个 hunk |
| `]H` / `[H` | 最后 / 第一个 hunk |
| `<leader>sr` | 搜索并替换grug-far |
## LSP 与诊断

View File

@ -13,7 +13,9 @@
| **nvim-lspconfig** | [neovim/nvim-lspconfig](https://github.com/neovim/nvim-lspconfig) | LSP 客户端预设配置 |
| **mason.nvim** | [mason-org/mason.nvim](https://github.com/mason-org/mason.nvim) | LSP/DAP/格式化工具安装管理 |
| **conform.nvim** | [stevearc/conform.nvim](https://github.com/stevearc/conform.nvim) | 代码格式化(保存时自动格式化) |
| **vim-fugitive** | [tpope/vim-fugitive](https://github.com/tpope/vim-fugitive) | Git 集成 |
| **gitsigns.nvim** | [lewis6991/gitsigns.nvim](https://github.com/lewis6991/gitsigns.nvim) | Git inline gutter + hunk 操作buffer 级) |
| **neogit** | [NeogitOrg/neogit](https://github.com/NeogitOrg/neogit) | Git status 客户端(仓库级,依赖 plenary |
| **codediff.nvim** | [esmuellert/codediff.nvim](https://github.com/esmuellert/codediff.nvim) | side-by-side diff 可视化(文件级) |
| **grug-far.nvim** | [MagicDuck/grug-far.nvim](https://github.com/MagicDuck/grug-far.nvim) | 搜索与替换 |
| **friendly-snippets** | [rafamadriz/friendly-snippets](https://github.com/rafamadriz/friendly-snippets) | 社区代码片段集合 |
@ -33,5 +35,4 @@
| **mini.extra** | pick 扩展keymaps、oldfiles 等) | 按键触发 |
| **mini.completion** | 自动补全引擎LSP + Buffer | InsertEnter 懒加载 |
| **mini.snippets** | 代码片段引擎 | InsertEnter 懒加载 |
| **mini.diff** | Git diff 标记signcolumn | BufReadPost 懒加载 |
| **mini.surround** | 环绕文本操作(括号、引号等) | BufReadPost 懒加载 |

View File

@ -8,7 +8,7 @@
- **内置插件管理器**`vim.pack`Neovim 0.12+),无需 lazy.nvim / packer
- **自定义懒加载框架**`lua/lazy.lua`(约 35 行),通过 `on_event` / `on_keys` / `load` 延迟加载重型模块
- **mini.nvim 单体插件集** — starter、pick、extra、files、icons、notify、cmdline、completion、snippets、diff、surround、ai、cursorword、pairs
- **mini.nvim 单体插件集** — starter、pick、extra、files、icons、notify、cmdline、completion、snippets、surround、ai、cursorword、pairs
- **LSP + 代码格式化** — nvim-lspconfig + mason + conform.nvim保存时自动格式化支持全局/Buffer 级别开关
- **快速启动** — 禁用约 20 个内置插件,启用 Neovim 0.12+ 内置 UI 增强 (`vim._core.ui2`)
- **启动仪表盘** — ASCII Logo + 实时模块加载统计 + 启动耗时
@ -16,15 +16,15 @@
## 懒加载策略
| 触发条件 | 插件 |
| ------------- | ------------------------------ |
| `VimEnter` | treesitter、lsp、icons |
| `InsertEnter` | completion、snippets、pairs |
| `BufReadPost` | diff、surround、ai、cursorword |
| `BufWritePre` | conform |
| 按键触发 | pick、files、fugitive、grugfar |
| 首次按 `:` | cmdline |
| 命令触发 | ex-colors (`:ExColors`) |
| 触发条件 | 插件 |
| ------------- | ----------------------------------- |
| `VimEnter` | treesitter、lsp、icons |
| `InsertEnter` | completion、snippets、pairs |
| `BufReadPost` | gitsigns、surround、ai、cursorword |
| `BufWritePre` | conform |
| 按键触发 | pick、files、neogit、codediff、grugfar |
| 首次按 `:` | cmdline |
| 命令触发 | ex-colors (`:ExColors`) |
## 键位映射

View File

@ -105,7 +105,7 @@ end
--
-- 注意:
-- 此设计使得首次按键稍慢(需要 setup后续按键与直接映射无异。
-- 适合重型插件如 mini.pick、vim-fugitive
-- 适合重型插件如 mini.pick、neogit
M.on_keys = function(name, keys, mode, fn, action, opts)
mode = mode or "n"
opts = opts or {}

View File

@ -12,20 +12,22 @@
--
-- 插件列表:
-- mini.nvim - 单体插件集starter、pick、extra、files、icons、
-- notify、cmdline、completion、snippets、diff、surround
-- notify、cmdline、completion、snippets、surround
-- friendly-snippets - 社区代码片段集合
-- nvim-treesitter - 语法树解析与高亮
-- nvim-lspconfig - LSP 客户端配置
-- mason.nvim - LSP/DAP/格式化工具安装管理器
-- conform.nvim - 代码格式化(保存时自动格式化)
-- vim-fugitive - Git 集成
-- 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 → diff, surround, ai, cursorword
-- BufReadPost → gitsigns, surround, ai, cursorword
-- VimEnter → treesitter, lsp, icons
-- 按键触发 → pick, fugitive, files, grugfar
-- 按键触发 → pick, neogit, codediff, files, grugfar
-- BufWritePre → conform
-- 命令触发 → ex-colors
-- =============================================================================
@ -45,7 +47,10 @@ vim.pack.add({
"https://github.com/neovim/nvim-lspconfig", -- LSP 配置
"https://github.com/mason-org/mason.nvim", -- 工具安装器
"https://github.com/stevearc/conform.nvim", -- 格式化
"https://github.com/tpope/vim-fugitive", -- Git 集成
"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 })
@ -149,25 +154,6 @@ lazy.on_event("snippets", "InsertEnter", "*", function()
MiniSnippets.start_lsp_server({ match = false })
end)
-- ---------------------------------------------------------------------------
-- mini.diff — Git diff 标记BufReadPost 懒加载)
-- ---------------------------------------------------------------------------
-- 在 signcolumn 中显示当前 buffer 相对于 git HEAD 的变更标记。
lazy.on_event("diff", "BufReadPost", "*", function()
require("mini.diff").setup({
-- 使用 git 作为 diff 源index = false 表示对比工作区 vs HEAD不含暂存区
source = require("mini.diff").gen_source.git({ index = false }),
view = {
style = "sign",
signs = { add = "", change = "", delete = "" },
},
mappings = {
apply = "gs",
textobject = "",
},
})
end)
-- ---------------------------------------------------------------------------
-- mini.surround — 环绕文本操作BufReadPost 懒加载)
-- ---------------------------------------------------------------------------

View File

@ -1,257 +1,161 @@
-- =============================================================================
-- Git 工具封装 (lua/plugins/git.lua)
-- =============================================================================
-- 本模块提供基于 mini.diff 和原生 git 命令的 Git 相关功能。
-- 本模块提供三层 Git 工具栈,职责无重叠(对齐 nvchad 分支设计):
--
-- 功能列表:
-- 1. Hunk Preview<leader>ghp— 预览当前光标处 git diff hunk
-- 2. Blame Line<leader>ghb— 查看当前行的 git blame 信息
-- 3. Blame Buffer<leader>gB— 整文件 blamevia fugitive
-- 4. File History<leader>gD— 查看当前文件的 git log
-- 5. Fugitive 全屏(<leader>gg— 在新标签页打开 fugitive
-- 6. Git diff 分割(<leader>gd— 垂直分割查看 diff
-- 1. buffer 级(实时)— gitsigns.nvim
-- signcolumn gutter 标记 + hunk stage/reset/preview/blame + diffthis
-- 键位ghs/ghr/ghp/ghb/ghB/ghd/ghD + ]h/[h hunk 导航
--
-- 2. 仓库级(交互式)— neogit
-- Magit 风格 status 界面commit/push/pull/log
-- 键位:<leader>gg
--
-- 3. 文件级(可视化)— codediff.nvim
-- VSCode 风格 side-by-side diff + 文件历史
-- 键位:<leader>gd / <leader>gD
--
-- 依赖:
-- - mini.diff已在 pack.lua 中通过 BufReadPost 懒加载)
-- - vim-fugitive本文件通过 lazy.on_keys 按键触发懒加载)
-- - gitsigns.nvim本文件通过 BufReadPost 懒加载)
-- - neogit依赖 plenary.nvim按键触发懒加载
-- - codediff.nvim按键触发懒加载
-- =============================================================================
local lazy = require("lazy")
-- ---------------------------------------------------------------------------
-- 辅助函数:获取光标所在行的 hunk
-- gitsigns.nvim — buffer 级 Git 集成BufReadPost 懒加载)
-- ---------------------------------------------------------------------------
-- 遍历当前 buffer 的所有 hunks找到包含光标所在行的那个。
--
-- 返回值:
-- hunk - hunk 对象 { type, buf_start, buf_count, ref_start, ref_count }
-- ref_text - 参考文本HEAD 版本的内容)
-- nil - 光标不在任何 hunk 上
local function get_cursor_hunk()
local buf = vim.api.nvim_get_current_buf()
-- 从 mini.diff 获取当前 buffer 的 diff 数据
local data = require("mini.diff").get_buf_data(buf)
if not data or not data.hunks or #data.hunks == 0 then
return nil
end
-- 在 signcolumn 中显示 add/change/delete 标记,并提供 hunk 级操作。
-- on_attach 回调中注册 buffer-local 键位映射,仅对已 attach 的 buffer 生效。
local function load_gitsigns()
vim.cmd.packadd("gitsigns.nvim")
require("gitsigns").setup({
signs = {
add = { text = "" },
change = { text = "" },
delete = { text = "" },
topdelete = { text = "" },
changedelete = { text = "~" },
untracked = { text = "" },
},
signcolumn = true,
on_attach = function(bufnr)
local gs = require("gitsigns")
local cursor_line = vim.api.nvim_win_get_cursor(0)[1]
local function map(mode, l, r, desc)
vim.keymap.set(mode, l, r, { buffer = bufnr, silent = true, desc = desc })
end
for _, h in ipairs(data.hunks) do
-- hunk 在 buffer 中的起始行1-based
local start_line = math.max(h.buf_start, 1)
-- hunk 在 buffer 中的结束行
local end_line = h.buf_start + h.buf_count - 1
-- 空删除0 行)时特殊处理
if h.buf_count == 0 then
end_line = start_line
end
-- hunk 导航diff 模式下降级为原生 ]c/[c
map("n", "]h", function()
if vim.wo.diff then
vim.cmd.normal({ "]c", bang = true })
else
gs.nav_hunk("next")
end
end, "下一个 hunk")
map("n", "[h", function()
if vim.wo.diff then
vim.cmd.normal({ "[c", bang = true })
else
gs.nav_hunk("prev")
end
end, "上一个 hunk")
map("n", "]H", function()
gs.nav_hunk("last")
end, "最后一个 hunk")
map("n", "[H", function()
gs.nav_hunk("first")
end, "第一个 hunk")
-- 检查光标是否在此 hunk 范围内
if cursor_line >= start_line and cursor_line <= end_line then
return h, data.ref_text
end
end
return nil
end
-- ---------------------------------------------------------------------------
-- Hunk Preview — 浮动窗口预览当前 hunk
-- ---------------------------------------------------------------------------
-- 创建一个居中的浮动窗口,显示光标所在 hunk 的详细 diff 信息。
-- 支持三种 hunk 类型:
-- add — 显示新增的行
-- delete — 显示被删除的行(从参考文本中恢复)
-- change — 并排显示修改前后的内容
local function preview_hunk()
local hunk, ref_text = get_cursor_hunk()
if not hunk then
vim.notify("光标不在变更区域", vim.log.levels.WARN)
return
end
local lines = {}
table.insert(lines, "Hunk 类型: " .. hunk.type)
table.insert(lines, string.format("Buffer 行: %d-%d", hunk.buf_start, hunk.buf_start + hunk.buf_count - 1))
table.insert(lines, string.format("参考行: %d-%d", hunk.ref_start, hunk.ref_start + hunk.ref_count - 1))
table.insert(lines, "---")
local buf = vim.api.nvim_get_current_buf()
local ref_lines = vim.split(ref_text or "", "\n")
if hunk.type == "delete" then
-- 删除型 hunk显示被删除的内容来自参考文本
table.insert(lines, "被删除的行(来自参考版本):")
for i = hunk.ref_start, hunk.ref_start + hunk.ref_count - 1 do
table.insert(lines, "- " .. (ref_lines[i] or ""))
end
elseif hunk.type == "add" then
-- 新增型 hunk显示 buffer 中新增的内容
table.insert(lines, "新增的行:")
for i = hunk.buf_start, hunk.buf_start + hunk.buf_count - 1 do
table.insert(lines, "+ " .. (vim.api.nvim_buf_get_lines(buf, i - 1, i, false)[1] or ""))
end
else
-- 修改型 hunk显示修改前后的对比
table.insert(lines, "修改前(参考版本):")
for i = hunk.ref_start, hunk.ref_start + hunk.ref_count - 1 do
table.insert(lines, "- " .. (ref_lines[i] or ""))
end
table.insert(lines, "修改后(当前版本):")
for i = hunk.buf_start, hunk.buf_start + hunk.buf_count - 1 do
table.insert(lines, "+ " .. (vim.api.nvim_buf_get_lines(buf, i - 1, i, false)[1] or ""))
end
end
-- 计算浮动窗口尺寸
local width = math.min(80, vim.o.columns - 4)
local height = math.min(#lines + 2, vim.o.lines - 4)
-- 创建预览 buffer
local preview_buf = vim.api.nvim_create_buf(false, true) -- 无文件、可编辑
vim.api.nvim_buf_set_lines(preview_buf, 0, -1, false, lines)
vim.api.nvim_set_option_value("modifiable", false, { buf = preview_buf })
vim.api.nvim_set_option_value("filetype", "diff", { buf = preview_buf }) -- diff 语法高亮
-- 打开浮动窗口
local win = vim.api.nvim_open_win(preview_buf, true, {
relative = "editor",
row = math.floor((vim.o.lines - height) / 2),
col = math.floor((vim.o.columns - width) / 2),
width = width,
height = height,
style = "minimal",
border = "rounded",
title = " Hunk Preview ",
title_pos = "center",
-- hunk 操作Normal + Visual
-- stylua: ignore start
map({ "n", "x" }, "<leader>ghs", ":Gitsigns stage_hunk<CR>", "Stage Hunk")
map({ "n", "x" }, "<leader>ghr", ":Gitsigns reset_hunk<CR>", "Reset Hunk")
map("n", "<leader>ghS", gs.stage_buffer, "Stage Buffer")
map("n", "<leader>ghu", gs.undo_stage_hunk, "Undo Stage Hunk")
map("n", "<leader>ghR", gs.reset_buffer, "Reset Buffer")
map("n", "<leader>ghp", gs.preview_hunk, "Preview Hunk")
map("n", "<leader>ghb", function()
gs.blame_line({ full = true })
end, "Blame 当前行")
map("n", "<leader>ghB", gs.blame, "Blame 整个文件")
map("n", "<leader>ghd", gs.diffthis, "Diff This")
map("n", "<leader>ghD", function()
gs.diffthis("~")
end, "Diff This ~")
map({ "o", "x" }, "ih", ":<C-U>Gitsigns select_hunk<CR>", "Gitsigns Select Hunk")
-- stylua: ignore end
end,
})
-- q / Esc 关闭窗口
vim.keymap.set("n", "q", function()
vim.api.nvim_win_close(win, true)
end, { buffer = preview_buf })
vim.keymap.set("n", "<Esc>", function()
vim.api.nvim_win_close(win, true)
end, { buffer = preview_buf })
end
lazy.on_event("gitsigns", "BufReadPost", "*", load_gitsigns)
-- ---------------------------------------------------------------------------
-- Blame Line — 查看当前行的 Git blame 信息
-- neogit — 仓库级 Git 客户端(按键触发懒加载)
-- ---------------------------------------------------------------------------
-- 执行 git blame --porcelain 获取当前行的详细提交信息,
-- 以通知消息的形式展示提交哈希、作者、时间和提交摘要。
--
-- --porcelain 格式是机器可读的 blame 输出,包含以下字段:
-- <hash> <orig-line> <final-line> [<num-lines>]
-- author <name>
-- author-mail <email>
-- author-time <timestamp>
-- author-tz <timezone>
-- summary <commit-message>
-- ...
local function blame_line()
local file = vim.api.nvim_buf_get_name(0)
if file == "" then
vim.notify("当前 buffer 无文件名", vim.log.levels.WARN)
return
end
local line = vim.api.nvim_win_get_cursor(0)[1]
-- -L 限制 blame 范围为单行,提升性能
local cmd = { "git", "blame", "-L", line .. "," .. line, "--porcelain", file }
local output = vim.fn.system(cmd)
if vim.v.shell_error ~= 0 then
vim.notify("git blame 执行失败", vim.log.levels.ERROR)
return
end
-- 解析 --porcelain 输出
local hash = output:match("^(%x+)%s") or "?"
local author = output:match("author ([^\n]+)") or "?"
local email = output:match("author%-mail ([^\n]+)") or "?"
local time = output:match("author%-time (%d+)")
local summary = output:match("summary ([^\n]+)") or "?"
local time_str = time and os.date("%Y-%m-%d %H:%M", tonumber(time)) or "?"
vim.notify(
string.format("%s | %s %s | %s\n%s", hash:sub(1, 8), author, email, time_str, summary),
vim.log.levels.INFO
)
-- Magit 风格的交互式 status 界面,集成 commit/push/pull/log/rebase 等。
-- 依赖 plenary.nvim加载 neogit 前需确保 plenary 已在 runtimepath。
local function load_neogit()
vim.cmd.packadd("plenary.nvim")
vim.cmd.packadd("neogit")
require("neogit").setup({})
end
-- <leader>gg — 打开 Neogit status新标签页
lazy.on_keys("neogit", "<leader>gg", "n", load_neogit, function()
require("neogit").open({ kind = "tab" })
end, { desc = "Neogit status" })
-- ---------------------------------------------------------------------------
-- vim-fugitive 懒加载触发器
-- codediff.nvim — 文件级 diff 可视化(按键触发懒加载)
-- ---------------------------------------------------------------------------
local function load_fugitive()
vim.cmd.packadd("vim-fugitive")
-- VSCode 风格 side-by-side diff支持行级 + 字符级双层高亮。
-- 提供工作区 diff:CodeDiff和文件历史:CodeDiff history两种视图。
local function load_codediff()
vim.cmd.packadd("codediff.nvim")
require("codediff").setup({
diff = {
layout = "side-by-side",
disable_inlay_hints = true,
jump_to_first_change = true,
cycle_next_hunk = true,
cycle_next_file = true,
},
explorer = {
width = 35,
},
keymaps = {
view = {
quit = "q",
next_hunk = "]c",
prev_hunk = "[c",
next_file = "]f",
prev_file = "[f",
diff_get = "do",
diff_put = "dp",
open_in_prev_tab = "gf",
toggle_stage = "<leader>cs",
stage_hunk = "<leader>hs",
unstage_hunk = "<leader>hu",
discard_hunk = "<leader>hr",
hunk_textobject = "ih",
show_help = "g?",
align_move = "gm",
toggle_layout = "t",
},
},
})
end
-- ---------------------------------------------------------------------------
-- 键位映射
-- ---------------------------------------------------------------------------
-- <leader>gd — CodeDiff 工作区 diff 视图
lazy.on_keys("codediff", "<leader>gd", "n", load_codediff, function()
vim.cmd("CodeDiff")
end, { desc = "CodeDiff git status" })
-- <leader>ghp — 预览当前 hunk
vim.keymap.set("n", "<leader>ghp", preview_hunk, { desc = "预览 hunk" })
-- <leader>ghb — 查看当前行 blame
vim.keymap.set("n", "<leader>ghb", blame_line, { desc = "Blame 当前行" })
-- <leader>ghr — 重置当前 hunk恢复为 HEAD 版本)
vim.keymap.set("n", "<leader>ghr", function()
local hunk, ref_text = get_cursor_hunk()
if not hunk then
vim.notify("光标不在变更区域", vim.log.levels.WARN)
return
end
local buf = vim.api.nvim_get_current_buf()
local ref_lines = vim.split(ref_text or "", "\n")
if hunk.type == "add" then
-- 新增型 hunk删除这些行
vim.api.nvim_buf_set_lines(buf, hunk.buf_start - 1, hunk.buf_start + hunk.buf_count - 1, false, {})
elseif hunk.type == "delete" then
-- 删除型 hunk插入被删除的内容
local lines_to_insert = {}
for i = hunk.ref_start, hunk.ref_start + hunk.ref_count - 1 do
table.insert(lines_to_insert, ref_lines[i] or "")
end
vim.api.nvim_buf_set_lines(buf, hunk.buf_start - 1, hunk.buf_start - 1, false, lines_to_insert)
else
-- 修改型 hunk用参考版本替换
local lines_to_replace = {}
for i = hunk.ref_start, hunk.ref_start + hunk.ref_count - 1 do
table.insert(lines_to_replace, ref_lines[i] or "")
end
vim.api.nvim_buf_set_lines(buf, hunk.buf_start - 1, hunk.buf_start + hunk.buf_count - 1, false, lines_to_replace)
end
vim.notify("已重置 hunk", vim.log.levels.INFO)
end, { desc = "重置 hunk" })
-- <leader>gg — 在新标签页中打开 Fugitive 全屏
lazy.on_keys("fugitive", "<leader>gg", "n", load_fugitive, function()
vim.cmd("Git")
end, { desc = "Fugitive 全屏新标签" })
-- <leader>gd — Git diff 垂直分割
lazy.on_keys("fugitive", "<leader>gd", "n", load_fugitive, function()
vim.cmd("Gvdiffsplit")
end, { desc = "Git diff 分割" })
-- <leader>gB — 整文件 blame使用 fugitive 的 :Git blame
lazy.on_keys("fugitive", "<leader>gB", "n", load_fugitive, function()
vim.cmd("Git blame")
end, { desc = "Blame 整个文件" })
-- <leader>gD — 查看当前文件的 git 历史
lazy.on_keys("fugitive", "<leader>gD", "n", load_fugitive, function()
vim.cmd("Git log -p -- %")
end, { desc = "查看文件 Git 历史" })
-- <leader>gl — 查看当前文件的 Gclog
lazy.on_keys("fugitive", "<leader>gl", "n", load_fugitive, function()
vim.cmd("GcLog")
end, { desc = "查看文件 GcLog" })
-- <leader>gD — CodeDiff 当前文件历史(共享 codediff 懒加载setup 仅首次执行)
lazy.on_keys("codediff", "<leader>gD", "n", load_codediff, function()
vim.cmd("CodeDiff history")
end, { desc = "CodeDiff 文件历史" })

View File

@ -118,7 +118,6 @@ local all_modules = {
"icons",
"pick",
"files",
"diff",
"surround",
"completion",
"snippets",
@ -127,7 +126,9 @@ local all_modules = {
"conform",
"lspconfig",
"mason",
"fugitive",
"gitsigns",
"neogit",
"codediff",
"grugfar",
"pairs",
"ai",

View File

@ -15,7 +15,7 @@
-- :PackAdd — 添加插件
-- ---------------------------------------------------------------------------
-- 用法::PackAdd user/repo1 user/repo2 ...
-- 示例::PackAdd stevearc/conform.nvim tpope/vim-fugitive
-- 示例::PackAdd stevearc/conform.nvim lewis6991/gitsigns.nvim
--
-- 原理:
-- 将命令行参数opts.fargs已按空格分割的字符串数组
@ -31,7 +31,7 @@ end, { nargs = "+", desc = "添加插件 (:PackAdd user/repo1 user/repo2)" })
-- :PackDel — 删除插件
-- ---------------------------------------------------------------------------
-- 用法::PackDel plugin1 plugin2 ...
-- 示例::PackDel conform.nvim vim-fugitive
-- 示例::PackDel conform.nvim gitsigns.nvim
--
-- 注意:
-- 参数是插件目录名(即 repo 名),不是完整 URL。

View File

@ -1,5 +1,9 @@
{
"plugins": {
"codediff.nvim": {
"rev": "7608f3b436ce1f84a4888f75e53079caa981a2e9",
"src": "https://github.com/esmuellert/codediff.nvim"
},
"conform.nvim": {
"rev": "619363c30309d29ffa631e67c8183f2a72caa373",
"src": "https://github.com/stevearc/conform.nvim"
@ -8,6 +12,10 @@
"rev": "6cd7280adead7f586db6fccbd15d2cac7e2188b9",
"src": "https://github.com/rafamadriz/friendly-snippets"
},
"gitsigns.nvim": {
"rev": "25050e4ed39e628282831d4cbecb1850454ce915",
"src": "https://github.com/lewis6991/gitsigns.nvim"
},
"grug-far.nvim": {
"rev": "5506c2f59dc9ab2ed6c233585412b24d31d51521",
"src": "https://github.com/MagicDuck/grug-far.nvim"
@ -20,6 +28,10 @@
"rev": "44657837c7338e52727facc85c1d95bec1f6bd7c",
"src": "https://github.com/nvim-mini/mini.nvim"
},
"neogit": {
"rev": "5d1b65d6215928e941e1a6a4e76e02fd45ada31f",
"src": "https://github.com/NeogitOrg/neogit"
},
"nvim-lspconfig": {
"rev": "6f76a3eeadc2ee235d74cd7d5319e95a261084af",
"src": "https://github.com/neovim/nvim-lspconfig"
@ -28,9 +40,9 @@
"rev": "4916d6592ede8c07973490d9322f187e07dfefac",
"src": "https://github.com/nvim-treesitter/nvim-treesitter"
},
"vim-fugitive": {
"rev": "3b753cf8c6a4dcde6edee8827d464ba9b8c4a6f0",
"src": "https://github.com/tpope/vim-fugitive"
"plenary.nvim": {
"rev": "74b06c6c75e4eeb3108ec01852001636d85a932b",
"src": "https://github.com/nvim-lua/plenary.nvim"
}
}
}