1use std::{
2 cmp::Ordering,
3 fmt::Display,
4 ops::Range,
5};
6
7use ropey::{
8 Rope,
9 iter::Lines,
10};
11use unicode_segmentation::UnicodeSegmentation;
12
13use crate::{
14 EditorLine,
15 TextSelection,
16 editor_history::{
17 EditorHistory,
18 HistoryChange,
19 },
20 text_editor::{
21 Line,
22 TextEditor,
23 },
24};
25
26pub struct RopeEditor {
28 pub(crate) rope: Rope,
29 pub(crate) selection: TextSelection,
30 pub(crate) identation: u8,
31 pub(crate) history: EditorHistory,
32}
33
34impl Display for RopeEditor {
35 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36 f.write_str(&self.rope.to_string())
37 }
38}
39
40impl RopeEditor {
41 pub fn new(
43 text: String,
44 selection: TextSelection,
45 identation: u8,
46 history: EditorHistory,
47 ) -> Self {
48 Self {
49 rope: Rope::from_str(&text),
50 selection,
51 identation,
52 history,
53 }
54 }
55
56 pub fn rope(&self) -> &Rope {
57 &self.rope
58 }
59}
60
61impl TextEditor for RopeEditor {
62 type LinesIterator<'a> = LinesIterator<'a>;
63
64 fn lines(&self) -> Self::LinesIterator<'_> {
65 let lines = self.rope.lines();
66 LinesIterator { lines }
67 }
68
69 fn insert_char(&mut self, ch: char, idx: usize) -> usize {
70 let idx_utf8 = self.utf16_cu_to_char(idx);
71
72 let len_before_insert = self.rope.len_utf16_cu();
73 self.rope.insert_char(idx_utf8, ch);
74 let len_after_insert = self.rope.len_utf16_cu();
75
76 let inserted_text_len = len_after_insert - len_before_insert;
77
78 self.history.push_change(HistoryChange::InsertChar {
79 idx,
80 ch,
81 len: inserted_text_len,
82 });
83
84 inserted_text_len
85 }
86
87 fn insert(&mut self, text: &str, idx: usize) -> usize {
88 let idx_utf8 = self.utf16_cu_to_char(idx);
89
90 let len_before_insert = self.rope.len_utf16_cu();
91 self.rope.insert(idx_utf8, text);
92 let len_after_insert = self.rope.len_utf16_cu();
93
94 let inserted_text_len = len_after_insert - len_before_insert;
95
96 self.history.push_change(HistoryChange::InsertText {
97 idx,
98 text: text.to_owned(),
99 len: inserted_text_len,
100 });
101
102 inserted_text_len
103 }
104
105 fn remove(&mut self, range_utf16: Range<usize>) -> usize {
106 let range =
107 self.utf16_cu_to_char(range_utf16.start)..self.utf16_cu_to_char(range_utf16.end);
108 let text = self.rope.slice(range.clone()).to_string();
109
110 let len_before_remove = self.rope.len_utf16_cu();
111 self.rope.remove(range);
112 let len_after_remove = self.rope.len_utf16_cu();
113
114 let removed_text_len = len_before_remove - len_after_remove;
115
116 self.history.push_change(HistoryChange::Remove {
117 idx: range_utf16.end - removed_text_len,
118 text,
119 len: removed_text_len,
120 });
121
122 removed_text_len
123 }
124
125 fn char_to_line(&self, char_idx: usize) -> usize {
126 self.rope.char_to_line(char_idx)
127 }
128
129 fn line_to_char(&self, line_idx: usize) -> usize {
130 self.rope.line_to_char(line_idx)
131 }
132
133 fn utf16_cu_to_char(&self, utf16_cu_idx: usize) -> usize {
134 self.rope.utf16_cu_to_char(utf16_cu_idx)
135 }
136
137 fn char_to_utf16_cu(&self, idx: usize) -> usize {
138 self.rope.char_to_utf16_cu(idx)
139 }
140
141 fn line(&self, line_idx: usize) -> Option<Line<'_>> {
142 let line = self.rope.get_line(line_idx);
143
144 line.map(|line| Line {
145 text: line.into(),
146 utf16_len: line.len_utf16_cu(),
147 })
148 }
149
150 fn len_lines(&self) -> usize {
151 self.rope.len_lines()
152 }
153
154 fn len_chars(&self) -> usize {
155 self.rope.len_chars()
156 }
157
158 fn len_utf16_cu(&self) -> usize {
159 self.rope.len_utf16_cu()
160 }
161
162 fn selection(&self) -> &TextSelection {
163 &self.selection
164 }
165
166 fn selection_mut(&mut self) -> &mut TextSelection {
167 &mut self.selection
168 }
169
170 fn has_any_selection(&self) -> bool {
171 self.selection.is_range()
172 }
173
174 fn get_selection(&self) -> Option<(usize, usize)> {
175 match self.selection {
176 TextSelection::Cursor(_) => None,
177 TextSelection::Range { from, to } => Some((from, to)),
178 }
179 }
180
181 fn get_visible_selection(&self, editor_line: EditorLine) -> Option<(usize, usize)> {
182 let (selected_from, selected_to) = match self.selection {
183 TextSelection::Cursor(_) => return None,
184 TextSelection::Range { from, to } => (from, to),
185 };
186
187 match editor_line {
188 EditorLine::Paragraph(line_index) => {
189 let selected_from_row = self.char_to_line(self.utf16_cu_to_char(selected_from));
190 let selected_to_row = self.char_to_line(self.utf16_cu_to_char(selected_to));
191
192 let editor_row_idx = self.char_to_utf16_cu(self.line_to_char(line_index));
193 let selected_from_row_idx =
194 self.char_to_utf16_cu(self.line_to_char(selected_from_row));
195 let selected_to_row_idx = self.char_to_utf16_cu(self.line_to_char(selected_to_row));
196
197 let selected_from_col_idx = selected_from - selected_from_row_idx;
198 let selected_to_col_idx = selected_to - selected_to_row_idx;
199
200 if (line_index > selected_from_row && line_index < selected_to_row)
202 || (line_index < selected_from_row && line_index > selected_to_row)
203 {
204 let len = self.line(line_index).unwrap().utf16_len();
205 return Some((0, len));
206 }
207
208 match selected_from_row.cmp(&selected_to_row) {
209 Ordering::Greater => {
211 if selected_from_row == line_index {
212 Some((0, selected_from_col_idx))
214 } else if selected_to_row == line_index {
215 let len = self.line(selected_to_row).unwrap().utf16_len();
217 Some((selected_to_col_idx, len))
218 } else {
219 None
220 }
221 }
222 Ordering::Less => {
224 if selected_from_row == line_index {
225 let len = self.line(selected_from_row).unwrap().utf16_len();
227 Some((selected_from_col_idx, len))
228 } else if selected_to_row == line_index {
229 Some((0, selected_to_col_idx))
231 } else {
232 None
233 }
234 }
235 Ordering::Equal if selected_from_row == line_index => {
236 Some((selected_from - editor_row_idx, selected_to - editor_row_idx))
238 }
239 _ => None,
240 }
241 }
242 EditorLine::SingleParagraph => Some((selected_from, selected_to)),
243 }
244 }
245
246 fn set(&mut self, text: &str) {
247 self.rope.remove(0..);
248 self.rope.insert(0, text);
249 if self.cursor_pos() > text.len() {
250 self.move_cursor_to(text.len());
251 }
252 }
253
254 fn clear_selection(&mut self) {
255 let end = self.selection().end();
256 self.selection_mut().set_as_cursor();
257 self.selection_mut().move_to(end);
258 }
259
260 fn measure_selection(&self, to: usize, line_index: EditorLine) -> TextSelection {
261 let mut selection = self.selection().clone();
262
263 match line_index {
264 EditorLine::Paragraph(line_index) => {
265 let row_char = self.line_to_char(line_index);
266 let pos = self.char_to_utf16_cu(row_char) + to;
267 selection.move_to(pos);
268 }
269 EditorLine::SingleParagraph => {
270 selection.move_to(to);
271 }
272 }
273
274 selection
275 }
276
277 fn set_selection(&mut self, (from, to): (usize, usize)) {
278 self.selection = TextSelection::Range { from, to };
279 }
280
281 fn get_selected_text(&self) -> Option<String> {
282 let (start, end) = self.get_selection_range()?;
283
284 let start = self.utf16_cu_to_char(start);
285 let end = self.utf16_cu_to_char(end);
286
287 Some(self.rope().get_slice(start..end)?.to_string())
288 }
289
290 fn get_selection_range(&self) -> Option<(usize, usize)> {
291 let (start, end) = match self.selection {
292 TextSelection::Cursor(_) => return None,
293 TextSelection::Range { from, to } => (from, to),
294 };
295
296 let (start, end) = if start < end {
298 (start, end)
299 } else {
300 (end, start)
301 };
302
303 Some((start, end))
304 }
305
306 fn undo(&mut self) -> Option<usize> {
307 self.history.undo(&mut self.rope)
308 }
309
310 fn redo(&mut self) -> Option<usize> {
311 self.history.redo(&mut self.rope)
312 }
313
314 fn editor_history(&mut self) -> &mut EditorHistory {
315 &mut self.history
316 }
317
318 fn get_identation(&self) -> u8 {
319 self.identation
320 }
321
322 fn find_word_boundaries(&self, pos: usize) -> (usize, usize) {
323 let pos_char = self.utf16_cu_to_char(pos);
324 let len_chars = self.rope.len_chars();
325
326 if len_chars == 0 {
327 return (pos, pos);
328 }
329
330 let line_idx = self.rope.char_to_line(pos_char);
332 let line_char = self.rope.line_to_char(line_idx);
333 let line = self.rope.line(line_idx);
334
335 let line_str: std::borrow::Cow<str> = line.into();
336 let pos_in_line = pos_char - line_char;
337
338 let mut char_offset = 0;
340 for word in line_str.split_word_bounds() {
341 let word_char_len = word.chars().count();
342 let word_start = char_offset;
343 let word_end = char_offset + word_char_len;
344
345 if pos_in_line >= word_start && pos_in_line < word_end {
346 let start_char = line_char + word_start;
347 let end_char = line_char + word_end;
348 return (
349 self.char_to_utf16_cu(start_char),
350 self.char_to_utf16_cu(end_char),
351 );
352 }
353
354 char_offset = word_end;
355 }
356
357 (pos, pos)
358 }
359}
360
361pub struct LinesIterator<'a> {
363 pub lines: Lines<'a>,
364}
365
366impl<'a> Iterator for LinesIterator<'a> {
367 type Item = Line<'a>;
368
369 fn next(&mut self) -> Option<Self::Item> {
370 let line = self.lines.next();
371
372 line.map(|line| Line {
373 text: line.into(),
374 utf16_len: line.len_utf16_cu(),
375 })
376 }
377}