pub fn detect_sixel_via_device_attributes(timeout_ms: u64) -> Option<bool> {
#[cfg(unix)]
{
let _raw_mode = unix::RawModeGuard::enable().ok()?;
query(timeout_ms)
}
#[cfg(windows)]
{
query(timeout_ms)
}
#[cfg(not(any(unix, windows)))]
{
let _ = timeout_ms;
None
}
}
#[cfg_attr(not(any(unix, windows)), allow(dead_code))]
fn query(timeout_ms: u64) -> Option<bool> {
let response = xterm_query::query("\x1b[c", timeout_ms).ok()?;
Some(response_indicates_sixel(&response))
}
fn response_indicates_sixel(response: &str) -> bool {
response
.trim_start_matches(['\u{1b}', '['])
.trim_end_matches('c')
.trim_start_matches('?')
.split(';')
.skip(1)
.any(|part| part == "4")
}
#[cfg(unix)]
mod unix {
use rustix::termios::{tcgetattr, tcsetattr, OptionalActions, Termios};
use std::fs::File;
use std::io;
pub(super) struct RawModeGuard {
tty: File,
original: Termios,
}
impl RawModeGuard {
pub(super) fn enable() -> io::Result<Self> {
let tty = File::open("/dev/tty")?;
let original = tcgetattr(&tty)?;
let mut raw = original.clone();
raw.make_raw();
tcsetattr(&tty, OptionalActions::Now, &raw)?;
Ok(Self { tty, original })
}
}
impl Drop for RawModeGuard {
fn drop(&mut self) {
let _ = tcsetattr(&self.tty, OptionalActions::Now, &self.original);
}
}
}
#[cfg(test)]
mod tests {
use super::response_indicates_sixel;
#[test]
fn response_indicates_sixel_true_when_extension_4_present() {
assert!(response_indicates_sixel("\u{1b}[?62;1;2;4;6;9;15;22c"));
}
#[test]
fn response_indicates_sixel_false_when_extension_4_absent() {
assert!(!response_indicates_sixel("\u{1b}[?62;1;2;6;9;15;22c"));
}
#[test]
fn response_indicates_sixel_ignores_terminal_class_matching_4() {
assert!(!response_indicates_sixel("\u{1b}[?4;1;2c"));
}
#[test]
fn response_indicates_sixel_false_for_malformed_response() {
assert!(!response_indicates_sixel(""));
assert!(!response_indicates_sixel("garbage"));
}
}