From c3a066eeb4b0d7576388c5656a11a928725d517f Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Mon, 11 May 2020 23:05:44 +0300 Subject: [PATCH] Add examples to commands (#1752) * Pass &dyn WholeStreamCommand to get_help * Add an optional example to the WholeStreamCommand trait * Add an example to the alias command --- crates/nu-cli/src/commands.rs | 4 ++- crates/nu-cli/src/commands/alias.rs | 9 ++++++- crates/nu-cli/src/commands/command.rs | 15 ++++++++++- crates/nu-cli/src/commands/from.rs | 5 +--- crates/nu-cli/src/commands/help.rs | 37 ++++++++++++--------------- crates/nu-cli/src/commands/to.rs | 5 +--- 6 files changed, 44 insertions(+), 31 deletions(-) diff --git a/crates/nu-cli/src/commands.rs b/crates/nu-cli/src/commands.rs index d12ac42fd2..8e1b4fec27 100644 --- a/crates/nu-cli/src/commands.rs +++ b/crates/nu-cli/src/commands.rs @@ -125,7 +125,9 @@ pub(crate) mod wrap; pub(crate) use autoview::Autoview; pub(crate) use cd::Cd; -pub(crate) use command::{whole_stream_command, Command, UnevaluatedCallInfo, WholeStreamCommand}; +pub(crate) use command::{ + whole_stream_command, Command, Example, UnevaluatedCallInfo, WholeStreamCommand, +}; pub(crate) use alias::Alias; pub(crate) use append::Append; diff --git a/crates/nu-cli/src/commands/alias.rs b/crates/nu-cli/src/commands/alias.rs index 98f322abb5..3e66391c03 100644 --- a/crates/nu-cli/src/commands/alias.rs +++ b/crates/nu-cli/src/commands/alias.rs @@ -1,4 +1,4 @@ -use crate::commands::WholeStreamCommand; +use crate::commands::{Example, WholeStreamCommand}; use crate::context::CommandRegistry; use crate::prelude::*; use nu_errors::ShellError; @@ -41,6 +41,13 @@ impl WholeStreamCommand for Alias { ) -> Result { args.process(registry, alias)?.run() } + + fn examples(&self) -> &[Example] { + &[Example { + description: "Some people prefer to write one letter instead of two", + example: "alias l [x] { ls $x }", + }] + } } pub fn alias( diff --git a/crates/nu-cli/src/commands/command.rs b/crates/nu-cli/src/commands/command.rs index 9f6a52b920..aedb67b75b 100644 --- a/crates/nu-cli/src/commands/command.rs +++ b/crates/nu-cli/src/commands/command.rs @@ -350,6 +350,11 @@ impl EvaluatedCommandArgs { } } +pub struct Example { + pub example: &'static str, + pub description: &'static str, +} + pub trait WholeStreamCommand: Send + Sync { fn name(&self) -> &str; @@ -368,6 +373,10 @@ pub trait WholeStreamCommand: Send + Sync { fn is_binary(&self) -> bool { false } + + fn examples(&self) -> &[Example] { + &[] + } } #[derive(Clone)] @@ -407,7 +416,7 @@ impl Command { pub fn run(&self, args: CommandArgs, registry: &CommandRegistry) -> OutputStream { if args.call_info.switch_present("help") { - get_help(self.name(), self.usage(), self.signature(), registry).into() + get_help(&*self.0, registry).into() } else { match self.0.run(args, registry) { Ok(stream) => stream, @@ -419,6 +428,10 @@ impl Command { pub fn is_binary(&self) -> bool { self.0.is_binary() } + + pub fn stream_command(&self) -> &dyn WholeStreamCommand { + &*self.0 + } } pub struct FnFilterCommand { diff --git a/crates/nu-cli/src/commands/from.rs b/crates/nu-cli/src/commands/from.rs index 18e214cbd8..f6475005ac 100644 --- a/crates/nu-cli/src/commands/from.rs +++ b/crates/nu-cli/src/commands/from.rs @@ -23,9 +23,6 @@ impl WholeStreamCommand for From { _args: CommandArgs, registry: &CommandRegistry, ) -> Result { - Ok( - crate::commands::help::get_help(self.name(), self.usage(), self.signature(), registry) - .into(), - ) + Ok(crate::commands::help::get_help(&*self, registry).into()) } } diff --git a/crates/nu-cli/src/commands/help.rs b/crates/nu-cli/src/commands/help.rs index 4210680090..96c780a313 100644 --- a/crates/nu-cli/src/commands/help.rs +++ b/crates/nu-cli/src/commands/help.rs @@ -86,22 +86,10 @@ fn help( // Check for a subcommand let command_name = format!("{} {}", rest[0].item, rest[1].item); if let Some(command) = registry.get_command(&command_name) { - return Ok(get_help( - &command.name(), - &command.usage(), - command.signature(), - ®istry, - ) - .into()); + return Ok(get_help(command.stream_command(), ®istry).into()); } } else if let Some(command) = registry.get_command(&document.item) { - return Ok(get_help( - &command.name(), - &command.usage(), - command.signature(), - ®istry, - ) - .into()); + return Ok(get_help(command.stream_command(), ®istry).into()); } else { return Err(ShellError::labeled_error( "Can't find command (use 'help commands' for full list)", @@ -142,20 +130,19 @@ You can also learn more at https://www.nushell.sh/book/"#; } } +#[allow(clippy::cognitive_complexity)] pub(crate) fn get_help( - cmd_name: &str, - cmd_usage: &str, - cmd_sig: Signature, + cmd: &dyn WholeStreamCommand, registry: &CommandRegistry, ) -> impl Into { + let cmd_name = cmd.name(); + let signature = cmd.signature(); let mut help = VecDeque::new(); let mut long_desc = String::new(); - long_desc.push_str(&cmd_usage); + long_desc.push_str(&cmd.usage()); long_desc.push_str("\n"); - let signature = cmd_sig; - let mut subcommands = String::new(); for name in registry.names() { if name.starts_with(&format!("{} ", cmd_name)) { @@ -283,6 +270,16 @@ pub(crate) fn get_help( } } + let examples = cmd.examples(); + if !examples.is_empty() { + long_desc.push_str("\nExamples:\n"); + } + for example in examples { + long_desc.push_str(" "); + long_desc.push_str(example.description); + long_desc.push_str(&format!("\n > {}\n", example.example)); + } + help.push_back(ReturnSuccess::value( UntaggedValue::string(long_desc).into_value(Tag::from((0, cmd_name.len(), None))), )); diff --git a/crates/nu-cli/src/commands/to.rs b/crates/nu-cli/src/commands/to.rs index 17a0cf693f..d33bebd013 100644 --- a/crates/nu-cli/src/commands/to.rs +++ b/crates/nu-cli/src/commands/to.rs @@ -23,9 +23,6 @@ impl WholeStreamCommand for To { _args: CommandArgs, registry: &CommandRegistry, ) -> Result { - Ok( - crate::commands::help::get_help(self.name(), self.usage(), self.signature(), registry) - .into(), - ) + Ok(crate::commands::help::get_help(self, registry).into()) } }