1use crate::{BufferPosition, EditorAction, EditorState};
4use std::fs;
5use std::io;
6use std::path::{Path, PathBuf};
7use std::time::{Duration, Instant};
8
9pub struct EditorEngine {
10 state: EditorState,
11 undo_stack: Vec<EditorState>,
12 redo_stack: Vec<EditorState>,
13 last_edit_time: Option<Instant>,
14}
15
16const UNDO_CHUNK_DURATION: Duration = Duration::from_millis(500);
17
18impl EditorEngine {
19 pub fn new() -> Self {
20 Self {
21 state: EditorState::new(),
22 undo_stack: Vec::new(),
23 redo_stack: Vec::new(),
24 last_edit_time: None,
25 }
26 }
27
28 pub fn state(&self) -> &EditorState {
29 &self.state
30 }
31
32 pub fn state_mut(&mut self) -> &mut EditorState {
33 &mut self.state
34 }
35
36 fn should_push_undo_state(&self) -> bool {
37 if let Some(last_time) = self.last_edit_time {
38 Instant::now().duration_since(last_time) > UNDO_CHUNK_DURATION
39 } else {
40 true
41 }
42 }
43
44 fn push_undo_state(&mut self) {
45 if !self.should_push_undo_state() {
46 return;
47 }
48 self.undo_stack.push(self.state.clone_for_undo());
49 self.redo_stack.clear();
50 }
51
52 fn mark_edit_time(&mut self) {
53 self.last_edit_time = Some(Instant::now());
54 }
55
56 pub fn handle_action(&mut self, action: EditorAction) {
57 match action {
58 EditorAction::TypeCharacter(c) => self.type_character(c),
59 EditorAction::TypeString(s) => self.type_string(&s),
60 EditorAction::Backspace => self.backspace(),
61 EditorAction::Delete => self.delete(),
62 EditorAction::Newline => self.newline(),
63 EditorAction::MoveLeft => self.move_left(),
64 EditorAction::MoveRight => self.move_right(),
65 EditorAction::MoveUp => self.move_up(),
66 EditorAction::MoveDown => self.move_down(),
67 EditorAction::MoveToBeginningOfLine => self.move_to_line_start(),
68 EditorAction::MoveToEndOfLine => self.move_to_line_end(),
69 EditorAction::MoveWordLeft => self.move_word_left(),
70 EditorAction::MoveWordRight => self.move_word_right(),
71 EditorAction::Undo => self.undo(),
72 EditorAction::Redo => self.redo(),
73 EditorAction::DeleteLine => self.delete_line(),
74 EditorAction::DeleteToBeginningOfLine => self.delete_to_beginning_of_line(),
75 EditorAction::DeleteToEndOfLine => self.delete_to_end_of_line(),
76 EditorAction::DeleteWordLeft => self.delete_word_left(),
77 EditorAction::DeleteWordRight => self.delete_word_right(),
78 EditorAction::MoveLineUp => self.move_line_up(),
79 EditorAction::MoveLineDown => self.move_line_down(),
80 EditorAction::Tab => self.tab(),
81 EditorAction::Outdent => self.outdent(),
82 EditorAction::SelectLeft => self.select_left(),
83 EditorAction::SelectRight => self.select_right(),
84 EditorAction::SelectUp => self.select_up(),
85 EditorAction::SelectDown => self.select_down(),
86 EditorAction::SelectWordLeft => self.select_word_left(),
87 EditorAction::SelectWordRight => self.select_word_right(),
88 EditorAction::SelectAll => self.select_all(),
89 EditorAction::IncreaseFontSize => {
90 self.state.font_size = (self.state.font_size + 2.0).min(72.0);
91 }
92 EditorAction::DecreaseFontSize => {
93 self.state.font_size = (self.state.font_size - 2.0).max(8.0);
94 }
95 EditorAction::ResetFontSize => {
96 self.state.font_size = 14.0;
97 }
98 EditorAction::Cut | EditorAction::Copy | EditorAction::Paste(_) => {
99 }
101 EditorAction::Quit => {
102 }
104 EditorAction::SetCursorPosition { row, column } => {
105 self.set_cursor_position(row, column)
106 }
107 EditorAction::StartSelection { row, column } => self.start_selection(row, column),
108 EditorAction::ExtendSelection { row, column } => self.extend_selection(row, column),
109 }
110 }
111
112 fn selection_range(&self) -> Option<(BufferPosition, BufferPosition)> {
113 self.state.selection_anchor.map(|anchor| {
114 if anchor.row < self.state.cursor.row
115 || (anchor.row == self.state.cursor.row && anchor.column < self.state.cursor.column)
116 {
117 (anchor, self.state.cursor)
118 } else {
119 (self.state.cursor, anchor)
120 }
121 })
122 }
123
124 fn clear_selection(&mut self) {
125 self.state.selection_anchor = None;
126 }
127
128 fn delete_selection(&mut self) {
129 if let Some((start, end)) = self.selection_range() {
130 self.delete_range(start, end);
131 self.state.cursor = start;
132 self.clear_selection();
133 }
134 }
135
136 fn delete_range(&mut self, start: BufferPosition, end: BufferPosition) {
137 if start.row == end.row {
138 let line = &mut self.state.lines[start.row];
139 line.replace_range(start.column..end.column, "");
140 } else {
141 let first_part = self.state.lines[start.row][..start.column].to_string();
142 let last_part = self.state.lines[end.row][end.column..].to_string();
143 self.state.lines[start.row] = first_part + &last_part;
144 self.state.lines.drain((start.row + 1)..=(end.row));
145 }
146 }
147
148 fn type_character(&mut self, c: char) {
149 self.push_undo_state();
150 self.mark_edit_time();
151 self.delete_selection();
152
153 if c == '\n' {
154 let line = self.state.lines[self.state.cursor.row].clone();
155 let (before, after) = line.split_at(self.state.cursor.column);
156 self.state.lines[self.state.cursor.row] = before.to_string();
157 self.state
158 .lines
159 .insert(self.state.cursor.row + 1, after.to_string());
160 self.state.cursor = BufferPosition::new(self.state.cursor.row + 1, 0);
161 } else {
162 self.state.lines[self.state.cursor.row].insert(self.state.cursor.column, c);
163 self.state.cursor.column += c.len_utf8();
164 }
165 }
166
167 fn type_string(&mut self, s: &str) {
168 self.push_undo_state();
169 self.mark_edit_time();
170 self.delete_selection();
171
172 for c in s.chars() {
173 if c == '\n' {
174 let line = self.state.lines[self.state.cursor.row].clone();
175 let (before, after) = line.split_at(self.state.cursor.column);
176 self.state.lines[self.state.cursor.row] = before.to_string();
177 self.state
178 .lines
179 .insert(self.state.cursor.row + 1, after.to_string());
180 self.state.cursor = BufferPosition::new(self.state.cursor.row + 1, 0);
181 } else {
182 self.state.lines[self.state.cursor.row].insert(self.state.cursor.column, c);
183 self.state.cursor.column += c.len_utf8();
184 }
185 }
186 }
187
188 fn backspace(&mut self) {
189 self.push_undo_state();
190 self.mark_edit_time();
191
192 if let Some((start, end)) = self.selection_range() {
193 self.delete_range(start, end);
194 self.state.cursor = start;
195 self.clear_selection();
196 } else if self.state.cursor.column > 0 {
197 let line = &self.state.lines[self.state.cursor.row];
198 let before = &line[..self.state.cursor.column];
199 if let Some((last_char_start, _)) = before.char_indices().last() {
200 self.state.lines[self.state.cursor.row].remove(last_char_start);
201 self.state.cursor.column = last_char_start;
202 }
203 } else if self.state.cursor.row > 0 {
204 let current_line = self.state.lines.remove(self.state.cursor.row);
205 self.state.cursor.row -= 1;
206 self.state.cursor.column = self.state.lines[self.state.cursor.row].len();
207 self.state.lines[self.state.cursor.row].push_str(¤t_line);
208 }
209 }
210
211 fn delete(&mut self) {
212 self.push_undo_state();
213 self.mark_edit_time();
214
215 if let Some((start, end)) = self.selection_range() {
216 self.delete_range(start, end);
217 self.state.cursor = start;
218 self.clear_selection();
219 } else {
220 let line_len = self.state.lines[self.state.cursor.row].len();
221 if self.state.cursor.column < line_len {
222 self.state.lines[self.state.cursor.row].remove(self.state.cursor.column);
223 } else if self.state.cursor.row + 1 < self.state.lines.len() {
224 let next_line = self.state.lines.remove(self.state.cursor.row + 1);
225 self.state.lines[self.state.cursor.row].push_str(&next_line);
226 }
227 }
228 }
229
230 fn detect_list_pattern(line: &str) -> Option<(String, usize, bool)> {
231 let trimmed = line.trim_start();
232 let indent_len = line.len() - trimmed.len();
233
234 if let Some(rest) = trimmed.strip_prefix("- [ ] ") {
235 return Some(("- [ ] ".to_string(), indent_len + 6, rest.is_empty()));
236 }
237 if let Some(rest) = trimmed.strip_prefix("- [x] ") {
238 return Some(("- [ ] ".to_string(), indent_len + 6, rest.is_empty()));
239 }
240 if let Some(rest) = trimmed.strip_prefix("- [X] ") {
241 return Some(("- [ ] ".to_string(), indent_len + 6, rest.is_empty()));
242 }
243 if let Some(rest) = trimmed.strip_prefix("- ") {
244 return Some(("- ".to_string(), indent_len + 2, rest.is_empty()));
245 }
246 if let Some(rest) = trimmed.strip_prefix("* ") {
247 return Some(("* ".to_string(), indent_len + 2, rest.is_empty()));
248 }
249 if let Some(rest) = trimmed.strip_prefix("+ ") {
250 return Some(("+ ".to_string(), indent_len + 2, rest.is_empty()));
251 }
252
253 if let Some(number_end) = trimmed.find(". ") {
254 if let Ok(num) = trimmed[..number_end].parse::<usize>() {
255 let rest = &trimmed[number_end + 2..];
256 let next_num = num + 1;
257 let pattern = format!("{}. ", next_num);
258 return Some((pattern, indent_len + number_end + 2, rest.is_empty()));
259 }
260 }
261
262 None
263 }
264
265 fn newline(&mut self) {
266 self.push_undo_state();
267 self.last_edit_time = None;
268 self.delete_selection();
269
270 let line = self.state.lines[self.state.cursor.row].clone();
271
272 if let Some((pattern, pattern_len, is_empty)) = Self::detect_list_pattern(&line) {
273 if is_empty {
274 let before_pattern = &line[..line.len() - pattern_len];
275 self.state.lines[self.state.cursor.row] = before_pattern.to_string();
276 self.state
277 .lines
278 .insert(self.state.cursor.row + 1, String::new());
279 self.state.cursor = BufferPosition::new(self.state.cursor.row + 1, 0);
280 } else {
281 let (before, after) = line.split_at(self.state.cursor.column);
282 self.state.lines[self.state.cursor.row] = before.to_string();
283 self.state
284 .lines
285 .insert(self.state.cursor.row + 1, pattern.clone() + after);
286 self.state.cursor = BufferPosition::new(self.state.cursor.row + 1, pattern.len());
287 }
288 } else {
289 let (before, after) = line.split_at(self.state.cursor.column);
290 self.state.lines[self.state.cursor.row] = before.to_string();
291 self.state
292 .lines
293 .insert(self.state.cursor.row + 1, after.to_string());
294 self.state.cursor = BufferPosition::new(self.state.cursor.row + 1, 0);
295 }
296 }
297
298 fn move_left(&mut self) {
299 self.clear_selection();
300 if self.state.cursor.column > 0 {
301 let line = &self.state.lines[self.state.cursor.row];
302 let before = &line[..self.state.cursor.column];
303 if let Some(prev_char) = before.chars().last() {
304 self.state.cursor.column -= prev_char.len_utf8();
305 }
306 } else if self.state.cursor.row > 0 {
307 self.state.cursor.row -= 1;
308 self.state.cursor.column = self.state.lines[self.state.cursor.row].len();
309 }
310 }
311
312 fn move_right(&mut self) {
313 self.clear_selection();
314 let line_len = self.state.lines[self.state.cursor.row].len();
315 if self.state.cursor.column < line_len {
316 let after = &self.state.lines[self.state.cursor.row][self.state.cursor.column..];
317 if let Some(next_char) = after.chars().next() {
318 self.state.cursor.column += next_char.len_utf8();
319 }
320 } else if self.state.cursor.row + 1 < self.state.lines.len() {
321 self.state.cursor.row += 1;
322 self.state.cursor.column = 0;
323 }
324 }
325
326 fn move_up(&mut self) {
327 self.clear_selection();
328 if self.state.cursor.row > 0 {
329 self.state.cursor.row -= 1;
330 let line_len = self.state.lines[self.state.cursor.row].len();
331 self.state.cursor.column = self.state.cursor.column.min(line_len);
332 }
333 }
334
335 fn move_down(&mut self) {
336 self.clear_selection();
337 if self.state.cursor.row + 1 < self.state.lines.len() {
338 self.state.cursor.row += 1;
339 let line_len = self.state.lines[self.state.cursor.row].len();
340 self.state.cursor.column = self.state.cursor.column.min(line_len);
341 }
342 }
343
344 fn move_to_line_start(&mut self) {
345 self.clear_selection();
346 self.state.cursor.column = 0;
347 }
348
349 fn move_to_line_end(&mut self) {
350 self.clear_selection();
351 self.state.cursor.column = self.state.lines[self.state.cursor.row].len();
352 }
353
354 fn move_word_left(&mut self) {
355 self.clear_selection();
356
357 if self.state.cursor.column == 0 {
358 if self.state.cursor.row > 0 {
359 self.state.cursor.row -= 1;
360 self.state.cursor.column = self.state.lines[self.state.cursor.row].len();
361 }
362 return;
363 }
364
365 let line = &self.state.lines[self.state.cursor.row];
366 let mut pos = self.state.cursor.column;
367
368 while pos > 0
370 && line
371 .chars()
372 .nth(pos - 1)
373 .map_or(false, |c| c.is_whitespace())
374 {
375 pos -= 1;
376 }
377
378 while pos > 0 {
380 let ch = line.chars().nth(pos - 1);
381 if ch.map_or(false, |c| !c.is_alphanumeric() && c != '_') {
382 break;
383 }
384 pos -= 1;
385 }
386
387 self.state.cursor.column = pos;
388 }
389
390 fn move_word_right(&mut self) {
391 self.clear_selection();
392
393 let line = &self.state.lines[self.state.cursor.row];
394
395 if self.state.cursor.column >= line.len() {
396 if self.state.cursor.row < self.state.lines.len() - 1 {
397 self.state.cursor.row += 1;
398 self.state.cursor.column = 0;
399 }
400 return;
401 }
402
403 let mut pos = self.state.cursor.column;
404
405 while pos < line.len() {
407 let ch = line.chars().nth(pos);
408 if ch.map_or(false, |c| !c.is_alphanumeric() && c != '_') {
409 break;
410 }
411 pos += 1;
412 }
413
414 while pos < line.len() && line.chars().nth(pos).map_or(false, |c| c.is_whitespace()) {
416 pos += 1;
417 }
418
419 self.state.cursor.column = pos;
420 }
421
422 fn undo(&mut self) {
423 if let Some(prev_state) = self.undo_stack.pop() {
424 self.redo_stack.push(self.state.clone_for_undo());
425 self.state = prev_state;
426 self.last_edit_time = None;
427 }
428 }
429
430 fn redo(&mut self) {
431 if let Some(next_state) = self.redo_stack.pop() {
432 self.undo_stack.push(self.state.clone_for_undo());
433 self.state = next_state;
434 self.last_edit_time = None;
435 }
436 }
437
438 fn delete_line(&mut self) {
439 self.push_undo_state();
440 self.last_edit_time = None;
441
442 if self.state.lines.len() == 1 {
443 self.state.lines[0].clear();
444 self.state.cursor = BufferPosition::zero();
445 } else if self.state.cursor.row < self.state.lines.len() - 1 {
446 self.state.lines.remove(self.state.cursor.row);
447 self.state.cursor.column = 0;
448 } else {
449 self.state.lines.remove(self.state.cursor.row);
450 self.state.cursor.row -= 1;
451 self.state.cursor.column = 0;
452 }
453 self.clear_selection();
454 }
455
456 fn delete_to_beginning_of_line(&mut self) {
457 self.push_undo_state();
458 self.last_edit_time = None;
459 self.state.lines[self.state.cursor.row].replace_range(..self.state.cursor.column, "");
460 self.state.cursor.column = 0;
461 }
462
463 fn delete_to_end_of_line(&mut self) {
464 self.push_undo_state();
465 self.last_edit_time = None;
466 self.state.lines[self.state.cursor.row].replace_range(self.state.cursor.column.., "");
467 }
468
469 fn delete_word_left(&mut self) {
470 let start_pos = self.state.cursor;
471 self.move_word_left();
472 let end_pos = self.state.cursor;
473
474 if start_pos.row == end_pos.row {
475 self.push_undo_state();
476 self.last_edit_time = None;
477 self.state.lines[end_pos.row].replace_range(end_pos.column..start_pos.column, "");
478 }
479 }
480
481 fn delete_word_right(&mut self) {
482 let start_pos = self.state.cursor;
483 self.move_word_right();
484 let end_pos = self.state.cursor;
485
486 if start_pos.row == end_pos.row {
487 self.push_undo_state();
488 self.last_edit_time = None;
489 self.state.cursor = start_pos;
490 self.state.lines[start_pos.row].replace_range(start_pos.column..end_pos.column, "");
491 }
492 }
493
494 fn move_line_up(&mut self) {
495 if self.state.cursor.row == 0 {
496 return;
497 }
498 self.push_undo_state();
499 self.last_edit_time = None;
500 self.state
501 .lines
502 .swap(self.state.cursor.row, self.state.cursor.row - 1);
503 self.state.cursor.row -= 1;
504 }
505
506 fn move_line_down(&mut self) {
507 if self.state.cursor.row + 1 >= self.state.lines.len() {
508 return;
509 }
510 self.push_undo_state();
511 self.last_edit_time = None;
512 self.state
513 .lines
514 .swap(self.state.cursor.row, self.state.cursor.row + 1);
515 self.state.cursor.row += 1;
516 }
517
518 fn tab(&mut self) {
519 self.push_undo_state();
520 self.last_edit_time = None;
521
522 if let Some((start, end)) = self.selection_range() {
523 for row in start.row..=end.row {
524 self.state.lines[row].insert_str(0, " ");
525 }
526 self.state.selection_anchor = Some(BufferPosition::new(start.row, start.column + 4));
527 self.state.cursor = BufferPosition::new(end.row, end.column + 4);
528 } else {
529 self.state.lines[self.state.cursor.row].insert_str(self.state.cursor.column, " ");
530 self.state.cursor.column += 4;
531 }
532 }
533
534 fn outdent(&mut self) {
535 self.push_undo_state();
536 self.last_edit_time = None;
537
538 if let Some((start, end)) = self.selection_range() {
539 for row in start.row..=end.row {
540 let spaces_to_remove = self.state.lines[row]
541 .chars()
542 .take(4)
543 .take_while(|&c| c == ' ')
544 .count();
545 if spaces_to_remove > 0 {
546 self.state.lines[row].replace_range(..spaces_to_remove, "");
547 }
548 }
549 let new_start_col = start.column.saturating_sub(4);
550 let new_end_col = end.column.saturating_sub(4);
551 self.state.selection_anchor = Some(BufferPosition::new(start.row, new_start_col));
552 self.state.cursor = BufferPosition::new(end.row, new_end_col);
553 } else {
554 let spaces_to_remove = self.state.lines[self.state.cursor.row]
555 .chars()
556 .take(4)
557 .take_while(|&c| c == ' ')
558 .count();
559 if spaces_to_remove > 0 {
560 self.state.lines[self.state.cursor.row].replace_range(..spaces_to_remove, "");
561 self.state.cursor.column =
562 self.state.cursor.column.saturating_sub(spaces_to_remove);
563 }
564 }
565 }
566
567 fn select_left(&mut self) {
568 if self.state.selection_anchor.is_none() {
569 self.state.selection_anchor = Some(self.state.cursor);
570 }
571 if self.state.cursor.column > 0 {
572 let line = &self.state.lines[self.state.cursor.row];
573 let before = &line[..self.state.cursor.column];
574 if let Some(prev_char) = before.chars().last() {
575 self.state.cursor.column -= prev_char.len_utf8();
576 }
577 } else if self.state.cursor.row > 0 {
578 self.state.cursor.row -= 1;
579 self.state.cursor.column = self.state.lines[self.state.cursor.row].len();
580 }
581 }
582
583 fn select_right(&mut self) {
584 if self.state.selection_anchor.is_none() {
585 self.state.selection_anchor = Some(self.state.cursor);
586 }
587 let line_len = self.state.lines[self.state.cursor.row].len();
588 if self.state.cursor.column < line_len {
589 let after = &self.state.lines[self.state.cursor.row][self.state.cursor.column..];
590 if let Some(next_char) = after.chars().next() {
591 self.state.cursor.column += next_char.len_utf8();
592 }
593 } else if self.state.cursor.row + 1 < self.state.lines.len() {
594 self.state.cursor.row += 1;
595 self.state.cursor.column = 0;
596 }
597 }
598
599 fn select_up(&mut self) {
600 if self.state.selection_anchor.is_none() {
601 self.state.selection_anchor = Some(self.state.cursor);
602 }
603 if self.state.cursor.row > 0 {
604 self.state.cursor.row -= 1;
605 let line_len = self.state.lines[self.state.cursor.row].len();
606 self.state.cursor.column = self.state.cursor.column.min(line_len);
607 }
608 }
609
610 fn select_down(&mut self) {
611 if self.state.selection_anchor.is_none() {
612 self.state.selection_anchor = Some(self.state.cursor);
613 }
614 if self.state.cursor.row + 1 < self.state.lines.len() {
615 self.state.cursor.row += 1;
616 let line_len = self.state.lines[self.state.cursor.row].len();
617 self.state.cursor.column = self.state.cursor.column.min(line_len);
618 }
619 }
620
621 fn select_word_left(&mut self) {
622 if self.state.selection_anchor.is_none() {
623 self.state.selection_anchor = Some(self.state.cursor);
624 }
625 self.move_word_left();
626 }
627
628 fn select_word_right(&mut self) {
629 if self.state.selection_anchor.is_none() {
630 self.state.selection_anchor = Some(self.state.cursor);
631 }
632 self.move_word_right();
633 }
634
635 fn select_all(&mut self) {
636 self.state.selection_anchor = Some(BufferPosition::zero());
637 let last_row = self.state.lines.len().saturating_sub(1);
638 let last_col = self.state.lines[last_row].len();
639 self.state.cursor = BufferPosition::new(last_row, last_col);
640 }
641
642 fn set_cursor_position(&mut self, row: usize, column: usize) {
644 self.clear_selection();
645 let row = row.min(self.state.lines.len().saturating_sub(1));
646 let column = column.min(self.state.lines[row].len());
647 self.state.cursor = BufferPosition::new(row, column);
648 }
649
650 fn start_selection(&mut self, row: usize, column: usize) {
652 let row = row.min(self.state.lines.len().saturating_sub(1));
653 let column = column.min(self.state.lines[row].len());
654 self.state.cursor = BufferPosition::new(row, column);
655 self.state.selection_anchor = Some(self.state.cursor);
656 }
657
658 fn extend_selection(&mut self, row: usize, column: usize) {
660 if self.state.selection_anchor.is_none() {
661 self.state.selection_anchor = Some(self.state.cursor);
662 }
663 let row = row.min(self.state.lines.len().saturating_sub(1));
664 let column = column.min(self.state.lines[row].len());
665 self.state.cursor = BufferPosition::new(row, column);
666 }
667
668 pub fn load_from_file<P: AsRef<Path>>(&mut self, path: P) -> io::Result<()> {
670 let content = fs::read_to_string(path)?;
671 self.state.lines = if content.is_empty() {
672 vec![String::new()]
673 } else {
674 content.lines().map(|s| s.to_string()).collect()
675 };
676 self.state.cursor = BufferPosition::zero();
677 self.state.selection_anchor = None;
678 self.undo_stack.clear();
679 self.redo_stack.clear();
680 self.last_edit_time = None;
681 Ok(())
682 }
683
684 pub fn save_to_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
686 let content = self.state.lines.join("\n");
687 if let Some(parent) = path.as_ref().parent() {
688 fs::create_dir_all(parent)?;
689 }
690 fs::write(path, content)
691 }
692
693 pub fn default_file_path() -> PathBuf {
695 let home = std::env::var("HOME")
696 .or_else(|_| std::env::var("USERPROFILE"))
697 .unwrap_or_else(|_| ".".to_string());
698 PathBuf::from(home)
699 .join(".config")
700 .join("zrd")
701 .join("default.txt")
702 }
703}
704
705impl Default for EditorEngine {
706 fn default() -> Self {
707 Self::new()
708 }
709}