diff --git a/src/engine.rs b/src/engine.rs index 7a16641..c0c3191 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -2,7 +2,7 @@ use crate::{ clip_buffer::{get_default_clipboard, Clipboard}, default_emacs_keybindings, keybindings::{default_vi_insert_keybindings, default_vi_normal_keybindings, Keybindings}, - prompt::PromptMode, + prompt::{PromptEditMode, PromptHistorySearch, PromptHistorySearchStatus, PromptViMode}, DefaultPrompt, Prompt, }; use crate::{history::History, line_buffer::LineBuffer}; @@ -147,10 +147,11 @@ impl Reedline { self.edit_mode } - pub fn prompt_mode(&self) -> PromptMode { + pub fn prompt_edit_mode(&self) -> PromptEditMode { match self.edit_mode { - EditMode::ViInsert => PromptMode::ViInsert, - _ => PromptMode::Normal, + EditMode::ViInsert => PromptEditMode::Vi(PromptViMode::Insert), + EditMode::ViNormal => PromptEditMode::Vi(PromptViMode::Normal), + EditMode::Emacs => PromptEditMode::Emacs, } } @@ -636,7 +637,7 @@ impl Reedline { /// Used at the beginning of each [`Reedline::read_line()`] call. fn queue_prompt(&mut self, screen_width: usize) -> Result<()> { // print our prompt - let prompt_mode = self.prompt_mode(); + let prompt_mode = self.prompt_edit_mode(); self.stdout .queue(MoveToColumn(0))? @@ -654,7 +655,7 @@ impl Reedline { /// the prompt fn queue_prompt_indicator(&mut self) -> Result<()> { // print our prompt - let prompt_mode = self.prompt_mode(); + let prompt_mode = self.prompt_edit_mode(); self.stdout .queue(MoveToColumn(0))? .queue(SetForegroundColor(self.prompt.get_prompt_color()))? @@ -724,19 +725,21 @@ impl Reedline { .expect("couldn't get history_search reference"); let status = if search.result.is_none() && !search.search_string.is_empty() { - "failed " + PromptHistorySearchStatus::Failing } else { - "" + PromptHistorySearchStatus::Passing }; + let prompt_history_search = PromptHistorySearch::new(status, search.search_string.clone()); + let history_indicator = self + .prompt + .render_prompt_history_search_indicator(prompt_history_search); + // print search prompt self.stdout .queue(MoveToColumn(0))? .queue(SetForegroundColor(Color::Blue))? - .queue(Print(format!( - "({}reverse-search)`{}':", - status, search.search_string - )))? + .queue(Print(history_indicator))? .queue(ResetColor)?; match search.result { diff --git a/src/prompt.rs b/src/prompt.rs index ac93bcd..f3e2fd7 100644 --- a/src/prompt.rs +++ b/src/prompt.rs @@ -5,13 +5,39 @@ use std::env; pub static DEFAULT_PROMPT_COLOR: Color = Color::Blue; pub static DEFAULT_PROMPT_INDICATOR: &str = "〉"; pub static DEFAULT_VI_INSERT_PROMPT_INDICATOR: &str = ": "; +pub static DEFAULT_VI_VISUAL_PROMPT_INDICATOR: &str = "v "; pub static DEFAULT_MULTILINE_INDICATOR: &str = "::: "; -/// The type of prompt indicator to display -pub enum PromptMode { +pub enum PromptHistorySearchStatus { + Passing, + Failing, +} + +pub struct PromptHistorySearch { + status: PromptHistorySearchStatus, + term: String, +} + +impl PromptHistorySearch { + pub fn new(status: PromptHistorySearchStatus, search_term: String) -> Self { + PromptHistorySearch { + status, + term: search_term, + } + } +} + +pub enum PromptEditMode { + Default, + Emacs, + Vi(PromptViMode), + Custom(String), +} + +pub enum PromptViMode { Normal, - ViInsert, - Multiline, + Insert, + Visual, } /// API to provide a custom prompt. @@ -22,7 +48,12 @@ pub trait Prompt { /// Provide content off the full prompt. May use a line above the entry buffer that fits into `screen_width`. fn render_prompt(&self, screen_width: usize) -> String; /// Render the default prompt indicator - fn render_prompt_indicator(&self, prompt_mode: PromptMode) -> String; + fn render_prompt_indicator(&self, prompt_mode: PromptEditMode) -> String; + /// Render the default prompt indicator + fn render_prompt_multiline_indicator(&self) -> String; + /// Render the default prompt indicator + fn render_prompt_history_search_indicator(&self, history_search: PromptHistorySearch) + -> String; /// Render the vi insert mode prompt indicator /// Get back the prompt color fn get_prompt_color(&self) -> Color { @@ -35,13 +66,35 @@ impl Prompt for DefaultPrompt { DefaultPrompt::render_prompt(self, screen_width) } - fn render_prompt_indicator(&self, prompt_mode: PromptMode) -> String { - match prompt_mode { - PromptMode::Normal => DEFAULT_PROMPT_INDICATOR.into(), - PromptMode::ViInsert => DEFAULT_VI_INSERT_PROMPT_INDICATOR.into(), - PromptMode::Multiline => DEFAULT_MULTILINE_INDICATOR.into(), + fn render_prompt_indicator(&self, edit_mode: PromptEditMode) -> String { + match edit_mode { + PromptEditMode::Default => DEFAULT_PROMPT_INDICATOR.into(), + PromptEditMode::Emacs => DEFAULT_PROMPT_INDICATOR.into(), + PromptEditMode::Vi(vi_mode) => match vi_mode { + PromptViMode::Normal => DEFAULT_PROMPT_INDICATOR.into(), + PromptViMode::Insert => DEFAULT_VI_INSERT_PROMPT_INDICATOR.into(), + PromptViMode::Visual => DEFAULT_VI_VISUAL_PROMPT_INDICATOR.into(), + }, + PromptEditMode::Custom(str) => self.default_wrapped_custom_string(str), } } + + fn render_prompt_multiline_indicator(&self) -> String { + DEFAULT_MULTILINE_INDICATOR.into() + } + + fn render_prompt_history_search_indicator( + &self, + history_search: PromptHistorySearch, + ) -> String { + let prefix = match history_search.status { + PromptHistorySearchStatus::Passing => "", + PromptHistorySearchStatus::Failing => "failing ", + }; + // NOTE: magic strings, givent there is logic on how these compose I am not sure if it + // is worth extracting in to static constant + format!("({}reverse-search: {})", prefix, history_search.term) + } } impl Default for DefaultPrompt { @@ -90,6 +143,10 @@ impl DefaultPrompt { prompt_str } + + fn default_wrapped_custom_string(&self, str: String) -> String { + format!("({})", str) + } } fn get_working_dir() -> Result {