liner/keymap/
vi.rs

1use std::io::{self, Write};
2use std::{cmp, mem};
3use termion::event::Key;
4
5use crate::buffer::Buffer;
6use crate::Editor;
7use crate::KeyMap;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10enum CharMovement {
11    RightUntil,
12    RightAt,
13    LeftUntil,
14    LeftAt,
15    Repeat,
16    ReverseRepeat,
17}
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20enum MoveType {
21    Inclusive,
22    Exclusive,
23}
24
25/// The editing mode.
26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27enum Mode {
28    Insert,
29    Normal,
30    Replace,
31    Delete(usize),
32    MoveToChar(CharMovement),
33    G,
34    Tilde,
35}
36
37struct ModeStack(Vec<Mode>);
38
39impl ModeStack {
40    fn with_insert() -> Self {
41        ModeStack(vec![Mode::Insert])
42    }
43
44    /// Get the current mode.
45    ///
46    /// If the stack is empty, we are in normal mode.
47    fn mode(&self) -> Mode {
48        self.0.last().cloned().unwrap_or(Mode::Normal)
49    }
50
51    /// Empty the stack and return to normal mode.
52    fn clear(&mut self) {
53        self.0.clear()
54    }
55
56    /// Push the given mode on to the stack.
57    fn push(&mut self, m: Mode) {
58        self.0.push(m)
59    }
60
61    fn pop(&mut self) -> Mode {
62        self.0.pop().unwrap_or(Mode::Normal)
63    }
64}
65
66fn is_movement_key(key: Key) -> bool {
67    matches!(
68        key,
69        Key::Char('h')
70            | Key::Char('l')
71            | Key::Left
72            | Key::Right
73            | Key::Char('w')
74            | Key::Char('W')
75            | Key::Char('b')
76            | Key::Char('B')
77            | Key::Char('e')
78            | Key::Char('E')
79            | Key::Char('g')
80            | Key::Backspace
81            | Key::Char(' ')
82            | Key::Home
83            | Key::End
84            | Key::Char('^')
85            | Key::Char('$')
86            | Key::Char('t')
87            | Key::Char('f')
88            | Key::Char('T')
89            | Key::Char('F')
90            | Key::Char(';')
91            | Key::Char(',')
92    )
93}
94
95#[derive(PartialEq)]
96enum ViMoveMode {
97    Keyword,
98    Whitespace,
99}
100
101#[derive(PartialEq, Clone, Copy)]
102enum ViMoveDir {
103    Left,
104    Right,
105}
106
107impl ViMoveDir {
108    pub fn advance(self, cursor: &mut usize, max: usize) -> bool {
109        self.move_cursor(cursor, max, self)
110    }
111
112    pub fn go_back(self, cursor: &mut usize, max: usize) -> bool {
113        match self {
114            ViMoveDir::Right => self.move_cursor(cursor, max, ViMoveDir::Left),
115            ViMoveDir::Left => self.move_cursor(cursor, max, ViMoveDir::Right),
116        }
117    }
118
119    fn move_cursor(self, cursor: &mut usize, max: usize, dir: ViMoveDir) -> bool {
120        if dir == ViMoveDir::Right && *cursor == max {
121            return false;
122        }
123
124        if dir == ViMoveDir::Left && *cursor == 0 {
125            return false;
126        }
127
128        match dir {
129            ViMoveDir::Right => *cursor += 1,
130            ViMoveDir::Left => *cursor -= 1,
131        };
132        true
133    }
134}
135
136/// All alphanumeric characters and _ are considered valid for keywords in vi by default.
137fn is_vi_keyword(c: char) -> bool {
138    c == '_' || c.is_alphanumeric()
139}
140
141fn move_word<W: Write>(ed: &mut Editor<W>, count: usize) -> io::Result<()> {
142    vi_move_word(ed, ViMoveMode::Keyword, ViMoveDir::Right, count)
143}
144
145fn move_word_ws<W: Write>(ed: &mut Editor<W>, count: usize) -> io::Result<()> {
146    vi_move_word(ed, ViMoveMode::Whitespace, ViMoveDir::Right, count)
147}
148
149fn move_to_end_of_word_back<W: Write>(ed: &mut Editor<W>, count: usize) -> io::Result<()> {
150    vi_move_word(ed, ViMoveMode::Keyword, ViMoveDir::Left, count)
151}
152
153fn move_to_end_of_word_ws_back<W: Write>(ed: &mut Editor<W>, count: usize) -> io::Result<()> {
154    vi_move_word(ed, ViMoveMode::Whitespace, ViMoveDir::Left, count)
155}
156
157fn vi_move_word<W: Write>(
158    ed: &mut Editor<W>,
159    move_mode: ViMoveMode,
160    direction: ViMoveDir,
161    count: usize,
162) -> io::Result<()> {
163    enum State {
164        Whitespace,
165        Keyword,
166        NonKeyword,
167    }
168
169    let mut cursor = ed.cursor();
170    'repeat: for _ in 0..count {
171        let buf = ed.current_buffer();
172        let mut state = match buf.char_after(cursor) {
173            None => break,
174            Some(c) => match c {
175                c if c.is_whitespace() => State::Whitespace,
176                c if is_vi_keyword(c) => State::Keyword,
177                _ => State::NonKeyword,
178            },
179        };
180
181        while direction.advance(&mut cursor, buf.num_chars()) {
182            let c = match buf.char_after(cursor) {
183                Some(c) => c,
184                _ => break 'repeat,
185            };
186
187            match state {
188                State::Whitespace => match c {
189                    c if c.is_whitespace() => {}
190                    _ => break,
191                },
192                State::Keyword => match c {
193                    c if c.is_whitespace() => state = State::Whitespace,
194                    c if move_mode == ViMoveMode::Keyword && !is_vi_keyword(c) => break,
195                    _ => {}
196                },
197                State::NonKeyword => match c {
198                    c if c.is_whitespace() => state = State::Whitespace,
199                    c if move_mode == ViMoveMode::Keyword && is_vi_keyword(c) => break,
200                    _ => {}
201                },
202            }
203        }
204    }
205
206    ed.move_cursor_to(cursor)
207}
208
209fn move_to_end_of_word<W: Write>(ed: &mut Editor<W>, count: usize) -> io::Result<()> {
210    vi_move_word_end(ed, ViMoveMode::Keyword, ViMoveDir::Right, count)
211}
212
213fn move_to_end_of_word_ws<W: Write>(ed: &mut Editor<W>, count: usize) -> io::Result<()> {
214    vi_move_word_end(ed, ViMoveMode::Whitespace, ViMoveDir::Right, count)
215}
216
217fn move_word_back<W: Write>(ed: &mut Editor<W>, count: usize) -> io::Result<()> {
218    vi_move_word_end(ed, ViMoveMode::Keyword, ViMoveDir::Left, count)
219}
220
221fn move_word_ws_back<W: Write>(ed: &mut Editor<W>, count: usize) -> io::Result<()> {
222    vi_move_word_end(ed, ViMoveMode::Whitespace, ViMoveDir::Left, count)
223}
224
225fn vi_move_word_end<W: Write>(
226    ed: &mut Editor<W>,
227    move_mode: ViMoveMode,
228    direction: ViMoveDir,
229    count: usize,
230) -> io::Result<()> {
231    enum State {
232        Whitespace,
233        EndOnWord,
234        EndOnOther,
235        EndOnWhitespace,
236    }
237
238    let mut cursor = ed.cursor();
239    'repeat: for _ in 0..count {
240        let buf = ed.current_buffer();
241        let mut state = State::Whitespace;
242
243        while direction.advance(&mut cursor, buf.num_chars()) {
244            let c = match buf.char_after(cursor) {
245                Some(c) => c,
246                _ => break 'repeat,
247            };
248
249            match state {
250                State::Whitespace => match c {
251                    // skip initial whitespace
252                    c if c.is_whitespace() => {}
253                    // if we are in keyword mode and found a keyword, stop on word
254                    c if move_mode == ViMoveMode::Keyword && is_vi_keyword(c) => {
255                        state = State::EndOnWord;
256                    }
257                    // not in keyword mode, stop on whitespace
258                    _ if move_mode == ViMoveMode::Whitespace => {
259                        state = State::EndOnWhitespace;
260                    }
261                    // in keyword mode, found non-whitespace non-keyword, stop on anything
262                    _ => {
263                        state = State::EndOnOther;
264                    }
265                },
266                State::EndOnWord if !is_vi_keyword(c) => {
267                    direction.go_back(&mut cursor, buf.num_chars());
268                    break;
269                }
270                State::EndOnWhitespace if c.is_whitespace() => {
271                    direction.go_back(&mut cursor, buf.num_chars());
272                    break;
273                }
274                State::EndOnOther if c.is_whitespace() || is_vi_keyword(c) => {
275                    direction.go_back(&mut cursor, buf.num_chars());
276                    break;
277                }
278                _ => {}
279            }
280        }
281    }
282
283    ed.move_cursor_to(cursor)
284}
285
286fn find_char(buf: &Buffer, start: usize, ch: char, count: usize) -> Option<usize> {
287    assert!(count > 0);
288    buf.chars()
289        .enumerate()
290        .skip(start)
291        .filter(|&(_, &c)| c == ch)
292        .nth(count - 1)
293        .map(|(i, _)| i)
294}
295
296fn find_char_rev(buf: &Buffer, start: usize, ch: char, count: usize) -> Option<usize> {
297    assert!(count > 0);
298    let rstart = buf.num_chars() - start;
299    buf.chars()
300        .enumerate()
301        .rev()
302        .skip(rstart)
303        .filter(|&(_, &c)| c == ch)
304        .nth(count - 1)
305        .map(|(i, _)| i)
306}
307
308/// Vi keybindings for `Editor`.
309///
310/// ```
311/// use liner::*;
312/// let mut context = Context::new();
313/// context.key_bindings = KeyBindings::Vi;
314/// ```
315pub struct Vi {
316    mode_stack: ModeStack,
317    current_command: Vec<Key>,
318    last_command: Vec<Key>,
319    current_insert: Option<Key>,
320    last_insert: Option<Key>,
321    count: u32,
322    secondary_count: u32,
323    last_count: u32,
324    movement_reset: bool,
325    last_char_movement: Option<(char, CharMovement)>,
326}
327
328impl Default for Vi {
329    fn default() -> Self {
330        Vi {
331            mode_stack: ModeStack::with_insert(),
332            current_command: Vec::new(),
333            last_command: Vec::new(),
334            current_insert: None,
335            // we start vi in insert mode
336            last_insert: Some(Key::Char('i')),
337            count: 0,
338            secondary_count: 0,
339            last_count: 0,
340            movement_reset: false,
341            last_char_movement: None,
342        }
343    }
344}
345
346impl Vi {
347    pub fn new() -> Self {
348        Self::default()
349    }
350
351    /// Get the current mode.
352    fn mode(&self) -> Mode {
353        self.mode_stack.mode()
354    }
355
356    fn set_mode<W: Write>(&mut self, mode: Mode, ed: &mut Editor<'_, W>) -> io::Result<()> {
357        use self::Mode::*;
358        self.set_mode_preserve_last(mode, ed)?;
359        if mode == Insert {
360            self.last_count = 0;
361            self.last_command.clear();
362        }
363        Ok(())
364    }
365
366    fn set_editor_mode<W: Write>(&self, ed: &mut Editor<'_, W>) -> io::Result<()> {
367        use crate::editor::ViPromptMode;
368        use Mode::*;
369        if let Some(mode) = match self.mode() {
370            Insert => Some(ViPromptMode::Insert),
371            Normal => Some(ViPromptMode::Normal),
372            _ => None, // Leave the last one
373        } {
374            ed.set_vi_mode(mode);
375            ed.display()
376        } else {
377            Ok(())
378        }
379    }
380
381    fn set_mode_preserve_last<W: Write>(
382        &mut self,
383        mode: Mode,
384        ed: &mut Editor<'_, W>,
385    ) -> io::Result<()> {
386        use self::Mode::*;
387
388        ed.no_eol = mode == Normal;
389        self.movement_reset = mode != Insert;
390        self.mode_stack.push(mode);
391        self.set_editor_mode(ed)?;
392
393        if mode == Insert || mode == Tilde {
394            ed.current_buffer_mut().start_undo_group();
395        }
396        Ok(())
397    }
398
399    fn pop_mode_after_movement<W: Write>(
400        &mut self,
401        move_type: MoveType,
402        ed: &mut Editor<'_, W>,
403    ) -> io::Result<()> {
404        use self::Mode::*;
405        use self::MoveType::*;
406
407        let original_mode = self.mode_stack.pop();
408        let last_mode = {
409            // after popping, if mode is delete or change, pop that too. This is used for movements
410            // with sub commands like 't' (MoveToChar) and 'g' (G).
411            match self.mode() {
412                Delete(_) => self.mode_stack.pop(),
413                _ => original_mode,
414            }
415        };
416
417        ed.no_eol = self.mode() == Normal;
418        self.movement_reset = self.mode() != Insert;
419
420        if let Delete(start_pos) = last_mode {
421            // perform the delete operation
422            match move_type {
423                Exclusive => ed.delete_until(start_pos)?,
424                Inclusive => ed.delete_until_inclusive(start_pos)?,
425            }
426
427            // update the last state
428            mem::swap(&mut self.last_command, &mut self.current_command);
429            self.last_insert = self.current_insert;
430            self.last_count = self.count;
431
432            // reset our counts
433            self.count = 0;
434            self.secondary_count = 0;
435        }
436
437        // in normal mode, count goes back to 0 after movement
438        if original_mode == Normal {
439            self.count = 0;
440        }
441
442        self.set_editor_mode(ed)
443    }
444
445    fn pop_mode<W: Write>(&mut self, ed: &mut Editor<'_, W>) -> io::Result<()> {
446        use self::Mode::*;
447
448        let last_mode = self.mode_stack.pop();
449        ed.no_eol = self.mode() == Normal;
450        self.movement_reset = self.mode() != Insert;
451
452        if last_mode == Insert || last_mode == Tilde {
453            ed.current_buffer_mut().end_undo_group();
454        }
455
456        if last_mode == Tilde {
457            ed.display().unwrap();
458        }
459        self.set_editor_mode(ed)
460    }
461
462    /// Return to normal mode.
463    fn normal_mode_abort<W: Write>(&mut self, ed: &mut Editor<'_, W>) -> io::Result<()> {
464        self.mode_stack.clear();
465        ed.no_eol = true;
466        self.count = 0;
467        self.set_editor_mode(ed)
468    }
469
470    /// When doing a move, 0 should behave the same as 1 as far as the count goes.
471    fn move_count(&self) -> usize {
472        match self.count {
473            0 => 1,
474            _ => self.count as usize,
475        }
476    }
477
478    /// Get the current count or the number of remaining chars in the buffer.
479    fn move_count_left<W: Write>(&self, ed: &Editor<'_, W>) -> usize {
480        cmp::min(ed.cursor(), self.move_count())
481    }
482
483    /// Get the current count or the number of remaining chars in the buffer.
484    fn move_count_right<W: Write>(&self, ed: &Editor<'_, W>) -> usize {
485        cmp::min(
486            ed.current_buffer().num_chars() - ed.cursor(),
487            self.move_count(),
488        )
489    }
490
491    fn repeat<W: Write>(&mut self, ed: &mut Editor<'_, W>) -> io::Result<()> {
492        self.last_count = self.count;
493        let keys = mem::take(&mut self.last_command);
494
495        if let Some(insert_key) = self.last_insert {
496            // enter insert mode if necessary
497            self.handle_key_core(insert_key, ed)?;
498        }
499
500        for k in &keys {
501            self.handle_key_core(*k, ed)?;
502        }
503
504        if self.last_insert.is_some() {
505            // leave insert mode
506            self.handle_key_core(Key::Esc, ed)?;
507        }
508
509        // restore the last command
510        self.last_command = keys;
511
512        Ok(())
513    }
514
515    fn handle_key_common<W: Write>(&mut self, key: Key, ed: &mut Editor<'_, W>) -> io::Result<()> {
516        match key {
517            Key::Ctrl('l') => ed.clear(),
518            Key::Left => ed.move_cursor_left(1),
519            Key::Right => ed.move_cursor_right(1),
520            Key::Up => ed.move_up(),
521            Key::Down => ed.move_down(),
522            Key::Home => ed.move_cursor_to_start_of_line(),
523            Key::End => ed.move_cursor_to_end_of_line(),
524            Key::Backspace => ed.delete_before_cursor(),
525            Key::Delete => ed.delete_after_cursor(),
526            Key::Null => Ok(()),
527            _ => Ok(()),
528        }
529    }
530
531    fn handle_key_insert<W: Write>(&mut self, key: Key, ed: &mut Editor<'_, W>) -> io::Result<()> {
532        match key {
533            Key::Esc | Key::Ctrl('[') => {
534                // perform any repeats
535                if self.count > 0 {
536                    self.last_count = self.count;
537                    for _ in 1..self.count {
538                        let keys = mem::take(&mut self.last_command);
539                        for k in keys {
540                            self.handle_key_core(k, ed)?;
541                        }
542                    }
543                    self.count = 0;
544                }
545                // cursor moves to the left when switching from insert to normal mode
546                ed.move_cursor_left(1)?;
547                self.pop_mode(ed)
548            }
549            Key::Char(c) => {
550                if self.movement_reset {
551                    ed.current_buffer_mut().end_undo_group();
552                    ed.current_buffer_mut().start_undo_group();
553                    self.last_command.clear();
554                    self.movement_reset = false;
555                    // vim behaves as if this was 'i'
556                    self.last_insert = Some(Key::Char('i'));
557                }
558                self.last_command.push(key);
559                ed.insert_after_cursor(c)
560            }
561            // delete and backspace need to be included in the command buffer
562            Key::Backspace | Key::Delete => {
563                if self.movement_reset {
564                    ed.current_buffer_mut().end_undo_group();
565                    ed.current_buffer_mut().start_undo_group();
566                    self.last_command.clear();
567                    self.movement_reset = false;
568                    // vim behaves as if this was 'i'
569                    self.last_insert = Some(Key::Char('i'));
570                }
571                self.last_command.push(key);
572                self.handle_key_common(key, ed)
573            }
574            // if this is a movement while in insert mode, reset the repeat count
575            Key::Left | Key::Right | Key::Home | Key::End => {
576                self.count = 0;
577                self.movement_reset = true;
578                self.handle_key_common(key, ed)
579            }
580            // up and down require even more special handling
581            Key::Up => {
582                self.count = 0;
583                self.movement_reset = true;
584                ed.current_buffer_mut().end_undo_group();
585                ed.move_up()?;
586                ed.current_buffer_mut().start_undo_group();
587                Ok(())
588            }
589            Key::Down => {
590                self.count = 0;
591                self.movement_reset = true;
592                ed.current_buffer_mut().end_undo_group();
593                ed.move_down()?;
594                ed.current_buffer_mut().start_undo_group();
595                Ok(())
596            }
597            _ => self.handle_key_common(key, ed),
598        }
599    }
600
601    fn handle_key_normal<W: Write>(&mut self, key: Key, ed: &mut Editor<'_, W>) -> io::Result<()> {
602        use self::CharMovement::*;
603        use self::Mode::*;
604        use self::MoveType::*;
605
606        match key {
607            Key::Esc => {
608                self.count = 0;
609                Ok(())
610            }
611            Key::Char('i') => {
612                self.last_insert = Some(key);
613                self.set_mode(Insert, ed)
614            }
615            Key::Char('a') => {
616                self.last_insert = Some(key);
617                self.set_mode(Insert, ed)?;
618                ed.move_cursor_right(1)
619            }
620            Key::Char('A') => {
621                self.last_insert = Some(key);
622                self.set_mode(Insert, ed)?;
623                ed.move_cursor_to_end_of_line()
624            }
625            Key::Char('I') => {
626                self.last_insert = Some(key);
627                self.set_mode(Insert, ed)?;
628                ed.move_cursor_to_start_of_line()
629            }
630            Key::Char('s') => {
631                self.last_insert = Some(key);
632                self.set_mode(Insert, ed)?;
633                let pos = ed.cursor() + self.move_count_right(ed);
634                ed.delete_until(pos)?;
635                self.last_count = self.count;
636                self.count = 0;
637                Ok(())
638            }
639            Key::Char('r') => self.set_mode(Replace, ed),
640            Key::Char('d') | Key::Char('c') => {
641                self.current_command.clear();
642
643                if key == Key::Char('d') {
644                    // handle special 'd' key stuff
645                    self.current_insert = None;
646                    self.current_command.push(key);
647                } else {
648                    // handle special 'c' key stuff
649                    self.current_insert = Some(key);
650                    self.current_command.clear();
651                    self.set_mode(Insert, ed)?;
652                }
653
654                let start_pos = ed.cursor();
655                self.set_mode(Delete(start_pos), ed)?;
656                self.secondary_count = self.count;
657                self.count = 0;
658                Ok(())
659            }
660            Key::Char('D') => {
661                // update the last command state
662                self.last_insert = None;
663                self.last_command.clear();
664                self.last_command.push(key);
665                self.count = 0;
666                self.last_count = 0;
667
668                ed.delete_all_after_cursor()
669            }
670            Key::Char('C') => {
671                // update the last command state
672                self.last_insert = None;
673                self.last_command.clear();
674                self.last_command.push(key);
675                self.count = 0;
676                self.last_count = 0;
677
678                self.set_mode_preserve_last(Insert, ed)?;
679                ed.delete_all_after_cursor()
680            }
681            Key::Char('.') => {
682                // repeat the last command
683                self.count = match (self.count, self.last_count) {
684                    // if both count and last_count are zero, use 1
685                    (0, 0) => 1,
686                    // if count is zero, use last_count
687                    (0, _) => self.last_count,
688                    // otherwise use count
689                    (_, _) => self.count,
690                };
691                self.repeat(ed)
692            }
693            Key::Char('h') | Key::Left | Key::Backspace => {
694                let count = self.move_count_left(ed);
695                ed.move_cursor_left(count)?;
696                self.pop_mode_after_movement(Exclusive, ed)
697            }
698            Key::Char('l') | Key::Right | Key::Char(' ') => {
699                let count = self.move_count_right(ed);
700                ed.move_cursor_right(count)?;
701                self.pop_mode_after_movement(Exclusive, ed)
702            }
703            Key::Char('k') | Key::Up => {
704                ed.move_up()?;
705                self.pop_mode_after_movement(Exclusive, ed)
706            }
707            Key::Char('j') | Key::Down => {
708                ed.move_down()?;
709                self.pop_mode_after_movement(Exclusive, ed)
710            }
711            Key::Char('t') => self.set_mode(MoveToChar(RightUntil), ed),
712            Key::Char('T') => self.set_mode(MoveToChar(LeftUntil), ed),
713            Key::Char('f') => self.set_mode(MoveToChar(RightAt), ed),
714            Key::Char('F') => self.set_mode(MoveToChar(LeftAt), ed),
715            Key::Char(';') => self.handle_key_move_to_char(key, Repeat, ed),
716            Key::Char(',') => self.handle_key_move_to_char(key, ReverseRepeat, ed),
717            Key::Char('w') => {
718                let count = self.move_count();
719                move_word(ed, count)?;
720                self.pop_mode_after_movement(Exclusive, ed)
721            }
722            Key::Char('W') => {
723                let count = self.move_count();
724                move_word_ws(ed, count)?;
725                self.pop_mode_after_movement(Exclusive, ed)
726            }
727            Key::Char('e') => {
728                let count = self.move_count();
729                move_to_end_of_word(ed, count)?;
730                self.pop_mode_after_movement(Exclusive, ed)
731            }
732            Key::Char('E') => {
733                let count = self.move_count();
734                move_to_end_of_word_ws(ed, count)?;
735                self.pop_mode_after_movement(Exclusive, ed)
736            }
737            Key::Char('b') => {
738                let count = self.move_count();
739                move_word_back(ed, count)?;
740                self.pop_mode_after_movement(Exclusive, ed)
741            }
742            Key::Char('B') => {
743                let count = self.move_count();
744                move_word_ws_back(ed, count)?;
745                self.pop_mode_after_movement(Exclusive, ed)
746            }
747            Key::Char('g') => self.set_mode(G, ed),
748            // if count is 0, 0 should move to start of line
749            Key::Char('0') if self.count == 0 => {
750                ed.move_cursor_to_start_of_line()?;
751                self.pop_mode_after_movement(Exclusive, ed)
752            }
753            Key::Char(i @ '0'..='9') => {
754                let i = i.to_digit(10).unwrap();
755                // count = count * 10 + i
756                self.count = self.count.saturating_mul(10).saturating_add(i);
757                Ok(())
758            }
759            Key::Char('^') => {
760                ed.move_cursor_to_start_of_line()?;
761                self.pop_mode_after_movement(Exclusive, ed)
762            }
763            Key::Char('$') => {
764                ed.move_cursor_to_end_of_line()?;
765                self.pop_mode_after_movement(Exclusive, ed)
766            }
767            Key::Char('x') | Key::Delete => {
768                // update the last command state
769                self.last_insert = None;
770                self.last_command.clear();
771                self.last_command.push(key);
772                self.last_count = self.count;
773
774                let pos = ed.cursor() + self.move_count_right(ed);
775                ed.delete_until(pos)?;
776                self.count = 0;
777                Ok(())
778            }
779            Key::Char('~') => {
780                // update the last command state
781                self.last_insert = None;
782                self.last_command.clear();
783                self.last_command.push(key);
784                self.last_count = self.count;
785
786                self.set_mode(Tilde, ed)?;
787                for _ in 0..self.move_count_right(ed) {
788                    let c = ed.current_buffer().char_after(ed.cursor()).unwrap();
789                    if c.is_lowercase() {
790                        ed.delete_after_cursor()?;
791                        for c in c.to_uppercase() {
792                            ed.insert_after_cursor(c)?;
793                        }
794                    } else if c.is_uppercase() {
795                        ed.delete_after_cursor()?;
796                        for c in c.to_lowercase() {
797                            ed.insert_after_cursor(c)?;
798                        }
799                    } else {
800                        ed.move_cursor_right(1)?;
801                    }
802                }
803                self.pop_mode(ed)
804            }
805            Key::Char('u') => {
806                let count = self.move_count();
807                self.count = 0;
808                for _ in 0..count {
809                    if !ed.undo()? {
810                        break;
811                    }
812                }
813                Ok(())
814            }
815            Key::Ctrl('r') => {
816                let count = self.move_count();
817                self.count = 0;
818                for _ in 0..count {
819                    let did = ed.redo()?;
820                    if !did {
821                        break;
822                    }
823                }
824                Ok(())
825            }
826            _ => self.handle_key_common(key, ed),
827        }
828    }
829
830    fn handle_key_replace<W: Write>(&mut self, key: Key, ed: &mut Editor<'_, W>) -> io::Result<()> {
831        match key {
832            Key::Char(c) => {
833                // make sure there are enough chars to replace
834                if self.move_count_right(ed) == self.move_count() {
835                    // update the last command state
836                    self.last_insert = None;
837                    self.last_command.clear();
838                    self.last_command.push(Key::Char('r'));
839                    self.last_command.push(key);
840                    self.last_count = self.count;
841
842                    // replace count characters
843                    ed.current_buffer_mut().start_undo_group();
844                    for _ in 0..self.move_count_right(ed) {
845                        ed.delete_after_cursor()?;
846                        ed.insert_after_cursor(c)?;
847                    }
848                    ed.current_buffer_mut().end_undo_group();
849
850                    ed.move_cursor_left(1)?;
851                }
852                self.pop_mode(ed)?;
853            }
854            // not a char
855            _ => {
856                self.normal_mode_abort(ed)?;
857            }
858        };
859
860        // back to normal mode
861        self.count = 0;
862        Ok(())
863    }
864
865    fn handle_key_delete_or_change<W: Write>(
866        &mut self,
867        key: Key,
868        ed: &mut Editor<'_, W>,
869    ) -> io::Result<()> {
870        match (key, self.current_insert) {
871            // check if this is a movement key
872            (key, _) if is_movement_key(key) | (key == Key::Char('0') && self.count == 0) => {
873                // set count
874                self.count = match (self.count, self.secondary_count) {
875                    (0, 0) => 0,
876                    (_, 0) => self.count,
877                    (0, _) => self.secondary_count,
878                    _ => {
879                        // secondary_count * count
880                        self.secondary_count.saturating_mul(self.count)
881                    }
882                };
883
884                // update the last command state
885                self.current_command.push(key);
886
887                // execute movement
888                self.handle_key_normal(key, ed)
889            }
890            // handle numeric keys
891            (Key::Char('0'..='9'), _) => self.handle_key_normal(key, ed),
892            (Key::Char('c'), Some(Key::Char('c'))) | (Key::Char('d'), None) => {
893                // updating the last command buffer doesn't really make sense in this context.
894                // Repeating 'dd' will simply erase and already erased line. Any other commands
895                // will then become the new last command and the user will need to press 'dd' again
896                // to clear the line. The same largely applies to the 'cc' command. We update the
897                // last command here anyway ¯\_(ツ)_/¯
898                self.current_command.push(key);
899
900                // delete the whole line
901                self.count = 0;
902                self.secondary_count = 0;
903                ed.move_cursor_to_start_of_line()?;
904                ed.delete_all_after_cursor()?;
905
906                // return to the previous mode
907                self.pop_mode(ed)
908            }
909            // not a delete or change command, back to normal mode
910            _ => self.normal_mode_abort(ed),
911        }
912    }
913
914    fn handle_key_move_to_char<W: Write>(
915        &mut self,
916        key: Key,
917        movement: CharMovement,
918        ed: &mut Editor<'_, W>,
919    ) -> io::Result<()> {
920        use self::CharMovement::*;
921        use self::MoveType::*;
922
923        let count = self.move_count();
924        self.count = 0;
925
926        let (key, movement) = match (key, movement, self.last_char_movement) {
927            // repeat the last movement
928            (_, Repeat, Some((c, last_movement))) => (Key::Char(c), last_movement),
929            // repeat the last movement in the opposite direction
930            (_, ReverseRepeat, Some((c, LeftUntil))) => (Key::Char(c), RightUntil),
931            (_, ReverseRepeat, Some((c, RightUntil))) => (Key::Char(c), LeftUntil),
932            (_, ReverseRepeat, Some((c, LeftAt))) => (Key::Char(c), RightAt),
933            (_, ReverseRepeat, Some((c, RightAt))) => (Key::Char(c), LeftAt),
934            // repeat with no last_char_movement, invalid
935            (_, Repeat, None) | (_, ReverseRepeat, None) => {
936                return self.normal_mode_abort(ed);
937            }
938            // pass valid keys through as is
939            (Key::Char(c), _, _) => {
940                // store last command info
941                self.last_char_movement = Some((c, movement));
942                self.current_command.push(key);
943                (key, movement)
944            }
945            // all other combinations are invalid, abort
946            _ => {
947                return self.normal_mode_abort(ed);
948            }
949        };
950
951        match key {
952            Key::Char(c) => {
953                let move_type;
954                match movement {
955                    RightUntil => {
956                        move_type = Inclusive;
957                        match find_char(ed.current_buffer(), ed.cursor() + 1, c, count) {
958                            Some(i) => ed.move_cursor_to(i - 1),
959                            None => Ok(()),
960                        }
961                    }
962                    RightAt => {
963                        move_type = Inclusive;
964                        match find_char(ed.current_buffer(), ed.cursor() + 1, c, count) {
965                            Some(i) => ed.move_cursor_to(i),
966                            None => Ok(()),
967                        }
968                    }
969                    LeftUntil => {
970                        move_type = Exclusive;
971                        match find_char_rev(ed.current_buffer(), ed.cursor(), c, count) {
972                            Some(i) => ed.move_cursor_to(i + 1),
973                            None => Ok(()),
974                        }
975                    }
976                    LeftAt => {
977                        move_type = Exclusive;
978                        match find_char_rev(ed.current_buffer(), ed.cursor(), c, count) {
979                            Some(i) => ed.move_cursor_to(i),
980                            None => Ok(()),
981                        }
982                    }
983                    Repeat | ReverseRepeat => unreachable!(),
984                }?;
985
986                // go back to the previous mode
987                self.pop_mode_after_movement(move_type, ed)
988            }
989
990            // can't get here due to our match above
991            _ => unreachable!(),
992        }
993    }
994
995    fn handle_key_g<W: Write>(&mut self, key: Key, ed: &mut Editor<'_, W>) -> io::Result<()> {
996        use self::MoveType::*;
997
998        let count = self.move_count();
999        self.current_command.push(key);
1000
1001        let res = match key {
1002            Key::Char('e') => {
1003                move_to_end_of_word_back(ed, count)?;
1004                self.pop_mode_after_movement(Inclusive, ed)
1005            }
1006            Key::Char('E') => {
1007                move_to_end_of_word_ws_back(ed, count)?;
1008                self.pop_mode_after_movement(Inclusive, ed)
1009            }
1010
1011            // not a supported command
1012            _ => self.normal_mode_abort(ed),
1013        };
1014
1015        self.count = 0;
1016        res
1017    }
1018}
1019
1020impl KeyMap for Vi {
1021    fn init<W: Write>(&mut self, ed: &mut Editor<'_, W>) {
1022        // since we start in insert mode, we need to start an undo group
1023        ed.current_buffer_mut().start_undo_group();
1024        let _ = self.set_editor_mode(ed);
1025    }
1026
1027    fn handle_key_core<W: Write>(&mut self, key: Key, ed: &mut Editor<'_, W>) -> io::Result<()> {
1028        match self.mode() {
1029            Mode::Normal => self.handle_key_normal(key, ed),
1030            Mode::Insert => self.handle_key_insert(key, ed),
1031            Mode::Replace => self.handle_key_replace(key, ed),
1032            Mode::Delete(_) => self.handle_key_delete_or_change(key, ed),
1033            Mode::MoveToChar(movement) => self.handle_key_move_to_char(key, movement, ed),
1034            Mode::G => self.handle_key_g(key, ed),
1035            Mode::Tilde => unreachable!(),
1036        }
1037    }
1038}
1039
1040#[cfg(test)]
1041mod tests {
1042    use super::*;
1043    use crate::editor::Prompt;
1044    use crate::{Buffer, Completer, Context, Editor, KeyMap};
1045    use std::io::Write;
1046    use termion::event::Key;
1047    use termion::event::Key::*;
1048
1049    fn simulate_keys<'a, 'b, W: Write, M: KeyMap, I>(
1050        keymap: &mut M,
1051        ed: &mut Editor<'a, W>,
1052        keys: I,
1053    ) -> bool
1054    where
1055        I: IntoIterator<Item = &'b Key>,
1056    {
1057        for k in keys {
1058            if keymap.handle_key(*k, ed, &mut EmptyCompleter).unwrap() {
1059                return true;
1060            }
1061        }
1062
1063        false
1064    }
1065
1066    struct EmptyCompleter;
1067
1068    impl Completer for EmptyCompleter {
1069        fn completions(&mut self, _start: &str) -> Vec<String> {
1070            Vec::default()
1071        }
1072    }
1073
1074    // Editor::new(out, "prompt".to_owned(), &mut context).unwrap()
1075
1076    #[test]
1077    fn enter_is_done() {
1078        let mut context = Context::new();
1079        let out = Vec::new();
1080        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
1081        let mut map = Vi::new();
1082        map.init(&mut ed);
1083        ed.insert_str_after_cursor("done").unwrap();
1084        assert_eq!(ed.cursor(), 4);
1085
1086        assert!(simulate_keys(&mut map, &mut ed, [Char('\n'),].iter()));
1087
1088        assert_eq!(ed.cursor(), 4);
1089        assert_eq!(String::from(ed), "done");
1090    }
1091
1092    #[test]
1093    fn move_cursor_left() {
1094        let mut context = Context::new();
1095        let out = Vec::new();
1096        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
1097        let mut map = Vi::new();
1098        map.init(&mut ed);
1099        ed.insert_str_after_cursor("let").unwrap();
1100        assert_eq!(ed.cursor(), 3);
1101
1102        simulate_keys(&mut map, &mut ed, [Left, Char('f')].iter());
1103
1104        assert_eq!(ed.cursor(), 3);
1105        assert_eq!(String::from(ed), "left");
1106    }
1107
1108    #[test]
1109    fn cursor_movement() {
1110        let mut context = Context::new();
1111        let out = Vec::new();
1112        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
1113        let mut map = Vi::new();
1114        map.init(&mut ed);
1115        ed.insert_str_after_cursor("right").unwrap();
1116        assert_eq!(ed.cursor(), 5);
1117
1118        simulate_keys(&mut map, &mut ed, [Left, Left, Right].iter());
1119
1120        assert_eq!(ed.cursor(), 4);
1121    }
1122
1123    #[test]
1124    fn move_cursor_start_end() {
1125        let mut context = Context::new();
1126        let out = Vec::new();
1127        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
1128        let mut map = Vi::new();
1129        map.init(&mut ed);
1130        let test_str = "let there be tests";
1131        ed.insert_str_after_cursor(test_str).unwrap();
1132        assert_eq!(ed.cursor(), test_str.len());
1133
1134        simulate_keys(&mut map, &mut ed, [Esc, Char('^')].iter());
1135        assert_eq!(ed.cursor(), 0);
1136
1137        simulate_keys(&mut map, &mut ed, [Char('^')].iter());
1138        assert_eq!(ed.cursor(), 0);
1139
1140        simulate_keys(&mut map, &mut ed, [Char('$')].iter());
1141        assert_eq!(ed.cursor(), test_str.len() - 1);
1142
1143        simulate_keys(&mut map, &mut ed, [Char('$')].iter());
1144        assert_eq!(ed.cursor(), test_str.len() - 1);
1145    }
1146
1147    #[test]
1148    fn vi_initial_insert() {
1149        let mut context = Context::new();
1150        let out = Vec::new();
1151        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
1152        let mut map = Vi::new();
1153        map.init(&mut ed);
1154
1155        simulate_keys(
1156            &mut map,
1157            &mut ed,
1158            [
1159                Char('i'),
1160                Char('n'),
1161                Char('s'),
1162                Char('e'),
1163                Char('r'),
1164                Char('t'),
1165            ]
1166            .iter(),
1167        );
1168
1169        assert_eq!(ed.cursor(), 6);
1170        assert_eq!(String::from(ed), "insert");
1171    }
1172
1173    #[test]
1174    fn vi_left_right_movement() {
1175        let mut context = Context::new();
1176        let out = Vec::new();
1177        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
1178        let mut map = Vi::new();
1179        map.init(&mut ed);
1180        ed.insert_str_after_cursor("data").unwrap();
1181        assert_eq!(ed.cursor(), 4);
1182
1183        simulate_keys(&mut map, &mut ed, [Left].iter());
1184        assert_eq!(ed.cursor(), 3);
1185        simulate_keys(&mut map, &mut ed, [Right].iter());
1186        assert_eq!(ed.cursor(), 4);
1187
1188        // switching from insert mode moves the cursor left
1189        simulate_keys(&mut map, &mut ed, [Esc, Left].iter());
1190        assert_eq!(ed.cursor(), 2);
1191        simulate_keys(&mut map, &mut ed, [Right].iter());
1192        assert_eq!(ed.cursor(), 3);
1193
1194        simulate_keys(&mut map, &mut ed, [Char('h')].iter());
1195        assert_eq!(ed.cursor(), 2);
1196        simulate_keys(&mut map, &mut ed, [Char('l')].iter());
1197        assert_eq!(ed.cursor(), 3);
1198    }
1199
1200    #[test]
1201    /// Shouldn't be able to move past the last char in vi normal mode
1202    fn vi_no_eol() {
1203        let mut context = Context::new();
1204        let out = Vec::new();
1205        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
1206        let mut map = Vi::new();
1207        map.init(&mut ed);
1208        ed.insert_str_after_cursor("data").unwrap();
1209        assert_eq!(ed.cursor(), 4);
1210
1211        simulate_keys(&mut map, &mut ed, [Esc].iter());
1212        assert_eq!(ed.cursor(), 3);
1213
1214        simulate_keys(&mut map, &mut ed, [Right, Right].iter());
1215        assert_eq!(ed.cursor(), 3);
1216
1217        // in insert mode, we can move past the last char, but no further
1218        simulate_keys(&mut map, &mut ed, [Char('i'), Right, Right].iter());
1219        assert_eq!(ed.cursor(), 4);
1220    }
1221
1222    #[test]
1223    /// Cursor moves left when exiting insert mode.
1224    fn vi_switch_from_insert() {
1225        let mut context = Context::new();
1226        let out = Vec::new();
1227        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
1228        let mut map = Vi::new();
1229        map.init(&mut ed);
1230        ed.insert_str_after_cursor("data").unwrap();
1231        assert_eq!(ed.cursor(), 4);
1232
1233        simulate_keys(&mut map, &mut ed, [Esc].iter());
1234        assert_eq!(ed.cursor(), 3);
1235
1236        simulate_keys(
1237            &mut map,
1238            &mut ed,
1239            [
1240                Char('i'),
1241                Esc,
1242                Char('i'),
1243                //Ctrl+[ is the same as escape
1244                Ctrl('['),
1245                Char('i'),
1246                Esc,
1247                Char('i'),
1248                Ctrl('['),
1249            ]
1250            .iter(),
1251        );
1252        assert_eq!(ed.cursor(), 0);
1253    }
1254
1255    #[test]
1256    fn vi_normal_history_cursor_eol() {
1257        let mut context = Context::new();
1258        context.history.push("data hostory".into()).unwrap();
1259        context.history.push("data history".into()).unwrap();
1260        let out = Vec::new();
1261        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
1262        let mut map = Vi::new();
1263        map.init(&mut ed);
1264        ed.insert_str_after_cursor("data").unwrap();
1265        assert_eq!(ed.cursor(), 4);
1266
1267        simulate_keys(&mut map, &mut ed, [Up].iter());
1268        assert_eq!(ed.cursor(), 12);
1269
1270        // in normal mode, make sure we don't end up past the last char
1271        simulate_keys(&mut map, &mut ed, [Ctrl('['), Up].iter());
1272        assert_eq!(ed.cursor(), 11);
1273    }
1274
1275    #[test]
1276    fn vi_normal_history() {
1277        let mut context = Context::new();
1278        context.history.push("data second".into()).unwrap();
1279        context.history.push("skip1".into()).unwrap();
1280        context.history.push("data one".into()).unwrap();
1281        context.history.push("skip2".into()).unwrap();
1282        let out = Vec::new();
1283        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
1284        let mut map = Vi::new();
1285        map.init(&mut ed);
1286        ed.insert_str_after_cursor("data").unwrap();
1287        assert_eq!(ed.cursor(), 4);
1288
1289        simulate_keys(&mut map, &mut ed, [Up].iter());
1290        assert_eq!(ed.cursor(), 8);
1291
1292        // in normal mode, make sure we don't end up past the last char
1293        simulate_keys(&mut map, &mut ed, [Ctrl('['), Char('k')].iter());
1294        assert_eq!(ed.cursor(), 10);
1295    }
1296
1297    #[test]
1298    fn vi_search_history() {
1299        // Test incremental search as well as vi binding in search mode.
1300        let mut context = Context::new();
1301        context.history.push("data pat second".into()).unwrap();
1302        context.history.push("skip1".into()).unwrap();
1303        context.history.push("data pat one".into()).unwrap();
1304        context.history.push("skip2".into()).unwrap();
1305        let out = Vec::new();
1306        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
1307        let mut map = Vi::new();
1308        map.init(&mut ed);
1309        ed.insert_str_after_cursor("pat").unwrap();
1310        assert_eq!(ed.cursor(), 3);
1311        simulate_keys(&mut map, &mut ed, [Ctrl('r'), Right].iter());
1312        assert_eq!(ed.cursor(), 12);
1313
1314        //simulate_keys(&mut map,     &mut ed, [Ctrl('['), Char('u'), Char('i')].iter());
1315        ed.delete_all_before_cursor().unwrap();
1316        assert_eq!(ed.cursor(), 0);
1317        //ed.insert_str_after_cursor("pat").unwrap();
1318        //assert_eq!(ed.cursor(), 3);
1319        simulate_keys(
1320            &mut map,
1321            &mut ed,
1322            [
1323                Ctrl('r'),
1324                Char('p'),
1325                Char('a'),
1326                Char('t'),
1327                Ctrl('['),
1328                Char('k'),
1329                Ctrl('f'),
1330            ]
1331            .iter(),
1332        );
1333        assert_eq!(ed.cursor(), 14);
1334
1335        simulate_keys(&mut map, &mut ed, [Ctrl('['), Char('u'), Char('i')].iter());
1336        assert_eq!(ed.cursor(), 0);
1337        simulate_keys(
1338            &mut map,
1339            &mut ed,
1340            [Ctrl('s'), Char('p'), Char('a'), Char('t'), Ctrl('f')].iter(),
1341        );
1342        assert_eq!(ed.cursor(), 15);
1343
1344        ed.delete_all_before_cursor().unwrap();
1345        assert_eq!(ed.cursor(), 0);
1346        ed.insert_str_after_cursor("pat").unwrap();
1347        assert_eq!(ed.cursor(), 3);
1348        simulate_keys(
1349            &mut map,
1350            &mut ed,
1351            [Ctrl('s'), Ctrl('['), Char('j'), Right].iter(),
1352        );
1353        assert_eq!(ed.cursor(), 11);
1354    }
1355
1356    #[test]
1357    fn vi_normal_delete() {
1358        let mut context = Context::new();
1359        context.history.push("history".into()).unwrap();
1360        context.history.push("history".into()).unwrap();
1361        let out = Vec::new();
1362        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
1363        let mut map = Vi::new();
1364        map.init(&mut ed);
1365        ed.insert_str_after_cursor("data").unwrap();
1366        assert_eq!(ed.cursor(), 4);
1367
1368        simulate_keys(
1369            &mut map,
1370            &mut ed,
1371            [Esc, Char('0'), Delete, Char('x')].iter(),
1372        );
1373        assert_eq!(ed.cursor(), 0);
1374        assert_eq!(String::from(ed), "ta");
1375    }
1376    #[test]
1377    fn vi_substitute_command() {
1378        let mut context = Context::new();
1379        let out = Vec::new();
1380        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
1381        let mut map = Vi::new();
1382        map.init(&mut ed);
1383        ed.insert_str_after_cursor("data").unwrap();
1384        assert_eq!(ed.cursor(), 4);
1385
1386        simulate_keys(
1387            &mut map,
1388            &mut ed,
1389            [
1390                //ctrl+[ is the same as Esc
1391                Ctrl('['),
1392                Char('0'),
1393                Char('s'),
1394                Char('s'),
1395            ]
1396            .iter(),
1397        );
1398        assert_eq!(String::from(ed), "sata");
1399    }
1400
1401    #[test]
1402    fn substitute_with_count() {
1403        let mut context = Context::new();
1404        let out = Vec::new();
1405        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
1406        let mut map = Vi::new();
1407        map.init(&mut ed);
1408        ed.insert_str_after_cursor("data").unwrap();
1409        assert_eq!(ed.cursor(), 4);
1410
1411        simulate_keys(
1412            &mut map,
1413            &mut ed,
1414            [Esc, Char('0'), Char('2'), Char('s'), Char('b'), Char('e')].iter(),
1415        );
1416        assert_eq!(String::from(ed), "beta");
1417    }
1418
1419    #[test]
1420    fn substitute_with_count_repeat() {
1421        let mut context = Context::new();
1422        let out = Vec::new();
1423        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
1424        let mut map = Vi::new();
1425        map.init(&mut ed);
1426        ed.insert_str_after_cursor("data data").unwrap();
1427
1428        simulate_keys(
1429            &mut map,
1430            &mut ed,
1431            [
1432                Esc,
1433                Char('0'),
1434                Char('2'),
1435                Char('s'),
1436                Char('b'),
1437                Char('e'),
1438                //The same as Esc
1439                Ctrl('['),
1440                Char('4'),
1441                Char('l'),
1442                Char('.'),
1443            ]
1444            .iter(),
1445        );
1446        assert_eq!(String::from(ed), "beta beta");
1447    }
1448
1449    #[test]
1450    /// make sure our count is accurate
1451    fn vi_count() {
1452        let mut context = Context::new();
1453        let out = Vec::new();
1454        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
1455        let mut map = Vi::new();
1456        map.init(&mut ed);
1457
1458        simulate_keys(&mut map, &mut ed, [Esc].iter());
1459        assert_eq!(map.count, 0);
1460
1461        simulate_keys(&mut map, &mut ed, [Char('1')].iter());
1462        assert_eq!(map.count, 1);
1463
1464        simulate_keys(&mut map, &mut ed, [Char('1')].iter());
1465        assert_eq!(map.count, 11);
1466
1467        // switching to insert mode and back to edit mode should reset the count
1468        simulate_keys(&mut map, &mut ed, [Char('i'), Esc].iter());
1469        assert_eq!(map.count, 0);
1470
1471        assert_eq!(String::from(ed), "");
1472    }
1473
1474    #[test]
1475    /// make sure large counts don't overflow
1476    fn vi_count_overflow() {
1477        let mut context = Context::new();
1478        let out = Vec::new();
1479        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
1480        let mut map = Vi::new();
1481        map.init(&mut ed);
1482
1483        // make sure large counts don't overflow our u32
1484        simulate_keys(
1485            &mut map,
1486            &mut ed,
1487            [
1488                Esc,
1489                Char('9'),
1490                Char('9'),
1491                Char('9'),
1492                Char('9'),
1493                Char('9'),
1494                Char('9'),
1495                Char('9'),
1496                Char('9'),
1497                Char('9'),
1498                Char('9'),
1499                Char('9'),
1500                Char('9'),
1501                Char('9'),
1502                Char('9'),
1503                Char('9'),
1504                Char('9'),
1505                Char('9'),
1506                Char('9'),
1507                Char('9'),
1508                Char('9'),
1509                Char('9'),
1510                Char('9'),
1511                Char('9'),
1512                Char('9'),
1513                Char('9'),
1514                Char('9'),
1515                Char('9'),
1516                Char('9'),
1517                Char('9'),
1518                Char('9'),
1519                Char('9'),
1520                Char('9'),
1521                Char('9'),
1522                Char('9'),
1523                Char('9'),
1524                Char('9'),
1525                Char('9'),
1526                Char('9'),
1527                Char('9'),
1528                Char('9'),
1529                Char('9'),
1530                Char('9'),
1531                Char('9'),
1532                Char('9'),
1533                Char('9'),
1534                Char('9'),
1535                Char('9'),
1536                Char('9'),
1537                Char('9'),
1538                Char('9'),
1539                Char('9'),
1540                Char('9'),
1541                Char('9'),
1542                Char('9'),
1543                Char('9'),
1544                Char('9'),
1545                Char('9'),
1546                Char('9'),
1547                Char('9'),
1548                Char('9'),
1549                Char('9'),
1550                Char('9'),
1551                Char('9'),
1552                Char('9'),
1553                Char('9'),
1554            ]
1555            .iter(),
1556        );
1557        assert_eq!(String::from(ed), "");
1558    }
1559
1560    #[test]
1561    /// make sure large counts ending in zero don't overflow
1562    fn vi_count_overflow_zero() {
1563        let mut context = Context::new();
1564        let out = Vec::new();
1565        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
1566        let mut map = Vi::new();
1567        map.init(&mut ed);
1568
1569        // make sure large counts don't overflow our u32
1570        simulate_keys(
1571            &mut map,
1572            &mut ed,
1573            [
1574                Esc,
1575                Char('1'),
1576                Char('0'),
1577                Char('0'),
1578                Char('0'),
1579                Char('0'),
1580                Char('0'),
1581                Char('0'),
1582                Char('0'),
1583                Char('0'),
1584                Char('0'),
1585                Char('0'),
1586                Char('0'),
1587                Char('0'),
1588                Char('0'),
1589                Char('0'),
1590                Char('0'),
1591                Char('0'),
1592                Char('0'),
1593                Char('0'),
1594                Char('0'),
1595                Char('0'),
1596                Char('0'),
1597                Char('0'),
1598                Char('0'),
1599                Char('0'),
1600                Char('0'),
1601                Char('0'),
1602                Char('0'),
1603                Char('0'),
1604                Char('0'),
1605                Char('0'),
1606                Char('0'),
1607                Char('0'),
1608                Char('0'),
1609                Char('0'),
1610                Char('0'),
1611                Char('0'),
1612                Char('0'),
1613                Char('0'),
1614                Char('0'),
1615                Char('0'),
1616                Char('0'),
1617                Char('0'),
1618                Char('0'),
1619                Char('0'),
1620                Char('0'),
1621                Char('0'),
1622                Char('0'),
1623                Char('0'),
1624                Char('0'),
1625                Char('0'),
1626                Char('0'),
1627                Char('0'),
1628                Char('0'),
1629                Char('0'),
1630                Char('0'),
1631                Char('0'),
1632                Char('0'),
1633                Char('0'),
1634                Char('0'),
1635            ]
1636            .iter(),
1637        );
1638        assert_eq!(String::from(ed), "");
1639    }
1640
1641    #[test]
1642    /// Esc should cancel the count
1643    fn vi_count_cancel() {
1644        let mut context = Context::new();
1645        let out = Vec::new();
1646        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
1647        let mut map = Vi::new();
1648        map.init(&mut ed);
1649
1650        simulate_keys(&mut map, &mut ed, [Esc, Char('1'), Char('0'), Esc].iter());
1651        assert_eq!(map.count, 0);
1652        assert_eq!(String::from(ed), "");
1653    }
1654
1655    #[test]
1656    /// test insert with a count
1657    fn vi_count_simple() {
1658        let mut context = Context::new();
1659        let out = Vec::new();
1660
1661        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
1662        let mut map = Vi::new();
1663        map.init(&mut ed);
1664
1665        simulate_keys(
1666            &mut map,
1667            &mut ed,
1668            [
1669                //same as Esc
1670                Ctrl('['),
1671                Char('3'),
1672                Char('i'),
1673                Char('t'),
1674                Char('h'),
1675                Char('i'),
1676                Char('s'),
1677                Esc,
1678            ]
1679            .iter(),
1680        );
1681        assert_eq!(String::from(ed), "thisthisthis");
1682    }
1683
1684    #[test]
1685    /// test dot command
1686    fn vi_dot_command() {
1687        let mut context = Context::new();
1688        let out = Vec::new();
1689        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
1690        let mut map = Vi::new();
1691        map.init(&mut ed);
1692
1693        simulate_keys(
1694            &mut map,
1695            &mut ed,
1696            [Char('i'), Char('f'), Esc, Char('.'), Char('.')].iter(),
1697        );
1698        assert_eq!(String::from(ed), "iiifff");
1699    }
1700
1701    #[test]
1702    /// test dot command with repeat
1703    fn vi_dot_command_repeat() {
1704        let mut context = Context::new();
1705        let out = Vec::new();
1706        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
1707        let mut map = Vi::new();
1708        map.init(&mut ed);
1709
1710        simulate_keys(
1711            &mut map,
1712            &mut ed,
1713            [Char('i'), Char('f'), Esc, Char('3'), Char('.')].iter(),
1714        );
1715        assert_eq!(String::from(ed), "iifififf");
1716    }
1717
1718    #[test]
1719    /// test dot command with repeat
1720    fn vi_dot_command_repeat_multiple() {
1721        let mut context = Context::new();
1722        let out = Vec::new();
1723        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
1724        let mut map = Vi::new();
1725        map.init(&mut ed);
1726
1727        simulate_keys(
1728            &mut map,
1729            &mut ed,
1730            [Char('i'), Char('f'), Esc, Char('3'), Char('.'), Char('.')].iter(),
1731        );
1732        assert_eq!(String::from(ed), "iififiifififff");
1733    }
1734
1735    #[test]
1736    /// test dot command with append
1737    fn vi_dot_command_append() {
1738        let mut context = Context::new();
1739        let out = Vec::new();
1740
1741        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
1742        let mut map = Vi::new();
1743        map.init(&mut ed);
1744
1745        simulate_keys(
1746            &mut map,
1747            &mut ed,
1748            [
1749                Esc,
1750                Char('a'),
1751                Char('i'),
1752                Char('f'),
1753                Esc,
1754                Char('.'),
1755                Char('.'),
1756            ]
1757            .iter(),
1758        );
1759        assert_eq!(String::from(ed), "ififif");
1760    }
1761
1762    #[test]
1763    /// test dot command with append and repeat
1764    fn vi_dot_command_append_repeat() {
1765        let mut context = Context::new();
1766        let out = Vec::new();
1767
1768        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
1769        let mut map = Vi::new();
1770        map.init(&mut ed);
1771
1772        simulate_keys(
1773            &mut map,
1774            &mut ed,
1775            [
1776                Esc,
1777                Char('a'),
1778                Char('i'),
1779                Char('f'),
1780                Esc,
1781                Char('3'),
1782                Char('.'),
1783            ]
1784            .iter(),
1785        );
1786        assert_eq!(String::from(ed), "ifififif");
1787    }
1788
1789    #[test]
1790    /// test dot command with movement
1791    fn vi_dot_command_movement() {
1792        let mut context = Context::new();
1793        let out = Vec::new();
1794
1795        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
1796        let mut map = Vi::new();
1797        map.init(&mut ed);
1798
1799        simulate_keys(
1800            &mut map,
1801            &mut ed,
1802            [
1803                Esc,
1804                Char('a'),
1805                Char('d'),
1806                Char('t'),
1807                Char(' '),
1808                Left,
1809                Left,
1810                Char('a'),
1811                Esc,
1812                Right,
1813                Right,
1814                Char('.'),
1815            ]
1816            .iter(),
1817        );
1818        assert_eq!(String::from(ed), "data ");
1819    }
1820
1821    #[test]
1822    /// test move_count function
1823    fn move_count() {
1824        let mut context = Context::new();
1825        let out = Vec::new();
1826        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
1827        let mut map = Vi::new();
1828        map.init(&mut ed);
1829
1830        assert_eq!(map.move_count(), 1);
1831        map.count = 1;
1832        assert_eq!(map.move_count(), 1);
1833        map.count = 99;
1834        assert_eq!(map.move_count(), 99);
1835    }
1836
1837    #[test]
1838    /// make sure the count is reset if movement occurs
1839    fn vi_count_movement_reset() {
1840        let mut context = Context::new();
1841        let out = Vec::new();
1842
1843        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
1844        let mut map = Vi::new();
1845        map.init(&mut ed);
1846
1847        simulate_keys(
1848            &mut map,
1849            &mut ed,
1850            [
1851                Esc,
1852                Char('3'),
1853                Char('i'),
1854                Char('t'),
1855                Char('h'),
1856                Char('i'),
1857                Char('s'),
1858                Left,
1859                Esc,
1860            ]
1861            .iter(),
1862        );
1863        assert_eq!(String::from(ed), "this");
1864    }
1865
1866    #[test]
1867    /// test movement with counts
1868    fn movement_with_count() {
1869        let mut context = Context::new();
1870        let out = Vec::new();
1871        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
1872        let mut map = Vi::new();
1873        map.init(&mut ed);
1874        ed.insert_str_after_cursor("right").unwrap();
1875        assert_eq!(ed.cursor(), 5);
1876
1877        simulate_keys(&mut map, &mut ed, [Esc, Char('3'), Left].iter());
1878
1879        assert_eq!(ed.cursor(), 1);
1880    }
1881
1882    #[test]
1883    /// test movement with counts, then insert (count should be reset before insert)
1884    fn movement_with_count_then_insert() {
1885        let mut context = Context::new();
1886        let out = Vec::new();
1887        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
1888        let mut map = Vi::new();
1889        map.init(&mut ed);
1890        ed.insert_str_after_cursor("right").unwrap();
1891        assert_eq!(ed.cursor(), 5);
1892
1893        simulate_keys(
1894            &mut map,
1895            &mut ed,
1896            [Esc, Char('3'), Left, Char('i'), Char(' '), Esc].iter(),
1897        );
1898        assert_eq!(String::from(ed), "r ight");
1899    }
1900
1901    #[test]
1902    /// make sure we only attempt to repeat for as many chars are in the buffer
1903    fn count_at_buffer_edge() {
1904        let mut context = Context::new();
1905        let out = Vec::new();
1906
1907        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
1908        let mut map = Vi::new();
1909        map.init(&mut ed);
1910        ed.insert_str_after_cursor("replace").unwrap();
1911        assert_eq!(ed.cursor(), 7);
1912
1913        simulate_keys(
1914            &mut map,
1915            &mut ed,
1916            [Esc, Char('3'), Char('r'), Char('x')].iter(),
1917        );
1918        // the cursor should not have moved and no change should have occured
1919        assert_eq!(ed.cursor(), 6);
1920        assert_eq!(String::from(ed), "replace");
1921    }
1922
1923    #[test]
1924    /// test basic replace
1925    fn basic_replace() {
1926        let mut context = Context::new();
1927        let out = Vec::new();
1928        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
1929        let mut map = Vi::new();
1930        map.init(&mut ed);
1931        ed.insert_str_after_cursor("replace").unwrap();
1932        assert_eq!(ed.cursor(), 7);
1933
1934        simulate_keys(&mut map, &mut ed, [Esc, Char('r'), Char('x')].iter());
1935        assert_eq!(ed.cursor(), 6);
1936        assert_eq!(String::from(ed), "replacx");
1937    }
1938
1939    #[test]
1940    fn replace_with_count() {
1941        let mut context = Context::new();
1942        let out = Vec::new();
1943
1944        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
1945        let mut map = Vi::new();
1946        map.init(&mut ed);
1947        ed.insert_str_after_cursor("replace").unwrap();
1948        assert_eq!(ed.cursor(), 7);
1949
1950        simulate_keys(
1951            &mut map,
1952            &mut ed,
1953            [Esc, Char('0'), Char('3'), Char('r'), Char(' ')].iter(),
1954        );
1955        // cursor should be on the last replaced char
1956        assert_eq!(ed.cursor(), 2);
1957        assert_eq!(String::from(ed), "   lace");
1958    }
1959
1960    #[test]
1961    /// make sure replace won't work if there aren't enough chars
1962    fn replace_with_count_eol() {
1963        let mut context = Context::new();
1964        let out = Vec::new();
1965
1966        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
1967        let mut map = Vi::new();
1968        map.init(&mut ed);
1969        ed.insert_str_after_cursor("replace").unwrap();
1970        assert_eq!(ed.cursor(), 7);
1971
1972        simulate_keys(
1973            &mut map,
1974            &mut ed,
1975            [Esc, Char('3'), Char('r'), Char('x')].iter(),
1976        );
1977        // the cursor should not have moved and no change should have occured
1978        assert_eq!(ed.cursor(), 6);
1979        assert_eq!(String::from(ed), "replace");
1980    }
1981
1982    #[test]
1983    /// make sure normal mode is enabled after replace
1984    fn replace_then_normal() {
1985        let mut context = Context::new();
1986        let out = Vec::new();
1987
1988        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
1989        let mut map = Vi::new();
1990        map.init(&mut ed);
1991        ed.insert_str_after_cursor("replace").unwrap();
1992        assert_eq!(ed.cursor(), 7);
1993
1994        simulate_keys(
1995            &mut map,
1996            &mut ed,
1997            [Esc, Char('r'), Char('x'), Char('0')].iter(),
1998        );
1999        assert_eq!(ed.cursor(), 0);
2000        assert_eq!(String::from(ed), "replacx");
2001    }
2002
2003    #[test]
2004    /// test replace with dot
2005    fn dot_replace() {
2006        let mut context = Context::new();
2007        let out = Vec::new();
2008
2009        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2010        let mut map = Vi::new();
2011        map.init(&mut ed);
2012        ed.insert_str_after_cursor("replace").unwrap();
2013        assert_eq!(ed.cursor(), 7);
2014
2015        simulate_keys(
2016            &mut map,
2017            &mut ed,
2018            [
2019                Esc,
2020                Char('0'),
2021                Char('r'),
2022                Char('x'),
2023                Char('.'),
2024                Char('.'),
2025                Char('7'),
2026                Char('.'),
2027            ]
2028            .iter(),
2029        );
2030        assert_eq!(String::from(ed), "xxxxxxx");
2031    }
2032
2033    #[test]
2034    /// test replace with dot
2035    fn dot_replace_count() {
2036        let mut context = Context::new();
2037        let out = Vec::new();
2038
2039        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2040        let mut map = Vi::new();
2041        map.init(&mut ed);
2042        ed.insert_str_after_cursor("replace").unwrap();
2043        assert_eq!(ed.cursor(), 7);
2044
2045        simulate_keys(
2046            &mut map,
2047            &mut ed,
2048            [
2049                Esc,
2050                Char('0'),
2051                Char('2'),
2052                Char('r'),
2053                Char('x'),
2054                Char('.'),
2055                Char('.'),
2056                Char('.'),
2057                Char('.'),
2058                Char('.'),
2059            ]
2060            .iter(),
2061        );
2062        assert_eq!(String::from(ed), "xxxxxxx");
2063    }
2064
2065    #[test]
2066    /// test replace with dot at eol
2067    fn dot_replace_eol() {
2068        let mut context = Context::new();
2069        let out = Vec::new();
2070
2071        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2072        let mut map = Vi::new();
2073        map.init(&mut ed);
2074        ed.insert_str_after_cursor("test").unwrap();
2075
2076        simulate_keys(
2077            &mut map,
2078            &mut ed,
2079            [
2080                Esc,
2081                Char('0'),
2082                Char('3'),
2083                Char('r'),
2084                Char('x'),
2085                Char('.'),
2086                Char('.'),
2087            ]
2088            .iter(),
2089        );
2090        assert_eq!(String::from(ed), "xxxt");
2091    }
2092
2093    #[test]
2094    /// test replace with dot at eol multiple times
2095    fn dot_replace_eol_multiple() {
2096        let mut context = Context::new();
2097        let out = Vec::new();
2098
2099        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2100        let mut map = Vi::new();
2101        map.init(&mut ed);
2102        ed.insert_str_after_cursor("this is a test").unwrap();
2103
2104        simulate_keys(
2105            &mut map,
2106            &mut ed,
2107            [
2108                Esc,
2109                Char('0'),
2110                Char('3'),
2111                Char('r'),
2112                Char('x'),
2113                Char('$'),
2114                Char('.'),
2115                Char('4'),
2116                Char('h'),
2117                Char('.'),
2118            ]
2119            .iter(),
2120        );
2121        assert_eq!(String::from(ed), "xxxs is axxxst");
2122    }
2123
2124    #[test]
2125    /// verify our move count
2126    fn move_count_right() {
2127        let mut context = Context::new();
2128        let out = Vec::new();
2129        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2130        let mut map = Vi::new();
2131        map.init(&mut ed);
2132        ed.insert_str_after_cursor("replace").unwrap();
2133        assert_eq!(ed.cursor(), 7);
2134        assert_eq!(map.move_count_right(&ed), 0);
2135        map.count = 10;
2136        assert_eq!(map.move_count_right(&ed), 0);
2137
2138        map.count = 0;
2139
2140        simulate_keys(&mut map, &mut ed, [Esc, Left].iter());
2141        assert_eq!(map.move_count_right(&ed), 1);
2142    }
2143
2144    #[test]
2145    /// verify our move count
2146    fn move_count_left() {
2147        let mut context = Context::new();
2148        let out = Vec::new();
2149        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2150        let mut map = Vi::new();
2151        map.init(&mut ed);
2152        ed.insert_str_after_cursor("replace").unwrap();
2153        assert_eq!(ed.cursor(), 7);
2154        assert_eq!(map.move_count_left(&ed), 1);
2155        map.count = 10;
2156        assert_eq!(map.move_count_left(&ed), 7);
2157
2158        map.count = 0;
2159
2160        simulate_keys(&mut map, &mut ed, [Esc, Char('0')].iter());
2161        assert_eq!(map.move_count_left(&ed), 0);
2162    }
2163
2164    #[test]
2165    /// test delete with dot
2166    fn dot_x_delete() {
2167        let mut context = Context::new();
2168        let out = Vec::new();
2169        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2170        let mut map = Vi::new();
2171        map.init(&mut ed);
2172        ed.insert_str_after_cursor("replace").unwrap();
2173        assert_eq!(ed.cursor(), 7);
2174
2175        simulate_keys(
2176            &mut map,
2177            &mut ed,
2178            [Esc, Char('0'), Char('2'), Char('x'), Char('.')].iter(),
2179        );
2180        assert_eq!(String::from(ed), "ace");
2181    }
2182
2183    #[test]
2184    /// test deleting a line
2185    fn delete_line() {
2186        let mut context = Context::new();
2187        let out = Vec::new();
2188        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2189        let mut map = Vi::new();
2190        map.init(&mut ed);
2191        ed.insert_str_after_cursor("delete").unwrap();
2192
2193        simulate_keys(&mut map, &mut ed, [Esc, Char('d'), Char('d')].iter());
2194        assert_eq!(ed.cursor(), 0);
2195        assert_eq!(String::from(ed), "");
2196    }
2197
2198    #[test]
2199    /// test for normal mode after deleting a line
2200    fn delete_line_normal() {
2201        let mut context = Context::new();
2202        let out = Vec::new();
2203
2204        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2205        let mut map = Vi::new();
2206        map.init(&mut ed);
2207        ed.insert_str_after_cursor("delete").unwrap();
2208
2209        simulate_keys(
2210            &mut map,
2211            &mut ed,
2212            [
2213                Esc,
2214                Char('d'),
2215                Char('d'),
2216                Char('i'),
2217                Char('n'),
2218                Char('e'),
2219                Char('w'),
2220                Esc,
2221            ]
2222            .iter(),
2223        );
2224        assert_eq!(ed.cursor(), 2);
2225        assert_eq!(String::from(ed), "new");
2226    }
2227
2228    #[test]
2229    /// test aborting a delete (and change)
2230    fn delete_abort() {
2231        let mut context = Context::new();
2232        let out = Vec::new();
2233
2234        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2235        let mut map = Vi::new();
2236        map.init(&mut ed);
2237        ed.insert_str_after_cursor("don't delete").unwrap();
2238
2239        simulate_keys(
2240            &mut map,
2241            &mut ed,
2242            [
2243                Esc,
2244                Char('d'),
2245                Esc,
2246                Char('d'),
2247                Char('c'),
2248                Char('c'),
2249                Char('d'),
2250            ]
2251            .iter(),
2252        );
2253        assert_eq!(ed.cursor(), 11);
2254        assert_eq!(String::from(ed), "don't delete");
2255    }
2256
2257    #[test]
2258    /// test deleting a single char to the left
2259    fn delete_char_left() {
2260        let mut context = Context::new();
2261        let out = Vec::new();
2262        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2263        let mut map = Vi::new();
2264        map.init(&mut ed);
2265        ed.insert_str_after_cursor("delete").unwrap();
2266
2267        simulate_keys(&mut map, &mut ed, [Esc, Char('d'), Char('h')].iter());
2268        assert_eq!(ed.cursor(), 4);
2269        assert_eq!(String::from(ed), "delee");
2270    }
2271
2272    #[test]
2273    /// test deleting multiple chars to the left
2274    fn delete_chars_left() {
2275        let mut context = Context::new();
2276        let out = Vec::new();
2277        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2278        let mut map = Vi::new();
2279        map.init(&mut ed);
2280        ed.insert_str_after_cursor("delete").unwrap();
2281
2282        simulate_keys(
2283            &mut map,
2284            &mut ed,
2285            [Esc, Char('3'), Char('d'), Char('h')].iter(),
2286        );
2287        assert_eq!(ed.cursor(), 2);
2288        assert_eq!(String::from(ed), "dee");
2289    }
2290
2291    #[test]
2292    /// test deleting a single char to the right
2293    fn delete_char_right() {
2294        let mut context = Context::new();
2295        let out = Vec::new();
2296
2297        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2298        let mut map = Vi::new();
2299        map.init(&mut ed);
2300        ed.insert_str_after_cursor("delete").unwrap();
2301
2302        simulate_keys(
2303            &mut map,
2304            &mut ed,
2305            [Esc, Char('0'), Char('d'), Char('l')].iter(),
2306        );
2307        assert_eq!(ed.cursor(), 0);
2308        assert_eq!(String::from(ed), "elete");
2309    }
2310
2311    #[test]
2312    /// test deleting multiple chars to the right
2313    fn delete_chars_right() {
2314        let mut context = Context::new();
2315        let out = Vec::new();
2316
2317        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2318        let mut map = Vi::new();
2319        map.init(&mut ed);
2320        ed.insert_str_after_cursor("delete").unwrap();
2321
2322        simulate_keys(
2323            &mut map,
2324            &mut ed,
2325            [Esc, Char('0'), Char('3'), Char('d'), Char('l')].iter(),
2326        );
2327        assert_eq!(ed.cursor(), 0);
2328        assert_eq!(String::from(ed), "ete");
2329    }
2330
2331    #[test]
2332    /// test repeat with delete
2333    fn delete_and_repeat() {
2334        let mut context = Context::new();
2335        let out = Vec::new();
2336
2337        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2338        let mut map = Vi::new();
2339        map.init(&mut ed);
2340        ed.insert_str_after_cursor("delete").unwrap();
2341
2342        simulate_keys(
2343            &mut map,
2344            &mut ed,
2345            [Esc, Char('0'), Char('d'), Char('l'), Char('.')].iter(),
2346        );
2347        assert_eq!(ed.cursor(), 0);
2348        assert_eq!(String::from(ed), "lete");
2349    }
2350
2351    #[test]
2352    /// test delete until end of line
2353    fn delete_until_end() {
2354        let mut context = Context::new();
2355        let out = Vec::new();
2356
2357        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2358        let mut map = Vi::new();
2359        map.init(&mut ed);
2360        ed.insert_str_after_cursor("delete").unwrap();
2361
2362        simulate_keys(
2363            &mut map,
2364            &mut ed,
2365            [Esc, Char('0'), Char('d'), Char('$')].iter(),
2366        );
2367        assert_eq!(ed.cursor(), 0);
2368        assert_eq!(String::from(ed), "");
2369    }
2370
2371    #[test]
2372    /// test delete until end of line
2373    fn delete_until_end_shift_d() {
2374        let mut context = Context::new();
2375        let out = Vec::new();
2376        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2377        let mut map = Vi::new();
2378        map.init(&mut ed);
2379        ed.insert_str_after_cursor("delete").unwrap();
2380
2381        simulate_keys(&mut map, &mut ed, [Esc, Char('0'), Char('D')].iter());
2382        assert_eq!(ed.cursor(), 0);
2383        assert_eq!(String::from(ed), "");
2384    }
2385
2386    #[test]
2387    /// test delete until start of line
2388    fn delete_until_start() {
2389        let mut context = Context::new();
2390        let out = Vec::new();
2391
2392        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2393        let mut map = Vi::new();
2394        map.init(&mut ed);
2395        ed.insert_str_after_cursor("delete").unwrap();
2396
2397        simulate_keys(
2398            &mut map,
2399            &mut ed,
2400            [Esc, Char('$'), Char('d'), Char('0')].iter(),
2401        );
2402        assert_eq!(ed.cursor(), 0);
2403        assert_eq!(String::from(ed), "e");
2404    }
2405
2406    #[test]
2407    /// test a compound count with delete
2408    fn delete_with_count() {
2409        let mut context = Context::new();
2410        let out = Vec::new();
2411
2412        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2413        let mut map = Vi::new();
2414        map.init(&mut ed);
2415        ed.insert_str_after_cursor("delete").unwrap();
2416
2417        simulate_keys(
2418            &mut map,
2419            &mut ed,
2420            [Esc, Char('0'), Char('2'), Char('d'), Char('2'), Char('l')].iter(),
2421        );
2422        assert_eq!(ed.cursor(), 0);
2423        assert_eq!(String::from(ed), "te");
2424    }
2425
2426    #[test]
2427    /// test a compound count with delete and repeat
2428    fn delete_with_count_and_repeat() {
2429        let mut context = Context::new();
2430        let out = Vec::new();
2431
2432        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2433        let mut map = Vi::new();
2434        map.init(&mut ed);
2435        ed.insert_str_after_cursor("delete delete").unwrap();
2436
2437        simulate_keys(
2438            &mut map,
2439            &mut ed,
2440            [
2441                Esc,
2442                Char('0'),
2443                Char('2'),
2444                Char('d'),
2445                Char('2'),
2446                Char('l'),
2447                Char('.'),
2448            ]
2449            .iter(),
2450        );
2451        assert_eq!(ed.cursor(), 0);
2452        assert_eq!(String::from(ed), "elete");
2453    }
2454
2455    #[test]
2456    fn move_to_end_of_word_simple() {
2457        let mut context = Context::new();
2458        let out = Vec::new();
2459        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2460
2461        ed.insert_str_after_cursor("here are").unwrap();
2462        let start_pos = ed.cursor();
2463        ed.insert_str_after_cursor(" som").unwrap();
2464        let end_pos = ed.cursor();
2465        ed.insert_str_after_cursor("e words").unwrap();
2466        ed.move_cursor_to(start_pos).unwrap();
2467
2468        move_to_end_of_word(&mut ed, 1).unwrap();
2469        assert_eq!(ed.cursor(), end_pos);
2470    }
2471
2472    #[test]
2473    fn move_to_end_of_word_comma() {
2474        let mut context = Context::new();
2475        let out = Vec::new();
2476        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2477
2478        ed.insert_str_after_cursor("here ar").unwrap();
2479        let start_pos = ed.cursor();
2480        ed.insert_after_cursor('e').unwrap();
2481        let end_pos1 = ed.cursor();
2482        ed.insert_str_after_cursor(", som").unwrap();
2483        let end_pos2 = ed.cursor();
2484        ed.insert_str_after_cursor("e words").unwrap();
2485        ed.move_cursor_to(start_pos).unwrap();
2486
2487        move_to_end_of_word(&mut ed, 1).unwrap();
2488        assert_eq!(ed.cursor(), end_pos1);
2489        move_to_end_of_word(&mut ed, 1).unwrap();
2490        assert_eq!(ed.cursor(), end_pos2);
2491    }
2492
2493    #[test]
2494    fn move_to_end_of_word_nonkeywords() {
2495        let mut context = Context::new();
2496        let out = Vec::new();
2497        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2498
2499        ed.insert_str_after_cursor("here ar").unwrap();
2500        let start_pos = ed.cursor();
2501        ed.insert_str_after_cursor("e,,,").unwrap();
2502        let end_pos1 = ed.cursor();
2503        ed.insert_str_after_cursor(",som").unwrap();
2504        let end_pos2 = ed.cursor();
2505        ed.insert_str_after_cursor("e words").unwrap();
2506        ed.move_cursor_to(start_pos).unwrap();
2507
2508        move_to_end_of_word(&mut ed, 1).unwrap();
2509        assert_eq!(ed.cursor(), end_pos1);
2510        move_to_end_of_word(&mut ed, 1).unwrap();
2511        assert_eq!(ed.cursor(), end_pos2);
2512    }
2513
2514    #[test]
2515    fn move_to_end_of_word_whitespace() {
2516        let mut context = Context::new();
2517        let out = Vec::new();
2518        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2519
2520        assert_eq!(ed.cursor(), 0);
2521        ed.insert_str_after_cursor("here are").unwrap();
2522        let start_pos = ed.cursor();
2523        assert_eq!(ed.cursor(), 8);
2524        ed.insert_str_after_cursor("      som").unwrap();
2525        assert_eq!(ed.cursor(), 17);
2526        ed.insert_str_after_cursor("e words").unwrap();
2527        assert_eq!(ed.cursor(), 24);
2528        ed.move_cursor_to(start_pos).unwrap();
2529        assert_eq!(ed.cursor(), 8);
2530
2531        move_to_end_of_word(&mut ed, 1).unwrap();
2532        assert_eq!(ed.cursor(), 17);
2533    }
2534
2535    #[test]
2536    fn move_to_end_of_word_whitespace_nonkeywords() {
2537        let mut context = Context::new();
2538        let out = Vec::new();
2539        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2540
2541        ed.insert_str_after_cursor("here ar").unwrap();
2542        let start_pos = ed.cursor();
2543        ed.insert_str_after_cursor("e   ,,,").unwrap();
2544        let end_pos1 = ed.cursor();
2545        ed.insert_str_after_cursor(", som").unwrap();
2546        let end_pos2 = ed.cursor();
2547        ed.insert_str_after_cursor("e words").unwrap();
2548        ed.move_cursor_to(start_pos).unwrap();
2549
2550        move_to_end_of_word(&mut ed, 1).unwrap();
2551        assert_eq!(ed.cursor(), end_pos1);
2552        move_to_end_of_word(&mut ed, 1).unwrap();
2553        assert_eq!(ed.cursor(), end_pos2);
2554    }
2555
2556    #[test]
2557    fn move_to_end_of_word_ws_simple() {
2558        let mut context = Context::new();
2559        let out = Vec::new();
2560        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2561
2562        ed.insert_str_after_cursor("here are").unwrap();
2563        let start_pos = ed.cursor();
2564        ed.insert_str_after_cursor(" som").unwrap();
2565        let end_pos = ed.cursor();
2566        ed.insert_str_after_cursor("e words").unwrap();
2567        ed.move_cursor_to(start_pos).unwrap();
2568
2569        move_to_end_of_word_ws(&mut ed, 1).unwrap();
2570        assert_eq!(ed.cursor(), end_pos);
2571    }
2572
2573    #[test]
2574    fn move_to_end_of_word_ws_comma() {
2575        let mut context = Context::new();
2576        let out = Vec::new();
2577        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2578
2579        ed.insert_str_after_cursor("here ar").unwrap();
2580        let start_pos = ed.cursor();
2581        ed.insert_after_cursor('e').unwrap();
2582        let end_pos1 = ed.cursor();
2583        ed.insert_str_after_cursor(", som").unwrap();
2584        let end_pos2 = ed.cursor();
2585        ed.insert_str_after_cursor("e words").unwrap();
2586        ed.move_cursor_to(start_pos).unwrap();
2587
2588        move_to_end_of_word_ws(&mut ed, 1).unwrap();
2589        assert_eq!(ed.cursor(), end_pos1);
2590        move_to_end_of_word_ws(&mut ed, 1).unwrap();
2591        assert_eq!(ed.cursor(), end_pos2);
2592    }
2593
2594    #[test]
2595    fn move_to_end_of_word_ws_nonkeywords() {
2596        let mut context = Context::new();
2597        let out = Vec::new();
2598        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2599
2600        ed.insert_str_after_cursor("here ar").unwrap();
2601        let start_pos = ed.cursor();
2602        ed.insert_str_after_cursor("e,,,,som").unwrap();
2603        let end_pos = ed.cursor();
2604        ed.insert_str_after_cursor("e words").unwrap();
2605        ed.move_cursor_to(start_pos).unwrap();
2606        move_to_end_of_word_ws(&mut ed, 1).unwrap();
2607        assert_eq!(ed.cursor(), end_pos);
2608    }
2609
2610    #[test]
2611    fn move_to_end_of_word_ws_whitespace() {
2612        let mut context = Context::new();
2613        let out = Vec::new();
2614        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2615
2616        ed.insert_str_after_cursor("here are").unwrap();
2617        let start_pos = ed.cursor();
2618        ed.insert_str_after_cursor("      som").unwrap();
2619        let end_pos = ed.cursor();
2620        ed.insert_str_after_cursor("e words").unwrap();
2621        ed.move_cursor_to(start_pos).unwrap();
2622
2623        move_to_end_of_word_ws(&mut ed, 1).unwrap();
2624        assert_eq!(ed.cursor(), end_pos);
2625    }
2626
2627    #[test]
2628    fn move_to_end_of_word_ws_whitespace_nonkeywords() {
2629        let mut context = Context::new();
2630        let out = Vec::new();
2631        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2632
2633        ed.insert_str_after_cursor("here ar").unwrap();
2634        let start_pos = ed.cursor();
2635        ed.insert_str_after_cursor("e   ,,,").unwrap();
2636        let end_pos1 = ed.cursor();
2637        ed.insert_str_after_cursor(", som").unwrap();
2638        let end_pos2 = ed.cursor();
2639        ed.insert_str_after_cursor("e words").unwrap();
2640        ed.move_cursor_to(start_pos).unwrap();
2641
2642        move_to_end_of_word_ws(&mut ed, 1).unwrap();
2643        assert_eq!(ed.cursor(), end_pos1);
2644        move_to_end_of_word_ws(&mut ed, 1).unwrap();
2645        assert_eq!(ed.cursor(), end_pos2);
2646    }
2647
2648    #[test]
2649    fn move_word_simple() {
2650        let mut context = Context::new();
2651        let out = Vec::new();
2652        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2653
2654        ed.insert_str_after_cursor("here ").unwrap();
2655        let pos1 = ed.cursor();
2656        ed.insert_str_after_cursor("are ").unwrap();
2657        let pos2 = ed.cursor();
2658        ed.insert_str_after_cursor("some words").unwrap();
2659        ed.move_cursor_to_start_of_line().unwrap();
2660
2661        move_word(&mut ed, 1).unwrap();
2662        assert_eq!(ed.cursor(), pos1);
2663        move_word(&mut ed, 1).unwrap();
2664        assert_eq!(ed.cursor(), pos2);
2665
2666        ed.move_cursor_to_start_of_line().unwrap();
2667        move_word_ws(&mut ed, 1).unwrap();
2668        assert_eq!(ed.cursor(), pos1);
2669        move_word_ws(&mut ed, 1).unwrap();
2670        assert_eq!(ed.cursor(), pos2);
2671    }
2672
2673    #[test]
2674    fn move_word_whitespace() {
2675        let mut context = Context::new();
2676        let out = Vec::new();
2677        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2678
2679        ed.insert_str_after_cursor("   ").unwrap();
2680        let pos1 = ed.cursor();
2681        ed.insert_str_after_cursor("word").unwrap();
2682        let pos2 = ed.cursor();
2683        ed.move_cursor_to_start_of_line().unwrap();
2684
2685        move_word(&mut ed, 1).unwrap();
2686        assert_eq!(ed.cursor(), pos1);
2687        move_word(&mut ed, 1).unwrap();
2688        assert_eq!(ed.cursor(), pos2);
2689
2690        ed.move_cursor_to_start_of_line().unwrap();
2691        move_word_ws(&mut ed, 1).unwrap();
2692        assert_eq!(ed.cursor(), pos1);
2693        move_word_ws(&mut ed, 1).unwrap();
2694        assert_eq!(ed.cursor(), pos2);
2695    }
2696
2697    #[test]
2698    fn move_word_nonkeywords() {
2699        let mut context = Context::new();
2700        let out = Vec::new();
2701        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2702
2703        ed.insert_str_after_cursor("..=").unwrap();
2704        let pos1 = ed.cursor();
2705        ed.insert_str_after_cursor("word").unwrap();
2706        let pos2 = ed.cursor();
2707        ed.move_cursor_to_start_of_line().unwrap();
2708
2709        move_word(&mut ed, 1).unwrap();
2710        assert_eq!(ed.cursor(), pos1);
2711        move_word(&mut ed, 1).unwrap();
2712        assert_eq!(ed.cursor(), pos2);
2713
2714        ed.move_cursor_to_start_of_line().unwrap();
2715        move_word_ws(&mut ed, 1).unwrap();
2716        assert_eq!(ed.cursor(), pos2);
2717    }
2718
2719    #[test]
2720    fn move_word_whitespace_nonkeywords() {
2721        let mut context = Context::new();
2722        let out = Vec::new();
2723        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2724
2725        ed.insert_str_after_cursor("..=   ").unwrap();
2726        let pos1 = ed.cursor();
2727        ed.insert_str_after_cursor("..=").unwrap();
2728        let pos2 = ed.cursor();
2729        ed.insert_str_after_cursor("word").unwrap();
2730        let pos3 = ed.cursor();
2731        ed.move_cursor_to_start_of_line().unwrap();
2732
2733        move_word(&mut ed, 1).unwrap();
2734        assert_eq!(ed.cursor(), pos1);
2735        move_word(&mut ed, 1).unwrap();
2736        assert_eq!(ed.cursor(), pos2);
2737
2738        ed.move_cursor_to_start_of_line().unwrap();
2739        move_word_ws(&mut ed, 1).unwrap();
2740        assert_eq!(ed.cursor(), pos1);
2741        move_word_ws(&mut ed, 1).unwrap();
2742        assert_eq!(ed.cursor(), pos3);
2743    }
2744
2745    #[test]
2746    fn move_word_and_back() {
2747        let mut context = Context::new();
2748        let out = Vec::new();
2749        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2750
2751        ed.insert_str_after_cursor("here ").unwrap();
2752        let pos1 = ed.cursor();
2753        ed.insert_str_after_cursor("are ").unwrap();
2754        let pos2 = ed.cursor();
2755        ed.insert_str_after_cursor("some").unwrap();
2756        let pos3 = ed.cursor();
2757        ed.insert_str_after_cursor("..= ").unwrap();
2758        let pos4 = ed.cursor();
2759        ed.insert_str_after_cursor("words").unwrap();
2760        let pos5 = ed.cursor();
2761
2762        // make sure move_word() and move_word_back() are reflections of eachother
2763
2764        ed.move_cursor_to_start_of_line().unwrap();
2765        move_word(&mut ed, 1).unwrap();
2766        assert_eq!(ed.cursor(), pos1);
2767        move_word(&mut ed, 1).unwrap();
2768        assert_eq!(ed.cursor(), pos2);
2769        move_word(&mut ed, 1).unwrap();
2770        assert_eq!(ed.cursor(), pos3);
2771        move_word(&mut ed, 1).unwrap();
2772        assert_eq!(ed.cursor(), pos4);
2773        move_word(&mut ed, 1).unwrap();
2774        assert_eq!(ed.cursor(), pos5);
2775
2776        move_word_back(&mut ed, 1).unwrap();
2777        assert_eq!(ed.cursor(), pos4);
2778        move_word_back(&mut ed, 1).unwrap();
2779        assert_eq!(ed.cursor(), pos3);
2780        move_word_back(&mut ed, 1).unwrap();
2781        assert_eq!(ed.cursor(), pos2);
2782        move_word_back(&mut ed, 1).unwrap();
2783        assert_eq!(ed.cursor(), pos1);
2784        move_word_back(&mut ed, 1).unwrap();
2785        assert_eq!(ed.cursor(), 0);
2786
2787        ed.move_cursor_to_start_of_line().unwrap();
2788        move_word_ws(&mut ed, 1).unwrap();
2789        assert_eq!(ed.cursor(), pos1);
2790        move_word_ws(&mut ed, 1).unwrap();
2791        assert_eq!(ed.cursor(), pos2);
2792        move_word_ws(&mut ed, 1).unwrap();
2793        assert_eq!(ed.cursor(), pos4);
2794        move_word_ws(&mut ed, 1).unwrap();
2795        assert_eq!(ed.cursor(), pos5);
2796
2797        move_word_ws_back(&mut ed, 1).unwrap();
2798        assert_eq!(ed.cursor(), pos4);
2799        move_word_ws_back(&mut ed, 1).unwrap();
2800        assert_eq!(ed.cursor(), pos2);
2801        move_word_ws_back(&mut ed, 1).unwrap();
2802        assert_eq!(ed.cursor(), pos1);
2803        move_word_ws_back(&mut ed, 1).unwrap();
2804        assert_eq!(ed.cursor(), 0);
2805    }
2806
2807    #[test]
2808    fn move_word_and_back_with_count() {
2809        let mut context = Context::new();
2810        let out = Vec::new();
2811        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2812
2813        ed.insert_str_after_cursor("here ").unwrap();
2814        ed.insert_str_after_cursor("are ").unwrap();
2815        let pos1 = ed.cursor();
2816        ed.insert_str_after_cursor("some").unwrap();
2817        let pos2 = ed.cursor();
2818        ed.insert_str_after_cursor("..= ").unwrap();
2819        ed.insert_str_after_cursor("words").unwrap();
2820        let pos3 = ed.cursor();
2821
2822        // make sure move_word() and move_word_back() are reflections of eachother
2823        ed.move_cursor_to_start_of_line().unwrap();
2824        move_word(&mut ed, 3).unwrap();
2825        assert_eq!(ed.cursor(), pos2);
2826        move_word(&mut ed, 2).unwrap();
2827        assert_eq!(ed.cursor(), pos3);
2828
2829        move_word_back(&mut ed, 2).unwrap();
2830        assert_eq!(ed.cursor(), pos2);
2831        move_word_back(&mut ed, 3).unwrap();
2832        assert_eq!(ed.cursor(), 0);
2833
2834        ed.move_cursor_to_start_of_line().unwrap();
2835        move_word_ws(&mut ed, 2).unwrap();
2836        assert_eq!(ed.cursor(), pos1);
2837        move_word_ws(&mut ed, 2).unwrap();
2838        assert_eq!(ed.cursor(), pos3);
2839
2840        move_word_ws_back(&mut ed, 2).unwrap();
2841        assert_eq!(ed.cursor(), pos1);
2842        move_word_ws_back(&mut ed, 2).unwrap();
2843        assert_eq!(ed.cursor(), 0);
2844    }
2845
2846    #[test]
2847    fn move_to_end_of_word_ws_whitespace_count() {
2848        let mut context = Context::new();
2849        let out = Vec::new();
2850        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2851
2852        ed.insert_str_after_cursor("here are").unwrap();
2853        let start_pos = ed.cursor();
2854        ed.insert_str_after_cursor("      som").unwrap();
2855        ed.insert_str_after_cursor("e word").unwrap();
2856        let end_pos = ed.cursor();
2857        ed.insert_str_after_cursor("s and some").unwrap();
2858
2859        ed.move_cursor_to(start_pos).unwrap();
2860        move_to_end_of_word_ws(&mut ed, 2).unwrap();
2861        assert_eq!(ed.cursor(), end_pos);
2862    }
2863
2864    #[test]
2865    /// test delete word
2866    fn delete_word() {
2867        let mut context = Context::new();
2868        let out = Vec::new();
2869
2870        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2871        let mut map = Vi::new();
2872        map.init(&mut ed);
2873        ed.insert_str_after_cursor("delete some words").unwrap();
2874
2875        simulate_keys(
2876            &mut map,
2877            &mut ed,
2878            [Esc, Char('0'), Char('d'), Char('w')].iter(),
2879        );
2880        assert_eq!(ed.cursor(), 0);
2881        assert_eq!(String::from(ed), "some words");
2882    }
2883
2884    #[test]
2885    /// test changing a line
2886    fn change_line() {
2887        let mut context = Context::new();
2888        let out = Vec::new();
2889
2890        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2891        let mut map = Vi::new();
2892        map.init(&mut ed);
2893        ed.insert_str_after_cursor("change").unwrap();
2894
2895        simulate_keys(
2896            &mut map,
2897            &mut ed,
2898            [
2899                Esc,
2900                Char('c'),
2901                Char('c'),
2902                Char('d'),
2903                Char('o'),
2904                Char('n'),
2905                Char('e'),
2906            ]
2907            .iter(),
2908        );
2909        assert_eq!(ed.cursor(), 4);
2910        assert_eq!(String::from(ed), "done");
2911    }
2912
2913    #[test]
2914    /// test deleting a single char to the left
2915    fn change_char_left() {
2916        let mut context = Context::new();
2917        let out = Vec::new();
2918        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2919        let mut map = Vi::new();
2920        map.init(&mut ed);
2921        ed.insert_str_after_cursor("change").unwrap();
2922
2923        simulate_keys(
2924            &mut map,
2925            &mut ed,
2926            [Esc, Char('c'), Char('h'), Char('e'), Esc].iter(),
2927        );
2928        assert_eq!(ed.cursor(), 4);
2929        assert_eq!(String::from(ed), "chanee");
2930    }
2931
2932    #[test]
2933    /// test deleting multiple chars to the left
2934    fn change_chars_left() {
2935        let mut context = Context::new();
2936        let out = Vec::new();
2937        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2938        let mut map = Vi::new();
2939        map.init(&mut ed);
2940        ed.insert_str_after_cursor("change").unwrap();
2941
2942        simulate_keys(
2943            &mut map,
2944            &mut ed,
2945            [Esc, Char('3'), Char('c'), Char('h'), Char('e')].iter(),
2946        );
2947        assert_eq!(ed.cursor(), 3);
2948        assert_eq!(String::from(ed), "chee");
2949    }
2950
2951    #[test]
2952    /// test deleting a single char to the right
2953    fn change_char_right() {
2954        let mut context = Context::new();
2955        let out = Vec::new();
2956        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2957        let mut map = Vi::new();
2958        map.init(&mut ed);
2959        ed.insert_str_after_cursor("change").unwrap();
2960
2961        simulate_keys(
2962            &mut map,
2963            &mut ed,
2964            [Esc, Char('0'), Char('c'), Char('l'), Char('s')].iter(),
2965        );
2966        assert_eq!(ed.cursor(), 1);
2967        assert_eq!(String::from(ed), "shange");
2968    }
2969
2970    #[test]
2971    /// test changing multiple chars to the right
2972    fn change_chars_right() {
2973        let mut context = Context::new();
2974        let out = Vec::new();
2975
2976        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
2977        let mut map = Vi::new();
2978        map.init(&mut ed);
2979        ed.insert_str_after_cursor("change").unwrap();
2980
2981        simulate_keys(
2982            &mut map,
2983            &mut ed,
2984            [
2985                Esc,
2986                Char('0'),
2987                Char('3'),
2988                Char('c'),
2989                Char('l'),
2990                Char('s'),
2991                Char('t'),
2992                Char('r'),
2993                Char('a'),
2994                Esc,
2995            ]
2996            .iter(),
2997        );
2998        assert_eq!(ed.cursor(), 3);
2999        assert_eq!(String::from(ed), "strange");
3000    }
3001
3002    #[test]
3003    /// test repeat with change
3004    fn change_and_repeat() {
3005        let mut context = Context::new();
3006        let out = Vec::new();
3007
3008        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3009        let mut map = Vi::new();
3010        map.init(&mut ed);
3011        ed.insert_str_after_cursor("change").unwrap();
3012
3013        simulate_keys(
3014            &mut map,
3015            &mut ed,
3016            [
3017                Esc,
3018                Char('0'),
3019                Char('c'),
3020                Char('l'),
3021                Char('s'),
3022                Esc,
3023                Char('l'),
3024                Char('.'),
3025                Char('l'),
3026                Char('.'),
3027            ]
3028            .iter(),
3029        );
3030        assert_eq!(ed.cursor(), 2);
3031        assert_eq!(String::from(ed), "sssnge");
3032    }
3033
3034    #[test]
3035    /// test change until end of line
3036    fn change_until_end() {
3037        let mut context = Context::new();
3038        let out = Vec::new();
3039
3040        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3041        let mut map = Vi::new();
3042        map.init(&mut ed);
3043        ed.insert_str_after_cursor("change").unwrap();
3044
3045        simulate_keys(
3046            &mut map,
3047            &mut ed,
3048            [
3049                Esc,
3050                Char('0'),
3051                Char('c'),
3052                Char('$'),
3053                Char('o'),
3054                Char('k'),
3055                Esc,
3056            ]
3057            .iter(),
3058        );
3059        assert_eq!(ed.cursor(), 1);
3060        assert_eq!(String::from(ed), "ok");
3061    }
3062
3063    #[test]
3064    /// test change until end of line
3065    fn change_until_end_shift_c() {
3066        let mut context = Context::new();
3067        let out = Vec::new();
3068        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3069        let mut map = Vi::new();
3070        map.init(&mut ed);
3071        ed.insert_str_after_cursor("change").unwrap();
3072
3073        simulate_keys(
3074            &mut map,
3075            &mut ed,
3076            [Esc, Char('0'), Char('C'), Char('o'), Char('k')].iter(),
3077        );
3078        assert_eq!(ed.cursor(), 2);
3079        assert_eq!(String::from(ed), "ok");
3080    }
3081
3082    #[test]
3083    /// test change until end of line
3084    fn change_until_end_from_middle_shift_c() {
3085        let mut context = Context::new();
3086        let out = Vec::new();
3087
3088        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3089        let mut map = Vi::new();
3090        map.init(&mut ed);
3091        ed.insert_str_after_cursor("change").unwrap();
3092
3093        simulate_keys(
3094            &mut map,
3095            &mut ed,
3096            [
3097                Esc,
3098                Char('0'),
3099                Char('2'),
3100                Char('l'),
3101                Char('C'),
3102                Char(' '),
3103                Char('o'),
3104                Char('k'),
3105                Esc,
3106            ]
3107            .iter(),
3108        );
3109        assert_eq!(String::from(ed), "ch ok");
3110    }
3111
3112    #[test]
3113    /// test change until start of line
3114    fn change_until_start() {
3115        let mut context = Context::new();
3116        let out = Vec::new();
3117
3118        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3119        let mut map = Vi::new();
3120        map.init(&mut ed);
3121        ed.insert_str_after_cursor("change").unwrap();
3122
3123        simulate_keys(
3124            &mut map,
3125            &mut ed,
3126            [
3127                Esc,
3128                Char('$'),
3129                Char('c'),
3130                Char('0'),
3131                Char('s'),
3132                Char('t'),
3133                Char('r'),
3134                Char('a'),
3135                Char('n'),
3136                Char('g'),
3137            ]
3138            .iter(),
3139        );
3140        assert_eq!(ed.cursor(), 6);
3141        assert_eq!(String::from(ed), "strange");
3142    }
3143
3144    #[test]
3145    /// test a compound count with change
3146    fn change_with_count() {
3147        let mut context = Context::new();
3148        let out = Vec::new();
3149
3150        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3151        let mut map = Vi::new();
3152        map.init(&mut ed);
3153        ed.insert_str_after_cursor("change").unwrap();
3154
3155        simulate_keys(
3156            &mut map,
3157            &mut ed,
3158            [
3159                Esc,
3160                Char('0'),
3161                Char('2'),
3162                Char('c'),
3163                Char('2'),
3164                Char('l'),
3165                Char('s'),
3166                Char('t'),
3167                Char('r'),
3168                Char('a'),
3169                Char('n'),
3170                Esc,
3171            ]
3172            .iter(),
3173        );
3174        assert_eq!(ed.cursor(), 4);
3175        assert_eq!(String::from(ed), "strange");
3176    }
3177
3178    #[test]
3179    /// test a compound count with change and repeat
3180    fn change_with_count_and_repeat() {
3181        let mut context = Context::new();
3182        let out = Vec::new();
3183
3184        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3185        let mut map = Vi::new();
3186        map.init(&mut ed);
3187        ed.insert_str_after_cursor("change change").unwrap();
3188
3189        simulate_keys(
3190            &mut map,
3191            &mut ed,
3192            [
3193                Esc,
3194                Char('0'),
3195                Char('2'),
3196                Char('c'),
3197                Char('2'),
3198                Char('l'),
3199                Char('o'),
3200                Esc,
3201                Char('.'),
3202            ]
3203            .iter(),
3204        );
3205        assert_eq!(ed.cursor(), 0);
3206        assert_eq!(String::from(ed), "ochange");
3207    }
3208
3209    #[test]
3210    /// test change word
3211    fn change_word() {
3212        let mut context = Context::new();
3213        let out = Vec::new();
3214
3215        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3216        let mut map = Vi::new();
3217        map.init(&mut ed);
3218        ed.insert_str_after_cursor("change some words").unwrap();
3219
3220        simulate_keys(
3221            &mut map,
3222            &mut ed,
3223            [
3224                Esc,
3225                Char('0'),
3226                Char('c'),
3227                Char('w'),
3228                Char('t'),
3229                Char('w'),
3230                Char('e'),
3231                Char('a'),
3232                Char('k'),
3233                Char(' '),
3234            ]
3235            .iter(),
3236        );
3237        assert_eq!(String::from(ed), "tweak some words");
3238    }
3239
3240    #[test]
3241    /// make sure the count is properly reset
3242    fn test_count_reset_around_insert_and_delete() {
3243        let mut context = Context::new();
3244        let out = Vec::new();
3245
3246        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3247        let mut map = Vi::new();
3248        map.init(&mut ed);
3249        ed.insert_str_after_cursor("these are some words").unwrap();
3250
3251        simulate_keys(
3252            &mut map,
3253            &mut ed,
3254            [
3255                Esc,
3256                Char('0'),
3257                Char('d'),
3258                Char('3'),
3259                Char('w'),
3260                Char('i'),
3261                Char('w'),
3262                Char('o'),
3263                Char('r'),
3264                Char('d'),
3265                Char('s'),
3266                Char(' '),
3267                Esc,
3268                Char('l'),
3269                Char('.'),
3270            ]
3271            .iter(),
3272        );
3273        assert_eq!(String::from(ed), "words words words");
3274    }
3275
3276    #[test]
3277    /// make sure t command does nothing if nothing was found
3278    fn test_t_not_found() {
3279        let mut context = Context::new();
3280        let out = Vec::new();
3281
3282        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3283        let mut map = Vi::new();
3284        map.init(&mut ed);
3285        ed.insert_str_after_cursor("abc defg").unwrap();
3286
3287        simulate_keys(
3288            &mut map,
3289            &mut ed,
3290            [Esc, Char('0'), Char('t'), Char('z')].iter(),
3291        );
3292        assert_eq!(ed.cursor(), 0);
3293    }
3294
3295    #[test]
3296    /// make sure t command moves the cursor
3297    fn test_t_movement() {
3298        let mut context = Context::new();
3299        let out = Vec::new();
3300        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3301        let mut map = Vi::new();
3302        map.init(&mut ed);
3303        ed.insert_str_after_cursor("abc defg").unwrap();
3304
3305        simulate_keys(
3306            &mut map,
3307            &mut ed,
3308            [Esc, Char('0'), Char('t'), Char('d')].iter(),
3309        );
3310        assert_eq!(ed.cursor(), 3);
3311    }
3312
3313    #[test]
3314    /// make sure t command moves the cursor
3315    fn test_t_movement_with_count() {
3316        let mut context = Context::new();
3317        let out = Vec::new();
3318
3319        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3320        let mut map = Vi::new();
3321        map.init(&mut ed);
3322        ed.insert_str_after_cursor("abc defg d").unwrap();
3323
3324        simulate_keys(
3325            &mut map,
3326            &mut ed,
3327            [Esc, Char('0'), Char('2'), Char('t'), Char('d')].iter(),
3328        );
3329        assert_eq!(ed.cursor(), 8);
3330    }
3331
3332    #[test]
3333    /// test normal mode after char movement
3334    fn test_t_movement_then_normal() {
3335        let mut context = Context::new();
3336        let out = Vec::new();
3337        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3338        let mut map = Vi::new();
3339        map.init(&mut ed);
3340        ed.insert_str_after_cursor("abc defg").unwrap();
3341
3342        simulate_keys(
3343            &mut map,
3344            &mut ed,
3345            [Esc, Char('0'), Char('t'), Char('d'), Char('l')].iter(),
3346        );
3347        assert_eq!(ed.cursor(), 4);
3348    }
3349
3350    #[test]
3351    /// test delete with char movement
3352    fn test_t_movement_with_delete() {
3353        let mut context = Context::new();
3354        let out = Vec::new();
3355
3356        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3357        let mut map = Vi::new();
3358        map.init(&mut ed);
3359        ed.insert_str_after_cursor("abc defg").unwrap();
3360
3361        simulate_keys(
3362            &mut map,
3363            &mut ed,
3364            [Esc, Char('0'), Char('d'), Char('t'), Char('d')].iter(),
3365        );
3366        assert_eq!(ed.cursor(), 0);
3367        assert_eq!(String::from(ed), "defg");
3368    }
3369
3370    #[test]
3371    /// test change with char movement
3372    fn test_t_movement_with_change() {
3373        let mut context = Context::new();
3374        let out = Vec::new();
3375
3376        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3377        let mut map = Vi::new();
3378        map.init(&mut ed);
3379        ed.insert_str_after_cursor("abc defg").unwrap();
3380
3381        simulate_keys(
3382            &mut map,
3383            &mut ed,
3384            [
3385                Esc,
3386                Char('0'),
3387                Char('c'),
3388                Char('t'),
3389                Char('d'),
3390                Char('z'),
3391                Char(' '),
3392                Esc,
3393            ]
3394            .iter(),
3395        );
3396        assert_eq!(ed.cursor(), 1);
3397        assert_eq!(String::from(ed), "z defg");
3398    }
3399
3400    #[test]
3401    /// make sure f command moves the cursor
3402    fn test_f_movement() {
3403        let mut context = Context::new();
3404        let out = Vec::new();
3405        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3406        let mut map = Vi::new();
3407        map.init(&mut ed);
3408        ed.insert_str_after_cursor("abc defg").unwrap();
3409
3410        simulate_keys(
3411            &mut map,
3412            &mut ed,
3413            [Esc, Char('0'), Char('f'), Char('d')].iter(),
3414        );
3415        assert_eq!(ed.cursor(), 4);
3416    }
3417
3418    #[test]
3419    /// make sure T command moves the cursor
3420    fn test_cap_t_movement() {
3421        let mut context = Context::new();
3422        let out = Vec::new();
3423        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3424        let mut map = Vi::new();
3425        map.init(&mut ed);
3426        ed.insert_str_after_cursor("abc defg").unwrap();
3427
3428        simulate_keys(
3429            &mut map,
3430            &mut ed,
3431            [Esc, Char('$'), Char('T'), Char('d')].iter(),
3432        );
3433        assert_eq!(ed.cursor(), 5);
3434    }
3435
3436    #[test]
3437    /// make sure F command moves the cursor
3438    fn test_cap_f_movement() {
3439        let mut context = Context::new();
3440        let out = Vec::new();
3441        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3442        let mut map = Vi::new();
3443        map.init(&mut ed);
3444        ed.insert_str_after_cursor("abc defg").unwrap();
3445
3446        simulate_keys(
3447            &mut map,
3448            &mut ed,
3449            [Esc, Char('$'), Char('F'), Char('d')].iter(),
3450        );
3451        assert_eq!(ed.cursor(), 4);
3452    }
3453
3454    #[test]
3455    /// make sure ; command moves the cursor
3456    fn test_semi_movement() {
3457        let mut context = Context::new();
3458        let out = Vec::new();
3459        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3460        let mut map = Vi::new();
3461        map.init(&mut ed);
3462        ed.insert_str_after_cursor("abc abc").unwrap();
3463
3464        simulate_keys(
3465            &mut map,
3466            &mut ed,
3467            [Esc, Char('0'), Char('f'), Char('c'), Char(';')].iter(),
3468        );
3469        assert_eq!(ed.cursor(), 6);
3470    }
3471
3472    #[test]
3473    /// make sure , command moves the cursor
3474    fn test_comma_movement() {
3475        let mut context = Context::new();
3476        let out = Vec::new();
3477        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3478        let mut map = Vi::new();
3479        map.init(&mut ed);
3480        ed.insert_str_after_cursor("abc abc").unwrap();
3481
3482        simulate_keys(
3483            &mut map,
3484            &mut ed,
3485            [Esc, Char('0'), Char('f'), Char('c'), Char('$'), Char(',')].iter(),
3486        );
3487        assert_eq!(ed.cursor(), 2);
3488    }
3489
3490    #[test]
3491    /// test delete with semi (;)
3492    fn test_semi_delete() {
3493        let mut context = Context::new();
3494        let out = Vec::new();
3495        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3496        let mut map = Vi::new();
3497        map.init(&mut ed);
3498        ed.insert_str_after_cursor("abc abc").unwrap();
3499
3500        simulate_keys(
3501            &mut map,
3502            &mut ed,
3503            [Esc, Char('0'), Char('f'), Char('c'), Char('d'), Char(';')].iter(),
3504        );
3505        assert_eq!(ed.cursor(), 1);
3506        assert_eq!(String::from(ed), "ab");
3507    }
3508
3509    #[test]
3510    /// test delete with semi (;) and repeat
3511    fn test_semi_delete_repeat() {
3512        let mut context = Context::new();
3513        let out = Vec::new();
3514
3515        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3516        let mut map = Vi::new();
3517        map.init(&mut ed);
3518        ed.insert_str_after_cursor("abc abc abc abc").unwrap();
3519
3520        simulate_keys(
3521            &mut map,
3522            &mut ed,
3523            [
3524                Esc,
3525                Char('0'),
3526                Char('f'),
3527                Char('c'),
3528                Char('d'),
3529                Char(';'),
3530                Char('.'),
3531                Char('.'),
3532            ]
3533            .iter(),
3534        );
3535        assert_eq!(String::from(ed), "ab");
3536    }
3537
3538    #[test]
3539    /// test find_char
3540    fn test_find_char() {
3541        let mut context = Context::new();
3542        let out = Vec::new();
3543        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3544        ed.insert_str_after_cursor("abcdefg").unwrap();
3545        assert_eq!(find_char(ed.current_buffer(), 0, 'd', 1), Some(3));
3546    }
3547
3548    #[test]
3549    /// test find_char with non-zero start
3550    fn test_find_char_with_start() {
3551        let mut context = Context::new();
3552        let out = Vec::new();
3553        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3554        ed.insert_str_after_cursor("abcabc").unwrap();
3555        assert_eq!(find_char(ed.current_buffer(), 1, 'a', 1), Some(3));
3556    }
3557
3558    #[test]
3559    /// test find_char with count
3560    fn test_find_char_with_count() {
3561        let mut context = Context::new();
3562        let out = Vec::new();
3563        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3564        ed.insert_str_after_cursor("abcabc").unwrap();
3565        assert_eq!(find_char(ed.current_buffer(), 0, 'a', 2), Some(3));
3566    }
3567
3568    #[test]
3569    /// test find_char not found
3570    fn test_find_char_not_found() {
3571        let mut context = Context::new();
3572        let out = Vec::new();
3573        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3574        ed.insert_str_after_cursor("abcdefg").unwrap();
3575        assert_eq!(find_char(ed.current_buffer(), 0, 'z', 1), None);
3576    }
3577
3578    #[test]
3579    /// test find_char_rev
3580    fn test_find_char_rev() {
3581        let mut context = Context::new();
3582        let out = Vec::new();
3583        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3584        ed.insert_str_after_cursor("abcdefg").unwrap();
3585        assert_eq!(find_char_rev(ed.current_buffer(), 6, 'd', 1), Some(3));
3586    }
3587
3588    #[test]
3589    /// test find_char_rev with non-zero start
3590    fn test_find_char_rev_with_start() {
3591        let mut context = Context::new();
3592        let out = Vec::new();
3593        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3594        ed.insert_str_after_cursor("abcabc").unwrap();
3595        assert_eq!(find_char_rev(ed.current_buffer(), 5, 'c', 1), Some(2));
3596    }
3597
3598    #[test]
3599    /// test find_char_rev with count
3600    fn test_find_char_rev_with_count() {
3601        let mut context = Context::new();
3602        let out = Vec::new();
3603        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3604        ed.insert_str_after_cursor("abcabc").unwrap();
3605        assert_eq!(find_char_rev(ed.current_buffer(), 6, 'c', 2), Some(2));
3606    }
3607
3608    #[test]
3609    /// test find_char_rev not found
3610    fn test_find_char_rev_not_found() {
3611        let mut context = Context::new();
3612        let out = Vec::new();
3613        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3614        ed.insert_str_after_cursor("abcdefg").unwrap();
3615        assert_eq!(find_char_rev(ed.current_buffer(), 6, 'z', 1), None);
3616    }
3617
3618    #[test]
3619    /// undo with counts
3620    fn test_undo_with_counts() {
3621        let mut context = Context::new();
3622        let out = Vec::new();
3623        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3624        let mut map = Vi::new();
3625        map.init(&mut ed);
3626        ed.insert_str_after_cursor("abcdefg").unwrap();
3627
3628        simulate_keys(
3629            &mut map,
3630            &mut ed,
3631            [Esc, Char('x'), Char('x'), Char('x'), Char('3'), Char('u')].iter(),
3632        );
3633        assert_eq!(String::from(ed), "abcdefg");
3634    }
3635
3636    #[test]
3637    /// redo with counts
3638    fn test_redo_with_counts() {
3639        let mut context = Context::new();
3640        let out = Vec::new();
3641        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3642        let mut map = Vi::new();
3643        map.init(&mut ed);
3644        ed.insert_str_after_cursor("abcdefg").unwrap();
3645
3646        simulate_keys(
3647            &mut map,
3648            &mut ed,
3649            [
3650                Esc,
3651                Char('x'),
3652                Char('x'),
3653                Char('x'),
3654                Char('u'),
3655                Char('u'),
3656                Char('u'),
3657            ]
3658            .iter(),
3659        );
3660        // Ctrl-r taken by incremental search so do this manually.
3661        ed.redo().unwrap();
3662        ed.redo().unwrap();
3663        assert_eq!(String::from(ed), "abcde");
3664    }
3665
3666    #[test]
3667    /// test change word with 'gE'
3668    fn change_word_ge_ws() {
3669        let mut context = Context::new();
3670        let out = Vec::new();
3671
3672        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3673        let mut map = Vi::new();
3674        map.init(&mut ed);
3675        ed.insert_str_after_cursor("change some words").unwrap();
3676
3677        simulate_keys(
3678            &mut map,
3679            &mut ed,
3680            [
3681                Esc,
3682                Char('c'),
3683                Char('g'),
3684                Char('E'),
3685                Char('e'),
3686                Char('t'),
3687                Char('h'),
3688                Char('i'),
3689                Char('n'),
3690                Char('g'),
3691                Esc,
3692            ]
3693            .iter(),
3694        );
3695        assert_eq!(String::from(ed), "change something");
3696    }
3697
3698    #[test]
3699    /// test undo in groups
3700    fn undo_insert() {
3701        let mut context = Context::new();
3702        let out = Vec::new();
3703
3704        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3705        let mut map = Vi::new();
3706        map.init(&mut ed);
3707
3708        simulate_keys(
3709            &mut map,
3710            &mut ed,
3711            [
3712                Char('i'),
3713                Char('n'),
3714                Char('s'),
3715                Char('e'),
3716                Char('r'),
3717                Char('t'),
3718                Esc,
3719                Char('u'),
3720            ]
3721            .iter(),
3722        );
3723        assert_eq!(String::from(ed), "");
3724    }
3725
3726    #[test]
3727    /// test undo in groups
3728    fn undo_insert2() {
3729        let mut context = Context::new();
3730        let out = Vec::new();
3731
3732        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3733        let mut map = Vi::new();
3734        map.init(&mut ed);
3735
3736        simulate_keys(
3737            &mut map,
3738            &mut ed,
3739            [
3740                Esc,
3741                Char('i'),
3742                Char('i'),
3743                Char('n'),
3744                Char('s'),
3745                Char('e'),
3746                Char('r'),
3747                Char('t'),
3748                Esc,
3749                Char('u'),
3750            ]
3751            .iter(),
3752        );
3753        assert_eq!(String::from(ed), "");
3754    }
3755
3756    #[test]
3757    /// test undo in groups
3758    fn undo_insert_with_history() {
3759        let mut context = Context::new();
3760        context
3761            .history
3762            .push(Buffer::from("insert something"))
3763            .unwrap();
3764        let out = Vec::new();
3765
3766        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3767        let mut map = Vi::new();
3768        map.init(&mut ed);
3769
3770        simulate_keys(
3771            &mut map,
3772            &mut ed,
3773            [
3774                Esc,
3775                Char('i'),
3776                Char('i'),
3777                Char('n'),
3778                Char('s'),
3779                Char('e'),
3780                Char('r'),
3781                Char('t'),
3782                Up,
3783                Char('h'),
3784                Char('i'),
3785                Char('s'),
3786                Char('t'),
3787                Char('o'),
3788                Char('r'),
3789                Char('y'),
3790                Down,
3791                Char(' '),
3792                Char('t'),
3793                Char('e'),
3794                Char('x'),
3795                Char('t'),
3796                Esc,
3797                Char('u'),
3798            ]
3799            .iter(),
3800        );
3801        assert_eq!(String::from(ed), "insert");
3802    }
3803
3804    #[test]
3805    /// test undo in groups
3806    fn undo_insert_with_history2() {
3807        let mut context = Context::new();
3808        context.history.push(Buffer::from("")).unwrap();
3809        let out = Vec::new();
3810
3811        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3812        let mut map = Vi::new();
3813        map.init(&mut ed);
3814
3815        simulate_keys(
3816            &mut map,
3817            &mut ed,
3818            [
3819                Esc,
3820                Char('i'),
3821                Char('i'),
3822                Char('n'),
3823                Char('s'),
3824                Char('e'),
3825                Char('r'),
3826                Char('t'),
3827                Up,
3828                Esc,
3829                Down,
3830                Char('u'),
3831            ]
3832            .iter(),
3833        );
3834        assert_eq!(String::from(ed), "");
3835    }
3836
3837    #[test]
3838    /// test undo in groups
3839    fn undo_insert_with_movement_reset() {
3840        let mut context = Context::new();
3841        let out = Vec::new();
3842
3843        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3844        let mut map = Vi::new();
3845        map.init(&mut ed);
3846
3847        simulate_keys(
3848            &mut map,
3849            &mut ed,
3850            [
3851                Esc,
3852                Char('i'),
3853                Char('i'),
3854                Char('n'),
3855                Char('s'),
3856                Char('e'),
3857                Char('r'),
3858                Char('t'),
3859                // movement reset will get triggered here
3860                Left,
3861                Right,
3862                Char(' '),
3863                Char('t'),
3864                Char('e'),
3865                Char('x'),
3866                Char('t'),
3867                Esc,
3868                Char('u'),
3869            ]
3870            .iter(),
3871        );
3872        assert_eq!(String::from(ed), "insert");
3873    }
3874
3875    #[test]
3876    /// test undo in groups
3877    fn undo_3x() {
3878        let mut context = Context::new();
3879        let out = Vec::new();
3880        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3881        let mut map = Vi::new();
3882        map.init(&mut ed);
3883        ed.insert_str_after_cursor("rm some words").unwrap();
3884
3885        simulate_keys(
3886            &mut map,
3887            &mut ed,
3888            [Esc, Char('0'), Char('3'), Char('x'), Char('u')].iter(),
3889        );
3890        assert_eq!(String::from(ed), "rm some words");
3891    }
3892
3893    #[test]
3894    /// test undo in groups
3895    fn undo_insert_with_count() {
3896        let mut context = Context::new();
3897        let out = Vec::new();
3898
3899        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3900        let mut map = Vi::new();
3901        map.init(&mut ed);
3902
3903        simulate_keys(
3904            &mut map,
3905            &mut ed,
3906            [
3907                Char('i'),
3908                Char('n'),
3909                Char('s'),
3910                Char('e'),
3911                Char('r'),
3912                Char('t'),
3913                Esc,
3914                Char('3'),
3915                Char('i'),
3916                Char('i'),
3917                Char('n'),
3918                Char('s'),
3919                Char('e'),
3920                Char('r'),
3921                Char('t'),
3922                Esc,
3923                Char('u'),
3924            ]
3925            .iter(),
3926        );
3927        assert_eq!(String::from(ed), "insert");
3928    }
3929
3930    #[test]
3931    /// test undo in groups
3932    fn undo_insert_with_repeat() {
3933        let mut context = Context::new();
3934        let out = Vec::new();
3935
3936        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3937        let mut map = Vi::new();
3938        map.init(&mut ed);
3939
3940        simulate_keys(
3941            &mut map,
3942            &mut ed,
3943            [
3944                Char('i'),
3945                Char('n'),
3946                Char('s'),
3947                Char('e'),
3948                Char('r'),
3949                Char('t'),
3950                Esc,
3951                Char('3'),
3952                Char('.'),
3953                Esc,
3954                Char('u'),
3955            ]
3956            .iter(),
3957        );
3958        assert_eq!(String::from(ed), "insert");
3959    }
3960
3961    #[test]
3962    /// test undo in groups
3963    fn undo_s_with_count() {
3964        let mut context = Context::new();
3965        let out = Vec::new();
3966
3967        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3968        let mut map = Vi::new();
3969        map.init(&mut ed);
3970        ed.insert_str_after_cursor("replace some words").unwrap();
3971
3972        simulate_keys(
3973            &mut map,
3974            &mut ed,
3975            [
3976                Esc,
3977                Char('0'),
3978                Char('8'),
3979                Char('s'),
3980                Char('o'),
3981                Char('k'),
3982                Esc,
3983                Char('u'),
3984            ]
3985            .iter(),
3986        );
3987        assert_eq!(String::from(ed), "replace some words");
3988    }
3989
3990    #[test]
3991    /// test undo in groups
3992    fn undo_multiple_groups() {
3993        let mut context = Context::new();
3994        let out = Vec::new();
3995
3996        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
3997        let mut map = Vi::new();
3998        map.init(&mut ed);
3999        ed.insert_str_after_cursor("replace some words").unwrap();
4000
4001        simulate_keys(
4002            &mut map,
4003            &mut ed,
4004            [
4005                Esc,
4006                Char('A'),
4007                Char(' '),
4008                Char('h'),
4009                Char('e'),
4010                Char('r'),
4011                Char('e'),
4012                Esc,
4013                Char('0'),
4014                Char('8'),
4015                Char('s'),
4016                Char('o'),
4017                Char('k'),
4018                Esc,
4019                Char('2'),
4020                Char('u'),
4021            ]
4022            .iter(),
4023        );
4024        assert_eq!(String::from(ed), "replace some words");
4025    }
4026
4027    #[test]
4028    /// test undo in groups
4029    fn undo_r_command_with_count() {
4030        let mut context = Context::new();
4031        let out = Vec::new();
4032
4033        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
4034        let mut map = Vi::new();
4035        map.init(&mut ed);
4036        ed.insert_str_after_cursor("replace some words").unwrap();
4037
4038        simulate_keys(
4039            &mut map,
4040            &mut ed,
4041            [Esc, Char('0'), Char('8'), Char('r'), Char(' '), Char('u')].iter(),
4042        );
4043        assert_eq!(String::from(ed), "replace some words");
4044    }
4045
4046    #[test]
4047    /// test tilde
4048    fn tilde_basic() {
4049        let mut context = Context::new();
4050        let out = Vec::new();
4051        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
4052        let mut map = Vi::new();
4053        map.init(&mut ed);
4054        ed.insert_str_after_cursor("tilde").unwrap();
4055
4056        simulate_keys(&mut map, &mut ed, [Esc, Char('~')].iter());
4057        assert_eq!(String::from(ed), "tildE");
4058    }
4059
4060    #[test]
4061    /// test tilde
4062    fn tilde_basic2() {
4063        let mut context = Context::new();
4064        let out = Vec::new();
4065        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
4066        let mut map = Vi::new();
4067        map.init(&mut ed);
4068        ed.insert_str_after_cursor("tilde").unwrap();
4069
4070        simulate_keys(&mut map, &mut ed, [Esc, Char('~'), Char('~')].iter());
4071        assert_eq!(String::from(ed), "tilde");
4072    }
4073
4074    #[test]
4075    /// test tilde
4076    fn tilde_move() {
4077        let mut context = Context::new();
4078        let out = Vec::new();
4079        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
4080        let mut map = Vi::new();
4081        map.init(&mut ed);
4082        ed.insert_str_after_cursor("tilde").unwrap();
4083
4084        simulate_keys(
4085            &mut map,
4086            &mut ed,
4087            [Esc, Char('0'), Char('~'), Char('~')].iter(),
4088        );
4089        assert_eq!(String::from(ed), "TIlde");
4090    }
4091
4092    #[test]
4093    /// test tilde
4094    fn tilde_repeat() {
4095        let mut context = Context::new();
4096        let out = Vec::new();
4097        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
4098        let mut map = Vi::new();
4099        map.init(&mut ed);
4100        ed.insert_str_after_cursor("tilde").unwrap();
4101
4102        simulate_keys(&mut map, &mut ed, [Esc, Char('~'), Char('.')].iter());
4103        assert_eq!(String::from(ed), "tilde");
4104    }
4105
4106    #[test]
4107    /// test tilde
4108    fn tilde_count() {
4109        let mut context = Context::new();
4110        let out = Vec::new();
4111        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
4112        let mut map = Vi::new();
4113        map.init(&mut ed);
4114        ed.insert_str_after_cursor("tilde").unwrap();
4115
4116        simulate_keys(
4117            &mut map,
4118            &mut ed,
4119            [Esc, Char('0'), Char('1'), Char('0'), Char('~')].iter(),
4120        );
4121        assert_eq!(String::from(ed), "TILDE");
4122    }
4123
4124    #[test]
4125    /// test tilde
4126    fn tilde_count_short() {
4127        let mut context = Context::new();
4128        let out = Vec::new();
4129        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
4130        let mut map = Vi::new();
4131        map.init(&mut ed);
4132        ed.insert_str_after_cursor("TILDE").unwrap();
4133
4134        simulate_keys(
4135            &mut map,
4136            &mut ed,
4137            [Esc, Char('0'), Char('2'), Char('~')].iter(),
4138        );
4139        assert_eq!(String::from(ed), "tiLDE");
4140    }
4141
4142    #[test]
4143    /// test tilde
4144    fn tilde_nocase() {
4145        let mut context = Context::new();
4146        let out = Vec::new();
4147        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
4148        let mut map = Vi::new();
4149        map.init(&mut ed);
4150        ed.insert_str_after_cursor("ti_lde").unwrap();
4151
4152        simulate_keys(
4153            &mut map,
4154            &mut ed,
4155            [Esc, Char('0'), Char('6'), Char('~')].iter(),
4156        );
4157        assert_eq!(String::from(ed), "TI_LDE");
4158    }
4159
4160    #[test]
4161    /// ctrl-h should act as backspace
4162    fn ctrl_h() {
4163        let mut context = Context::new();
4164        let out = Vec::new();
4165        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
4166        let mut map = Vi::new();
4167        map.init(&mut ed);
4168        ed.insert_str_after_cursor("not empty").unwrap();
4169
4170        let res = map.handle_key(Ctrl('h'), &mut ed, &mut EmptyCompleter);
4171        assert_eq!(res.is_ok(), true);
4172        assert_eq!(ed.current_buffer().to_string(), "not empt".to_string());
4173    }
4174
4175    #[test]
4176    /// repeat char move with no last char
4177    fn repeat_char_move_no_char() {
4178        let mut context = Context::new();
4179        let out = Vec::new();
4180        let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
4181        let mut map = Vi::new();
4182        map.init(&mut ed);
4183        ed.insert_str_after_cursor("abc defg").unwrap();
4184
4185        simulate_keys(&mut map, &mut ed, [Esc, Char('$'), Char(';')].iter());
4186        assert_eq!(ed.cursor(), 7);
4187    }
4188}