1use std::{collections::HashSet, iter, ops::Range};
2
3use itertools::Itertools;
4use lapce_xi_rope::{DeltaElement, Rope, RopeDelta};
5
6use crate::{
7 buffer::{rope_text::RopeText, Buffer, InvalLines},
8 command::EditCommand,
9 cursor::{get_first_selection_after, Cursor, CursorMode},
10 mode::{Mode, MotionMode, VisualMode},
11 register::{Clipboard, Register, RegisterData, RegisterKind},
12 selection::{InsertDrift, SelRegion, Selection},
13 util::{
14 has_unmatched_pair, matching_char, matching_pair_direction, str_is_pair_left,
15 str_matching_pair,
16 },
17 word::{get_char_property, CharClassification},
18};
19
20fn format_start_end(
21 buffer: &Buffer,
22 range: Range<usize>,
23 is_vertical: bool,
24 first_non_blank: bool,
25 count: usize,
26) -> Range<usize> {
27 let start = range.start;
28 let end = range.end;
29
30 if is_vertical {
31 let start_line = buffer.line_of_offset(start.min(end));
32 let end_line = buffer.line_of_offset(end.max(start));
33 let start = if first_non_blank {
34 buffer.first_non_blank_character_on_line(start_line)
35 } else {
36 buffer.offset_of_line(start_line)
37 };
38 let end = buffer.offset_of_line(end_line + count);
39 start..end
40 } else {
41 let s = start.min(end);
42 let e = start.max(end);
43 s..e
44 }
45}
46
47#[derive(Clone, Copy, Debug, PartialEq, Eq)]
48pub enum EditType {
49 InsertChars,
50 Delete,
51 DeleteSelection,
52 InsertNewline,
53 Cut,
54 Paste,
55 Indent,
56 Outdent,
57 ToggleComment,
58 MoveLine,
59 Completion,
60 DeleteWord,
61 DeleteToBeginningOfLine,
62 DeleteToEndOfLine,
63 DeleteToEndOfLineAndInsert,
64 MotionDelete,
65 NormalizeLineEndings,
66 Undo,
67 Redo,
68 Other,
69}
70
71impl EditType {
72 pub fn breaks_undo_group(self, previous: EditType) -> bool {
74 !((self == EditType::InsertChars || self == EditType::Delete) && self == previous)
75 }
76}
77
78pub struct EditConf<'a> {
79 pub comment_token: &'a str,
80 pub modal: bool,
81 pub smart_tab: bool,
82 pub keep_indent: bool,
83 pub auto_indent: bool,
84}
85
86pub struct Action {}
87
88impl Action {
89 pub fn insert(
90 cursor: &mut Cursor,
91 buffer: &mut Buffer,
92 s: &str,
93 prev_unmatched: &dyn Fn(&Buffer, char, usize) -> Option<usize>,
94 auto_closing_matching_pairs: bool,
95 auto_surround: bool,
96 ) -> Vec<(Rope, RopeDelta, InvalLines)> {
97 let mut deltas = Vec::new();
98 if let CursorMode::Insert(selection) = &cursor.mode {
99 if s.chars().count() != 1 {
100 let (text, delta, inval_lines) =
101 buffer.edit([(selection, s)], EditType::InsertChars);
102 let selection = selection.apply_delta(&delta, true, InsertDrift::Default);
103 deltas.push((text, delta, inval_lines));
104 cursor.mode = CursorMode::Insert(selection);
105 } else {
106 let c = s.chars().next().unwrap();
107 let matching_pair_type = matching_pair_direction(c);
108
109 let mut edits = vec![];
111
112 let mut edits_after = vec![];
114
115 let mut selection = selection.clone();
116 for (idx, region) in selection.regions_mut().iter_mut().enumerate() {
117 let offset = region.end;
118 let cursor_char = buffer.char_at_offset(offset);
119 let prev_offset = buffer.move_left(offset, Mode::Normal, 1);
120 let prev_cursor_char = if prev_offset < offset {
121 buffer.char_at_offset(prev_offset)
122 } else {
123 None
124 };
125
126 if region.start != region.end
129 && auto_surround
130 && (matching_pair_type == Some(true) || c == '"' || c == '\'' || c == '`')
131 {
132 edits.push((Selection::region(region.min(), region.min()), c.to_string()));
133 edits_after.push((
134 idx,
135 match c {
136 '"' => '"',
137 '\'' => '\'',
138 '`' => '`',
139 _ => matching_char(c).unwrap(),
140 },
141 ));
142 continue;
143 }
144
145 if auto_closing_matching_pairs {
146 if (c == '"' || c == '\'' || c == '`') && cursor_char == Some(c) {
147 let new_offset = buffer.next_grapheme_offset(offset, 1, buffer.len());
149
150 *region = SelRegion::caret(new_offset);
151 continue;
152 }
153
154 if matching_pair_type == Some(false) {
155 if cursor_char == Some(c) {
156 let new_offset =
158 buffer.next_grapheme_offset(offset, 1, buffer.len());
159
160 *region = SelRegion::caret(new_offset);
161 continue;
162 }
163
164 let line = buffer.line_of_offset(offset);
165 let line_start = buffer.offset_of_line(line);
166 if buffer.slice_to_cow(line_start..offset).trim() == "" {
167 let opening_character = matching_char(c).unwrap();
168 if let Some(previous_offset) =
169 prev_unmatched(buffer, opening_character, offset)
170 {
171 let previous_line = buffer.line_of_offset(previous_offset);
173 let line_indent = buffer.indent_on_line(previous_line);
174
175 let current_selection = Selection::region(line_start, offset);
176
177 edits.push((current_selection, format!("{line_indent}{c}")));
178 continue;
179 }
180 }
181 }
182
183 if matching_pair_type == Some(true) || c == '"' || c == '\'' || c == '`' {
184 let is_whitespace_or_punct = cursor_char
186 .map(|c| {
187 let prop = get_char_property(c);
188 prop == CharClassification::Lf
189 || prop == CharClassification::Cr
190 || prop == CharClassification::Space
191 || prop == CharClassification::Punctuation
192 })
193 .unwrap_or(true);
194
195 let should_insert_pair = match c {
196 '"' | '\'' | '`' => {
197 is_whitespace_or_punct
198 && prev_cursor_char
199 .map(|c| {
200 let prop = get_char_property(c);
201 prop == CharClassification::Lf
202 || prop == CharClassification::Cr
203 || prop == CharClassification::Space
204 || prop == CharClassification::Punctuation
205 })
206 .unwrap_or(true)
207 }
208 _ => is_whitespace_or_punct,
209 };
210
211 if should_insert_pair {
212 let insert_after = match c {
213 '"' => '"',
214 '\'' => '\'',
215 '`' => '`',
216 _ => matching_char(c).unwrap(),
217 };
218 edits_after.push((idx, insert_after));
219 }
220 };
221 }
222
223 let current_selection = Selection::region(region.start, region.end);
224
225 edits.push((current_selection, c.to_string()));
226 }
227
228 let edits = edits
230 .iter()
231 .map(|(selection, content)| (selection, content.as_str()))
232 .collect::<Vec<_>>();
233
234 let (text, delta, inval_lines) = buffer.edit(&edits, EditType::InsertChars);
235
236 buffer.set_cursor_before(CursorMode::Insert(selection.clone()));
237
238 let mut selection = selection.apply_delta(&delta, true, InsertDrift::Default);
240
241 buffer.set_cursor_after(CursorMode::Insert(selection.clone()));
242
243 deltas.push((text, delta, inval_lines));
244 let edits_after = edits_after
246 .iter()
247 .map(|(idx, content)| {
248 let region = &selection.regions()[*idx];
249 (
250 Selection::region(region.max(), region.max()),
251 content.to_string(),
252 )
253 })
254 .collect::<Vec<_>>();
255
256 let edits_after = edits_after
257 .iter()
258 .map(|(selection, content)| (selection, content.as_str()))
259 .collect::<Vec<_>>();
260
261 if !edits_after.is_empty() {
262 let (text, delta, inval_lines) =
263 buffer.edit(&edits_after, EditType::InsertChars);
264 deltas.push((text, delta, inval_lines));
265 }
266
267 let mut adjustment = 0;
269 for region in selection
270 .regions_mut()
271 .iter_mut()
272 .sorted_by(|region_a, region_b| region_a.start.cmp(®ion_b.start))
273 {
274 let new_region =
275 SelRegion::new(region.start + adjustment, region.end + adjustment, None);
276
277 if let Some(inserted) = edits_after.iter().find_map(|(selection, str)| {
278 if selection.last_inserted().map(|r| r.start) == Some(region.start) {
279 Some(str)
280 } else {
281 None
282 }
283 }) {
284 adjustment += inserted.len();
285 }
286
287 *region = new_region;
288 }
289
290 cursor.mode = CursorMode::Insert(selection);
291 }
292 }
293 deltas
294 }
295
296 fn toggle_visual(cursor: &mut Cursor, visual_mode: VisualMode, modal: bool) {
297 if !modal {
298 return;
299 }
300
301 match &cursor.mode {
302 CursorMode::Visual { start, end, mode } => {
303 if mode != &visual_mode {
304 cursor.mode = CursorMode::Visual {
305 start: *start,
306 end: *end,
307 mode: visual_mode,
308 };
309 } else {
310 cursor.mode = CursorMode::Normal(*end);
311 };
312 }
313 _ => {
314 let offset = cursor.offset();
315 cursor.mode = CursorMode::Visual {
316 start: offset,
317 end: offset,
318 mode: visual_mode,
319 };
320 }
321 }
322 }
323
324 fn insert_new_line(
325 buffer: &mut Buffer,
326 cursor: &mut Cursor,
327 selection: Selection,
328 keep_indent: bool,
329 auto_indent: bool,
330 ) -> Vec<(Rope, RopeDelta, InvalLines)> {
331 let mut edits = Vec::with_capacity(selection.regions().len());
332 let mut extra_edits = Vec::new();
333 let mut shift = 0i32;
334 let line_ending = buffer.line_ending().get_chars();
335 for region in selection.regions() {
336 let offset = region.max();
337 let line = buffer.line_of_offset(offset);
338 let line_start = buffer.offset_of_line(line);
339 let line_end = buffer.line_end_offset(line, true);
340 let line_indent = buffer.indent_on_line(line);
341 let first_half = buffer.slice_to_cow(line_start..offset);
342 let second_half = buffer.slice_to_cow(offset..line_end);
343 let second_half_trim = second_half.trim();
344
345 let new_line_content = {
347 let indent_storage;
348 let indent = if auto_indent && has_unmatched_pair(&first_half) {
349 indent_storage = format!("{}{}", line_indent, buffer.indent_unit());
350 &indent_storage
351 } else if keep_indent
352 && (second_half_trim.is_empty() || !second_half.starts_with(&line_indent))
353 {
354 &line_indent
355 } else {
356 indent_storage = String::new();
357 &indent_storage
358 };
359 format!("{line_ending}{indent}")
360 };
361
362 let selection = Selection::region(region.min(), region.max());
363
364 shift -= (region.max() - region.min()) as i32;
365 shift += new_line_content.len() as i32;
366
367 edits.push((selection, new_line_content));
368
369 if let Some(c) = first_half.chars().rev().find(|&c| c != ' ') {
370 if let Some(true) = matching_pair_direction(c) {
371 if let Some(c) = matching_char(c) {
372 if second_half_trim.starts_with(c) {
373 let selection =
374 Selection::caret((region.max() as i32 + shift) as usize);
375 let content = format!("{line_ending}{line_indent}",);
376 extra_edits.push((selection, content));
377 }
378 }
379 }
380 }
381 }
382
383 let edits = edits
384 .iter()
385 .map(|(selection, s)| (selection, s.as_str()))
386 .collect::<Vec<_>>();
387 let (text, delta, inval_lines) = buffer.edit(&edits, EditType::InsertNewline);
388 let mut selection = selection.apply_delta(&delta, true, InsertDrift::Default);
389
390 let mut deltas = vec![(text, delta, inval_lines)];
391
392 if !extra_edits.is_empty() {
393 let edits = extra_edits
394 .iter()
395 .map(|(selection, s)| (selection, s.as_str()))
396 .collect::<Vec<_>>();
397 let (text, delta, inval_lines) = buffer.edit(&edits, EditType::InsertNewline);
398 selection = selection.apply_delta(&delta, false, InsertDrift::Default);
399 deltas.push((text, delta, inval_lines));
400 }
401
402 cursor.mode = CursorMode::Insert(selection);
403
404 deltas
405 }
406
407 pub fn execute_motion_mode(
408 cursor: &mut Cursor,
409 buffer: &mut Buffer,
410 motion_mode: MotionMode,
411 range: Range<usize>,
412 is_vertical: bool,
413 register: &mut Register,
414 ) -> Vec<(Rope, RopeDelta, InvalLines)> {
415 let mut deltas = Vec::new();
416 match motion_mode {
417 MotionMode::Delete { .. } => {
418 let range = format_start_end(buffer, range, is_vertical, false, 1);
419 register.add(
420 RegisterKind::Delete,
421 RegisterData {
422 content: buffer.slice_to_cow(range.clone()).to_string(),
423 mode: if is_vertical {
424 VisualMode::Linewise
425 } else {
426 VisualMode::Normal
427 },
428 },
429 );
430 let selection = Selection::region(range.start, range.end);
431 let (text, delta, inval_lines) =
432 buffer.edit([(&selection, "")], EditType::MotionDelete);
433 cursor.apply_delta(&delta);
434 deltas.push((text, delta, inval_lines));
435 }
436 MotionMode::Yank { .. } => {
437 let range = format_start_end(buffer, range, is_vertical, false, 1);
438 register.add(
439 RegisterKind::Yank,
440 RegisterData {
441 content: buffer.slice_to_cow(range).to_string(),
442 mode: if is_vertical {
443 VisualMode::Linewise
444 } else {
445 VisualMode::Normal
446 },
447 },
448 );
449 }
450 MotionMode::Indent => {
451 let selection = Selection::region(range.start, range.end);
452 let (text, delta, inval_lines) = Self::do_indent(buffer, selection);
453 deltas.push((text, delta, inval_lines));
454 }
455 MotionMode::Outdent => {
456 let selection = Selection::region(range.start, range.end);
457 let (text, delta, inval_lines) = Self::do_outdent(buffer, selection);
458 deltas.push((text, delta, inval_lines));
459 }
460 }
461 deltas
462 }
463
464 fn compute_paste_edit(
470 buffer: &mut Buffer,
471 selection: &Selection,
472 content: &str,
473 mode: VisualMode,
474 ) -> (Rope, RopeDelta, InvalLines) {
475 if selection.len() > 1 {
476 let line_ends: Vec<_> = content.match_indices('\n').map(|(idx, _)| idx).collect();
477
478 match mode {
479 VisualMode::Normal if (line_ends.len() + 1) % selection.len() == 0 => {
483 let lines_per_group = (line_ends.len() + 1) / selection.len();
484 let mut start_idx = 0;
485 let last_line_start = line_ends
486 .len()
487 .checked_sub(lines_per_group)
488 .and_then(|line_idx| line_ends.get(line_idx))
489 .map(|line_end| line_end + 1)
490 .unwrap_or(0);
491
492 let groups = line_ends
493 .iter()
494 .skip(lines_per_group - 1)
495 .step_by(lines_per_group)
496 .map(|&end_idx| {
497 let group = &content[start_idx..end_idx];
498 let group = group.strip_suffix('\r').unwrap_or(group);
499 start_idx = end_idx + 1;
500
501 group
502 })
503 .chain(iter::once(&content[last_line_start..]));
504
505 let edits = selection
506 .regions()
507 .iter()
508 .copied()
509 .map(Selection::sel_region)
510 .zip(groups);
511
512 buffer.edit(edits, EditType::Paste)
513 }
514 VisualMode::Linewise | VisualMode::Blockwise
518 if line_ends.len() % selection.len() == 0 =>
519 {
520 let lines_per_group = line_ends.len() / selection.len();
521 let mut start_idx = 0;
522
523 let groups = line_ends
524 .iter()
525 .skip(lines_per_group - 1)
526 .step_by(lines_per_group)
527 .map(|&end_idx| {
528 let group = &content[start_idx..=end_idx];
529 start_idx = end_idx + 1;
530
531 group
532 });
533
534 let edits = selection
535 .regions()
536 .iter()
537 .copied()
538 .map(Selection::sel_region)
539 .zip(groups);
540
541 buffer.edit(edits, EditType::Paste)
542 }
543 _ => buffer.edit([(&selection, content)], EditType::Paste),
544 }
545 } else {
546 buffer.edit([(&selection, content)], EditType::Paste)
547 }
548 }
549
550 pub fn do_paste(
551 cursor: &mut Cursor,
552 buffer: &mut Buffer,
553 data: &RegisterData,
554 ) -> Vec<(Rope, RopeDelta, InvalLines)> {
555 let mut deltas = Vec::new();
556 match data.mode {
557 VisualMode::Normal => {
558 let selection = match cursor.mode {
559 CursorMode::Normal(offset) => {
560 let line_end = buffer.offset_line_end(offset, true);
561 let offset = (offset + 1).min(line_end);
562 Selection::caret(offset)
563 }
564 CursorMode::Insert { .. } | CursorMode::Visual { .. } => {
565 cursor.edit_selection(buffer)
566 }
567 };
568 let after = cursor.is_insert() || !data.content.contains('\n');
569 let (text, delta, inval_lines) =
570 Self::compute_paste_edit(buffer, &selection, &data.content, data.mode);
571 let selection = selection.apply_delta(&delta, after, InsertDrift::Default);
572 deltas.push((text, delta, inval_lines));
573 if !after {
574 cursor.update_selection(buffer, selection);
575 } else {
576 match cursor.mode {
577 CursorMode::Normal(_) | CursorMode::Visual { .. } => {
578 let offset = buffer.prev_grapheme_offset(selection.min_offset(), 1, 0);
579 cursor.mode = CursorMode::Normal(offset);
580 }
581 CursorMode::Insert { .. } => {
582 cursor.mode = CursorMode::Insert(selection);
583 }
584 }
585 }
586 }
587 VisualMode::Linewise | VisualMode::Blockwise => {
588 let (selection, content) = match &cursor.mode {
589 CursorMode::Normal(offset) => {
590 let line = buffer.line_of_offset(*offset);
591 let offset = buffer.offset_of_line(line + 1);
592 (Selection::caret(offset), data.content.clone())
593 }
594 CursorMode::Insert(selection) => {
595 let mut selection = selection.clone();
596 for region in selection.regions_mut() {
597 if region.is_caret() {
598 let line = buffer.line_of_offset(region.start);
599 let start = buffer.offset_of_line(line);
600 region.start = start;
601 region.end = start;
602 }
603 }
604 (selection, data.content.clone())
605 }
606 CursorMode::Visual { mode, .. } => {
607 let selection = cursor.edit_selection(buffer);
608 let data = match mode {
609 VisualMode::Linewise => data.content.clone(),
610 _ => "\n".to_string() + &data.content,
611 };
612 (selection, data)
613 }
614 };
615 let (text, delta, inval_lines) =
616 Self::compute_paste_edit(buffer, &selection, &content, data.mode);
617 let selection =
618 selection.apply_delta(&delta, cursor.is_insert(), InsertDrift::Default);
619 deltas.push((text, delta, inval_lines));
620 match cursor.mode {
621 CursorMode::Normal(_) | CursorMode::Visual { .. } => {
622 let offset = selection.min_offset();
623 let offset = if cursor.is_visual() {
624 offset + 1
625 } else {
626 offset
627 };
628 let line = buffer.line_of_offset(offset);
629 let offset = buffer.first_non_blank_character_on_line(line);
630 cursor.mode = CursorMode::Normal(offset);
631 }
632 CursorMode::Insert(_) => {
633 cursor.mode = CursorMode::Insert(selection);
634 }
635 }
636 }
637 }
638 deltas
639 }
640
641 fn do_indent(buffer: &mut Buffer, selection: Selection) -> (Rope, RopeDelta, InvalLines) {
642 let indent = buffer.indent_unit();
643 let mut edits = Vec::new();
644
645 let mut lines = HashSet::new();
646 for region in selection.regions() {
647 let start_line = buffer.line_of_offset(region.min());
648 let mut end_line = buffer.line_of_offset(region.max());
649 if end_line > start_line {
650 let end_line_start = buffer.offset_of_line(end_line);
651 if end_line_start == region.max() {
652 end_line -= 1;
653 }
654 }
655 for line in start_line..=end_line {
656 if lines.insert(line) {
657 let line_content = buffer.line_content(line);
658 if line_content == "\n" || line_content == "\r\n" {
659 continue;
660 }
661 let nonblank = buffer.first_non_blank_character_on_line(line);
662 let edit = crate::indent::create_edit(buffer, nonblank, indent);
663 edits.push(edit);
664 }
665 }
666 }
667
668 buffer.edit(&edits, EditType::Indent)
669 }
670
671 fn do_outdent(buffer: &mut Buffer, selection: Selection) -> (Rope, RopeDelta, InvalLines) {
672 let indent = buffer.indent_unit();
673 let mut edits = Vec::new();
674
675 let mut lines = HashSet::new();
676 for region in selection.regions() {
677 let start_line = buffer.line_of_offset(region.min());
678 let mut end_line = buffer.line_of_offset(region.max());
679 if end_line > start_line {
680 let end_line_start = buffer.offset_of_line(end_line);
681 if end_line_start == region.max() {
682 end_line -= 1;
683 }
684 }
685 for line in start_line..=end_line {
686 if lines.insert(line) {
687 let line_content = buffer.line_content(line);
688 if line_content == "\n" || line_content == "\r\n" {
689 continue;
690 }
691 let nonblank = buffer.first_non_blank_character_on_line(line);
692 if let Some(edit) = crate::indent::create_outdent(buffer, nonblank, indent) {
693 edits.push(edit);
694 }
695 }
696 }
697 }
698
699 buffer.edit(&edits, EditType::Outdent)
700 }
701
702 fn duplicate_line(
703 cursor: &mut Cursor,
704 buffer: &mut Buffer,
705 direction: DuplicateDirection,
706 ) -> Vec<(Rope, RopeDelta, InvalLines)> {
707 let selection = match cursor.mode {
709 CursorMode::Insert(ref mut sel) => sel,
710 _ => return vec![],
711 };
712
713 let mut line_ranges = HashSet::new();
714 for region in selection.regions_mut() {
715 let start_line = buffer.line_of_offset(region.start);
716 let end_line = buffer.line_of_offset(region.end) + 1;
717
718 line_ranges.insert(start_line..end_line);
719 }
720
721 let mut edits = vec![];
722 for range in line_ranges {
723 let start = buffer.offset_of_line(range.start);
724 let end = buffer.offset_of_line(range.end);
725
726 let content = buffer.slice_to_cow(start..end).into_owned();
727 edits.push((
728 match direction {
729 DuplicateDirection::Up => Selection::caret(end),
730 DuplicateDirection::Down => Selection::caret(start),
731 },
732 content,
733 ));
734 }
735
736 let edits = edits
737 .iter()
738 .map(|(sel, content)| (sel, content.as_str()))
739 .collect::<Vec<_>>();
740
741 let (text, delta, inval_lines) = buffer.edit(&edits, EditType::InsertChars);
742
743 *selection = selection.apply_delta(&delta, true, InsertDrift::Default);
744
745 vec![(text, delta, inval_lines)]
746 }
747
748 #[allow(clippy::too_many_arguments)]
749 pub fn do_edit<T: Clipboard>(
750 cursor: &mut Cursor,
751 buffer: &mut Buffer,
752 cmd: &EditCommand,
753 clipboard: &mut T,
754 register: &mut Register,
755 EditConf {
756 comment_token,
757 modal,
758 smart_tab,
759 keep_indent,
760 auto_indent,
761 }: EditConf,
762 ) -> Vec<(Rope, RopeDelta, InvalLines)> {
763 use crate::command::EditCommand::*;
764 match cmd {
765 MoveLineUp => {
766 let mut deltas = Vec::new();
767 if let CursorMode::Insert(mut selection) = cursor.mode.clone() {
768 for region in selection.regions_mut() {
769 let start_line = buffer.line_of_offset(region.min());
770 if start_line > 0 {
771 let previous_line_len = buffer.line_content(start_line - 1).len();
772
773 let end_line = buffer.line_of_offset(region.max());
774 let start = buffer.offset_of_line(start_line);
775 let end = buffer.offset_of_line(end_line + 1);
776 let content = buffer.slice_to_cow(start..end).to_string();
777 let (text, delta, inval_lines) = buffer.edit(
778 [
779 (&Selection::region(start, end), ""),
780 (
781 &Selection::caret(buffer.offset_of_line(start_line - 1)),
782 &content,
783 ),
784 ],
785 EditType::MoveLine,
786 );
787 deltas.push((text, delta, inval_lines));
788 region.start -= previous_line_len;
789 region.end -= previous_line_len;
790 }
791 }
792 cursor.mode = CursorMode::Insert(selection);
793 }
794 deltas
795 }
796 MoveLineDown => {
797 let mut deltas = Vec::new();
798 if let CursorMode::Insert(mut selection) = cursor.mode.clone() {
799 for region in selection.regions_mut().iter_mut().rev() {
800 let last_line = buffer.last_line();
801 let start_line = buffer.line_of_offset(region.min());
802 let end_line = buffer.line_of_offset(region.max());
803 if end_line < last_line {
804 let next_line_len = buffer.line_content(end_line + 1).len();
805
806 let start = buffer.offset_of_line(start_line);
807 let end = buffer.offset_of_line(end_line + 1);
808 let content = buffer.slice_to_cow(start..end).to_string();
809 let (text, delta, inval_lines) = buffer.edit(
810 [
811 (
812 &Selection::caret(buffer.offset_of_line(end_line + 2)),
813 content.as_str(),
814 ),
815 (&Selection::region(start, end), ""),
816 ],
817 EditType::MoveLine,
818 );
819 deltas.push((text, delta, inval_lines));
820 region.start += next_line_len;
821 region.end += next_line_len;
822 }
823 }
824 cursor.mode = CursorMode::Insert(selection);
825 }
826 deltas
827 }
828 InsertNewLine => match cursor.mode.clone() {
829 CursorMode::Normal(offset) => Self::insert_new_line(
830 buffer,
831 cursor,
832 Selection::caret(offset),
833 keep_indent,
834 auto_indent,
835 ),
836 CursorMode::Insert(selection) => {
837 Self::insert_new_line(buffer, cursor, selection, keep_indent, auto_indent)
838 }
839 CursorMode::Visual {
840 start: _,
841 end: _,
842 mode: _,
843 } => {
844 vec![]
845 }
846 },
847 InsertTab => {
848 let mut deltas = Vec::new();
849 if let CursorMode::Insert(selection) = &cursor.mode {
850 if smart_tab {
851 let indent = buffer.indent_unit();
852 let mut edits = Vec::new();
853
854 for region in selection.regions() {
855 if region.is_caret() {
856 edits.push(crate::indent::create_edit(buffer, region.start, indent))
857 } else {
858 let start_line = buffer.line_of_offset(region.min());
859 let end_line = buffer.line_of_offset(region.max());
860 for line in start_line..=end_line {
861 let offset = buffer.first_non_blank_character_on_line(line);
862 edits.push(crate::indent::create_edit(buffer, offset, indent))
863 }
864 }
865 }
866
867 let (text, delta, inval_lines) = buffer.edit(&edits, EditType::InsertChars);
868 let selection = selection.apply_delta(&delta, true, InsertDrift::Default);
869 deltas.push((text, delta, inval_lines));
870 cursor.mode = CursorMode::Insert(selection);
871 } else {
872 let (text, delta, inval_lines) =
873 buffer.edit([(&selection, "\t")], EditType::InsertChars);
874 let selection = selection.apply_delta(&delta, true, InsertDrift::Default);
875 deltas.push((text, delta, inval_lines));
876 cursor.mode = CursorMode::Insert(selection);
877 }
878 }
879 deltas
880 }
881 IndentLine => {
882 let selection = cursor.edit_selection(buffer);
883 let (text, delta, inval_lines) = Self::do_indent(buffer, selection);
884 cursor.apply_delta(&delta);
885 vec![(text, delta, inval_lines)]
886 }
887 JoinLines => {
888 let offset = cursor.offset();
889 let (line, _col) = buffer.offset_to_line_col(offset);
890 if line < buffer.last_line() {
891 let start = buffer.line_end_offset(line, true);
892 let end = buffer.first_non_blank_character_on_line(line + 1);
893 vec![buffer.edit([(&Selection::region(start, end), " ")], EditType::Other)]
894 } else {
895 vec![]
896 }
897 }
898 OutdentLine => {
899 let selection = cursor.edit_selection(buffer);
900 let (text, delta, inval_lines) = Self::do_outdent(buffer, selection);
901 cursor.apply_delta(&delta);
902 vec![(text, delta, inval_lines)]
903 }
904 ToggleLineComment => {
905 let mut lines = HashSet::new();
906 let selection = cursor.edit_selection(buffer);
907 let mut had_comment = true;
908 let mut smallest_indent = usize::MAX;
909 for region in selection.regions() {
910 let mut line = buffer.line_of_offset(region.min());
911 let end_line = buffer.line_of_offset(region.max());
912 let end_line_offset = buffer.offset_of_line(end_line);
913 let end = if end_line > line && region.max() == end_line_offset {
914 end_line_offset
915 } else {
916 buffer.offset_of_line(end_line + 1)
917 };
918 let start = buffer.offset_of_line(line);
919 for content in buffer.text().lines(start..end) {
920 let trimmed_content = content.trim_start();
921 if trimmed_content.is_empty() {
922 line += 1;
923 continue;
924 }
925 let indent = content.len() - trimmed_content.len();
926 if indent < smallest_indent {
927 smallest_indent = indent;
928 }
929 if !trimmed_content.starts_with(comment_token) {
930 had_comment = false;
931 lines.insert((line, indent, 0));
932 } else {
933 let had_space_after_comment =
934 trimmed_content.chars().nth(comment_token.len()) == Some(' ');
935 lines.insert((
936 line,
937 indent,
938 comment_token.len() + usize::from(had_space_after_comment),
939 ));
940 }
941 line += 1;
942 }
943 }
944
945 let (text, delta, inval_lines) = if had_comment {
946 let mut selection = Selection::new();
947 for (line, indent, len) in lines.iter() {
948 let start = buffer.offset_of_line(*line) + indent;
949 selection.add_region(SelRegion::new(start, start + len, None))
950 }
951 buffer.edit([(&selection, "")], EditType::ToggleComment)
952 } else {
953 let mut selection = Selection::new();
954 for (line, _, _) in lines.iter() {
955 let start = buffer.offset_of_line(*line) + smallest_indent;
956 selection.add_region(SelRegion::new(start, start, None))
957 }
958 buffer.edit(
959 [(&selection, format!("{comment_token} ").as_str())],
960 EditType::ToggleComment,
961 )
962 };
963 cursor.apply_delta(&delta);
964 vec![(text, delta, inval_lines)]
965 }
966 Undo => {
967 if let Some((text, delta, inval_lines, cursor_mode)) = buffer.do_undo() {
968 apply_undo_redo(cursor, buffer, modal, text, delta, inval_lines, cursor_mode)
969 } else {
970 vec![]
971 }
972 }
973 Redo => {
974 if let Some((text, delta, inval_lines, cursor_mode)) = buffer.do_redo() {
975 apply_undo_redo(cursor, buffer, modal, text, delta, inval_lines, cursor_mode)
976 } else {
977 vec![]
978 }
979 }
980 ClipboardCopy => {
981 let data = cursor.yank(buffer);
982 clipboard.put_string(data.content);
983
984 match &cursor.mode {
985 CursorMode::Visual {
986 start,
987 end,
988 mode: _,
989 } => {
990 let offset = *start.min(end);
991 let offset = buffer.offset_line_end(offset, false).min(offset);
992 cursor.mode = CursorMode::Normal(offset);
993 }
994 CursorMode::Normal(_) | CursorMode::Insert(_) => {}
995 }
996 vec![]
997 }
998 ClipboardCut => {
999 let data = cursor.yank(buffer);
1000 clipboard.put_string(data.content);
1001
1002 let selection = if let CursorMode::Insert(mut selection) = cursor.mode.clone() {
1003 for region in selection.regions_mut() {
1004 if region.is_caret() {
1005 let line = buffer.line_of_offset(region.start);
1006 let start = buffer.offset_of_line(line);
1007 let end = buffer.offset_of_line(line + 1);
1008 region.start = start;
1009 region.end = end;
1010 }
1011 }
1012 selection
1013 } else {
1014 cursor.edit_selection(buffer)
1015 };
1016
1017 let (text, delta, inval_lines) = buffer.edit([(&selection, "")], EditType::Cut);
1018 let selection = selection.apply_delta(&delta, true, InsertDrift::Default);
1019 cursor.update_selection(buffer, selection);
1020 vec![(text, delta, inval_lines)]
1021 }
1022 ClipboardPaste => {
1023 if let Some(s) = clipboard.get_string() {
1024 let mode = if s.ends_with('\n') {
1025 VisualMode::Linewise
1026 } else {
1027 VisualMode::Normal
1028 };
1029 let data = RegisterData { content: s, mode };
1030 Self::do_paste(cursor, buffer, &data)
1031 } else {
1032 vec![]
1033 }
1034 }
1035 Yank => {
1036 match &cursor.mode {
1037 CursorMode::Visual { start, end, .. } => {
1038 let data = cursor.yank(buffer);
1039 register.add_yank(data);
1040
1041 let offset = *start.min(end);
1042 let offset = buffer.offset_line_end(offset, false).min(offset);
1043 cursor.mode = CursorMode::Normal(offset);
1044 }
1045 CursorMode::Normal(_) => {}
1046 CursorMode::Insert(_) => {}
1047 }
1048 vec![]
1049 }
1050 Paste => {
1051 let data = register.unnamed.clone();
1052 Self::do_paste(cursor, buffer, &data)
1053 }
1054 PasteBefore => {
1055 let offset = cursor.offset();
1056 let data = register.unnamed.clone();
1057 let mut local_cursor =
1058 Cursor::new(CursorMode::Insert(Selection::new()), None, None);
1059 local_cursor.set_offset(offset, false, false);
1060 Self::do_paste(&mut local_cursor, buffer, &data)
1061 }
1062 NewLineAbove => {
1063 let offset = cursor.offset();
1064 let line = buffer.line_of_offset(offset);
1065 let offset = if line > 0 {
1066 buffer.line_end_offset(line - 1, true)
1067 } else {
1068 buffer.first_non_blank_character_on_line(line)
1069 };
1070 let delta = Self::insert_new_line(
1071 buffer,
1072 cursor,
1073 Selection::caret(offset),
1074 keep_indent,
1075 auto_indent,
1076 );
1077 if line == 0 {
1078 cursor.mode = CursorMode::Insert(Selection::caret(offset));
1079 }
1080 delta
1081 }
1082 NewLineBelow => {
1083 let offset = cursor.offset();
1084 let offset = buffer.offset_line_end(offset, true);
1085 Self::insert_new_line(
1086 buffer,
1087 cursor,
1088 Selection::caret(offset),
1089 keep_indent,
1090 auto_indent,
1091 )
1092 }
1093 DeleteBackward => {
1094 let (selection, edit_type) = match cursor.mode {
1095 CursorMode::Normal(_) => (cursor.edit_selection(buffer), EditType::Delete),
1096 CursorMode::Visual { .. } => {
1097 (cursor.edit_selection(buffer), EditType::DeleteSelection)
1098 }
1099 CursorMode::Insert(_) => {
1100 let selection = cursor.edit_selection(buffer);
1101 let edit_type = if selection.is_caret() {
1102 EditType::Delete
1103 } else {
1104 EditType::DeleteSelection
1105 };
1106 let indent = buffer.indent_unit();
1107 let mut new_selection = Selection::new();
1108 for region in selection.regions() {
1109 let new_region = if region.is_caret() {
1110 if indent.starts_with('\t') {
1111 let new_end = buffer.move_left(region.end, Mode::Insert, 1);
1112 SelRegion::new(region.start, new_end, None)
1113 } else {
1114 let line = buffer.line_of_offset(region.start);
1115 let nonblank = buffer.first_non_blank_character_on_line(line);
1116 let (_, col) = buffer.offset_to_line_col(region.start);
1117 let count = if region.start <= nonblank && col > 0 {
1118 let r = col % indent.len();
1119 if r == 0 {
1120 indent.len()
1121 } else {
1122 r
1123 }
1124 } else {
1125 1
1126 };
1127 let new_end = buffer.move_left(region.end, Mode::Insert, count);
1128 SelRegion::new(region.start, new_end, None)
1129 }
1130 } else {
1131 *region
1132 };
1133 new_selection.add_region(new_region);
1134 }
1135
1136 let mut selection = new_selection;
1137 if selection.regions().len() == 1 {
1138 let delete_str = buffer
1139 .slice_to_cow(selection.min_offset()..selection.max_offset())
1140 .to_string();
1141 if str_is_pair_left(&delete_str)
1142 || delete_str == "\""
1143 || delete_str == "'"
1144 || delete_str == "`"
1145 {
1146 let matching_char = match delete_str.as_str() {
1147 "\"" => Some('"'),
1148 "'" => Some('\''),
1149 "`" => Some('`'),
1150 _ => str_matching_pair(&delete_str),
1151 };
1152 if let Some(c) = matching_char {
1153 let offset = selection.max_offset();
1154 let line = buffer.line_of_offset(offset);
1155 let line_end = buffer.line_end_offset(line, true);
1156 let content = buffer.slice_to_cow(offset..line_end).to_string();
1157 if content.trim().starts_with(&c.to_string()) {
1158 let index = content.match_indices(c).next().unwrap().0;
1159 selection = Selection::region(
1160 selection.min_offset(),
1161 offset + index + 1,
1162 );
1163 }
1164 }
1165 }
1166 }
1167 (selection, edit_type)
1168 }
1169 };
1170 let (text, delta, inval_lines) = buffer.edit([(&selection, "")], edit_type);
1171 let selection = selection.apply_delta(&delta, true, InsertDrift::Default);
1172 cursor.update_selection(buffer, selection);
1173 vec![(text, delta, inval_lines)]
1174 }
1175 DeleteForward => {
1176 let (selection, edit_type) = match cursor.mode {
1177 CursorMode::Normal(_) => (cursor.edit_selection(buffer), EditType::Delete),
1178 CursorMode::Visual { .. } => {
1179 (cursor.edit_selection(buffer), EditType::DeleteSelection)
1180 }
1181 CursorMode::Insert(_) => {
1182 let selection = cursor.edit_selection(buffer);
1183 let edit_type = if selection.is_caret() {
1184 EditType::Delete
1185 } else {
1186 EditType::DeleteSelection
1187 };
1188 let mut new_selection = Selection::new();
1189 for region in selection.regions() {
1190 let new_region = if region.is_caret() {
1191 let new_end = buffer.move_right(region.end, Mode::Insert, 1);
1192 SelRegion::new(region.start, new_end, None)
1193 } else {
1194 *region
1195 };
1196 new_selection.add_region(new_region);
1197 }
1198 (new_selection, edit_type)
1199 }
1200 };
1201 let (text, delta, inval_lines) = buffer.edit([(&selection, "")], edit_type);
1202 let selection = selection.apply_delta(&delta, true, InsertDrift::Default);
1203 cursor.update_selection(buffer, selection);
1204 vec![(text, delta, inval_lines)]
1205 }
1206 DeleteLine => {
1207 let selection = cursor.edit_selection(buffer);
1208 let range = format_start_end(
1209 buffer,
1210 selection.min_offset()..selection.max_offset(),
1211 true,
1212 false,
1213 1,
1214 );
1215 let selection = Selection::region(range.start, range.end);
1216 let (text, delta, inval_lines) = buffer.edit([(&selection, "")], EditType::Delete);
1217 let selection = selection.apply_delta(&delta, true, InsertDrift::Default);
1218 cursor.mode = CursorMode::Insert(selection);
1219 vec![(text, delta, inval_lines)]
1220 }
1221 DeleteWordForward => {
1222 let selection = match cursor.mode {
1223 CursorMode::Normal(_) | CursorMode::Visual { .. } => {
1224 cursor.edit_selection(buffer)
1225 }
1226 CursorMode::Insert(_) => {
1227 let mut new_selection = Selection::new();
1228 let selection = cursor.edit_selection(buffer);
1229
1230 for region in selection.regions() {
1231 let end = buffer.move_word_forward(region.end);
1232 let new_region = SelRegion::new(region.start, end, None);
1233 new_selection.add_region(new_region);
1234 }
1235
1236 new_selection
1237 }
1238 };
1239 let (text, delta, inval_lines) =
1240 buffer.edit([(&selection, "")], EditType::DeleteWord);
1241 let selection = selection.apply_delta(&delta, true, InsertDrift::Default);
1242 cursor.update_selection(buffer, selection);
1243 vec![(text, delta, inval_lines)]
1244 }
1245 DeleteWordBackward => {
1246 let selection = match cursor.mode {
1247 CursorMode::Normal(_) | CursorMode::Visual { .. } => {
1248 cursor.edit_selection(buffer)
1249 }
1250 CursorMode::Insert(_) => {
1251 let mut new_selection = Selection::new();
1252 let selection = cursor.edit_selection(buffer);
1253
1254 for region in selection.regions() {
1255 let end = buffer.move_word_backward_deletion(region.end);
1256 let new_region = SelRegion::new(region.start, end, None);
1257 new_selection.add_region(new_region);
1258 }
1259
1260 new_selection
1261 }
1262 };
1263 let (text, delta, inval_lines) =
1264 buffer.edit([(&selection, "")], EditType::DeleteWord);
1265 let selection = selection.apply_delta(&delta, true, InsertDrift::Default);
1266 cursor.update_selection(buffer, selection);
1267 vec![(text, delta, inval_lines)]
1268 }
1269 DeleteToBeginningOfLine => {
1270 let selection = match cursor.mode {
1271 CursorMode::Normal(_) | CursorMode::Visual { .. } => {
1272 cursor.edit_selection(buffer)
1273 }
1274 CursorMode::Insert(_) => {
1275 let selection = cursor.edit_selection(buffer);
1276
1277 let mut new_selection = Selection::new();
1278 for region in selection.regions() {
1279 let line = buffer.line_of_offset(region.end);
1280 let end = buffer.offset_of_line(line);
1281 let new_region = SelRegion::new(region.start, end, None);
1282 new_selection.add_region(new_region);
1283 }
1284
1285 new_selection
1286 }
1287 };
1288 let (text, delta, inval_lines) =
1289 buffer.edit([(&selection, "")], EditType::DeleteToBeginningOfLine);
1290 let selection = selection.apply_delta(&delta, true, InsertDrift::Default);
1291 cursor.update_selection(buffer, selection);
1292 vec![(text, delta, inval_lines)]
1293 }
1294 DeleteToEndOfLine => {
1295 let selection = match cursor.mode {
1296 CursorMode::Normal(_) | CursorMode::Visual { .. } => {
1297 cursor.edit_selection(buffer)
1298 }
1299 CursorMode::Insert(_) => {
1300 let mut selection = cursor.edit_selection(buffer);
1301
1302 let cursor_offset = cursor.offset();
1303 let line = buffer.line_of_offset(cursor_offset);
1304 let end_of_line_offset = buffer.line_end_offset(line, true);
1305 let new_region = SelRegion::new(cursor_offset, end_of_line_offset, None);
1306 selection.add_region(new_region);
1307
1308 selection
1309 }
1310 };
1311 let (text, delta, inval_lines) =
1312 buffer.edit([(&selection, "")], EditType::DeleteToEndOfLine);
1313 let selection = selection.apply_delta(&delta, true, InsertDrift::Default);
1314 cursor.update_selection(buffer, selection);
1315 vec![(text, delta, inval_lines)]
1316 }
1317 DeleteForwardAndInsert => {
1318 let selection = cursor.edit_selection(buffer);
1319 let (text, delta, inval_lines) = buffer.edit([(&selection, "")], EditType::Delete);
1320 let selection = selection.apply_delta(&delta, true, InsertDrift::Default);
1321 cursor.mode = CursorMode::Insert(selection);
1322 vec![(text, delta, inval_lines)]
1323 }
1324 DeleteWordAndInsert => {
1325 let selection = {
1326 let mut new_selection = Selection::new();
1327 let selection = cursor.edit_selection(buffer);
1328
1329 for region in selection.regions() {
1330 let end = buffer.move_word_forward(region.end);
1331 let new_region = SelRegion::new(region.start, end, None);
1332 new_selection.add_region(new_region);
1333 }
1334
1335 new_selection
1336 };
1337 let (text, delta, inval_lines) =
1338 buffer.edit([(&selection, "")], EditType::DeleteWord);
1339 let selection = selection.apply_delta(&delta, true, InsertDrift::Default);
1340 cursor.mode = CursorMode::Insert(selection);
1341 vec![(text, delta, inval_lines)]
1342 }
1343 DeleteLineAndInsert => {
1344 let selection = cursor.edit_selection(buffer);
1345 let range = format_start_end(
1346 buffer,
1347 selection.min_offset()..selection.max_offset(),
1348 true,
1349 true,
1350 1,
1351 );
1352 let selection = Selection::region(range.start, range.end - 1); let (text, delta, inval_lines) = buffer.edit([(&selection, "")], EditType::Delete);
1354 let selection = selection.apply_delta(&delta, true, InsertDrift::Default);
1355 cursor.mode = CursorMode::Insert(selection);
1356 vec![(text, delta, inval_lines)]
1357 }
1358 DeleteToEndOfLineAndInsert => {
1359 let mut selection = cursor.edit_selection(buffer);
1360
1361 let cursor_offset = cursor.offset();
1362 let line = buffer.line_of_offset(cursor_offset);
1363 let end_of_line_offset = buffer.line_end_offset(line, true);
1364
1365 let new_region = SelRegion::new(cursor_offset, end_of_line_offset, None);
1366 selection.add_region(new_region);
1367
1368 let (text, delta, inval_lines) = buffer.edit([(&selection, "")], EditType::Delete);
1369 let selection = selection.apply_delta(&delta, true, InsertDrift::Default);
1370 cursor.mode = CursorMode::Insert(selection);
1371 vec![(text, delta, inval_lines)]
1372 }
1373 NormalMode => {
1374 if !modal {
1375 if let CursorMode::Insert(selection) = &cursor.mode {
1376 match selection.regions().len() {
1377 i if i > 1 => {
1378 if let Some(region) = selection.last_inserted() {
1379 let new_selection = Selection::region(region.start, region.end);
1380 cursor.mode = CursorMode::Insert(new_selection);
1381 return vec![];
1382 }
1383 }
1384 1 => {
1385 let region = selection.regions()[0];
1386 if !region.is_caret() {
1387 let new_selection = Selection::caret(region.end);
1388 cursor.mode = CursorMode::Insert(new_selection);
1389 return vec![];
1390 }
1391 }
1392 _ => (),
1393 }
1394 }
1395
1396 return vec![];
1397 }
1398
1399 let offset = match &cursor.mode {
1400 CursorMode::Insert(selection) => {
1401 let offset = selection.min_offset();
1402 buffer.prev_grapheme_offset(
1403 offset,
1404 1,
1405 buffer.offset_of_line(buffer.line_of_offset(offset)),
1406 )
1407 }
1408 CursorMode::Visual { end, .. } => buffer.offset_line_end(*end, false).min(*end),
1409 CursorMode::Normal(offset) => *offset,
1410 };
1411
1412 buffer.reset_edit_type();
1413 cursor.mode = CursorMode::Normal(offset);
1414 cursor.horiz = None;
1415 vec![]
1416 }
1417 InsertMode => {
1418 cursor.mode = CursorMode::Insert(Selection::caret(cursor.offset()));
1419 vec![]
1420 }
1421 InsertFirstNonBlank => {
1422 match &cursor.mode {
1423 CursorMode::Normal(offset) => {
1424 let line = buffer.line_of_offset(*offset);
1425 let offset = buffer.first_non_blank_character_on_line(line);
1426 cursor.mode = CursorMode::Insert(Selection::caret(offset));
1427 }
1428 CursorMode::Visual { .. } => {
1429 let mut selection = Selection::new();
1430 for region in cursor.edit_selection(buffer).regions() {
1431 selection.add_region(SelRegion::caret(region.min()));
1432 }
1433 cursor.mode = CursorMode::Insert(selection);
1434 }
1435 CursorMode::Insert(_) => {}
1436 };
1437 vec![]
1438 }
1439 Append => {
1440 let offset = cursor.offset();
1441 let line = buffer.line_of_offset(offset);
1442 let line_len = buffer.line_len(line);
1443 let count = (line_len > 1 || (buffer.last_line() == line && line_len > 0)) as usize;
1444 let offset = buffer.move_right(cursor.offset(), Mode::Insert, count);
1445 cursor.mode = CursorMode::Insert(Selection::caret(offset));
1446 vec![]
1447 }
1448 AppendEndOfLine => {
1449 let offset = cursor.offset();
1450 let line = buffer.line_of_offset(offset);
1451 let offset = buffer.line_end_offset(line, true);
1452 cursor.mode = CursorMode::Insert(Selection::caret(offset));
1453 vec![]
1454 }
1455 ToggleVisualMode => {
1456 Self::toggle_visual(cursor, VisualMode::Normal, modal);
1457 vec![]
1458 }
1459 ToggleLinewiseVisualMode => {
1460 Self::toggle_visual(cursor, VisualMode::Linewise, modal);
1461 vec![]
1462 }
1463 ToggleBlockwiseVisualMode => {
1464 Self::toggle_visual(cursor, VisualMode::Blockwise, modal);
1465 vec![]
1466 }
1467 DuplicateLineUp => Self::duplicate_line(cursor, buffer, DuplicateDirection::Up),
1468 DuplicateLineDown => Self::duplicate_line(cursor, buffer, DuplicateDirection::Down),
1469 NormalizeLineEndings => {
1470 let Some((text, delta, inval)) = buffer.normalize_line_endings() else {
1471 return vec![];
1472 };
1473
1474 cursor.apply_delta(&delta);
1475
1476 vec![(text, delta, inval)]
1477 }
1478 }
1479 }
1480}
1481
1482fn apply_undo_redo(
1483 cursor: &mut Cursor,
1484 buffer: &mut Buffer,
1485 modal: bool,
1486 text: Rope,
1487 delta: RopeDelta,
1488 inval_lines: InvalLines,
1489 cursor_mode: Option<CursorMode>,
1490) -> Vec<(Rope, RopeDelta, InvalLines)> {
1491 if let Some(cursor_mode) = cursor_mode {
1492 cursor.mode = if modal {
1493 CursorMode::Normal(cursor_mode.offset())
1494 } else if cursor.is_insert() {
1495 cursor_mode
1496 } else {
1497 CursorMode::Insert(Selection::caret(cursor_mode.offset()))
1498 };
1499 } else if let Some(new_cursor) = get_first_selection_after(cursor, buffer, &delta) {
1500 *cursor = new_cursor
1501 } else if !delta
1502 .els
1503 .iter()
1504 .any(|el| matches!(el, DeltaElement::Copy(_, _)))
1505 {
1506 } else {
1509 cursor.apply_delta(&delta);
1510 }
1511 vec![(text, delta, inval_lines)]
1512}
1513
1514enum DuplicateDirection {
1515 Up,
1516 Down,
1517}
1518
1519#[cfg(test)]
1520mod test {
1521 use crate::{
1522 buffer::{rope_text::RopeText, Buffer},
1523 cursor::{Cursor, CursorMode},
1524 editor::{Action, DuplicateDirection},
1525 selection::{SelRegion, Selection},
1526 word::WordCursor,
1527 };
1528
1529 fn prev_unmatched(buffer: &Buffer, c: char, offset: usize) -> Option<usize> {
1530 WordCursor::new(buffer.text(), offset).previous_unmatched(c)
1531 }
1532
1533 #[test]
1534 fn test_insert_simple() {
1535 let mut buffer = Buffer::new("abc");
1536 let mut cursor = Cursor::new(CursorMode::Insert(Selection::caret(1)), None, None);
1537
1538 Action::insert(&mut cursor, &mut buffer, "e", &prev_unmatched, true, true);
1539 assert_eq!("aebc", buffer.slice_to_cow(0..buffer.len()));
1540 }
1541
1542 #[test]
1543 fn test_insert_multiple_cursor() {
1544 let mut buffer = Buffer::new("abc\nefg\n");
1545 let mut selection = Selection::new();
1546 selection.add_region(SelRegion::caret(1));
1547 selection.add_region(SelRegion::caret(5));
1548 let mut cursor = Cursor::new(CursorMode::Insert(selection), None, None);
1549
1550 Action::insert(&mut cursor, &mut buffer, "i", &prev_unmatched, true, true);
1551 assert_eq!("aibc\neifg\n", buffer.slice_to_cow(0..buffer.len()));
1552 }
1553
1554 #[test]
1555 fn test_insert_complex() {
1556 let mut buffer = Buffer::new("abc\nefg\n");
1557 let mut selection = Selection::new();
1558 selection.add_region(SelRegion::caret(1));
1559 selection.add_region(SelRegion::caret(5));
1560 let mut cursor = Cursor::new(CursorMode::Insert(selection), None, None);
1561
1562 Action::insert(&mut cursor, &mut buffer, "i", &prev_unmatched, true, true);
1563 assert_eq!("aibc\neifg\n", buffer.slice_to_cow(0..buffer.len()));
1564 Action::insert(&mut cursor, &mut buffer, "j", &prev_unmatched, true, true);
1565 assert_eq!("aijbc\neijfg\n", buffer.slice_to_cow(0..buffer.len()));
1566 Action::insert(&mut cursor, &mut buffer, "{", &prev_unmatched, true, true);
1567 assert_eq!("aij{bc\neij{fg\n", buffer.slice_to_cow(0..buffer.len()));
1568 Action::insert(&mut cursor, &mut buffer, " ", &prev_unmatched, true, true);
1569 assert_eq!("aij{ bc\neij{ fg\n", buffer.slice_to_cow(0..buffer.len()));
1570 }
1571
1572 #[test]
1573 fn test_insert_pair() {
1574 let mut buffer = Buffer::new("a bc\ne fg\n");
1575 let mut selection = Selection::new();
1576 selection.add_region(SelRegion::caret(1));
1577 selection.add_region(SelRegion::caret(6));
1578 let mut cursor = Cursor::new(CursorMode::Insert(selection), None, None);
1579
1580 Action::insert(&mut cursor, &mut buffer, "{", &prev_unmatched, true, true);
1581 assert_eq!("a{} bc\ne{} fg\n", buffer.slice_to_cow(0..buffer.len()));
1582 Action::insert(&mut cursor, &mut buffer, "}", &prev_unmatched, true, true);
1583 assert_eq!("a{} bc\ne{} fg\n", buffer.slice_to_cow(0..buffer.len()));
1584 }
1585
1586 #[test]
1587 fn test_insert_pair_with_selection() {
1588 let mut buffer = Buffer::new("a bc\ne fg\n");
1589 let mut selection = Selection::new();
1590 selection.add_region(SelRegion::new(0, 4, None));
1591 selection.add_region(SelRegion::new(5, 9, None));
1592 let mut cursor = Cursor::new(CursorMode::Insert(selection), None, None);
1593 Action::insert(&mut cursor, &mut buffer, "{", &prev_unmatched, true, true);
1594 assert_eq!("{a bc}\n{e fg}\n", buffer.slice_to_cow(0..buffer.len()));
1595 }
1596
1597 #[test]
1598 fn test_insert_pair_without_auto_closing() {
1599 let mut buffer = Buffer::new("a bc\ne fg\n");
1600 let mut selection = Selection::new();
1601 selection.add_region(SelRegion::caret(1));
1602 selection.add_region(SelRegion::caret(6));
1603 let mut cursor = Cursor::new(CursorMode::Insert(selection), None, None);
1604
1605 Action::insert(&mut cursor, &mut buffer, "{", &prev_unmatched, false, false);
1606 assert_eq!("a{ bc\ne{ fg\n", buffer.slice_to_cow(0..buffer.len()));
1607 Action::insert(&mut cursor, &mut buffer, "}", &prev_unmatched, false, false);
1608 assert_eq!("a{} bc\ne{} fg\n", buffer.slice_to_cow(0..buffer.len()));
1609 }
1610
1611 #[test]
1612 fn duplicate_down_simple() {
1613 let mut buffer = Buffer::new("first line\nsecond line\n");
1614 let mut selection = Selection::new();
1615 selection.add_region(SelRegion::caret(0));
1616 let mut cursor = Cursor::new(CursorMode::Insert(selection), None, None);
1617
1618 Action::duplicate_line(&mut cursor, &mut buffer, DuplicateDirection::Down);
1619
1620 assert_ne!(cursor.offset(), 0);
1621 assert_eq!(
1622 "first line\nfirst line\nsecond line\n",
1623 buffer.slice_to_cow(0..buffer.len())
1624 );
1625 }
1626
1627 #[test]
1628 fn duplicate_up_simple() {
1629 let mut buffer = Buffer::new("first line\nsecond line\n");
1630 let mut selection = Selection::new();
1631 selection.add_region(SelRegion::caret(0));
1632 let mut cursor = Cursor::new(CursorMode::Insert(selection), None, None);
1633
1634 Action::duplicate_line(&mut cursor, &mut buffer, DuplicateDirection::Up);
1635
1636 assert_eq!(cursor.offset(), 0);
1637 assert_eq!(
1638 "first line\nfirst line\nsecond line\n",
1639 buffer.slice_to_cow(0..buffer.len())
1640 );
1641 }
1642
1643 #[test]
1644 fn duplicate_down_multiple_cursors_in_same_line() {
1645 let mut buffer = Buffer::new("first line\nsecond line\n");
1646 let mut selection = Selection::new();
1647 selection.add_region(SelRegion::caret(0));
1648 selection.add_region(SelRegion::caret(1));
1649 let mut cursor = Cursor::new(CursorMode::Insert(selection), None, None);
1650
1651 Action::duplicate_line(&mut cursor, &mut buffer, DuplicateDirection::Down);
1652
1653 assert_eq!(
1654 "first line\nfirst line\nsecond line\n",
1655 buffer.slice_to_cow(0..buffer.len())
1656 );
1657 }
1658
1659 #[test]
1660 fn duplicate_up_multiple_cursors_in_same_line() {
1661 let mut buffer = Buffer::new("first line\nsecond line\n");
1662 let mut selection = Selection::new();
1663 selection.add_region(SelRegion::caret(0));
1664 selection.add_region(SelRegion::caret(1));
1665 let mut cursor = Cursor::new(CursorMode::Insert(selection), None, None);
1666
1667 Action::duplicate_line(&mut cursor, &mut buffer, DuplicateDirection::Up);
1668
1669 assert_eq!(
1670 "first line\nfirst line\nsecond line\n",
1671 buffer.slice_to_cow(0..buffer.len())
1672 );
1673 }
1674
1675 #[test]
1676 fn duplicate_down_multiple() {
1677 let mut buffer = Buffer::new("first line\nsecond line\n");
1678 let mut selection = Selection::new();
1679 selection.add_region(SelRegion::caret(0));
1680 selection.add_region(SelRegion::caret(15));
1681 let mut cursor = Cursor::new(CursorMode::Insert(selection), None, None);
1682
1683 Action::duplicate_line(&mut cursor, &mut buffer, DuplicateDirection::Down);
1684
1685 assert_eq!(
1686 "first line\nfirst line\nsecond line\nsecond line\n",
1687 buffer.slice_to_cow(0..buffer.len())
1688 );
1689 }
1690
1691 #[test]
1692 fn duplicate_up_multiple() {
1693 let mut buffer = Buffer::new("first line\nsecond line\n");
1694 let mut selection = Selection::new();
1695 selection.add_region(SelRegion::caret(0));
1696 selection.add_region(SelRegion::caret(15));
1697 let mut cursor = Cursor::new(CursorMode::Insert(selection), None, None);
1698
1699 Action::duplicate_line(&mut cursor, &mut buffer, DuplicateDirection::Up);
1700
1701 assert_eq!(
1702 "first line\nfirst line\nsecond line\nsecond line\n",
1703 buffer.slice_to_cow(0..buffer.len())
1704 );
1705 }
1706
1707 #[test]
1708 fn duplicate_down_multiple_with_swapped_cursor_order() {
1709 let mut buffer = Buffer::new("first line\nsecond line\n");
1710 let mut selection = Selection::new();
1711 selection.add_region(SelRegion::caret(15));
1712 selection.add_region(SelRegion::caret(0));
1713 let mut cursor = Cursor::new(CursorMode::Insert(selection), None, None);
1714
1715 Action::duplicate_line(&mut cursor, &mut buffer, DuplicateDirection::Down);
1716
1717 assert_eq!(
1718 "first line\nfirst line\nsecond line\nsecond line\n",
1719 buffer.slice_to_cow(0..buffer.len())
1720 );
1721 }
1722
1723 #[test]
1724 fn duplicate_up_multiple_with_swapped_cursor_order() {
1725 let mut buffer = Buffer::new("first line\nsecond line\n");
1726 let mut selection = Selection::new();
1727 selection.add_region(SelRegion::caret(15));
1728 selection.add_region(SelRegion::caret(0));
1729 let mut cursor = Cursor::new(CursorMode::Insert(selection), None, None);
1730
1731 Action::duplicate_line(&mut cursor, &mut buffer, DuplicateDirection::Up);
1732
1733 assert_eq!(
1734 "first line\nfirst line\nsecond line\nsecond line\n",
1735 buffer.slice_to_cow(0..buffer.len())
1736 );
1737 }
1738
1739 #[test]
1740 fn check_multiple_cursor_match_insertion() {
1741 let mut buffer = Buffer::new(" 123 567 9ab def");
1742 let mut selection = Selection::new();
1743 selection.add_region(SelRegion::caret(0));
1744 selection.add_region(SelRegion::caret(4));
1745 selection.add_region(SelRegion::caret(8));
1746 selection.add_region(SelRegion::caret(12));
1747 let mut cursor = Cursor::new(CursorMode::Insert(selection), None, None);
1748
1749 Action::insert(&mut cursor, &mut buffer, "(", &prev_unmatched, true, true);
1750
1751 assert_eq!(
1752 "() 123() 567() 9ab() def",
1753 buffer.slice_to_cow(0..buffer.len())
1754 );
1755
1756 let mut end_selection = Selection::new();
1757 end_selection.add_region(SelRegion::caret(1));
1758 end_selection.add_region(SelRegion::caret(7));
1759 end_selection.add_region(SelRegion::caret(13));
1760 end_selection.add_region(SelRegion::caret(19));
1761 assert_eq!(cursor.mode, CursorMode::Insert(end_selection));
1762 }
1763
1764 }