1use std::{
2 borrow::Cow,
3 fmt::Display,
4 ops::{
5 Mul,
6 Range,
7 },
8 time::Duration,
9};
10
11use freya_core::{
12 elements::paragraph::ParagraphHolderInner,
13 prelude::*,
14};
15use freya_edit::*;
16use ropey::Rope;
17use tree_sitter::InputEdit;
18
19use crate::{
20 editor_theme::SyntaxTheme,
21 languages::LanguageId,
22 metrics::EditorMetrics,
23 syntax::InputEditExt,
24};
25
26pub struct CodeEditorData {
27 pub(crate) history: EditorHistory,
28 pub rope: Rope,
29 pub(crate) selection: TextSelection,
30 pub(crate) last_saved_history_change: usize,
31 pub(crate) metrics: EditorMetrics,
32 pub(crate) dragging: TextDragging,
33 pub(crate) scrolls: (i32, i32),
34 pub(crate) pending_edit: Option<InputEdit>,
35 pub language_id: LanguageId,
36 theme: SyntaxTheme,
37}
38
39impl CodeEditorData {
40 pub fn new(rope: Rope, language_id: LanguageId) -> Self {
41 Self {
42 rope,
43 selection: TextSelection::new_cursor(0),
44 history: EditorHistory::new(Duration::from_secs(1)),
45 last_saved_history_change: 0,
46 metrics: EditorMetrics::new(),
47 dragging: TextDragging::default(),
48 scrolls: (0, 0),
49 pending_edit: None,
50 language_id,
51 theme: SyntaxTheme::default(),
52 }
53 }
54
55 pub fn is_edited(&self) -> bool {
56 self.history.current_change() != self.last_saved_history_change
57 }
58
59 pub fn mark_as_saved(&mut self) {
60 self.last_saved_history_change = self.history.current_change();
61 }
62
63 pub fn parse(&mut self) {
64 let edit = self.pending_edit.take();
65 self.metrics
66 .run_parser(&self.rope, self.language_id, edit, &self.theme);
67 }
68
69 pub fn measure(&mut self, font_size: f32, font_family: &str) {
70 self.metrics
71 .measure_longest_line(font_size, font_family, &self.rope);
72 }
73
74 pub fn set_theme(&mut self, theme: SyntaxTheme) {
75 self.theme = theme;
76 }
77
78 pub fn process(
79 &mut self,
80 font_size: f32,
81 font_family: &str,
82 edit_event: EditableEvent,
83 ) -> bool {
84 let mut processed = false;
85 match edit_event {
86 EditableEvent::Down {
87 location,
88 editor_line,
89 holder,
90 } => {
91 let holder = holder.0.borrow();
92 let ParagraphHolderInner {
93 paragraph,
94 scale_factor,
95 } = holder.as_ref().unwrap();
96
97 let current_selection = self.selection().clone();
98
99 if self.dragging.shift || self.dragging.clicked {
100 self.selection_mut().set_as_range();
101 } else {
102 self.clear_selection();
103 }
104
105 if ¤t_selection != self.selection() {
106 processed = true;
107 }
108
109 self.dragging.clicked = true;
110
111 let char_position = paragraph.get_glyph_position_at_coordinate(
112 location.mul(*scale_factor).to_i32().to_tuple(),
113 );
114 let press_selection =
115 self.measure_selection(char_position.position as usize, editor_line);
116
117 let new_selection = match EventsCombos::pressed(location) {
118 PressEventType::Quadruple => {
119 TextSelection::new_range((0, self.rope.len_utf16_cu()))
120 }
121 PressEventType::Triple => {
122 let line = self.char_to_line(press_selection.pos());
123 let line_char = self.line_to_char(line);
124 let line_len = self.line(line).unwrap().utf16_len();
125 TextSelection::new_range((line_char, line_char + line_len))
126 }
127 PressEventType::Double => {
128 let range = self.find_word_boundaries(press_selection.pos());
129 TextSelection::new_range(range)
130 }
131 PressEventType::Single => press_selection,
132 };
133
134 if *self.selection() != new_selection {
135 *self.selection_mut() = new_selection;
136 processed = true;
137 }
138 }
139 EditableEvent::Move {
140 location,
141 editor_line,
142 holder,
143 } => {
144 if self.dragging.clicked {
145 let paragraph = holder.0.borrow();
146 let ParagraphHolderInner {
147 paragraph,
148 scale_factor,
149 } = paragraph.as_ref().unwrap();
150
151 let dist_position = location.mul(*scale_factor);
152
153 let dist_char = paragraph
155 .get_glyph_position_at_coordinate(dist_position.to_i32().to_tuple());
156 let to = dist_char.position as usize;
157
158 if self.get_selection().is_none() {
159 self.selection_mut().set_as_range();
160 processed = true;
161 }
162
163 let current_selection = self.selection().clone();
164
165 let new_selection = self.measure_selection(to, editor_line);
166
167 if current_selection != new_selection {
169 *self.selection_mut() = new_selection;
170 processed = true;
171 }
172 }
173 }
174 EditableEvent::Release => {
175 self.dragging.clicked = false;
176 }
177 EditableEvent::KeyDown { key, modifiers } => {
178 match key {
179 Key::Named(NamedKey::Shift) => {
181 self.dragging.shift = true;
182 }
183 _ => {
185 let event = self.process_key(key, &modifiers, true, true, true);
186 if event.contains(TextEvent::TEXT_CHANGED) {
187 self.parse();
188 self.measure(font_size, font_family);
189 self.dragging = TextDragging::default();
190 }
191 if !event.is_empty() {
192 processed = true;
193 }
194 }
195 }
196 }
197 EditableEvent::KeyUp { key, .. } => {
198 if *key == Key::Named(NamedKey::Shift) {
199 self.dragging.shift = false;
200 }
201 }
202 };
203 processed
204 }
205}
206
207impl Display for CodeEditorData {
208 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
209 f.write_str(&self.rope.to_string())
210 }
211}
212
213impl TextEditor for CodeEditorData {
214 type LinesIterator<'a>
215 = LinesIterator<'a>
216 where
217 Self: 'a;
218
219 fn lines(&self) -> Self::LinesIterator<'_> {
220 unimplemented!("Unused.")
221 }
222
223 fn insert_char(&mut self, ch: char, idx: usize) -> usize {
224 let idx_utf8 = self.utf16_cu_to_char(idx);
225 let selection = self.selection.clone();
226
227 let start_byte = self.rope.char_to_byte(idx_utf8);
229 let start_line = self.rope.char_to_line(idx_utf8);
230 let start_line_byte = self.rope.line_to_byte(start_line);
231 let start_col = start_byte - start_line_byte;
232
233 let len_before_insert = self.rope.len_utf16_cu();
234 self.rope.insert_char(idx_utf8, ch);
235 let len_after_insert = self.rope.len_utf16_cu();
236
237 let inserted_text_len = len_after_insert - len_before_insert;
238
239 let new_end_char = idx_utf8 + 1; let new_end_byte = self.rope.char_to_byte(new_end_char);
242 let new_end_line = self.rope.char_to_line(new_end_char);
243 let new_end_line_byte = self.rope.line_to_byte(new_end_line);
244 let new_end_col = new_end_byte - new_end_line_byte;
245
246 self.pending_edit = Some(InputEdit::new_edit(
247 start_byte,
248 start_byte,
249 new_end_byte,
250 (start_line, start_col),
251 (start_line, start_col),
252 (new_end_line, new_end_col),
253 ));
254
255 self.history.push_change(HistoryChange::InsertChar {
256 idx,
257 ch,
258 len: inserted_text_len,
259 selection,
260 });
261
262 inserted_text_len
263 }
264
265 fn insert(&mut self, text: &str, idx: usize) -> usize {
266 let idx_utf8 = self.utf16_cu_to_char(idx);
267 let selection = self.selection.clone();
268
269 let start_byte = self.rope.char_to_byte(idx_utf8);
271 let start_line = self.rope.char_to_line(idx_utf8);
272 let start_line_byte = self.rope.line_to_byte(start_line);
273 let start_col = start_byte - start_line_byte;
274
275 let len_before_insert = self.rope.len_utf16_cu();
276 self.rope.insert(idx_utf8, text);
277 let len_after_insert = self.rope.len_utf16_cu();
278
279 let inserted_text_len = len_after_insert - len_before_insert;
280
281 let inserted_chars = text.chars().count();
283 let new_end_char = idx_utf8 + inserted_chars;
284 let new_end_byte = self.rope.char_to_byte(new_end_char);
285 let new_end_line = self.rope.char_to_line(new_end_char);
286 let new_end_line_byte = self.rope.line_to_byte(new_end_line);
287 let new_end_col = new_end_byte - new_end_line_byte;
288
289 self.pending_edit = Some(InputEdit::new_edit(
290 start_byte,
291 start_byte,
292 new_end_byte,
293 (start_line, start_col),
294 (start_line, start_col),
295 (new_end_line, new_end_col),
296 ));
297
298 self.history.push_change(HistoryChange::InsertText {
299 idx,
300 text: text.to_owned(),
301 len: inserted_text_len,
302 selection,
303 });
304
305 inserted_text_len
306 }
307
308 fn remove(&mut self, range_utf16: Range<usize>) -> usize {
309 let range =
310 self.utf16_cu_to_char(range_utf16.start)..self.utf16_cu_to_char(range_utf16.end);
311 let text = self.rope.slice(range.clone()).to_string();
312 let selection = self.selection.clone();
313
314 let start_byte = self.rope.char_to_byte(range.start);
316 let old_end_byte = self.rope.char_to_byte(range.end);
317 let start_line = self.rope.char_to_line(range.start);
318 let start_line_byte = self.rope.line_to_byte(start_line);
319 let start_col = start_byte - start_line_byte;
320 let old_end_line = self.rope.char_to_line(range.end);
321 let old_end_line_byte = self.rope.line_to_byte(old_end_line);
322 let old_end_col = old_end_byte - old_end_line_byte;
323
324 let len_before_remove = self.rope.len_utf16_cu();
325 self.rope.remove(range);
326 let len_after_remove = self.rope.len_utf16_cu();
327
328 let removed_text_len = len_before_remove - len_after_remove;
329
330 self.pending_edit = Some(InputEdit::new_edit(
332 start_byte,
333 old_end_byte,
334 start_byte,
335 (start_line, start_col),
336 (old_end_line, old_end_col),
337 (start_line, start_col),
338 ));
339
340 self.history.push_change(HistoryChange::Remove {
341 idx: range_utf16.end - removed_text_len,
342 text,
343 len: removed_text_len,
344 selection,
345 });
346
347 removed_text_len
348 }
349
350 fn char_to_line(&self, char_idx: usize) -> usize {
351 self.rope.char_to_line(char_idx)
352 }
353
354 fn line_to_char(&self, line_idx: usize) -> usize {
355 self.rope.line_to_char(line_idx)
356 }
357
358 fn utf16_cu_to_char(&self, utf16_cu_idx: usize) -> usize {
359 self.rope.utf16_cu_to_char(utf16_cu_idx)
360 }
361
362 fn char_to_utf16_cu(&self, idx: usize) -> usize {
363 self.rope.char_to_utf16_cu(idx)
364 }
365
366 fn line(&self, line_idx: usize) -> Option<Line<'_>> {
367 let line = self.rope.get_line(line_idx);
368
369 line.map(|line| Line {
370 text: Cow::Owned(line.to_string()),
371 utf16_len: line.len_utf16_cu(),
372 })
373 }
374
375 fn len_lines(&self) -> usize {
376 self.rope.len_lines()
377 }
378
379 fn len_chars(&self) -> usize {
380 self.rope.len_chars()
381 }
382
383 fn len_utf16_cu(&self) -> usize {
384 self.rope.len_utf16_cu()
385 }
386
387 fn has_any_selection(&self) -> bool {
388 self.selection.is_range()
389 }
390
391 fn get_selection(&self) -> Option<(usize, usize)> {
392 match self.selection {
393 TextSelection::Cursor(_) => None,
394 TextSelection::Range { from, to } => Some((from, to)),
395 }
396 }
397
398 fn set(&mut self, text: &str) {
399 self.rope.remove(0..);
400 self.rope.insert(0, text);
401 }
402
403 fn clear_selection(&mut self) {
404 let end = self.selection().end();
405 self.selection_mut().set_as_cursor();
406 self.selection_mut().move_to(end);
407 }
408
409 fn set_selection(&mut self, (from, to): (usize, usize)) {
410 self.selection = TextSelection::Range { from, to };
411 }
412
413 fn get_selected_text(&self) -> Option<String> {
414 let (start, end) = self.get_selection_range()?;
415
416 Some(self.rope.get_slice(start..end)?.to_string())
417 }
418
419 fn get_selection_range(&self) -> Option<(usize, usize)> {
420 let (start, end) = match self.selection {
421 TextSelection::Cursor(_) => return None,
422 TextSelection::Range { from, to } => (from, to),
423 };
424
425 let (start, end) = if start < end {
427 (start, end)
428 } else {
429 (end, start)
430 };
431
432 Some((start, end))
433 }
434
435 fn undo(&mut self) -> Option<TextSelection> {
436 self.pending_edit = None;
438 self.metrics.highlighter.invalidate_tree();
439 self.history.undo(&mut self.rope)
440 }
441
442 fn redo(&mut self) -> Option<TextSelection> {
443 self.pending_edit = None;
445 self.metrics.highlighter.invalidate_tree();
446 self.history.redo(&mut self.rope)
447 }
448
449 fn editor_history(&mut self) -> &mut EditorHistory {
450 &mut self.history
451 }
452
453 fn selection(&self) -> &TextSelection {
454 &self.selection
455 }
456
457 fn selection_mut(&mut self) -> &mut TextSelection {
458 &mut self.selection
459 }
460
461 fn get_indentation(&self) -> u8 {
462 4
463 }
464}