Skip to main content

redox_core/buffer/text_buffer/
slicing.rs

1//! `TextBuffer` slicing helpers.
2//!
3//! Design notes:
4//! - All indices are **character indices** (Unicode scalar values) to match `ropey`.
5//! - These helpers are intentionally allocating (`String`) for ergonomics.
6//!   If I later need more performance, add `RopeSlice`-returning variants
7//!   without changing call sites that just need owned strings.
8
9use std::cmp::min;
10
11use super::TextBuffer;
12use crate::buffer::{Pos, Selection};
13
14impl TextBuffer {
15    /// Get the full buffer as a `String`.
16    ///
17    /// For large buffers, this allocates. Kept as an inherent method so call sites
18    /// can use `b.to_string()` without depending on `Display`/`ToString`.
19    #[inline]
20    pub fn to_string(&self) -> String {
21        self.rope().to_string()
22    }
23
24    /// Get a `String` for a character range `[start, end)`.
25    ///
26    /// - Indices are clamped to the buffer bounds.
27    /// - If `start > end`, the values are swapped.
28    ///
29    /// This is a convenience API; it allocates.
30    pub fn slice_chars(&self, mut start: usize, mut end: usize) -> String {
31        let maxc = self.len_chars();
32        start = min(start, maxc);
33        end = min(end, maxc);
34        if start > end {
35            std::mem::swap(&mut start, &mut end);
36        }
37        self.rope().slice(start..end).to_string()
38    }
39
40    /// Get the selected text for a selection (ordered).
41    ///
42    /// This is a convenience API; it allocates.
43    pub fn slice_selection(&self, sel: Selection) -> String {
44        let (a, b) = sel.ordered();
45        let start = self.pos_to_char(a);
46        let end = self.pos_to_char(b);
47        self.slice_chars(start, end)
48    }
49
50    /// Convenience: slice by two logical positions (order-independent).
51    ///
52    /// This is useful if there are two cursors/marks and I want the substring
53    /// between them without explicitly building a `Selection`.
54    pub fn slice_pos_range(&self, a: Pos, b: Pos) -> String {
55        let start = self.pos_to_char(a);
56        let end = self.pos_to_char(b);
57        self.slice_chars(start, end)
58    }
59}