Written by: algebnaly
Date: 2025-07-19T09:58:03.000Z
假定有如下的文本行
A = 0
B = 42
C = 100
我们希望把它转化为
0 => Ok(A)
42 => Ok(B)
100 => Ok(C)
使用nvim的宏当然也可以做到, 但是需要操作register, 而且这还是问题比较简单的情况, 如果一行需要的操作多一点, 使用宏就非常容易出错了. 幸运的是, 我们可以使用lua脚本.
我们可以使用lua脚本定义一个函数来对一行进行操作, 接着, 绑定按键到该函数, 对这些行进行重复操作.我没有系统地学过lua, 只能凭借一些探索来使用lua脚本. 但这对我来说已经足够了.
首先, lua脚本的位置可以相对于当前文件夹, 或者相对于$XDG_CONFIG_HOME/nvim/lua,当然还有其它搜索路径, 但一般使用这两个目录就够了.
以lua脚本的位置是相对于当前文件夹为例, 假定脚本文件放在./my-script/convert.lua,
文件内容为
print("hello")
function Foo()
print("hi, from Foo")
end
return Foo
那么我们可以在nvim中使用如下命令来使用该lua脚本:
:lua require("my-script/convert")
我们可以看到nvim输出了
hello
再次运行
:lua require("my-script/convert")
这次没有任何输出, 这说明:lua require("my-script/convert") 和python的import有点像, 不会重复导入同一个模块.
注意到我们的lua脚本中包含一个return语句, 返回了一个函数, 我们可以尝试调用这个返回的函数:
:lua require("my-script/convert")()
现在nvim输出了
hi, from Foo
这说明导入模块时, 返回的东西被缓存了. 我们可以直接使用返回的东西, 在这里就是返回的函数Foo.
现在我们修改脚本./my-script/convert.lua为如下内容
local M = {}
function M.convert_line(line)
-- 匹配模式:捕获变量名和值
local pattern = "^%s*([%w_]+)%s*=%s*([%w%-]+)%s*$"
local var_name, value = line:match(pattern)
if var_name and value then
-- 构造新行
local new_line = string.format("%s => Ok(%s)", value, var_name)
return new_line
else
-- 匹配失败则返回原行
return line
end
end
-- 处理当前行
function M.process_current_line()
local line = vim.api.nvim_get_current_line()
local new_line = M.convert_line(line)
vim.api.nvim_set_current_line(new_line)
end
-- 设置键盘映射
function M.setup_keymaps()
-- 普通模式:转换当前行
vim.keymap.set('n', '<leader>nf', M.process_current_line,
{ desc = 'Convert current line to target format' })
end
function M.setup()
M.setup_keymaps()
end
return M
上面的脚本应该相当容易理解, 我们定义了一个lua的table, table中定义了几个函数, 从名称上都比较容易理解:
M.convert_line将一行字符串转换成目标字符串.M.process_current_line使用vim api获取当前行, 调用M.convert_line转换, 然后再调用vim api设置当前行.M.setup_keymaps被调用时使用vim api设置按键映射, <leader>默认为反斜杠"\", 即在normal模式下输入\nf即可调用M.process_current_line.M.setup调用M.setup_keymaps完成按键映射.我们使用如下命令来导入我们编写好的脚本
:lua require("my-script/convert").setup()
注意, 在require(...)后, 我们立即对返回的M调用了setup(), 即调用了M.setup()于是按键映射被绑定, 接下来我们就可以使用快捷键\nf来调用M.process_current_line处理当前行了.