Skip to main content

ratatui_core/terminal/
backend.rs

1use crate::backend::Backend;
2use crate::layout::Size;
3use crate::terminal::Terminal;
4
5impl<B: Backend> Terminal<B> {
6    /// Returns a shared reference to the backend.
7    ///
8    /// This is primarily useful for backend-specific inspection in tests (e.g. reading
9    /// [`TestBackend`]'s buffer) or for backend-specific APIs that Ratatui does not model.
10    ///
11    /// Reading from the backend does not desynchronize Ratatui, but values observed here may lag
12    /// behind the current render callback because Ratatui does not apply a frame to the backend
13    /// until the end of [`Terminal::draw`] / [`Terminal::try_draw`].
14    ///
15    /// [`TestBackend`]: crate::backend::TestBackend
16    pub const fn backend(&self) -> &B {
17        &self.backend
18    }
19
20    /// Returns a mutable reference to the backend.
21    ///
22    /// This is an advanced escape hatch. Normal applications should render through
23    /// [`Terminal::draw`] / [`Terminal::try_draw`] instead of mutating the backend directly.
24    ///
25    /// Use this when integrating with backend-specific APIs that Ratatui does not model, or when
26    /// tests need direct control over backend state.
27    ///
28    /// Mutating the backend directly can desynchronize Ratatui's internal buffers, cursor
29    /// tracking, or viewport assumptions from what's on-screen. If you do this, call
30    /// [`Terminal::clear`] or perform a full draw pass before relying on Ratatui's view of the
31    /// terminal again.
32    ///
33    /// [`Terminal::clear`]: crate::terminal::Terminal::clear
34    /// [`Terminal::draw`]: crate::terminal::Terminal::draw
35    /// [`Terminal::try_draw`]: crate::terminal::Terminal::try_draw
36    pub const fn backend_mut(&mut self) -> &mut B {
37        &mut self.backend
38    }
39
40    /// Queries the real size of the backend.
41    ///
42    /// This returns the backend's current terminal size and does not update Ratatui's internal
43    /// viewport bookkeeping by itself. The current renderable area depends on the configured
44    /// [`Viewport`]; use [`Frame::area`] inside [`Terminal::draw`] / [`Terminal::try_draw`] if you
45    /// want the area you should render into for the current pass.
46    ///
47    /// To make Ratatui observe backend size changes for fullscreen or inline viewports, see
48    /// [`Terminal::autoresize`].
49    ///
50    /// [`Frame::area`]: crate::terminal::Frame::area
51    /// [`Terminal::autoresize`]: crate::terminal::Terminal::autoresize
52    /// [`Terminal::draw`]: crate::terminal::Terminal::draw
53    /// [`Terminal::try_draw`]: crate::terminal::Terminal::try_draw
54    /// [`Viewport`]: crate::terminal::Viewport
55    pub fn size(&self) -> Result<Size, B::Error> {
56        self.backend.size()
57    }
58}
59
60#[cfg(test)]
61mod tests {
62    use crate::backend::TestBackend;
63    use crate::layout::{Position, Size};
64    use crate::terminal::Terminal;
65
66    #[test]
67    fn backend_returns_shared_reference() {
68        let backend = TestBackend::new(3, 2);
69        let terminal = Terminal::new(backend).unwrap();
70
71        assert_eq!(terminal.backend().cursor_position(), Position::ORIGIN);
72    }
73
74    #[test]
75    fn backend_mut_allows_mutating_backend_state() {
76        let backend = TestBackend::new(3, 2);
77        let mut terminal = Terminal::new(backend).unwrap();
78
79        terminal.backend_mut().resize(4, 3);
80
81        assert_eq!(terminal.size().unwrap(), Size::new(4, 3));
82        terminal
83            .backend()
84            .assert_buffer_lines(["    ", "    ", "    "]);
85    }
86
87    #[test]
88    fn size_queries_underlying_backend_size() {
89        let mut backend = TestBackend::new(3, 2);
90        backend.resize(4, 3);
91        let terminal = Terminal::new(backend).unwrap();
92
93        assert_eq!(terminal.size().unwrap(), Size::new(4, 3));
94    }
95}