Repository navigation
Conversation
Kitty graphics do not render inside tmux even with passthrough enabled. The graphics sequences were sent directly to the terminal, but tmux intercepted them instead of forwarding them to Kitty. When running inside tmux, graphics commands are now wrapped in tmux DCS passthrough sequences, with embedded ESC bytes doubled. This allows Kitty to receive and render images without changing the existing rendering logic.
|
Thank you for this, and for the clear write-up with before and after screenshots. tmux users only get alt text today, so I would like to fix this. I do not want to merge it in this form, though, for these reasons. I do not use tmux myself, so these come from reading the code rather than from running it. Please correct me if I have misread something.
Today a tmux user sees alt text, which is limited but correct. With this change, depending on the layout, some users would instead see images over the wrong part of the screen that stay after they switch away, so I think it would be a step back for them. There is a plan for this in #61. denny0223 found the same thing there: detection and DCS passthrough alone put the image at the top-left, and placement needs Unicode placeholders. The scope we agreed on is the native backend (no Snacks), no change outside tmux, Neovim 0.12, and a small interface so that denny0223 has also offered to work on this, but there is no need to coordinate in advance. If you would like to rework this PR into the first step, please go ahead: passthrough plus detection of a Kitty client attached to tmux, with a test that checks the wrapped output rather than unwrapping it. Whichever PR along these lines comes first, I will mention the other person on #61 so that nobody duplicates the work. I would keep the first step unreleased until placement lands, so that nobody gets the misplaced images in between. Separately, #78 proposes routing every image transmission through one helper so that images can be sent as data over SSH. If that lands first, passthrough fits there naturally. tmux limits how much one passthrough sequence may carry, so each chunk would need to be wrapped on its own. I will leave this PR open while that is sorted out. |
Wrap each Kitty graphics command in tmux DCS passthrough instead of wrapping an entire output batch. Cursor movement remains handled by tmux, preserving pane-relative placement coordinates. Detect an xterm-kitty client attached through tmux when KITTY_WINDOW_ID is unavailable.
|
I reworked this into the requested detection-and-transport first step.
I have intentionally left Unicode-placeholder placement and lifecycle handling out of this change. This should remain unreleased until that follow-up lands. Screenshot evidence of the Kitty suuport:
|

What was happening
Kitty graphics did not render inside tmux, even with
allow-passthroughenabled.The plugin sends Kitty graphics commands through
vim.api.nvim_ui_send(). This works when Neovim runs directly inside Kitty, but tmux sits between Neovim and the terminal and does not transparently forward Kitty graphics escape sequences.The plugin correctly detected Kitty support (
supports_kitty()returnedtrue), andkitten icatsuccessfully displayed images inside the same tmux session. The missing piece was tmux passthrough framing.What fixed it
Wrap Kitty graphics commands in tmux DCS passthrough sequences, doubling embedded ESC bytes as required by the protocol.
The wrapper is applied only when both conditions are met:
TMUXis set).ESC_G).Outside tmux, the original output is preserved. Non-graphics writes and the existing image rendering logic remain unchanged.
Verification
Before
After
Known limitation
Images can remain visible after switching tmux windows because Kitty manages graphics placements independently of tmux's screen contents.
tmux must have passthrough enabled:
set -g allow-passthrough on