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::Triple => {
119 let line = self.char_to_line(press_selection.pos());
120 let line_char = self.line_to_char(line);
121 let line_len = self.line(line).unwrap().utf16_len();
122 TextSelection::new_range((line_char, line_char + line_len))
123 }
124 PressEventType::Double => {
125 let range = self.find_word_boundaries(press_selection.pos());
126 TextSelection::new_range(range)
127 }
128 PressEventType::Single => press_selection,
129 };
130
131 if *self.selection() != new_selection {
132 *self.selection_mut() = new_selection;
133 processed = true;
134 }
135 }
136 EditableEvent::Move {
137 location,
138 editor_line,
139 holder,
140 } => {
141 if self.dragging.clicked {
142 let paragraph = holder.0.borrow();
143 let ParagraphHolderInner {
144 paragraph,
145 scale_factor,
146 } = paragraph.as_ref().unwrap();
147
148 let dist_position = location.mul(*scale_factor);
149
150 let dist_char = paragraph
152 .get_glyph_position_at_coordinate(dist_position.to_i32().to_tuple());
153 let to = dist_char.position as usize;
154
155 if self.get_selection().is_none() {
156 self.selection_mut().set_as_range();
157 processed = true;
158 }
159
160 let current_selection = self.selection().clone();
161
162 let new_selection = self.measure_selection(to, editor_line);
163
164 if current_selection != new_selection {
166 *self.selection_mut() = new_selection;
167 processed = true;
168 }
169 }
170 }
171 EditableEvent::Release => {
172 self.dragging.clicked = false;
173 }
174 EditableEvent::KeyDown { key, modifiers } => {
175 match key {
176 Key::Named(NamedKey::Shift) => {
178 self.dragging.shift = true;
179 }
180 _ => {
182 let event = self.process_key(key, &modifiers, true, true, true);
183 if event.contains(TextEvent::TEXT_CHANGED) {
184 self.parse();
185 self.measure(font_size, font_family);
186 self.dragging = TextDragging::default();
187 }
188 if !event.is_empty() {
189 processed = true;
190 }
191 }
192 }
193 }
194 EditableEvent::KeyUp { key, .. } => {
195 if *key == Key::Named(NamedKey::Shift) {
196 self.dragging.shift = false;
197 }
198 }
199 };
200 processed
201 }
202}
203
204impl Display for CodeEditorData {
205 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
206 f.write_str(&self.rope.to_string())
207 }
208}
209
210impl TextEditor for CodeEditorData {
211 type LinesIterator<'a>
212 = LinesIterator<'a>
213 where
214 Self: 'a;
215
216 fn lines(&self) -> Self::LinesIterator<'_> {
217 unimplemented!("Unused.")
218 }
219
220 fn insert_char(&mut self, ch: char, idx: usize) -> usize {
221 let idx_utf8 = self.utf16_cu_to_char(idx);
222 let selection = self.selection.clone();
223
224 let start_byte = self.rope.char_to_byte(idx_utf8);
226 let start_line = self.rope.char_to_line(idx_utf8);
227 let start_line_byte = self.rope.line_to_byte(start_line);
228 let start_col = start_byte - start_line_byte;
229
230 let len_before_insert = self.rope.len_utf16_cu();
231 self.rope.insert_char(idx_utf8, ch);
232 let len_after_insert = self.rope.len_utf16_cu();
233
234 let inserted_text_len = len_after_insert - len_before_insert;
235
236 let new_end_char = idx_utf8 + 1; let new_end_byte = self.rope.char_to_byte(new_end_char);
239 let new_end_line = self.rope.char_to_line(new_end_char);
240 let new_end_line_byte = self.rope.line_to_byte(new_end_line);
241 let new_end_col = new_end_byte - new_end_line_byte;
242
243 self.pending_edit = Some(InputEdit::new_edit(
244 start_byte,
245 start_byte,
246 new_end_byte,
247 (start_line, start_col),
248 (start_line, start_col),
249 (new_end_line, new_end_col),
250 ));
251
252 self.history.push_change(HistoryChange::InsertChar {
253 idx,
254 ch,
255 len: inserted_text_len,
256 selection,
257 });
258
259 inserted_text_len
260 }
261
262 fn insert(&mut self, text: &str, idx: usize) -> usize {
263 let idx_utf8 = self.utf16_cu_to_char(idx);
264 let selection = self.selection.clone();
265
266 let start_byte = self.rope.char_to_byte(idx_utf8);
268 let start_line = self.rope.char_to_line(idx_utf8);
269 let start_line_byte = self.rope.line_to_byte(start_line);
270 let start_col = start_byte - start_line_byte;
271
272 let len_before_insert = self.rope.len_utf16_cu();
273 self.rope.insert(idx_utf8, text);
274 let len_after_insert = self.rope.len_utf16_cu();
275
276 let inserted_text_len = len_after_insert - len_before_insert;
277
278 let inserted_chars = text.chars().count();
280 let new_end_char = idx_utf8 + inserted_chars;
281 let new_end_byte = self.rope.char_to_byte(new_end_char);
282 let new_end_line = self.rope.char_to_line(new_end_char);
283 let new_end_line_byte = self.rope.line_to_byte(new_end_line);
284 let new_end_col = new_end_byte - new_end_line_byte;
285
286 self.pending_edit = Some(InputEdit::new_edit(
287 start_byte,
288 start_byte,
289 new_end_byte,
290 (start_line, start_col),
291 (start_line, start_col),
292 (new_end_line, new_end_col),
293 ));
294
295 self.history.push_change(HistoryChange::InsertText {
296 idx,
297 text: text.to_owned(),
298 len: inserted_text_len,
299 selection,
300 });
301
302 inserted_text_len
303 }
304
305 fn remove(&mut self, range_utf16: Range<usize>) -> usize {
306 let range =
307 self.utf16_cu_to_char(range_utf16.start)..self.utf16_cu_to_char(range_utf16.end);
308 let text = self.rope.slice(range.clone()).to_string();
309 let selection = self.selection.clone();
310
311 let start_byte = self.rope.char_to_byte(range.start);
313 let old_end_byte = self.rope.char_to_byte(range.end);
314 let start_line = self.rope.char_to_line(range.start);
315 let start_line_byte = self.rope.line_to_byte(start_line);
316 let start_col = start_byte - start_line_byte;
317 let old_end_line = self.rope.char_to_line(range.end);
318 let old_end_line_byte = self.rope.line_to_byte(old_end_line);
319 let old_end_col = old_end_byte - old_end_line_byte;
320
321 let len_before_remove = self.rope.len_utf16_cu();
322 self.rope.remove(range);
323 let len_after_remove = self.rope.len_utf16_cu();
324
325 let removed_text_len = len_before_remove - len_after_remove;
326
327 self.pending_edit = Some(InputEdit::new_edit(
329 start_byte,
330 old_end_byte,
331 start_byte,
332 (start_line, start_col),
333 (old_end_line, old_end_col),
334 (start_line, start_col),
335 ));
336
337 self.history.push_change(HistoryChange::Remove {
338 idx: range_utf16.end - removed_text_len,
339 text,
340 len: removed_text_len,
341 selection,
342 });
343
344 removed_text_len
345 }
346
347 fn char_to_line(&self, char_idx: usize) -> usize {
348 self.rope.char_to_line(char_idx)
349 }
350
351 fn line_to_char(&self, line_idx: usize) -> usize {
352 self.rope.line_to_char(line_idx)
353 }
354
355 fn utf16_cu_to_char(&self, utf16_cu_idx: usize) -> usize {
356 self.rope.utf16_cu_to_char(utf16_cu_idx)
357 }
358
359 fn char_to_utf16_cu(&self, idx: usize) -> usize {
360 self.rope.char_to_utf16_cu(idx)
361 }
362
363 fn line(&self, line_idx: usize) -> Option<Line<'_>> {
364 let line = self.rope.get_line(line_idx);
365
366 line.map(|line| Line {
367 text: Cow::Owned(line.to_string()),
368 utf16_len: line.len_utf16_cu(),
369 })
370 }
371
372 fn len_lines(&self) -> usize {
373 self.rope.len_lines()
374 }
375
376 fn len_chars(&self) -> usize {
377 self.rope.len_chars()
378 }
379
380 fn len_utf16_cu(&self) -> usize {
381 self.rope.len_utf16_cu()
382 }
383
384 fn has_any_selection(&self) -> bool {
385 self.selection.is_range()
386 }
387
388 fn get_selection(&self) -> Option<(usize, usize)> {
389 match self.selection {
390 TextSelection::Cursor(_) => None,
391 TextSelection::Range { from, to } => Some((from, to)),
392 }
393 }
394
395 fn set(&mut self, text: &str) {
396 self.rope.remove(0..);
397 self.rope.insert(0, text);
398 }
399
400 fn clear_selection(&mut self) {
401 let end = self.selection().end();
402 self.selection_mut().set_as_cursor();
403 self.selection_mut().move_to(end);
404 }
405
406 fn set_selection(&mut self, (from, to): (usize, usize)) {
407 self.selection = TextSelection::Range { from, to };
408 }
409
410 fn get_selected_text(&self) -> Option<String> {
411 let (start, end) = self.get_selection_range()?;
412
413 Some(self.rope.get_slice(start..end)?.to_string())
414 }
415
416 fn get_selection_range(&self) -> Option<(usize, usize)> {
417 let (start, end) = match self.selection {
418 TextSelection::Cursor(_) => return None,
419 TextSelection::Range { from, to } => (from, to),
420 };
421
422 let (start, end) = if start < end {
424 (start, end)
425 } else {
426 (end, start)
427 };
428
429 Some((start, end))
430 }
431
432 fn undo(&mut self) -> Option<TextSelection> {
433 self.pending_edit = None;
435 self.metrics.highlighter.invalidate_tree();
436 self.history.undo(&mut self.rope)
437 }
438
439 fn redo(&mut self) -> Option<TextSelection> {
440 self.pending_edit = None;
442 self.metrics.highlighter.invalidate_tree();
443 self.history.redo(&mut self.rope)
444 }
445
446 fn editor_history(&mut self) -> &mut EditorHistory {
447 &mut self.history
448 }
449
450 fn selection(&self) -> &TextSelection {
451 &self.selection
452 }
453
454 fn selection_mut(&mut self) -> &mut TextSelection {
455 &mut self.selection
456 }
457
458 fn get_indentation(&self) -> u8 {
459 4
460 }
461}