-
Notifications
You must be signed in to change notification settings - Fork 0
nvim dev api
ES edited this page Jul 16, 2026
·
1 revision
面向插件作者的 API 地图。每个条目配
:htag,想细看就:help
Neovim
├── C 核心(事件循环 + nvim_* API)
├── Vimscript(历史兼容 + Ex 命令 + 内置函数)
└── Lua 层(vim.* stdlib,插件开发的主战场)
├── 对接 C 核心 → vim.api.*
├── 对接 Vimscript → vim.fn.* / vim.cmd
└── 自有标准库 → vim.lsp / vim.treesitter / vim.diagnostic / ...
插件作者 95% 时间在 Lua 层。下面全部挂在 vim.* 下
| 命名空间 | 作用 |
:h tag |
|---|---|---|
vim.api.* |
C 核心 API 的 Lua 绑定(nvim_* 家族) |
:h api |
vim.fn.* |
调 Vimscript 内建函数 | :h vim.fn |
vim.cmd |
执 Ex 命令 | :h vim.cmd |
vim.g/b/w/t/v/env |
作用域变量(global/buf/win/tab/v:/env) | :h lua-vim-variables |
vim.opt/bo/wo/go/o |
选项访问器(支持 list/set 语义) | :h vim.opt |
vim.keymap |
键位映射 | :h vim.keymap.set |
vim.lsp |
LSP 客户端 + 内置功能 | :h lsp |
vim.treesitter |
Treesitter parser / query / highlighter | :h treesitter |
vim.diagnostic |
诊断显示与导航 | :h vim.diagnostic |
vim.uv |
libuv 绑定(异步 IO/定时器) | :h vim.uv |
vim.system |
子进程 API(推荐替代 jobstart) | :h vim.system |
vim.ui |
可被插件覆盖的 input / select / open | :h vim.ui |
vim.iter |
链式迭代器 | :h vim.iter |
vim.fs |
文件系统工具 | :h vim.fs |
vim.filetype |
filetype 注册与匹配 | :h vim.filetype |
vim.snippet |
内置 snippet 引擎 | :h vim.snippet |
vim.hl |
高亮范围(旧名 vim.highlight) |
:h vim.hl |
vim.pack |
原生包管理器(0.12+) | :h vim.pack |
最常用、最底层。所有 nvim_* 都可以从 Lua 调
| API | 说明 |
|---|---|
nvim_create_buf(listed, scratch) |
创建 buffer |
nvim_buf_get_lines(buf, start, end, strict) |
读行(0-indexed,end 是 exclusive) |
nvim_buf_set_lines(buf, start, end, strict, lines) |
写行(需要 modifiable=true) |
nvim_buf_attach(buf, send_buffer, {on_lines=...}) |
订阅 buffer 变化 |
nvim_buf_get_name(buf) |
获取 buffer 文件路径 |
nvim_buf_delete(buf, {force}) |
删除 buffer |
| API | 说明 |
|---|---|
nvim_open_win(buf, enter, config) |
打开浮窗 / split(relative='editor' 为浮窗) |
nvim_win_set_buf(win, buf) |
换窗口内的 buffer |
nvim_win_get_cursor(win) / set_cursor(win, {r, c})
|
读/设光标(1-indexed 行,0-indexed 列) |
nvim_win_set_config(win, config) |
修改浮窗配置 |
nvim_win_close(win, force) |
关窗口 |
浮窗配置关键字段:relative / row / col / width / height / border / title / footer / zindex / style='minimal'
虚拟文本、内联诊断、sign、高亮都走它。:h api-extended-marks
local ns = vim.api.nvim_create_namespace('myplug')
vim.api.nvim_buf_set_extmark(buf, ns, row, col, {
virt_text = { {'TODO', 'WarningMsg'} }, -- 行尾虚拟文本
virt_lines = { {{'-- above line', 'Comment'}} }, -- 虚拟行
sign_text = 'E', sign_hl_group = 'Error', -- sign 列图标
hl_group = 'Search', -- 范围高亮
end_row = row, end_col = col + 10,
})
vim.api.nvim_buf_clear_namespace(buf, ns, 0, -1) -- 直接清除-- autocmd
local aug = vim.api.nvim_create_augroup('MyPlug', { clear = true })
vim.api.nvim_create_autocmd('BufWritePost', {
group = aug, pattern = '*.ts',
callback = function(args) print('saved', args.file) end,
})
-- 用户命令
vim.api.nvim_create_user_command('MyCmd', function(o)
print(o.args, o.bang)
end, { nargs = '?', bang = true, desc = 'my command' })
-- 高亮
vim.api.nvim_set_hl(0, 'MyHl', { fg = '#ff6ac1', bold = true })nvim_open_term, nvim_chan_send, rpcrequest, rpcnotify —— 用于终端、外部 UI、远程插件。:h rpc
vim.fn.expand('%:p') -- Vimscript 函数
vim.fn.glob('*.lua', nil, true)
vim.cmd('edit foo.lua') -- Ex 命令字符串
vim.cmd.edit('foo.lua') -- 新式调用语法
vim.cmd.colorscheme('tokyonight')-- 变量
vim.g.mapleader = ' ' -- 全局
vim.b.my_state = 1 -- 当前 buffer
vim.b[bufnr].my_state = 1 -- 指定 buffer
vim.w[win].my_state = 1 -- window
vim.env.FOO = 'bar' -- 进程环境变量
-- 选项(三套 API,按需选)
vim.o.number = true -- 普通值(get/set)
vim.bo.filetype = 'lua' -- buf 局部
vim.wo[win].number = false -- win 局部
vim.opt.list:append({ tab = '»·' }) -- list/set 语义
vim.opt_local.wrap = false -- setlocalvim.keymap.set('n', '<leader>w', '<cmd>write<cr>', { desc = 'save', silent = true })
vim.keymap.set({'n', 'v'}, 'gf', function() vim.lsp.buf.format() end)
vim.keymap.set('n', '<leader>x', '<cmd>MyCmd<cr>', { buffer = buf }) -- buffer-local
vim.keymap.del('n', '<leader>w')-- 全局注册 server 配置
vim.lsp.config('lua_ls', {
cmd = { 'lua-language-server' },
root_markers = { '.luarc.json', '.git' },
settings = { Lua = { diagnostics = { globals = { 'vim' } } } },
})
-- 按需启用
vim.lsp.enable({ 'lua_ls', 'tsserver' })| API | 用途 |
|---|---|
vim.lsp.buf.hover() |
K 显示 hover |
vim.lsp.buf.definition() |
跳定义 |
vim.lsp.buf.references() |
引用列表 |
vim.lsp.buf.rename() |
重命名 |
vim.lsp.buf.code_action() |
代码动作 |
vim.lsp.buf.format({async=true}) |
格式化 |
vim.lsp.inlay_hint.enable(true) |
开 inlay hint |
vim.lsp.get_clients({bufnr=0}) |
查当前 buffer 的 client |
vim.lsp.log.set_level('debug') |
调试 LSP |
子模块:handlers / util / protocol / semantic_tokens / codelens / inlay_hint / completion / diagnostic / rpc / client
local parser = vim.treesitter.get_parser(bufnr, 'typescript')
local tree = parser:parse()[1]
local root = tree:root()
-- 查询
local query = vim.treesitter.query.parse('typescript', [[
(function_declaration name: (identifier) @func)
]])
for id, node in query:iter_captures(root, bufnr, 0, -1) do
local name = query.captures[id]
local text = vim.treesitter.get_node_text(node, bufnr)
end
-- 光标下节点
local node = vim.treesitter.get_node()子模块:query / highlighter / language / languagetree / dev(playground、:Inspect、:EditQuery)
-- 发布诊断(给自己插件用)
local ns = vim.api.nvim_create_namespace('myplug.diag')
vim.diagnostic.set(ns, bufnr, {
{ lnum = 0, col = 0, severity = vim.diagnostic.severity.WARN, message = 'oops' },
})
-- 读取 / 跳转
vim.diagnostic.get(bufnr, { severity = vim.diagnostic.severity.ERROR })
vim.diagnostic.jump({ count = 1 }) -- next
vim.diagnostic.open_float()
-- 全局配置
vim.diagnostic.config({
virtual_text = false,
virtual_lines = true, -- 0.11 新:多行展示
severity_sort = true,
signs = { text = { [vim.diagnostic.severity.ERROR] = 'E' } },
})-- vim.uv:libuv 全绑定
local timer = vim.uv.new_timer()
timer:start(100, 0, vim.schedule_wrap(function()
vim.notify('tick')
timer:close()
end))
-- vim.system:子进程推荐 API
vim.system({ 'git', 'status', '--porcelain' }, { text = true }, function(obj)
vim.schedule(function()
print(obj.code, obj.stdout)
end)
end)
-- 同步版
local result = vim.system({'ls', '-la'}, { text = true }):wait()
-- 主循环调度
vim.schedule(function() ... end) -- 下一个安全点执行
vim.schedule_wrap(cb) -- 包装一个 cb
vim.defer_fn(fn, 100) -- 100ms 后
vim.wait(100, function() return done end, 10) -- 忙等(尽量别用)关键:libuv 回调里不能直接调 vim.api.*,必须走 vim.schedule
-- 用户级调用
vim.ui.input({ prompt = 'Name: ', default = 'foo' }, function(val)
if val then print('got', val) end
end)
vim.ui.select({ 'a', 'b', 'c' }, { prompt = 'Pick:' }, function(choice)
print(choice)
end)
vim.ui.open('https://google.com') -- 走系统默认打开器
-- 插件级覆盖(dressing / telescope 都这么干)
vim.ui.select = function(items, opts, on_choice) ... endvim.ui_attach 可订阅底层 UI event(cmdline_show/popupmenu_show),用于写浮窗 cmdline(见 noice.nvim)
-- iter:链式迭代器
vim.iter({1,2,3,4})
:filter(function(x) return x > 1 end)
:map(function(x) return x * 2 end)
:totable() -- { 4, 6, 8 }
-- fs
vim.fs.find('.git', { upward = true, path = vim.fn.expand('%:p') })
vim.fs.root(0, { 'package.json', '.git' }) -- 0.10+ 根目录查找
vim.fs.dirname('/a/b/c.lua')
vim.fs.normalize('~/x/../y')
-- filetype
vim.filetype.add({
extension = { tsx = 'typescriptreact' },
pattern = { ['.*%.env%..*'] = 'sh' },
})
-- validate
vim.validate('name', name, 'string')
vim.validate('count', count, 'number', true) -- 可选
-- inspect / print
vim.print(obj) -- = print(vim.inspect(obj))
vim.inspect({a=1, b={2,3}})
-- tbl_*
vim.tbl_deep_extend('force', defaults, opts)
vim.tbl_keys(t) / vim.tbl_values(t) / vim.tbl_map(fn, t) / vim.tbl_filter(fn, t)
vim.islist(t)
-- version
local v = vim.version.parse('1.2.3')
vim.version.lt(v1, v2)vim.snippet.expand('console.log($1);$0')
vim.snippet.jump(1) -- 下一个 tabstop
vim.snippet.stop()
vim.snippet.active({ direction = 1 })vim.pack.add({
'https://github.com/folke/tokyonight.nvim',
{ src = 'https://github.com/nvim-telescope/telescope.nvim', version = '0.1.8' },
})
vim.pack.update() -- 升级
vim.pack.del({ 'tokyonight.nvim' })Lockfile:$XDG_CONFIG_HOME/nvim/nvim-pack-lock.json
| 特性 | 写法 |
|---|---|
| 浮窗 | nvim_open_win(buf, true, { relative='editor', border='rounded', ... }) |
| statusline |
vim.o.statusline = '%f %m' 或 %!v:lua.MyFn()
|
| winbar | vim.wo.winbar = ... |
| statuscolumn | vim.o.statuscolumn = '%s%=%l ' |
| foldtext / foldexpr | vim.wo.foldexpr = 'v:lua.MyFn()' |
| sign 列 | 推荐走 extmark 的 sign_text / sign_hl_group
|
myplugin/
├── plugin/*.lua Nvim 启动时自动 source(每次一次)
├── ftplugin/<ft>.lua 对应 filetype buffer 打开时加载(每 buffer 一次)
├── after/{plugin,ftplugin}/ runtimepath 末尾加载,用于覆盖默认
├── lua/<mod>/init.lua require('mod') 触发,不会自动执行
├── queries/<lang>/*.scm Treesitter 查询
├── colors/<scheme>.lua :colorscheme 触发
└── doc/*.txt :h 文档(:helptags 生成 tags)
核心规则:
-
lua/是惰性的(require 触发) -
plugin/是主动的(启动加载) - 副作用集中到
M.setup(opts)
-- lua/myplug/init.lua
local M = {}
---@class MyPlugConfig
---@field border string @default 'rounded'
---@field debug boolean @default false
local defaults = { border = 'rounded', debug = false }
---@param opts MyPlugConfig?
function M.setup(opts)
M.config = vim.tbl_deep_extend('force', defaults, opts or {})
vim.validate('border', M.config.border, 'string')
vim.api.nvim_create_user_command('MyPlug', function()
M.hello()
end, {})
end
function M.hello()
vim.notify('hi from myplug', vim.log.levels.INFO)
end
return M-- lua/myplug/health.lua
local M = {}
function M.check()
vim.health.start('myplug')
if vim.fn.executable('rg') == 1 then
vim.health.ok('rg found')
else
vim.health.error('ripgrep not installed')
end
end
return M调用 :checkhealth myplug
常用调试:
-
vim.print(x)=print(vim.inspect(x)) vim.notify(msg, vim.log.levels.WARN)-
:messages看历史 -
:lua =vim.o.runtimepath快查值
| 工具 | 特点 |
|---|---|
plenary.nvim (PlenaryBustedDirectory) |
生态最广,busted 语法 |
| mini.test | 无依赖、支持 child Nvim 进程 |
| busted + nlua | 纯 CLI,CI 最轻 |
mkdir -p ~/plugins/myplug/{lua/myplug,plugin,doc} && cd $_ && git init- 写
lua/myplug/init.lua:导出M.setup(opts)+ demo 函数 - 写
plugin/myplug.lua:nvim_create_user_command('MyPlug', ...) - 本地测试:
vim.pack.add({ 'file:///abs/path/to/myplug' });在本配置中也可把仓库放入vendors/,由pack.dev自动重定向 - 加 autocmd demo:
nvim_create_augroup+nvim_create_autocmd - 玩 extmark:
nvim_create_namespace+nvim_buf_set_extmark - 写
doc/myplug.txt(带*myplug-setup*tag),:helptags doc/,:h myplug验证 - 加
lua/myplug/health.lua,:checkhealth myplug
-
:h lua/:h api/:h lsp/:h treesitter/:h vim.diagnostic -
:h write-plugin(插件作者规范) -
:h news-0.11/:h news-0.12(新特性) - 源码:
neovim/neovim/runtime/lua/vim/ - 文档:
runtime/doc/*.txt