diff --git a/crates/nu-cmd-lang/src/core_commands/describe.rs b/crates/nu-cmd-lang/src/core_commands/describe.rs index b3f7b50611..6fa11d8061 100644 --- a/crates/nu-cmd-lang/src/core_commands/describe.rs +++ b/crates/nu-cmd-lang/src/core_commands/describe.rs @@ -1,6 +1,9 @@ use nu_engine::command_prelude::*; -use nu_protocol::{engine::StateWorkingSet, ByteStreamSource, PipelineMetadata}; - +use nu_protocol::{ + engine::{Closure, StateWorkingSet}, + BlockId, ByteStreamSource, Category, PipelineMetadata, Signature, +}; +use std::any::type_name; #[derive(Clone)] pub struct Describe; @@ -73,39 +76,116 @@ impl Command for Describe { "{shell:'true', uwu:true, features: {bugs:false, multiplatform:true, speed: 10}, fib: [1 1 2 3 5 8], on_save: {|x| $'Saving ($x)'}, first_commit: 2019-05-10, my_duration: (4min + 20sec)} | describe -d", result: Some(Value::test_record(record!( "type" => Value::test_string("record"), + "detailed_type" => Value::test_string("record, fib: list, on_save: closure, first_commit: datetime, my_duration: duration>"), "columns" => Value::test_record(record!( - "shell" => Value::test_string("string"), - "uwu" => Value::test_string("bool"), + "shell" => Value::test_record(record!( + "type" => Value::test_string("string"), + "detailed_type" => Value::test_string("string"), + "rust_type" => Value::test_string("&alloc::string::String"), + "value" => Value::test_string("true"), + )), + "uwu" => Value::test_record(record!( + "type" => Value::test_string("bool"), + "detailed_type" => Value::test_string("bool"), + "rust_type" => Value::test_string("bool"), + "value" => Value::test_bool(true), + )), "features" => Value::test_record(record!( "type" => Value::test_string("record"), + "detailed_type" => Value::test_string("record"), "columns" => Value::test_record(record!( - "bugs" => Value::test_string("bool"), - "multiplatform" => Value::test_string("bool"), - "speed" => Value::test_string("int"), + "bugs" => Value::test_record(record!( + "type" => Value::test_string("bool"), + "detailed_type" => Value::test_string("bool"), + "rust_type" => Value::test_string("bool"), + "value" => Value::test_bool(false), + )), + "multiplatform" => Value::test_record(record!( + "type" => Value::test_string("bool"), + "detailed_type" => Value::test_string("bool"), + "rust_type" => Value::test_string("bool"), + "value" => Value::test_bool(true), + )), + "speed" => Value::test_record(record!( + "type" => Value::test_string("int"), + "detailed_type" => Value::test_string("int"), + "rust_type" => Value::test_string("i64"), + "value" => Value::test_int(10), + )), )), + "rust_type" => Value::test_string("&nu_utils::shared_cow::SharedCow"), )), "fib" => Value::test_record(record!( "type" => Value::test_string("list"), + "detailed_type" => Value::test_string("list"), "length" => Value::test_int(6), - "values" => Value::test_list(vec![ - Value::test_string("int"), - Value::test_string("int"), - Value::test_string("int"), - Value::test_string("int"), - Value::test_string("int"), - Value::test_string("int"), - ]), + "rust_type" => Value::test_string("&mut alloc::vec::Vec"), + "value" => Value::test_list(vec![ + Value::test_record(record!( + "type" => Value::test_string("int"), + "detailed_type" => Value::test_string("int"), + "rust_type" => Value::test_string("i64"), + "value" => Value::test_int(1), + )), + Value::test_record(record!( + "type" => Value::test_string("int"), + "detailed_type" => Value::test_string("int"), + "rust_type" => Value::test_string("i64"), + "value" => Value::test_int(1), + )), + Value::test_record(record!( + "type" => Value::test_string("int"), + "detailed_type" => Value::test_string("int"), + "rust_type" => Value::test_string("i64"), + "value" => Value::test_int(2), + )), + Value::test_record(record!( + "type" => Value::test_string("int"), + "detailed_type" => Value::test_string("int"), + "rust_type" => Value::test_string("i64"), + "value" => Value::test_int(3), + )), + Value::test_record(record!( + "type" => Value::test_string("int"), + "detailed_type" => Value::test_string("int"), + "rust_type" => Value::test_string("i64"), + "value" => Value::test_int(5), + )), + Value::test_record(record!( + "type" => Value::test_string("int"), + "detailed_type" => Value::test_string("int"), + "rust_type" => Value::test_string("i64"), + "value" => Value::test_int(8), + ))] + ), )), "on_save" => Value::test_record(record!( "type" => Value::test_string("closure"), + "detailed_type" => Value::test_string("closure"), + "rust_type" => Value::test_string("&alloc::boxed::Box"), + "value" => Value::test_closure(Closure { + block_id: BlockId::new(1), + captures: vec![], + }), "signature" => Value::test_record(record!( "name" => Value::test_string(""), "category" => Value::test_string("default"), )), )), - "first_commit" => Value::test_string("datetime"), - "my_duration" => Value::test_string("duration"), + "first_commit" => Value::test_record(record!( + "type" => Value::test_string("datetime"), + "detailed_type" => Value::test_string("datetime"), + "rust_type" => Value::test_string("chrono::datetime::DateTime"), + "value" => Value::test_date("2019-05-10 00:00:00Z".parse().unwrap_or_default()), + )), + "my_duration" => Value::test_record(record!( + "type" => Value::test_string("duration"), + "detailed_type" => Value::test_string("duration"), + "rust_type" => Value::test_string("i64"), + "value" => Value::test_duration(260_000_000_000), + )) )), + "rust_type" => Value::test_string("&nu_utils::shared_cow::SharedCow"), ))), }, Example { @@ -175,7 +255,9 @@ fn run( Value::record( record! { - "type" => Value::string(type_, head), + "type" => Value::string("bytestream", head), + "detailed_type" => Value::string(type_, head), + "rust_type" => Value::string(type_of(&stream), head), "origin" => Value::string(origin, head), "metadata" => metadata_to_value(metadata, head), }, @@ -192,6 +274,7 @@ fn run( description } PipelineData::ListStream(stream, ..) => { + let type_ = type_of(&stream); if options.detailed { let subtype = if options.no_collect { Value::string("any", head) @@ -201,6 +284,8 @@ fn run( Value::record( record! { "type" => Value::string("stream", head), + "detailed_type" => Value::string("list stream", head), + "rust_type" => Value::string(type_, head), "origin" => Value::string("nushell", head), "subtype" => subtype, "metadata" => metadata_to_value(metadata, head), @@ -229,45 +314,95 @@ fn run( } enum Description { - String(String), Record(Record), } impl Description { fn into_value(self, span: Span) -> Value { match self { - Description::String(ty) => Value::string(ty, span), Description::Record(record) => Value::record(record, span), } } } fn describe_value(value: Value, head: Span, engine_state: Option<&EngineState>) -> Value { - let record = match describe_value_inner(value, head, engine_state) { - Description::String(ty) => record! { "type" => Value::string(ty, head) }, - Description::Record(record) => record, - }; + let Description::Record(record) = describe_value_inner(value, head, engine_state); Value::record(record, head) } +fn type_of(_: &T) -> String { + type_name::().to_string() +} + fn describe_value_inner( - value: Value, + mut value: Value, head: Span, engine_state: Option<&EngineState>, ) -> Description { + let value_type = value.get_type().to_string(); match value { - Value::Bool { .. } - | Value::Int { .. } - | Value::Float { .. } - | Value::Filesize { .. } - | Value::Duration { .. } - | Value::Date { .. } - | Value::Range { .. } - | Value::String { .. } - | Value::Glob { .. } - | Value::Nothing { .. } => Description::String(value.get_type().to_string()), - Value::Record { val, .. } => { - let mut columns = val.into_owned(); + Value::Bool { val, .. } => Description::Record(record! { + "type" => Value::string("bool", head), + "detailed_type" => Value::string(value_type, head), + "rust_type" => Value::string(type_of(&val), head), + "value" => value, + }), + Value::Int { val, .. } => Description::Record(record! { + "type" => Value::string("int", head), + "detailed_type" => Value::string(value_type, head), + "rust_type" => Value::string(type_of(&val), head), + "value" => value, + }), + Value::Float { val, .. } => Description::Record(record! { + "type" => Value::string("float", head), + "detailed_type" => Value::string(value_type, head), + "rust_type" => Value::string(type_of(&val), head), + "value" => value, + }), + Value::Filesize { val, .. } => Description::Record(record! { + "type" => Value::string("filesize", head), + "detailed_type" => Value::string(value_type, head), + "rust_type" => Value::string(type_of(&val), head), + "value" => value, + }), + Value::Duration { val, .. } => Description::Record(record! { + "type" => Value::string("duration", head), + "detailed_type" => Value::string(value_type, head), + "rust_type" => Value::string(type_of(&val), head), + "value" => value, + }), + Value::Date { val, .. } => Description::Record(record! { + "type" => Value::string("datetime", head), + "detailed_type" => Value::string(value_type, head), + "rust_type" => Value::string(type_of(&val), head), + "value" => value, + }), + Value::Range { ref val, .. } => Description::Record(record! { + "type" => Value::string("range", head), + "detailed_type" => Value::string(value_type, head), + "rust_type" => Value::string(type_of(&val), head), + "value" => value, + }), + Value::String { ref val, .. } => Description::Record(record! { + "type" => Value::string("string", head), + "detailed_type" => Value::string(value_type, head), + "rust_type" => Value::string(type_of(&val), head), + "value" => value, + }), + Value::Glob { ref val, .. } => Description::Record(record! { + "type" => Value::string("glob", head), + "detailed_type" => Value::string(value_type, head), + "rust_type" => Value::string(type_of(&val), head), + "value" => value, + }), + Value::Nothing { .. } => Description::Record(record! { + "type" => Value::string("nothing", head), + "detailed_type" => Value::string(value_type, head), + "rust_type" => Value::string("", head), + "value" => value, + }), + Value::Record { ref val, .. } => { + let mut columns = val.clone().into_owned(); for (_, val) in &mut columns { *val = describe_value_inner(std::mem::take(val), head, engine_state).into_value(head); @@ -275,25 +410,34 @@ fn describe_value_inner( Description::Record(record! { "type" => Value::string("record", head), - "columns" => Value::record(columns, head), + "detailed_type" => Value::string(value_type, head), + "columns" => Value::record(columns.clone(), head), + "rust_type" => Value::string(type_of(&val), head), }) } - Value::List { mut vals, .. } => { - for val in &mut vals { + Value::List { ref mut vals, .. } => { + for val in &mut *vals { *val = describe_value_inner(std::mem::take(val), head, engine_state).into_value(head); } Description::Record(record! { "type" => Value::string("list", head), + "detailed_type" => Value::string(value_type, head), "length" => Value::int(vals.len() as i64, head), - "values" => Value::list(vals, head), + "rust_type" => Value::string(type_of(&vals), head), + "value" => value, }) } - Value::Closure { val, .. } => { + Value::Closure { ref val, .. } => { let block = engine_state.map(|engine_state| engine_state.get_block(val.block_id)); - let mut record = record! { "type" => Value::string("closure", head) }; + let mut record = record! { + "type" => Value::string("closure", head), + "detailed_type" => Value::string(value_type, head), + "rust_type" => Value::string(type_of(&val), head), + "value" => value, + }; if let Some(block) = block { record.push( "signature", @@ -308,21 +452,37 @@ fn describe_value_inner( } Description::Record(record) } - Value::Error { error, .. } => Description::Record(record! { + Value::Error { ref error, .. } => Description::Record(record! { "type" => Value::string("error", head), + "detailed_type" => Value::string(value_type, head), "subtype" => Value::string(error.to_string(), head), + "rust_type" => Value::string(type_of(&error), head), + "value" => value, }), - Value::Binary { val, .. } => Description::Record(record! { + Value::Binary { ref val, .. } => Description::Record(record! { "type" => Value::string("binary", head), + "detailed_type" => Value::string(value_type, head), "length" => Value::int(val.len() as i64, head), + "rust_type" => Value::string(type_of(&val), head), + "value" => value, }), - Value::CellPath { val, .. } => Description::Record(record! { + Value::CellPath { ref val, .. } => Description::Record(record! { "type" => Value::string("cell-path", head), + "detailed_type" => Value::string(value_type, head), "length" => Value::int(val.members.len() as i64, head), + "rust_type" => Value::string(type_of(&val), head), + "value" => value }), - Value::Custom { val, .. } => Description::Record(record! { + Value::Custom { ref val, .. } => Description::Record(record! { "type" => Value::string("custom", head), + "detailed_type" => Value::string(value_type, head), "subtype" => Value::string(val.type_name(), head), + "rust_type" => Value::string(type_of(&val), head), + "value" => + match val.to_base_value(head) { + Ok(base_value) => base_value, + Err(err) => Value::error(err, head), + } }), } }