nvim使用lua脚本进行编辑

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脚本.

使用nvim的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中定义了几个函数, 从名称上都比较容易理解:

我们使用如下命令来导入我们编写好的脚本

:lua require("my-script/convert").setup()

注意, 在require(...)后, 我们立即对返回的M调用了setup(), 即调用了M.setup()于是按键映射被绑定, 接下来我们就可以使用快捷键\nf来调用M.process_current_line处理当前行了.