# nvim **Repository Path**: nathanjoy/nvim ## Basic Information - **Project Name**: nvim - **Description**: ~/.config/nvim NvChad custom config - **Primary Language**: Unknown - **License**: Unlicense - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-07-29 - **Last Updated**: 2026-08-07 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # nvim 配置 基于 **NvChad v2.5** 的个人 Neovim 配置, 目标是**对标 VSCode 的日常开发体验**。 - 主入口 `init.lua`, 通过 lazy.nvim 拉 NvChad + 自定义插件 - 自定义逻辑在 `lua/custom/`(已合并到 `lua/` 下)和 `lua/configs/`、`lua/plugins/` - 所有 `nvim xxx` 自动 `cd` 到 `xxx`, `nvim-tree` 跟随 cwd --- ## 安装 ```bash git clone ~/.config/nvim nvim # 第一次会装所有插件, 等几秒 :checkhealth ``` --- ## 环境变量 | 变量 | 用途 | |---|---| | `DPX_API_KEY` | LLM chat 走 horizon, 必备 | | `DEEPSEEK_API_KEY` | 代码补全走 DeepSeek FIM, 必备 | `fetch_key` 优先读 env, 兜底从 `~/.bashrc` 读 `export ...=...` 行。 --- ## 快捷键速查 `` 默认是**空格**。`xx` 表示 "空格 + x + x"。 ### 文件 / 工程 | 键 | 动作 | |---|---| | `ff` | telescope: 找文件 | | `fg` | telescope: 内容搜索 | | `fb` | telescope: buffers | | `fh` | telescope: help tags | | `gc` | git commits (按当前 buffer 路径找 git root) | | `gs` | git status (按当前 buffer 路径找 git root) | | `gb` | git branches (按当前 buffer 路径找 git root) | | `fy` | 复制相对路径 (相对 cwd) | | `fY` | 复制绝对路径 | | `fn` | 复制文件名 | | `;` | 冒号 (CMD 模式) | | `jk` (insert) | 退出插入模式 | ### nvim-tree 内 (buffer-local) #### 自定义 (lua/plugins/nvim-tree.lua) | 键 | 动作 | |---|---| | `s` | 当前节点目录 live grep | | `f` | 当前节点目录 find files | | `dc` | **比较 2 个文件** (VSCode Compare with... 同款): 第 1 次按记文件 A, 第 2 次按跟光标处文件 B 开 diff | #### 默认键 — 文件操作 (重命名 / 复制 / 刷新) | 键 | 动作 | |---|---| | `r` | **重命名** (vim buffer 改, `:wq` 落盘; vscode F2 等价) | | `c` | **复制文件** (标记, 配合 `p` 粘贴 = 复制到目标目录) | | `x` | 剪切 (标记, 配合 `p` = 移动文件) | | `p` | 粘贴 (落盘 `c` / `x` / `gp` 标记的内容) | | `gp` | 移动 (同 `x` + `p`, 一步到位) | | `R` | **刷新当前目录** (新增/删除文件后用, 注意: `` 是"重命名只改后缀", 别按错) | | `a` | 新建文件 / 目录 (后缀 `/` = 目录) | | `d` | 删除 (立即, 有确认) | | `D` | 移到回收站 | #### 默认键 — 打开方式 | 键 | 动作 | |---|---| | `` / `o` | 打开 (有 window picker 选窗口) | | `O` | 打开 (无 window picker, 用当前窗口) | | `` | 在垂直分屏打开 | | `` | 在水平分屏打开 | | `` | 在新 tab 打开 | | `` | 预览 (不离开当前文件) | #### 默认键 — 复制路径到剪贴板 | 键 | 动作 | |---|---| | `y` | 复制文件名 (如 `init.lua`) | | `Y` | 复制相对路径 (如 `lua/plugins/init.lua`) | | `gy` | 复制绝对路径 (如 `/home/user/.../lua/plugins/init.lua`) | #### 默认键 — 导航 | 键 | 动作 | |---|---| | `` | cd 到光标处目录 (变成 tree root) | | `-` | 回到上一层目录 (root - 1) | | `` | 关闭当前目录折叠 | | `E` | 展开所有 | | `f` | live filter (即时过滤文件名) | | `g?` | 看完整快捷键帮助 | ### 可视模式 | 键 | 动作 | |---|---| | `v` | 字符可视 | | `V` | 行可视 | | `vv` | **块可视** (等同 ``, 顺手多了) | ### 编辑器行为 | 特性 | 设置 | |---|---| | 缩进 | `vim-sleuth` 自动跟随文件 (打开 2 空格 Python → sw=2; 打开 Makefile → 自动用 tab) | | 缩进默认值 | `tabstop=4, shiftwidth=4, expandtab=false` (options.lua) | ### LSP (光标处有 LSP 时生效) | 键 | 动作 | |---|---| | `fs` | 当前文件 outline (document symbols) | | `fS` | workspace symbols (按名搜全工程) | | `fr` | LSP references (所有引用) | | `fd` | 当前 buffer diagnostics | | `fc` | LSP code actions | ### Trouble (VSCode Problems 风格) | 键 | 动作 | |---|---| | `xx` | workspace diagnostics | | `xd` | 当前 buffer diagnostics | | `xr` | LSP references 面板 | | `xL` | location list | | `xQ` | quickfix list | ### Git | 键 | 动作 | |---|---| | `gB` | gitsigns blame (弹窗) | | `gi` | git-blame.nvim 行尾常驻 toggle | | `gb` | git branches (按当前 buffer 路径找 git root) | | `gd` | gitsigns: 当前 buffer diff (vs HEAD, 浮动窗) | | `gD` | **diffview: 全 diff 面板** (vs HEAD, 左侧 working / 右侧 HEAD) | | `gH` | **diffview: 当前文件历史** (提交列表 + 每次 diff) | | `gC` | diffview: 关闭 | | `]c` / `[c` | 下一处 / 上一处 hunk | | `ph` | preview hunk | | `rh` | reset hunk | | `sh` | stage hunk | 行尾常驻 blame 默认开, 显示 `作者 时间 commit message` 截断 50 字。 #### diffview 用法 (VSCode Git tab 同款) ``` :DiffviewOpen # 当前 working vs HEAD :DiffviewOpen HEAD~2 # 跟 2 个 commit 前比 :DiffviewOpen main..feature # 两个分支比 :DiffviewOpen path/to/file.lua # 单文件 diff :DiffviewFileHistory # 当前文件提交历史 + 每次 diff :DiffviewClose # 关掉 :DiffviewRefresh # 文件改动后刷新 ``` #### 两个任意文件比较 (不依赖 git) ``` :e file1.lua :vert diffsplit file2.lua :diffthis (或者每个窗口都 :diffthis) ``` 光标在 file1 窗口 `:diffthis` 标记, 在 file2 窗口 `:diffthis` 标记, 两边立刻 diff。 退出 diff: `:diffoff` #### Diff 高亮配色 (init.lua) monokai 主题没自定义 diff 颜色, 覆盖如下 (暗底 + 高对比字): | 组 | 用途 | 配色 | |---|---|---| | `DiffAdd` | 新增行 | 暗绿底 + monokai 绿字 | | `DiffChange` | 修改行 | 暗蓝底 + monokai 青字 | | `DiffDelete` | 删除行 | 暗红底 + monokai 粉字 | | `DiffText` | 行内差异 (词级) | 暗橙底 + monokai 黄字加粗 | ### Git merge 冲突解决 执行 `git merge` / `git pull` 产生冲突后, 打开冲突文件会自动高亮: - `<<<<<<< HEAD` / `=======` / `>>>>>>> branch` 三行标记 = `ConflictMarker` (粉色加粗) - 整个冲突块 (`<<<<<<<` 到 `>>>>>>>` 区间) = `ConflictOurs` (粉底背景) | 键 | 动作 | |---|---| | `]m` | 下一个冲突标记 (`<<<<<<<` 起始行) | | `[m` | 上一个冲突标记 | | `co` | vimdiff 中取 **ours** (= `:diffg LO`) | | `ct` | vimdiff 中取 **theirs** (= `:diffg RE`) | | `cb` | vimdiff 中取 **base** (= `:diffg BA`) | `co/ct/cb` 只在 vimdiff 模式 (`git mergetool` 三窗) 里有效, 单冲突文件里按会报 "E99: Current window is not in diff mode"。 **解决单个冲突**: ``` <<<<<<< HEAD 我们的代码 ======= 对方的代码 >>>>>>> feature ``` 四种策略: 1. **保留 ours**: `co` (vimdiff) 或手动删 `<<<<<<< ... =======` 之间的 theirs 部分 2. **保留 theirs**: `ct` (vimdiff) 或手动删 `======= ... >>>>>>>` 之间的 ours 部分 3. **保留 base**: `cb` (vimdiff) 或手动用 base 版本内容替换整段 4. **保留全部 (自己改)**: 直接手动编辑, 删掉所有标记行, 留下最终版本 **批量解决 (vimdiff 三窗)**: ```bash git config --global merge.tool nvimdiff git config --global mergetool.nvimdiff.cmd \ 'nvim -d $LOCAL $MERGED $REMOTE -c "wincmd J | wincmd = | windo diffthis"' git config --global mergetool.keepBackup false ``` 然后 `git mergetool` — 左中右三个窗口分别是 LOCAL / MERGED / REMOTE。在中间窗口编辑, `:diffg L` / `:diffg R` 取左侧/右侧内容。 **标记解决完**: `:!git add %` (加当前文件) 或 `:Git add %` (装了 vim-fugitive)。 `gitsigns.nvim` 在冲突文件里也能用, `]c` / `[c` 跳 hunk, `sh` 直接 stage 当前 hunk。 ### 项目级搜索替换 两种方式, 按需选用: #### 内置方案 (无插件, 推荐先用) ``` :Telescope live_grep cwd=~/src/myproj " 1. 在指定目录搜 " 2. 结果里按 全部送进 quickfix :cfdo %s/old_string/new_string/g | update " 3. 替换并保存所有 quickfix 文件 ``` 只替换某种后缀: ``` :args ~/src/myproj/**/*.lua | argdo %s/old/new/g | update ``` #### grug-far.nvim (VSCode 同款 UI) | 键 | 动作 | |---|---| | `sr` | 打开 search & replace 面板 | 面板里: - 上方输 query (用 ripgrep 实时预览) - 下方输 replacement - `R` 切换到 replace 模式, 一键全部 / 逐个确认 - 默认 cwd 是当前 buffer 目录, 想全工程改一下 prefills 适合场景: 重构变量名 / API 路径 / 批量改字符串。 ### 终端 (toggleterm) **预设 4 个具名水平终端** (count=1..4, 跟 VSCode terminal profiles 一致),都是普通 shell,命令自己输: | 键 | 动作 | |---|---| | `tt` | **toggle** count=1 (纯 toggle, 不动其他) | | `t1` | **focus** count=1 (关其他具名, 打开 1; 同 key 再按 = 关) | | `t2` | **focus** count=2 | | `t3` | **focus** count=3 | | `t4` | **focus** count=4 | | `th` | 新建匿名水平终端 (走 `tn/p` 循环) | | `tv` | 新建匿名垂直终端 | | `tf` | 新建匿名浮动终端 | | `tg` | lazygit 浮动 (匿名, 每次新建; 需 `lazygit` 在 PATH, 已装 `~/.local/bin/lazygit`) | | `tn` / `tp` | 下一个 / 上一个终端 (匿名终端循环) | **VSCode 切换语义** (`t1`..`t4`): 同时只显示**一个**具名终端。按 `t2` 时如果 `t1` 已开,会自动关掉 `t1` 开 `t2`(跟 VSCode terminal tab 切换一致)。同 key 再按一次 = 关掉当前。 **`tt` 是 toggle 不是 focus**: 单纯 toggle count=1,不影响其他具名。如果想"关掉整个 panel",按两次当前已开的那个 key 即可(`t1+t1` 或 `t2+t2`)。 **预设 4 个全是不带 cmd 的普通 shell** (display_name 都叫 `1 shell`..`4 shell`),数字只是区分,具体跑啥用户自己定。server / build 命令跨项目不一样 (`npm run dev` vs `cargo run` vs `python main.py`),硬编码反而是坑。 **为什么用 `t1..t4` 而不是 `ts/tb/tm`**: 数字键记忆负担小,跟 VSCode 的 terminal tab index 一致,且留出字母键给未来扩展。 **注意**: 终端窗口默认在 Terminal-Insert 模式 (直接输入给 shell), 此时 `` 等键不会触发 nvim 映射。想用 `tt` 关闭终端, 先用 `jk` 或 `` 进入 Terminal-Normal 模式, 再按 `tt`。 Terminal-Normal 下按 `i` / `a` 可回到 Terminal-Insert (继续打 shell)。 ### LSP Inlay Hints (参数提示) | 键 | 动作 | |---|---| | `ih` | toggle (默认开) | 支持 ts / python / rust / go (server 自身要支持, 例如 tsserver / pyright / rust-analyzer / gopls)。 ### 调试 (nvim-dap) | 键 | 动作 | |---|---| | `db` | toggle 断点 | | `dB` | 条件断点 | | `dc` | continue | | `di` | step into | | `do` | step out | | `dn` | step over (next) | | `de` | eval 表达式 | | `dr` | REPL toggle | | `du` | DAP UI toggle (call stack / variables / breakpoints 面板) | | `dt` | terminate | | `dl` | run last | **默认没装任何 adapter**, 按需: - python: `mfussenegger/nvim-dap-python` - go: `leoluz/nvim-dap-go` - rust / c / cpp: `rcarriga/nvim-dap-codelldb` - node: `mfussenegger/nvim-dap-js` ### LLM (Kurama622/llm.nvim) | 键 | 动作 | |---|---| | `ac` | chat toggle (horizon endpoint) | | `cc` | code completion toggle (DeepSeek FIM 开关) | | `cm` | 主动触发 cmp 补全 (insert 模式, 含 llm 源) | ### Treesitter (Sticky Scroll + 语法高亮) 开启后, 光标在函数/类内部时, 顶部自动固定显示所在代码块签名(类似 VSCode Sticky Scroll / JetBrains Breadcrumbs). 见 `lua/plugins/treesitter.lua`. chat 走 `https://llmapi.horizon.auto/v1/chat/completions` (HORIZON-DeepSeek-Pro, reasoning)。 补全走 `https://api.deepseek.com/beta/completions` (deepseek-chat, FIM, 懒到按 `cc` 才 source)。 --- ## 目录结构 ``` . ├── init.lua # 入口, 加载 lazy + nvchad + 自定义 ├── lua/ │ ├── options.lua # 编辑器选项 + OSC 52 剪贴板 │ ├── autocmds.lua # argv 解析 auto-cd + nvim-tree 根同步 │ ├── mappings.lua # 自定义键 (路径复制) │ ├── chadrc.lua # NvChad UI 配置 │ ├── configs/ # 跨插件的 helper 配置 │ │ ├── conform.lua │ │ ├── lazy.lua │ │ ├── lspconfig.lua │ │ └── telescope.lua # telescope 全局键 + tree attach │ └── plugins/ # lazy.nvim spec, 每个插件一个文件 │ ├── comments.lua │ ├── dap.lua │ ├── git-blame.lua │ ├── gitsigns.lua │ ├── inlayhints.lua │ ├── init.lua │ ├── llm.lua │ ├── nvim-tree.lua │ ├── telescope.lua │ ├── toggleterm.lua │ ├── trouble.lua │ └── ui.lua ├── .gitignore # lazy-lock.json / .omc / .stylua.toml └── README.md ``` --- ## 设计原则 1. **延迟加载**: 大部分插件 `event = "BufReadPost"` 或 `cmd`, 启动零卡顿 2. **OSC 52 剪贴板**: `lua/options.lua` 里塞了 vim.ui.clipboard, 无 tmux 也可与系统剪贴板互通 3. **cwd 跟用户走**: argv 自动 cd 到第一个非 flag 参数, 切换 buffer 时 nvim-tree 根跟随 4. **fetch_key 兜底 bashrc**: GUI 启动时 env 没继承, plugin 自己从 bashrc grep --- ## Credits 1. [Lazyvim starter](https://github.com/LazyVim/starter) - 启发了 NvChad starter 结构 2. [NvChad](https://github.com/NvChad/NvChad) - UI 基座 3. [Kurama622/llm.nvim](https://github.com/Kurama622/llm.nvim) - LLM chat + completion