|
|
@ -6,11 +6,11 @@ |
|
|
|
|
|
|
|
## 目录 |
|
|
|
|
|
|
|
- [在 neovim 中使用 Lua](#在-neovim-中使用-lua) |
|
|
|
- [在 Neovim 中使用 Lua](#在-neovim-中使用-lua) |
|
|
|
- [目录](#目录) |
|
|
|
- [简介](#简介) |
|
|
|
- [学习 Lua](#学习-lua) |
|
|
|
- [现有的一些在 neovim 中使用 Lua 的教程](#现有的一些在-neovim-中使用-lua-的教程) |
|
|
|
- [现有的一些在 Neovim 中使用 Lua 的教程](#现有的一些在-neovim-中使用-lua-的教程) |
|
|
|
- [相关插件](#相关插件) |
|
|
|
- [Lua 文件位置](#lua-文件位置) |
|
|
|
- [警告](#警告) |
|
|
@ -59,23 +59,23 @@ |
|
|
|
|
|
|
|
## 简介 |
|
|
|
|
|
|
|
Lua 作为 Neovim 中的一等语言的集成正在成为它的杀手级特性之一。 然而,学习如何用 Lua 编写插件的教程数量并不像用 Vimscript 编写插件那样多。 这是一种尝试,试图提供一些基本信息,让人们可以使用 Lua 编写 neovim 插件。 |
|
|
|
本指南假定您使用的是最新的 Neovim[Nighly build](https://github.com/neovim/neovim/releases/tag/nightly)]。 由于 Neovim 的 0.5 版本是开发版本,请记住,正在积极开发的一些 API 并不十分稳定, |
|
|
|
在发布之前可能会发生变化。 |
|
|
|
Lua 作为 Neovim 中的一等语言的集成正在成为它的杀手级特性之一。然而,学习如何用 Lua 编写插件的教程数量并不像用 Vimscript 编写插件那样多。这是一种尝试,试图提供一些基本信息,让人们可以使用 Lua 编写 Neovim 插件。 |
|
|
|
|
|
|
|
本指南假定您使用的是最新的 Neovim [Nighly build](https://github.com/neovim/neovim/releases/tag/nightly)。由于 Neovim 的 0.5 版本是开发版本,请记住,正在积极开发的一些 API 并不十分稳定,在发布之前可能会发生变化。 |
|
|
|
|
|
|
|
### 学习 Lua |
|
|
|
|
|
|
|
不同于原版教程,一下资源适用于国内用户: |
|
|
|
不同于原版教程,以下资源适用于国内用户: |
|
|
|
- [在 Y 分钟内学习 X 关于 Lua 的页面](https://learnxinyminutes.com/docs/lua/) |
|
|
|
- [Lua 菜鸟教程](https://www.runoob.com/lua/lua-tutorial.html) |
|
|
|
- [Lua 用户维基](http://lua-users.org/wiki/LuaDirectory) |
|
|
|
- [Lua 的官方参考手册](https://www.lua.org/manual/5.1/) |
|
|
|
|
|
|
|
Lua 是一种非常干净和简单的语言。 它很容易学习,特别是如果你有其他编程语言基础的例如 typescript/javascript 等,会更加容易上手 Lua。注意:Neovim 嵌入的 Lua 版本是 LuaJIT 2.1.0,它与 Lua 5.1 保持兼容(带有几个 5.2 扩展) |
|
|
|
Lua 是一种非常干净和简单的语言。它很容易学习,特别是如果你有其他编程语言基础的例如 TypeScript / JavaScript 等,会更加容易上手 Lua。注意:Neovim 嵌入的 Lua 版本是 LuaJIT 2.1.0,它与 Lua 5.1 保持兼容(带有几个 5.2 扩展) |
|
|
|
|
|
|
|
### 现有的一些在 neovim 中使用 Lua 的教程 |
|
|
|
### 现有的一些在 Neovim 中使用 Lua 的教程 |
|
|
|
|
|
|
|
已经编写了一些教程来帮助人们用 Lua 编写插件。 他们中的一些人在写这本指南时提供了不少的帮助。 非常感谢它们的作者。 |
|
|
|
已经编写了一些教程来帮助人们用 Lua 编写插件。他们中的一些人在写这本指南时提供了不少的帮助。非常感谢它们的作者。 |
|
|
|
|
|
|
|
- [teukka.tech - 从 init.vim 转到 init.lua](https://teukka.tech/luanvim.html) |
|
|
|
- [2n.pl - 如何使用 Lua 编写 neovim 插件](https://www.2n.pl/blog/how-to-write-neovim-plugins-in-lua.md) |
|
|
@ -96,7 +96,7 @@ Lua 是一种非常干净和简单的语言。 它很容易学习,特别是如 |
|
|
|
|
|
|
|
## Lua 文件位置 |
|
|
|
|
|
|
|
Lua 文件通常位于您的`runtimepath`中的`lua/`文件夹中(对于大多数用户来说,在*nix 系统上为`~/.config/nvim/lua`,在 Windows 系统上为`~/appdata/Local/nvim/lua`)。 `Package.path`和`Package.cpath`全局变量会自动调整为包含该文件夹下的 Lua 文件。 这意味着您可以`require()`这些文件作为 Lua 模块 |
|
|
|
Lua 文件通常位于您的 `runtimepath` 中的 `lua/` 文件夹中(对于大多数用户来说,在 *nix 系统上为 `~/.config/nvim/lua`,在 Windows 系统上为 `~/appdata/Local/nvim/lua`)。`Package.path` 和 `Package.cpath` 全局变量会自动调整为包含该文件夹下的 Lua 文件。这意味着您可以 `require()` 这些文件作为 Lua 模块 |
|
|
|
|
|
|
|
我们以下面的文件夹结构为例: |
|
|
|
|
|
|
@ -115,15 +115,15 @@ Lua 文件通常位于您的`runtimepath`中的`lua/`文件夹中(对于大多 |
|
|
|
└── 🇻 init.vim |
|
|
|
``` |
|
|
|
|
|
|
|
下面的 Lua 代码将加载`myluamodule.lua` |
|
|
|
下面的 Lua 代码将加载 `myluamodule.lua` |
|
|
|
|
|
|
|
```lua |
|
|
|
require('myluamodule') |
|
|
|
``` |
|
|
|
|
|
|
|
注意没有`.lua`扩展名。 |
|
|
|
注意没有 `.lua` 扩展名。 |
|
|
|
|
|
|
|
类似地,加载`ther_module/anthermodule e.lua`的过程如下: |
|
|
|
类似地,加载 `other_modules/anothermodule.lua` 的过程如下: |
|
|
|
|
|
|
|
```lua |
|
|
|
require('other_modules.anothermodule') |
|
|
@ -131,9 +131,9 @@ require('other_modules.anothermodule') |
|
|
|
require('other_modules/anothermodule') |
|
|
|
``` |
|
|
|
|
|
|
|
路径分隔符可以用点`.`表示,也可以用斜杠`/`表示。 |
|
|
|
路径分隔符可以用点 `.` 表示,也可以用斜杠 `/` 表示。 |
|
|
|
|
|
|
|
文件夹如果包含`init.lua`文件,可以直接引用该文件夹而不必指定该文件的名称 |
|
|
|
文件夹如果包含 `init.lua` 文件,可以直接引用该文件夹而不必指定该文件的名称 |
|
|
|
|
|
|
|
```lua |
|
|
|
require('other_modules') -- loads other_modules/init.lua |
|
|
@ -143,32 +143,32 @@ require('other_modules') -- loads other_modules/init.lua |
|
|
|
|
|
|
|
#### 警告 |
|
|
|
|
|
|
|
与.vim 文件不同,.lua 文件不会自动从您的`runtimepath`目录中获取。 相反,您必须从 Vimscript source/require 它们。 计划增加`init.lua`文件加载选项,替代`init.vim`: |
|
|
|
与 .vim 文件不同,.lua 文件不会自动从您的 `runtimepath` 目录中获取。相反,您必须从 Vimscript source/require 它们。计划增加 `init.lua` 文件加载选项,替代 `init.vim`: |
|
|
|
- [Issue #7895](https://github.com/neovim/neovim/issues/7895) |
|
|
|
- [Corresponding pull request](https://github.com/neovim/neovim/pull/12235) |
|
|
|
|
|
|
|
#### 提示 |
|
|
|
|
|
|
|
多个 Lua 插件在它们的`lua/`文件夹中可能有相同的文件名。 这可能会导致命名空间冲突。如果两个不同的插件有一个`lua/main.lua`文件,那么执行`require('main')`是不明确的:我们想要加载哪个文件?最好将您的配置或插件命名为顶级文件夹, |
|
|
|
多个 Lua 插件在它们的 `lua/` 文件夹中可能有相同的文件名。这可能会导致命名空间冲突。如果两个不同的插件有一个 `lua/main.lua` 文件,那么执行 `require('main')` 是不明确的:我们想要加载哪个文件?最好将您的配置或插件命名为顶级文件夹, |
|
|
|
例如这样的形式:`lua/plugin_name/main.lua`。 |
|
|
|
|
|
|
|
#### 包说明 |
|
|
|
|
|
|
|
如果您是`package`特性的用户或基于它的插件管理器例如 [packer.nvim](https://github.com/wbthomason/packer.nvim),[minpac](https://github.com/k-takata/minpac) 或 [vim-packager](https://github.com/kristijanhusak/vim-packager/),那么在使用 Lua 插件时需要注意一些事情。`start`文件夹中的包只有在源化您的`init.vim`之后才会加载。 这意味着只有在 Neovim 处理完文件之后,才会将包添加到`runtimepath`中。如果插件期望 |
|
|
|
`require`一个 Lua 模块或调用自动加载的函数,这可能会导致问题。假设包`start/foo`有一个`lua/bar.lua`文件,从您的`init.vim`执行此操作将引发错误,因为`runtimepath`尚未更新。 |
|
|
|
如果您是 `package` 特性的用户或基于它的插件管理器例如 [packer.nvim](https://github.com/wbthomason/packer.nvim),[minpac](https://github.com/k-takata/minpac) 或 [vim-packager](https://github.com/kristijanhusak/vim-packager/),那么在使用 Lua 插件时需要注意一些事情。`start` 文件夹中的包只有在源化您的 `init.vim` 之后才会加载。这意味着只有在 Neovim 处理完文件之后,才会将包添加到 `runtimepath` 中。如果插件期望 |
|
|
|
`require` 一个 Lua 模块或调用自动加载的函数,这可能会导致问题。假设包 `start/foo` 有一个 `lua/bar.lua` 文件,从您的 `init.vim` 执行此操作将引发错误,因为 `runtimepath` 尚未更新。 |
|
|
|
|
|
|
|
```vim |
|
|
|
lua require('bar') |
|
|
|
``` |
|
|
|
|
|
|
|
你需要使用`packadd! foo`命令在`require` 这个模块之前 |
|
|
|
你需要使用 `packadd! foo` 命令在 `require` 这个模块之前 |
|
|
|
|
|
|
|
```vim |
|
|
|
packadd! foo |
|
|
|
lua require('bar') |
|
|
|
``` |
|
|
|
|
|
|
|
在`Packadd`后附加`!`表示 Neovim 会将包放在`runtimepath`中,而不会在其`plugin`或`ftDetect`目录下寻找任何脚本。 |
|
|
|
在 `Packadd` 后附加 `!` 表示 Neovim 会将包放在 `runtimepath` 中,而不会在其 `plugin` 或 `ftDetect` 目录下寻找任何脚本。 |
|
|
|
|
|
|
|
See also: |
|
|
|
- `:help :packadd` |
|
|
@ -208,19 +208,19 @@ See also: |
|
|
|
|
|
|
|
#### 警告 |
|
|
|
|
|
|
|
在 vim 文件中编写 Lua 时,您不会得到正确的语法突出显示。 使用`:lua`命令作为需要外部 Lua 文件的入口点可能会更方便。 |
|
|
|
在 Vim 文件中编写 Lua 时,您不会得到正确的语法突出显示。使用 `:lua` 命令作为需要外部 Lua 文件的入口点可能会更方便。 |
|
|
|
|
|
|
|
### :luado |
|
|
|
|
|
|
|
该命令执行一段 Lua 代码,该代码作用于当前缓冲区中的选中的行。 如果未指定范围,则改为使用整个缓冲区。 从块`return`的任何字符串都用于确定应该用什么替换每行。 |
|
|
|
该命令执行一段 Lua 代码,该代码作用于当前缓冲区中的选中的行。如果未指定范围,则改为使用整个缓冲区。从块 `return` 的任何字符串都用于确定应该用什么替换每行。 |
|
|
|
|
|
|
|
以下命令会将当前缓冲区中的每一行替换为文本`hello world` |
|
|
|
以下命令会将当前缓冲区中的每一行替换为文本 `hello world` |
|
|
|
|
|
|
|
```vim |
|
|
|
:luado return 'hello world' |
|
|
|
``` |
|
|
|
|
|
|
|
提供了两个隐式的`line`和`linenr`变量。 `line`是被迭代的行的文本,而`linenr`是它的编号。 以下命令将可以被 2 整数的行转成大写: |
|
|
|
提供了两个隐式的 `line` 和 `linenr` 变量。`line` 是被迭代的行的文本,而 `linenr` 是它的编号。以下命令将可以被 2 整数的行转成大写: |
|
|
|
|
|
|
|
```vim |
|
|
|
:luado if linenr % 2 == 0 then return line:upper() end |
|
|
@ -238,7 +238,7 @@ See also: |
|
|
|
:luafile ~/foo/bar/baz/myluafile.lua |
|
|
|
``` |
|
|
|
|
|
|
|
类似于 vim 的`:source`命令或 Lua 内置的`dofile()`函数。 |
|
|
|
类似于 Vim 的 `:source` 命令或 Lua 内置的 `dofile()` 函数。 |
|
|
|
|
|
|
|
See also: |
|
|
|
|
|
|
@ -246,18 +246,18 @@ See also: |
|
|
|
|
|
|
|
#### luafile 对比 require(): |
|
|
|
|
|
|
|
您可能想知道`lua request()`和`luafile`之间的区别是什么,以及您是否应该使用其中一个而不是另一个。 它们有不同的使用情形: |
|
|
|
您可能想知道 `lua request()` 和 `luafile` 之间的区别是什么,以及您是否应该使用其中一个而不是另一个。它们有不同的使用情形: |
|
|
|
|
|
|
|
- `require()`: |
|
|
|
- 是内置的 Lua 函数,它允许你使用 Lua 的模块系统。 |
|
|
|
- 使用`Package.path`变量搜索模块(如前所述,您可以使用`runtimepath`中的`lua/`文件夹内的`required()`lua 脚本) |
|
|
|
- 跟踪已加载的模块,并防止第二次解析和执行脚本。 如果您更改包含某个模块代码的文件,并在 Neovim 运行时再次尝试‘required()’,则该模块实际上不会更新。 |
|
|
|
- 使用 `Package.path` 变量搜索模块(如前所述,您可以使用 `runtimepath` 中的 `lua/` 文件夹内的 `required()` lua 脚本) |
|
|
|
- 跟踪已加载的模块,并防止第二次解析和执行脚本。如果您更改包含某个模块代码的文件,并在 Neovim 运行时再次尝试 `required()`,则该模块实际上不会更新。 |
|
|
|
- `:luafile`: |
|
|
|
- 是一个执行命令,它不支持模块。 |
|
|
|
- 采用相对于当前窗口的工作目录的绝对或相对路径 |
|
|
|
- 执行脚本的内容,而不管该脚本以前是否执行过 |
|
|
|
|
|
|
|
如果您想运行您正在处理的 Lua 文件,`:luafile`很有用: |
|
|
|
如果您想运行您正在处理的 Lua 文件,`:luafile` 很有用: |
|
|
|
|
|
|
|
```vim |
|
|
|
:luafile % |
|
|
@ -265,7 +265,7 @@ See also: |
|
|
|
|
|
|
|
### luaeval() |
|
|
|
|
|
|
|
`luaeval()`是内置的 Vimscript 函数计算 Lua 表达式字符串并返回它的值。 Lua 的数据类型自动转换为 Vimscript 类型(反之亦然)。 |
|
|
|
`luaeval()` 是内置的 Vimscript 函数计算 Lua 表达式字符串并返回它的值。Lua 的数据类型自动转换为 Vimscript 类型(反之亦然)。 |
|
|
|
|
|
|
|
```vim |
|
|
|
" 你可以将结果存储到一个变量中 |
|
|
@ -276,15 +276,15 @@ let concat = luaeval('"Lua".." is ".."awesome"') |
|
|
|
echo concat |
|
|
|
" 'Lua is awesome' |
|
|
|
|
|
|
|
" Lua 中的 table 数组转成成 vimscript 的 list |
|
|
|
" Lua 中的 table 数组转成成 Vimscript 的 list |
|
|
|
let list = luaeval('{1, 2, 3, 4}') |
|
|
|
echo list[0] |
|
|
|
" 1 |
|
|
|
echo list[1] |
|
|
|
" 2 |
|
|
|
" 注意 vimscript 的数组索引下标与 Lua 不同是从 0 开始的,Lua 中是从 1 开始 |
|
|
|
" 注意 Vimscript 的数组索引下标与 Lua 不同是从 0 开始的,Lua 中是从 1 开始 |
|
|
|
|
|
|
|
" Lua 中类似 dict 的 table 会被转成 vimscript 中的 dict |
|
|
|
" Lua 中类似 dict 的 table 会被转成 Vimscript 中的 dict |
|
|
|
let dict = luaeval('{foo = "bar", baz = "qux"}') |
|
|
|
echo dict.foo |
|
|
|
" 'bar' |
|
|
@ -307,7 +307,7 @@ lua X = function(k, v) return string.format("%s:%s", k, v) end |
|
|
|
echo map([1, 2, 3], luaeval("X")) |
|
|
|
``` |
|
|
|
|
|
|
|
`luaeval()`接受可选的第二个参数,该参数允许您将数据传递给表达式。 然后您可以使用全局的`_A`从 Lua 访问该数据: |
|
|
|
`luaeval()` 接受可选的第二个参数,该参数允许您将数据传递给表达式。然后您可以使用全局的 `_A` 从 Lua 访问该数据: |
|
|
|
|
|
|
|
```vim |
|
|
|
echo luaeval('_A[1] + _A[2]', [1, 1]) |
|
|
@ -322,7 +322,7 @@ See also: |
|
|
|
|
|
|
|
### v:lua |
|
|
|
|
|
|
|
这个全局 Vim 变量允许您直接从 Vimscript 调用全局 Lua 函数。 同样 Vim 数据类型被转换为 Lua 类型,反之亦然。 |
|
|
|
这个全局 Vim 变量允许您直接从 Vimscript 调用全局 Lua 函数。同样 Vim 数据类型被转换为 Lua 类型,反之亦然。 |
|
|
|
|
|
|
|
```vim |
|
|
|
call v:lua.print('Hello from Lua!') |
|
|
@ -376,7 +376,7 @@ See also: |
|
|
|
|
|
|
|
#### Caveats |
|
|
|
|
|
|
|
此变量只能用于调用函数。 以下代码将始终引发错误: |
|
|
|
此变量只能用于调用函数。以下代码将始终引发错误: |
|
|
|
|
|
|
|
```vim |
|
|
|
" Aliasing functions doesn't work |
|
|
@ -391,22 +391,22 @@ echo map([1, 2, 3], v:lua.global_callback) |
|
|
|
|
|
|
|
## Vim 命名空间 |
|
|
|
|
|
|
|
Neovim 会暴露一个全局的`vim`变量来作为 lua 调用 vim 的 APIs 的入口。它还提供给用户一些额外的函数和子模块“标准库” |
|
|
|
Neovim 会暴露一个全局的 `vim` 变量来作为 Lua 调用 Vim 的 APIs 的入口。它还提供给用户一些额外的函数和子模块“标准库” |
|
|
|
|
|
|
|
一些比较实用的函数和子模块如下: |
|
|
|
|
|
|
|
- `vim.inspect`: 把 lua 对象以更易读的方式打印(在打印 lua table 是会很有用) |
|
|
|
- `vim.regex`: 在 lua 中使用 vim 寄存器 |
|
|
|
- `vim.inspect`: 把 Lua 对象以更易读的方式打印(在打印 Lua table 时会很有用) |
|
|
|
- `vim.regex`: 在 Lua 中使用 Vim 寄存器 |
|
|
|
- `vim.api`: 暴露 vim 的 API(`:h API`) 的模块(别的远程调用也是调用同样的 API) |
|
|
|
- `vim.loop`: Neovim 的 event lopp 模块(使用 LibUV) |
|
|
|
- `vim.lsp`: 控制内置 LSP 客户端的模块 |
|
|
|
- `vim.treesitter`: 暴露 tree-sitter 库中一些实用函数的模块 |
|
|
|
|
|
|
|
上面列举功能的并不全面。如果你想知道更多可行的操作可以看:`:help lua-stdlib`和`help lua-vim`。你也可以通过`:lua print(vim.inspect(vim))`所有可用模块 |
|
|
|
上面列举功能的并不全面。如果你想知道更多可行的操作可以看:`:help lua-stdlib` 和 `help lua-vim`。你也可以通过 `:lua print(vim.inspect(vim))` 获得所有可用模块 |
|
|
|
|
|
|
|
#### Tips |
|
|
|
|
|
|
|
每次你想检查一个对象时到要用`print(vim.inspect(x))`是相当繁琐的。你可以你的配置中写一个全局的包装器函数来替代这个繁琐的过程 |
|
|
|
每次你想检查一个对象时到要用 `print(vim.inspect(x))` 是相当繁琐的。你可以你的配置中写一个全局的包装器函数来替代这个繁琐的过程 |
|
|
|
|
|
|
|
```lua |
|
|
|
function _G.dump(...) |
|
|
@ -425,15 +425,15 @@ dump({1, 2, 3}) |
|
|
|
:lua dump(vim.loop) |
|
|
|
``` |
|
|
|
|
|
|
|
另外要注意的是,你可能会发现 Lua 会比其他语言少一些实用的内置函数(例如:`os.clock()`,返回以秒为单位,而不是以毫秒为单位的值)。仔细阅读 Neovim 提供的标准库和`vim.fn`(后续还会有更多内容),里面可以会有你想要的东西。 |
|
|
|
另外要注意的是,你可能会发现 Lua 会比其他语言少一些实用的内置函数(例如:`os.clock()`,返回以秒为单位,而不是以毫秒为单位的值)。仔细阅读 Neovim 提供的标准库和 `vim.fn` (后续还会有更多内容),里面可以会有你想要的东西。 |
|
|
|
|
|
|
|
## 在 Lua 中使用 Vimscript |
|
|
|
|
|
|
|
### vim.api.nvim_eval() |
|
|
|
|
|
|
|
此函数计算 Vimscript 表达式字符串并返回其值。 Vimscript 数据类型自动转换为 Lua 类型(反之亦然)。 |
|
|
|
此函数计算 Vimscript 表达式字符串并返回其值。Vimscript 数据类型自动转换为 Lua 类型(反之亦然)。 |
|
|
|
|
|
|
|
它等同于 vimscript 中的`luaeval()`函数 |
|
|
|
它等同于 vimscript 中的 `luaeval()` 函数 |
|
|
|
|
|
|
|
```lua |
|
|
|
-- Data types are converted correctly |
|
|
@ -448,11 +448,11 @@ print(vim.api.nvim_eval('v:null')) -- nil |
|
|
|
|
|
|
|
#### Caveats |
|
|
|
|
|
|
|
与`luaeval()`不同,`vim.api.nvim_eval()`不提供隐式`_A`变量来传递数据给表达式。 |
|
|
|
与 `luaeval()` 不同,`vim.api.nvim_eval()` 不提供隐式 `_A` 变量来传递数据给表达式。 |
|
|
|
|
|
|
|
### vim.api.nvim_exec() |
|
|
|
|
|
|
|
此函数用于计算 Vimscript 代码块。 它接受一个包含要执行的源代码的字符串和一个布尔值,以确定代码的输出是否应该由函数返回(例如,您可以将输出存储在变量中)。 |
|
|
|
此函数用于计算 Vimscript 代码块。它接受一个包含要执行的源代码的字符串和一个布尔值,以确定代码的输出是否应该由函数返回(例如,您可以将输出存储在变量中)。 |
|
|
|
|
|
|
|
```lua |
|
|
|
local result = vim.api.nvim_exec( |
|
|
@ -474,7 +474,7 @@ print(result) -- 'hello world' |
|
|
|
|
|
|
|
### vim.api.nvim_command() |
|
|
|
|
|
|
|
此函数执行一个 EX 命令。 它接受包含要执行的命令的字符串。 |
|
|
|
此函数执行一个 EX 命令。它接受包含要执行的命令的字符串。 |
|
|
|
|
|
|
|
```lua |
|
|
|
vim.api.nvim_command('new') |
|
|
@ -521,7 +521,7 @@ Neovim 提供了一组 API 函数来设置选项或获取其当前值: |
|
|
|
|
|
|
|
它们接受一个字符串,其中包含要设置或者要获取的选项的名称以及要将其设置为的值。 |
|
|
|
|
|
|
|
布尔选项(如`(no)number`) 必须设置为`true`或`false`: |
|
|
|
布尔选项(如 `(no)number`) 必须设置为 `true` 或 `false`: |
|
|
|
|
|
|
|
```lua |
|
|
|
vim.api.nvim_set_option('smarttab', false) |
|
|
@ -542,7 +542,7 @@ vim.api.nvim_set_option('updatetime', 3000) |
|
|
|
print(vim.api.nvim_get_option('updatetime')) -- 3000 |
|
|
|
``` |
|
|
|
|
|
|
|
Buffer-local 和 Window-local 选项还需要缓冲区编号或窗口编号(使用`0`将设置 / 获取当前缓冲区 / 窗口的选项): |
|
|
|
Buffer-local 和 Window-local 选项还需要缓冲区编号或窗口编号(使用 `0` 将设置 / 获取当前缓冲区 / 窗口的选项): |
|
|
|
|
|
|
|
```lua |
|
|
|
vim.api.nvim_win_set_option(0, 'number', true) |
|
|
@ -553,7 +553,7 @@ print(vim.api.nvim_buf_get_option(10, 'shiftwidth')) -- 4 |
|
|
|
|
|
|
|
### 使用元访问器 |
|
|
|
|
|
|
|
如果您想以更“惯用”的方式设置选项,可以使用一些元访问器。 它们本质上包装了上述 API 函数,并允许您像处理变量一样操作选项: |
|
|
|
如果您想以更“惯用”的方式设置选项,可以使用一些元访问器。它们本质上包装了上述 API 函数,并允许您像处理变量一样操作选项: |
|
|
|
|
|
|
|
- `vim.o.{option}`: 全局选项 |
|
|
|
- `vim.bo.{option}`: buffer-local 选项 |
|
|
@ -567,7 +567,7 @@ vim.bo.shiftwidth = 4 |
|
|
|
print(vim.bo.shiftwidth) -- 4 |
|
|
|
``` |
|
|
|
|
|
|
|
您可以为缓冲区本地和窗口本地选项指定一个数字。 如果未给出编号,则使用当前缓冲区 / 窗口: |
|
|
|
您可以为缓冲区本地和窗口本地选项指定一个数字。如果未给出编号,则使用当前缓冲区 / 窗口: |
|
|
|
|
|
|
|
```lua |
|
|
|
vim.bo[4].expandtab = true -- same as vim.api.nvim_buf_set_option(4, 'expandtab', true) |
|
|
@ -579,17 +579,17 @@ See also: |
|
|
|
|
|
|
|
#### Caveats |
|
|
|
|
|
|
|
**WARNING**:以下部分基于我做的几个实验。 文档似乎没有提到这种行为,我也没有检查源代码来验证我的声明。 |
|
|
|
**WARNING**:以下部分基于我做的几个实验。文档似乎没有提到这种行为,我也没有检查源代码来验证我的声明。 |
|
|
|
**TODO**:有谁能确认一下吗? |
|
|
|
|
|
|
|
如果您只使用`:set`命令处理过选项,那么某些选项的行为可能会让您大吃一惊。 |
|
|
|
如果您只使用 `:set` 命令处理过选项,那么某些选项的行为可能会让您大吃一惊。 |
|
|
|
本质上,选项可以是全局的、缓冲区 / 窗口的局部的,或者同时具有全局和局部值。 |
|
|
|
|
|
|
|
`:setglobal`命令用于设置选项的全局值。 |
|
|
|
`:setlocal`命令用于设置选项的本地值。 |
|
|
|
`:set`命令用于设置选项的全局和局部值。 |
|
|
|
`:setglobal` 命令用于设置选项的全局值。 |
|
|
|
`:setlocal` 命令用于设置选项的本地值。 |
|
|
|
`:set` 命令用于设置选项的全局和局部值。 |
|
|
|
|
|
|
|
这是`:help:setglobal`的简易表格: |
|
|
|
这是 `:help :setglobal` 的简易表格: |
|
|
|
|
|
|
|
| Command | global value | local value | |
|
|
|
|-------------------------|--------------|-------------| |
|
|
@ -597,21 +597,21 @@ See also: |
|
|
|
| :setlocal option=value | - | set | |
|
|
|
| :setglobal option=value | set | - | |
|
|
|
|
|
|
|
Lua 中没有`:set`命令的等价命令,可以全局设置,也可以本地设置。 |
|
|
|
您可能认为`number‘选项是全局的,但文档将其描述为`Windows-local`。 这样的选项实际上是“粘性的”:当您打开一个新窗口时,它们的值是从当前窗口复制过来的。 |
|
|
|
因此,如果您要从您的`init.lua`设置选项,您应该这样做: |
|
|
|
Lua 中没有 `:set` 命令的等价命令,可以全局设置,也可以本地设置。 |
|
|
|
您可能认为 `number` 选项是全局的,但文档将其描述为 `Windows-local`。这样的选项实际上是“粘性的”:当您打开一个新窗口时,它们的值是从当前窗口复制过来的。 |
|
|
|
因此,如果您要从您的 `init.lua` 设置选项,您应该这样做: |
|
|
|
|
|
|
|
```lua |
|
|
|
vim.wo.number = true |
|
|
|
``` |
|
|
|
|
|
|
|
`shiftwidth`、`expandtab`、`undofile`等`本地到缓冲区`的选项更容易混淆。 假设您的`init.lua`包含以下代码: |
|
|
|
`shiftwidth`、`expandtab`、`undofile` 等本地到缓冲区的选项更容易混淆。假设您的 `init.lua` 包含以下代码: |
|
|
|
|
|
|
|
```lua |
|
|
|
vim.bo.expandtab = true |
|
|
|
``` |
|
|
|
|
|
|
|
当你启动 Neovim 并开始编辑时,一切都很好:按下`<Tab>`键会插入空格,而不是制表符。 打开另一个缓冲区,您会突然返回到选项卡... |
|
|
|
当你启动 Neovim 并开始编辑时,一切都很好:按下 `<Tab>` 键会插入空格,而不是制表符。打开另一个缓冲区,您会突然返回到选项卡... |
|
|
|
|
|
|
|
在全局设置它具有相反的问题: |
|
|
|
|
|
|
@ -619,7 +619,7 @@ vim.bo.expandtab = true |
|
|
|
vim.o.expandtab = true |
|
|
|
``` |
|
|
|
|
|
|
|
这次,您在第一次启动 Neovim 时插入选项卡。 打开另一个缓冲区,然后按`<Tab>`即可实现预期效果。 |
|
|
|
这次,您在第一次启动 Neovim 时插入选项卡。打开另一个缓冲区,然后按 `<Tab>` 即可实现预期效果。 |
|
|
|
简而言之,如果您想要正确的行为,“本地到缓冲区”的选项必须这样设置: |
|
|
|
|
|
|
|
```lua |
|
|
@ -659,8 +659,8 @@ See also: |
|
|
|
- `vim.api.nvim_set_vvar()` |
|
|
|
- `vim.api.nvim_get_vvar()` |
|
|
|
|
|
|
|
除了预定义的 Vim 变量外,还可以删除它们(等同于 vimscript 中的`:unlet`)。 局部变量 (`l:`)、脚本变量 (s:`) 和函数参数 (`a:`) 不能操作,因为它们只在 Vim 脚本上下文中有意义,Lua 有自己的作用域规则。 |
|
|
|
如果您不熟悉这些变量的作用,请参考`:help internal-variables`对其进行详细介绍。 |
|
|
|
除了预定义的 Vim 变量外,还可以删除它们(等同于 Vimscript 中的 `:unlet`)。局部变量 (`l:`)、脚本变量 (`s:`) 和函数参数 (`a:`) 不能操作,因为它们只在 Vim 脚本上下文中有意义,Lua 有自己的作用域规则。 |
|
|
|
如果您不熟悉这些变量的作用,请参考 `:help internal-variables` 对其进行详细介绍。 |
|
|
|
这些函数接受一个字符串,该字符串包含要设置 / 获取 / 删除的变量的名称以及要将其设置为的值。 |
|
|
|
|
|
|
|
```lua |
|
|
@ -728,7 +728,7 @@ echo g:variable |
|
|
|
|
|
|
|
### vim.call() |
|
|
|
|
|
|
|
`vim.call()`调用 Vimscript 函数。 这可以是内置 Vim 函数,也可以是用户函数。 同样,数据类型在 Lua 和 Vimscript 之间来回转换。它接受函数名,后跟要传递给该函数的参数: |
|
|
|
`vim.call()` 调用 Vimscript 函数。这可以是内置 Vim 函数,也可以是用户函数。同样,数据类型在 Lua 和 Vimscript 之间来回转换。它接受函数名,后跟要传递给该函数的参数: |
|
|
|
|
|
|
|
```lua |
|
|
|
print(vim.call('printf', 'Hello from %s', 'Lua')) |
|
|
@ -750,7 +750,7 @@ See also: |
|
|
|
|
|
|
|
### vim.fn.{function}() |
|
|
|
|
|
|
|
`vim.fn`的功能与`vim.call()`完全相同,但看起来更像是原生 Lua 函数调用 |
|
|
|
`vim.fn` 的功能与 `vim.call()` 完全相同,但看起来更像是原生 Lua 函数调用 |
|
|
|
|
|
|
|
```lua |
|
|
|
print(vim.fn.printf('Hello from %s', 'Lua')) |
|
|
@ -765,7 +765,7 @@ end |
|
|
|
vim.fn.jobstart('ls', { on_stdout = print_stdout }) |
|
|
|
``` |
|
|
|
|
|
|
|
Hashes `#`不是 Lua 中识别符的有效字符,因此必须使用以下语法调用 autoload 函数: |
|
|
|
Hashes `#` 不是 Lua 中识别符的有效字符,因此必须使用以下语法调用 autoload 函数: |
|
|
|
|
|
|
|
```lua |
|
|
|
vim.fn['my#autoload#function']() |
|
|
@ -776,11 +776,11 @@ See also: |
|
|
|
|
|
|
|
#### Tips |
|
|
|
|
|
|
|
Neovim 有一个强大的内置函数库,这些函数对插件非常有用。 按字母顺序排列的函数列表参见`:help vim-function`,按主题分组的函数列表参见`:help function-list`。 |
|
|
|
Neovim 有一个强大的内置函数库,这些函数对插件非常有用。按字母顺序排列的函数列表参见 `:help vim-function`,按主题分组的函数列表参见 `:help function-list`。 |
|
|
|
|
|
|
|
#### Caveats |
|
|
|
|
|
|
|
一些应该返回布尔值的 Vim 函数返回`1`或`0`。 这在 Vimscript 中不是问题,因为`1‘是真的,而`0’是假的,支持如下结构: |
|
|
|
一些应该返回布尔值的 Vim 函数返回 `1` 或 `0`。这在 Vimscript 中不是问题,因为 `1` 是真的,而 `0` 是假的,支持如下结构: |
|
|
|
|
|
|
|
```vim |
|
|
|
if has('nvim') |
|
|
@ -788,7 +788,7 @@ if has('nvim') |
|
|
|
endif |
|
|
|
``` |
|
|
|
|
|
|
|
然而,在 Lua 中,只有`false`和`nil`被认为是假的,数字的计算结果总是`true`,无论它们的值是什么。 您必须显式检查`1`或`0`: |
|
|
|
然而,在 Lua 中,只有 `false` 和 `nil` 被认为是假的,数字的计算结果总是 `true`,无论它们的值是什么。您必须显式检查 `1` 或 `0`: |
|
|
|
|
|
|
|
```lua |
|
|
|
if vim.fn.has('nvim') == 1 then |
|
|
@ -809,7 +809,7 @@ Neovim 提供了一系列的 api 函数来设置获取和删除映射: |
|
|
|
- `vim.api.nvim_buf_get_keymap()` |
|
|
|
- `vim.api.nvim_buf_del_keymap()` |
|
|
|
|
|
|
|
让我们从`vim.api.nvim_set_keymap()`和`vim.api.nvim_buf_set_keymap()`开始,传递给函数的第一个参数是一个包含映射生效模式名称的字符串: |
|
|
|
让我们从 `vim.api.nvim_set_keymap()` 和 `vim.api.nvim_buf_set_keymap()` 开始,传递给函数的第一个参数是一个包含映射生效模式名称的字符串: |
|
|
|
|
|
|
|
| String value | Help page | Affected modes | Vimscript equivalent | |
|
|
|
|------------------------|---------------|------------------------------------------|----------------------| |
|
|
@ -825,13 +825,13 @@ Neovim 提供了一系列的 api 函数来设置获取和删除映射: |
|
|
|
| `'c'` | `mapmode-c` | Command-line | `:cmap` | |
|
|
|
| `'t'` | `mapmode-t` | Terminal | `:tmap` | |
|
|
|
|
|
|
|
第二个参数是包含映射左侧的字符串(触发映射中定义的命令的键或键集)。 空字符串相当于`<Nop>`,表示禁用键位。 |
|
|
|
第二个参数是包含映射左侧的字符串(触发映射中定义的命令的键或键集)。空字符串相当于 `<Nop>`,表示禁用键位。 |
|
|
|
|
|
|
|
第三个参数是包含映射右侧(要执行的命令)的字符串。 |
|
|
|
|
|
|
|
最后一个参数是一个表,包含`:help:map-arguments`中定义的映射的布尔值选项(包括`noremap`,不包括`buffer`)。 |
|
|
|
最后一个参数是一个表,包含 `:help :map-arguments` 中定义的映射的布尔值选项(包括 `noremap`,不包括 `buffer`)。 |
|
|
|
|
|
|
|
缓冲区-本地映射也将缓冲区编号作为其第一个参数 (`0`设置当前缓冲区的映射)。 |
|
|
|
缓冲区-本地映射也将缓冲区编号作为其第一个参数(`0` 设置当前缓冲区的映射)。 |
|
|
|
|
|
|
|
```lua |
|
|
|
vim.api.nvim_set_keymap('n', '<leader><Space>', ':set hlsearch!<CR>', { noremap = true, silent = true }) |
|
|
@ -841,28 +841,28 @@ vim.api.nvim_buf_set_keymap(0, '', 'cc', 'line(".") == 1 ? "cc" : "ggcc"', { nor |
|
|
|
-- :noremap <buffer> <expr> cc line('.') == 1 ? 'cc' : 'ggcc' |
|
|
|
``` |
|
|
|
|
|
|
|
`vim.api.nvim_get_keymap()`接受一个字符串,该字符串包含您想要映射列表的模式的短名称(见上表)。 返回值是包含该模式的所有全局映射的表。 |
|
|
|
`vim.api.nvim_get_keymap()` 接受一个字符串,该字符串包含您想要映射列表的模式的短名称(见上表)。返回值是包含该模式的所有全局映射的表。 |
|
|
|
|
|
|
|
```lua |
|
|
|
print(vim.inspect(vim.api.nvim_get_keymap('n'))) |
|
|
|
-- :verbose nmap |
|
|
|
``` |
|
|
|
|
|
|
|
`vim.api.nvim_buf_get_keymap()`将缓冲区编号作为其第一个参数 (`0`将获取当前缓冲区的映射) |
|
|
|
`vim.api.nvim_buf_get_keymap()` 将缓冲区编号作为其第一个参数 (`0` 将获取当前缓冲区的映射) |
|
|
|
|
|
|
|
```lua |
|
|
|
print(vim.inspect(vim.api.nvim_buf_get_keymap(0, 'i'))) |
|
|
|
-- :verbose imap <buffer> |
|
|
|
``` |
|
|
|
|
|
|
|
`vim.api.nvim_del_keymap()`获取映射左侧的模式。 |
|
|
|
`vim.api.nvim_del_keymap()` 获取映射左侧的模式。 |
|
|
|
|
|
|
|
```lua |
|
|
|
vim.api.nvim_del_keymap('n', '<leader><Space>') |
|
|
|
-- :nunmap <leader><Space> |
|
|
|
``` |
|
|
|
|
|
|
|
同样,`vim.api.nvim_buf_del_keymap()`以缓冲区编号作为第一个参数,其中`0`表示当前缓冲区。 |
|
|
|
同样,`vim.api.nvim_buf_del_keymap()` 以缓冲区编号作为第一个参数,其中 `0` 表示当前缓冲区。 |
|
|
|
|
|
|
|
```lua |
|
|
|
vim.api.nvim_buf_del_keymap(0, 'i', '<Tab>') |
|
|
@ -871,7 +871,7 @@ vim.api.nvim_buf_del_keymap(0, 'i', '<Tab>') |
|
|
|
|
|
|
|
## 定义用户命令 |
|
|
|
|
|
|
|
目前在 Lua 中没有创建用户命令的接口。 不过已经在计划内: |
|
|
|
目前在 Lua 中没有创建用户命令的接口。不过已经在计划内: |
|
|
|
|
|
|
|
- [Pull request #11613](https://github.com/neovim/neovim/pull/11613) |
|
|
|
|
|
|
@ -879,11 +879,11 @@ vim.api.nvim_buf_del_keymap(0, 'i', '<Tab>') |
|
|
|
|
|
|
|
## 定义自动命令 |
|
|
|
|
|
|
|
AUGROUP 和 AUTOCOMMAND 还没有接口,但正在处理: |
|
|
|
AUGROUP 和 AUTOCOMMAND 还没有接口,但正在处理 |
|
|
|
|
|
|
|
- [Pull request #12378](https://github.com/neovim/neovim/pull/12378) |
|
|
|
|
|
|
|
不过你可以使用`vim.api.nvim_command`来创建自动命令,例如: |
|
|
|
不过你可以使用 `vim.api.nvim_command` 来创建自动命令,例如: |
|
|
|
|
|
|
|
```lua |
|
|
|
-- Create autocmd |
|
|
@ -899,7 +899,7 @@ vim.api.nvim_command('augroup end') |
|
|
|
|
|
|
|
`vim.api.nvim_buf_add_highlight` 为 buffer 指定的行和位置添加高亮 |
|
|
|
|
|
|
|
neovim 0.5 集成 treesitter,对于语法高亮相比之前使用正则的方式更加的高效,[nvim-treesitter](https://github.com/nvim-treesitter/nvim-treesitter) |
|
|
|
Neovim 0.5 集成 treesitter,对于语法高亮相比之前使用正则的方式更加的高效,[nvim-treesitter](https://github.com/nvim-treesitter/nvim-treesitter) |
|
|
|
|
|
|
|
- `:help lua-treesitter` |
|
|
|
|
|
|
@ -918,7 +918,7 @@ neovim 0.5 集成 treesitter,对于语法高亮相比之前使用正则的方 |
|
|
|
|
|
|
|
### vim.loop |
|
|
|
|
|
|
|
`vim.loop`是暴露 LibUV 接口的模块。 |
|
|
|
`vim.loop` 是暴露 LibUV 接口的模块。 |
|
|
|
|
|
|
|
```lua |
|
|
|
local stop_signal = false |
|
|
|