Eric's Blog 时光荏苒,岁月如梭

代码格式化插件 format.nvim

2024-12-25
Eric Wong

前因

最近,我在 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>

延生阅读

分享到:

评论

目前只支持使用邮件参与评论。