前因
最近,我在 Reddit 上面分享了一个新的代码格式化的插件 format.nvim, 回复大多是是在问为什么要做这个插件以及跟现有插件的区别。
在 SpaceVim v2.3.0 之前,一直使用的代码格式化插件是 neoformat, 这个插件是使用 Vim 脚本写的,同时支持 Neovim 和 Vim。
但是美中不足的地方是这个插件执行格式化命令是调用 Vim 的 system()
函数,当命令执行消耗时间很长时,就会卡住界面无法进行下一步操作。
我也尝试过给 neoformat 增加异步支持,但是最终还是决定重新开发一个插件,
主要市考虑到以下几个原因:
- Lua 尤其是 luajit 速度相较于 Vim 脚本要快很多,相关比较文章可以查看我前面写的使用 Lua 重写 SpaceVim 内置插件和Vim9Script 与 Lua 的速度比较
- 做一个格式化插件的框架,尽可能减少默认的 formatter,提供接口自行定义。
- 不需要太过复杂的功能,仅仅是异步执行指定命令并更新 Neovim 缓冲区。
其实 neoformat 的插件代码实现逻辑还是非常好的,因此我也是参考了 neoformat 的实现逻辑, 使用 Lua 来实现了这个异步代码格式化的插件 format.nvim。 这个插件使用了 SpaceVim 的 job api 可以异步执行格式化命令,使得 Neovim 的操作更加顺畅。
插件的安装
可以使用任意插件管理器,比如nvim-plug来进行安装:
require('plug').add({
{
'wsdjeg/format.nvim',
cmds = { 'Format' },
depends = {
{ 'wsdjeg/job.nvim' },
{ 'wsdjeg/notify.nvim' },
},
},
})
对于 SpaceVim 用户来说,只需要在启用 format 模块的时候,指定格式化方法为 format.nvim 即可,配置如下:
[[layers]]
name = 'format'
format_method = 'format.nvim'
自定义 formatter
以 Lua 语言为例,设置使用 stylua 命令进行格式化:
require('format').setup({
custom_formatters = {
lua = {
exe = 'stylua',
args = { '-' },
stdin = true,
},
},
})
插件的使用
- 格式化整个文件
format.nvim 只提供了一个命令 :Fromat
, 执行该命令时就可以根据当前文件的文件类型选择对应的 formatter 对整个 Buffer 进行格式化。
- 选中区域进行格式化
:Format
命令支持指定区域进行格式化,因此可以在 Neovim 中选中几行代码进行格式化。
- 指定文件类型
通常执行 :Format
命令时,会读取当前 Buffer 的 &filetype 选项,但是如果需要指定其他文件类型,比如 java,可以使用如下格式执行命令:
:Format! <filetype>
- 指定格式化工具
如果一个文件类型有多个 formatters,可以在执行改命令时指定一个 formatter 的名字,比如 :Format prettier
- 同时指定文件类型、格式化工具,比如选中 markdown 内一段代码块进行格式化:
:Format! <filetype> <formatter>
Markdown 代码块格式化
前面提到 :Format
命令支持指定区域格式,这里需要借助一个插件 context_filetype.vim。
通过这个插件获取到代码块的区域和文件类型,传给 Format 命令。
以下示例使用 <Leader>f
格式化光标所在的代码块:
function! s:format_code_block() abort
let cf = context_filetype#get()
if cf.filetype !=# 'markdown'
let command = printf('%s,%sFormat! %s', cf.range[0][0], cf.range[1][0], cf.filetype)
exe command
endif
endfunction
nnoremap <silent> <Leader>f <cmd><sid>format_code_block()<cr>