mirror of
https://github.com/nushell/nushell
synced 2025-01-14 06:04:09 +00:00
history-menu (#846)
This commit is contained in:
parent
0cecaf82b1
commit
69954a362d
6 changed files with 87 additions and 12 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -2863,7 +2863,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reedline"
|
name = "reedline"
|
||||||
version = "0.2.0"
|
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 = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"crossterm",
|
"crossterm",
|
||||||
|
|
|
@ -17,6 +17,7 @@ pub struct NushellPrompt {
|
||||||
default_vi_visual_prompt_indicator: String,
|
default_vi_visual_prompt_indicator: String,
|
||||||
default_menu_prompt_indicator: String,
|
default_menu_prompt_indicator: String,
|
||||||
default_multiline_indicator: String,
|
default_multiline_indicator: String,
|
||||||
|
default_history_prompt_indicator: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for NushellPrompt {
|
impl Default for NushellPrompt {
|
||||||
|
@ -35,6 +36,7 @@ impl NushellPrompt {
|
||||||
default_vi_visual_prompt_indicator: "v ".to_string(),
|
default_vi_visual_prompt_indicator: "v ".to_string(),
|
||||||
default_menu_prompt_indicator: "| ".to_string(),
|
default_menu_prompt_indicator: "| ".to_string(),
|
||||||
default_multiline_indicator: "::: ".to_string(),
|
default_multiline_indicator: "::: ".to_string(),
|
||||||
|
default_history_prompt_indicator: "? ".to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,11 +69,12 @@ impl NushellPrompt {
|
||||||
left_prompt_string: Option<String>,
|
left_prompt_string: Option<String>,
|
||||||
right_prompt_string: Option<String>,
|
right_prompt_string: Option<String>,
|
||||||
prompt_indicator_string: String,
|
prompt_indicator_string: String,
|
||||||
prompt_indicator_menu: String,
|
|
||||||
prompt_multiline_indicator_string: String,
|
prompt_multiline_indicator_string: String,
|
||||||
prompt_vi: (String, String),
|
prompt_vi: (String, String),
|
||||||
|
prompt_menus: (String, String),
|
||||||
) {
|
) {
|
||||||
let (prompt_vi_insert_string, prompt_vi_visual_string) = prompt_vi;
|
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.left_prompt_string = left_prompt_string;
|
||||||
self.right_prompt_string = right_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_insert_prompt_indicator = prompt_vi_insert_string;
|
||||||
self.default_vi_visual_prompt_indicator = prompt_vi_visual_string;
|
self.default_vi_visual_prompt_indicator = prompt_vi_visual_string;
|
||||||
self.default_multiline_indicator = prompt_multiline_indicator_string;
|
self.default_multiline_indicator = prompt_multiline_indicator_string;
|
||||||
|
|
||||||
self.default_menu_prompt_indicator = prompt_indicator_menu;
|
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 {
|
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::Custom(str) => self.default_wrapped_custom_string(str).into(),
|
||||||
PromptEditMode::Menu => self.default_menu_prompt_indicator.as_str().into(),
|
PromptEditMode::Menu => self.default_menu_prompt_indicator.as_str().into(),
|
||||||
|
PromptEditMode::HistoryMenu => self.default_history_prompt_indicator.as_str().into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,6 +65,7 @@ pub struct Config {
|
||||||
pub log_level: String,
|
pub log_level: String,
|
||||||
pub menu_config: HashMap<String, Value>,
|
pub menu_config: HashMap<String, Value>,
|
||||||
pub keybindings: Vec<ParsedKeybinding>,
|
pub keybindings: Vec<ParsedKeybinding>,
|
||||||
|
pub history_config: HashMap<String, Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
|
@ -86,6 +87,7 @@ impl Default for Config {
|
||||||
log_level: String::new(),
|
log_level: String::new(),
|
||||||
menu_config: HashMap::new(),
|
menu_config: HashMap::new(),
|
||||||
keybindings: Vec::new(),
|
keybindings: Vec::new(),
|
||||||
|
history_config: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -243,6 +245,13 @@ impl Value {
|
||||||
eprintln!("$config.keybindings is not a valid keybindings list")
|
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 => {
|
x => {
|
||||||
eprintln!("$config.{} is an unknown config setting", x)
|
eprintln!("$config.{} is an unknown config setting", x)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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_VI_VISUAL: &str = "PROMPT_INDICATOR_VI_VISUAL";
|
||||||
pub(crate) const PROMPT_INDICATOR_MENU: &str = "PROMPT_INDICATOR_MENU";
|
pub(crate) const PROMPT_INDICATOR_MENU: &str = "PROMPT_INDICATOR_MENU";
|
||||||
pub(crate) const PROMPT_MULTILINE_INDICATOR: &str = "PROMPT_MULTILINE_INDICATOR";
|
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(
|
pub(crate) fn get_prompt_indicators(
|
||||||
config: &Config,
|
config: &Config,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
stack: &Stack,
|
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) {
|
let prompt_indicator = match stack.get_env_var(engine_state, PROMPT_INDICATOR) {
|
||||||
Some(pi) => pi.into_string("", config),
|
Some(pi) => pi.into_string("", config),
|
||||||
None => "〉".to_string(),
|
None => "〉".to_string(),
|
||||||
|
@ -36,22 +37,28 @@ pub(crate) fn get_prompt_indicators(
|
||||||
None => "v ".to_string(),
|
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) {
|
let prompt_menu = match stack.get_env_var(engine_state, PROMPT_INDICATOR_MENU) {
|
||||||
Some(pm) => pm.into_string("", config),
|
Some(pm) => pm.into_string("", config),
|
||||||
None => "| ".to_string(),
|
None => "| ".to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let prompt_multiline = match stack.get_env_var(engine_state, PROMPT_MULTILINE_INDICATOR) {
|
let prompt_history = match stack.get_env_var(engine_state, PROMPT_INDICATOR_HISTORY) {
|
||||||
Some(pm) => pm.into_string("", config),
|
Some(ph) => ph.into_string("", config),
|
||||||
None => "::: ".to_string(),
|
None => "? ".to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
(
|
(
|
||||||
prompt_indicator,
|
prompt_indicator,
|
||||||
prompt_vi_insert,
|
prompt_vi_insert,
|
||||||
prompt_vi_visual,
|
prompt_vi_visual,
|
||||||
prompt_menu,
|
|
||||||
prompt_multiline,
|
prompt_multiline,
|
||||||
|
prompt_menu,
|
||||||
|
prompt_history,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,8 +108,9 @@ pub(crate) fn update_prompt<'prompt>(
|
||||||
prompt_indicator_string,
|
prompt_indicator_string,
|
||||||
prompt_vi_insert_string,
|
prompt_vi_insert_string,
|
||||||
prompt_vi_visual_string,
|
prompt_vi_visual_string,
|
||||||
prompt_indicator_menu,
|
|
||||||
prompt_multiline_string,
|
prompt_multiline_string,
|
||||||
|
prompt_indicator_menu,
|
||||||
|
prompt_indicator_history,
|
||||||
) = get_prompt_indicators(config, engine_state, stack);
|
) = get_prompt_indicators(config, engine_state, stack);
|
||||||
|
|
||||||
let mut stack = stack.clone();
|
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, config, engine_state, &mut stack),
|
||||||
get_prompt_string(PROMPT_COMMAND_RIGHT, config, engine_state, &mut stack),
|
get_prompt_string(PROMPT_COMMAND_RIGHT, config, engine_state, &mut stack),
|
||||||
prompt_indicator_string,
|
prompt_indicator_string,
|
||||||
prompt_indicator_menu,
|
|
||||||
prompt_multiline_string,
|
prompt_multiline_string,
|
||||||
(prompt_vi_insert_string, prompt_vi_visual_string),
|
(prompt_vi_insert_string, prompt_vi_visual_string),
|
||||||
|
(prompt_indicator_menu, prompt_indicator_history),
|
||||||
);
|
);
|
||||||
|
|
||||||
nu_prompt as &dyn Prompt
|
nu_prompt as &dyn Prompt
|
||||||
|
|
|
@ -3,10 +3,10 @@ use nu_color_config::lookup_ansi_color_style;
|
||||||
use nu_protocol::{extract_value, Config, ParsedKeybinding, ShellError, Span, Type, Value};
|
use nu_protocol::{extract_value, Config, ParsedKeybinding, ShellError, Span, Type, Value};
|
||||||
use reedline::{
|
use reedline::{
|
||||||
default_emacs_keybindings, default_vi_insert_keybindings, default_vi_normal_keybindings,
|
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
|
// stored in the config variable
|
||||||
pub(crate) fn create_menu_input(config: &Config) -> ContextMenuInput {
|
pub(crate) fn create_menu_input(config: &Config) -> ContextMenuInput {
|
||||||
let mut input = ContextMenuInput::default();
|
let mut input = ContextMenuInput::default();
|
||||||
|
@ -58,6 +58,52 @@ pub(crate) fn create_menu_input(config: &Config) -> ContextMenuInput {
|
||||||
input
|
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 {
|
pub enum KeybindingsMode {
|
||||||
Emacs(Keybindings),
|
Emacs(Keybindings),
|
||||||
Vi {
|
Vi {
|
||||||
|
@ -215,6 +261,11 @@ fn parse_event(value: Value, config: &Config) -> Result<ReedlineEvent, ShellErro
|
||||||
"menuright" => ReedlineEvent::MenuRight,
|
"menuright" => ReedlineEvent::MenuRight,
|
||||||
"menunext" => ReedlineEvent::MenuNext,
|
"menunext" => ReedlineEvent::MenuNext,
|
||||||
"menuprevious" => ReedlineEvent::MenuPrevious,
|
"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::Mouse
|
||||||
// TODO: add ReedlineEvent::Resize
|
// TODO: add ReedlineEvent::Resize
|
||||||
|
|
|
@ -119,7 +119,8 @@ pub(crate) fn evaluate(ctrlc: Arc<AtomicBool>, engine_state: &mut EngineState) -
|
||||||
.with_menu_completer(
|
.with_menu_completer(
|
||||||
Box::new(NuCompleter::new(engine_state.clone())),
|
Box::new(NuCompleter::new(engine_state.clone())),
|
||||||
reedline_config::create_menu_input(&config),
|
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
|
//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.
|
// turn off the hinter but I don't see any way to do that yet.
|
||||||
|
|
Loading…
Reference in a new issue