概述
参考文档:
Neovim 是 Vim 的分支,内置 Lua 解释器、LSP 客户端、Treesitter 与终端,配置从
vimrc迁到init.lua与 Vim 的关系:模式与按键语法基本不变,差异集中在配置语言、默认行为与内建子系统,官方清单在
:h vim-differences结构:
flowchart LR A["init.lua"] --> B["vim.* 标准库"] B --> C["vim.lsp(内置 LSP 客户端)"] B --> D["vim.treesitter"] B --> E["vim.pack(0.13 插件管理)"] F["任意 GUI / 终端"] -->|"RPC"| G["Neovim 核心"]
本文假设读者已会 Vim 基本操作,编辑入门见Vim 入门,各语言 LSP 的安装见Neovim LSP 服务器
快速开始
配置入口是
~/.config/nvim/init.lua,最小可用示例:luavim.opt.number = true -- 行号 vim.opt.termguicolors = true -- 24 位真彩色 vim.g.mapleader = " " -- leader 设为空格 vim.keymap.set("n", "<leader>w", ":w<CR>", { desc = "保存" }) vim.pack.add({ -- 0.13 官方插件安装 { src = "https://github.com/nvim-treesitter/nvim-treesitter" }, { src = "https://github.com/echasnovski/mini.nvim" }, })查手册:
:h lua-guide入门,之后按模块:h vim.api、:h vim.pack、:h vim.ui试运行 Lua:
:= 表达式在命令行直接求值,:lua 语句执行单句
Lua 桥接 Vim
五个入口对象:
vim.opt:选项对象,支持链式与列表式赋值,vim.opt.listchars = { tab = "→ " },只要字符串时用vim.ovim.g/vim.b/vim.w:全局、缓冲区、窗口变量,对应 VimL 的g:、b:、w:vim.fn:调用 VimL 函数,vim.fn.getcwd()vim.cmd:执行 Ex 命令,vim.cmd.colorscheme("habamax")vim.api.*:底层 C API,nvim_create_autocmd等都在这里,:h api
键位用
vim.keymap.set,比nnoremap多了desc描述与buffer局部选项,which-key 类插件靠desc生成提示异步原语:
vim.defer_fn(fn, ms)延时执行,vim.schedule(fn)在事件循环安全点执行,vim.uv是 libuv 的完整绑定autocmd 与用户命令:
luavim.api.nvim_create_autocmd("TextYankPost", { callback = function() vim.hl.on_yank() end, -- 0.11 起 vim.hl 取代 vim.highlight }) vim.api.nvim_create_user_command("Trim", function() vim.cmd("%s/\\s\\+$//e") -- 删行尾空白 end, {})
vim.fs 与 vim.ui
vim.fs文件系统工具:vim.fs.find("Cargo.toml", { upward = true })从当前文件向上找vim.fs.root(0, { ".git" })定位项目根,0表示当前缓冲区vim.fs.normalize(path)跨平台整理路径分隔符
vim.ui交互接口:vim.ui.input()与vim.ui.select()是异步回调式,插件可整体接管其 UI,这就是 dressing 类插件"只换皮不改逻辑"的原因vim.ui.open(目标)用系统默认程序打开 URL 或路径(0.12 起),等价xdg-open但跨平台
vim.system 与 vim.snippet
vim.system()(0.10 起)跑子进程,取代手写io.popen:lualocal out = vim.system({ "rg", "--version" }):wait() -- 同步等待 vim.system({ "make" }, { text = true }, function(res) -- 异步回调 vim.notify("make 退出码 " .. res.code) end)vim.snippet(0.10 起)原生 LSP 风格 snippet 引擎:vim.snippet.expand("fn $1($2) $0")直接展开,支持 Tabstop、占位符与选择分支- 配合内置 LSP 起步不需要第三方 snippet 插件
LSP 配置
0.11 起的写法:
vim.lsp.config定义,vim.lsp.enable启用,取代往setup{}里塞整个配置:luavim.lsp.config("clangd", { cmd = { "clangd", "--background-index" }, root_markers = { "compile_commands.json" }, -- 0.13 起用 root_markers 声明根标记 }) vim.lsp.enable("clangd")LspAttach事件里做按缓冲区键位:luavim.api.nvim_create_autocmd("LspAttach", { callback = function(args) vim.keymap.set("n", "gd", vim.lsp.buf.definition, { buffer = args.buf }) end, })内置 LSP 客户端不含补全 UI,社区主流是
blink.cmp与nvim-cmp,服务器侧安装见Neovim LSP 服务器
vim.pack 与插件生态
0.13 的
vim.pack是官方(实验性)插件管理:vim.pack.add({...})克隆到stdpath("data")下并立即加载,条目是src(仓库地址,支持完整 URL)与可选的versionvim.pack.update()交互式更新,可传名字列表只更新部分- 只有安装与加载,锁文件与复杂延迟加载仍需
lazy.nvim等第三方方案
Lua 插件的约定结构:
lua/目录下的模块加setup()入口,用法固定为:luarequire("gitsigns").setup({})
从 Vim 迁移
init.vim仍被支持,旧配置可直接沿用,但新代码建议全部写 Lua- 默认行为差异:Neovim 默认启用鼠标、更好的撤销持久化与
syntax等,逐项看:h vim-defaults - 必须换的习惯:
set换vim.opt,let g:换vim.gnnoremap换vim.keymap.setvim-plug换vim.pack或lazy.nvim
- 多套配置隔离:
NVIM_APPNAME=work nvim让 Neovim 读~/.config/work/下的整套配置(0.9 起)
相关阅读
- Vim 入门:模式体系与编辑命令
- Neovim LSP 服务器:各语言 LSP 的安装与配置