Skip to content
Open
6 changes: 5 additions & 1 deletion examples/demo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,11 @@ fn main() -> reedline::Result<()> {

add_newline_keybinding(&mut insert_keybindings);

Box::new(Vi::new(insert_keybindings, normal_keybindings))
Box::new(Vi::new(
insert_keybindings,
normal_keybindings,
(KeyCode::Null, KeyCode::Null),
))
} else {
let mut keybindings = default_emacs_keybindings();
add_menu_keybindings(&mut keybindings);
Expand Down
76 changes: 61 additions & 15 deletions src/edit_mode/vi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,44 +46,87 @@
previous: Option<ReedlineEvent>,
// last f, F, t, T motion for ; and ,
last_char_search: Option<ViCharSearch>,
alternate_esc_seq: (KeyCode, KeyCode),
most_recent_keycode: KeyCode,
}

impl Default for Vi {
fn default() -> Self {
Vi {
insert_keybindings: default_vi_insert_keybindings(),
normal_keybindings: default_vi_normal_keybindings(),
alternate_esc_seq: (KeyCode::Null, KeyCode::Null),
cache: Vec::new(),
mode: ViMode::Insert,
previous: None,
last_char_search: None,
most_recent_keycode: KeyCode::Null,
}
}
}

impl Vi {
/// Creates Vi editor using defined keybindings
pub fn new(insert_keybindings: Keybindings, normal_keybindings: Keybindings) -> Self {
pub fn new(
insert_keybindings: Keybindings,
normal_keybindings: Keybindings,
alternate_esc_seq: (KeyCode, KeyCode),
) -> Self {
Self {
insert_keybindings,
normal_keybindings,
alternate_esc_seq,
..Default::default()
}
}
}

fn exit_insert_mode(editor: &mut Vi, new_mode: ViMode) -> ReedlineEvent {
editor.most_recent_keycode = KeyCode::Null;

Check warning on line 85 in src/edit_mode/vi/mod.rs

View workflow job for this annotation

GitHub Actions / build-lint-test (ubuntu-latest, stable, default)

Diff in /home/runner/work/reedline/reedline/src/edit_mode/vi/mod.rs

Check warning on line 85 in src/edit_mode/vi/mod.rs

View workflow job for this annotation

GitHub Actions / build-lint-test (ubuntu-latest, stable, sqlite)

Diff in /home/runner/work/reedline/reedline/src/edit_mode/vi/mod.rs

Check warning on line 85 in src/edit_mode/vi/mod.rs

View workflow job for this annotation

GitHub Actions / build-lint-test (ubuntu-latest, stable, external_printer)

Diff in /home/runner/work/reedline/reedline/src/edit_mode/vi/mod.rs

Check warning on line 85 in src/edit_mode/vi/mod.rs

View workflow job for this annotation

GitHub Actions / build-lint-test (ubuntu-latest, stable, bashisms)

Diff in /home/runner/work/reedline/reedline/src/edit_mode/vi/mod.rs

Check warning on line 85 in src/edit_mode/vi/mod.rs

View workflow job for this annotation

GitHub Actions / build-lint-test (ubuntu-latest, stable, basqlite)

Diff in /home/runner/work/reedline/reedline/src/edit_mode/vi/mod.rs
editor.cache.clear();
editor.mode = new_mode;
ReedlineEvent::Multiple(vec![ReedlineEvent::Esc, ReedlineEvent::Repaint, ReedlineEvent::Left])
}

impl EditMode for Vi {
fn parse_event(&mut self, event: ReedlineRawEvent) -> ReedlineEvent {
match event.into() {
Event::Key(KeyEvent {
code, modifiers, ..
}) => match (self.mode, modifiers, code) {
(ViMode::Normal, KeyModifiers::NONE, KeyCode::Char('v')) => {
self.cache.clear();
self.mode = ViMode::Visual;
ReedlineEvent::Multiple(vec![ReedlineEvent::Esc, ReedlineEvent::Repaint])
}) => match (
self.mode,
modifiers,
code,
self.alternate_esc_seq,
self.most_recent_keycode,
) {
(ViMode::Insert, KeyModifiers::NONE, code, (e1, e2), mr)
if code == e2 && mr == e1 =>
{
exit_insert_mode(self, ViMode::Normal)
}
(ViMode::Normal, KeyModifiers::NONE, KeyCode::Char('v'), _, _) => {
exit_insert_mode(self, ViMode::Visual)
}
(ViMode::Insert, KeyModifiers::NONE, code, (e1, _), _) if code == e1 => {
self.most_recent_keycode = code;
ReedlineEvent::None
}
(ViMode::Normal | ViMode::Visual, modifier, KeyCode::Char(c)) => {
(
ViMode::Insert,
KeyModifiers::NONE,
KeyCode::Char(code),
(KeyCode::Char(e1), KeyCode::Char(e2)),
KeyCode::Char(mr),
) if code != e2 && mr == e1 => {
self.most_recent_keycode = KeyCode::Char(code);
ReedlineEvent::Multiple(vec![
ReedlineEvent::Edit(vec![EditCommand::InsertChar(e1)]),
ReedlineEvent::Edit(vec![EditCommand::InsertChar(code)]),
])
}

(ViMode::Normal | ViMode::Visual, modifier, KeyCode::Char(c), _, _) => {
let c = c.to_ascii_lowercase();

if let Some(event) = self
Expand Down Expand Up @@ -117,7 +160,7 @@
ReedlineEvent::None
}
}
(ViMode::Insert, modifier, KeyCode::Char(c)) => {
(ViMode::Insert, modifier, KeyCode::Char(c), _, _) => {
// Note. The modifier can also be a combination of modifiers, for
// example:
// KeyModifiers::CONTROL | KeyModifiers::ALT
Expand All @@ -142,6 +185,7 @@
| KeyModifiers::ALT
| KeyModifiers::SHIFT
{
self.most_recent_keycode = KeyCode::Char(c);
ReedlineEvent::Edit(vec![EditCommand::InsertChar(
if modifier == KeyModifiers::SHIFT {
c.to_ascii_uppercase()
Expand All @@ -151,15 +195,17 @@
)])
} else {
ReedlineEvent::None
}

Check warning on line 198 in src/edit_mode/vi/mod.rs

View workflow job for this annotation

GitHub Actions / build-lint-test (ubuntu-latest, stable, default)

Diff in /home/runner/work/reedline/reedline/src/edit_mode/vi/mod.rs

Check warning on line 198 in src/edit_mode/vi/mod.rs

View workflow job for this annotation

GitHub Actions / build-lint-test (ubuntu-latest, stable, sqlite)

Diff in /home/runner/work/reedline/reedline/src/edit_mode/vi/mod.rs

Check warning on line 198 in src/edit_mode/vi/mod.rs

View workflow job for this annotation

GitHub Actions / build-lint-test (ubuntu-latest, stable, external_printer)

Diff in /home/runner/work/reedline/reedline/src/edit_mode/vi/mod.rs

Check warning on line 198 in src/edit_mode/vi/mod.rs

View workflow job for this annotation

GitHub Actions / build-lint-test (ubuntu-latest, stable, bashisms)

Diff in /home/runner/work/reedline/reedline/src/edit_mode/vi/mod.rs

Check warning on line 198 in src/edit_mode/vi/mod.rs

View workflow job for this annotation

GitHub Actions / build-lint-test (ubuntu-latest, stable, basqlite)

Diff in /home/runner/work/reedline/reedline/src/edit_mode/vi/mod.rs
})
}
(_, KeyModifiers::NONE, KeyCode::Esc) => {
self.cache.clear();
self.mode = ViMode::Normal;
ReedlineEvent::Multiple(vec![ReedlineEvent::Esc, ReedlineEvent::Repaint])
(_, KeyModifiers::NONE, KeyCode::Esc, _, _) => exit_insert_mode(self, ViMode::Normal),
(_, KeyModifiers::NONE, KeyCode::Enter, _, _) => {
self.mode = ViMode::Insert;
self.insert_keybindings
.find_binding(modifiers, code)
.unwrap_or(ReedlineEvent::Enter)
}
(ViMode::Normal | ViMode::Visual, _, _) => self
(ViMode::Normal | ViMode::Visual, _, _, _, _) => self
.normal_keybindings
.find_binding(modifiers, code)
.unwrap_or_else(|| {
Expand All @@ -171,7 +217,7 @@
ReedlineEvent::None
}
}),
(ViMode::Insert, _, _) => self
(ViMode::Insert, _, _, _, _) => self
.insert_keybindings
.find_binding(modifiers, code)
.unwrap_or_else(|| {
Expand Down Expand Up @@ -227,10 +273,10 @@
ReedlineRawEvent::try_from(Event::Key(KeyEvent::new(KeyCode::Esc, KeyModifiers::NONE)))
.unwrap();
let result = vi.parse_event(esc);

Check warning on line 276 in src/edit_mode/vi/mod.rs

View workflow job for this annotation

GitHub Actions / build-lint-test (ubuntu-latest, stable, default)

Diff in /home/runner/work/reedline/reedline/src/edit_mode/vi/mod.rs

Check warning on line 276 in src/edit_mode/vi/mod.rs

View workflow job for this annotation

GitHub Actions / build-lint-test (ubuntu-latest, stable, sqlite)

Diff in /home/runner/work/reedline/reedline/src/edit_mode/vi/mod.rs

Check warning on line 276 in src/edit_mode/vi/mod.rs

View workflow job for this annotation

GitHub Actions / build-lint-test (ubuntu-latest, stable, external_printer)

Diff in /home/runner/work/reedline/reedline/src/edit_mode/vi/mod.rs

Check warning on line 276 in src/edit_mode/vi/mod.rs

View workflow job for this annotation

GitHub Actions / build-lint-test (ubuntu-latest, stable, bashisms)

Diff in /home/runner/work/reedline/reedline/src/edit_mode/vi/mod.rs

Check warning on line 276 in src/edit_mode/vi/mod.rs

View workflow job for this annotation

GitHub Actions / build-lint-test (ubuntu-latest, stable, basqlite)

Diff in /home/runner/work/reedline/reedline/src/edit_mode/vi/mod.rs
assert_eq!(
result,
ReedlineEvent::Multiple(vec![ReedlineEvent::Esc, ReedlineEvent::Repaint])
ReedlineEvent::Multiple(vec![ReedlineEvent::Esc, ReedlineEvent::Repaint, ReedlineEvent::Left])
);
assert!(matches!(vi.mode, ViMode::Normal));
}
Expand Down
3 changes: 2 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,12 +166,13 @@
//! // Create a reedline object with custom edit mode
//! // This can define a keybinding setting or enable vi-emulation
//! use reedline::{
//! default_vi_insert_keybindings, default_vi_normal_keybindings, EditMode, Reedline, Vi,
//! default_vi_insert_keybindings, default_vi_normal_keybindings, EditMode, Reedline, Vi, KeyCode
//! };
//!
//! let mut line_editor = Reedline::create().with_edit_mode(Box::new(Vi::new(
//! default_vi_insert_keybindings(),
//! default_vi_normal_keybindings(),
//! (KeyCode::Null, KeyCode::Null),
//! )));
//! ```
//!
Expand Down
Loading