diff options
| author | unship <liyananfamily@gmail.com> | 2026-04-30 16:25:21 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-04-30 10:25:21 +0200 |
| commit | 632b33b6ecbc3e2a7c8277effcac9b2de0fff5a9 (patch) | |
| tree | 30d91a02cf24d29219044f40e244f268131ad7ae | |
| parent | 91f9a3bbef5f275d0b8dc0a79dc4a4e0e04324ca (diff) | |
| download | kitty-graphics-632b33b6ecbc3e2a7c8277effcac9b2de0fff5a9.tar.gz | |
fix(detect): read terminal env from frame for emacs --daemon (#15)
`kitty-gfx--kitty-detect' and `kitty-gfx--sixel-detect' read TERM,
TERM_PROGRAM, TMUX, KITTY_PID, and the WT_* markers via
`(getenv VAR)' -- the process-level lookup. Under
`emacs --daemon' / `emacsclient -t', the daemon process inherits
the launcher's env (often `TERM=dumb' from a systemd unit, no
TMUX, no TERM_PROGRAM); the *attached client* env lives on the
new frame's `environment' parameter. As a result, every detect
call sees daemon env and reports "terminal not supported" even
when the client is attached from a fully sixel-/kitty-capable
terminal inside tmux.
Note `(getenv VAR FRAME)' only consults the frame env (no
process fallback), and `(getenv VAR)' only consults the process
env first (then the *selected* frame's env). Neither alone gives
the desired prefer-frame-then-process semantics. Add a small
helper `kitty-gfx--frame-getenv' that does, and route both detect
functions plus `kitty-gfx--tmux-sixel-supported-p' through it.
For TERM specifically also consult the frame's `tty-type'
parameter, which is set by `server-create-tty-frame' and is the
canonical TERM emacs uses for this frame -- preferred over the
env value when the latter is missing or `dumb'.
Repro before this patch (Linux, ghostty + tmux, emacs daemon):
*kitty-gfx-debug*:
kitty-detect: nil (KITTY_PID=nil TERM_PROGRAM=tmux)
sixel-detect: nil (TERM=dumb TERM_PROGRAM=tmux TMUX=yes
tmux-ver=3.6 tmux-ok=yes WT=no)
mode: terminal not supported, aborting enable
After the patch the detectors read the frame env, so TERM
resolves to the actual `tmux-256color' / `xterm-kitty' / etc.
and the matching backend is picked.
Behaviour unchanged for non-daemon emacs: when the frame has no
`environment' parameter, `kitty-gfx--frame-getenv' falls back to
the process env directly.
| -rw-r--r-- | kitty-graphics.el | 63 |
1 files changed, 46 insertions, 17 deletions
diff --git a/kitty-graphics.el b/kitty-graphics.el index 4879de6..7ae9cb7 100644 --- a/kitty-graphics.el +++ b/kitty-graphics.el @@ -545,14 +545,31 @@ Uses direct placement: move cursor, then `a=p' with `c' and `r' params." ;;;; Kitty backend +(defun kitty-gfx--frame-getenv (var &optional frame) + "Return env VAR for FRAME, preferring frame env over process env. +Daemon Emacs (`emacs --daemon' / `emacsclient -t') sets the attached +client's TERM, TERM_PROGRAM, TMUX, etc. on the frame's `environment' +parameter, while the daemon process inherits whatever shell launched +it (often `TERM=dumb' from a non-tty service unit). Plain +`getenv VAR FRAME' looks ONLY at the frame env, so it returns nil +for vars the client did not forward; plain `getenv VAR' looks at +process env first and never sees the client's value. This helper +returns the frame env when present and falls back to the process +env otherwise." + (let ((f (or frame (selected-frame)))) + (or (getenv var f) (getenv var)))) + (defun kitty-gfx--kitty-detect () - "Return non-nil if the terminal supports Kitty graphics protocol." - (let ((supported (or (getenv "KITTY_PID") - (equal (getenv "TERM_PROGRAM") "kitty") - (equal (getenv "TERM_PROGRAM") "WezTerm") - (equal (getenv "TERM_PROGRAM") "ghostty")))) + "Return non-nil if the terminal supports Kitty graphics protocol. +Reads env vars via `kitty-gfx--frame-getenv' so emacs --daemon +clients see the attached terminal's environment." + (let* ((frame (selected-frame)) + (kitty-pid (kitty-gfx--frame-getenv "KITTY_PID" frame)) + (term-prog (kitty-gfx--frame-getenv "TERM_PROGRAM" frame)) + (supported (or kitty-pid + (member term-prog '("kitty" "WezTerm" "ghostty"))))) (kitty-gfx--log "kitty-detect: %s (KITTY_PID=%s TERM_PROGRAM=%s)" - supported (getenv "KITTY_PID") (getenv "TERM_PROGRAM")) + supported kitty-pid term-prog) supported)) (defun kitty-gfx--kitty-prepare (file image-id) @@ -621,11 +638,13 @@ Memoised in `kitty-gfx--tmux-version-cache'." (string-to-number (match-string 2))))))))) kitty-gfx--tmux-version-cache) -(defun kitty-gfx--tmux-sixel-supported-p () +(defun kitty-gfx--tmux-sixel-supported-p (&optional frame) "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") +nil when tmux's version cannot be determined, and nil for tmux < 3.4. +TMUX is read via `kitty-gfx--frame-getenv' so this works under +emacs --daemon clients; FRAME defaults to the selected frame." + (and (kitty-gfx--frame-getenv "TMUX" frame) kitty-gfx-tmux-allow-sixel (let ((ver (kitty-gfx--tmux-version))) (and ver @@ -636,17 +655,27 @@ nil when tmux's version cannot be determined, and nil for tmux < 3.4." "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")) +Sixel because they drop the DCS payload. + +Reads env vars via `kitty-gfx--frame-getenv' so emacs --daemon +clients see the attached terminal's environment. Falls back to the +frame's `tty-type' parameter when TERM is missing or `dumb', which +is typical for daemons launched from a non-tty service unit." + (let* ((frame (selected-frame)) + (frame-term (frame-parameter frame 'tty-type)) + (env-term (kitty-gfx--frame-getenv "TERM" frame)) + (term (cond ((and frame-term (not (equal frame-term "dumb"))) frame-term) + ((and env-term (not (equal env-term "dumb"))) env-term) + (t (or frame-term env-term)))) + (term-prog (kitty-gfx--frame-getenv "TERM_PROGRAM" frame)) + (in-tmux (kitty-gfx--frame-getenv "TMUX" frame)) (tmux-ver (and in-tmux (kitty-gfx--tmux-version))) - (tmux-ok (kitty-gfx--tmux-sixel-supported-p)) + (tmux-ok (kitty-gfx--tmux-sixel-supported-p frame)) ;; Windows Terminal's TERM value is not stable enough to rely on ;; alone, so accept its session markers when present. - (windows-terminal (or (getenv "WT_SESSION") - (getenv "WT_PROFILE_ID") - (getenv "WT_WINDOWID"))) + (windows-terminal (or (kitty-gfx--frame-getenv "WT_SESSION" frame) + (kitty-gfx--frame-getenv "WT_PROFILE_ID" frame) + (kitty-gfx--frame-getenv "WT_WINDOWID" frame))) (supported (and term (or (not in-tmux) tmux-ok) (or (string-match-p "xterm\\|vt[0-9]\\|foot\\|contour" term) |
