首次发布 三天后,我发布了 v0.2.1。第一个版本在 r/emacs 上获得了热烈的反响,大家马上开始提出各种需求:LaTeX 片段预览、doc-view 支持、折叠标题时隐藏图片。我把这些功能全都实现了。
这篇文章介绍 v0.2.1 中的所有新功能。
Org 内联图片
首次发布中的核心功能,现在更加稳健。使用 C-c C-x C-v 切换内联图片显示。文件链接、附件链接和相对路径均可正常工作。

LaTeX 片段预览
这是呼声最高的功能之一。现在可以在 org-mode 中使用 C-c C-x C-l 直接预览 LaTeX 片段,和你熟悉的快捷键完全一样。片段通过 dvipng 渲染,并通过 Kitty 图形协议内联显示。不需要 GUI 窗口。

实现方式是通过 advise org-latex-preview 和 org--make-preview-overlay 来拦截图片生成管线。Org 的 LaTeX 渲染实际上不需要 GUI,它调用的是 dvipng=/=dvisvgm 外部命令,所以我们只需要绕过 display-graphic-p 检查,然后把生成的 PNG 传给 Kitty 协议即可。
一个烦人的边界情况:终端 Emacs 有时会将 face 颜色报告为 =unspecified-fg=,这会导致 org 的颜色格式化出错。advice 会强制使用具体的前景色/背景色,确保 LaTeX 输出不会变成不可见的。
使用 =C-u C-c C-x C-l=(区域)或 =C-u C-u C-c C-x C-l=(整个 buffer)清除预览。
doc-view 集成
PDF、DVI 和 PostScript 文件现在可以通过 doc-view 在终端中渲染。页面导航正常工作,=n=/=p= 翻页。缩放也可以:=+= 放大,=-= 缩小,=0= 重置。每页在窗口中居中渲染。

实现方式是 patch doc-view-mode-p 来绕过 GUI 检查(和 LaTeX 同样的方法,用 cl-letf 临时让 display-graphic-p 返回 t=),并 patch =doc-view-insert-image 通过 Kitty 图形协议显示页面 PNG,而不是使用 Emacs image spec。
Image-Mode
Image-mode 现在会在窗口中居中显示图片,并支持缩放控制:
+/=放大-缩小0重置为 1:1

为了避免与 evil-mode 冲突(这在首次发布时是个问题),终端图片查看器现在使用自己的 kitty-gfx-image-mode major mode,而不是直接劫持 =image-mode=。这意味着 evil-collection 的 image-mode 按键绑定(那些调用在终端中无法工作的原生图片函数的绑定)不会产生干扰。
Dirvish 集成
Dirvish 中的图片预览现在可以在终端中原生工作。该包注册了一个 kitty-image 预览分发器,在你浏览文件时渲染预览窗格中的图片。不需要额外配置。如果 kitty-graphics-mode 已启用且 dirvish 已加载,它就能直接工作。

折叠 Org 标题时隐藏图片
这是首次发布后的第一个 bug 报告,也可以说是最烦人的问题。折叠标题时图片仍然可见,悬浮在空中,与其上下文脱节。
修复方案同时检查 =org-fold=(org 9.6+,基于 text-property)和传统的基于 overlay 的不可见性。当标题被折叠时,折叠内的图片 overlay 会删除其终端放置。展开时,刷新循环会重新放置它们。它还正确地忽略装饰性的不可见性,如隐藏的链接括号(=org-link=)。
稳健性大修
内部机制进行了全面改造。这些改动不影响用户可见的行为,但使整个系统显著更加可靠。
LRU 图片缓存
旧的缓存是一个无限增长的哈希表,曾经显示过的每张图片都永远留在终端内存中。现在有了一个带有可配置大小限制的 LRU 缓存(=kitty-gfx-cache-size=,默认 64)。当缓存满时,最近最少使用的图片会被淘汰,其终端数据也会被删除。
缓存也不再存储图片尺寸。尺寸每次都从像素大小和当前单元格度量重新计算。这意味着缩放、调整窗口大小,或在不同上下文中查看同一张图片(org-mode vs. image-mode vs. dired)总能获得正确的尺寸,而不是过时的缓存值。
减少闪烁
Buffer 和窗口切换以前会删除 所有 放置并从头重新创建。这会导致明显的闪烁,尤其是在分屏中切换 buffer 时。现在:
- /Buffer 切换/:只删除不再在任何窗口中可见的 buffer 的放置。可见 buffer 只是使其位置缓存失效。
- /窗口切换/:使位置缓存和单元格像素大小失效,但不删除任何东西。刷新循环处理重新放置。
- /前沿防抖/:第一次刷新立即触发(在 redisplay 之后),然后进入冷却期。冷却期间的调用被抑制但标记。当冷却期结束时,触发一次尾部刷新以捕获最终状态。
溢出保护
超出窗口底部边缘的图片现在会被隐藏而不是放置。在此之前,屏幕底部附近的高图片会溢出到窗口下方的内容中,导致视觉混乱。
更安全的清理
关闭 buffer 时现在会检查其他 buffer 是否仍然引用相同的图片 ID,然后才删除终端端的图片数据。这防止了破坏共享图片的问题,例如同时在 org-mode 和 image-mode 中打开同一个文件。
其他改动
convert-to-png在失败时返回 =nil=,而不是将原始的非 PNG 文件传给终端- 所有显示路径中的临时文件创建使用
unwind-protect - 每个
send-string-to-terminal调用都用ignore-errors包裹 - 窗口大小改变时重新查询单元格像素大小
- 刷新循环中清理死亡的 overlay
- 毫秒精度的调试日志(使用
kitty-gfx-debug启用)
安装
将 kitty-graphics.el 放到你的 load path 中并启用该模式:
(require 'kitty-graphics)
(kitty-graphics-mode 1)
或者使用 use-package 和 =straight.el=:
(use-package kitty-graphics
:straight (:host github :repo "cashmeredev/kitty-graphics.el")
:if (and (not (display-graphic-p)) (getenv "KITTY_PID"))
:config
(kitty-graphics-mode 1)
(with-eval-after-load 'dired
(define-key dired-mode-map (kbd "P") #'kitty-gfx-dired-preview)))
如果你遇到问题或有功能建议,请在 GitHub 上提 issue。
发布版本:GitHub 上的 v0.2.1