diff --git a/crates/nu-command/tests/commands/help.rs b/crates/nu-command/tests/commands/help.rs index b0c61ce7a..a606bd874 100644 --- a/crates/nu-command/tests/commands/help.rs +++ b/crates/nu-command/tests/commands/help.rs @@ -20,13 +20,11 @@ fn help_commands_length() { #[test] fn help_shows_signature() { let actual = nu!("help str distance"); - assert!(actual - .out - .contains(" | str distance -> ")); + assert!(actual.out.contains("Input/output types")); // don't show signature for parser keyword let actual = nu!("help alias"); - assert!(!actual.out.contains("Signatures")); + assert!(!actual.out.contains("Input/output types")); } #[ignore = "TODO: Need to decide how to do help messages of new aliases"] diff --git a/crates/nu-engine/src/documentation.rs b/crates/nu-engine/src/documentation.rs index fdd4ec536..a6b22f60b 100644 --- a/crates/nu-engine/src/documentation.rs +++ b/crates/nu-engine/src/documentation.rs @@ -3,7 +3,9 @@ use nu_protocol::{ engine::{EngineState, Stack}, Example, IntoPipelineData, PipelineData, Signature, Span, SyntaxShape, Value, }; -use std::fmt::Write; +use std::{collections::HashMap, fmt::Write}; + +use crate::eval_call; pub fn get_full_help( sig: &Signature, @@ -129,17 +131,6 @@ fn get_documentation( })) } - if !is_parser_keyword && !sig.input_output_types.is_empty() { - if sig.operates_on_cell_paths() { - let _ = writeln!( - long_desc, - "\n{G}Signatures(Cell paths are supported){RESET}:\n{sig}" - ); - } else { - let _ = writeln!(long_desc, "\n{G}Signatures{RESET}:\n{sig}"); - } - } - if !sig.required_positional.is_empty() || !sig.optional_positional.is_empty() || sig.rest_positional.is_some() @@ -213,6 +204,46 @@ fn get_documentation( } } + if !is_parser_keyword && !sig.input_output_types.is_empty() { + if let Some(decl_id) = engine_state.find_decl(b"table", &[]) { + // FIXME: we may want to make this the span of the help command in the future + let span = Span::unknown(); + let mut vals = vec![]; + for (input, output) in &sig.input_output_types { + vals.push(Value::Record { + cols: vec!["input".into(), "output".into()], + vals: vec![ + Value::string(input.to_string(), span), + Value::string(output.to_string(), span), + ], + span, + }); + } + + let mut caller_stack = Stack::new(); + if let Ok(result) = eval_call( + engine_state, + &mut caller_stack, + &Call { + decl_id, + head: span, + arguments: vec![], + redirect_stdout: true, + redirect_stderr: true, + parser_info: HashMap::new(), + }, + PipelineData::Value(Value::List { vals, span }, None), + ) { + if let Ok((str, ..)) = result.collect_string_strict(span) { + let _ = writeln!(long_desc, "\n{G}Input/output types{RESET}:"); + for line in str.lines() { + let _ = writeln!(long_desc, " {line}"); + } + } + } + } + } + if !examples.is_empty() { let _ = write!(long_desc, "\n{G}Examples{RESET}:"); } diff --git a/src/tests/test_engine.rs b/src/tests/test_engine.rs index 4aa2b7453..81ca12400 100644 --- a/src/tests/test_engine.rs +++ b/src/tests/test_engine.rs @@ -55,7 +55,7 @@ fn in_and_if_else() -> TestResult { #[test] fn help_works_with_missing_requirements() -> TestResult { // `each while` is part of the *extra* feature and adds 3 lines - let expected_length = if cfg!(feature = "extra") { "66" } else { "63" }; + let expected_length = if cfg!(feature = "extra") { "70" } else { "67" }; run_test(r#"each --help | lines | length"#, expected_length) }