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