Skip to main content

rmux_core/
terminal_screen.rs

1//! Public live-terminal screen facade.
2//!
3//! This module exposes the server-facing screen wrapper while keeping the
4//! parser implementation inside the crate-private `terminal` module.
5
6use rmux_proto::TerminalSize;
7
8use crate::input::OscColourSlot;
9use crate::screen::Screen;
10use crate::terminal::TerminalParser;
11use crate::terminal_passthrough::TerminalPassthrough;
12use crate::utf8::Utf8Config;
13
14/// Live terminal screen fed by rmux-core's private parser boundary.
15///
16/// `TerminalScreen` is the public core facade that server code uses to feed
17/// raw PTY bytes and inspect structured screen cells. The parser itself stays
18/// hidden behind the crate-private terminal module, so SDK/protocol code can
19/// depend on screen-cell semantics without coupling to parser internals.
20pub struct TerminalScreen {
21    parser: TerminalParser,
22}
23
24impl TerminalScreen {
25    /// Builds a fresh terminal screen with the given geometry and scrollback
26    /// limit.
27    #[must_use]
28    pub fn new(size: TerminalSize, history_limit: usize) -> Self {
29        Self {
30            parser: TerminalParser::new(size, history_limit),
31        }
32    }
33
34    /// Returns a borrow of the structured screen grid.
35    #[must_use]
36    pub fn screen(&self) -> &Screen {
37        self.parser.screen()
38    }
39
40    /// Returns a mutable borrow of the structured screen grid.
41    pub fn screen_mut(&mut self) -> &mut Screen {
42        self.parser.screen_mut()
43    }
44
45    /// Returns whether plain printable output can bypass structured rendering
46    /// without losing parser or screen semantics.
47    #[must_use]
48    pub fn plain_output_forwarding_safe(&self) -> bool {
49        self.parser.plain_output_forwarding_safe()
50    }
51
52    /// Updates the tmux-style UTF-8 width and combining configuration.
53    pub fn set_utf8_config(&mut self, config: Utf8Config) {
54        self.parser.set_utf8_config(config);
55    }
56
57    /// Enables or disables DEC alternate-screen entry for subsequent output.
58    pub fn set_alternate_screen_enabled(&mut self, enabled: bool) {
59        self.parser.set_alternate_screen_enabled(enabled);
60    }
61
62    /// Enables or disables title changes requested by pane output.
63    pub fn set_title_rename_enabled(&mut self, enabled: bool) {
64        self.parser.set_title_rename_enabled(enabled);
65    }
66
67    /// Updates the tmux `input-buffer-size` parser limit.
68    pub fn set_input_buffer_limit(&mut self, limit: usize) {
69        self.parser.set_input_buffer_limit(limit);
70    }
71
72    /// Resizes the screen and resets the scroll region.
73    pub fn resize(&mut self, size: TerminalSize) {
74        self.parser.resize(size);
75    }
76
77    /// Feeds raw PTY output bytes through the private parser into the screen.
78    pub fn feed(&mut self, bytes: &[u8]) {
79        self.parser.feed(bytes);
80    }
81
82    /// Returns and clears whether the latest feeds used terminal-parser state
83    /// that an ANSI recovery keyframe cannot reconstruct.
84    ///
85    /// Callers publishing raw continuation bytes must replace that
86    /// continuation with an authoritative post-dispatch keyframe.
87    #[must_use]
88    pub fn take_recovery_rebase_required(&mut self) -> bool {
89        self.parser.take_recovery_rebase_required()
90    }
91
92    /// Returns and drains terminal replies generated while parsing PTY output.
93    pub fn take_replies(&mut self) -> Vec<u8> {
94        self.parser.take_replies()
95    }
96
97    /// Returns any bytes still buffered inside an incomplete parser state.
98    #[must_use]
99    pub fn pending_bytes(&self) -> Vec<u8> {
100        self.parser.pending_bytes()
101    }
102
103    /// Borrows bytes buffered inside an incomplete parser state.
104    #[must_use]
105    pub fn pending_bytes_ref(&self) -> &[u8] {
106        self.parser.pending_bytes_ref()
107    }
108
109    /// Clones renderer state, including bounded scrollback and saved buffers.
110    #[must_use]
111    pub fn clone_recovery_screen(&self) -> Screen {
112        self.parser.clone_recovery_screen()
113    }
114
115    /// Returns ANSI restoring the parser's active rendition and character sets.
116    #[must_use]
117    pub fn active_cell_state_ansi(&self) -> Vec<u8> {
118        self.parser.active_cell_state_ansi()
119    }
120
121    /// Returns bounded ANSI for the active rendition and whether metadata was
122    /// represented completely.
123    #[must_use]
124    pub fn active_cell_state_ansi_bounded(&self, max_hyperlink_bytes: usize) -> (Vec<u8>, bool) {
125        self.parser
126            .active_cell_state_ansi_bounded(max_hyperlink_bytes)
127    }
128
129    /// Returns ANSI restoring the rendition saved by DECSC/SCP.
130    #[must_use]
131    pub fn saved_cell_state_ansi(&self) -> Vec<u8> {
132        self.parser.saved_cell_state_ansi()
133    }
134
135    /// Returns bounded ANSI for the saved rendition and whether metadata was
136    /// represented completely.
137    #[must_use]
138    pub fn saved_cell_state_ansi_bounded(&self, max_hyperlink_bytes: usize) -> (Vec<u8>, bool) {
139        self.parser
140            .saved_cell_state_ansi_bounded(max_hyperlink_bytes)
141    }
142
143    /// Returns the cursor and origin mode saved by DECSC/SCP.
144    #[must_use]
145    pub fn saved_cursor_state(&self) -> (u32, u32, bool) {
146        self.parser.saved_cursor_state()
147    }
148
149    /// Returns ANSI restoring parser-owned state that has a faithful terminal
150    /// representation, such as application-defined dynamic colours.
151    #[must_use]
152    pub fn recovery_parser_state_ansi(&self) -> Vec<u8> {
153        self.parser.recovery_parser_state_ansi()
154    }
155
156    /// Returns an application-defined OSC 10/11/12 colour.
157    #[must_use]
158    pub fn dynamic_colour(&self, slot: OscColourSlot) -> Option<&str> {
159        self.parser.dynamic_colour(slot)
160    }
161
162    /// Returns whether the parser ground timeout is currently armed.
163    #[must_use]
164    pub fn ground_timer_active(&self) -> bool {
165        self.parser.ground_timer_active()
166    }
167
168    /// Notifies the parser that its ground timeout has expired.
169    pub fn ground_timer_expired(&mut self) {
170        self.parser.ground_timer_expired();
171    }
172
173    /// Returns and drains passthrough events generated while parsing PTY output.
174    pub fn take_terminal_passthrough(&mut self) -> Vec<TerminalPassthrough> {
175        self.parser.take_terminal_passthrough()
176    }
177
178    /// Returns and drains passthrough events dropped by parser safety limits.
179    pub fn take_terminal_passthrough_dropped_count(&mut self) -> u64 {
180        self.parser.take_terminal_passthrough_dropped_count()
181    }
182
183    /// Replaces the hidden parser with a fresh ground-state instance while
184    /// preserving the current screen grid.
185    pub fn reset_parser(&mut self) {
186        self.parser.reset_parser();
187    }
188}