From 7e9f87c57fffa73ae36ea43279dfddaadb99ef25 Mon Sep 17 00:00:00 2001 From: Darren Schroeder <343840+fdncred@users.noreply.github.com> Date: Wed, 22 Jul 2020 16:43:52 -0500 Subject: [PATCH] Expose all rustyline configuration points (#2238) * Added all rustyline config points * comments cleanup * my good friend fmt keeps changing his mind --- crates/nu-cli/src/cli.rs | 233 ++++++++++++++++++++---------- crates/nu-cli/src/shell/helper.rs | 2 +- 2 files changed, 159 insertions(+), 76 deletions(-) diff --git a/crates/nu-cli/src/cli.rs b/crates/nu-cli/src/cli.rs index ef8d904fc7..d48622cafd 100644 --- a/crates/nu-cli/src/cli.rs +++ b/crates/nu-cli/src/cli.rs @@ -7,6 +7,7 @@ use crate::context::Context; use crate::git::current_branch; use crate::path::canonicalize; use crate::prelude::*; +use crate::shell::Helper; use crate::EnvironmentSyncer; use futures_codec::FramedRead; use nu_errors::{ProximateShellError, ShellDiagnostic, ShellError}; @@ -16,11 +17,9 @@ use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue, Value}; use nu_source::Tagged; use log::{debug, trace}; +use rustyline::config::{ColorMode, CompletionType, Config}; use rustyline::error::ReadlineError; -use rustyline::{ - self, config::Configurer, config::EditMode, At, Cmd, ColorMode, CompletionType, Config, Editor, - KeyPress, Movement, Word, -}; +use rustyline::{self, config::Configurer, At, Cmd, Editor, KeyPress, Movement, Word}; use std::error::Error; use std::io::{BufRead, BufReader, Write}; use std::iter::Iterator; @@ -521,18 +520,12 @@ pub async fn run_pipeline_standalone( Ok(()) } -/// The entry point for the CLI. Will register all known internal commands, load experimental commands, load plugins, then prepare the prompt and line reader for input. -pub async fn cli( - mut syncer: EnvironmentSyncer, - mut context: Context, -) -> Result<(), Box> { +pub fn set_rustyline_configuration() -> (Editor, IndexMap) { #[cfg(windows)] const DEFAULT_COMPLETION_MODE: CompletionType = CompletionType::Circular; #[cfg(not(windows))] const DEFAULT_COMPLETION_MODE: CompletionType = CompletionType::List; - let _ = load_plugins(&mut context); - let config = Config::builder().color_mode(ColorMode::Forced).build(); let mut rl: Editor<_> = Editor::with_config(config); @@ -550,14 +543,165 @@ pub async fn cli( println!("Error loading keybindings: {:?}", e); } + let config = match config::config(Tag::unknown()) { + Ok(config) => config, + Err(e) => { + eprintln!("Config could not be loaded."); + if let ShellError { + error: ProximateShellError::Diagnostic(ShellDiagnostic { diagnostic }), + .. + } = e + { + eprintln!("{}", diagnostic.message); + } + IndexMap::new() + } + }; + + if let Ok(config) = config::config(Tag::unknown()) { + if let Some(batvars) = config.get("line_editor") { + for (idx, value) in batvars.row_entries() { + match idx.as_ref() { + "max_history_size" => { + let max_history_size = match value.as_u64() { + Ok(n) => n as usize, + _ => 1000 as usize, + }; + rl.set_max_history_size(max_history_size as usize); + } + "history_duplicates" => { + // history_duplicates = match value.as_string() { + // Ok(s) if s.to_lowercase() == "alwaysadd" => { + // rustyline::config::HistoryDuplicates::AlwaysAdd + // } + // Ok(s) if s.to_lowercase() == "ignoreconsecutive" => { + // rustyline::config::HistoryDuplicates::IgnoreConsecutive + // } + // _ => rustyline::config::HistoryDuplicates::AlwaysAdd, + // }; + let history_duplicates = match value.as_bool() { + Ok(b) => b, + _ => true, + }; + rl.set_history_ignore_dups(history_duplicates); + } + "history_ignore_space" => { + let history_ignore_space = match value.as_bool() { + Ok(b) => b, + _ => true, + }; + rl.set_history_ignore_space(history_ignore_space); + } + "completion_type" => { + let completion_type = match value.as_string() { + Ok(s) if s.to_lowercase() == "circular" => { + rustyline::config::CompletionType::Circular + } + Ok(s) if s.to_lowercase() == "list" => { + rustyline::config::CompletionType::List + } + #[cfg(all(unix, feature = "with-fuzzy"))] + Ok(s) if s.to_lowercase() == "fuzzy" => { + rustyline::config::CompletionType::Fuzzy + } + _ => DEFAULT_COMPLETION_MODE, + }; + rl.set_completion_type(completion_type); + } + "completion_prompt_limit" => { + let completion_prompt_limit = match value.as_u64() { + Ok(n) => n as usize, + _ => 1 as usize, + }; + rl.set_completion_prompt_limit(completion_prompt_limit); + } + "keyseq_timeout_ms" => { + let keyseq_timeout_ms = match value.as_u64() { + Ok(n) => n as i32, + _ => 500i32, + }; + rl.set_keyseq_timeout(keyseq_timeout_ms); + } + "edit_mode" => { + let edit_mode = match value.as_string() { + Ok(s) if s.to_lowercase() == "vi" => rustyline::config::EditMode::Vi, + Ok(s) if s.to_lowercase() == "emacs" => { + rustyline::config::EditMode::Emacs + } + _ => rustyline::config::EditMode::Vi, + }; + rl.set_edit_mode(edit_mode); + } + "auto_add_history" => { + let auto_add_history = match value.as_bool() { + Ok(b) => b, + _ => true, + }; + rl.set_auto_add_history(auto_add_history); + } + "bell_style" => { + let bell_style = match value.as_string() { + Ok(s) if s.to_lowercase() == "audible" => { + rustyline::config::BellStyle::Audible + } + Ok(s) if s.to_lowercase() == "none" => { + rustyline::config::BellStyle::None + } + Ok(s) if s.to_lowercase() == "visible" => { + rustyline::config::BellStyle::Visible + } + _ => rustyline::config::BellStyle::None, + }; + rl.set_bell_style(bell_style); + } + "color_mode" => { + let color_mode = match value.as_string() { + Ok(s) if s.to_lowercase() == "enabled" => rustyline::ColorMode::Enabled, + Ok(s) if s.to_lowercase() == "forced" => rustyline::ColorMode::Forced, + Ok(s) if s.to_lowercase() == "disabled" => { + rustyline::ColorMode::Disabled + } + _ => rustyline::ColorMode::Enabled, + }; + rl.set_color_mode(color_mode); + } + "tab_stop" => { + let tab_stop = match value.as_u64() { + Ok(n) => n as usize, + _ => 4 as usize, + }; + rl.set_tab_stop(tab_stop); + } + _ => (), + } + } + } + } + + (rl, config) +} + +/// The entry point for the CLI. Will register all known internal commands, load experimental commands, load plugins, then prepare the prompt and line reader for input. +pub async fn cli( + mut syncer: EnvironmentSyncer, + mut context: Context, +) -> Result<(), Box> { + let _ = load_plugins(&mut context); + + let (mut rl, config) = set_rustyline_configuration(); + let use_starship = match config.get("use_starship") { + Some(b) => match b.as_bool() { + Ok(b) => b, + _ => false, + }, + _ => false, + }; + #[cfg(windows)] { let _ = ansi_term::enable_ansi_support(); } - // we are ok if history does not exist - let _ = rl.load_history(&History::path()); - #[cfg(feature = "ctrlc")] { let cc = context.ctrl_c.clone(); @@ -606,67 +750,6 @@ pub async fn cli( rl.set_helper(Some(crate::shell::Helper::new(context.clone()))); - let config = match config::config(Tag::unknown()) { - Ok(config) => config, - Err(e) => { - eprintln!("Config could not be loaded."); - if let ShellError { - error: ProximateShellError::Diagnostic(ShellDiagnostic { diagnostic }), - .. - } = e - { - eprintln!("{}", diagnostic.message); - } - IndexMap::new() - } - }; - - let use_starship = match config.get("use_starship") { - Some(b) => match b.as_bool() { - Ok(b) => b, - _ => false, - }, - _ => false, - }; - - let edit_mode = config - .get("edit_mode") - .map(|s| match s.value.expect_string() { - "vi" => EditMode::Vi, - "emacs" => EditMode::Emacs, - _ => EditMode::Emacs, - }) - .unwrap_or(EditMode::Emacs); - - rl.set_edit_mode(edit_mode); - - let max_history_size = config - .get("history_size") - .map(|i| i.value.expect_int()) - .unwrap_or(100_000); - - // rl.set_max_history_size(max_history_size as usize); - rustyline::config::Configurer::set_max_history_size(&mut rl, max_history_size as usize); - rustyline::Editor::set_max_history_size(&mut rl, max_history_size as usize); - - let key_timeout = config - .get("key_timeout") - .map(|s| s.value.expect_int()) - .unwrap_or(1); - - rl.set_keyseq_timeout(key_timeout as i32); - - let completion_mode = config - .get("completion_mode") - .map(|s| match s.value.expect_string() { - "list" => CompletionType::List, - "circular" => CompletionType::Circular, - _ => DEFAULT_COMPLETION_MODE, - }) - .unwrap_or(DEFAULT_COMPLETION_MODE); - - rl.set_completion_type(completion_mode); - let colored_prompt = { if use_starship { #[cfg(feature = "starship")] diff --git a/crates/nu-cli/src/shell/helper.rs b/crates/nu-cli/src/shell/helper.rs index d6534bb575..a2fc7a3842 100644 --- a/crates/nu-cli/src/shell/helper.rs +++ b/crates/nu-cli/src/shell/helper.rs @@ -11,7 +11,7 @@ use rustyline::highlight::Highlighter; use rustyline::hint::Hinter; use std::borrow::Cow::{self, Owned}; -pub(crate) struct Helper { +pub struct Helper { context: Context, pub colored_prompt: String, }