Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modularization of the main struct #134

Merged
merged 21 commits into from
Aug 28, 2021
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 28 additions & 69 deletions src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,23 +65,25 @@ impl PromptWidget {
}
}

trait EventParser {
trait InputParser {
fn parse_event(&self, event: Event) -> ReedlineEvent;
fn update_keybindings(&mut self, keybindings: Keybindings);
fn edit_mode(&self) -> EditMode;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a makeshift interface for now. It should remain the same in spirit only (i.e. it parses Events to ReedlineEvents) but the interface will definitely need updating.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: Now the user of this lib can develop their own InputParser's without any help from the lib. All they need to do is adhere to this interface and we will be done. (prompt handling might pose a caveat in this though)


struct EmacsEventParser {
struct EmacsInputParser {
keybindings: Keybindings,
}

impl Default for EmacsEventParser {
impl Default for EmacsInputParser {
fn default() -> Self {
EmacsEventParser {
EmacsInputParser {
keybindings: default_emacs_keybindings(),
}
}
}

impl EventParser for EmacsEventParser {
impl InputParser for EmacsInputParser {
fn parse_event(&self, event: Event) -> ReedlineEvent {
match event {
Event::Key(KeyEvent { code, modifiers }) => match (modifiers, code) {
Expand All @@ -107,6 +109,15 @@ impl EventParser for EmacsEventParser {
Event::Resize(width, height) => ReedlineEvent::Resize(width, height),
}
}

// HACK: This about this interface more
fn update_keybindings(&mut self, keybindings: Keybindings) {
self.keybindings = keybindings;
}

fn edit_mode(&self) -> EditMode {
EditMode::Emacs
}
}

/// Line editor engine
Expand Down Expand Up @@ -139,11 +150,7 @@ pub struct Reedline {
// Stdout
painter: Painter,

// Keybindings
keybindings: HashMap<EditMode, Keybindings>,

// Edit mode
edit_mode: EditMode,
input_parser: Box<dyn InputParser>,

tab_handler: Box<dyn ComplationActionHandler>,

Expand All @@ -165,13 +172,14 @@ impl Reedline {
// Note: this is started with a garbage value
let prompt_widget = Default::default();

let input_parser = Box::new(EmacsInputParser::default());

let reedline = Reedline {
editor: Editor::default(),
history,
input_mode: InputMode::Regular,
painter,
keybindings: keybindings_hashmap,
edit_mode: EditMode::Emacs,
input_parser,
tab_handler: Box::new(DefaultCompletionActionHandler::default()),
terminal_size,
prompt_widget,
Expand Down Expand Up @@ -290,36 +298,22 @@ impl Reedline {

/// A builder which configures the keybindings for your instance of the Reedline engine
pub fn with_keybindings(mut self, keybindings: Keybindings) -> Reedline {
self.keybindings.insert(EditMode::Emacs, keybindings);
self.input_parser.update_keybindings(keybindings);

self
}

/// A builder which configures the edit mode for your instance of the Reedline engine
pub fn with_edit_mode(mut self, edit_mode: EditMode) -> Reedline {
self.edit_mode = edit_mode;
match edit_mode {
EditMode::Emacs => {
self.input_parser = Box::new(EmacsInputParser::default());
}
};

self
}

/// Gets the current keybindings for Emacs mode
pub fn get_keybindings(&self) -> &Keybindings {
self.keybindings
.get(&EditMode::Emacs)
.expect("Internal error: emacs should always be supported")
}

/// Sets the keybindings to the given keybindings
/// Note: keybindings are set on the emacs mode. The vi mode is not configurable
pub fn update_keybindings(&mut self, keybindings: Keybindings) {
self.keybindings.insert(EditMode::Emacs, keybindings);
}

/// Get the current edit mode
pub fn edit_mode(&self) -> EditMode {
self.edit_mode
}

fn terminal_columns(&self) -> u16 {
self.terminal_size.0
}
Expand All @@ -330,22 +324,11 @@ impl Reedline {

/// Returns the corresponding expected prompt style for the given edit mode
pub fn prompt_edit_mode(&self) -> PromptEditMode {
match self.edit_mode {
match self.input_parser.edit_mode() {
EditMode::Emacs => PromptEditMode::Emacs,
}
}

fn find_keybinding(
&self,
modifier: KeyModifiers,
key_code: KeyCode,
) -> Option<Vec<EditCommand>> {
self.keybindings
.get(&self.edit_mode)
.expect("Internal error: expected to find keybindings for edit mode")
.find_binding(modifier, key_code)
}

/// Output the complete [`History`] chronologically with numbering to the terminal
pub fn print_history(&mut self) -> Result<()> {
let history: Vec<_> = self
Expand Down Expand Up @@ -883,31 +866,7 @@ impl Reedline {

fn event_gen(&self) -> io::Result<ReedlineEvent> {
let event = read()?;
let editor_event = match event {
Event::Key(KeyEvent { code, modifiers }) => match (modifiers, code) {
(KeyModifiers::NONE, KeyCode::Tab) => ReedlineEvent::HandleTab,
(KeyModifiers::CONTROL, KeyCode::Char('d')) => ReedlineEvent::CtrlD,
(KeyModifiers::CONTROL, KeyCode::Char('c')) => ReedlineEvent::CtrlC,
(KeyModifiers::CONTROL, KeyCode::Char('l')) => ReedlineEvent::ClearScreen,
(KeyModifiers::NONE, KeyCode::Char(c))
| (KeyModifiers::SHIFT, KeyCode::Char(c)) => {
ReedlineEvent::EditInsert(EditCommand::InsertChar(c))
}
(KeyModifiers::NONE, KeyCode::Enter) => ReedlineEvent::Enter,
_ => {
if let Some(binding) = self.find_keybinding(modifiers, code) {
ReedlineEvent::Edit(binding)
} else {
ReedlineEvent::Edit(vec![])
}
}
},

Event::Mouse(_) => ReedlineEvent::Mouse,
Event::Resize(width, height) => ReedlineEvent::Resize(width, height),
};

Ok(editor_event)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And finally, we achieve complete segregation of even parsing into a separate struct.

Ok(self.input_parser.parse_event(event))
}

/// Helper implemting the logic for [`Reedline::read_line()`] to be wrapped
Expand Down