diff --git a/src/edit_mode/base.rs b/src/edit_mode/base.rs index 455e2c80e..408098b32 100644 --- a/src/edit_mode/base.rs +++ b/src/edit_mode/base.rs @@ -1,5 +1,5 @@ use crate::{ - enums::{ReedlineEvent, ReedlineRawEvent}, + enums::{EventStatus, ReedlineEvent, ReedlineRawEvent}, PromptEditMode, }; @@ -13,4 +13,9 @@ pub trait EditMode: Send { /// What to display in the prompt indicator fn edit_mode(&self) -> PromptEditMode; + + /// Handles events that apply only to specific edit modes (e.g changing vi mode) + fn handle_mode_specific_event(&mut self, _event: ReedlineEvent) -> EventStatus { + EventStatus::Inapplicable + } } diff --git a/src/edit_mode/vi/mod.rs b/src/edit_mode/vi/mod.rs index 8d92c5e7d..de6bf7227 100644 --- a/src/edit_mode/vi/mod.rs +++ b/src/edit_mode/vi/mod.rs @@ -3,6 +3,8 @@ mod motion; mod parser; mod vi_keybindings; +use std::str::FromStr; + use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers}; pub use vi_keybindings::{default_vi_insert_keybindings, default_vi_normal_keybindings}; @@ -11,7 +13,7 @@ use self::motion::ViCharSearch; use super::EditMode; use crate::{ edit_mode::{keybindings::Keybindings, vi::parser::parse}, - enums::{EditCommand, ReedlineEvent, ReedlineRawEvent}, + enums::{EditCommand, EventStatus, ReedlineEvent, ReedlineRawEvent}, PromptEditMode, PromptViMode, }; @@ -22,6 +24,19 @@ enum ViMode { Visual, } +impl FromStr for ViMode { + type Err = (); + + fn from_str(s: &str) -> Result { + match s { + "normal" => Ok(ViMode::Normal), + "insert" => Ok(ViMode::Insert), + "visual" => Ok(ViMode::Visual), + _ => Err(()), + } + } +} + /// This parses incoming input `Event`s like a Vi-Style editor pub struct Vi { cache: Vec, @@ -174,6 +189,19 @@ impl EditMode for Vi { ViMode::Insert => PromptEditMode::Vi(PromptViMode::Insert), } } + + fn handle_mode_specific_event(&mut self, event: ReedlineEvent) -> EventStatus { + match event { + ReedlineEvent::ViChangeMode(mode_str) => match ViMode::from_str(&mode_str) { + Ok(mode) => { + self.mode = mode; + EventStatus::Handled + } + Err(_) => EventStatus::Inapplicable, + }, + _ => EventStatus::Inapplicable, + } + } } #[cfg(test)] diff --git a/src/engine.rs b/src/engine.rs index b5f6958a3..e13e9184e 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -928,7 +928,8 @@ impl Reedline { | ReedlineEvent::MenuLeft | ReedlineEvent::MenuRight | ReedlineEvent::MenuPageNext - | ReedlineEvent::MenuPagePrevious => Ok(EventStatus::Inapplicable), + | ReedlineEvent::MenuPagePrevious + | ReedlineEvent::ViChangeMode(_) => Ok(EventStatus::Inapplicable), } } @@ -1273,6 +1274,7 @@ impl Reedline { // Exhausting the event handlers is still considered handled Ok(EventStatus::Inapplicable) } + ReedlineEvent::ViChangeMode(_) => Ok(self.edit_mode.handle_mode_specific_event(event)), ReedlineEvent::None | ReedlineEvent::Mouse => Ok(EventStatus::Inapplicable), } } diff --git a/src/enums.rs b/src/enums.rs index 643afb485..f03ae301e 100644 --- a/src/enums.rs +++ b/src/enums.rs @@ -758,6 +758,9 @@ pub enum ReedlineEvent { /// Open text editor OpenEditor, + + /// Change mode (vi mode only) + ViChangeMode(String), } impl Display for ReedlineEvent { @@ -801,11 +804,12 @@ impl Display for ReedlineEvent { ReedlineEvent::MenuPagePrevious => write!(f, "MenuPagePrevious"), ReedlineEvent::ExecuteHostCommand(_) => write!(f, "ExecuteHostCommand"), ReedlineEvent::OpenEditor => write!(f, "OpenEditor"), + ReedlineEvent::ViChangeMode(_) => write!(f, "ViChangeMode mode: "), } } } -pub(crate) enum EventStatus { +pub enum EventStatus { Handled, Inapplicable, Exits(Signal),