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//! - Non-allocating `RopeSlice` APIs are provided for hot paths.
6//! - Allocating `String` helpers remain for ergonomics.
7
8use std::cmp::min;
9
10use ropey::RopeSlice;
11
12use super::TextBuffer;
13use crate::buffer::{Pos, Selection};
14
15impl TextBuffer {
16 /// Get a non-allocating slice for a character range `[start, end)`.
17 ///
18 /// - Indices are clamped to the buffer bounds.
19 /// - If `start > end`, the values are swapped.
20 pub fn slice_chars_ref(&self, mut start: usize, mut end: usize) -> RopeSlice<'_> {
21 let maxc = self.len_chars();
22 start = min(start, maxc);
23 end = min(end, maxc);
24 if start > end {
25 std::mem::swap(&mut start, &mut end);
26 }
27 self.rope().slice(start..end)
28 }
29
30 /// Get a non-allocating slice for a selection (ordered).
31 pub fn slice_selection_ref(&self, sel: Selection) -> RopeSlice<'_> {
32 let (a, b) = sel.ordered();
33 let start = self.pos_to_char(a);
34 let end = self.pos_to_char(b);
35 self.slice_chars_ref(start, end)
36 }
37
38 /// Convenience: non-allocating slice by two logical positions (order-independent).
39 pub fn slice_pos_range_ref(&self, a: Pos, b: Pos) -> RopeSlice<'_> {
40 let start = self.pos_to_char(a);
41 let end = self.pos_to_char(b);
42 self.slice_chars_ref(start, end)
43 }
44
45 /// Get the full buffer as a `String`.
46 ///
47 /// For large buffers, this allocates. Kept as an inherent method so call sites
48 /// can use `b.to_string()` without depending on `Display`/`ToString`.
49 #[inline]
50 pub fn to_string(&self) -> String {
51 self.rope().to_string()
52 }
53
54 /// Get a `String` for a character range `[start, end)`.
55 ///
56 /// - Indices are clamped to the buffer bounds.
57 /// - If `start > end`, the values are swapped.
58 ///
59 /// This is a convenience API; it allocates.
60 pub fn slice_chars(&self, start: usize, end: usize) -> String {
61 self.slice_chars_ref(start, end).to_string()
62 }
63
64 /// Get the selected text for a selection (ordered).
65 ///
66 /// This is a convenience API; it allocates.
67 pub fn slice_selection(&self, sel: Selection) -> String {
68 self.slice_selection_ref(sel).to_string()
69 }
70
71 /// Convenience: slice by two logical positions (order-independent).
72 ///
73 /// This is useful when there are two cursors/marks and the substring
74 /// between them without explicitly building a `Selection`.
75 pub fn slice_pos_range(&self, a: Pos, b: Pos) -> String {
76 self.slice_pos_range_ref(a, b).to_string()
77 }
78}