Skip to main content

uncurses/ansi/
termcap.rs

1//! XTGETTCAP capability queries.
2//!
3//! ## Category
4//!
5//! XTGETTCAP asks a terminal to report termcap/terminfo-style capability values
6//! using a DCS `+q` request.
7//!
8//! ## DCS framing
9//!
10//! The writer emits `ESC P + q <hex-name>[;<hex-name>...] ESC \\`. Capability
11//! names are uppercase hexadecimal byte strings; an empty request emits nothing.
12//!
13//! ## Mode interaction
14//!
15//! XTGETTCAP is a query, not a mode. Replies arrive asynchronously as DCS
16//! strings and must be parsed by input handling code.
17
18use std::io::{self, Write};
19
20/// Request terminal capability values with XTGETTCAP, `ESC P + q <hex-caps> ESC \`.
21///
22/// Each capability name in `caps` is hex-encoded as uppercase bytes and separated with `;`. An empty slice emits nothing.
23pub fn write_xtgettcap<W: Write>(w: &mut W, caps: &[&str]) -> io::Result<()> {
24    if caps.is_empty() {
25        return Ok(());
26    }
27    w.write_all(b"\x1bP+q")?;
28    for (i, c) in caps.iter().enumerate() {
29        if i > 0 {
30            w.write_all(b";")?;
31        }
32        for byte in c.bytes() {
33            write!(w, "{byte:02X}")?;
34        }
35    }
36    w.write_all(b"\x1b\\")
37}
38
39#[cfg(test)]
40mod tests {
41    use super::*;
42
43    #[test]
44    fn test_xtgettcap() {
45        let mut buf = Vec::new();
46        write_xtgettcap(&mut buf, &["Co", "TN"]).unwrap();
47        assert_eq!(buf, b"\x1bP+q436F;544E\x1b\\");
48    }
49
50    #[test]
51    fn test_xtgettcap_single_key() {
52        // The truecolor-probe path queries one capability per request.
53        let mut buf = Vec::new();
54        write_xtgettcap(&mut buf, &["RGB"]).unwrap();
55        assert_eq!(buf, b"\x1bP+q524742\x1b\\");
56        let mut buf = Vec::new();
57        write_xtgettcap(&mut buf, &["Tc"]).unwrap();
58        assert_eq!(buf, b"\x1bP+q5463\x1b\\");
59    }
60
61    #[test]
62    fn test_xtgettcap_empty() {
63        let mut buf = Vec::new();
64        write_xtgettcap(&mut buf, &[]).unwrap();
65        assert!(buf.is_empty());
66    }
67}