Skip to main content

text_editing/
selection.rs

1use std::ops::Range;
2
3use super::TextLine;
4
5impl TextLine {
6    /// Returns the ordered selection range from an anchor and cursor position.
7    ///
8    /// Returns `None` if no anchor is set.
9    ///
10    /// # Arguments
11    /// * `cursor` - The current text cursor position.
12    /// * `anchor` - The optional selection anchor position.
13    ///
14    /// # Examples
15    /// ```
16    /// use text_editing::TextLine;
17    ///
18    /// assert_eq!(TextLine::selection_range(10, Some(5)), Some(5..10));
19    /// assert_eq!(TextLine::selection_range(3, Some(8)), Some(3..8));
20    /// assert_eq!(TextLine::selection_range(5, None), None);
21    /// ```
22    pub fn selection_range(cursor: usize, anchor: Option<usize>) -> Option<Range<usize>> {
23        let a = anchor?;
24        Some(a.min(cursor)..a.max(cursor))
25    }
26
27    /// Returns the selected text, if a selection is active.
28    ///
29    /// # Arguments
30    /// * `cursor` - The current text cursor position.
31    /// * `anchor` - The optional selection anchor position.
32    ///
33    /// # Examples
34    /// ```
35    /// use text_editing::TextLine;
36    ///
37    /// let line = TextLine::from_string("Hello, world!".into());
38    /// assert_eq!(line.selected_text(12, Some(7)), Some("world"));
39    /// assert_eq!(line.selected_text(5, None), None);
40    /// ```
41    pub fn selected_text(&self, cursor: usize, anchor: Option<usize>) -> Option<&str> {
42        Self::selection_range(cursor, anchor)
43            .map(|range| &self.text[self.string_index(range.start)..self.string_index(range.end)])
44    }
45
46    /// Deletes the currently selected text and updates cursor and anchor.
47    ///
48    /// Returns `true` if text was deleted, `false` if no selection was active
49    /// or the selection was empty.
50    ///
51    /// # Arguments
52    /// * `cursor` - A mutable reference to the current text cursor position.
53    /// * `anchor` - A mutable reference to the optional selection anchor.
54    ///
55    /// # Examples
56    /// ```
57    /// use text_editing::TextLine;
58    ///
59    /// let mut line = TextLine::from_string("Hello, world!".into());
60    /// let mut cursor = 12;
61    /// let mut anchor = Some(7);
62    /// assert!(line.delete_selection(&mut cursor, &mut anchor));
63    /// assert_eq!(line.as_str(), "Hello, !");
64    /// assert_eq!(cursor, 7);
65    /// assert_eq!(anchor, None);
66    /// ```
67    pub fn delete_selection(&mut self, cursor: &mut usize, anchor: &mut Option<usize>) -> bool {
68        if let Some(range) = Self::selection_range(*cursor, *anchor)
69            && !range.is_empty()
70        {
71            self.remove_range(range.clone());
72            *cursor = range.start;
73            *anchor = None;
74            return true;
75        }
76        *anchor = None;
77        false
78    }
79
80    /// Replaces the current selection with the given text.
81    ///
82    /// If no selection is active, inserts the text at the cursor position.
83    ///
84    /// # Arguments
85    /// * `cursor` - A mutable reference to the current text cursor position.
86    /// * `anchor` - A mutable reference to the optional selection anchor.
87    /// * `text` - The replacement text.
88    ///
89    /// # Examples
90    /// ```
91    /// use text_editing::TextLine;
92    ///
93    /// let mut line = TextLine::from_string("Hello, world!".into());
94    /// let mut cursor = 12;
95    /// let mut anchor = Some(7);
96    /// line.replace_selection(&mut cursor, &mut anchor, "Rust");
97    /// assert_eq!(line.as_str(), "Hello, Rust!");
98    /// assert_eq!(cursor, 11);
99    /// assert_eq!(anchor, None);
100    /// ```
101    pub fn replace_selection(
102        &mut self,
103        cursor: &mut usize,
104        anchor: &mut Option<usize>,
105        text: &str,
106    ) {
107        self.delete_selection(cursor, anchor);
108        self.insert_str(cursor, text);
109    }
110
111    /// Selects all text in the line.
112    ///
113    /// Sets the anchor to the beginning and the cursor to the end.
114    ///
115    /// # Arguments
116    /// * `cursor` - A mutable reference to the current text cursor position.
117    /// * `anchor` - A mutable reference to the optional selection anchor.
118    ///
119    /// # Examples
120    /// ```
121    /// use text_editing::TextLine;
122    ///
123    /// let line = TextLine::from_string("Hello, world!".into());
124    /// let mut cursor = 5;
125    /// let mut anchor = None;
126    /// line.select_all(&mut cursor, &mut anchor);
127    /// assert_eq!(cursor, 13);
128    /// assert_eq!(anchor, Some(0));
129    /// ```
130    pub fn select_all(&self, cursor: &mut usize, anchor: &mut Option<usize>) {
131        *anchor = Some(0);
132        *cursor = self.len();
133    }
134
135    /// Extends the selection forward by one character.
136    ///
137    /// Sets the anchor to the current cursor position if no selection is active,
138    /// then moves the cursor forward.
139    ///
140    /// # Examples
141    /// ```
142    /// use text_editing::TextLine;
143    ///
144    /// let line = TextLine::from_string("Hello, world!".into());
145    /// let mut cursor = 7;
146    /// let mut anchor = None;
147    /// assert!(line.select_forward(&mut cursor, &mut anchor));
148    /// assert_eq!(cursor, 8);
149    /// assert_eq!(anchor, Some(7));
150    /// ```
151    pub fn select_forward(&self, cursor: &mut usize, anchor: &mut Option<usize>) -> bool {
152        if anchor.is_none() {
153            *anchor = Some(*cursor);
154        }
155        self.forward(cursor)
156    }
157
158    /// Extends the selection backward by one character.
159    ///
160    /// Sets the anchor to the current cursor position if no selection is active,
161    /// then moves the cursor backward.
162    ///
163    /// # Examples
164    /// ```
165    /// use text_editing::TextLine;
166    ///
167    /// let line = TextLine::from_string("Hello, world!".into());
168    /// let mut cursor = 7;
169    /// let mut anchor = None;
170    /// assert!(line.select_backward(&mut cursor, &mut anchor));
171    /// assert_eq!(cursor, 6);
172    /// assert_eq!(anchor, Some(7));
173    /// ```
174    pub fn select_backward(&self, cursor: &mut usize, anchor: &mut Option<usize>) -> bool {
175        if anchor.is_none() {
176            *anchor = Some(*cursor);
177        }
178        self.backward(cursor)
179    }
180
181    /// Extends the selection forward by one word.
182    ///
183    /// Sets the anchor to the current cursor position if no selection is active,
184    /// then moves the cursor to the end of the next word.
185    ///
186    /// # Examples
187    /// ```
188    /// use text_editing::TextLine;
189    ///
190    /// let line = TextLine::from_string("Hello, world!".into());
191    /// let mut cursor = 7;
192    /// let mut anchor = None;
193    /// assert!(line.select_forward_skip(&mut cursor, &mut anchor));
194    /// assert_eq!(cursor, 12);
195    /// assert_eq!(anchor, Some(7));
196    /// ```
197    pub fn select_forward_skip(&self, cursor: &mut usize, anchor: &mut Option<usize>) -> bool {
198        if anchor.is_none() {
199            *anchor = Some(*cursor);
200        }
201        self.skip_forward(cursor)
202    }
203
204    /// Extends the selection backward by one word.
205    ///
206    /// Sets the anchor to the current cursor position if no selection is active,
207    /// then moves the cursor to the start of the previous word.
208    ///
209    /// # Examples
210    /// ```
211    /// use text_editing::TextLine;
212    ///
213    /// let line = TextLine::from_string("Hello, world!".into());
214    /// let mut cursor = 12;
215    /// let mut anchor = None;
216    /// assert!(line.select_backward_skip(&mut cursor, &mut anchor));
217    /// assert_eq!(cursor, 7);
218    /// assert_eq!(anchor, Some(12));
219    /// ```
220    pub fn select_backward_skip(&self, cursor: &mut usize, anchor: &mut Option<usize>) -> bool {
221        if anchor.is_none() {
222            *anchor = Some(*cursor);
223        }
224        self.skip_backward(cursor)
225    }
226
227    /// Clears the current selection without modifying the text.
228    ///
229    /// # Examples
230    /// ```
231    /// use text_editing::TextLine;
232    ///
233    /// let mut anchor = Some(5);
234    /// TextLine::clear_selection(&mut anchor);
235    /// assert_eq!(anchor, None);
236    /// ```
237    pub fn clear_selection(anchor: &mut Option<usize>) {
238        *anchor = None;
239    }
240}