Skip to content

Lazy

AtroNvim 的配置完全依赖lazy.nvim插件,对 AstroNvim 的配置同样是通过 lazy 的 opts 表进行的。因此整个配置实际上都是建立在 lazy 这个插件管理器上的。

加载插件

lazy 将要加载的插件以 table 的形式传递给 spec 即可,AstroNvim 默认模版在 lazy_setup 中引入了 lazy 的配置:

Lua
require("lazy").setup({
  -- plugins config
  spec = {
    {
      -- AstroNvim plugin,Basic Config in opts
      "AstroNvim/AstroNvim",
      import = "astronvim.plugins",
      opts = { -- AstroNvim options must be set here with the `import` key
        mapleader = " ",
        maplocalleader = ",",
        icons_enabled = true,
        pin_plugins = nil,
        update_notifications = true,
      },
    },
    -- import other plugins
    -- other file.lua or other dir/*.lua
    { import = "community" },
    { import = "plugins" },
  },
  -- lazy.nvim config
  install = { colorscheme = { "habamax" } },
  checker = { enabled = true },
})

因此安装插件就是编写一个个的 spec 表,而 AstroNvim 也是以插件的形式提供,因此对他的配置也是通过 spec 中的 opts 公开的。

spec

lazy.nvim 对插件的配置都是通过Spec完成的。Spec 本身就是一个 table 其中可用的属性有很多他们被分为几个部分:

Spec Source

Spec Source 即插件源,主要分为网络直接下载和本地目录:

属性 类型 描述
[1] string? 插件网址(只需要路径部分)
url string? 自定义 git url(默认就是 github)
dir string? 本地插件目录(主要是调试用)
name string? 用于本地插件目录的自定义名称

Spec Versioning

Spec Versioning 即插件版本控制,主要针对于远程插件

属性 类型 描述
branch string? 仓库的分支
tag string? 仓库的标签
commit string? 仓库的提交
version string? or false 仓库的版本,支持 Semver 定义
pin boolean? 当为 true 是,此插件不会被更新
submodules boolean? 如果为 false 不会获取 git 子模块

Spec Setup

Spec Setup 即插件配置,这也是最核心的地方

属性 类型 描述
init fun(Spec) init 函数始终在启动期间执行,主要用于设置 vim.g.* 这样的全局变量来控制插件的行为
opts table or fun(Spec, opts:table) -> opts 如果是一个 table 将覆盖父配置(未覆盖的依然使用父配置),如果是一个函数,返回的 table 将替换父配置
config fun(Spec, opts: table) or true 如果 config=true 且设置了 opts,则默认运行 require(MAIN).setup(opts), 或者是一个配置根据插件推荐方法来设置
main string? 指定用于 config 中的 main 模块
build fun(Spec) or string or false 在安装或更新插件时执行的命令

这部分是 Spec 最核心的部分。neovim 内置了 lua 引擎,而大多数 lua 插件的配置方式都是:

Lua
require('plugin_main').setup(opts)

这也就是 config=true 是的情况。因此我们通常只需要编写 opts 就可以了。当然有些插件也可能不遵循这个规则,此时就需要用到 config=fun 的情况。

Spec Lazy Loading

Lazy Loading 就是懒加载,这也是 Lazy 的强大的地方,从名字也能看出来:

属性 类型 描述
lazy boolean? 当为 true 时,插件仅在需要时加载
event string? or string[] or fun(Spec,envet: string[]) -> string[] 延迟加载事件
cmd string? or string[] or fun(Spec,cmd: string[]) -> string[] 延迟加载命令
ft string? or string[] or fun(Spec,cmd: string[]) -> string[] 在特定 filetype 上延迟加载
keys LazyKeysSpec? or LazyKeysSpec[] or fun(Spec,keys: LazyKeysSpec[]) -> LazyKeysSpec[] 在特定键位映射上延迟加载

lazy=true 启动懒加载,默认会在遇到require(plugin)时加载插件,也可以指定 cmd、ft、key 来加载。其中比较不好设置的就是 keys,它可以是一个表:

  • [1]: string: lhs,即触发按键(必须)
  • [2]: string|func(): rhs,即要执行的命令(可以为 nil,此时真正的映射必须由 config 函数创建)
  • mode: string|string[]: 指定模式,默认 n
  • ft: string|string[]: 特定 filetype 生效的映射
  • desc: 描述
  • 其他用于 vim.keymap.set 中可用的属性
Lua
-- Example for neo-tree.nvim
{
  "nvim-neo-tree/neo-tree.nvim",
    keys = {
      -- key   cmd    desc
      { "<leader>ft", "<cmd>Neotree toggle<cr>", desc = "NeoTree" },
    },
    config = function()
      require("neo-tree").setup()
    end,
}

Spec Loading

指定插件加载条件:

属性 类型 描述
dependencies Spec[] 插件依赖,注意依赖一定是懒加载的
enabled boolean? or fun() -> boolean 当为 false 时禁用插件
cond boolean? or fun(Spec) -> boolean 行为和 enabled 相同,但是当为 false 是不卸载插件(在 vscode 中禁用某些插件很有用)
priority number? 仅仅对 lazy=false 强制加载某些插件时有用,缺省值 50,对于配色方案建议调高

Spec Advanced

这里是一些高级设置部分,它主要用于一些 Neovim 发行版中。

属性 类型 描述
optional boolean? 可选,它出现在可能存在多个同一个插件的多个 Spec
module false? 当某处需要此 lua 模块时,不要自动加载该 lua 模块
import string? 导入给定的 spec 模块

opts 以及覆盖原理

opts 是最常用的配置方式,他可以是 table 和 fun 他们之间的区别在于:

  • table: 这会和父配置(其他配置)合并或覆盖
  • fun -> table: 他会返回新的 table 来作为新的配置
  • fun -> nil: 其中需要 opts.map 这样的方式来修改 opts,这种形式大多数和 table 没啥区别,除非需要引用其他库,它更加灵活些

table 这种合并而不是完全替代是在 lazy.nvim V10.23.0 版本修改的,它通过添加了一个 opts_extend 引入的,在之前他是完全替代的,而之前我么修改配置 table 的方式通常都是 fun -> nil:

Lua
-- 旧版本
{
  "nvim-treesitter/nvim-treesitter",
  opts = function(_, opts)
    -- list like portions of a table cannot be merged naturally and require the user to merge it manually
    -- check to make sure the key exists
    if not opts.ensure_installed then
      opts.ensure_installed = {}
    end
    vim.list_extend(opts.ensure_installed, {
      "lua",
      "vim",
      -- add more arguments for adding more treesitter parsers
    })
  end,
}

-- 新版本
{
  "nvim-treesitter/nvim-treesitter",
  opts = {
    ensure_installed = { "lua", "vim" },
    highlight = {
      enable = true,
    },
  },
}

插件加载顺序

Lazy 接管了整个 Neovim 的用户插件加载流程,执行顺序:

  1. 所有插件的 Spec 的 init 配置
  2. 所有带有 lazy=false 的插件,这也包括 /plugin/ftdetect 中的脚本文件
  3. 所有 /after/plugin 中脚本文件

删除

lazy 会用到下面的目录:

Bash
# data
$HOME/.local/share/nvim/lazy
# state
$HOME/.local/state/nvim/lazy
# lockfile
$HOME/.config/nvim/lazy-lock.json

多端同步: lockfile

其中 lockfile 比较特殊,在每次更新后会更新该文件,可以将它置于版本控制来同步多台机器确保插件都是相同的版本。

执行 :Lazy restore 会安装 lazy-lock.json 指定版本的插件

推荐配置方式

使用 Lazy 插件管理器,只需要编写 Spec 来配置对应插件即可。而且推荐将不同的插件拆分为多个文件,而不是将所有插件的 Spec 以单表构建。之后可以通过:

Lua
-- 只需要引入 plugins 目录
require("lazy").setup("plugins")

-- plugins 目录中的所有 lua 文件都可以直接 return Spec[]
return {
  "folke/neodev.nvim",
  "folke/which-key.nvim",
  { "folke/neoconf.nvim", cmd = "Neoconf" },
}

编写 Spec 的最佳实践

Lua
-- 如果插件必须 setup() 最简单的方式
{ "me/my-plugin", opts = {} }

-- 对于不需要 setup 的纯 lua 库应当延迟加载
{ "nvim-lua/plenary.nvim", lazy = true }

-- 尽可能使用 opts 来配置,而不是 config
{ "folke/todo-comments.nvim", opts = {} } -- good
-- 下面就是不是一个好方式
{
  "folke/todo-comments.nvim",
  config = function()
    require("todo-comments").setup({})
  end,
},

Tips

AstroNvim 也提供了一个lazy.nvim 配置指南