diff --git a/crates/nu-command/src/core_commands/debug.rs b/crates/nu-command/src/core_commands/debug.rs index bd4f07b97f..255bbc0b5e 100644 --- a/crates/nu-command/src/core_commands/debug.rs +++ b/crates/nu-command/src/core_commands/debug.rs @@ -24,7 +24,7 @@ impl Command for Debug { (Type::Table(vec![]), Type::List(Box::new(Type::String))), (Type::Any, Type::String), ]) - .category(Category::Core) + .category(Category::Debug) .switch("raw", "Prints the raw value representation", Some('r')) } diff --git a/crates/nu-command/src/default_context.rs b/crates/nu-command/src/default_context.rs index 37e343ac08..a27a462bb0 100644 --- a/crates/nu-command/src/default_context.rs +++ b/crates/nu-command/src/default_context.rs @@ -473,8 +473,11 @@ pub fn create_default_context() -> EngineState { // Experimental bind_command! { - ViewSource, IsAdmin, + View, + ViewFiles, + ViewSource, + ViewSpan, }; // Deprecated diff --git a/crates/nu-command/src/experimental/mod.rs b/crates/nu-command/src/experimental/mod.rs index b912a315a2..534329067e 100644 --- a/crates/nu-command/src/experimental/mod.rs +++ b/crates/nu-command/src/experimental/mod.rs @@ -1,5 +1,11 @@ mod is_admin; +mod view; +mod view_files; mod view_source; +mod view_span; pub use is_admin::IsAdmin; +pub use view::View; +pub use view_files::ViewFiles; pub use view_source::ViewSource; +pub use view_span::ViewSpan; diff --git a/crates/nu-command/src/experimental/view.rs b/crates/nu-command/src/experimental/view.rs new file mode 100644 index 0000000000..387cf54822 --- /dev/null +++ b/crates/nu-command/src/experimental/view.rs @@ -0,0 +1,49 @@ +use nu_engine::get_full_help; +use nu_protocol::{ + ast::Call, + engine::{Command, EngineState, Stack}, + Category, IntoPipelineData, PipelineData, ShellError, Signature, Type, Value, +}; + +#[derive(Clone)] +pub struct View; + +impl Command for View { + fn name(&self) -> &str { + "view" + } + + fn signature(&self) -> Signature { + Signature::build("view") + .category(Category::Debug) + .input_output_types(vec![(Type::Nothing, Type::String)]) + } + + fn usage(&self) -> &str { + "Various commands for viewing debug information" + } + + fn extra_usage(&self) -> &str { + "You must use one of the following subcommands. Using this command as-is will only produce this help message." + } + + fn run( + &self, + engine_state: &EngineState, + stack: &mut Stack, + call: &Call, + _input: PipelineData, + ) -> Result { + Ok(Value::String { + val: get_full_help( + &View.signature(), + &View.examples(), + engine_state, + stack, + self.is_parser_keyword(), + ), + span: call.head, + } + .into_pipeline_data()) + } +} diff --git a/crates/nu-command/src/experimental/view_files.rs b/crates/nu-command/src/experimental/view_files.rs new file mode 100644 index 0000000000..5ccd2a4d5d --- /dev/null +++ b/crates/nu-command/src/experimental/view_files.rs @@ -0,0 +1,70 @@ +use nu_protocol::ast::Call; +use nu_protocol::engine::{Command, EngineState, Stack}; +use nu_protocol::{ + Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Type, Value, +}; + +#[derive(Clone)] +pub struct ViewFiles; + +impl Command for ViewFiles { + fn name(&self) -> &str { + "view files" + } + + fn usage(&self) -> &str { + "View the files registered in nushell's EngineState memory" + } + + fn extra_usage(&self) -> &str { + "These are files parsed and loaded at runtime." + } + + fn signature(&self) -> nu_protocol::Signature { + Signature::build("view files") + .input_output_types(vec![(Type::Nothing, Type::String)]) + .category(Category::Debug) + } + + fn run( + &self, + engine_state: &EngineState, + _stack: &mut Stack, + call: &Call, + _input: PipelineData, + ) -> Result { + let mut records = vec![]; + + for (file, start, end) in engine_state.files() { + records.push(Value::Record { + cols: vec![ + "filename".to_string(), + "start".to_string(), + "end".to_string(), + "size".to_string(), + ], + vals: vec![ + Value::string(file, call.head), + Value::int(*start as i64, call.head), + Value::int(*end as i64, call.head), + Value::int(*end as i64 - *start as i64, call.head), + ], + span: call.head, + }); + } + + Ok(Value::List { + vals: records, + span: call.head, + } + .into_pipeline_data()) + } + + fn examples(&self) -> Vec { + vec![Example { + description: "View the files registered in nushell's EngineState memory", + example: r#"view files"#, + result: None, + }] + } +} diff --git a/crates/nu-command/src/experimental/view_source.rs b/crates/nu-command/src/experimental/view_source.rs index bb7167d149..b4e63d2582 100644 --- a/crates/nu-command/src/experimental/view_source.rs +++ b/crates/nu-command/src/experimental/view_source.rs @@ -12,7 +12,7 @@ pub struct ViewSource; impl Command for ViewSource { fn name(&self) -> &str { - "view-source" + "view source" } fn usage(&self) -> &str { @@ -20,10 +20,10 @@ impl Command for ViewSource { } fn signature(&self) -> nu_protocol::Signature { - Signature::build("view-source") + Signature::build("view source") .input_output_types(vec![(Type::Nothing, Type::String)]) .required("item", SyntaxShape::Any, "name or block to view") - .category(Category::Core) + .category(Category::Debug) } fn run( @@ -166,27 +166,27 @@ impl Command for ViewSource { vec![ Example { description: "View the source of a code block", - example: r#"let abc = { echo 'hi' }; view-source $abc"#, + example: r#"let abc = { echo 'hi' }; view source $abc"#, result: Some(Value::test_string("{ echo 'hi' }")), }, Example { description: "View the source of a custom command", - example: r#"def hi [] { echo 'Hi!' }; view-source hi"#, + example: r#"def hi [] { echo 'Hi!' }; view source hi"#, result: Some(Value::test_string("{ echo 'Hi!' }")), }, Example { description: "View the source of a custom command, which participates in the caller environment", - example: r#"def-env foo [] { let-env BAR = 'BAZ' }; view-source foo"#, + example: r#"def-env foo [] { let-env BAR = 'BAZ' }; view source foo"#, result: Some(Value::test_string("{ let-env BAR = 'BAZ' }")), }, Example { description: "View the source of a module", - example: r#"module mod-foo { export-env { let-env FOO_ENV = 'BAZ' } }; view-source mod-foo"#, + example: r#"module mod-foo { export-env { let-env FOO_ENV = 'BAZ' } }; view source mod-foo"#, result: Some(Value::test_string(" export-env { let-env FOO_ENV = 'BAZ' }")), }, Example { description: "View the source of an alias", - example: r#"alias hello = echo hi; view-source hello"#, + example: r#"alias hello = echo hi; view source hello"#, result: Some(Value::test_string("echo hi")), }, ] diff --git a/crates/nu-command/src/experimental/view_span.rs b/crates/nu-command/src/experimental/view_span.rs new file mode 100644 index 0000000000..0423a90a6f --- /dev/null +++ b/crates/nu-command/src/experimental/view_span.rs @@ -0,0 +1,68 @@ +use nu_engine::CallExt; +use nu_protocol::ast::Call; +use nu_protocol::engine::{Command, EngineState, Stack}; +use nu_protocol::{ + Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Spanned, + SyntaxShape, Type, Value, +}; + +#[derive(Clone)] +pub struct ViewSpan; + +impl Command for ViewSpan { + fn name(&self) -> &str { + "view span" + } + + fn usage(&self) -> &str { + "View the contents of a span" + } + + fn extra_usage(&self) -> &str { + "This command is meant for debugging purposes.\nIt allows you to view the contents of nushell spans.\nOne way to get spans is to pipe something into 'debug --raw'.\nThen you can use the Span { start, end } values as the start and end values for this command." + } + + fn signature(&self) -> nu_protocol::Signature { + Signature::build("view span") + .input_output_types(vec![(Type::Nothing, Type::String)]) + .required("start", SyntaxShape::Int, "start of the span") + .required("end", SyntaxShape::Int, "end of the span") + .category(Category::Debug) + } + + fn run( + &self, + engine_state: &EngineState, + stack: &mut Stack, + call: &Call, + _input: PipelineData, + ) -> Result { + let start_span: Spanned = call.req(engine_state, stack, 0)?; + let end_span: Spanned = call.req(engine_state, stack, 1)?; + + if start_span.item < end_span.item { + let bin_contents = + engine_state.get_span_contents(&Span::new(start_span.item, end_span.item)); + Ok( + Value::string(String::from_utf8_lossy(bin_contents), call.head) + .into_pipeline_data(), + ) + } else { + Err(ShellError::GenericError( + "Cannot view span".to_string(), + "this start and end does not correspond to a viewable value".to_string(), + Some(call.head), + None, + Vec::new(), + )) + } + } + + fn examples(&self) -> Vec { + vec![Example { + description: "View the source of a span. 1 and 2 are just example values. Use the return of debug -r to get the actual values", + example: r#"some | pipeline | or | variable | debug -r; view span 1 2"#, + result: None, + }] + } +} diff --git a/crates/nu-protocol/src/signature.rs b/crates/nu-protocol/src/signature.rs index 964e0ae045..491ba06ada 100644 --- a/crates/nu-protocol/src/signature.rs +++ b/crates/nu-protocol/src/signature.rs @@ -40,61 +40,63 @@ pub struct PositionalArg { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub enum Category { - Default, - Conversions, - Core, Bits, Bytes, + Chart, + Conversions, + Core, + Custom(String), Date, + Debug, + Default, + Deprecated, Env, Experimental, FileSystem, Filters, Formats, + Generators, + Hash, Math, Misc, Network, - Random, Platform, + Random, Shells, Strings, System, Viewers, - Hash, - Generators, - Chart, - Custom(String), - Deprecated, } impl std::fmt::Display for Category { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let msg = match self { - Category::Default => "default", + Category::Bits => "bits", + Category::Bytes => "bytes", + Category::Chart => "chart", Category::Conversions => "conversions", Category::Core => "core", + Category::Custom(name) => name, Category::Date => "date", + Category::Debug => "debug", + Category::Default => "default", + Category::Deprecated => "deprecated", Category::Env => "env", Category::Experimental => "experimental", Category::FileSystem => "filesystem", Category::Filters => "filters", Category::Formats => "formats", + Category::Generators => "generators", + Category::Hash => "hash", Category::Math => "math", Category::Misc => "misc", Category::Network => "network", - Category::Random => "random", Category::Platform => "platform", + Category::Random => "random", Category::Shells => "shells", Category::Strings => "strings", Category::System => "system", Category::Viewers => "viewers", - Category::Hash => "hash", - Category::Generators => "generators", - Category::Chart => "chart", - Category::Custom(name) => name, - Category::Deprecated => "deprecated", - Category::Bytes => "bytes", - Category::Bits => "bits", }; write!(f, "{msg}")