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