refactor(nvim): 完整重写配置,支持 Go/Rust/Python/TypeScript 开发

- 架构重构:新增 plugins/lang/ 子目录,按语言拆分配置
- 补全引擎:nvim-cmp → blink.cmp + LuaSnip
- 文件浏览:新增 neo-tree(<Space>e)
- 语言支持:
  - Go: ray-x/go.nvim + dap-go + neotest-go
  - Rust: rustaceanvim + crates.nvim
  - Python: venv-selector + dap-python + neotest-python
  - TypeScript: typescript-tools.nvim(替换 ts_ls)
- LSP: lazydev + mason + mason-lspconfig + fidget + inc-rename
- 格式化: conform.nvim(lsp_format fallback,保存时自动格式化)
- Lint: nvim-lint(selene 替换 luacheck,Mason 可直接安装)
- UI: snacks.nvim(dashboard+notifier+picker)+ noice + lualine + bufferline
- 编辑增强: mini.ai + mini.surround + grug-far + flash + ufo + trouble v3
- 删除废弃文件: cmp/coding/null-ls/mason/lspconfig/go/python 等旧文件
- 修复: Neovim 0.12 treesitter query 校验报错(noice routes 过滤)
- 新增: NVIM_GUIDE.md 快捷键使用手册

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
2026-04-07 16:55:07 +08:00
parent 2aa176dff5
commit 6fd5d96043
36 changed files with 2087 additions and 2814 deletions

View File

@@ -0,0 +1,121 @@
-- lang/go.lua - Go 开发专用配置
return {
-- ray-x/go.nvim - Go 全功能插件
{
"ray-x/go.nvim",
dependencies = {
"ray-x/guihua.lua",
"neovim/nvim-lspconfig",
"nvim-treesitter/nvim-treesitter",
},
ft = { "go", "gomod", "gowork", "gotmpl" },
build = ':lua require("go.install").update_all_sync()',
opts = {
lsp_cfg = false, -- LSP 由 lsp.lua 的 gopls 配置统一管理
lsp_keymaps = false,
lsp_codelens = true,
lsp_inlay_hints = {
enable = true,
only_current_line = false,
show_parameter_hints = true,
parameter_hints_prefix = " ",
other_hints_prefix = " ",
},
formatter = "gofumpt",
goimport = "gopls",
gofmt = true,
test_runner = "go",
run_in_floaterm = true,
dap_debug = true,
dap_debug_gui = true,
dap_debug_vt = true,
textobjects = true,
trouble = true,
diagnostic = {
hdlr = true,
underline = true,
virtual_text = { space = 0, prefix = "" },
signs = true,
update_in_insert = false,
},
tag_transform = "snakecase",
verbose = false,
},
config = function(_, opts)
require("go").setup(opts)
local gogroup = vim.api.nvim_create_augroup("GoGroup", { clear = true })
vim.api.nvim_create_autocmd("BufWritePre", {
pattern = "*.go",
group = gogroup,
callback = function()
require("go.format").goimport()
end,
})
end,
keys = {
{ "<leader>gts", "<cmd>GoAlt<cr>", ft = "go", desc = "切换测试/实现" },
{ "<leader>gtt", "<cmd>GoTest<cr>", ft = "go", desc = "运行测试" },
{ "<leader>gtf", "<cmd>GoTestFunc<cr>", ft = "go", desc = "测试当前函数" },
{ "<leader>gtc", "<cmd>GoCoverage<cr>", ft = "go", desc = "测试覆盖率" },
{ "<leader>gtC", "<cmd>GoCoverageClear<cr>", ft = "go", desc = "清除覆盖率" },
{ "<leader>gge", "<cmd>GoIfErr<cr>", ft = "go", desc = "生成错误处理" },
{ "<leader>ggf", "<cmd>GoFillStruct<cr>", ft = "go", desc = "填充结构体" },
{ "<leader>ggs", "<cmd>GoFillSwitch<cr>", ft = "go", desc = "填充 switch" },
{ "<leader>gta", "<cmd>GoAddTag<cr>", ft = "go", desc = "添加标签" },
{ "<leader>gtr", "<cmd>GoRmTag<cr>", ft = "go", desc = "移除标签" },
{ "<leader>gr", "<cmd>GoRun<cr>", ft = "go", desc = "运行" },
{ "<leader>gb", "<cmd>GoBuild<cr>", ft = "go", desc = "构建" },
{ "<leader>gi", "<cmd>GoImpl<cr>", ft = "go", desc = "实现接口" },
{ "<leader>gdc", "<cmd>GoDoc<cr>", ft = "go", desc = "查看文档" },
{ "<leader>gv", "<cmd>GoVet<cr>", ft = "go", desc = "go vet" },
},
},
-- Go DAP 支持
{
"leoluz/nvim-dap-go",
ft = "go",
dependencies = { "mfussenegger/nvim-dap" },
config = function()
require("dap-go").setup({ dap_configurations = {
{ type = "go", name = "调试文件", request = "launch", program = "${file}" },
{ type = "go", name = "调试包", request = "launch", program = "${fileDirname}" },
{ type = "go", name = "调试测试", request = "launch", mode = "test", program = "${file}" },
}})
end,
keys = {
{ "<leader>dtg", function() require("dap-go").debug_test() end, ft = "go", desc = "调试当前测试" },
{ "<leader>dtl", function() require("dap-go").debug_last_test() end, ft = "go", desc = "调试上次测试" },
},
},
-- neotest Go 适配器
{
"nvim-neotest/neotest",
optional = true,
dependencies = { "nvim-neotest/neotest-go" },
opts = {
adapters = {
["neotest-go"] = {
args = { "-count=1", "-timeout=30s", "-v" },
},
},
},
},
-- Mason Go 工具
{
"williamboman/mason.nvim",
optional = true,
opts = function(_, opts)
opts.ensure_installed = opts.ensure_installed or {}
vim.list_extend(opts.ensure_installed, {
"gopls", "gofumpt", "goimports", "golangci-lint",
"gomodifytags", "gotests", "impl", "delve",
})
end,
},
}

View File

@@ -0,0 +1,95 @@
-- lang/python.lua - Python 开发专用配置
return {
-- 虚拟环境选择器
{
"linux-cultist/venv-selector.nvim",
branch = "regexp",
cmd = "VenvSelect",
ft = "python",
dependencies = { "neovim/nvim-lspconfig", "nvim-telescope/telescope.nvim" },
opts = {
settings = {
options = {
notify_user_on_venv_activation = true,
},
},
},
keys = {
{ "<leader>pv", "<cmd>VenvSelect<cr>", ft = "python", desc = "选择虚拟环境" },
},
},
-- Python DAP 支持
{
"mfussenegger/nvim-dap-python",
ft = "python",
dependencies = { "mfussenegger/nvim-dap" },
config = function()
local ok, mason_registry = pcall(require, "mason-registry")
local python_path = "python3"
if ok and mason_registry.is_installed("debugpy") then
python_path = mason_registry.get_package("debugpy"):get_install_path() .. "/venv/bin/python"
end
require("dap-python").setup(python_path)
require("dap-python").test_runner = "pytest"
-- 带参数启动
table.insert(require("dap").configurations.python, {
type = "python", request = "launch",
name = "带参数启动",
program = "${file}",
args = function()
return vim.split(vim.fn.input("命令行参数: "), " ")
end,
console = "integratedTerminal",
})
end,
keys = {
{ "<leader>dpm", function() require("dap-python").test_method() end, ft = "python", desc = "调试当前方法" },
{ "<leader>dpc", function() require("dap-python").test_class() end, ft = "python", desc = "调试当前类" },
},
},
-- neotest Python 适配器
{
"nvim-neotest/neotest",
optional = true,
dependencies = { "nvim-neotest/neotest-python" },
opts = function(_, opts)
opts.adapters = opts.adapters or {}
table.insert(opts.adapters, require("neotest-python")({
runner = "pytest",
args = { "--color=yes", "-v" },
python = function()
if vim.env.VIRTUAL_ENV then
return vim.env.VIRTUAL_ENV .. "/bin/python"
end
return "python3"
end,
}))
return opts
end,
keys = {
{ "<leader>pt", function() require("neotest").run.run() end, ft = "python", desc = "运行最近测试" },
{ "<leader>pT", function() require("neotest").run.run(vim.fn.expand("%")) end, ft = "python", desc = "运行文件测试" },
{ "<leader>pd", function() require("neotest").run.run({ strategy = "dap" }) end, ft = "python", desc = "调试测试" },
{ "<leader>ps", function() require("neotest").run.stop() end, ft = "python", desc = "停止测试" },
{ "<leader>po", function() require("neotest").output.open() end, ft = "python", desc = "测试输出" },
{ "<leader>pO", function() require("neotest").output_panel.toggle() end, ft = "python", desc = "输出面板" },
{ "<leader>pS", function() require("neotest").summary.toggle() end, ft = "python", desc = "摘要窗口" },
},
},
-- Mason Python 工具
{
"williamboman/mason.nvim",
optional = true,
opts = function(_, opts)
opts.ensure_installed = opts.ensure_installed or {}
vim.list_extend(opts.ensure_installed, {
"pyright", "ruff", "isort", "debugpy",
})
end,
},
}

View File

@@ -0,0 +1,111 @@
-- lang/rust.lua - Rust 开发专用配置rustaceanvim + codelldb
return {
-- rustaceanvim - Rust 全功能插件(接管 rust-analyzer LSP
{
"mrcjkb/rustaceanvim",
version = "^5",
ft = "rust",
opts = {
server = {
on_attach = function(_, bufnr)
local map = function(mode, lhs, rhs, desc)
vim.keymap.set(mode, lhs, rhs, { buffer = bufnr, silent = true, desc = desc })
end
-- Rust 专用操作
map("n", "<leader>rr", function() vim.cmd.RustLsp("runnables") end, "Rust 运行目标")
map("n", "<leader>rt", function() vim.cmd.RustLsp("testables") end, "Rust 测试目标")
map("n", "<leader>rd", function() vim.cmd.RustLsp("debuggables") end, "Rust 调试目标")
map("n", "<leader>re", function() vim.cmd.RustLsp("explainError") end, "解释错误")
map("n", "<leader>rc", function() vim.cmd.RustLsp("openCargo") end, "打开 Cargo.toml")
map("n", "<leader>rp", function() vim.cmd.RustLsp("parentModule") end, "父模块")
map("n", "<leader>rm", function() vim.cmd.RustLsp("expandMacro") end, "展开宏")
map("n", "<leader>rx", function() vim.cmd.RustLsp("externalDocs") end, "外部文档")
map("n", "K", function() vim.cmd.RustLsp({ "hover", "actions" }) end, "悬浮操作")
map("n", "<leader>ca", function() vim.cmd.RustLsp("codeAction") end, "代码操作")
end,
default_settings = {
["rust-analyzer"] = {
cargo = {
allFeatures = true,
loadOutDirsFromCheck = true,
runBuildScripts = true,
},
checkOnSave = {
allFeatures = true,
command = "clippy",
extraArgs = { "--no-deps" },
},
procMacro = {
enable = true,
ignored = {
["async-trait"] = { "async_trait" },
["napi-derive"] = { "napi" },
["async-recursion"] = { "async_recursion" },
},
},
inlayHints = {
bindingModeHints = { enable = false },
chainingHints = { enable = true },
closingBraceHints = { enable = true, minLines = 25 },
closureReturnTypeHints = { enable = "never" },
lifetimeElisionHints = { enable = "never" },
parameterHints = { enable = false },
typeHints = { enable = true, hideClosureInitialization = false, hideNamedConstructor = false },
},
},
},
},
-- DAP 配置codelldb
dap = {},
},
config = function(_, opts)
-- 延迟设置 DAP adapter需在 rustaceanvim 加载后才能 require
local ok_mason, mason_registry = pcall(require, "mason-registry")
if ok_mason and mason_registry.is_installed("codelldb") then
local codelldb_path = mason_registry.get_package("codelldb"):get_install_path()
local codelldb = codelldb_path .. "/codelldb"
local liblldb = codelldb_path .. "/extension/lldb/lib/liblldb.dylib"
if vim.fn.has("linux") == 1 then
liblldb = codelldb_path .. "/extension/lldb/lib/liblldb.so"
end
opts.dap = opts.dap or {}
opts.dap.adapter = require("rustaceanvim.config").get_codelldb_adapter(codelldb, liblldb)
end
vim.g.rustaceanvim = vim.tbl_deep_extend("keep", vim.g.rustaceanvim or {}, opts)
end,
},
-- crates.nvim - Cargo.toml 依赖管理
{
"saecki/crates.nvim",
event = { "BufRead Cargo.toml" },
opts = {
completion = {
cmp = { enabled = false },
crates = { enabled = true, max_results = 8, min_chars = 3 },
},
lsp = {
enabled = true,
on_attach = function() end,
actions = true,
completion = true,
hover = true,
},
},
keys = {
{ "<leader>rcu", function() require("crates").upgrade_all_crates() end, ft = "toml", desc = "升级所有依赖" },
{ "<leader>rco", function() require("crates").show_popup() end, ft = "toml", desc = "Crate 信息" },
},
},
-- Mason Rust 工具
{
"williamboman/mason.nvim",
optional = true,
opts = function(_, opts)
opts.ensure_installed = opts.ensure_installed or {}
vim.list_extend(opts.ensure_installed, { "codelldb" })
end,
},
}

View File

@@ -0,0 +1,99 @@
-- lang/typescript.lua - TypeScript/JavaScript 开发专用配置
return {
-- typescript-tools.nvim - 高性能 TypeScript LSP直接对接 tsserver 协议)
{
"pmizio/typescript-tools.nvim",
dependencies = { "nvim-lua/plenary.nvim", "neovim/nvim-lspconfig" },
ft = { "javascript", "javascriptreact", "typescript", "typescriptreact", "vue" },
opts = {
on_attach = function(_, bufnr)
local map = function(mode, lhs, rhs, desc)
vim.keymap.set(mode, lhs, rhs, { buffer = bufnr, silent = true, desc = desc })
end
map("n", "<leader>to", "<cmd>TSToolsOrganizeImports<cr>", "整理 Import")
map("n", "<leader>ta", "<cmd>TSToolsAddMissingImports<cr>", "添加缺失 Import")
map("n", "<leader>tu", "<cmd>TSToolsRemoveUnusedImports<cr>", "删除未使用 Import")
map("n", "<leader>tf", "<cmd>TSToolsFixAll<cr>", "修复所有")
map("n", "<leader>tr", "<cmd>TSToolsRenameFile<cr>", "重命名文件")
map("n", "<leader>tR", "<cmd>TSToolsFileReferences<cr>", "文件引用")
end,
settings = {
separate_diagnostic_server = true,
publish_diagnostic_on = "insert_leave",
expose_as_code_action = "all",
tsserver_path = nil,
tsserver_plugins = {},
tsserver_max_memory = "auto",
tsserver_format_options = {
allowIncompleteCompletions = false,
allowRenameOfImportPath = false,
},
tsserver_file_preferences = {
includeInlayParameterNameHints = "all",
includeInlayParameterNameHintsWhenArgumentMatchesName = false,
includeInlayFunctionParameterTypeHints = true,
includeInlayVariableTypeHints = true,
includeInlayVariableTypeHintsWhenTypeMatchesName = false,
includeInlayPropertyDeclarationTypeHints = true,
includeInlayFunctionLikeReturnTypeHints = true,
includeInlayEnumMemberValueHints = true,
quotePreference = "auto",
},
-- 代码样式
tsserver_locale = "zh-cn",
complete_function_calls = true,
include_completions_with_insert_text = true,
code_lens = "off",
disable_member_code_lens = true,
jsx_close_tag = { enable = true, filetypes = { "javascriptreact", "typescriptreact" } },
},
},
},
-- ESLint LSP通过 nvim-lspconfigmason 安装)
{
"neovim/nvim-lspconfig",
optional = true,
opts = {
servers = {
eslint = {
settings = {
workingDirectories = { mode = "auto" },
format = false, -- 格式化由 prettier 处理
},
on_attach = function(_, bufnr)
vim.api.nvim_create_autocmd("BufWritePre", {
buffer = bufnr,
command = "EslintFixAll",
})
end,
},
},
},
},
-- Mason TypeScript 工具
{
"williamboman/mason.nvim",
optional = true,
opts = function(_, opts)
opts.ensure_installed = opts.ensure_installed or {}
vim.list_extend(opts.ensure_installed, {
"typescript-language-server", "eslint-lsp", "prettierd",
})
end,
},
-- Treesitter TypeScript/JSX
{
"nvim-treesitter/nvim-treesitter",
optional = true,
opts = function(_, opts)
opts.ensure_installed = opts.ensure_installed or {}
vim.list_extend(opts.ensure_installed, {
"javascript", "typescript", "tsx", "jsdoc",
})
end,
},
}