1#![allow(clippy::enum_glob_use)]
2
3use crate::{
4 editor::Editor,
5 keymap::{Keymap, KeymapResult, keymap},
6 mode::{
7 Mode,
8 command::enter_command_mode,
9 insert, prompt, replace,
10 seek::{self, SeekDirection, SeekInclude, SeekSelect},
11 },
12 rope::{LINE_TYPE, RopeExt as _},
13 selection::PasteMode,
14 window::{
15 scroll_full_page_down, scroll_full_page_up, scroll_half_page_down, scroll_half_page_up,
16 },
17};
18use regex_cursor::engines::meta::Regex;
19use std::{cmp::min, num::NonZeroUsize, sync::LazyLock};
20
21#[cfg(feature = "arbitrary")]
22use arbitrary::Arbitrary;
23
24#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
25#[derive(Debug)]
26pub enum Action {
27 AppendCountDigit(u8),
28 ClearCount,
29 Commit,
30 EnterNormalMode,
31 EnterCommandMode,
32 EnterInsertMode,
33 EnterSeekMode {
34 select: SeekSelect,
35 include: SeekInclude,
36 direction: SeekDirection,
37 },
38 EnterReplaceMode,
39 InsertAfterHead,
40 InsertAtLineNonBlankStart,
41 InsertAtLineEnd,
42 InsertLineAbove,
43 InsertLineBelow,
44 AddLineAbove,
45 AddLineBelow,
46 MoveLeft,
47 MoveRight,
48 MoveUp,
49 MoveDown,
50 ExtendLeft,
51 ExtendRight,
52 ExtendUp,
53 ExtendDown,
54 GotoMoveToLine,
55 GotoMoveToStart,
56 GotoExtendToStart,
57 GotoMoveToBottom,
58 GotoExtendToBottom,
59 GotoMoveToEnd,
60 GotoExtendToEnd,
61 GotoMoveToLineStart,
62 GotoExtendToLineStart,
63 GotoMoveToLineNonBlankStart,
64 GotoExtendToLineNonBlankStart,
65 GotoMoveUntilLineEnd,
66 GotoExtendUntilLineEnd,
67 KeepPrimary,
68 RotateSelectionBackward,
69 RotateSelectionForward,
70 Collapse,
71 Flip,
72 FlipForward,
73 SelectAll,
74 ExpandToFullLines,
75 SplitIntoLines,
76 SelectRegex,
77 Delete,
78 Yank,
79 PasteAfter,
80 PasteBefore,
81 PasteReplace,
82 PasteAllAfter,
83 PasteAllBefore,
84 PasteAllReplace,
85 Undo,
86 Redo,
87 ScrollHalfPageUp,
88 ScrollHalfPageDown,
89 ScrollFullPageUp,
90 ScrollFullPageDown,
91}
92
93pub static KEYMAP: LazyLock<Keymap<Vec<Action>>> = LazyLock::new(|| {
94 use Action::*;
95 use SeekDirection::{Next, Prev};
96 use SeekInclude::{Onto, Until};
97 use SeekSelect::{Extend, Move};
98 keymap! { Vec<Action>;
99 "<esc>" => vec![EnterNormalMode],
100
101 "0" => vec![AppendCountDigit(0)],
102 "1" => vec![AppendCountDigit(1)],
103 "2" => vec![AppendCountDigit(2)],
104 "3" => vec![AppendCountDigit(3)],
105 "4" => vec![AppendCountDigit(4)],
106 "5" => vec![AppendCountDigit(5)],
107 "6" => vec![AppendCountDigit(6)],
108 "7" => vec![AppendCountDigit(7)],
109 "8" => vec![AppendCountDigit(8)],
110 "9" => vec![AppendCountDigit(9)],
111
112 "h" => vec![MoveLeft], "l" => vec![MoveRight], "k" => vec![MoveUp], "j" => vec![MoveDown], "H" => vec![ExtendLeft], "L" => vec![ExtendRight], "K" => vec![ExtendUp], "J" => vec![ExtendDown], "i" => vec![EnterInsertMode], "a" => vec![InsertAfterHead], "I" => vec![InsertAtLineNonBlankStart], "A" => vec![InsertAtLineEnd], "r" => vec![EnterReplaceMode], "y" => vec![Yank], "c" => vec![Yank, Delete, EnterInsertMode], "d" => vec![Yank, Delete, Commit], "<a-c>" => vec![Delete, EnterInsertMode], "<a-d>" => vec![Delete, Commit], "p" => vec![PasteAfter, Commit], "P" => vec![PasteBefore, Commit], "R" => vec![PasteReplace, Commit], "<a-p>" => vec![PasteAllAfter, Commit], "<a-P>" => vec![PasteAllBefore, Commit], "<a-R>" => vec![PasteAllReplace, Commit], "u" => vec![Undo], "U" => vec![Redo], "gk" => vec![GotoMoveToStart], "gj" => vec![GotoMoveToBottom], "ge" => vec![GotoMoveToEnd], "gh" => vec![GotoMoveToLineStart], "gi" => vec![GotoMoveToLineNonBlankStart], "gl" => vec![GotoMoveUntilLineEnd], "gK" => vec![GotoExtendToStart], "gJ" => vec![GotoExtendToBottom], "gE" => vec![GotoExtendToEnd], "gH" => vec![GotoExtendToLineStart], "gI" => vec![GotoExtendToLineNonBlankStart], "gL" => vec![GotoExtendUntilLineEnd], "f" => vec![EnterSeekMode { select: Move, include: Onto, direction: Next }], "<a-f>" => vec![EnterSeekMode { select: Move, include: Onto, direction: Prev }], "t" => vec![EnterSeekMode { select: Move, include: Until, direction: Next }], "<a-t>" => vec![EnterSeekMode { select: Move, include: Until, direction: Prev }], "F" => vec![EnterSeekMode { select: Extend, include: Onto, direction: Next }], "<a-F>" => vec![EnterSeekMode { select: Extend, include: Onto, direction: Prev }], "T" => vec![EnterSeekMode { select: Extend, include: Until, direction: Next }], "<a-T>" => vec![EnterSeekMode { select: Extend, include: Until, direction: Prev }], "%" => vec![SelectAll], "s" => vec![SelectRegex], "<a-s>" => vec![SplitIntoLines], "x" => vec![ExpandToFullLines], "<a-;>" => vec![Flip], "<a-:>" => vec![FlipForward], "(" => vec![RotateSelectionBackward], ")" => vec![RotateSelectionForward], "," => vec![KeepPrimary], ";" => vec![Collapse], "o" => vec![InsertLineBelow], "O" => vec![InsertLineAbove], "<a-o>" => vec![AddLineBelow, Commit], "<a-O>" => vec![AddLineAbove, Commit], ":" => vec![EnterCommandMode], "<c-u>" => vec![ScrollHalfPageUp], "<c-d>" => vec![ScrollHalfPageDown], "<c-b>" => vec![ScrollFullPageUp], "<c-f>" => vec![ScrollFullPageDown], _keys => {
190 KeymapResult::Fallback(vec![ClearCount])
191 }, }
193});
194
195pub fn handle_actions(editor: &mut Editor, actions: &[Action]) {
196 for action in actions {
197 handle_action(editor, action);
198 }
199}
200
201pub fn handle_action(editor: &mut Editor, action: &Action) {
202 match action {
203 Action::AppendCountDigit(digit) => {
204 let digit = usize::from(*digit);
205 let old_count = editor.count.map_or(0, |count| usize::from(count));
206 let new_count = NonZeroUsize::new(old_count.saturating_mul(10).saturating_add(digit));
207 editor.count = new_count;
208 }
209 Action::ClearCount => editor.count = None,
210 Action::Commit => editor.focused_buffer_mut().text.commit(),
211 Action::EnterNormalMode => enter(editor),
212 Action::EnterCommandMode => enter_command_mode(editor),
213 Action::EnterInsertMode => insert::enter(editor),
214 Action::EnterSeekMode {
215 select,
216 include,
217 direction,
218 } => {
219 seek::enter(editor, *select, *include, *direction);
220 }
221 Action::EnterReplaceMode => replace::enter(editor),
222 Action::InsertAfterHead => insert_after_head(editor),
223 Action::InsertAtLineNonBlankStart => insert_at_line_non_blank_start(editor),
224 Action::InsertAtLineEnd => insert_at_line_end(editor),
225 Action::InsertLineAbove => insert_line_above(editor),
226 Action::InsertLineBelow => insert_line_below(editor),
227 Action::AddLineAbove => add_line_above(editor),
228 Action::AddLineBelow => add_line_below(editor),
229 Action::MoveLeft => move_left(editor),
230 Action::MoveRight => move_right(editor),
231 Action::MoveUp => move_up(editor),
232 Action::MoveDown => move_down(editor),
233 Action::ExtendLeft => extend_left(editor),
234 Action::ExtendRight => extend_right(editor),
235 Action::ExtendUp => extend_up(editor),
236 Action::ExtendDown => extend_down(editor),
237 Action::GotoMoveToLine => goto_move_to_line(editor),
238 Action::GotoMoveToStart => goto_move_to_start(editor),
239 Action::GotoExtendToStart => goto_extend_to_start(editor),
240 Action::GotoMoveToBottom => goto_move_to_bottom(editor),
241 Action::GotoExtendToBottom => goto_extend_to_bottom(editor),
242 Action::GotoMoveToEnd => goto_move_to_end(editor),
243 Action::GotoExtendToEnd => goto_extend_to_end(editor),
244 Action::GotoMoveToLineStart => goto_move_to_line_start(editor),
245 Action::GotoExtendToLineStart => goto_extend_to_line_start(editor),
246 Action::GotoMoveToLineNonBlankStart => goto_move_to_line_non_blank_start(editor),
247 Action::GotoExtendToLineNonBlankStart => goto_extend_to_line_non_blank_start(editor),
248 Action::GotoMoveUntilLineEnd => goto_move_until_line_end(editor),
249 Action::GotoExtendUntilLineEnd => goto_extend_until_line_end(editor),
250 Action::KeepPrimary => keep_primary(editor),
251 Action::RotateSelectionBackward => rotate_selection_backward(editor),
252 Action::RotateSelectionForward => rotate_selection_forward(editor),
253 Action::Collapse => collapse(editor),
254 Action::Flip => flip(editor),
255 Action::FlipForward => flip_forward(editor),
256 Action::SelectAll => select_all(editor),
257 Action::ExpandToFullLines => expand_to_full_lines(editor),
258 Action::SplitIntoLines => split_into_lines(editor),
259 Action::SelectRegex => select_regex(editor),
260 Action::Delete => delete(editor),
261 Action::Yank => yank(editor),
262 Action::PasteAfter => paste(editor, PasteMode::After),
263 Action::PasteBefore => paste(editor, PasteMode::Before),
264 Action::PasteReplace => paste(editor, PasteMode::Replace),
265 Action::PasteAllAfter => paste_all(editor, PasteMode::After),
266 Action::PasteAllBefore => paste_all(editor, PasteMode::Before),
267 Action::PasteAllReplace => paste_all(editor, PasteMode::Replace),
268 Action::Undo => undo(editor),
269 Action::Redo => redo(editor),
270 Action::ScrollHalfPageUp => scroll_half_page_up(editor),
271 Action::ScrollHalfPageDown => scroll_half_page_down(editor),
272 Action::ScrollFullPageUp => scroll_full_page_up(editor),
273 Action::ScrollFullPageDown => scroll_full_page_down(editor),
274 }
275}
276
277pub fn handle_keys(editor: &mut Editor) -> bool {
278 match KEYMAP.get_keys(&editor.pending_keys) {
279 KeymapResult::Mapped(actions) => {
280 editor.pending_keys.clear();
281 handle_actions(editor, actions);
282 true
283 }
284 KeymapResult::Fallback(actions) => {
285 editor.pending_keys.clear();
286 handle_actions(editor, &actions);
287 true
288 }
289 KeymapResult::Unmapped => {
290 editor.pending_keys.clear();
291 false
292 }
293 KeymapResult::Pending => true,
294 }
295}
296
297pub fn enter(editor: &mut Editor) {
298 editor.focused_buffer_mut().text.commit();
299 editor.mode = Mode::Normal;
300 editor.count = None;
301}
302
303fn extend_left(editor: &mut Editor) {
304 let count = editor.count.take().unwrap_or(NonZeroUsize::MIN).get();
305 let mut window = editor.focused_window_mut();
306 window
307 .selection_move()
308 .for_each_move(|mut range| range.extend_left(count));
309 window.selection_move().merge_overlapping();
310 window.scroll_to_selection();
311}
312
313fn move_left(editor: &mut Editor) {
314 let count = editor.count.take().unwrap_or(NonZeroUsize::MIN).get();
315 let mut window = editor.focused_window_mut();
316 window
317 .selection_move()
318 .for_each_move(|mut range| range.move_left(count));
319 window.selection_move().merge_overlapping();
320 window.scroll_to_selection();
321}
322
323fn extend_right(editor: &mut Editor) {
324 let count = editor.count.take().unwrap_or(NonZeroUsize::MIN).get();
325 let mut window = editor.focused_window_mut();
326 window
327 .selection_move()
328 .for_each_move(|mut range| range.extend_right(count));
329 window.selection_move().merge_overlapping();
330 window.scroll_to_selection();
331}
332
333fn move_right(editor: &mut Editor) {
334 let count = editor.count.take().unwrap_or(NonZeroUsize::MIN).get();
335 let mut window = editor.focused_window_mut();
336 window
337 .selection_move()
338 .for_each_move(|mut range| range.move_right(count));
339 window.selection_move().merge_overlapping();
340 window.scroll_to_selection();
341}
342
343fn extend_up(editor: &mut Editor) {
344 let count = editor.count.take().unwrap_or(NonZeroUsize::MIN).get();
345 let mut window = editor.focused_window_mut();
346 window
347 .selection_move()
348 .for_each_move(|mut range| range.extend_up(count));
349 window.selection_move().merge_overlapping();
350 window.scroll_to_selection();
351}
352
353fn move_up(editor: &mut Editor) {
354 let count = editor.count.take().unwrap_or(NonZeroUsize::MIN).get();
355 let mut window = editor.focused_window_mut();
356 window
357 .selection_move()
358 .for_each_move(|mut range| range.move_up(count));
359 window.selection_move().merge_overlapping();
360 window.scroll_to_selection();
361}
362
363fn extend_down(editor: &mut Editor) {
364 let count = editor.count.take().unwrap_or(NonZeroUsize::MIN).get();
365 let mut window = editor.focused_window_mut();
366 window
367 .selection_move()
368 .for_each_move(|mut range| range.extend_down(count));
369 window.selection_move().merge_overlapping();
370 window.scroll_to_selection();
371}
372
373fn move_down(editor: &mut Editor) {
374 let count = editor.count.take().unwrap_or(NonZeroUsize::MIN).get();
375 let mut window = editor.focused_window_mut();
376 window
377 .selection_move()
378 .for_each_move(|mut range| range.move_down(count));
379 window.selection_move().merge_overlapping();
380 window.scroll_to_selection();
381}
382
383fn flip(editor: &mut Editor) {
384 let mut window = editor.focused_window_mut();
385 window
386 .selection_move()
387 .for_each_move(|mut range| range.flip());
388 window.scroll_to_selection();
389 editor.count = None;
390}
391
392fn flip_forward(editor: &mut Editor) {
393 let mut window = editor.focused_window_mut();
394 window
395 .selection_move()
396 .for_each_move(|mut range| range.flip_forward());
397 window.scroll_to_selection();
398 editor.count = None;
399}
400
401fn keep_primary(editor: &mut Editor) {
402 let mut window = editor.focused_window_mut();
403 window.selection_move().keep_primary();
404 window.scroll_to_selection();
405 editor.count = None;
406}
407
408fn rotate_selection_backward(editor: &mut Editor) {
409 let count = editor.count.take().unwrap_or(NonZeroUsize::MIN).get();
410 let mut window = editor.focused_window_mut();
411 window.selection_move().rotate_backward(count);
412 window.scroll_to_selection();
413}
414
415fn rotate_selection_forward(editor: &mut Editor) {
416 let count = editor.count.take().unwrap_or(NonZeroUsize::MIN).get();
417 let mut window = editor.focused_window_mut();
418 window.selection_move().rotate_forward(count);
419 window.scroll_to_selection();
420}
421
422fn collapse(editor: &mut Editor) {
423 let mut window = editor.focused_window_mut();
424 window
425 .selection_move()
426 .for_each_move(|mut range| range.collapse());
427 window.scroll_to_selection();
428 editor.count = None;
429}
430
431fn delete(editor: &mut Editor) {
432 if editor.focused_buffer().text.readonly {
433 editor.message = Some(Err(String::from("Buffer is readonly")));
434 editor.count = None;
435 return;
436 }
437 let mut window = editor.focused_window_mut();
438 window.selection_edit().delete();
439 window.scroll_to_selection();
440 editor.count = None;
441}
442
443fn yank(editor: &mut Editor) {
444 let values = editor
445 .focused_window()
446 .selection()
447 .contents()
448 .map(String::from)
449 .collect();
450 editor.registers.insert('"', values);
451 editor.count = None;
452}
453
454fn paste(editor: &mut Editor, paste_mode: PasteMode) {
455 let count = editor.count.take().unwrap_or(NonZeroUsize::MIN).get();
456 if editor.focused_buffer().text.readonly {
457 editor.message = Some(Err(String::from("Buffer is readonly")));
458 return;
459 }
460 let count = if paste_mode == PasteMode::Replace {
461 1
462 } else {
463 count
464 };
465 let values = editor.registers.get(&'"').cloned().unwrap_or_default();
466 let mut window = editor.focused_window_mut();
467 for _ in 1..=count {
468 window.selection_edit().paste(&values, paste_mode);
469 }
470 window.scroll_to_selection();
471}
472
473fn paste_all(editor: &mut Editor, paste_mode: PasteMode) {
474 editor.count = None;
475 if editor.focused_buffer().text.readonly {
476 editor.message = Some(Err(String::from("Buffer is readonly")));
477 return;
478 }
479 let values = editor.registers.get(&'"').cloned().unwrap_or_default();
480 if values.is_empty() {
481 editor.message = Some(Err(String::from("Nothing to paste")));
482 return;
483 }
484 let mut window = editor.focused_window_mut();
485 window.selection_edit().paste_all(&values, paste_mode);
486 window.scroll_to_selection();
487}
488
489fn undo(editor: &mut Editor) {
490 let count = editor.count.take().unwrap_or(NonZeroUsize::MIN).get();
491 if editor.focused_buffer().text.readonly {
492 editor.message = Some(Err(String::from("Buffer is readonly")));
493 return;
494 }
495 let mut window = editor.focused_window_mut();
496 for _ in 1..=count {
497 if !window.undo().unwrap() {
498 break;
499 }
500 }
501 window.scroll_to_selection();
502}
503
504fn redo(editor: &mut Editor) {
505 let count = editor.count.take().unwrap_or(NonZeroUsize::MIN).get();
506 if editor.focused_buffer().text.readonly {
507 editor.message = Some(Err(String::from("Buffer is readonly")));
508 return;
509 }
510 let mut window = editor.focused_window_mut();
511 for _ in 1..=count {
512 if !window.redo().unwrap() {
513 break;
514 }
515 }
516 window.scroll_to_selection();
517}
518
519fn select_all(editor: &mut Editor) {
520 let mut window = editor.focused_window_mut();
521 window.selection_move().select_all();
522 window.scroll_to_selection();
523 editor.count = None;
524}
525
526fn expand_to_full_lines(editor: &mut Editor) {
527 let mut window = editor.focused_window_mut();
528 window
529 .selection_move()
530 .for_each_move(|mut range| range.expand_to_full_lines());
531 window.selection_move().merge_overlapping();
532 window.scroll_to_selection();
533 editor.count = None;
534}
535
536fn split_into_lines(editor: &mut Editor) {
537 let mut window = editor.focused_window_mut();
538 window.selection_move().split_into_lines();
539 window.scroll_to_selection();
540 editor.count = None;
541}
542
543fn select_regex(editor: &mut Editor) {
544 prompt::enter(editor, "select", |editor, regex_str| {
545 if regex_str.is_empty() {
546 editor.message = Some(Err(String::from("Nothing selected")));
547 editor.count = None;
548 return;
549 }
550 let regex = Regex::builder()
551 .syntax(
552 regex_cursor::regex_automata::util::syntax::Config::new()
553 .multi_line(true)
554 .dot_matches_new_line(true),
555 )
556 .build(regex_str);
557 if let Ok(regex) = regex {
558 let matched = editor
559 .focused_window_mut()
560 .selection_move()
561 .select_regex(®ex);
562 if !matched {
563 editor.message = Some(Err(String::from("Nothing selected")));
564 }
565 } else {
566 editor.message = Some(Err(String::from("Invalid regex")));
567 }
568 editor.count = None;
569 });
570}
571
572fn insert_after_head(editor: &mut Editor) {
573 if editor.focused_buffer().text.readonly {
574 editor.message = Some(Err(String::from("Buffer is readonly")));
575 editor.count = None;
576 return;
577 }
578 let mut window = editor.focused_window_mut();
579 window.selection_edit().for_each_edit(|mut range| {
580 range.prepare_append();
581 });
582 window.scroll_to_selection();
583 editor.mode = Mode::Insert;
584 editor.count = None;
585}
586
587fn insert_at_line_non_blank_start(editor: &mut Editor) {
588 if editor.focused_buffer().text.readonly {
589 editor.message = Some(Err(String::from("Buffer is readonly")));
590 editor.count = None;
591 return;
592 }
593 let mut window = editor.focused_window_mut();
594 window.selection_move().for_each_move(|mut range| {
595 range.move_to_line_non_blank_start();
596 });
597 window.scroll_to_selection();
598 editor.mode = Mode::Insert;
599 editor.count = None;
600}
601
602fn insert_at_line_end(editor: &mut Editor) {
603 if editor.focused_buffer().text.readonly {
604 editor.message = Some(Err(String::from("Buffer is readonly")));
605 editor.count = None;
606 return;
607 }
608 let mut window = editor.focused_window_mut();
609 window.selection_move().for_each_move(|mut range| {
610 range.move_onto_line_end();
611 });
612 window.scroll_to_selection();
613 editor.mode = Mode::Insert;
614 editor.count = None;
615}
616
617fn insert_line_above(editor: &mut Editor) {
618 let count = editor.count.take().unwrap_or(NonZeroUsize::MIN).get();
620 if editor.focused_buffer().text.readonly {
621 editor.message = Some(Err(String::from("Buffer is readonly")));
622 return;
623 }
624 let mut window = editor.focused_window_mut();
625 window.selection_edit().for_each_edit(|mut range| {
627 range.move_to_line_start();
628 for _ in 0..count {
629 range.insert_char('\n');
630 }
631 range.move_left(1);
632 });
633 window.scroll_to_selection();
634 editor.mode = Mode::Insert;
635}
636
637fn insert_line_below(editor: &mut Editor) {
638 let count = editor.count.take().unwrap_or(NonZeroUsize::MIN).get();
640 if editor.focused_buffer().text.readonly {
641 editor.message = Some(Err(String::from("Buffer is readonly")));
642 return;
643 }
644 let mut window = editor.focused_window_mut();
645 window.selection_edit().for_each_edit(|mut range| {
647 range.move_onto_line_end();
648 for _ in 0..count {
649 range.insert_char('\n');
650 }
651 });
652 window.scroll_to_selection();
653 editor.mode = Mode::Insert;
654}
655
656fn add_line_above(editor: &mut Editor) {
657 let count = editor.count.take().unwrap_or(NonZeroUsize::MIN).get();
658 if editor.focused_buffer().text.readonly {
659 editor.message = Some(Err(String::from("Buffer is readonly")));
660 return;
661 }
662 let mut window = editor.focused_window_mut();
663 window.selection_edit().for_each_edit(|mut range| {
665 let snapshot = range.save();
666 range.move_to_line_start();
667 for _ in 0..count {
668 range.insert_char('\n');
669 }
670 assert!(range.restore(&snapshot));
671 });
672 window.selection_move().merge_overlapping();
673 window.scroll_to_selection();
674}
675
676fn add_line_below(editor: &mut Editor) {
677 let count = editor.count.take().unwrap_or(NonZeroUsize::MIN).get();
678 if editor.focused_buffer().text.readonly {
679 editor.message = Some(Err(String::from("Buffer is readonly")));
680 return;
681 }
682 let mut window = editor.focused_window_mut();
683 window.selection_edit().for_each_edit(|mut range| {
685 let snapshot = range.save();
686 range.move_onto_line_end();
687 for _ in 0..count {
688 range.insert_char('\n');
689 }
690 assert!(range.restore(&snapshot));
691 });
692 window.selection_move().merge_overlapping();
693 window.scroll_to_selection();
694}
695
696fn goto_move_to_line(editor: &mut Editor) {
697 let count = editor.count.take().unwrap_or(NonZeroUsize::MIN).get();
698 let mut window = editor.focused_window_mut();
699 let rope = window.buffer().text.rope().clone();
700 let line_index = min(count - 1, rope.len_lines_unix() - 1);
701 let byte_index = rope.line_to_byte_idx(line_index, LINE_TYPE);
702 window
703 .selection_move()
704 .for_each_move(|mut range| range.move_to(byte_index));
705 window.selection_move().merge_overlapping();
706 window.scroll_to_selection();
707}
708
709fn goto_move_to_start(editor: &mut Editor) {
710 let mut window = editor.focused_window_mut();
711 window
712 .selection_move()
713 .for_each_move(|mut range| range.move_to_start());
714 window.selection_move().merge_overlapping();
715 window.scroll_to_selection();
716 editor.count = None;
717}
718
719fn goto_extend_to_start(editor: &mut Editor) {
720 let mut window = editor.focused_window_mut();
721 window
722 .selection_move()
723 .for_each_move(|mut range| range.extend_to_start());
724 window.selection_move().merge_overlapping();
725 window.scroll_to_selection();
726 editor.count = None;
727}
728
729fn goto_move_to_bottom(editor: &mut Editor) {
730 let mut window = editor.focused_window_mut();
731 window
732 .selection_move()
733 .for_each_move(|mut range| range.move_to_bottom());
734 window.selection_move().merge_overlapping();
735 window.scroll_to_selection();
736 editor.count = None;
737}
738
739fn goto_extend_to_bottom(editor: &mut Editor) {
740 let mut window = editor.focused_window_mut();
741 window
742 .selection_move()
743 .for_each_move(|mut range| range.extend_to_bottom());
744 window.selection_move().merge_overlapping();
745 window.scroll_to_selection();
746 editor.count = None;
747}
748
749fn goto_move_to_end(editor: &mut Editor) {
750 let mut window = editor.focused_window_mut();
751 window
752 .selection_move()
753 .for_each_move(|mut range| range.move_to_end());
754 window.selection_move().merge_overlapping();
755 window.scroll_to_selection();
756 editor.count = None;
757}
758
759fn goto_extend_to_end(editor: &mut Editor) {
760 let mut window = editor.focused_window_mut();
761 window
762 .selection_move()
763 .for_each_move(|mut range| range.extend_to_end());
764 window.selection_move().merge_overlapping();
765 window.scroll_to_selection();
766 editor.count = None;
767}
768
769fn goto_move_to_line_start(editor: &mut Editor) {
770 let mut window = editor.focused_window_mut();
771 window
772 .selection_move()
773 .for_each_move(|mut range| range.move_to_line_start());
774 window.selection_move().merge_overlapping();
775 editor.count = None;
776}
777
778fn goto_extend_to_line_start(editor: &mut Editor) {
779 let mut window = editor.focused_window_mut();
780 window
781 .selection_move()
782 .for_each_move(|mut range| range.extend_to_line_start());
783 window.selection_move().merge_overlapping();
784 editor.count = None;
785}
786
787fn goto_move_to_line_non_blank_start(editor: &mut Editor) {
788 let mut window = editor.focused_window_mut();
789 window
790 .selection_move()
791 .for_each_move(|mut range| range.move_to_line_non_blank_start());
792 window.selection_move().merge_overlapping();
793 editor.count = None;
794}
795
796fn goto_extend_to_line_non_blank_start(editor: &mut Editor) {
797 let mut window = editor.focused_window_mut();
798 window
799 .selection_move()
800 .for_each_move(|mut range| range.extend_to_line_non_blank_start());
801 window.selection_move().merge_overlapping();
802 editor.count = None;
803}
804
805fn goto_move_until_line_end(editor: &mut Editor) {
806 let mut window = editor.focused_window_mut();
807 window
808 .selection_move()
809 .for_each_move(|mut range| range.move_until_line_end());
810 window.selection_move().merge_overlapping();
811 editor.count = None;
812}
813
814fn goto_extend_until_line_end(editor: &mut Editor) {
815 let mut window = editor.focused_window_mut();
816 window
817 .selection_move()
818 .for_each_move(|mut range| range.extend_until_line_end());
819 window.selection_move().merge_overlapping();
820 editor.count = None;
821}