From 7691a94d26190324d3f7b6ff22068fa4fc57c121 Mon Sep 17 00:00:00 2001 From: cashmere Date: Sun, 29 Mar 2026 09:07:06 +0200 Subject: fix: Sixel backend parity improvements Close gaps identified in Sixel vs Kitty audit: - image-mode: mode-name now shows Image[Sixel] or Image[Kitty] based on active backend (was hardcoded to Image[Kitty]) - LaTeX preview: docstring updated to reference kitty-graphics package name, not Kitty protocol specifically - sixel-cleanup-all: now erases visible Sixel images from terminal cells before cleaning disk/memory state (prevents pixel artifacts on mode disable) - sixel-place: LRU eviction for .six temp files, capped at kitty-gfx-cache-size (default 64), oldest evicted on overflow Remaining by-design differences (protocol limitations, not bugs): - Sixel re-emits raw pixel data on scroll (no placement IDs) - Sixel erases by overwriting with spaces (no protocol-level delete) - Sixel detection is env-var based (no DA1 query yet) --- kitty-graphics.el | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) (limited to 'kitty-graphics.el') diff --git a/kitty-graphics.el b/kitty-graphics.el index 60a1e70..f5006fb 100644 --- a/kitty-graphics.el +++ b/kitty-graphics.el @@ -630,7 +630,16 @@ Encodes on-demand if not cached, then emits DCS sequence." (with-temp-file cache-path (set-buffer-multibyte nil) (insert sixel-data))) - (push cache-path kitty-gfx--sixel-temp-files))) + (push cache-path kitty-gfx--sixel-temp-files) + ;; LRU eviction: cap temp files at kitty-gfx-cache-size + (when (> (length kitty-gfx--sixel-temp-files) kitty-gfx-cache-size) + (let ((victim (car (last kitty-gfx--sixel-temp-files)))) + (kitty-gfx--log "sixel-cache-evict: %s (count=%d max=%d)" + victim (length kitty-gfx--sixel-temp-files) + kitty-gfx-cache-size) + (ignore-errors (delete-file victim)) + (setq kitty-gfx--sixel-temp-files + (butlast kitty-gfx--sixel-temp-files)))))) ;; Emit Sixel sequence if we have data (when sixel-data (let* ((cw (or kitty-gfx--cell-pixel-width 8)) @@ -669,9 +678,21 @@ Sixel has no placement IDs — erase by writing spaces over the region." (setq kitty-gfx--sixel-temp-files (delete temp-file kitty-gfx--sixel-temp-files))))) (defun kitty-gfx--sixel-cleanup-all () - "Cleanup all Sixel resources." + "Cleanup all Sixel resources. +Erases visible Sixel images from the terminal before cleaning +disk/memory state, preventing pixel artifacts on mode disable." (kitty-gfx--log "sixel-cleanup-all: deleting %d temp files" (length kitty-gfx--sixel-temp-files)) + ;; Erase visible images from terminal (Sixel has no protocol-level + ;; delete — must overwrite cells with spaces). + (dolist (buf (buffer-list)) + (with-current-buffer buf + (dolist (ov kitty-gfx--overlays) + (when (and (overlay-buffer ov) + (not (overlay-get ov 'kitty-gfx-heading)) + (overlay-get ov 'kitty-gfx-last-row)) + (funcall #'kitty-gfx--sixel-delete ov nil nil))))) + ;; Clean disk cache (dolist (temp-file kitty-gfx--sixel-temp-files) (ignore-errors (delete-file temp-file))) (setq kitty-gfx--sixel-temp-files nil) @@ -2097,8 +2118,9 @@ With prefix ARG \\[universal-argument], clear previews." (defun kitty-gfx--org-latex-preview-advice (orig-fn &optional arg beg end) "Around advice for `org-latex-preview'. Bypasses org's `display-graphic-p' guard so LaTeX fragments are -rendered to images via dvipng/dvisvgm and displayed via Kitty -graphics. The image generation pipeline does not require a GUI." +rendered to images via dvipng/dvisvgm and displayed via +kitty-graphics (works with both Kitty and Sixel backends). +The image generation pipeline does not require a GUI." (if (and kitty-graphics-mode (not (display-graphic-p))) (cond ;; C-u = clear previews in region/subtree @@ -2219,7 +2241,9 @@ Values > 1.0 zoom in, < 1.0 zoom out.") ;; image-mode bindings (which call native image functions ;; that fail in terminal) don't override our keymap. (setq major-mode 'kitty-gfx-image-mode - mode-name "Image[Kitty]") + mode-name (format "Image[%s]" + (pcase kitty-gfx--active-backend + ('kitty "Kitty") ('sixel "Sixel") (_ "GFX")))) (let ((map (make-sparse-keymap))) (set-keymap-parent map special-mode-map) (define-key map (kbd "q") #'kill-current-buffer) -- cgit v1.3.1