freya_edit/
rope_editor.rs1use std::{
2 fmt::Display,
3 ops::Range,
4};
5
6use ropey::{
7 Rope,
8 iter::Lines,
9};
10
11use crate::{
12 TextSelection,
13 editor_history::{
14 EditorHistory,
15 HistoryChange,
16 },
17 text_editor::{
18 Line,
19 TextEditor,
20 },
21};
22
23pub struct RopeEditor {
25 pub(crate) rope: Rope,
26 pub(crate) selection: TextSelection,
27 pub(crate) indentation: u8,
28 pub(crate) history: EditorHistory,
29}
30
31impl Display for RopeEditor {
32 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33 f.write_str(&self.rope.to_string())
34 }
35}
36
37impl RopeEditor {
38 pub fn new(
40 text: String,
41 selection: TextSelection,
42 indentation: u8,
43 history: EditorHistory,
44 ) -> Self {
45 Self {
46 rope: Rope::from_str(&text),
47 selection,
48 indentation,
49 history,
50 }
51 }
52
53 pub fn rope(&self) -> &Rope {
54 &self.rope
55 }
56}
57
58impl TextEditor for RopeEditor {
59 type LinesIterator<'a> = LinesIterator<'a>;
60
61 fn lines(&self) -> Self::LinesIterator<'_> {
62 let lines = self.rope.lines();
63 LinesIterator { lines }
64 }
65
66 fn insert_char(&mut self, ch: char, idx: usize) -> usize {
67 let idx_utf8 = self.utf16_cu_to_char(idx);
68 let selection = self.selection.clone();
69
70 let len_before_insert = self.rope.len_utf16_cu();
71 self.rope.insert_char(idx_utf8, ch);
72 let len_after_insert = self.rope.len_utf16_cu();
73
74 let inserted_text_len = len_after_insert - len_before_insert;
75
76 self.history.push_change(HistoryChange::InsertChar {
77 idx,
78 ch,
79 len: inserted_text_len,
80 selection,
81 });
82
83 inserted_text_len
84 }
85
86 fn insert(&mut self, text: &str, idx: usize) -> usize {
87 let idx_utf8 = self.utf16_cu_to_char(idx);
88 let selection = self.selection.clone();
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 selection,
101 });
102
103 inserted_text_len
104 }
105
106 fn remove(&mut self, range_utf16: Range<usize>) -> usize {
107 let range =
108 self.utf16_cu_to_char(range_utf16.start)..self.utf16_cu_to_char(range_utf16.end);
109 let text = self.rope.slice(range.clone()).to_string();
110 let selection = self.selection.clone();
111
112 let len_before_remove = self.rope.len_utf16_cu();
113 self.rope.remove(range);
114 let len_after_remove = self.rope.len_utf16_cu();
115
116 let removed_text_len = len_before_remove - len_after_remove;
117
118 self.history.push_change(HistoryChange::Remove {
119 idx: range_utf16.end - removed_text_len,
120 text,
121 len: removed_text_len,
122 selection,
123 });
124
125 removed_text_len
126 }
127
128 fn char_to_line(&self, char_idx: usize) -> usize {
129 self.rope.char_to_line(char_idx)
130 }
131
132 fn line_to_char(&self, line_idx: usize) -> usize {
133 self.rope.line_to_char(line_idx)
134 }
135
136 fn utf16_cu_to_char(&self, utf16_cu_idx: usize) -> usize {
137 self.rope.utf16_cu_to_char(utf16_cu_idx)
138 }
139
140 fn char_to_utf16_cu(&self, idx: usize) -> usize {
141 self.rope.char_to_utf16_cu(idx)
142 }
143
144 fn line(&self, line_idx: usize) -> Option<Line<'_>> {
145 let line = self.rope.get_line(line_idx);
146
147 line.map(|line| Line {
148 text: line.into(),
149 utf16_len: line.len_utf16_cu(),
150 })
151 }
152
153 fn len_lines(&self) -> usize {
154 self.rope.len_lines()
155 }
156
157 fn len_chars(&self) -> usize {
158 self.rope.len_chars()
159 }
160
161 fn len_utf16_cu(&self) -> usize {
162 self.rope.len_utf16_cu()
163 }
164
165 fn selection(&self) -> &TextSelection {
166 &self.selection
167 }
168
169 fn selection_mut(&mut self) -> &mut TextSelection {
170 &mut self.selection
171 }
172
173 fn has_any_selection(&self) -> bool {
174 self.selection.is_range()
175 }
176
177 fn get_selection(&self) -> Option<(usize, usize)> {
178 match self.selection {
179 TextSelection::Cursor(_) => None,
180 TextSelection::Range { from, to } => Some((from, to)),
181 }
182 }
183
184 fn set(&mut self, text: &str) {
185 self.rope.remove(0..);
186 self.rope.insert(0, text);
187 if self.cursor_pos() > text.len() {
188 self.move_cursor_to(text.len());
189 }
190 }
191
192 fn clear_selection(&mut self) {
193 let end = self.selection().end();
194 self.selection_mut().set_as_cursor();
195 self.selection_mut().move_to(end);
196 }
197
198 fn set_selection(&mut self, (from, to): (usize, usize)) {
199 self.selection = TextSelection::Range { from, to };
200 }
201
202 fn get_selected_text(&self) -> Option<String> {
203 let (start, end) = self.get_selection_range()?;
204
205 let start = self.utf16_cu_to_char(start);
206 let end = self.utf16_cu_to_char(end);
207
208 Some(self.rope().get_slice(start..end)?.to_string())
209 }
210
211 fn get_selection_range(&self) -> Option<(usize, usize)> {
212 let (start, end) = match self.selection {
213 TextSelection::Cursor(_) => return None,
214 TextSelection::Range { from, to } => (from, to),
215 };
216
217 let (start, end) = if start < end {
219 (start, end)
220 } else {
221 (end, start)
222 };
223
224 Some((start, end))
225 }
226
227 fn undo(&mut self) -> Option<TextSelection> {
228 self.history.undo(&mut self.rope)
229 }
230
231 fn redo(&mut self) -> Option<TextSelection> {
232 self.history.redo(&mut self.rope)
233 }
234
235 fn editor_history(&mut self) -> &mut EditorHistory {
236 &mut self.history
237 }
238
239 fn get_indentation(&self) -> u8 {
240 self.indentation
241 }
242}
243
244pub struct LinesIterator<'a> {
246 pub lines: Lines<'a>,
247}
248
249impl<'a> Iterator for LinesIterator<'a> {
250 type Item = Line<'a>;
251
252 fn next(&mut self) -> Option<Self::Item> {
253 let line = self.lines.next();
254
255 line.map(|line| Line {
256 text: line.into(),
257 utf16_len: line.len_utf16_cu(),
258 })
259 }
260}