Flycheck 38:力量与魔法

Lobsters Hottest 工具

摘要

Flycheck 38 是一个重大版本,增加了对语言服务器的内置 Eglot 支持、内联诊断注释以及应用快速修复代码操作的能力,复兴了 Emacs 的 linting 工具。

<p><a href="https://lobste.rs/s/odojje/flycheck_38_might_magic">评论</a></p>
查看原文
查看缓存全文

缓存时间: 2026/07/29 19:58

Flycheck 38:力量与魔法

飘荡者并非皆迷失。 —— J.R.R. 托尔金

今天我很高兴地宣布 Flycheck 38(https://github.com/flycheck/flycheck/releases/tag/v38.0)正式发布——这无疑是我接管项目以来最大、最具雄心的 Flycheck 版本。在这个版本中,Flycheck 为语言服务器提供了完整的支持方案,引入了现代编辑器所应具备的内联诊断功能,并且学会了应用修复——所有这一切都没有放弃让它最初广受欢迎的检查器模型。

我得承认,这个版本号本身配不上这次发布——它只是 37 之后的整数,“38” 这个数字本身一点也不“特别“。但版本号就是这样:有些版本比另一些更特别,而仅从数字上你几乎猜不到。

去而复返

简单回顾一下历史,因为这正是让我如此兴奋的原因。Flycheck 的诞生是为了给 Emacs 带来真正现代的代码检查体验,那时 Emacs 内置的选项——我们客气点说——乏善可陈。多年来,它一直是 Emacs 中实现实时检查的首选方式。但后来开发速度放缓,Flymake 被彻底重写,并在许多领域悄悄赶了上来——它最近甚至增加了行末诊断功能(https://emacsredux.com/blog/2026/07/20/flymake-can-now-show-diagnostics-at-the-end-of-the-line/)——我开始看到人们公开质疑 Flycheck 是否还能带来什么价值。

我理解这个问题——一个停滞不前的项目自然会招致这种质疑。但我从不相信 Flycheck 已经完成;它只是在休整。这次发布就是我的回答:证明它依然能够创新,依然能带来惊喜。而且我真心感谢竞争。Flymake 的奋起直追,恰恰促使我思考更大胆的方案,而不是再来一轮小修小补。这个领域的竞争是件好事,毫无疑问——它让两个项目都变得更好,而 Emacs 用户是最终的赢家。如果你好奇两者现在如何比较,手册中有诚实的对比(https://www.flycheck.org/en/latest/user/flycheck-versus-flymake.html)。

所以,本着勇敢迈向许多编辑器已先行之地的精神,以下是新功能。

Eglot 支持,终于内置了

多年来,Flycheck 与 LSP 之间的配合一直很尴尬。Eglot 通过 Flymake 呈现诊断信息,本身没有提供 Flycheck 后端,所以如果你想让 LSP 错误出现在 Flycheck 的错误列表中,就得借助第三方包 flycheck-eglot。这确实能用,但“再装一个包来桥接两个已经随 Emacs 一起发布的东西“这种事情,我一直不太认可。

现在 Flycheck 自己解决了这个问题。启用 global-flycheck-eglot-mode 后,由 Eglot 管理的缓冲区会通过 Flycheck 报告服务器的诊断信息——错误列表、导航、边缘区域,所有功能——而 Eglot 继续负责 LSP 的重活。这使得 flycheck-eglot 包变得过时。¹(https://emacsredux.com/blog/2026/07/29/flycheck-38/#fn:collision)

而且,由于 Flycheck 读取的是原始的 LSP 诊断信息,而不是经过 Flymake 扁平化处理后的内容,这个桥接层能够呈现 Flymake-over-Eglot 所丢弃的信息:LSP 的 quickfix 代码操作会变成 Flycheck 的修复,你可以用 C-c ! f 应用;诊断信息的关联位置也可以导航。

美观的内联诊断

我真正想要的另一项功能是内联消息——错误直接显示在它们所指的代码旁边,就像 VS Code 的 Error Lens、Neovim、Helix 和 Zed 那样。Flycheck 38 开箱即提供此功能。

flycheck-annotate-mode 的内联诊断

打开 flycheck-annotate-mode 即可获得此效果。有两种布局:紧凑型 eol 模式,消息显示在行末;宽敞型 below 布局,将完整消息单独显示在下方行中,并用连线指向出错的列。默认情况下,当前光标所在行使用宽敞布局,其余行保持紧凑,这样你正在处理的错误会完整显示,而其他行不会过度喧宾夺主。还有 Error Lens 风格的全行背景高亮,以及右对齐的 sideline 样式——手册(https://www.flycheck.org/en/latest/user/error-reports.html#inline-error-messages)中有每种样式的截图。

使用全局模式即可在任意位置启用:

(global-flycheck-annotate-mode 1)
;; 可选:Error Lens 风格的全行高亮
(setq flycheck-annotate-background t)

关于名称,还有一个小故事。我本想叫它 flycheck-inline-mode,但那个名字已被(现已弃用的)flycheck-inline 包占用。“Diagnostics” 是另一个明显的选择,但 Flycheck 一直称它们为errors(错误)而非 diagnostics(诊断)——flycheck-error、错误列表、flycheck-checkers——我不想为同一件事引入两套术语。所以最终定为 flycheck-annotate-mode。命名(依然)很难。

原生 LSP 支持,无需客户端

更精彩的是:Flycheck 现在可以直接与语言服务器通信——无需 Eglot、无需 lsp-mode、完全不需要完整的 LSP 客户端。

RuboCop 的 LSP 诊断通过原生 LSP 检查器呈现,支持修复

这是为了满足以下需求:越来越多的代码检查工具自带 LSP 服务器——RuboCop、Ruff、Biome、Harper 等——而传统的命令行检查器每次检查都会重新启动检查工具,反复支付启动成本(在 rubocop 加载大型项目时等待过的人都懂)。检查工具自带的 LSP 服务器保持常驻,增量地进行检查,因此检查速度快得多——而且你无需运行完整的语言服务器和客户端就能获得诊断信息。

启用 global-flycheck-lsp-mode,它即可开箱支持 RuboCop(Ruby)、Ruff(Python)、Biome(JavaScript、TypeScript、JSON、CSS)和 Harper(Markdown 散文)。每个服务器只在其程序已安装时才会启动,因此全局启用此模式是安全的。想要不同的工具?只需一行代码:

;; 对 Ruby 使用 Standard 替代 RuboCop
(setf (alist-get 'ruby-mode flycheck-lsp-servers) '("standardrb" "--lsp"))

整个功能构建在 Emacs 自己的 jsonrpc 库之上,因此没有新增依赖。而且,如果服务器提供了修复功能——RuboCop 的自动纠正、Ruff 和 Biome 的快速修复——这些也会作为 Flycheck 的修复呈现。该功能是为仅需诊断的场景设计的;当你需要带有补全和悬停提示的完整语言服务器时,通过 Eglot 运行它并使用 flycheck-eglot-mode。手册中有一个表格(https://www.flycheck.org/en/latest/user/syntax-checks.html#which-lsp-integration-should-i-use)帮助你选择。

项目级诊断

Flycheck 一直以来都是严格的缓冲区局部操作:它检查你正在查看的文件并显示这些文件中的错误。这在大多数情况下都很好,直到你想获得更全局的视图——所有打开文件中的问题,以及像 tsccargo checkmypy 等检查器确实知道的跨文件错误,但这些错误在逐缓冲区视图中被悄悄丢弃了。

在错误列表中按 P 键,它会切换到项目级范围:汇集所有打开的 Flycheck 缓冲区中的错误,那些跨文件诊断终于有了容身之处。这是 Flycheck 最接近“问题“面板的一次,而且它很快成为我日常使用中最喜欢的功能之一。

项目级范围的错误列表

注意其中 models.py 的类型错误:它是在检查 api.py 时报告的,旧的逐缓冲区视图会直接丢弃它。模式行中的 [project] 标签告诉你正在查看整个项目,而不是单个文件。

检查 TRAMP 远程文件

这个功能说起来很简单,而且坦白说早就该有了:Flycheck 现在可以在 TRAMP 上运行检查器。打开远程主机上的文件,检查器会在那里运行,在远程机器上,使用真实环境——而以前它干脆拒绝运行。如果你通过 TRAMP 在服务器或容器内编辑代码,仅此一项功能可能就值得升级。

还有更多

以上三个主要功能依赖于同一版本中落地的大量支持性工作。重点包括:

  • Flycheck 现在可以应用修复C-c ! fflycheck-fix-error-at-point)应用检查器建议的可自动应用的修复,C-c ! F 一次性应用缓冲区中的所有修复,并作为一个可撤销的变更;可修复的错误会有一个独特的边缘指示器——一个“可修复“的小灯泡图标。eslint --fixcargo clippy 的建议、ruffshellcheck 以及任何基于 SARIF 的检查器都会携带这些修复,而 Flycheck 过去会解析后丢弃它们。
  • 错误列表进行了重大改造:可以按文件、检查器或级别分组错误(并可组合这些维度),折叠组,并通过顶部的条带用鼠标驱动所有操作。
  • 错误可以携带次要位置——重定义之前的定义位置、Rust 生命周期错误背后的借用位置。用 C-c ! j 跳转到它们,它们会显示在消息之后的内联位置和错误列表中。
  • 正在运行的检查会被新开始的检查中断(除非已经取得了实质性进展),因此慢速检查器不再让 Flycheck 感觉迟钝,错误列表也不会再每次光标移动时重新扫描所有行。

按文件和级别分组的错误列表

更多内容请查看更新日志(https://github.com/flycheck/flycheck/blob/master/CHANGELOG.md),但以上就是大致的模样。

整合在一起

如果你想要完整的现代配置——随处实时检查、内联诊断、LSP 服务器的诊断信息流经 Flycheck——以下是一个能全部开启的 use-package 配置块:

(use-package flycheck
  :ensure t
  :hook ((after-init . global-flycheck-mode)
         ;; 内联显示诊断信息,紧邻代码 (Error Lens 风格)
         (after-init . global-flycheck-annotate-mode))
  :config
  ;; 通过 Flycheck 报告 Eglot 的 LSP 诊断
  (global-flycheck-eglot-mode 1))

更喜欢跳过 Eglot,直接从检查工具自带的 LSP 服务器(RuboCop、Ruff、Biome、Harper)读取诊断?将最后一行替换为 (global-flycheck-lsp-mode 1) 即可。当只需要诊断时使用原生检查器,当还需要完整语言服务器的补全和悬停提示时使用 Eglot 桥接。

升级

大多数配置将持续正常工作。需要注意一点:内置的 flycheck-eglot-mode 重用了旧第三方 flycheck-eglot 包的名称,因此如果你已安装该包,请先卸载它再依赖内置模式——否则两者会定义相同的命令并发生冲突。

关于资金支持的一点话

让我稍微直言不讳地说几句。在我维护 Flycheck 的这两三年里,它的 OpenCollective(https://opencollective.com/flycheck)收到的捐款总计不到 300 美元。个人捐赠也没有带来多大变化。我这么说不是为了让人内疚;这只是开源的日常现实。流行的项目工作量很大,而通常的回报是使用自己帮助改进的东西所带来的平静满足感。

不过,如果 Flycheck 为你节省了时间——尤其是在工作中——请考虑通过 OpenCollective(https://opencollective.com/flycheck)、GitHub Sponsors(https://github.com/sponsors/bbatsov)或 README 中链接的其他选项(https://github.com/flycheck/flycheck#sponsoring)提供支持。即使是小额定期捐赠,如果乘以每天依赖这个项目的用户数量,也会对我能投入多少时间产生实质性的影响。

结语

即使是最渺小的人也能改变未来的走向。 —— 加拉德瑞尔

当我接管 Flycheck 时,我的动机很简单:保持项目存活,并维持 Emacs 这一领域的竞争。很长一段时间里,这几乎只意味着保持基本运转。这次发布是许久以来它第一次真正地向前迈出了一大步,我对最终成果感到自豪——现代的诊断用户体验、双管齐下的一流 LSP 支持、项目级诊断和修复功能,同时始终忠于人们喜爱的检查器模型。姑且称之为绝地归来。我希望你会认为,我在追求的目标上至少取得了适度的成功。

衷心感谢所有测试、报告和推动这次发布的人。试试 flycheck-annotate-modeflycheck-lsp-mode,告诉我你的想法。

继续黑客!

相似文章

clj-refactor.el 4.0

Lobsters Hottest

clj-refactor.el 4.0,近五年来首个主要版本,引入了热依赖加载、异步重构、差异预览、瞬态菜单以及众多针对Emacs中Clojure开发的改进。

Racket v9.3

Hacker News Top

Racket v9.3 已发布,包含多项新功能,包括 Markdown 文档生成、改进的教学语言,以及增强的包管理和 FFI 支持。