diff --git a/Cargo.lock b/Cargo.lock index 40efc80a07..472fa919e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2863,7 +2863,7 @@ dependencies = [ [[package]] name = "reedline" version = "0.2.0" -source = "git+https://github.com/nushell/reedline?branch=main#7a07ab2bcca2e0287a1efcf8ccdf9845229428c5" +source = "git+https://github.com/nushell/reedline?branch=main#d7f42e5de4aeee9332dc8eaff07e68923401edcf" dependencies = [ "chrono", "crossterm", diff --git a/crates/nu-cli/src/prompt.rs b/crates/nu-cli/src/prompt.rs index fcc181bc12..7f77598c1f 100644 --- a/crates/nu-cli/src/prompt.rs +++ b/crates/nu-cli/src/prompt.rs @@ -17,6 +17,7 @@ pub struct NushellPrompt { default_vi_visual_prompt_indicator: String, default_menu_prompt_indicator: String, default_multiline_indicator: String, + default_history_prompt_indicator: String, } impl Default for NushellPrompt { @@ -35,6 +36,7 @@ impl NushellPrompt { default_vi_visual_prompt_indicator: "v ".to_string(), default_menu_prompt_indicator: "| ".to_string(), default_multiline_indicator: "::: ".to_string(), + default_history_prompt_indicator: "? ".to_string(), } } @@ -67,11 +69,12 @@ impl NushellPrompt { left_prompt_string: Option, right_prompt_string: Option, prompt_indicator_string: String, - prompt_indicator_menu: String, prompt_multiline_indicator_string: String, prompt_vi: (String, String), + prompt_menus: (String, String), ) { let (prompt_vi_insert_string, prompt_vi_visual_string) = prompt_vi; + let (prompt_indicator_menu, prompt_history_indicator_menu) = prompt_menus; self.left_prompt_string = left_prompt_string; self.right_prompt_string = right_prompt_string; @@ -79,7 +82,9 @@ impl NushellPrompt { self.default_vi_insert_prompt_indicator = prompt_vi_insert_string; self.default_vi_visual_prompt_indicator = prompt_vi_visual_string; self.default_multiline_indicator = prompt_multiline_indicator_string; + self.default_menu_prompt_indicator = prompt_indicator_menu; + self.default_history_prompt_indicator = prompt_history_indicator_menu; } fn default_wrapped_custom_string(&self, str: String) -> String { @@ -117,6 +122,7 @@ impl Prompt for NushellPrompt { }, PromptEditMode::Custom(str) => self.default_wrapped_custom_string(str).into(), PromptEditMode::Menu => self.default_menu_prompt_indicator.as_str().into(), + PromptEditMode::HistoryMenu => self.default_history_prompt_indicator.as_str().into(), } } diff --git a/crates/nu-protocol/src/config.rs b/crates/nu-protocol/src/config.rs index 0525e395ec..994cdd4fa3 100644 --- a/crates/nu-protocol/src/config.rs +++ b/crates/nu-protocol/src/config.rs @@ -65,6 +65,7 @@ pub struct Config { pub log_level: String, pub menu_config: HashMap, pub keybindings: Vec, + pub history_config: HashMap, } impl Default for Config { @@ -86,6 +87,7 @@ impl Default for Config { log_level: String::new(), menu_config: HashMap::new(), keybindings: Vec::new(), + history_config: HashMap::new(), } } } @@ -243,6 +245,13 @@ impl Value { eprintln!("$config.keybindings is not a valid keybindings list") } } + "history_config" => { + if let Ok(map) = create_map(value, &config) { + config.history_config = map; + } else { + eprintln!("$config.history_config is not a record") + } + } x => { eprintln!("$config.{} is an unknown config setting", x) } diff --git a/src/prompt_update.rs b/src/prompt_update.rs index b781d22d34..517d65a3b6 100644 --- a/src/prompt_update.rs +++ b/src/prompt_update.rs @@ -15,12 +15,13 @@ pub(crate) const PROMPT_INDICATOR_VI_INSERT: &str = "PROMPT_INDICATOR_VI_INSERT" pub(crate) const PROMPT_INDICATOR_VI_VISUAL: &str = "PROMPT_INDICATOR_VI_VISUAL"; pub(crate) const PROMPT_INDICATOR_MENU: &str = "PROMPT_INDICATOR_MENU"; pub(crate) const PROMPT_MULTILINE_INDICATOR: &str = "PROMPT_MULTILINE_INDICATOR"; +pub(crate) const PROMPT_INDICATOR_HISTORY: &str = "PROMPT_INDICATOR_HISTORY"; pub(crate) fn get_prompt_indicators( config: &Config, engine_state: &EngineState, stack: &Stack, -) -> (String, String, String, String, String) { +) -> (String, String, String, String, String, String) { let prompt_indicator = match stack.get_env_var(engine_state, PROMPT_INDICATOR) { Some(pi) => pi.into_string("", config), None => "〉".to_string(), @@ -36,22 +37,28 @@ pub(crate) fn get_prompt_indicators( None => "v ".to_string(), }; + let prompt_multiline = match stack.get_env_var(engine_state, PROMPT_MULTILINE_INDICATOR) { + Some(pm) => pm.into_string("", config), + None => "::: ".to_string(), + }; + let prompt_menu = match stack.get_env_var(engine_state, PROMPT_INDICATOR_MENU) { Some(pm) => pm.into_string("", config), None => "| ".to_string(), }; - let prompt_multiline = match stack.get_env_var(engine_state, PROMPT_MULTILINE_INDICATOR) { - Some(pm) => pm.into_string("", config), - None => "::: ".to_string(), + let prompt_history = match stack.get_env_var(engine_state, PROMPT_INDICATOR_HISTORY) { + Some(ph) => ph.into_string("", config), + None => "? ".to_string(), }; ( prompt_indicator, prompt_vi_insert, prompt_vi_visual, - prompt_menu, prompt_multiline, + prompt_menu, + prompt_history, ) } @@ -101,8 +108,9 @@ pub(crate) fn update_prompt<'prompt>( prompt_indicator_string, prompt_vi_insert_string, prompt_vi_visual_string, - prompt_indicator_menu, prompt_multiline_string, + prompt_indicator_menu, + prompt_indicator_history, ) = get_prompt_indicators(config, engine_state, stack); let mut stack = stack.clone(); @@ -112,9 +120,9 @@ pub(crate) fn update_prompt<'prompt>( get_prompt_string(PROMPT_COMMAND, config, engine_state, &mut stack), get_prompt_string(PROMPT_COMMAND_RIGHT, config, engine_state, &mut stack), prompt_indicator_string, - prompt_indicator_menu, prompt_multiline_string, (prompt_vi_insert_string, prompt_vi_visual_string), + (prompt_indicator_menu, prompt_indicator_history), ); nu_prompt as &dyn Prompt diff --git a/src/reedline_config.rs b/src/reedline_config.rs index 2497471d74..df3cdd77c9 100644 --- a/src/reedline_config.rs +++ b/src/reedline_config.rs @@ -3,10 +3,10 @@ use nu_color_config::lookup_ansi_color_style; use nu_protocol::{extract_value, Config, ParsedKeybinding, ShellError, Span, Type, Value}; use reedline::{ default_emacs_keybindings, default_vi_insert_keybindings, default_vi_normal_keybindings, - ContextMenuInput, EditCommand, Keybindings, ReedlineEvent, + ContextMenuInput, EditCommand, HistoryMenuInput, Keybindings, ReedlineEvent, }; -// This creates an input object for the context menu based on the dictionary +// Creates an input object for the context menu based on the dictionary // stored in the config variable pub(crate) fn create_menu_input(config: &Config) -> ContextMenuInput { let mut input = ContextMenuInput::default(); @@ -58,6 +58,52 @@ pub(crate) fn create_menu_input(config: &Config) -> ContextMenuInput { input } +// Creates an input object for the history menu based on the dictionary +// stored in the config variable +pub(crate) fn create_history_input(config: &Config) -> HistoryMenuInput { + let mut input = HistoryMenuInput::default(); + + input = match config + .history_config + .get("page_size") + .and_then(|value| value.as_integer().ok()) + { + Some(value) => input.with_page_size(value as usize), + None => input, + }; + + input = match config + .history_config + .get("selector") + .and_then(|value| value.as_string().ok()) + { + Some(value) => { + let char = value.chars().next().unwrap_or(':'); + input.with_row_char(char) + } + None => input, + }; + + input = match config + .history_config + .get("text_style") + .and_then(|value| value.as_string().ok()) + { + Some(value) => input.with_text_style(lookup_ansi_color_style(&value)), + None => input, + }; + + input = match config + .history_config + .get("selected_text_style") + .and_then(|value| value.as_string().ok()) + { + Some(value) => input.with_selected_text_style(lookup_ansi_color_style(&value)), + None => input, + }; + + input +} pub enum KeybindingsMode { Emacs(Keybindings), Vi { @@ -215,6 +261,11 @@ fn parse_event(value: Value, config: &Config) -> Result ReedlineEvent::MenuRight, "menunext" => ReedlineEvent::MenuNext, "menuprevious" => ReedlineEvent::MenuPrevious, + "historymenu" => ReedlineEvent::HistoryMenu, + "historymenunext" => ReedlineEvent::HistoryMenuNext, + "historymenuprevious" => ReedlineEvent::HistoryMenuPrevious, + "historypagenext" => ReedlineEvent::HistoryPageNext, + "historypageprevious" => ReedlineEvent::HistoryPagePrevious, // TODO: add ReedlineEvent::Mouse // TODO: add ReedlineEvent::Resize diff --git a/src/repl.rs b/src/repl.rs index 4bed676284..3e2c224011 100644 --- a/src/repl.rs +++ b/src/repl.rs @@ -119,7 +119,8 @@ pub(crate) fn evaluate(ctrlc: Arc, engine_state: &mut EngineState) - .with_menu_completer( Box::new(NuCompleter::new(engine_state.clone())), reedline_config::create_menu_input(&config), - ); + ) + .with_history_menu(reedline_config::create_history_input(&config)); //FIXME: if config.use_ansi_coloring is false then we should // turn off the hinter but I don't see any way to do that yet.