Skip to content

Latest commit

 

History

History
399 lines (304 loc) · 17.3 KB

File metadata and controls

399 lines (304 loc) · 17.3 KB

logo

SOV710's Neovim Configuration

Stand With Palestine License Last Commit Stars Neovim Lua Gentoo

Ask DeepWiki

English | 中文

dashboard-showcase

设计哲学

任何编辑器——VS Code、Emacs、Sublime、JetBrains、Neovim——本质上都是同样八件事的组合:

  1. 一个隐形的插件管理器——你不需要时它根本不存在
  2. 编辑器自身的旋钮——vim.opt、autocmd、各种内置选项
  3. 一套完全属于你的模态键位层
  4. 有审美的 UI——dashboard、状态栏、缩进线、配色方案
  5. 编辑流——括号补全、文件树、模糊查找、which-key、文件标记、终端
  6. 对每一种语言的完整支持,包括: Tree-sitter、LSP、补全、诊断、Linter、Formatter、DAP、Snippets
  7. 不需要切回 shell 就能完成的版本控制
  8. 对 AI 的态度——因为这是 2026 年,盲目接受 agent 工具本身也是一种态度

这份配置直接覆盖前七层。第八层现在是一个有意的空缺。

写给谁看

你已经在维护自己的配置了。 你在试图组织 20+ 种语言的支持而不让整件事变成一团乱麻,你已经不想再从别人的 init.lua 复制粘贴,或者你想看看一份 from-scratch 的架构在有一定规模时长什么样。

或者:你正在用 LazyVim、NvChad、AstroVim、LunarVim,并且开始感觉到它的边界。你说不出具体想改什么,但你知道你的编辑器在做一些你不完全理解的事情。这份 repo 是一个从零开始的替代方案。

如果你完全是 Neovim 新手,先去看 kickstart.nvim。半年之后再回来这里。

Quick Start

Dependencies:

  • Neovim 0.12+
  • Git、tree-sitter CLI、一个 Nerd Font
  • 一个 C 编译器(用来编 tree-sitter parser)
  • ripgrepgrug-far 等插件需要)。
git clone https://github.com/SOV710/nvim-config ~/.config/nvim
nvim

首次启动时 lazy.nvim 自举并安装所有插件,mason-tool-installer 拉取所有 mason 管理的包。

然后运行:

:checkhealth langs
:TSInstall

:checkhealth langs 会列出哪些非 mason 外部工具还需要安装,并给出每个工具的安装命令。:TSInstall 会拉取各语言模块声明的 tree-sitter parser 源码,需要时运行 tree-sitter generate,编译 parser,并把 parser 与 queries 安装到这份配置管理的 Neovim runtime 里。

Contents

1. Plugin manager

lazy.nvim。所有 spec 文件按用途组织在 lua/plugins/{ui,editor,langs,git}/ 下,每个目录作为一个整体被 import。Snacks 的各个模块拆成独立的 spec 文件放在 lua/plugins/ui/ 下,由 lazy.nvim 自动 merge。

2. Options

lua/core/options.lua——几十行 vim.opt。能保持默认的就保持默认。

3. Keymaps

所有键位都在 lua/keymaps/ 下,按功能组织。Plugin spec 不直接调用 vim.keymap.set——它们引用返回普通 table 的 keymap 文件:

-- lua/plugins/editor/flash.lua
return {
  'folke/flash.nvim',
  event = 'VeryLazy',
  opts = {},
  keys = require('keymaps.editor.flash'),
}
-- lua/keymaps/editor/flash.lua
return {
  { 's', mode = { 'n', 'x', 'o' }, function() require('flash').jump() end,       desc = 'Flash jump' },
  { 'S', mode = { 'n', 'x', 'o' }, function() require('flash').treesitter() end, desc = 'Flash treesitter' },
}

所有键位都可以在一个目录里 grep 到。

几个重点绑定:

  • s / S → flash(覆盖原生 substitute,反正我从不用)
  • m → grapple toggle(覆盖原生 mark)
  • ' → grapple 菜单(覆盖原生 jump-to-mark)
  • + / - → dial(替代 <C-a> / <C-x>
  • <leader>g* → git,<leader>h* → hunk

4. UI

Tokyo Night 统一配色。状态栏和 tabline 是用 heirline 自己搭的——tabline 和 grapple.nvim 集成,被标记的文件直接出现在顶栏里。

组件 插件
Colorscheme folke/tokyonight.nvim
Statusline + tabline rebelot/heirline.nvim(custom)
Icons nvim-mini/mini.icons
Messages folke/noice.nvim(仅 messages;cmdline 留在底部内联)
Dashboard、indent、scroll、statuscolumn、image folke/snacks.nvim
模式感知的 cursorline mvllow/modes.nvim
颜色字面量(hex、CSS、Tailwind) brenoprata10/nvim-highlight-colors

🚧 Showcase pending:完整 UI 巡礼——dashboard → 编辑 buffer → grapple-aware tabline(15 秒 GIF)

5. 编辑流

组件 插件
File explorer stevearc/oil.nvim + snacks.explorer
Picker snacks.picker(替代 telescope)
Motion folke/flash.nvim
Surround echasnovski/mini.surround
括号补全 windwp/nvim-autopairs
括号 / tag 匹配 andymass/vim-matchup
文本对象 nvim-treesitter-textobjects
Yank ring gbprod/yanky.nvim
注释 folke/ts-comments.nvim(treesitter-aware)
文件标记(harpoon style) cbochs/grapple.nvim
LSP reference 跳转 snacks.words
Scratch buffer snacks.scratch
Split / join Wansmer/treesj
Inc / dec monaqa/dial.nvim
Undo tree Neovim 内建 nvim.undotree
Substitute gbprod/substitute.nvim
项目级搜索替换 MagicDuck/grug-far.nvim
Terminal akinsho/toggleterm.nvim
Which-key folke/which-key.nvim

🚧 Showcase pending:10 秒 flash.nvim 跳转 GIF

🚧 Showcase pending:grapple 标记在 heirline tabline 中显示(10 秒 GIF)

6. 语言支持

每种支持的语言——Rust、Go、Python、TypeScript、Haskell、Lua、C/C++、LaTeX、Fish、SQL,外加 20 多种——在 lua/langs/ 下对应一个文件。这个文件包含关于该语言的全部声明:LSP server 配置、tree-sitter parser 源码/build/query manifest、formatter、linter、DAP adapter、snippets、mason 包、文件类型识别,以及任何语言专属插件。

一个典型的 lua/langs/<name>.lua

return {
  filetypes = { 'rust' },
  treesitter = {
    languages = {
      rust = {
        parser = {
          source = {
            type = 'git',
            url = 'https://github.com/tree-sitter/tree-sitter-rust',
          },
          build = {
            files = { 'src/parser.c', 'src/scanner.c' },
          },
        },
        queries = {
          sources = {
            { type = 'parser_source', lang = 'rust' },
          },
        },
      },
    },
  },

  lsp = {
    rust_analyzer = {
      settings = {
        ['rust-analyzer'] = {
          checkOnSave = { command = 'clippy' },
        },
      },
    },
  },

  formatter = 'rustfmt',
  -- linter 省略:rust_analyzer 已经覆盖

  dap = {
    adapter        = { codelldb = { type = 'server', port = '${port}', ... } },
    configurations = { rust = { { name = 'Launch', type = 'codelldb', ... } } },
  },

  snippets = function()
    local ls = require('luasnip')
    return {
      ls.snippet('pln', { ls.text_node('println!("'), ls.insert_node(1), ls.text_node('");') }),
    }
  end,

  mason = { 'rust-analyzer', 'codelldb' },

  external_deps = {
    { cmd = 'cargo',   install = 'rustup default stable',          required = true },
    { cmd = 'rustfmt', install = 'rustup component add rustfmt',   required = true },
  },

  plugins = {
    { 'mrcjkb/rustaceanvim', version = '^5', lazy = false },
  },
}

lua/core/language.lua 在 require 时扫描 lua/langs/*.lua,把各语言的声明聚合成:

聚合后的字段 谁在消费
language.formatters conform.nvim
language.linters nvim-lint
language.treesitter core.treesitter 的原生 installer/runtime
language.mason mason-tool-installer
language.dap_adapterslanguage.dap_configurations nvim-dap
language.snippets LuaSnip
language.plugins 直接 inject 进 lazy.nvim 的 spec
LSP servers 通过原生 vim.lsp.config / vim.lsp.enable 注册,不经过 nvim-lspconfig

lua/core/treesitter.lua 负责整条 tree-sitter 管线。它提供 :TSInstall:TSUpdate:TSStatus:TSClean;按声明的 git URL checkout parser 源码;在 manifest 要求时运行 tree-sitter generate;编译 parser shared object;把 query sources 安装到受管理的 runtime;通过 vim.treesitter.language.register 注册 filetype;最后用 Neovim 原生的 vim.treesitter.start 启动高亮。

这份配置不再依赖 nvim-treesitter 的 parser registry、ensure_installed 或 installer。Parser 的来源声明放在 lua/langs/*.lua 里,而不是外部插件注册表里。

所以 conform 的整个 spec 是:

opts = {
  formatters_by_ft = require('core.language').formatters,
}

🚧 Showcase pending:架构图——lua/langs/*.luacore/language.lua → 扇出到各个消费者

开关单种语言。 每个 lang 文件都接受 enabled = false 字段。设置后,该文件在扫描阶段被跳过,所有下游消费者(Tree-sitter、LSP、conform、lint、DAP、snippets、mason)同步看不到它。当某次插件更新后某种语言出了问题,用这个方式可以快速隔离。

外部依赖。 很多语言工具链不能由 mason 管理——tsgo 要从源码编译,ty 走 PyPI,HLS 走 GHCup,fish-lsp 走 npm,sleek 走 cargo,latexindentchktex 随 TeX Live 一起安装。每个有非 mason 依赖的 lang 文件都在两处记录这些依赖:

  1. 文件顶部的块注释,写明安装命令和验证方式。
  2. 结构化的 external_deps 字段,由 :checkhealth langs 消费——报告哪些依赖在、哪些缺,并给出安装命令。
:checkhealth langs

==============================================================================
langs:                                          require("langs.health").check()

haskell ~
- OK ghc
- OK cabal
- ERROR haskell-language-server: not found
  - install: ghcup install hls recommended
- WARN haskell-debug-adapter: not found (optional)
  - install: cabal install haskell-debug-adapter haskell-dap ghci-dap

python ~
- OK ty

rust ~
- OK cargo
- OK rustfmt

dashboard-checkhealth-langs

每种语言的下层管线:

层级 插件
Package manager williamboman/mason.nvim + WhoIsSethDaniel/mason-tool-installer.nvim
Tree-sitter core.treesitter + 原生 vim.treesitter
LSP vim.lsp.config + vim.lsp.enable(原生,不走 nvim-lspconfig
补全 saghen/blink.cmp(Rust 写的 fuzzy matcher)
Snippets L3MON4D3/LuaSnip + friendly-snippets
Formatter stevearc/conform.nvim
Linter mfussenegger/nvim-lint
诊断 vim.diagnostic(原生)+ rachartier/tiny-inline-diagnostic.nvim
诊断列表 folke/trouble.nvim
DAP mfussenegger/nvim-dap + theHamsta/nvim-dap-virtual-text

语言专属插件。 通过每个 lang 文件的 plugins 字段注入到 lazy.nvim 的 spec 里:

语言 插件
Rust mrcjkb/rustaceanvimSaecki/crates.nvim
Haskell mrcjkb/haskell-tools.nvim
C / C++ p00f/clangd_extensions.nvim
LaTeX lervag/vimtex
Clojure / Lisp Olical/conjure
Markdown MeanderingProgrammer/render-markdown.nvim
CSV / TSV cameron-wags/rainbow_csv.nvim
JSON / YAML b0o/SchemaStore.nvim
Ghostty bezhermoso/tree-sitter-ghostty

7. 版本控制

组件 插件 用来做什么
边栏 hunk 提示 lewis6991/gitsigns.nvim ]h / [h 跳转、<leader>hs stage hunk、行 blame
Git 命令 tpope/vim-fugitive :Git status、commit、push、pull、blame
Diff 浏览 sindrets/diffview.nvim 可视化 diff 和文件历史
浏览器打开 Snacks.gitbrowse <leader>gB 打开 GitHub / Codeberg

四个工具职责不重叠:fugitive 管命令,diffview 管看差异,gitsigns 管在 buffer 里操作 hunk,gitbrowse 管打开网页。

实际用起来,这一节里我最常打开的其实是 toggleterm。大部分 git 操作——stage、commit、rebase、push——都在 shell buffer 里完成。上面四个插件只用来补终端里做起来别扭的那几件事:inline blame、当前 buffer 里的 hunk 跳转、并排 diff,以及在浏览器里打开某次提交。

8. AI

现在没有 AI 插件层了。lua/plugins/ai/ 是有意删掉的。

对我来说,Claude Code 已经变成了 a piece of bullshit。Anthropic 也不再是一家值得信任或尊重的公司:它现在的产品方向对使用者非常不友好,而 Claude Code 作为一个想进入开发环境执行 agent 工作的工具,已经带了太多不透明的遥测、检测和审查面。你可以把它叫作间谍工具,也可以把它叫作敌意工具;无论用哪个词,它都已经不适合作为这份配置里的 agent 层。

更大的趋势也已经变了。Agent 正在从旧的 "Cursor mode"——编辑器侧边栏、inline chat overlay、由 editor 接管的工作流——走向 "chatbox mode":Codex、opencode 这一类独立工具自己拥有 TUI/chat surface,把编辑器当作 context,而不是把编辑器变成整个交互界面。在这个趋势下,claudecode.nvimavante.nvim 以及类似模仿 Cursor 模式的 Neovim 插件已经不再适合使用。

所以 AI 仍然是工作流的一部分,但它会留在 Neovim 外面。这份配置暂时不会再保留专门的 AI 插件分类。

添加一种新语言

  1. 新建 lua/langs/<name>.lua
  2. 填上需要的字段(除 filetypes 外都是可选的)
  3. 重启 Neovim

聚合器在下次 require 时自动捡起新文件,所有下游插件看到新条目。

如果新语言声明了 tree-sitter manifest,重启后运行 :TSInstall <lang> 来拉取、编译并注册它的 parser/query runtime。

临时禁用一种语言而不删文件:在文件顶部加 enabled = false,重启。该语言从所有消费者——Tree-sitter、LSP、formatter、linter、DAP、snippets——中消失。

删除一种语言

  1. 删掉 lua/langs/<name>.lua——或者只是把 mason 字段里不想要的那项去掉。
  2. 重启 Neovim。
  3. :checkhealth langslangs.mason 那一节会把所有还装着但已经不在声明里的 mason 包标出来。
  4. 如果被移除的语言有 tree-sitter parser,运行 :TSClean 清掉陈旧的 parser/query checkout 和 runtime 条目。
  5. :MasonUninstall <pkg> 精确卸载,或 :MasonToolsClean 一次清掉所有孤儿包。:MasonToolsClean 同时也会把当前被 enabled = false 的 lang 对应的包一起删掉,所以如果有禁用中的 lang,优先用 per-package 的 :MasonUninstall

项目结构

init.lua                     -- lazy.nvim 自举,顶层 setup
lua/
├── core/
│   ├── options.lua
│   ├── language.lua         -- 聚合器
│   ├── treesitter.lua       -- 原生 parser/query installer 和 runtime
│   └── sysinfo.lua
├── keymaps/                 -- 全部键位,按功能组织
│   ├── init.lua
│   ├── editing.lua
│   ├── winbuf.lua
│   ├── snacks.lua
│   ├── which-key.lua
│   ├── editor/
│   ├── git/
│   ├── ai/
│   └── langs/
├── plugins/
│   ├── snacks.lua           -- 中心 Snacks 注册
│   ├── ui/
│   ├── editor/
│   ├── langs/               -- completion、format、lint、treesitter、dap、mason、snippets
│   ├── git/
│   └── ai/
└── langs/                   -- 每种语言一个文件;声明的唯一来源
    ├── rust.lua
    ├── python.lua
    ├── haskell.lua
    └── ...

致谢

感谢亲爱的 @Lingshinx 杰出的 ASCII art

License

GPL-3.0-or-later。完整文本见 LICENSE

每个源文件都带有 SPDX-License-Identifier 头。