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 EditorLine,
14 TextSelection,
15 editor_history::{
16 EditorHistory,
17 HistoryChange,
18 },
19 text_editor::{
20 Line,
21 TextEditor,
22 },
23};
24
25pub struct RopeEditor {
27 pub(crate) rope: Rope,
28 pub(crate) selection: TextSelection,
29 pub(crate) indentation: u8,
30 pub(crate) history: EditorHistory,
31}
32
33impl Display for RopeEditor {
34 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35 f.write_str(&self.rope.to_string())
36 }
37}
38
39impl RopeEditor {
40 pub fn new(
42 text: String,
43 selection: TextSelection,
44 indentation: u8,
45 history: EditorHistory,
46 ) -> Self {
47 Self {
48 rope: Rope::from_str(&text),
49 selection,
50 indentation,
51 history,
52 }
53 }
54
55 pub fn rope(&self) -> &Rope {
56 &self.rope
57 }
58}
59
60impl TextEditor for RopeEditor {
61 type LinesIterator<'a> = LinesIterator<'a>;
62
63 fn lines(&self) -> Self::LinesIterator<'_> {
64 let lines = self.rope.lines();
65 LinesIterator { lines }
66 }
67
68 fn insert_char(&mut self, ch: char, idx: usize) -> usize {
69 let idx_utf8 = self.utf16_cu_to_char(idx);
70 let selection = self.selection.clone();
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 selection,
83 });
84
85 inserted_text_len
86 }
87
88 fn insert(&mut self, text: &str, idx: usize) -> usize {
89 let idx_utf8 = self.utf16_cu_to_char(idx);
90 let selection = self.selection.clone();
91
92 let len_before_insert = self.rope.len_utf16_cu();
93 self.rope.insert(idx_utf8, text);
94 let len_after_insert = self.rope.len_utf16_cu();
95
96 let inserted_text_len = len_after_insert - len_before_insert;
97
98 self.history.push_change(HistoryChange::InsertText {
99 idx,
100 text: text.to_owned(),
101 len: inserted_text_len,
102 selection,
103 });
104
105 inserted_text_len
106 }
107
108 fn remove(&mut self, range_utf16: Range<usize>) -> usize {
109 let range =
110 self.utf16_cu_to_char(range_utf16.start)..self.utf16_cu_to_char(range_utf16.end);
111 let text = self.rope.slice(range.clone()).to_string();
112 let selection = self.selection.clone();
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 selection,
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 selection(&self) -> &TextSelection {
168 &self.selection
169 }
170
171 fn selection_mut(&mut self) -> &mut TextSelection {
172 &mut self.selection
173 }
174
175 fn has_any_selection(&self) -> bool {
176 self.selection.is_range()
177 }
178
179 fn get_selection(&self) -> Option<(usize, usize)> {
180 match self.selection {
181 TextSelection::Cursor(_) => None,
182 TextSelection::Range { from, to } => Some((from, to)),
183 }
184 }
185
186 fn get_visible_selection(&self, editor_line: EditorLine) -> Option<(usize, usize)> {
187 let (selected_from, selected_to) = match self.selection {
188 TextSelection::Cursor(_) => return None,
189 TextSelection::Range { from, to } => (from, to),
190 };
191
192 match editor_line {
193 EditorLine::Paragraph(line_index) => {
194 let selected_from_row = self.char_to_line(self.utf16_cu_to_char(selected_from));
195 let selected_to_row = self.char_to_line(self.utf16_cu_to_char(selected_to));
196
197 let editor_row_idx = self.char_to_utf16_cu(self.line_to_char(line_index));
198 let selected_from_row_idx =
199 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 (line_index > selected_from_row && line_index < selected_to_row)
207 || (line_index < selected_from_row && line_index > selected_to_row)
208 {
209 let len = self.line(line_index).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 == line_index {
217 Some((0, selected_from_col_idx))
219 } else if selected_to_row == line_index {
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 == line_index {
230 let len = self.line(selected_from_row).unwrap().utf16_len();
232 Some((selected_from_col_idx, len))
233 } else if selected_to_row == line_index {
234 Some((0, selected_to_col_idx))
236 } else {
237 None
238 }
239 }
240 Ordering::Equal if selected_from_row == line_index => {
241 Some((selected_from - editor_row_idx, selected_to - editor_row_idx))
243 }
244 _ => None,
245 }
246 }
247 EditorLine::SingleParagraph => 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.move_cursor_to(text.len());
256 }
257 }
258
259 fn clear_selection(&mut self) {
260 let end = self.selection().end();
261 self.selection_mut().set_as_cursor();
262 self.selection_mut().move_to(end);
263 }
264
265 fn set_selection(&mut self, (from, to): (usize, usize)) {
266 self.selection = TextSelection::Range { from, to };
267 }
268
269 fn get_selected_text(&self) -> Option<String> {
270 let (start, end) = self.get_selection_range()?;
271
272 let start = self.utf16_cu_to_char(start);
273 let end = self.utf16_cu_to_char(end);
274
275 Some(self.rope().get_slice(start..end)?.to_string())
276 }
277
278 fn get_selection_range(&self) -> Option<(usize, usize)> {
279 let (start, end) = match self.selection {
280 TextSelection::Cursor(_) => return None,
281 TextSelection::Range { from, to } => (from, to),
282 };
283
284 let (start, end) = if start < end {
286 (start, end)
287 } else {
288 (end, start)
289 };
290
291 Some((start, end))
292 }
293
294 fn undo(&mut self) -> Option<TextSelection> {
295 self.history.undo(&mut self.rope)
296 }
297
298 fn redo(&mut self) -> Option<TextSelection> {
299 self.history.redo(&mut self.rope)
300 }
301
302 fn editor_history(&mut self) -> &mut EditorHistory {
303 &mut self.history
304 }
305
306 fn get_indentation(&self) -> u8 {
307 self.indentation
308 }
309}
310
311pub struct LinesIterator<'a> {
313 pub lines: Lines<'a>,
314}
315
316impl<'a> Iterator for LinesIterator<'a> {
317 type Item = Line<'a>;
318
319 fn next(&mut self) -> Option<Self::Item> {
320 let line = self.lines.next();
321
322 line.map(|line| Line {
323 text: line.into(),
324 utf16_len: line.len_utf16_cu(),
325 })
326 }
327}