rmux_core/
terminal_passthrough.rs1use std::sync::Arc;
2
3pub(crate) const MAX_TERMINAL_PASSTHROUGH_PAYLOAD_BYTES: usize = 8 * 1024 * 1024;
5
6#[derive(Debug, Clone, PartialEq, Eq)]
8pub struct TerminalPassthrough {
9 kind: TerminalPassthroughKind,
10 cursor_x: u32,
11 cursor_y: u32,
12 payload: Arc<[u8]>,
13}
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub enum TerminalPassthroughKind {
18 KittyGraphics,
20 Sixel,
22}
23
24impl TerminalPassthrough {
25 #[must_use]
27 pub fn kitty_graphics(cursor_x: u32, cursor_y: u32, payload: impl Into<Vec<u8>>) -> Self {
28 Self {
29 kind: TerminalPassthroughKind::KittyGraphics,
30 cursor_x,
31 cursor_y,
32 payload: Arc::from(payload.into()),
33 }
34 }
35
36 #[must_use]
38 pub fn sixel(cursor_x: u32, cursor_y: u32, payload: impl Into<Vec<u8>>) -> Self {
39 Self {
40 kind: TerminalPassthroughKind::Sixel,
41 cursor_x,
42 cursor_y,
43 payload: Arc::from(payload.into()),
44 }
45 }
46
47 #[must_use]
49 pub const fn kind(&self) -> TerminalPassthroughKind {
50 self.kind
51 }
52
53 #[must_use]
55 pub const fn cursor_x(&self) -> u32 {
56 self.cursor_x
57 }
58
59 #[must_use]
61 pub const fn cursor_y(&self) -> u32 {
62 self.cursor_y
63 }
64
65 #[must_use]
67 pub fn payload(&self) -> &[u8] {
68 &self.payload
69 }
70
71 #[must_use]
73 pub fn render_sequence(&self) -> Vec<u8> {
74 match self.kind {
75 TerminalPassthroughKind::KittyGraphics => {
76 let mut sequence = Vec::with_capacity(self.payload.len() + 4);
77 sequence.extend_from_slice(b"\x1b_");
78 sequence.extend_from_slice(&self.payload);
79 sequence.extend_from_slice(b"\x1b\\");
80 sequence
81 }
82 TerminalPassthroughKind::Sixel => {
83 let mut sequence = Vec::with_capacity(self.payload.len() + 4);
84 sequence.extend_from_slice(b"\x1bP");
85 sequence.extend_from_slice(&self.payload);
86 sequence.extend_from_slice(b"\x1b\\");
87 sequence
88 }
89 }
90 }
91}
92
93#[cfg(test)]
94mod tests {
95 use super::TerminalPassthrough;
96
97 #[test]
98 fn renders_kitty_apc_sequence() {
99 let passthrough = TerminalPassthrough::kitty_graphics(0, 0, b"Gf=100;AAAA".to_vec());
100
101 assert_eq!(passthrough.render_sequence(), b"\x1b_Gf=100;AAAA\x1b\\");
102 }
103
104 #[test]
105 fn renders_sixel_dcs_sequence() {
106 let passthrough = TerminalPassthrough::sixel(0, 0, b"q#0!10~".to_vec());
107
108 assert_eq!(passthrough.render_sequence(), b"\x1bPq#0!10~\x1b\\");
109 }
110}