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}