diff --git a/src/commands/autoview.rs b/src/commands/autoview.rs index adce1df402..6a8d61eeea 100644 --- a/src/commands/autoview.rs +++ b/src/commands/autoview.rs @@ -39,7 +39,7 @@ pub fn autoview( if input.len() > 0 { if let Tagged { - item: Value::Binary(_), + item: Value::Primitive(Primitive::Binary(_)), .. } = input[0usize] { @@ -50,7 +50,7 @@ pub fn autoview( } else { for i in input { match i.item { - Value::Binary(b) => { + Value::Primitive(Primitive::Binary(b)) => { use pretty_hex::*; println!("{:?}", b.hex_dump()); } diff --git a/src/commands/fetch.rs b/src/commands/fetch.rs index e87ddf8347..f2ddc737dc 100644 --- a/src/commands/fetch.rs +++ b/src/commands/fetch.rs @@ -186,7 +186,7 @@ pub async fn fetch( })?; Ok(( None, - Value::Binary(buf), + Value::Primitive(Primitive::Binary(buf)), Tag { span, origin: Some(Uuid::new_v4()), @@ -219,7 +219,7 @@ pub async fn fetch( })?; Ok(( Some(image_ty.to_string()), - Value::Binary(buf), + Value::Primitive(Primitive::Binary(buf)), Tag { span, origin: Some(Uuid::new_v4()), diff --git a/src/commands/from_bson.rs b/src/commands/from_bson.rs index 12f92965a1..c5f742057e 100644 --- a/src/commands/from_bson.rs +++ b/src/commands/from_bson.rs @@ -122,7 +122,7 @@ fn convert_bson_value_to_nu_value( ); collected.insert_tagged( "$binary".to_string(), - Value::Binary(bytes.to_owned()).tagged(tag), + Value::Primitive(Primitive::Binary(bytes.to_owned())).tagged(tag), ); collected.into_tagged_value() } @@ -207,7 +207,7 @@ fn from_bson(args: CommandArgs, registry: &CommandRegistry) -> Result + Value::Primitive(Primitive::Binary(vb)) => match from_bson_bytes_to_value(vb, span) { Ok(x) => yield ReturnSuccess::value(x), Err(_) => { diff --git a/src/commands/from_sqlite.rs b/src/commands/from_sqlite.rs index c19c4fef10..a56ecd3058 100644 --- a/src/commands/from_sqlite.rs +++ b/src/commands/from_sqlite.rs @@ -106,7 +106,7 @@ fn convert_sqlite_value_to_nu_value(value: ValueRef, tag: impl Into + Clone // this unwrap is safe because we know the ValueRef is Text. Value::Primitive(Primitive::String(t.as_str().unwrap().to_string())).tagged(tag) } - ValueRef::Blob(u) => Value::Binary(u.to_owned()).tagged(tag), + ValueRef::Blob(u) => Value::binary(u.to_owned()).tagged(tag), } } @@ -137,7 +137,7 @@ fn from_sqlite(args: CommandArgs, registry: &CommandRegistry) -> Result + Value::Primitive(Primitive::Binary(vb)) => match from_sqlite_bytes_to_value(vb, span) { Ok(x) => match x { Tagged { item: Value::Table(list), .. } => { diff --git a/src/commands/help.rs b/src/commands/help.rs index f8d9b5c2fe..d710521fb6 100644 --- a/src/commands/help.rs +++ b/src/commands/help.rs @@ -1,8 +1,7 @@ -use crate::commands::command::CommandAction; use crate::commands::PerItemCommand; use crate::data::{command_dict, TaggedDictBuilder}; use crate::errors::ShellError; -use crate::parser::registry; +use crate::parser::registry::{self, NamedType, PositionalType}; use crate::prelude::*; pub struct Help; @@ -29,44 +28,104 @@ impl PerItemCommand for Help { ) -> Result { let span = call_info.name_span; - if call_info.args.len() == 0 { - return Ok(vec![Ok(ReturnSuccess::Action(CommandAction::EnterHelpShell( - Tagged::from_simple_spanned_item(Value::nothing(), span), - )))] - .into()); - } - - match call_info.args.expect_nth(0)? { - Tagged { + match call_info.args.nth(0) { + Some(Tagged { item: Value::Primitive(Primitive::String(document)), tag, - } => { + }) => { + let mut help = VecDeque::new(); if document == "commands" { - let mut specs = VecDeque::new(); - - for cmd in registry.names() { - let mut spec = TaggedDictBuilder::new(tag.clone()); + let mut sorted_names = registry.names(); + sorted_names.sort(); + for cmd in sorted_names { + let mut short_desc = TaggedDictBuilder::new(tag.clone()); let value = command_dict(registry.get_command(&cmd).unwrap(), tag.clone()); - spec.insert("name", cmd); - spec.insert( + short_desc.insert("name", cmd); + short_desc.insert( "description", value.get_data_by_key("usage").unwrap().as_string().unwrap(), ); - spec.insert_tagged("details", value); - specs.push_back(ReturnSuccess::value(spec.into_tagged_value())); + help.push_back(ReturnSuccess::value(short_desc.into_tagged_value())); } + } else { + if let Some(command) = registry.get_command(document) { + let mut long_desc = String::new(); - return Ok(specs.to_output_stream()); + long_desc.push_str(&command.usage()); + long_desc.push_str("\n"); + + let signature = command.signature(); + + let mut one_liner = String::new(); + one_liner.push_str(&signature.name); + one_liner.push_str(" "); + if signature.named.len() > 0 { + one_liner.push_str("{flags} "); + } + + for positional in signature.positional { + match positional { + PositionalType::Mandatory(name, _m) => { + one_liner.push_str(&format!("<{}> ", name)); + } + PositionalType::Optional(name, _o) => { + one_liner.push_str(&format!("({}) ", name)); + } + } + } + + if signature.rest_positional.is_some() { + one_liner.push_str(" ...args"); + } + long_desc.push_str(&format!("\nUsage:\n > {}\n", one_liner)); + + if signature.named.len() > 0 { + long_desc.push_str("\nflags:\n"); + for (flag, ty) in signature.named { + match ty { + NamedType::Switch => { + long_desc.push_str(&format!(" --{}\n", flag)); + } + NamedType::Mandatory(m) => { + long_desc.push_str(&format!( + " --{} <{}> (required parameter)\n", + flag, m + )); + } + NamedType::Optional(o) => { + long_desc.push_str(&format!(" --{} <{}>\n", flag, o)); + } + } + } + } + + help.push_back(ReturnSuccess::value( + Value::string(long_desc).tagged(tag.clone()), + )); + } } - Ok(OutputStream::empty()) + Ok(help.to_output_stream()) + } + _ => { + let msg = r#"Welcome to Nushell. + +Here are some tips to help you get started. + * help commands - list all available commands + * help - display help about a particular command + +You can also learn more at http://book.nushell.sh"#; + + let mut output_stream = VecDeque::new(); + + output_stream.push_back(ReturnSuccess::value( + Value::string(msg).simple_spanned(span), + )); + + Ok(output_stream.to_output_stream()) } - x => Ok(vec![Ok(ReturnSuccess::Action(CommandAction::EnterHelpShell( - x.clone(), - )))] - .into()), } } } diff --git a/src/commands/nth.rs b/src/commands/nth.rs index 98ab6a10a9..554034d8e1 100644 --- a/src/commands/nth.rs +++ b/src/commands/nth.rs @@ -16,7 +16,7 @@ impl WholeStreamCommand for Nth { } fn signature(&self) -> Signature { - Signature::build("nth").required("amount", SyntaxType::Any) + Signature::build("nth").required("row number", SyntaxType::Any) } fn usage(&self) -> &str { diff --git a/src/commands/open.rs b/src/commands/open.rs index 32a99c6f17..232399a390 100644 --- a/src/commands/open.rs +++ b/src/commands/open.rs @@ -171,7 +171,7 @@ pub async fn fetch( )), Err(_) => Ok(( None, - Value::Binary(bytes), + Value::Primitive(Primitive::Binary(bytes)), Tag { span, origin: Some(Uuid::new_v4()), @@ -182,7 +182,7 @@ pub async fn fetch( } else { Ok(( None, - Value::Binary(bytes), + Value::Primitive(Primitive::Binary(bytes)), Tag { span, origin: Some(Uuid::new_v4()), @@ -209,7 +209,7 @@ pub async fn fetch( )), Err(_) => Ok(( None, - Value::Binary(bytes), + Value::Primitive(Primitive::Binary(bytes)), Tag { span, origin: Some(Uuid::new_v4()), @@ -220,7 +220,7 @@ pub async fn fetch( } else { Ok(( None, - Value::Binary(bytes), + Value::Primitive(Primitive::Binary(bytes)), Tag { span, origin: Some(Uuid::new_v4()), @@ -231,7 +231,7 @@ pub async fn fetch( } _ => Ok(( None, - Value::Binary(bytes), + Value::Primitive(Primitive::Binary(bytes)), Tag { span, origin: Some(Uuid::new_v4()), diff --git a/src/commands/post.rs b/src/commands/post.rs index e1001b98d2..e72ed175ac 100644 --- a/src/commands/post.rs +++ b/src/commands/post.rs @@ -167,7 +167,7 @@ pub async fn post( s.await } Tagged { - item: Value::Binary(b), + item: Value::Primitive(Primitive::Binary(b)), .. } => { let mut s = surf::post(location).body_bytes(b); @@ -277,7 +277,7 @@ pub async fn post( })?; Ok(( None, - Value::Binary(buf), + Value::Primitive(Primitive::Binary(buf)), Tag { span, origin: Some(Uuid::new_v4()), @@ -295,7 +295,7 @@ pub async fn post( })?; Ok(( Some(image_ty.to_string()), - Value::Binary(buf), + Value::Primitive(Primitive::Binary(buf)), Tag { span, origin: Some(Uuid::new_v4()), diff --git a/src/commands/save.rs b/src/commands/save.rs index 2fd26defeb..77bd4433d8 100644 --- a/src/commands/save.rs +++ b/src/commands/save.rs @@ -60,7 +60,7 @@ macro_rules! process_binary_return_success { for res in $result_vec { match res { Ok(ReturnSuccess::Value(Tagged { - item: Value::Binary(b), + item: Value::Primitive(Primitive::Binary(b)), .. })) => { for u in b.into_iter() { diff --git a/src/commands/to_bson.rs b/src/commands/to_bson.rs index a77bebeacc..e1cd3a108f 100644 --- a/src/commands/to_bson.rs +++ b/src/commands/to_bson.rs @@ -58,7 +58,7 @@ pub fn value_to_bson_value(v: &Tagged) -> Result { .collect::>()?, ), Value::Block(_) => Bson::Null, - Value::Binary(b) => Bson::Binary(BinarySubtype::Generic, b.clone()), + Value::Primitive(Primitive::Binary(b)) => Bson::Binary(BinarySubtype::Generic, b.clone()), Value::Row(o) => object_value_to_bson(o)?, }) } @@ -254,7 +254,7 @@ fn to_bson(args: CommandArgs, registry: &CommandRegistry) -> Result { match bson_value_to_bytes(bson_value, name_span) { Ok(x) => yield ReturnSuccess::value( - Value::Binary(x).simple_spanned(name_span), + Value::Primitive(Primitive::Binary(x)).simple_spanned(name_span), ), _ => yield Err(ShellError::labeled_error_with_secondary( "Expected a table with BSON-compatible structure.span() from pipeline", diff --git a/src/commands/to_json.rs b/src/commands/to_json.rs index 35c03af32d..aa0e720dbf 100644 --- a/src/commands/to_json.rs +++ b/src/commands/to_json.rs @@ -51,7 +51,7 @@ pub fn value_to_json_value(v: &Tagged) -> Result serde_json::Value::Array(json_list(l)?), Value::Block(_) => serde_json::Value::Null, - Value::Binary(b) => serde_json::Value::Array( + Value::Primitive(Primitive::Binary(b)) => serde_json::Value::Array( b.iter() .map(|x| { serde_json::Value::Number(serde_json::Number::from_f64(*x as f64).unwrap()) diff --git a/src/commands/to_sqlite.rs b/src/commands/to_sqlite.rs index 0fd392f345..e4eef72c24 100644 --- a/src/commands/to_sqlite.rs +++ b/src/commands/to_sqlite.rs @@ -85,7 +85,6 @@ fn get_columns(rows: &Vec>) -> Result { fn nu_value_to_sqlite_string(v: Value) -> String { match v { - Value::Binary(u) => format!("x'{}'", encode(u)), Value::Primitive(p) => match p { Primitive::Nothing => "NULL".into(), Primitive::Int(i) => format!("{}", i), @@ -97,6 +96,7 @@ fn nu_value_to_sqlite_string(v: Value) -> String { Primitive::Boolean(_) => "0".into(), Primitive::Date(d) => format!("'{}'", d), Primitive::Path(p) => format!("'{}'", p.display().to_string().replace("'", "''")), + Primitive::Binary(u) => format!("x'{}'", encode(u)), Primitive::BeginningOfStream => "NULL".into(), Primitive::EndOfStream => "NULL".into(), }, @@ -195,7 +195,7 @@ fn sqlite_input_stream_to_bytes( } let mut out = Vec::new(); tempfile.read_to_end(&mut out)?; - Ok(Value::Binary(out).tagged(tag)) + Ok(Value::binary(out).tagged(tag)) } fn to_sqlite(args: CommandArgs, registry: &CommandRegistry) -> Result { diff --git a/src/commands/to_toml.rs b/src/commands/to_toml.rs index e18e152363..6669c94cd6 100644 --- a/src/commands/to_toml.rs +++ b/src/commands/to_toml.rs @@ -50,7 +50,7 @@ pub fn value_to_toml_value(v: &Tagged) -> Result Value::Table(l) => toml::Value::Array(collect_values(l)?), Value::Block(_) => toml::Value::String("".to_string()), - Value::Binary(b) => { + Value::Primitive(Primitive::Binary(b)) => { toml::Value::Array(b.iter().map(|x| toml::Value::Integer(*x as i64)).collect()) } Value::Row(o) => { diff --git a/src/commands/to_yaml.rs b/src/commands/to_yaml.rs index 915827252d..f4aa63ad6a 100644 --- a/src/commands/to_yaml.rs +++ b/src/commands/to_yaml.rs @@ -56,7 +56,7 @@ pub fn value_to_yaml_value(v: &Tagged) -> Result serde_yaml::Value::Null, - Value::Binary(b) => serde_yaml::Value::Sequence( + Value::Primitive(Primitive::Binary(b)) => serde_yaml::Value::Sequence( b.iter() .map(|x| serde_yaml::Value::Number(serde_yaml::Number::from(*x))) .collect(), diff --git a/src/data/base.rs b/src/data/base.rs index aa491ebdcb..c80cf409f0 100644 --- a/src/data/base.rs +++ b/src/data/base.rs @@ -24,6 +24,8 @@ pub enum Primitive { Boolean(bool), Date(DateTime), Path(PathBuf), + #[serde(with = "serde_bytes")] + Binary(Vec), // Stream markers (used as bookend markers rather than actual values) BeginningOfStream, @@ -58,6 +60,7 @@ impl Primitive { String(_) => "string", Boolean(_) => "boolean", Date(_) => "date", + Binary(_) => "binary", } .to_string() } @@ -77,6 +80,7 @@ impl Primitive { String(string) => write!(f, "{:?}", string), Boolean(boolean) => write!(f, "{}", boolean), Date(date) => write!(f, "{}", date), + Binary(binary) => write!(f, "{:?}", binary), } } @@ -121,6 +125,7 @@ impl Primitive { (true, Some(_)) => format!("Yes"), (false, Some(_)) => format!("No"), }, + Primitive::Binary(_) => format!(""), Primitive::Date(d) => format!("{}", d.humanize()), } } @@ -175,8 +180,6 @@ impl Block { pub enum Value { Primitive(Primitive), Row(crate::data::Dictionary), - #[serde(with = "serde_bytes")] - Binary(Vec), Table(Vec>), Block(Block), @@ -227,7 +230,6 @@ impl fmt::Debug for ValueDebug<'_> { Value::Row(o) => o.debug(f), Value::Table(l) => debug_list(l).fmt(f), Value::Block(_) => write!(f, "[[block]]"), - Value::Binary(_) => write!(f, "[[binary]]"), } } } @@ -288,7 +290,7 @@ impl std::convert::TryFrom<&Tagged> for Vec { fn try_from(value: &Tagged) -> Result, ShellError> { match value.item() { - Value::Binary(b) => Ok(b.clone()), + Value::Primitive(Primitive::Binary(b)) => Ok(b.clone()), v => Err(ShellError::type_error( "Binary", value.copy_span(v.type_name()), @@ -347,7 +349,6 @@ impl Value { Value::Row(_) => format!("object"), Value::Table(_) => format!("list"), Value::Block(_) => format!("block"), - Value::Binary(_) => format!("binary"), } } @@ -363,7 +364,6 @@ impl Value { .collect(), Value::Block(_) => vec![], Value::Table(_) => vec![], - Value::Binary(_) => vec![], } } @@ -495,7 +495,6 @@ impl Value { Value::Row(o) => o.get_data(desc), Value::Block(_) => MaybeOwned::Owned(Value::nothing()), Value::Table(_) => MaybeOwned::Owned(Value::nothing()), - Value::Binary(_) => MaybeOwned::Owned(Value::nothing()), } } @@ -514,7 +513,6 @@ impl Value { l.len(), if l.len() == 1 { "row" } else { "rows" } ), - Value::Binary(_) => format!(""), } } @@ -602,6 +600,10 @@ impl Value { Value::Primitive(Primitive::Decimal(s.into())) } + pub fn binary(binary: Vec) -> Value { + Value::Primitive(Primitive::Binary(binary)) + } + pub fn number(s: impl Into) -> Value { let num = s.into(); diff --git a/src/format/generic.rs b/src/format/generic.rs index 57726f819c..b6f9e29f26 100644 --- a/src/format/generic.rs +++ b/src/format/generic.rs @@ -35,11 +35,6 @@ impl RenderView for GenericView<'_> { view.render_view(host)?; Ok(()) } - - Value::Binary(_) => { - host.stdout(""); - Ok(()) - } } } } diff --git a/src/plugins/binaryview.rs b/src/plugins/binaryview.rs index a6b8df8990..3b92177374 100644 --- a/src/plugins/binaryview.rs +++ b/src/plugins/binaryview.rs @@ -1,5 +1,7 @@ use crossterm::{cursor, terminal, Attribute, RawScreen}; -use nu::{serve_plugin, CallInfo, Plugin, ShellError, Signature, SpanSource, Tagged, Value}; +use nu::{ + serve_plugin, CallInfo, Plugin, Primitive, ShellError, Signature, SpanSource, Tagged, Value, +}; use pretty_hex::*; struct BinaryView; @@ -21,7 +23,7 @@ impl Plugin for BinaryView { for v in input { let value_origin = v.origin(); match v.item { - Value::Binary(b) => { + Value::Primitive(Primitive::Binary(b)) => { let source = value_origin.and_then(|x| call_info.source_map.get(&x)); let _ = view_binary(&b, source, call_info.args.has("lores")); }