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 == '\'')
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 _ => matching_char(c).unwrap(),
139 },
140 ));
141 continue;
142 }
143
144 if auto_closing_matching_pairs {
145 if (c == '"' || c == '\'') && cursor_char == Some(c) {
146 let new_offset = buffer.next_grapheme_offset(offset, 1, buffer.len());
148
149 *region = SelRegion::caret(new_offset);
150 continue;
151 }
152
153 if matching_pair_type == Some(false) {
154 if cursor_char == Some(c) {
155 let new_offset =
157 buffer.next_grapheme_offset(offset, 1, buffer.len());
158
159 *region = SelRegion::caret(new_offset);
160 continue;
161 }
162
163 let line = buffer.line_of_offset(offset);
164 let line_start = buffer.offset_of_line(line);
165 if buffer.slice_to_cow(line_start..offset).trim() == "" {
166 let opening_character = matching_char(c).unwrap();
167 if let Some(previous_offset) =
168 prev_unmatched(buffer, opening_character, offset)
169 {
170 let previous_line = buffer.line_of_offset(previous_offset);
172 let line_indent = buffer.indent_on_line(previous_line);
173
174 let current_selection = Selection::region(line_start, offset);
175
176 edits.push((current_selection, format!("{line_indent}{c}")));
177 continue;
178 }
179 }
180 }
181
182 if matching_pair_type == Some(true) || c == '"' || c == '\'' {
183 let is_whitespace_or_punct = cursor_char
185 .map(|c| {
186 let prop = get_char_property(c);
187 prop == CharClassification::Lf
188 || prop == CharClassification::Space
189 || prop == CharClassification::Punctuation
190 })
191 .unwrap_or(true);
192
193 let should_insert_pair = match c {
194 '"' | '\'' => {
195 is_whitespace_or_punct
196 && prev_cursor_char
197 .map(|c| {
198 let prop = get_char_property(c);
199 prop == CharClassification::Lf
200 || prop == CharClassification::Space
201 || prop == CharClassification::Punctuation
202 })
203 .unwrap_or(true)
204 }
205 _ => is_whitespace_or_punct,
206 };
207
208 if should_insert_pair {
209 let insert_after = match c {
210 '"' => '"',
211 '\'' => '\'',
212 _ => matching_char(c).unwrap(),
213 };
214 edits_after.push((idx, insert_after));
215 }
216 };
217 }
218
219 let current_selection = Selection::region(region.start, region.end);
220
221 edits.push((current_selection, c.to_string()));
222 }
223
224 let edits = edits
226 .iter()
227 .map(|(selection, content)| (selection, content.as_str()))
228 .collect::<Vec<_>>();
229
230 let (text, delta, inval_lines) = buffer.edit(&edits, EditType::InsertChars);
231
232 buffer.set_cursor_before(CursorMode::Insert(selection.clone()));
233
234 let mut selection = selection.apply_delta(&delta, true, InsertDrift::Default);
236
237 buffer.set_cursor_after(CursorMode::Insert(selection.clone()));
238
239 deltas.push((text, delta, inval_lines));
240 let edits_after = edits_after
242 .iter()
243 .map(|(idx, content)| {
244 let region = &selection.regions()[*idx];
245 (
246 Selection::region(region.max(), region.max()),
247 content.to_string(),
248 )
249 })
250 .collect::<Vec<_>>();
251
252 let edits_after = edits_after
253 .iter()
254 .map(|(selection, content)| (selection, content.as_str()))
255 .collect::<Vec<_>>();
256
257 if !edits_after.is_empty() {
258 let (text, delta, inval_lines) =
259 buffer.edit(&edits_after, EditType::InsertChars);
260 deltas.push((text, delta, inval_lines));
261 }
262
263 let mut adjustment = 0;
265 for region in selection
266 .regions_mut()
267 .iter_mut()
268 .sorted_by(|region_a, region_b| region_a.start.cmp(®ion_b.start))
269 {
270 let new_region =
271 SelRegion::new(region.start + adjustment, region.end + adjustment, None);
272
273 if let Some(inserted) = edits_after.iter().find_map(|(selection, str)| {
274 if selection.last_inserted().map(|r| r.start) == Some(region.start) {
275 Some(str)
276 } else {
277 None
278 }
279 }) {
280 adjustment += inserted.len();
281 }
282
283 *region = new_region;
284 }
285
286 cursor.mode = CursorMode::Insert(selection);
287 }
288 }
289 deltas
290 }
291
292 fn toggle_visual(cursor: &mut Cursor, visual_mode: VisualMode, modal: bool) {
293 if !modal {
294 return;
295 }
296
297 match &cursor.mode {
298 CursorMode::Visual { start, end, mode } => {
299 if mode != &visual_mode {
300 cursor.mode = CursorMode::Visual {
301 start: *start,
302 end: *end,
303 mode: visual_mode,
304 };
305 } else {
306 cursor.mode = CursorMode::Normal(*end);
307 };
308 }
309 _ => {
310 let offset = cursor.offset();
311 cursor.mode = CursorMode::Visual {
312 start: offset,
313 end: offset,
314 mode: visual_mode,
315 };
316 }
317 }
318 }
319
320 fn insert_new_line(
321 buffer: &mut Buffer,
322 cursor: &mut Cursor,
323 selection: Selection,
324 keep_indent: bool,
325 auto_indent: bool,
326 ) -> Vec<(Rope, RopeDelta, InvalLines)> {
327 let mut edits = Vec::with_capacity(selection.regions().len());
328 let mut extra_edits = Vec::new();
329 let mut shift = 0i32;
330 for region in selection.regions() {
331 let offset = region.max();
332 let line = buffer.line_of_offset(offset);
333 let line_start = buffer.offset_of_line(line);
334 let line_end = buffer.line_end_offset(line, true);
335 let line_indent = buffer.indent_on_line(line);
336 let first_half = buffer.slice_to_cow(line_start..offset);
337 let second_half = buffer.slice_to_cow(offset..line_end);
338 let second_half = second_half.trim();
339
340 let new_line_content = {
342 let indent_storage;
343 let indent = if auto_indent && has_unmatched_pair(&first_half) {
344 indent_storage = format!("{}{}", line_indent, buffer.indent_unit());
345 &indent_storage
346 } else if keep_indent && second_half.is_empty() {
347 indent_storage = buffer.indent_on_line(line + 1);
348 if indent_storage.len() > line_indent.len() {
349 &indent_storage
350 } else {
351 &line_indent
352 }
353 } else if keep_indent {
354 &line_indent
355 } else {
356 indent_storage = String::new();
357 &indent_storage
358 };
359 format!("\n{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.starts_with(c) {
373 let selection =
374 Selection::caret((region.max() as i32 + shift) as usize);
375 let content = format!("\n{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 {
1145 let matching_char = match delete_str.as_str() {
1146 "\"" => Some('"'),
1147 "'" => Some('\''),
1148 _ => str_matching_pair(&delete_str),
1149 };
1150 if let Some(c) = matching_char {
1151 let offset = selection.max_offset();
1152 let line = buffer.line_of_offset(offset);
1153 let line_end = buffer.line_end_offset(line, true);
1154 let content = buffer.slice_to_cow(offset..line_end).to_string();
1155 if content.trim().starts_with(&c.to_string()) {
1156 let index = content.match_indices(c).next().unwrap().0;
1157 selection = Selection::region(
1158 selection.min_offset(),
1159 offset + index + 1,
1160 );
1161 }
1162 }
1163 }
1164 }
1165 (selection, edit_type)
1166 }
1167 };
1168 let (text, delta, inval_lines) = buffer.edit([(&selection, "")], edit_type);
1169 let selection = selection.apply_delta(&delta, true, InsertDrift::Default);
1170 cursor.update_selection(buffer, selection);
1171 vec![(text, delta, inval_lines)]
1172 }
1173 DeleteForward => {
1174 let (selection, edit_type) = match cursor.mode {
1175 CursorMode::Normal(_) => (cursor.edit_selection(buffer), EditType::Delete),
1176 CursorMode::Visual { .. } => {
1177 (cursor.edit_selection(buffer), EditType::DeleteSelection)
1178 }
1179 CursorMode::Insert(_) => {
1180 let selection = cursor.edit_selection(buffer);
1181 let edit_type = if selection.is_caret() {
1182 EditType::Delete
1183 } else {
1184 EditType::DeleteSelection
1185 };
1186 let mut new_selection = Selection::new();
1187 for region in selection.regions() {
1188 let new_region = if region.is_caret() {
1189 let new_end = buffer.move_right(region.end, Mode::Insert, 1);
1190 SelRegion::new(region.start, new_end, None)
1191 } else {
1192 *region
1193 };
1194 new_selection.add_region(new_region);
1195 }
1196 (new_selection, edit_type)
1197 }
1198 };
1199 let (text, delta, inval_lines) = buffer.edit([(&selection, "")], edit_type);
1200 let selection = selection.apply_delta(&delta, true, InsertDrift::Default);
1201 cursor.update_selection(buffer, selection);
1202 vec![(text, delta, inval_lines)]
1203 }
1204 DeleteLine => {
1205 let selection = cursor.edit_selection(buffer);
1206 let range = format_start_end(
1207 buffer,
1208 selection.min_offset()..selection.max_offset(),
1209 true,
1210 false,
1211 1,
1212 );
1213 let selection = Selection::region(range.start, range.end);
1214 let (text, delta, inval_lines) = buffer.edit([(&selection, "")], EditType::Delete);
1215 let selection = selection.apply_delta(&delta, true, InsertDrift::Default);
1216 cursor.mode = CursorMode::Insert(selection);
1217 vec![(text, delta, inval_lines)]
1218 }
1219 DeleteWordForward => {
1220 let selection = match cursor.mode {
1221 CursorMode::Normal(_) | CursorMode::Visual { .. } => {
1222 cursor.edit_selection(buffer)
1223 }
1224 CursorMode::Insert(_) => {
1225 let mut new_selection = Selection::new();
1226 let selection = cursor.edit_selection(buffer);
1227
1228 for region in selection.regions() {
1229 let end = buffer.move_word_forward(region.end);
1230 let new_region = SelRegion::new(region.start, end, None);
1231 new_selection.add_region(new_region);
1232 }
1233
1234 new_selection
1235 }
1236 };
1237 let (text, delta, inval_lines) =
1238 buffer.edit([(&selection, "")], EditType::DeleteWord);
1239 let selection = selection.apply_delta(&delta, true, InsertDrift::Default);
1240 cursor.update_selection(buffer, selection);
1241 vec![(text, delta, inval_lines)]
1242 }
1243 DeleteWordBackward => {
1244 let selection = match cursor.mode {
1245 CursorMode::Normal(_) | CursorMode::Visual { .. } => {
1246 cursor.edit_selection(buffer)
1247 }
1248 CursorMode::Insert(_) => {
1249 let mut new_selection = Selection::new();
1250 let selection = cursor.edit_selection(buffer);
1251
1252 for region in selection.regions() {
1253 let end = buffer.move_word_backward_deletion(region.end);
1254 let new_region = SelRegion::new(region.start, end, None);
1255 new_selection.add_region(new_region);
1256 }
1257
1258 new_selection
1259 }
1260 };
1261 let (text, delta, inval_lines) =
1262 buffer.edit([(&selection, "")], EditType::DeleteWord);
1263 let selection = selection.apply_delta(&delta, true, InsertDrift::Default);
1264 cursor.update_selection(buffer, selection);
1265 vec![(text, delta, inval_lines)]
1266 }
1267 DeleteToBeginningOfLine => {
1268 let selection = match cursor.mode {
1269 CursorMode::Normal(_) | CursorMode::Visual { .. } => {
1270 cursor.edit_selection(buffer)
1271 }
1272 CursorMode::Insert(_) => {
1273 let selection = cursor.edit_selection(buffer);
1274
1275 let mut new_selection = Selection::new();
1276 for region in selection.regions() {
1277 let line = buffer.line_of_offset(region.end);
1278 let end = buffer.offset_of_line(line);
1279 let new_region = SelRegion::new(region.start, end, None);
1280 new_selection.add_region(new_region);
1281 }
1282
1283 new_selection
1284 }
1285 };
1286 let (text, delta, inval_lines) =
1287 buffer.edit([(&selection, "")], EditType::DeleteToBeginningOfLine);
1288 let selection = selection.apply_delta(&delta, true, InsertDrift::Default);
1289 cursor.update_selection(buffer, selection);
1290 vec![(text, delta, inval_lines)]
1291 }
1292 DeleteToEndOfLine => {
1293 let selection = match cursor.mode {
1294 CursorMode::Normal(_) | CursorMode::Visual { .. } => {
1295 cursor.edit_selection(buffer)
1296 }
1297 CursorMode::Insert(_) => {
1298 let mut selection = cursor.edit_selection(buffer);
1299
1300 let cursor_offset = cursor.offset();
1301 let line = buffer.line_of_offset(cursor_offset);
1302 let end_of_line_offset = buffer.line_end_offset(line, true);
1303 let new_region = SelRegion::new(cursor_offset, end_of_line_offset, None);
1304 selection.add_region(new_region);
1305
1306 selection
1307 }
1308 };
1309 let (text, delta, inval_lines) =
1310 buffer.edit([(&selection, "")], EditType::DeleteToEndOfLine);
1311 let selection = selection.apply_delta(&delta, true, InsertDrift::Default);
1312 cursor.update_selection(buffer, selection);
1313 vec![(text, delta, inval_lines)]
1314 }
1315 DeleteForwardAndInsert => {
1316 let selection = cursor.edit_selection(buffer);
1317 let (text, delta, inval_lines) = buffer.edit([(&selection, "")], EditType::Delete);
1318 let selection = selection.apply_delta(&delta, true, InsertDrift::Default);
1319 cursor.mode = CursorMode::Insert(selection);
1320 vec![(text, delta, inval_lines)]
1321 }
1322 DeleteWordAndInsert => {
1323 let selection = {
1324 let mut new_selection = Selection::new();
1325 let selection = cursor.edit_selection(buffer);
1326
1327 for region in selection.regions() {
1328 let end = buffer.move_word_forward(region.end);
1329 let new_region = SelRegion::new(region.start, end, None);
1330 new_selection.add_region(new_region);
1331 }
1332
1333 new_selection
1334 };
1335 let (text, delta, inval_lines) =
1336 buffer.edit([(&selection, "")], EditType::DeleteWord);
1337 let selection = selection.apply_delta(&delta, true, InsertDrift::Default);
1338 cursor.mode = CursorMode::Insert(selection);
1339 vec![(text, delta, inval_lines)]
1340 }
1341 DeleteLineAndInsert => {
1342 let selection = cursor.edit_selection(buffer);
1343 let range = format_start_end(
1344 buffer,
1345 selection.min_offset()..selection.max_offset(),
1346 true,
1347 true,
1348 1,
1349 );
1350 let selection = Selection::region(range.start, range.end - 1); let (text, delta, inval_lines) = buffer.edit([(&selection, "")], EditType::Delete);
1352 let selection = selection.apply_delta(&delta, true, InsertDrift::Default);
1353 cursor.mode = CursorMode::Insert(selection);
1354 vec![(text, delta, inval_lines)]
1355 }
1356 DeleteToEndOfLineAndInsert => {
1357 let mut selection = cursor.edit_selection(buffer);
1358
1359 let cursor_offset = cursor.offset();
1360 let line = buffer.line_of_offset(cursor_offset);
1361 let end_of_line_offset = buffer.line_end_offset(line, true);
1362
1363 let new_region = SelRegion::new(cursor_offset, end_of_line_offset, None);
1364 selection.add_region(new_region);
1365
1366 let (text, delta, inval_lines) = buffer.edit([(&selection, "")], EditType::Delete);
1367 let selection = selection.apply_delta(&delta, true, InsertDrift::Default);
1368 cursor.mode = CursorMode::Insert(selection);
1369 vec![(text, delta, inval_lines)]
1370 }
1371 NormalMode => {
1372 if !modal {
1373 if let CursorMode::Insert(selection) = &cursor.mode {
1374 match selection.regions().len() {
1375 i if i > 1 => {
1376 if let Some(region) = selection.last_inserted() {
1377 let new_selection = Selection::region(region.start, region.end);
1378 cursor.mode = CursorMode::Insert(new_selection);
1379 return vec![];
1380 }
1381 }
1382 1 => {
1383 let region = selection.regions()[0];
1384 if !region.is_caret() {
1385 let new_selection = Selection::caret(region.end);
1386 cursor.mode = CursorMode::Insert(new_selection);
1387 return vec![];
1388 }
1389 }
1390 _ => (),
1391 }
1392 }
1393
1394 return vec![];
1395 }
1396
1397 let offset = match &cursor.mode {
1398 CursorMode::Insert(selection) => {
1399 let offset = selection.min_offset();
1400 buffer.prev_grapheme_offset(
1401 offset,
1402 1,
1403 buffer.offset_of_line(buffer.line_of_offset(offset)),
1404 )
1405 }
1406 CursorMode::Visual { end, .. } => buffer.offset_line_end(*end, false).min(*end),
1407 CursorMode::Normal(offset) => *offset,
1408 };
1409
1410 buffer.reset_edit_type();
1411 cursor.mode = CursorMode::Normal(offset);
1412 cursor.horiz = None;
1413 vec![]
1414 }
1415 InsertMode => {
1416 cursor.mode = CursorMode::Insert(Selection::caret(cursor.offset()));
1417 vec![]
1418 }
1419 InsertFirstNonBlank => {
1420 match &cursor.mode {
1421 CursorMode::Normal(offset) => {
1422 let line = buffer.line_of_offset(*offset);
1423 let offset = buffer.first_non_blank_character_on_line(line);
1424 cursor.mode = CursorMode::Insert(Selection::caret(offset));
1425 }
1426 CursorMode::Visual { .. } => {
1427 let mut selection = Selection::new();
1428 for region in cursor.edit_selection(buffer).regions() {
1429 selection.add_region(SelRegion::caret(region.min()));
1430 }
1431 cursor.mode = CursorMode::Insert(selection);
1432 }
1433 CursorMode::Insert(_) => {}
1434 };
1435 vec![]
1436 }
1437 Append => {
1438 let offset = cursor.offset();
1439 let line = buffer.line_of_offset(offset);
1440 let line_len = buffer.line_len(line);
1441 let count = (line_len > 1 || (buffer.last_line() == line && line_len > 0)) as usize;
1442 let offset = buffer.move_right(cursor.offset(), Mode::Insert, count);
1443 cursor.mode = CursorMode::Insert(Selection::caret(offset));
1444 vec![]
1445 }
1446 AppendEndOfLine => {
1447 let offset = cursor.offset();
1448 let line = buffer.line_of_offset(offset);
1449 let offset = buffer.line_end_offset(line, true);
1450 cursor.mode = CursorMode::Insert(Selection::caret(offset));
1451 vec![]
1452 }
1453 ToggleVisualMode => {
1454 Self::toggle_visual(cursor, VisualMode::Normal, modal);
1455 vec![]
1456 }
1457 ToggleLinewiseVisualMode => {
1458 Self::toggle_visual(cursor, VisualMode::Linewise, modal);
1459 vec![]
1460 }
1461 ToggleBlockwiseVisualMode => {
1462 Self::toggle_visual(cursor, VisualMode::Blockwise, modal);
1463 vec![]
1464 }
1465 DuplicateLineUp => Self::duplicate_line(cursor, buffer, DuplicateDirection::Up),
1466 DuplicateLineDown => Self::duplicate_line(cursor, buffer, DuplicateDirection::Down),
1467 NormalizeLineEndings => {
1468 let Some((text, delta, inval)) = buffer.normalize_line_endings() else {
1469 return vec![];
1470 };
1471
1472 cursor.apply_delta(&delta);
1473
1474 vec![(text, delta, inval)]
1475 }
1476 }
1477 }
1478}
1479
1480fn apply_undo_redo(
1481 cursor: &mut Cursor,
1482 buffer: &mut Buffer,
1483 modal: bool,
1484 text: Rope,
1485 delta: RopeDelta,
1486 inval_lines: InvalLines,
1487 cursor_mode: Option<CursorMode>,
1488) -> Vec<(Rope, RopeDelta, InvalLines)> {
1489 if let Some(cursor_mode) = cursor_mode {
1490 cursor.mode = if modal {
1491 CursorMode::Normal(cursor_mode.offset())
1492 } else if cursor.is_insert() {
1493 cursor_mode
1494 } else {
1495 CursorMode::Insert(Selection::caret(cursor_mode.offset()))
1496 };
1497 } else if let Some(new_cursor) = get_first_selection_after(cursor, buffer, &delta) {
1498 *cursor = new_cursor
1499 } else if !delta
1500 .els
1501 .iter()
1502 .any(|el| matches!(el, DeltaElement::Copy(_, _)))
1503 {
1504 } else {
1507 cursor.apply_delta(&delta);
1508 }
1509 vec![(text, delta, inval_lines)]
1510}
1511
1512enum DuplicateDirection {
1513 Up,
1514 Down,
1515}
1516
1517#[cfg(test)]
1518mod test {
1519 use crate::{
1520 buffer::{rope_text::RopeText, Buffer},
1521 cursor::{Cursor, CursorMode},
1522 editor::{Action, DuplicateDirection},
1523 selection::{SelRegion, Selection},
1524 word::WordCursor,
1525 };
1526
1527 fn prev_unmatched(buffer: &Buffer, c: char, offset: usize) -> Option<usize> {
1528 WordCursor::new(buffer.text(), offset).previous_unmatched(c)
1529 }
1530
1531 #[test]
1532 fn test_insert_simple() {
1533 let mut buffer = Buffer::new("abc");
1534 let mut cursor = Cursor::new(CursorMode::Insert(Selection::caret(1)), None, None);
1535
1536 Action::insert(&mut cursor, &mut buffer, "e", &prev_unmatched, true, true);
1537 assert_eq!("aebc", buffer.slice_to_cow(0..buffer.len()));
1538 }
1539
1540 #[test]
1541 fn test_insert_multiple_cursor() {
1542 let mut buffer = Buffer::new("abc\nefg\n");
1543 let mut selection = Selection::new();
1544 selection.add_region(SelRegion::caret(1));
1545 selection.add_region(SelRegion::caret(5));
1546 let mut cursor = Cursor::new(CursorMode::Insert(selection), None, None);
1547
1548 Action::insert(&mut cursor, &mut buffer, "i", &prev_unmatched, true, true);
1549 assert_eq!("aibc\neifg\n", buffer.slice_to_cow(0..buffer.len()));
1550 }
1551
1552 #[test]
1553 fn test_insert_complex() {
1554 let mut buffer = Buffer::new("abc\nefg\n");
1555 let mut selection = Selection::new();
1556 selection.add_region(SelRegion::caret(1));
1557 selection.add_region(SelRegion::caret(5));
1558 let mut cursor = Cursor::new(CursorMode::Insert(selection), None, None);
1559
1560 Action::insert(&mut cursor, &mut buffer, "i", &prev_unmatched, true, true);
1561 assert_eq!("aibc\neifg\n", buffer.slice_to_cow(0..buffer.len()));
1562 Action::insert(&mut cursor, &mut buffer, "j", &prev_unmatched, true, true);
1563 assert_eq!("aijbc\neijfg\n", buffer.slice_to_cow(0..buffer.len()));
1564 Action::insert(&mut cursor, &mut buffer, "{", &prev_unmatched, true, true);
1565 assert_eq!("aij{bc\neij{fg\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 }
1569
1570 #[test]
1571 fn test_insert_pair() {
1572 let mut buffer = Buffer::new("a bc\ne fg\n");
1573 let mut selection = Selection::new();
1574 selection.add_region(SelRegion::caret(1));
1575 selection.add_region(SelRegion::caret(6));
1576 let mut cursor = Cursor::new(CursorMode::Insert(selection), None, None);
1577
1578 Action::insert(&mut cursor, &mut buffer, "{", &prev_unmatched, true, true);
1579 assert_eq!("a{} bc\ne{} fg\n", buffer.slice_to_cow(0..buffer.len()));
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 }
1583
1584 #[test]
1585 fn test_insert_pair_with_selection() {
1586 let mut buffer = Buffer::new("a bc\ne fg\n");
1587 let mut selection = Selection::new();
1588 selection.add_region(SelRegion::new(0, 4, None));
1589 selection.add_region(SelRegion::new(5, 9, None));
1590 let mut cursor = Cursor::new(CursorMode::Insert(selection), None, None);
1591 Action::insert(&mut cursor, &mut buffer, "{", &prev_unmatched, true, true);
1592 assert_eq!("{a bc}\n{e fg}\n", buffer.slice_to_cow(0..buffer.len()));
1593 }
1594
1595 #[test]
1596 fn test_insert_pair_without_auto_closing() {
1597 let mut buffer = Buffer::new("a bc\ne fg\n");
1598 let mut selection = Selection::new();
1599 selection.add_region(SelRegion::caret(1));
1600 selection.add_region(SelRegion::caret(6));
1601 let mut cursor = Cursor::new(CursorMode::Insert(selection), None, None);
1602
1603 Action::insert(&mut cursor, &mut buffer, "{", &prev_unmatched, false, false);
1604 assert_eq!("a{ bc\ne{ fg\n", buffer.slice_to_cow(0..buffer.len()));
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 }
1608
1609 #[test]
1610 fn duplicate_down_simple() {
1611 let mut buffer = Buffer::new("first line\nsecond line\n");
1612 let mut selection = Selection::new();
1613 selection.add_region(SelRegion::caret(0));
1614 let mut cursor = Cursor::new(CursorMode::Insert(selection), None, None);
1615
1616 Action::duplicate_line(&mut cursor, &mut buffer, DuplicateDirection::Down);
1617
1618 assert_ne!(cursor.offset(), 0);
1619 assert_eq!(
1620 "first line\nfirst line\nsecond line\n",
1621 buffer.slice_to_cow(0..buffer.len())
1622 );
1623 }
1624
1625 #[test]
1626 fn duplicate_up_simple() {
1627 let mut buffer = Buffer::new("first line\nsecond line\n");
1628 let mut selection = Selection::new();
1629 selection.add_region(SelRegion::caret(0));
1630 let mut cursor = Cursor::new(CursorMode::Insert(selection), None, None);
1631
1632 Action::duplicate_line(&mut cursor, &mut buffer, DuplicateDirection::Up);
1633
1634 assert_eq!(cursor.offset(), 0);
1635 assert_eq!(
1636 "first line\nfirst line\nsecond line\n",
1637 buffer.slice_to_cow(0..buffer.len())
1638 );
1639 }
1640
1641 #[test]
1642 fn duplicate_down_multiple_cursors_in_same_line() {
1643 let mut buffer = Buffer::new("first line\nsecond line\n");
1644 let mut selection = Selection::new();
1645 selection.add_region(SelRegion::caret(0));
1646 selection.add_region(SelRegion::caret(1));
1647 let mut cursor = Cursor::new(CursorMode::Insert(selection), None, None);
1648
1649 Action::duplicate_line(&mut cursor, &mut buffer, DuplicateDirection::Down);
1650
1651 assert_eq!(
1652 "first line\nfirst line\nsecond line\n",
1653 buffer.slice_to_cow(0..buffer.len())
1654 );
1655 }
1656
1657 #[test]
1658 fn duplicate_up_multiple_cursors_in_same_line() {
1659 let mut buffer = Buffer::new("first line\nsecond line\n");
1660 let mut selection = Selection::new();
1661 selection.add_region(SelRegion::caret(0));
1662 selection.add_region(SelRegion::caret(1));
1663 let mut cursor = Cursor::new(CursorMode::Insert(selection), None, None);
1664
1665 Action::duplicate_line(&mut cursor, &mut buffer, DuplicateDirection::Up);
1666
1667 assert_eq!(
1668 "first line\nfirst line\nsecond line\n",
1669 buffer.slice_to_cow(0..buffer.len())
1670 );
1671 }
1672
1673 #[test]
1674 fn duplicate_down_multiple() {
1675 let mut buffer = Buffer::new("first line\nsecond line\n");
1676 let mut selection = Selection::new();
1677 selection.add_region(SelRegion::caret(0));
1678 selection.add_region(SelRegion::caret(15));
1679 let mut cursor = Cursor::new(CursorMode::Insert(selection), None, None);
1680
1681 Action::duplicate_line(&mut cursor, &mut buffer, DuplicateDirection::Down);
1682
1683 assert_eq!(
1684 "first line\nfirst line\nsecond line\nsecond line\n",
1685 buffer.slice_to_cow(0..buffer.len())
1686 );
1687 }
1688
1689 #[test]
1690 fn duplicate_up_multiple() {
1691 let mut buffer = Buffer::new("first line\nsecond line\n");
1692 let mut selection = Selection::new();
1693 selection.add_region(SelRegion::caret(0));
1694 selection.add_region(SelRegion::caret(15));
1695 let mut cursor = Cursor::new(CursorMode::Insert(selection), None, None);
1696
1697 Action::duplicate_line(&mut cursor, &mut buffer, DuplicateDirection::Up);
1698
1699 assert_eq!(
1700 "first line\nfirst line\nsecond line\nsecond line\n",
1701 buffer.slice_to_cow(0..buffer.len())
1702 );
1703 }
1704
1705 #[test]
1706 fn duplicate_down_multiple_with_swapped_cursor_order() {
1707 let mut buffer = Buffer::new("first line\nsecond line\n");
1708 let mut selection = Selection::new();
1709 selection.add_region(SelRegion::caret(15));
1710 selection.add_region(SelRegion::caret(0));
1711 let mut cursor = Cursor::new(CursorMode::Insert(selection), None, None);
1712
1713 Action::duplicate_line(&mut cursor, &mut buffer, DuplicateDirection::Down);
1714
1715 assert_eq!(
1716 "first line\nfirst line\nsecond line\nsecond line\n",
1717 buffer.slice_to_cow(0..buffer.len())
1718 );
1719 }
1720
1721 #[test]
1722 fn duplicate_up_multiple_with_swapped_cursor_order() {
1723 let mut buffer = Buffer::new("first line\nsecond line\n");
1724 let mut selection = Selection::new();
1725 selection.add_region(SelRegion::caret(15));
1726 selection.add_region(SelRegion::caret(0));
1727 let mut cursor = Cursor::new(CursorMode::Insert(selection), None, None);
1728
1729 Action::duplicate_line(&mut cursor, &mut buffer, DuplicateDirection::Up);
1730
1731 assert_eq!(
1732 "first line\nfirst line\nsecond line\nsecond line\n",
1733 buffer.slice_to_cow(0..buffer.len())
1734 );
1735 }
1736
1737 #[test]
1738 fn check_multiple_cursor_match_insertion() {
1739 let mut buffer = Buffer::new(" 123 567 9ab def");
1740 let mut selection = Selection::new();
1741 selection.add_region(SelRegion::caret(0));
1742 selection.add_region(SelRegion::caret(4));
1743 selection.add_region(SelRegion::caret(8));
1744 selection.add_region(SelRegion::caret(12));
1745 let mut cursor = Cursor::new(CursorMode::Insert(selection), None, None);
1746
1747 Action::insert(&mut cursor, &mut buffer, "(", &prev_unmatched, true, true);
1748
1749 assert_eq!(
1750 "() 123() 567() 9ab() def",
1751 buffer.slice_to_cow(0..buffer.len())
1752 );
1753
1754 let mut end_selection = Selection::new();
1755 end_selection.add_region(SelRegion::caret(1));
1756 end_selection.add_region(SelRegion::caret(7));
1757 end_selection.add_region(SelRegion::caret(13));
1758 end_selection.add_region(SelRegion::caret(19));
1759 assert_eq!(cursor.mode, CursorMode::Insert(end_selection));
1760 }
1761
1762 }