Skip to main content

rmux_core/screen/
capture.rs

1use crate::grid::{Grid, GridCapture, GridRenderOptions, GridStringState};
2use crate::hyperlinks::Hyperlinks;
3use crate::transcript::{resolve_screen_capture_range, ScreenCaptureRange};
4
5use super::Screen;
6
7impl Screen {
8    #[cfg_attr(not(test), allow(dead_code))]
9    #[must_use]
10    pub(crate) fn capture_grid(&self, join_wrapped: bool) -> GridCapture {
11        self.grid.capture(join_wrapped)
12    }
13
14    /// Captures a tmux-style line range over the current grid contents.
15    #[must_use]
16    pub fn capture_transcript(
17        &self,
18        range: ScreenCaptureRange,
19        options: GridRenderOptions,
20    ) -> Vec<u8> {
21        capture_grid_bytes(&self.grid, &self.hyperlinks, range, options)
22    }
23
24    /// Captures the saved pre-alternate-screen copy when alternate mode is active.
25    #[must_use]
26    pub fn capture_saved_transcript(
27        &self,
28        range: ScreenCaptureRange,
29        options: GridRenderOptions,
30    ) -> Option<Vec<u8>> {
31        self.saved_grid
32            .as_ref()
33            .map(|saved| capture_grid_bytes(&saved.grid, &self.hyperlinks, range, options))
34    }
35}
36
37fn capture_grid_bytes(
38    grid: &Grid,
39    hyperlinks: &Hyperlinks,
40    range: ScreenCaptureRange,
41    options: GridRenderOptions,
42) -> Vec<u8> {
43    let total_lines = grid.hsize() + usize::try_from(grid.sy()).unwrap_or(usize::MAX);
44    let Some(range) = resolve_screen_capture_range(range, grid.hsize(), total_lines) else {
45        return Vec::new();
46    };
47
48    let mut output = Vec::new();
49    let mut state = GridStringState::default();
50    for absolute_y in range {
51        let Some(line) =
52            grid.render_absolute_line(absolute_y, options, &mut state, Some(hyperlinks))
53        else {
54            continue;
55        };
56        output.extend_from_slice(line.as_bytes());
57        let wrapped = grid.absolute_line_wrapped(absolute_y).unwrap_or(false);
58        if !options.join_wrapped || !wrapped {
59            output.push(b'\n');
60        }
61    }
62    output
63}