diff --git a/.azure/azure-pipelines.yml b/.azure/azure-pipelines.yml index bc8727979c..3a08f8a7f6 100644 --- a/.azure/azure-pipelines.yml +++ b/.azure/azure-pipelines.yml @@ -71,7 +71,7 @@ steps: - bash: RUSTFLAGS="-D warnings" cargo clippy --all -- -D clippy::unwrap_used condition: eq(variables['style'], 'canary') displayName: Check clippy lints - - bash: RUSTFLAGS="-D warnings" cargo test --all --no-default-features + - bash: RUSTFLAGS="-D warnings" cargo test --all --no-default-features --features=rustyline-support condition: eq(variables['style'], 'minimal') displayName: Run tests - bash: RUSTFLAGS="-D warnings" cargo test --all --features=extra diff --git a/Cargo.lock b/Cargo.lock index 504e212b21..f8b59f9e33 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -987,7 +987,7 @@ version = "3.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0b676fa23f995faf587496dcd1c80fead847ed58d2da52ac1caca9a72790dd2" dependencies = [ - "nix", + "nix 0.17.0", "winapi 0.3.9", ] @@ -1834,7 +1834,7 @@ dependencies = [ "lazy_static 1.4.0", "libc", "mach", - "nix", + "nix 0.17.0", "pin-utils", "uom 0.28.0", "winapi 0.3.9", @@ -1921,7 +1921,7 @@ dependencies = [ "heim-runtime", "libc", "macaddr", - "nix", + "nix 0.17.0", ] [[package]] @@ -2796,6 +2796,18 @@ dependencies = [ "void", ] +[[package]] +name = "nix" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83450fe6a6142ddd95fb064b746083fc4ef1705fe81f64a64e1d4b39f54a1055" +dependencies = [ + "bitflags", + "cc", + "cfg-if", + "libc", +] + [[package]] name = "nodrop" version = "0.1.14" @@ -4503,16 +4515,16 @@ dependencies = [ [[package]] name = "rustyline" -version = "6.2.0" +version = "6.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3358c21cbbc1a751892528db4e1de4b7a2b6a73f001e215aaba97d712cfa9777" +checksum = "6f0d5e7b0219a3eadd5439498525d4765c59b7c993ef0c12244865cd2d988413" dependencies = [ "cfg-if", "dirs-next", "libc", "log 0.4.11", "memchr", - "nix", + "nix 0.18.0", "scopeguard", "unicode-segmentation", "unicode-width", diff --git a/Cargo.toml b/Cargo.toml index a0a176ee83..f13d75cc99 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -75,6 +75,7 @@ default = [ "ptree-support", "term-support", "uuid-support", + "rustyline-support", "match", "post", "fetch", @@ -105,6 +106,7 @@ ctrlc-support = ["nu-cli/ctrlc"] directories-support = ["nu-cli/directories", "nu-cli/dirs", "nu-data/directories", "nu-data/dirs"] git-support = ["nu-cli/git2"] ptree-support = ["nu-cli/ptree"] +rustyline-support = ["nu-cli/rustyline-support"] term-support = ["nu-cli/term"] trash-support = ["nu-cli/trash-support"] uuid-support = ["nu-cli/uuid_crate"] diff --git a/crates/nu-cli/Cargo.toml b/crates/nu-cli/Cargo.toml index 423e617beb..644f82aa47 100644 --- a/crates/nu-cli/Cargo.toml +++ b/crates/nu-cli/Cargo.toml @@ -24,51 +24,51 @@ ansi_term = "0.12.1" async-recursion = "0.3.1" async-trait = "0.1.40" base64 = "0.12.3" -bigdecimal = { version = "0.1.2", features = ["serde"] } +bigdecimal = {version = "0.1.2", features = ["serde"]} byte-unit = "4.0.9" bytes = "0.5.6" calamine = "0.16.1" -chrono = { version = "0.4.15", features = ["serde"] } +chrono = {version = "0.4.15", features = ["serde"]} clap = "2.33.3" codespan-reporting = "0.9.5" csv = "1.1.3" -ctrlc = { version = "3.1.6", optional = true } +ctrlc = {version = "3.1.6", optional = true} derive-new = "0.5.8" -directories = { version = "3.0.1", optional = true } -dirs = { version = "3.0.1", optional = true } +directories = {version = "3.0.1", optional = true} +dirs = {version = "3.0.1", optional = true} dtparse = "1.1.0" dunce = "1.0.1" eml-parser = "0.1.0" filesize = "0.2.0" fs_extra = "1.2.0" -futures = { version = "0.3.5", features = ["compat", "io-compat"] } +futures = {version = "0.3.5", features = ["compat", "io-compat"]} futures-util = "0.3.5" futures_codec = "0.4.1" getset = "0.1.1" -git2 = { version = "0.13.11", default_features = false, optional = true } +git2 = {version = "0.13.11", default_features = false, optional = true} glob = "0.3.0" htmlescape = "0.3.1" ical = "0.6.0" -ichwh = { version = "0.3.4", optional = true } -indexmap = { version = "1.6.0", features = ["serde-1"] } +ichwh = {version = "0.3.4", optional = true} +indexmap = {version = "1.6.0", features = ["serde-1"]} itertools = "0.9.0" log = "0.4.11" meval = "0.2.0" natural = "0.5.0" -num-bigint = { version = "0.2.6", features = ["serde"] } -num-format = { version = "0.4.0", features = ["with-num-bigint"] } +num-bigint = {version = "0.2.6", features = ["serde"]} +num-format = {version = "0.4.0", features = ["with-num-bigint"]} num-traits = "0.2.12" parking_lot = "0.11.0" pin-utils = "0.1.0" pretty-hex = "0.2.0" -ptree = { version = "0.3.0", optional = true } +ptree = {version = "0.3.0", optional = true} query_interface = "0.3.5" rand = "0.7.3" regex = "1.3.9" roxmltree = "0.13.0" rust-embed = "5.6.0" -rustyline = "6.2.0" -serde = { version = "1.0.115", features = ["derive"] } +rustyline = {version = "6.3.0", optional = true} +serde = {version = "1.0.115", features = ["derive"]} serde-hjson = "0.9.1" serde_bytes = "0.11.5" serde_ini = "0.2.0" @@ -79,26 +79,26 @@ sha2 = "0.9.1" shellexpand = "2.0.0" strip-ansi-escapes = "0.1.0" tempfile = "3.1.0" -term = { version = "0.6.1", optional = true } +term = {version = "0.6.1", optional = true} term_size = "0.3.2" termcolor = "1.1.0" toml = "0.5.6" unicode-segmentation = "1.6.0" -uuid_crate = { package = "uuid", version = "0.8.1", features = ["v4"], optional = true } -which = { version = "4.0.2", optional = true } -zip = { version = "0.5.7", optional = true } +uuid_crate = {package = "uuid", version = "0.8.1", features = ["v4"], optional = true} +which = {version = "4.0.2", optional = true} +zip = {version = "0.5.7", optional = true} -clipboard = { version = "0.5.0", optional = true } +Inflector = "0.11" +clipboard = {version = "0.5.0", optional = true} encoding_rs = "0.8.24" quick-xml = "0.18.1" rayon = "1.4.0" -trash = { version = "1.1.1", optional = true } +trash = {version = "1.1.1", optional = true} url = "2.1.1" -Inflector = "0.11" [target.'cfg(unix)'.dependencies] -users = "0.10.0" umask = "1.0.0" +users = "0.10.0" # TODO this will be possible with new dependency resolver # (currently on nightly behind -Zfeatures=itarget): @@ -112,8 +112,7 @@ optional = true version = "0.23.1" [build-dependencies] -git2 = { version = "0.13.11", optional = true } - +git2 = {version = "0.13.11", optional = true} [dev-dependencies] quickcheck = "0.9.2" @@ -121,5 +120,6 @@ quickcheck_macros = "0.9.1" [features] clipboard-cli = ["clipboard"] +rustyline-support = ["rustyline"] stable = [] trash-support = ["trash"] diff --git a/crates/nu-cli/src/cli.rs b/crates/nu-cli/src/cli.rs index ec4ba0a916..a2b26a8ae9 100644 --- a/crates/nu-cli/src/cli.rs +++ b/crates/nu-cli/src/cli.rs @@ -1,9 +1,9 @@ use crate::commands::classified::block::run_block; use crate::commands::classified::maybe_text_codec::{MaybeTextCodec, StringOrBinary}; use crate::context::Context; -use crate::git::current_branch; use crate::path::canonicalize; use crate::prelude::*; +#[cfg(feature = "rustyline-support")] use crate::shell::Helper; use crate::EnvironmentSyncer; use futures_codec::FramedRead; @@ -12,9 +12,14 @@ use nu_protocol::hir::{ClassifiedCommand, Expression, InternalCommand, Literal, use nu_protocol::{Primitive, ReturnSuccess, UntaggedValue, Value}; use log::{debug, trace}; -use rustyline::config::{ColorMode, CompletionType, Config}; -use rustyline::error::ReadlineError; -use rustyline::{self, config::Configurer, At, Cmd, Editor, KeyPress, Movement, Word}; +#[cfg(feature = "rustyline-support")] +use rustyline::{ + self, + config::Configurer, + config::{ColorMode, CompletionType, Config}, + error::ReadlineError, + At, Cmd, Editor, KeyPress, Movement, Word, +}; use std::error::Error; use std::iter::Iterator; use std::path::{Path, PathBuf}; @@ -305,7 +310,21 @@ pub async fn run_vec_of_pipelines( Ok(()) } +#[cfg(feature = "rustyline-support")] +fn convert_rustyline_result_to_string(input: Result) -> LineResult { + match input { + Ok(s) => LineResult::Success(s), + Err(ReadlineError::Interrupted) => LineResult::CtrlC, + Err(ReadlineError::Eof) => LineResult::Break, + Err(err) => { + outln!("Error: {:?}", err); + LineResult::Break + } + } +} + /// 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. +#[cfg(feature = "rustyline-support")] pub async fn cli(mut context: Context) -> Result<(), Box> { let mut syncer = EnvironmentSyncer::new(); let configuration = syncer.get_config(); @@ -417,6 +436,7 @@ pub async fn cli(mut context: Context) -> Result<(), Box> { } } } else { + use crate::git::current_branch; format!( "\x1b[32m{}{}\x1b[m> ", cwd, @@ -444,7 +464,10 @@ pub async fn cli(mut context: Context) -> Result<(), Box> { initial_command = None; } - let line = process_line(readline, &mut context, false, true).await; + let line = match convert_rustyline_result_to_string(readline) { + LineResult::Success(s) => process_line(&s, &mut context, false, true).await, + x => x, + }; // Check the config to see if we need to update the path // TODO: make sure config is cached so we don't path this load every call @@ -579,7 +602,7 @@ pub async fn run_pipeline_standalone( context: &mut Context, exit_on_error: bool, ) -> Result<(), Box> { - let line = process_line(Ok(pipeline), context, redirect_stdin, false).await; + let line = process_line(&pipeline, context, redirect_stdin, false).await; match line { LineResult::Success(line) => { @@ -617,6 +640,7 @@ pub async fn run_pipeline_standalone( Ok(()) } +#[cfg(feature = "rustyline-support")] fn default_rustyline_editor_configuration() -> Editor { #[cfg(windows)] const DEFAULT_COMPLETION_MODE: CompletionType = CompletionType::Circular; @@ -657,6 +681,7 @@ fn default_rustyline_editor_configuration() -> Editor { rl } +#[cfg(feature = "rustyline-support")] fn configure_rustyline_editor( rl: &mut Editor, config: &dyn nu_data::config::Conf, @@ -771,6 +796,7 @@ fn configure_rustyline_editor( Ok(()) } +#[cfg(feature = "rustyline-support")] fn nu_line_editor_helper( context: &mut Context, config: &dyn nu_data::config::Conf, @@ -779,6 +805,7 @@ fn nu_line_editor_helper( crate::shell::Helper::new(context.clone(), hinter) } +#[cfg(feature = "rustyline-support")] fn rustyline_hinter(config: &dyn nu_data::config::Conf) -> Option { if let Some(line_editor_vars) = config.var("line_editor") { for (idx, value) in line_editor_vars.row_entries() { @@ -839,207 +866,199 @@ pub async fn parse_and_eval(line: &str, ctx: &mut Context) -> Result, + line: &str, ctx: &mut Context, redirect_stdin: bool, cli_mode: bool, ) -> LineResult { - match &readline { - Ok(line) if line.trim() == "" => LineResult::Success(line.clone()), + if line.trim() == "" { + LineResult::Success(line.to_string()) + } else { + let line = chomp_newline(line); + ctx.raw_input = line.to_string(); - Ok(line) => { - let line = chomp_newline(line); - ctx.raw_input = line.to_string(); - - let result = match nu_parser::lite_parse(&line, 0) { - Err(err) => { - return LineResult::Error(line.to_string(), err.into()); - } - - Ok(val) => val, - }; - - debug!("=== Parsed ==="); - debug!("{:#?}", result); - - let mut classified_block = nu_parser::classify_block(&result, ctx.registry()); - - debug!("{:#?}", classified_block); - //println!("{:#?}", pipeline); - - if let Some(failure) = classified_block.failed { - return LineResult::Error(line.to_string(), failure.into()); + let result = match nu_parser::lite_parse(&line, 0) { + Err(err) => { + return LineResult::Error(line.to_string(), err.into()); } - // There's a special case to check before we process the pipeline: - // If we're giving a path by itself - // ...and it's not a command in the path - // ...and it doesn't have any arguments - // ...and we're in the CLI - // ...then change to this directory - if cli_mode - && classified_block.block.block.len() == 1 - && classified_block.block.block[0].list.len() == 1 + Ok(val) => val, + }; + + debug!("=== Parsed ==="); + debug!("{:#?}", result); + + let mut classified_block = nu_parser::classify_block(&result, ctx.registry()); + + debug!("{:#?}", classified_block); + //println!("{:#?}", pipeline); + + if let Some(failure) = classified_block.failed { + return LineResult::Error(line.to_string(), failure.into()); + } + + // There's a special case to check before we process the pipeline: + // If we're giving a path by itself + // ...and it's not a command in the path + // ...and it doesn't have any arguments + // ...and we're in the CLI + // ...then change to this directory + if cli_mode + && classified_block.block.block.len() == 1 + && classified_block.block.block[0].list.len() == 1 + { + if let ClassifiedCommand::Internal(InternalCommand { + ref name, ref args, .. + }) = classified_block.block.block[0].list[0] { - if let ClassifiedCommand::Internal(InternalCommand { - ref name, ref args, .. - }) = classified_block.block.block[0].list[0] - { - let internal_name = name; - let name = args + let internal_name = name; + let name = args + .positional + .as_ref() + .and_then(|potionals| { + potionals.get(0).map(|e| { + if let Expression::Literal(Literal::String(ref s)) = e.expr { + &s + } else { + "" + } + }) + }) + .unwrap_or(""); + + if internal_name == "run_external" + && args .positional .as_ref() - .and_then(|potionals| { - potionals.get(0).map(|e| { - if let Expression::Literal(Literal::String(ref s)) = e.expr { - &s - } else { - "" - } - }) - }) - .unwrap_or(""); - - if internal_name == "run_external" - && args - .positional - .as_ref() - .map(|ref v| v.len() == 1) - .unwrap_or(true) - && args - .named - .as_ref() - .map(NamedArguments::is_empty) - .unwrap_or(true) - && canonicalize(ctx.shell_manager.path(), name).is_ok() - && Path::new(&name).is_dir() - && !crate::commands::classified::external::did_find_command(&name) + .map(|ref v| v.len() == 1) + .unwrap_or(true) + && args + .named + .as_ref() + .map(NamedArguments::is_empty) + .unwrap_or(true) + && canonicalize(ctx.shell_manager.path(), name).is_ok() + && Path::new(&name).is_dir() + && !crate::commands::classified::external::did_find_command(&name) + { + // Here we work differently if we're in Windows because of the expected Windows behavior + #[cfg(windows)] { - // Here we work differently if we're in Windows because of the expected Windows behavior - #[cfg(windows)] - { - if name.ends_with(':') { - // This looks like a drive shortcut. We need to a) switch drives and b) go back to the previous directory we were viewing on that drive - // But first, we need to save where we are now - let current_path = ctx.shell_manager.path(); + if name.ends_with(':') { + // This looks like a drive shortcut. We need to a) switch drives and b) go back to the previous directory we were viewing on that drive + // But first, we need to save where we are now + let current_path = ctx.shell_manager.path(); - let split_path: Vec<_> = current_path.split(':').collect(); - if split_path.len() > 1 { - ctx.windows_drives_previous_cwd - .lock() - .insert(split_path[0].to_string(), current_path); - } + let split_path: Vec<_> = current_path.split(':').collect(); + if split_path.len() > 1 { + ctx.windows_drives_previous_cwd + .lock() + .insert(split_path[0].to_string(), current_path); + } - let name = name.to_uppercase(); - let new_drive: Vec<_> = name.split(':').collect(); + let name = name.to_uppercase(); + let new_drive: Vec<_> = name.split(':').collect(); - if let Some(val) = - ctx.windows_drives_previous_cwd.lock().get(new_drive[0]) - { - ctx.shell_manager.set_path(val.to_string()); - return LineResult::Success(line.to_string()); - } else { - ctx.shell_manager - .set_path(format!("{}\\", name.to_string())); - return LineResult::Success(line.to_string()); - } + if let Some(val) = + ctx.windows_drives_previous_cwd.lock().get(new_drive[0]) + { + ctx.shell_manager.set_path(val.to_string()); + return LineResult::Success(line.to_string()); } else { - ctx.shell_manager.set_path(name.to_string()); + ctx.shell_manager + .set_path(format!("{}\\", name.to_string())); return LineResult::Success(line.to_string()); } - } - #[cfg(not(windows))] - { + } else { ctx.shell_manager.set_path(name.to_string()); return LineResult::Success(line.to_string()); } } - } - } - - let input_stream = if redirect_stdin { - let file = futures::io::AllowStdIo::new(std::io::stdin()); - let stream = FramedRead::new(file, MaybeTextCodec::default()).map(|line| { - if let Ok(line) = line { - let primitive = match line { - StringOrBinary::String(s) => Primitive::String(s), - StringOrBinary::Binary(b) => Primitive::Binary(b.into_iter().collect()), - }; - - Ok(Value { - value: UntaggedValue::Primitive(primitive), - tag: Tag::unknown(), - }) - } else { - panic!("Internal error: could not read lines of text from stdin") - } - }); - stream.to_input_stream() - } else { - InputStream::empty() - }; - - classified_block.block.expand_it_usage(); - - trace!("{:#?}", classified_block); - let env = ctx.get_env(); - match run_block( - &classified_block.block, - ctx, - input_stream, - &Value::nothing(), - &IndexMap::new(), - &env, - ) - .await - { - Ok(input) => { - // Running a pipeline gives us back a stream that we can then - // work through. At the top level, we just want to pull on the - // values to compute them. - use futures::stream::TryStreamExt; - - let context = RunnableContext { - input, - shell_manager: ctx.shell_manager.clone(), - host: ctx.host.clone(), - ctrl_c: ctx.ctrl_c.clone(), - current_errors: ctx.current_errors.clone(), - registry: ctx.registry.clone(), - name: Tag::unknown(), - raw_input: line.to_string(), - }; - - if let Ok(mut output_stream) = - crate::commands::autoview::command::autoview(context).await + #[cfg(not(windows))] { - loop { - match output_stream.try_next().await { - Ok(Some(ReturnSuccess::Value(Value { - value: UntaggedValue::Error(e), - .. - }))) => return LineResult::Error(line.to_string(), e), - Ok(Some(_item)) => { - if ctx.ctrl_c.load(Ordering::SeqCst) { - break; - } - } - Ok(None) => break, - Err(e) => return LineResult::Error(line.to_string(), e), - } - } + ctx.shell_manager.set_path(name.to_string()); + return LineResult::Success(line.to_string()); } - - LineResult::Success(line.to_string()) } - Err(err) => LineResult::Error(line.to_string(), err), } } - Err(ReadlineError::Interrupted) => LineResult::CtrlC, - Err(ReadlineError::Eof) => LineResult::Break, - Err(err) => { - outln!("Error: {:?}", err); - LineResult::Break + + let input_stream = if redirect_stdin { + let file = futures::io::AllowStdIo::new(std::io::stdin()); + let stream = FramedRead::new(file, MaybeTextCodec::default()).map(|line| { + if let Ok(line) = line { + let primitive = match line { + StringOrBinary::String(s) => Primitive::String(s), + StringOrBinary::Binary(b) => Primitive::Binary(b.into_iter().collect()), + }; + + Ok(Value { + value: UntaggedValue::Primitive(primitive), + tag: Tag::unknown(), + }) + } else { + panic!("Internal error: could not read lines of text from stdin") + } + }); + stream.to_input_stream() + } else { + InputStream::empty() + }; + + classified_block.block.expand_it_usage(); + + trace!("{:#?}", classified_block); + let env = ctx.get_env(); + match run_block( + &classified_block.block, + ctx, + input_stream, + &Value::nothing(), + &IndexMap::new(), + &env, + ) + .await + { + Ok(input) => { + // Running a pipeline gives us back a stream that we can then + // work through. At the top level, we just want to pull on the + // values to compute them. + use futures::stream::TryStreamExt; + + let context = RunnableContext { + input, + shell_manager: ctx.shell_manager.clone(), + host: ctx.host.clone(), + ctrl_c: ctx.ctrl_c.clone(), + current_errors: ctx.current_errors.clone(), + registry: ctx.registry.clone(), + name: Tag::unknown(), + raw_input: line.to_string(), + }; + + if let Ok(mut output_stream) = + crate::commands::autoview::command::autoview(context).await + { + loop { + match output_stream.try_next().await { + Ok(Some(ReturnSuccess::Value(Value { + value: UntaggedValue::Error(e), + .. + }))) => return LineResult::Error(line.to_string(), e), + Ok(Some(_item)) => { + if ctx.ctrl_c.load(Ordering::SeqCst) { + break; + } + } + Ok(None) => break, + Err(e) => return LineResult::Error(line.to_string(), e), + } + } + } + + LineResult::Success(line.to_string()) + } + Err(err) => LineResult::Error(line.to_string(), err), } } } diff --git a/crates/nu-cli/src/documentation.rs b/crates/nu-cli/src/documentation.rs index 5b8268a895..6ff1e79d12 100644 --- a/crates/nu-cli/src/documentation.rs +++ b/crates/nu-cli/src/documentation.rs @@ -213,7 +213,7 @@ pub fn get_documentation( long_desc.push_str(&format!("\n > {}\n", example.example)); } else { let colored_example = - crate::shell::helper::Painter::paint_string(example.example, registry, &palette); + crate::shell::painter::Painter::paint_string(example.example, registry, &palette); long_desc.push_str(&format!("\n > {}\n", colored_example)); } } diff --git a/crates/nu-cli/src/evaluate/variables.rs b/crates/nu-cli/src/evaluate/variables.rs index 9f342f0a59..59915ae54b 100644 --- a/crates/nu-cli/src/evaluate/variables.rs +++ b/crates/nu-cli/src/evaluate/variables.rs @@ -41,11 +41,14 @@ pub fn nu(env: &IndexMap, tag: impl Into) -> Result = Box::new(nu_data::config::NuConfig::new()); let history = crate::commands::history::history_path(&config); diff --git a/crates/nu-cli/src/lib.rs b/crates/nu-cli/src/lib.rs index 0a8038ee38..47a8d14413 100644 --- a/crates/nu-cli/src/lib.rs +++ b/crates/nu-cli/src/lib.rs @@ -15,6 +15,7 @@ extern crate quickcheck_macros; mod cli; mod commands; +#[cfg(feature = "rustyline-support")] mod completion; mod context; mod deserializer; @@ -23,7 +24,9 @@ mod env; mod evaluate; mod format; mod futures; +#[cfg(feature = "rustyline-support")] mod git; +#[cfg(feature = "rustyline-support")] mod keybinding; mod path; mod plugin; @@ -34,8 +37,11 @@ pub mod utils; #[cfg(test)] mod examples; +#[cfg(feature = "rustyline-support")] +pub use crate::cli::cli; + pub use crate::cli::{ - cli, create_default_context, parse_and_eval, process_line, register_plugins, + create_default_context, parse_and_eval, process_line, register_plugins, run_pipeline_standalone, run_vec_of_pipelines, LineResult, }; pub use crate::commands::command::{ diff --git a/crates/nu-cli/src/shell.rs b/crates/nu-cli/src/shell.rs index cb67948402..36baf3daad 100644 --- a/crates/nu-cli/src/shell.rs +++ b/crates/nu-cli/src/shell.rs @@ -1,12 +1,16 @@ #![allow(clippy::module_inception)] +#[cfg(feature = "rustyline-support")] pub(crate) mod completer; pub(crate) mod filesystem_shell; pub(crate) mod help_shell; +#[cfg(feature = "rustyline-support")] pub(crate) mod helper; +pub(crate) mod painter; pub(crate) mod palette; pub(crate) mod shell; pub(crate) mod shell_manager; pub(crate) mod value_shell; +#[cfg(feature = "rustyline-support")] pub(crate) use helper::Helper; diff --git a/crates/nu-cli/src/shell/completer.rs b/crates/nu-cli/src/shell/completer.rs index 9b7566f750..58bc3686da 100644 --- a/crates/nu-cli/src/shell/completer.rs +++ b/crates/nu-cli/src/shell/completer.rs @@ -3,7 +3,7 @@ use crate::completion::flag::FlagCompleter; use crate::completion::path::{PathCompleter, PathSuggestion}; use crate::completion::{self, Completer, Suggestion}; use crate::context; - +use std::borrow::Cow; pub(crate) struct NuCompleter {} impl NuCompleter {} @@ -109,8 +109,8 @@ fn select_directory_suggestions(completed_paths: Vec) -> Vec String { - let value = rustyline::completion::unescape(&value, Some('\\')); +fn requote(orig_value: String) -> String { + let value: Cow = rustyline::completion::unescape(&orig_value, Some('\\')); let mut quotes = vec!['"', '\'', '`']; let mut should_quote = false; diff --git a/crates/nu-cli/src/shell/helper.rs b/crates/nu-cli/src/shell/helper.rs index d8cf1d7811..0fb49b1354 100644 --- a/crates/nu-cli/src/shell/helper.rs +++ b/crates/nu-cli/src/shell/helper.rs @@ -1,14 +1,13 @@ use std::borrow::Cow::{self, Owned}; -use ansi_term::{Color, Style}; use nu_parser::SignatureRegistry; -use nu_protocol::hir::FlatShape; -use nu_source::{Spanned, Tag, Tagged}; +use nu_source::{Tag, Tagged}; use crate::completion; use crate::context::Context; use crate::shell::completer::NuCompleter; -use crate::shell::palette::{DefaultPalette, Palette}; +use crate::shell::painter::Painter; +use crate::shell::palette::DefaultPalette; pub struct Helper { completer: NuCompleter, @@ -143,90 +142,4 @@ fn vec_tag(input: Vec>) -> Option { }) } -pub struct Painter { - original: Vec, - styles: Vec