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}