diff options
| author | cashmere <cashmere@autistici.org> | 2026-04-26 21:14:50 +0200 |
|---|---|---|
| committer | cashmere <cashmere@autistici.org> | 2026-04-26 21:14:50 +0200 |
| commit | b4e12512a0db4ce8823e2265faf020bb222875a7 (patch) | |
| tree | 34330b69a718dfd2e4035462235fac5b78db49c7 /kitty-graphics.el | |
| parent | bcf54dda11f333b217443747f865c803dd7e489d (diff) | |
| download | kitty-graphics-b4e12512a0db4ce8823e2265faf020bb222875a7.tar.gz | |
feat(tmux): unlock Sixel backend inside tmux >= 3.4
Sixel detection used to hard-disable the moment `$TMUX' was set. That
guard predates tmux 3.4 (released 2024-02-13), which ships native Sixel
rendering, so we were rejecting a working configuration. Drop the hard
guard, gate on a parsed `tmux -V' >= 3.4, and let users opt out via a
new custom var.
- `kitty-gfx-tmux-allow-sixel' (default t). Set to nil if your tmux
build lacks `--enable-sixel' or if you want to avoid the upstream
scroll artifact (tmux's cell buffer is not pixel-aware, so images may
persist after scrolling).
- `kitty-gfx--tmux-version' parses `tmux -V' once per session and
caches the result in `kitty-gfx--tmux-version-cache' (with an
`unset' sentinel so we can distinguish "not probed" from "no tmux").
- `kitty-gfx--tmux-sixel-supported-p' centralises the (in-tmux + opt-in
+ version >= 3.4) check.
- `kitty-gfx--sixel-detect' now uses the helper instead of
`(not in-tmux)'. Debug log gained `tmux-ver=' and `tmux-ok='.
- AGENTS.md / README.org / CHANGELOG.org: limitation reworded from
"no tmux support" to a partial entry that explains exactly what works
and what the remaining caveats are (Kitty APC passthrough is still
unimplemented; scroll artifacts are upstream).
- justfile: new `test-sixel-tmux' recipe wraps `test-sixel-image' in
`tmux new-session' for one-command interactive verification, and
the sibling `test-sixel-image' recipe was switched from a fragile
shell conditional to an elisp `when' so passing an encoder argument
no longer breaks the parse.
Refs #2.
Diffstat (limited to 'kitty-graphics.el')
| -rw-r--r-- | kitty-graphics.el | 60 |
1 files changed, 56 insertions, 4 deletions
diff --git a/kitty-graphics.el b/kitty-graphics.el index 640454b..c5a1e9d 100644 --- a/kitty-graphics.el +++ b/kitty-graphics.el @@ -207,6 +207,17 @@ will otherwise block Emacs." :type '(choice (const :tag "No timeout" nil) number) :group 'kitty-graphics) +(defcustom kitty-gfx-tmux-allow-sixel t + "When non-nil, allow the Sixel backend to engage inside tmux >= 3.4. +tmux 3.4 (released 2024-02-13) ships native Sixel rendering, so this +package no longer hard-disables Sixel under tmux. Set to nil if your +tmux is built without `--enable-sixel' or if you prefer to avoid the +upstream scroll artifact: tmux's cell buffer is not pixel-aware, so +images may persist after scrolling until the affected cells are +overwritten." + :type 'boolean + :group 'kitty-graphics) + (defcustom kitty-gfx-heading-scales '((1 . 2.0) (2 . 1.5) (3 . 1.2)) "Alist mapping org heading level to visual scale factor. Headings at levels not listed use scale 1.0 (normal size). @@ -588,19 +599,60 @@ OV is the overlay (unused by Kitty backend but part of the interface)." (defvar kitty-gfx--sixel-cache (make-hash-table :test 'equal) "Maps (file . dims-string) to temp sixel file paths.") +(defvar kitty-gfx--tmux-version-cache 'unset + "Cached `kitty-gfx--tmux-version' result. +Sentinel `unset' means the probe has not run yet; nil means tmux was +absent or its version could not be parsed; otherwise a list (MAJOR MINOR).") + +(defun kitty-gfx--tmux-version () + "Return tmux version as (MAJOR MINOR) integers, or nil when unavailable. +Memoised in `kitty-gfx--tmux-version-cache'." + (when (eq kitty-gfx--tmux-version-cache 'unset) + (setq kitty-gfx--tmux-version-cache + (when (executable-find "tmux") + (with-temp-buffer + (when (zerop (ignore-errors + (call-process "tmux" nil t nil "-V"))) + (goto-char (point-min)) + (when (re-search-forward + "tmux\\(?:[[:space:]]+next-\\)?[[:space:]]+\\([0-9]+\\)\\.\\([0-9]+\\)" + nil t) + (list (string-to-number (match-string 1)) + (string-to-number (match-string 2))))))))) + kitty-gfx--tmux-version-cache) + +(defun kitty-gfx--tmux-sixel-supported-p () + "Return non-nil when running under tmux >= 3.4 with Sixel allowed. +Returns nil outside tmux, nil when `kitty-gfx-tmux-allow-sixel' is off, +nil when tmux's version cannot be determined, and nil for tmux < 3.4." + (and (getenv "TMUX") + kitty-gfx-tmux-allow-sixel + (let ((ver (kitty-gfx--tmux-version))) + (and ver + (or (> (car ver) 3) + (and (= (car ver) 3) (>= (cadr ver) 4))))))) + (defun kitty-gfx--sixel-detect () - "Return non-nil if the terminal likely supports Sixel protocol." + "Return non-nil if the terminal likely supports Sixel protocol. +Inside tmux, requires tmux >= 3.4 (native Sixel rendering, 2024-02-13) +and `kitty-gfx-tmux-allow-sixel'. Older tmux versions still disable +Sixel because they drop the DCS payload." (let* ((term (getenv "TERM")) (term-prog (getenv "TERM_PROGRAM")) (in-tmux (getenv "TMUX")) + (tmux-ver (and in-tmux (kitty-gfx--tmux-version))) + (tmux-ok (kitty-gfx--tmux-sixel-supported-p)) (supported (and term - (not in-tmux) ; Sixel doesn't work in tmux + (or (not in-tmux) tmux-ok) (or (string-match-p "xterm\\|vt[0-9]\\|foot\\|contour" term) (member term-prog '("foot" "Konsole" "mintty" "mlterm" "contour" "WezTerm"))) t))) - (kitty-gfx--log "sixel-detect: %s (TERM=%s TERM_PROGRAM=%s TMUX=%s)" - supported term term-prog (if in-tmux "yes" "no")) + (kitty-gfx--log + "sixel-detect: %s (TERM=%s TERM_PROGRAM=%s TMUX=%s tmux-ver=%s tmux-ok=%s)" + supported term term-prog (if in-tmux "yes" "no") + (if tmux-ver (format "%d.%d" (car tmux-ver) (cadr tmux-ver)) "n/a") + (if tmux-ok "yes" "no")) supported)) (defun kitty-gfx--sixel-cache-path (file cols rows) |
