Neovim 中文周刊 第 2 期

欢迎收看第 2 期 Neovim 中文周刊!

本期周刊包含以下版块:

  • Neovim 开发近况
    • 新功能:摘录近期合并的 PR,以新功能为主
    • 社区讨论:摘录近期更新的 Issue 讨论,以 Enhancement 为主
  • 文章推荐
  • 插件推荐

Neovim 开发近况

新功能

feat(lsp): add support for completion context (#32793)

Neovim 的 LSP 客户端现在支持在 textDocument/completion 请求的参数中传入 context ,具体规范详见微软的官方文档。这个主要影响的是 vim.lsp.completion.trigger,不过我倒是很好奇有多少人在用 vim.lsp.completion

vim-patch:62e8228: runtime(go): add 'keywordprg' and 'formatprg' to ftplugin (#32788)

为 Go 文件设置 keywordprgformatprg,其中 keywordprg 相当于 go doc -C <file> <cword>,而 formatprg 则直接设置为 gofmt

feat(messages): "g<" mapping for ext_messages (#32687)

g< 快捷键支持显示 ext_messagesg< 快捷键显示上一条命令的输出内容,而 ext_messages 则详见 :h ui-messages。作者 luukvbaal 指出“该提交可以被视为一次修复”。

feat(checkhealth): group parsers by name and path in output (#32825)

就是以前 :checkhealth vim.treesitter 的时候 parsers 列表是根据路径排序的,现在根据 parser 名称也就是 parser 对应的编程语言进行排序,这样重复的 parser 就会排在一起,说是这样看起来更直观喽。Neovim 会 bundle 一些最基本的 parser 随软件一起分发,所以估计不少人有重复的 parser。

feat(treesitter): allow passing lang to InspectTree (#32851)

InspectTree 命令现在接受一个参数来指定要解析的语言。

feat(treesitter): allow iter_captures to accept opts (#32838)

Query:iter_captures 终于和 Query:iter_matches 一样接受 opts 参数了,目前 opts 表支持两个字段:

  • max_start_depth 设置每个 match 的最大初始深度,避免遍历语法树过深;

  • match_limit 设置最多有多少个 in-progress match

feat(treesitter): disable captures and patterns on TSQuery (#32790)

增添了如下功能:

  • TSQuery:disable_patternTSQuery:disable_capture 分别用来为一条 treesitter query 禁用掉特定的 patterncapture

  • Inspect! 命令现在会显示每个匹配对应的 pattern id

此 PR 是 #32729 提案的第一部分,主要是为了解决一个痛点,该提案引用了一个例子。我们知道 nvim-treesitter 提供了大量编程语言的各种 query,用来实现语法高亮之类的功能。例子中的场景是用户希望取消掉 Lua 文件中 local 关键字的斜体效果,但保持其他关键字不变,很明显斜体效果来自 @keyword 高亮组,因为用户不希望取消掉其他关键字的斜体效果,所以没法通过修改 @keyword 高亮组来解决。此外,为 local 添加优先级更高的高亮组并不会改变斜体高亮已经应用在 local 上的事实。因此用户只能选择复制 query 然后在副本上面进行微调,但是因为 vim.treesitter.query.set 只支持直接以文本的形式设置 query,导致用户想要微调也只能通过文本替换的形式进行修改,正如例子展示的

vim.treesitter.query.set_query('lua', 'highlights', read_query_files(vim.treesitter.query.get_query_files('lua', 'highlights')):gsub([[%[
 "goto"
 "in"
 "local"
%] @keyword]], [[
[ "goto" "in" ] @keyword

; put more queries of yours here
  ]])
)

比较难绷。该 PR 合并后可以直接在原有的 query 的基础上微调了,注意:禁用后就不能再重新启用了。帮助文档中提供了一个示例,展示如何为 vimdoc 文件单独禁用 | 的高亮但保留其他 @markup.link 的高亮:

local link_pattern = 9 -- from :Inspect!
local query = vim.treesitter.query.get('vimdoc', 'highlights')
query.query:disable_pattern(link_pattern)
local tree = vim.treesitter.get_parser():parse()[1]

但还是没有解决问题,提案的下一步工作是让 vim.treesitter.query.set 可以直接接受 vim.treesitter.Query

feat(snippet): set snippet keymaps permanent instead of dynamic (#31887)

现在默认创建 <Tab><S-Tab> 快捷键来向前和向后 vim.snippet.jump

以前是在 vim.snippet.expand 的时候会自动创建这两个 keymap,那我问你,啊,那我问你,我怎么实现 smart-tab idiom 呢?smart-tab 就是很多人都喜欢的:在有 popup menu 的时候按 <Tab> 就是选择下一个候选项,否则就 fallback 到 vim.snippet.jump。结果 vim.snippet.expand 总是给我这俩键覆盖了,完全没办法自定义。

既然如此就直接将这两个 keymap 大大方方放出来好让大伙可以随便捏成自己想要的样子,顺便又提供了一个开箱即用的小功能,哎又是一件功德啊(笑)。

社区讨论

variable font sizes for 'statusline' and friends (#32539)

kitty (#8226) 现在支持显示可变的字体大小,该提案指出可以使用此功能减小 statuslinewinbar 的大小,这些 UI 组件不是特别重要,减小它们的大小能有效减少视觉噪音,为显示内容的 buffer 提供更多空间。

justinmk 指出还可以使用此功能实现 Markdown 不同等级的标题行以不同的字体大小显示。而 algmyr 则指出这对 inlay hint 同样很有用,正常字体大小的 inlay hint 通常会使整个编辑区显得很嘈杂。一如既往,fredizzimo 作为 neovide 的核心开发者,针对该类 UI 提案指出现有的 UI 协议在实现该功能的过程中需要解决的一些问题,建议使用一个全新的 UI 协议来实现此功能,并简要介绍了对全新的 UI 协议的一些构思。

确实,由于只能在终端中只能使用一种字体大小,在 Neovim 中实现的各种 UI 组件常常占据屏幕不少空间,特别是像 nvim-dap-ui 这种有不少交互界面的插件,对屏幕比较小或者喜欢大字号的用户并不友好。

此提案被标记了 gsoc,如果您有兴趣从该提案开始贡献 Neovim,请查看指引

UI can :restart Nvim server (#32484)

该提案提出期望实现一个 :restart 命令,通过该命令,UI 客户端可以

  1. 暂停 nvim --embed 服务端;

  2. 启动一个全新的 nvim --embed 并连接上它;

该提案的需求源自于 #32471,该问题指出 Neovim 插件通常大量依赖全局状态,但是又没有提供清理副作用的 API,这导致需要频繁重启 Neovim 来重新加载所有插件,与之对比的是 Visual Studio Code 可以在不重启的前提下重新加载插件。

针对该问题 justinmk 提出两种方案,

  • 提供 dispose 接口,插件可选地实现该接口以清理其全局状态。实现类似的功能不难,但是这还需要设计好插件的生命周期,这需要额外工作。

  • 不要求插件管理好资源,而是优化 :mksession 功能,使 Neovim 可以随意重启,然后让 UI :restart 服务端。

同样,此提案被标记了 gsoc,已经有若干开发者在 Issue 留言讨论。

文章推荐

DOs and DON'Ts for modern Neovim Lua plugin development

一些插件开发的最佳实践,推荐大家都可以看一看。

What's New in Neovim 0.10

去年的老文章了,是 Neovim 的核心开发者 gpanders 写的,这会儿估计 0.11 都快出了,权当查缺补漏。

插件推荐

nvim-tinygit

专注于快速和流畅的 Git 操作的轻量级命令集合。

相比于 vim-fugitiveneogit 这种 full-battery 的 Git 集成,这个插件就是一些插件作者常用的 Git 工作流攒起来的,比较杂,挑一些我觉得不错的说道说道:

  • Smart Commit。其实就是在你没有 stage 任何修改的时候帮你 git add --all,然后弹个好看的 float window 写写 commit 消息最后提交而已。 Smart Commit
  • fixup。从历史的 X 个提交里选一个 git commit --fixup,然后可选地自动 rebase,这个还是挺常用的。
  • 搜索 Git 历史,这个是我感觉最有用的。不同模式下调用有不同的效果
    • Normal 模式下调用就是 git log -G,也就是俗称的 pickaxe,非常实用的功能。
    • Visual 模式下调用就是 git log -L <funcname>
    • V-Line 模式调用就是 git log -L <range>File History
  • statusline 用的显示本地分支和远程分支领先或落后的 commit 数,弥补了 lualine.nvim 的默认 Git 组件没有完美 COSPLAY Visual Studio Code 的缺憾(笑)

还有其他的一些小功能,详情请看官方文档

这个插件总体给我一种小而美的感觉,呃虽然这两年作者不断往里面塞新东西现在来看也不怎么 "tiny" 了,但总的来说收录的功能大部分还是有一点设计感的,而不只是简单的 Git Wrapper。

mini.files

导航和操作文件系统。mini.nvim 的一部分。

大名鼎鼎的 mini.nvim 不需要我多介绍,但是 mini.files 这个组件貌似挺冷门的。

我们知道 Neovim 的文件浏览器类插件总的来说有两大阵营,一类是以 neo-tree.nvim 为代表的以文件树的形式呈现文件系统的插件,我个人认为这种类型的插件的优势是直观,符合多数用户的直觉,用户对整个文件系统的认知更清晰;另一类是以 oil.nvim 为代表的将文件系统作为一个平凡的 Neovim buffer 呈现的插件,优势是非常符合 (Neo)vim 哲学,在对文件系统进行操作时可以用上你所有的 (Neo)vim 技巧疯狂炫技。

mini.files 是我最喜欢的文件浏览器类插件,我不敢说它做到了集两大阵营的优势于一身,不过它确实有点两大阵营的杂交版的意思,推荐大家了解一下。

mini.files 一个短板就是不支持 diagnostics 和 Git 状态集成,而且 echasnovski 也明说了不会在插件里实现这些功能,理由是用户想要的话可以轻松自己实现一个,我试了一下,只能说可以是可以,就是实现得有点丑陋,我太菜了(汗)。

关于

算是赶上了周六发布,那就干脆定下来每周六更新吧。

看到不少开发者都在积极参与 Neovim 的 GSoC,看来 Neovim 还没有凉凉(笑),不禁感叹自己已经是老登了呀(悲)。

那么,一如既往,希望本期周刊能对您有所裨益,感谢您的阅读。

  • 周刊项目地址
  • RSS 订阅
  • 我不是 Neovim 贡献者,也不是任何有影响力的插件贡献者,甚至算不上一个 (Neo)vim 老手,我的观点很可能错漏百出。如果您希望贡献本周刊,请收下我的感谢并查看贡献指南
  • 发布日期:2025-03-15 修订日期:2025-03-21