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