- 安装 luarocks
- 在 Neovim 内使用 luarocks
- 使用 nvim-plug 下载 rocks
- luarocks 的限制
- 将插件发布到 LuaRocks
- 模块载入问题
- 排除问题
- Neovim 终端中使用
luarocks 是 lua 常用的包管理器,类似于 python 的 pip。前面使用 Lua 实现了一个 Neovim 的插件管理器,而目前我自己正在维护的插件也都是使用 Lua 来实现的。 因此使用 luarocks 来管理插件,同时又让插件管理器 nvim-plug 支持 luarocks 就显得很有必要了。看了下目前主流的插件管理器 lazy.nvim、rocks.nvim 也是支持 luarcoks 的。
安装 luarocks
在 Windows 下可以使用 scoop 命令进行安装:
scoop install luarocks
这里需要注意一下,上述命令会自动安装 lua 5.4,但是 Neovim 内默认使用的是 luajit 兼容的 lua 5.1。因此为了避免下载的 rocks 不兼容。可以再执行以下命令:
scoop uninstall lua
scoop install lua51
安装完成后检查一下:
luarocks config | rg deploy
输出内容:
deploy_bin_dir = "D:\\Scoop\\apps\\luarocks\\current\\rocks\\bin"
deploy_lib_dir = "D:\\Scoop\\apps\\luarocks\\current\\rocks\\lib\\lua\\5.1"
deploy_lua_dir = "D:\\Scoop\\apps\\luarocks\\current\\rocks\\share\\lua\\5.1"
在 Neovim 内使用 luarocks
在 Neovim 内使用 :lua 命令或者使用 lua 开发 Neovim 插件时,
若想要使用 luarocks 安装的包,其原理就是将 luarocks 所安装的包位置加入到
package.path 和 package.cpath:
nvim-plug 中实现这一步骤的逻辑如下:
function M.enable()
if enabled then
return
end
local ok, _ = pcall(function()
local luarocks_config = vim.json.decode(
vim.system({ 'luarocks', 'config', '--json' }):wait().stdout
)
package.path = package.path
.. ';'
.. luarocks_config.deploy_lua_dir
.. [[\?.lua]]
.. ';'
.. luarocks_config.deploy_lua_dir
.. [[\?\init.lua]]
.. ';'
package.cpath = package.cpath
.. ';'
.. luarocks_config.deploy_lib_dir
.. '\\?.'
.. luarocks_config.external_lib_extension
-- 此处,还可以将 luarcoks bin 目录加入到 PATH
vim.env.PATH = vim.env.PATH .. ';' .. luarocks_config.deploy_bin_dir
end)
if ok then
enabled = true
end
end
使用 nvim-plug 下载 rocks
可以在添加插件时,指定 type = 'rocks',比如:
return {
'wsdjeg/mru.nvim',
events = { 'UIEnter' },
opts = {
enable_cache = true,
ignore_path_regexs = {
'/.git/',
'/nvim/runtime/doc/',
'.mp3$',
'.mp4$',
'.png$',
'.jpg$',
'.exe$',
'nvim-mru.json$',
'tags$',
},
enable_logger = true,
sort_by = 'lastenter',
},
type = 'rocks',
desc = 'mru(most recently used) files',
}
参考以上方式添加插件后,nvim-plug 在安装插件时会自动调用 luarocks install plugin_name 这一命令。
luarocks 的限制
在实现完上述功能后,才发现 luarocks 这个包管理器似乎还有一些限制。比如:
-
不支持同时安装多个插件。
因为 nvim-plug 是使用异步 job 调用外部命令的,因此支持多线程。 但是起初实现后发现,当同时执行多个 luarocks install 命令时, 只有第一个是成功的,后续的命令都有会报这一错误:Error: command ‘install’ requires exclusive write access。
解决的办法是为 luarocks 实现单独的 tasks 序列,逐一执行,这样的话插件的安装会非常慢。一个是单线程,一个是 16 线程 (max_processes = 16)。
-
无法根据 plugSpec 获取的 rtp 目录位置
一个最简单 plugSpec 比如
{ 'wsdjeg/mru.nvim' }, 默认 type 是 git,我是可以获取到该插件默认的 runtimepath 值为plug.config.bundle_dir .. '/' .. 'wsdjeg/mru.nvim', 此时就可以根据这个目录是否存在来判断插件是否已安装。但是,这样一个 plugSpec:
return { 'wsdjeg/mru.nvim', type = 'rocks', }将无法获取到默认的 runtimepath 目录位置,因为他的格式是
D:/Scoop/apps/luarocks/current/rocks/lib/luarocks/rocks-5.1/mru.nvim/1.4.0-1最后面这个版本号,除非是 plugSpec 内指定,否则是无法判断到默认的值的。
最终的解决方案是分析 luarocks list 命令的输出内容,返回一个类似与这样的 lua table:
return { ['mru.nvim'] = { rtp = 'D:/Scoop/apps/luarocks/current/rocks/lib/luarocks/rocks-5.1/mru.nvim/1.4.0-1', }, ['rooter.nvim'] = { rtp = 'D:/Scoop/apps/luarocks/current/rocks/lib/luarocks/rocks-5.1/rooter.nvim/1.3.0-1', }, }
将插件发布到 LuaRocks
这里主要使用到两个 Github actions:
- googleapis/release-please-action
- nvim-neorocks/luarocks-tag-release
使用 googleapis/release-please-action 来自动打 tag 并且新建 GitHub release,可以参考之前的文章《Github 仓库自动 release》。
使用 nvim-neorocks/luarocks-tag-release GitHub action 自动将 tag 上传到 luarocks.org。
在仓库根目录新建文件 .github/workflows/luarocks.yml:
name: Push to Luarocks
on:
push:
tags: # Will upload to luarocks.org when a tag is pushed
- "*"
pull_request: # Will test a local install without uploading to luarocks.org
workflow_dispatch:
jobs:
luarocks-upload:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: LuaRocks Upload
uses: nvim-neorocks/luarocks-tag-release@v7
env:
LUAROCKS_API_KEY: $
模块载入问题
neovim 中直接使用 rocks 似乎还有问题,dll 文件载入时会报错,估计跟 luarocks 的包编译方式有关
D:\wsdjeg\my-blog>luarocks list | rg file -A 2
luafilesystem
1.8.0-1 (installed) - D:\Scoop\apps\luarocks\current\rocks\lib\luarocks\rocks-5.1
然后在 Neovim 内执行 :lua require('lfs') 时,报错:
E5108: Error executing lua error loading module 'lfs' from file 'D:\Scoop\apps\luarocks\current\rocks\lib\lua\5.1\lfs.dll':
找不到指定的模块。
stack traceback:
[C]: at 0x7ff83ac1bdb0
[C]: in function 'require'
[string ":lua"]:1: in main chunk
实际上这个 dll 文件是存在的:
D:\Scoop\apps\luarocks\current\rocks\lib\lua\5.1>ls
lfs.dll
排除问题
使用 scoop 安装 dependencies,
scoop install dependencies
打开 lfs.dll 文件,发现确实是依赖问题:

在 lua51 的安装目录里:
D:\Scoop\apps\lua51\current>ls
Microsoft.VC80.CRT install.json lua5.1.dll.manifest lua51.dll manifest.json
bin2c5.1.exe liblua5.1.a lua5.1.exe lua51.dll.manifest wlua5.1.exe
include lua5.1.dll lua5.1.exe.manifest luac5.1.exe wlua5.1.exe.manifest
而 Neovim 中 :lua 调用的是:
D:\Scoop\apps\neovim\current\bin>ls
dbghelp.dll lua51.dll nvim.exe platforms win32yank.exe xxd.exe
使用 scoop 安装 luajit:
scoop install luajit
看下 luajit 的目录结构
D:\Scoop\apps\luajit/..
2.1.1762795099-1
current ➛ 2.1.1762795099-1
bin
lua51.dll
luajit
luajit-2.1.1762795099.exe
luajit.exe
include/luajit-2.1
lauxlib.h
lua.h
lua.hpp
luaconf.h
luajit.h
lualib.h
lib
share
install.json
manifest.json
修改 D:\Scoop\apps\luarocks\current\config.lua 为:
lua_interpreter = "D:/Scoop/apps/luajit/current/bin/luajit.exe"
lua_version = "5.1"
rocks_trees = {
"D:/Scoop/apps/luarocks/current/rocks"
}
variables = {
LUA = "D:/Scoop/apps/luajit/current/bin/luajit.exe",
LUA_BINDIR = "D:/Scoop/apps/luajit/current/bin",
LUA_INCDIR = "D:/Scoop/apps/luajit/current/include/luajit-2.1",
LUA_DIR = "D:/Scoop/apps/luajit/current/bin"
}
重新安装 luafilesystem:
luarocks install luafilesystem --force
此时再使用 Dependencies 查看 lfs.dll:

此时在 Neovim 中执行 :=require('lfs') 就会看到:
{
_COPYRIGHT = "Copyright (C) 2003-2017 Kepler Project",
_DESCRIPTION = "LuaFileSystem is a Lua library developed to complement the set of functions related to file systems offered by the standard Lua distribution",
_VERSION = "LuaFileSystem 1.8.0",
attributes = <function 1>,
chdir = <function 2>,
currentdir = <function 3>,
dir = <function 4>,
link = <function 5>,
lock = <function 6>,
lock_dir = <function 7>,
mkdir = <function 8>,
rmdir = <function 9>,
setmode = <function 10>,
symlinkattributes = <function 11>,
touch = <function 12>,
unlock = <function 13>
}
Neovim 终端中使用
为了能在 Neovim 内置终端中使用 lua,luajit,luarocks 等,给 nvim-plug 增加这样一个 patch:
diff --git a/lua/plug/rocks/init.lua b/lua/plug/rocks/init.lua
index e336791..58f391d 100644
--- a/lua/plug/rocks/init.lua
+++ b/lua/plug/rocks/init.lua
@@ -71,6 +71,8 @@ function M.enable()
.. luarocks_config.deploy_lib_dir
.. '\\?.'
.. luarocks_config.external_lib_extension
+ vim.env.LUA_PATH = package.path
+ vim.env.LUA_CPATH = package.cpath
end)
if ok then
enabled = true
这样在 Neovim 内置终端内使用 lua 命令,或者 luajit 命令,就会自动读取这两个变量值。
D:\wsdjeg\my-blog>lua
Lua 5.1.5 Copyright (C) 1994-2012 Lua.org, PUC-Rio
> print(require('lfs'))
table: 00000000004DCAC0
>
D:\wsdjeg\my-blog>luajit
LuaJIT 2.1.1762795099 -- Copyright (C) 2005-2025 Mike Pall. https://luajit.org/
JIT: ON SSE3 SSE4.1 BMI2 fold cse dce fwd dse narrow loop abc sink fuse
> print(require('lfs'))
table: 0x01f72937bc70
>
D:\wsdjeg\my-blog>echo print(require("lfs")) | nvim -l -
table: 0x01dcba84a148