Graphics protocol check fails inside tmux
When running on kitty it works, but when running kitty->tmux the function support_graphics_protocol() doesn't return OK and:
This terminal does not support the graphics protocol.
Use a terminal such as kitty, or disable emotes.
But kitten icat image.jpg works as expected inside kitty->tmux and shows images so the graphics protocol IS supported in this context.
https://github.com/Xithrius/twitch-tui/blob/main/src/emotes/graphics_protocol.rs#L426 Here is a simple python test script to reproduce the function support_graphics_protocol() on kitty and on kitty->tmux
import sys, os, tty, termios, base64, select
data = base64.b64encode(b'AAAA').decode()
query = f"\033_Gi=31,s=1,v=1,a=q,t=d,f=24;{data}\033\\\033[c"
fd = sys.stdin.fileno()
old = termios.tcgetattr(fd)
tty.setraw(fd)
sys.stdout.write(query)
sys.stdout.flush()
r, _, _ = select.select([fd], [], [], 1)
out = os.read(fd, 4096).decode(errors="ignore") if r else "[no response]"
termios.tcsetattr(fd, termios.TCSADRAIN, old)
print(repr(out))
Output comparison:
Kitty (no tmux):
'\x1b_Gi=31;OK\x1b\\\x1b[?62;c'
kitty->tmux:
'\x1b[?1;2;4c'
So the response the Rust code is looking for (OK) isn't present when inside tmux, even though the graphics protocol clearly works.
This suggests the current check might be too strict
Yeah this problem has been around for a while, and was in issues such as #657. However when running with the check removed from the code (will have a config override for future versions), sending an emote will currently show up blank.
Searching for the emote:
After sending it:
Seems to be an issue with kitty overlays, but I haven't gone into that much depth on it (https://github.com/Xithrius/twitch-tui/pull/411#issuecomment-1696351964).
bypassing support_graphics_protocol(): the emotes don't show up, but also nothing wrong happens to the terminal. So maybe we can make a warning popup on start instead or a config override as you said.
kitten icat works
I won't open an issue on kittys' github because the author often closes them without analysis refering to a previous not analyzed issue but, will try to see what exception is being made for kitten icat
edit:
On Kitty (no tmux):
$ kitten icat --detect-support
memory
kitty->tmux:
$ kitten icat --detect-support
stream
So on tmux,kitten icat is using stream mode, whatever that means.
I think the wrong thing that does happen to the terminal is emotes not showing up, which is why the erroring-out exists in the first place. I don't know what else could break during that time, so I think the config override would be the best option in this case vs a warning. yeah that detect support flag doesn't give much. I'll dig around a bit as well.
-detect-support [=no]
Detect support for image display in the terminal. If not supported, will
exit with exit code 1, otherwise will exit with code 0 and print the
supported transfer mode to stderr, which can be used with the
--transfer-mode option.
Here's info on what stream vs memory is
--transfer-mode [=detect]
Which mechanism to use to transfer images to the terminal. The default is to
auto-detect. file means to use a temporary file, memory means to use shared
memory, stream means to send the data via terminal escape codes. Note that
if you use the file or memory transfer modes and you are connecting over a
remote session then image display will not work.
Choices: detect, file, memory, stream
--passthrough [=detect]
Whether to surround graphics commands with escape sequences that allow them
to passthrough programs like tmux. The default is to detect when running
inside tmux and automatically use the tmux passthrough escape codes. Note
that when this option is enabled it implies --unicode-placeholder as well.
Choices: detect, none, tmux
I found that kitten icat just escapes the codes when on tmux.
https://github.com/tmux/tmux/wiki/FAQ#what-is-the-passthrough-escape-sequence-and-how-do-i-use-it
So if tmux detected, or enforced via command line, or config override we could do something like:
fn wrap_for_tmux_passthrough(sequence: &str) -> String {
let escaped = sequence.replace("\x1b", "\x1b\x1b");
format!("\x1bPtmux;{}\x1b\\", escaped)
}
and then use this when writing each sequence:
let raw_sequence = gp!(...);
write!(f, "{}", wrap_for_tmux_passthrough(&raw_sequence))?;
You cannot check for graphics protocol support inside tmux. tmux will block graphics escape codes both to and from the terminal. At least when going to the terminal you can use tmux passthrough to force them through. And you have to use unicode placeholders when displaying graphics to hack around tmux.
So a solution would be:
- Checking if inside tmux ($TMUX env var),
std::env::var("TMUX").is_ok() - Wrapping output in the passthrough sequence and printing a Unicode placeholder character (like U+FFFC).
fn wrap_for_tmux_passthrough(sequence: &str) -> String {
let escaped = sequence.replace("\x1b", "\x1b\x1b");
format!("\x1bPtmux;{}\x1b\\\u{FFFC}", escaped)
}
I can look into doing this when inside tmux, but I think the issue is that I have no way to check that the underlying terminal is kitty.
I can look into doing this when inside tmux, but I think the issue is that I have no way to check that the underlying terminal is kitty.
Yeah, That is why I was thinking more of a flag to force graphics, bypassing terminal detection and adding the code to wrap_for_tmux_passthrough like in https://github.com/Xithrius/twitch-tui/issues/685#issuecomment-3066606885
My thinking is,
- adding the TMUX detection and wrap_for_tmux_passthrough()
- adding a flag to bypass SUPPORTED_TERMINALS, https://github.com/Xithrius/twitch-tui/blob/main/src/emotes/graphics_protocol.rs#L421