前因
最近,我在 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 的操作更加顺畅。
插件的安装
对于 SpaceVim 用户来说,只需要在启用 format 模块的时候,指定格式化方法为 format.nvim 即可,配置如下:
[[layers]]
name = 'format'
format_method = 'format.nvim'
虽然 format.nvim 是基于 SpaceVim 的 Job API 实现的,但是该插件已经包含的改 API 的必须文件, 因此可以任意插件管理器独立安装,例如使用 vim-plug:
Plug 'wsdjeg/format.nvim'
自定义 formatter
以 Lua 语言为例,设置使用 stylua 命令进行格式化:
require('format').setup({
custom_formatters = {
lua = {
exe = 'stylua',
args = { '-' },
stdin = true,
},
},
})
插件的使用
1、格式化整个 Buffer
format.nvim 只提供了一个命令 :Fromat
, 执行该命令时就可以根据当前文件的文件类型选择对应的 formatter 对整个 Buffer 进行格式化。
2、选中区域进行格式化
:Format
命令支持指定区域进行格式化,因此可以在 Neovim 中选中几行代码进行格式化。
3、指定文件类型
通常执行 :Format
命令时,会读取当前 Buffer 的 &filetype 选项,但是如果需要指定其他文件类型,比如 java,可以使用如下格式执行命令:
:Format! java
4、指定 formatter
如果一个文件类型有多个 formatters,可以在执行改命令时指定一个 formatter 的名字,比如 :Format prettier
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>