neovim/vim
使用者需要经常维护配置文件与插件库。由于插件API变更的频繁性,自己维护插件的配置需要付出一定精力,且很容易将配置目录弄得混乱。那么一个结构良好、层次分明、易于维护的配置框架成为我们的一大诉求。而nvchad正是解决此类麻烦的典型代表。
nvchad
高度可定制化,在默认情形下提供了一个开箱即用的配置,默认配置我们无需变动,只需要保持和上游的同步就能体验最新最酷炫最高效的插件。而当我们需要自定义配置或者需要增删插件时,可以在custom
目录下进行相应修改。nvchad
按照功能对用户提供了如下配置接口:
neovim
选项设置。控制neovim
的基本功能,如行号、缩进、高亮等。nvchad
采用纯lua
进行配置文件的编写,相比vimscript
更具可读性。neovim是基于vim
复刻的一个编辑器,在原有vim的基础上做了一些改进与调整。其中最大的特性是内置lua
引擎,其配置可以直接使用lua
进行开发,这一特性大大增强了neovim
的功能,诞生了许多以lua
进行开发的插件;同时neovim
兼容vim
的原有配置,既能享受强大的lua
插件同时也能继续使用原有vim
插件,是一个更值得推荐的编辑器。
lua是一种轻量级的脚本语言,语法特征和python
有点类似,因为非常高效小巧,因此很适合将其嵌入到其他软件项目中。关于如何在neovim
中使用lua
,可以参考这篇文档。
neovim
所有配置相关的文件位于目录$HOME/.config/nvim
下1,安装好的nvchad
的目录结构如下:
├── init.lua // 配置起始文件
└── lua
├── core // 默认配置目录
│ ├── bootstrap.lua // 提供首次安装时需要执行的一些函数
│ ├── default_config.lua // 默认配置的实际设置文件
│ ├── init.lua // core目录的配置起始文件
│ ├── mappings.lua // 默认快捷键映射
│ └── utils.lua // 封装几个功能函数,如load_config,lazy_load等
├── custom // 自定义用户配置目录
│ ├── chadrc.lua // 自定义配置的设置文件,用于覆盖core/default_config.lua
│ ├── configs // 自定义插件的配置文件,作用于cusom/plugins.lua
│ │ ├── lspconfig.lua
│ │ ├── vimtex.lua
│ │ └── overrides.lua
│ ├── highlights.lua
│ ├── init.lua // 自定义的lua代码片段,可覆盖或扩充core/init.lua
│ ├── mappings.lua // 自定义的映射,可覆盖core/mappings.lua
│ ├── plugins.lua // 自定义插件配置,可覆盖或扩充plugins/init.lua
│ └── README.md
└── plugins // 默认插件配置目录
├── configs
│ ├── cmp.lua
│ ├── lazy_nvim.lua
│ ├── lspconfig.lua
│ ├── mason.lua
│ ├── nvimtree.lua
│ ├── others.lua
│ ├── telescope.lua
│ └── treesitter.lua
└── init.lua // 所有默认插件的配置文件
init.lua
是配置的起始文件,neovim
在启动时会按照该文件来初始化配置。lua
目录下则是一些具体的配置子目录,包括默认的核心配置目录core
,自定义配置目录custom
以及默认插件配置目录plugins
。几乎所有默认配置均可由custom
目录下对应的文件进行覆盖或者扩充。init.lua
根据neovim
的说明文档,neovim
会从~/.config/nvim/init.lua
中加载用户配置,该文件是neovim
读取配置的起始文件。下面是该文件的主体流程:
执行lua/core/init.lua
来加载用户配置。
require "core"
判断是否有用户自定义的配置文件,如果有则执行lua/custom/init.lua
的自定义lua
代码片段。
local custom_init_path = vim.api.nvim_get_runtime_file("lua/custom/init.lua", false)[1]
if custom_init_path then
dofile(custom_init_path)
end
执行lua/core/utils.lua
中的load_mapping
函数加载快捷键设置。
require("core.utils").load_mappings()
安装lazy.nvim
以及所有插件。
local lazypath = vim.fn.stdpath "data" .. "/lazy/lazy.nvim"
-- bootstrap lazy.nvim!
if not vim.loop.fs_stat(lazypath) then
require("core.bootstrap").gen_chadrc_template() -- 生成lua/custom/chadrc.lua模板
require("core.bootstrap").lazy(lazypath) -- 安装lazy.nvim以及插件
end
dofile(vim.g.base46_cache .. "defaults") -- 主题颜色相关
vim.opt.rtp:prepend(lazypath) -- 将lazy.nvim安装目录加入rtp
加载插件配置。
require "plugins"
lua/core/init.lua
此文件是NvChad
的核心配置文件,主要包含UI、插件、快捷键映射、neovim选项、autocmd以及全局变量的一些配置。并且会根据custom
下的设置来确定最终的配置结果。其执行流程如下:
调用lua/core/utils.lua
中的load_config
函数加载并确定前述的大部分配置。
local config = require("core.utils").load_config()
该函数的定义为:
local M = {}
local merge_tb = vim.tbl_deep_extend
M.load_config = function()
local config = require "core.default_config" -- 获取默认配置
local chadrc_path = vim.api.nvim_get_runtime_file("lua/custom/chadrc.lua", false)[1] -- 自定义配置文件路径
if chadrc_path then
local chadrc = dofile(chadrc_path) -- 获取自定义配置
-- 将自定义的快捷键映射从默认映射中移除,自定义的快捷键功能具有更高的优先级
config.mappings = M.remove_disabled_keys(chadrc.mappings, config.mappings)
-- 合并自定义配置与默认配置,如果key相同value则以chadrc为准,参见:help vim.tbl_deep_extend
config = merge_tb("force", config, chadrc)
config.mappings.disabled = nil
end
return config
end
基本思想是加载lua/core/default_config.lua
以及lua/custom/chadrc.lua
,并合并两者的设置,如遇冲突则以chadrc
覆盖default_config
。关于如何进行合并,nvchad
的这篇文档有较详细的介绍。配置文件主要定义了UI、插件与映射的配置,分别由M.ui
、M.plugins
、M.mappings
确定。
定义neovim选项、autocmd等其他变量或命令。
local g = vim.g
opt.clipboard = "unnamedplus"
opt.cursorline = true
...
lua/core/bootstrap.lua
在安装NvChad
后首次启动时,会调用bootstrap.lua
中的gen_chadrc_template
与lazy
函数,分别用于生成chadrc
模板配置文件与安装lazy.nvim
,下面分析下lazy.nvim
的安装方式:
M.lazy = function(install_path)
------------- base46 ---------------
local lazy_path = vim.fn.stdpath "data" .. "/lazy/base46"
M.echo " Compiling base46 theme to bytecode ..."
local base46_repo = "https://github.com/NvChad/base46"
shell_call { "git", "clone", "--depth", "1", "-b", "v2.0", base46_repo, lazy_path }
vim.opt.rtp:prepend(lazy_path)
require("base46").compile()
--------- lazy.nvim ---------------
M.echo " Installing lazy.nvim & plugins ..."
local repo = "https://github.com/folke/lazy.nvim.git"
shell_call { "git", "clone", "--filter=blob:none", "--branch=stable", repo, install_path }
vim.opt.rtp:prepend(install_path)
-- install plugins
require "plugins"
-- mason packages & show post_boostrap screen
require "nvchad.post_bootstrap"()
end
该函数首先下载base46
主题仓库并编译成字节码,之后下载lazy.nvim
,然后调用lua/plugins/init.lua
安装所有插件,最后执行Mason
中LSP
的相关安装并显示最终的结果屏幕。
lua/plugins/init.lua
该文件是管理插件的顶层配置文件,其结构如下:
local default_plugins = { -- 所有nvchad默认使用的插件
...
-- nvchad plugins
{ "NvChad/extensions", branch = "v2.0" },
...
}
-- 加载default_config与chadrc中的配置并进行合并,这里主要用到其中的`plugins`表
local config = require("core.utils").load_config()
-- 如果有自定义的插件设置,那么插入一条{import = config.plugins}的表项到default_plugins中
if #config.plugins > 0 then
table.insert(default_plugins, { import = config.plugins })
end
-- 加载lazy.nvim,传入default_plugins
require("lazy").setup(default_plugins, config.lazy_nvim)
default_plugins
的table,其中声明了需要管理的插件以及相关配置参数lua/plugins/init.lua
会使用load_config
加载default_config
与chadrc
中的配置,确定是否有用于自定义的插件。如果存在用户自定义的插件,则在default_plugins
中加入一条{ import = config.plugins }
的表项,这条记录的含义可以参考lazy.nvim
中的README。default_plugins
并加载lazy.nvim
,NvChad
就可以使用lazy.nvim
管理插件了。可以在lua/custom/mappings.lua
中添加自定义的快捷键,以下是我的一部分快捷键配置:
local M = {}
M.general = {
n = {
-- 分割窗口
["<C-w>k"] = { ":abo split <CR>", "split window to top" },
["<C-w>h"] = { ":abo vsplit <CR>", "split window to left" },
["<C-w>j"] = { ":rightbelow split <CR>", "split window to bottom" },
["<C-w>l"] = { ":rightbelow vsplit <CR>", "split window to right" },
-- 关闭窗口
["q"] = { ": <ESC>:close <CR>", "close window", opts = { silent = true } },
-- 使用回车打开关闭折叠
["<CR>"] = { "za", "open fold with enter" },
-- 将:替换成;
[";"] = { ":", "enter command mode", opts = { nowait = true } },
-- 使用Q进行宏录制
["Q"] = { "q", "use Q to record macro" },
},
v = {
-- 关闭窗口
["q"] = { ": <ESC>:close <CR>", "close window"},
},
i = {
-- jk 快速退出
["jk"] = { "<ESC>", "quick escape" },
}
}
M.lspconfig = {
plugin = true,
n = {
-- 查找定义
["gd"] = {
function()
require("telescope.builtin").lsp_definitions({ fname_width = 100, reuse_win = true })
end
},
-- 查找引用
["gr"] = {
function()
require("telescope.builtin").lsp_references({ show_line = false })
end,
"LSP signature help",
},
-- 查找全局符号
["gs"] = {
function()
require("telescope.builtin").lsp_workspace_symbols({ fname_width = 100 })
end,
}
}
}
return M
以上配置中,M.general
、M.lspconfig
称为section
,是一个个逻辑独立的映射。如M.general
是一些通用的快捷键,M.lspconfig
则是针对lspconfig
插件专用的快捷键,用户可以根据自己的意愿来划分section
。
一个section
的快捷键设置的格式大致为:
section_name = {
mode1 = {
[key1] = mapping_info1,
[key2] = mapping_info2,
...
},
mode2 = {
[key3] = mapping_info3,
...
},
...
}
mode
表示该快捷键作用于哪种模式,如n
表示normal
模式,v
表示visual
模式,i
表示insert
模式等;key
则是要绑定的快捷键;mapping_info
则是具有特定格式的表,表的第一项是该快捷键对应的操作,可以是一个函数,也可以是一个普通的neovim
操作。表的第二项是一个可选的描述字符串。
每个section
内部可以添加一个plugin = true
的表项,如M.lspconfig
中我们就定义了这个plugin
。这个表示该section
的快捷键需要由插件进行加载。默认情形下,NvChad
可以使用load_mappings()
设置所有不含plugin
的section
快捷键,而如果我们想在使用某个插件时才设置对应的快捷键,就可以加入plugin
,并在插件的配置中使用load_mappings(section_name)
来进行加载了。
上面的M.lspconfig
是在NvChad
的lua/plugins/configs/lspconfig.lua
中的M.on_attach
函数进行加载的:
M.on_attach = function(client, bufnr)
...
utils.load_mappings("lspconfig", { buffer = bufnr })
...
end
NvChad
不仅可以安装lua
插件,也可以安装vimscript
插件。以vimtex
为例:
我们首先需要在lua/custom/plugins.lua
中加入vimtex
:
{
"lervag/vimtex",
ft = "tex", -- 按照filetype进行lazy加载,只有处理.tex文件时该插件才会被加载
config = function() -- 加载插件时会执行的钩子函数
require("custom.configs.vimtex").setup() -- 执行我们自定义的vimtex配置文件中的setup函数
end,
},
之后我们需要在lua/custom/configs
下新建一个插件的配置文件。对于本例就是vimtex.lua
,在该文件中实现前面的setup
函数:
local M = {}
M.setup = function ()
vim.cmd([[
" 在这里就可以加入vimscript的配置命令了
let g:vimtex_compiler_latexmk_engines = {
\ '_' : '-xelatex',
\}
]])
end
return M
可以利用vim.cmd([[ ... ]])
来执行vimscript
的配置
下文所有路径默认都以该目录为根目录。 ↩