From 0dd1403a69d26544ec958d43e8df0d4aef2ae79f Mon Sep 17 00:00:00 2001 From: Leonhard Kipp Date: Fri, 21 Aug 2020 19:51:29 +0200 Subject: [PATCH] Sleep command (#2381) * Add deserialization of Primitive::Duration; Fixes #2373 * Implement Sleep command * Add comment saying you should name your rest field "rest" * Fix typo * Add documentation for sleep command --- crates/nu-cli/src/cli.rs | 1 + crates/nu-cli/src/commands.rs | 2 + crates/nu-cli/src/commands/sleep.rs | 86 +++++++++++++++++++++++++++++ crates/nu-cli/src/deserializer.rs | 9 +++ crates/nu-parser/src/parse.rs | 2 +- crates/nu-protocol/src/signature.rs | 2 + docs/commands/sleep.md | 21 +++++++ 7 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 crates/nu-cli/src/commands/sleep.rs create mode 100644 docs/commands/sleep.md diff --git a/crates/nu-cli/src/cli.rs b/crates/nu-cli/src/cli.rs index 8513ae7fb..b06f5ea51 100644 --- a/crates/nu-cli/src/cli.rs +++ b/crates/nu-cli/src/cli.rs @@ -275,6 +275,7 @@ pub fn create_default_context( whole_stream_command(Alias), whole_stream_command(WithEnv), whole_stream_command(Do), + whole_stream_command(Sleep), // Statistics whole_stream_command(Size), whole_stream_command(Count), diff --git a/crates/nu-cli/src/commands.rs b/crates/nu-cli/src/commands.rs index 1e4acf302..c360a401e 100644 --- a/crates/nu-cli/src/commands.rs +++ b/crates/nu-cli/src/commands.rs @@ -97,6 +97,7 @@ pub(crate) mod shells; pub(crate) mod shuffle; pub(crate) mod size; pub(crate) mod skip; +pub(crate) mod sleep; pub(crate) mod sort_by; pub(crate) mod split; pub(crate) mod split_by; @@ -227,6 +228,7 @@ pub(crate) use shells::Shells; pub(crate) use shuffle::Shuffle; pub(crate) use size::Size; pub(crate) use skip::{Skip, SkipUntil, SkipWhile}; +pub(crate) use sleep::Sleep; pub(crate) use sort_by::SortBy; pub(crate) use split::{Split, SplitChars, SplitColumn, SplitRow}; pub(crate) use split_by::SplitBy; diff --git a/crates/nu-cli/src/commands/sleep.rs b/crates/nu-cli/src/commands/sleep.rs new file mode 100644 index 000000000..e69f149f9 --- /dev/null +++ b/crates/nu-cli/src/commands/sleep.rs @@ -0,0 +1,86 @@ +use crate::commands::WholeStreamCommand; +use crate::context::CommandRegistry; +use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{Signature, SyntaxShape}; +use nu_source::Tagged; + +use std::{thread, time}; + +pub struct Sleep; + +#[derive(Deserialize)] +pub struct SleepArgs { + pub dur: Tagged, + pub rest: Vec>, +} + +#[async_trait] +impl WholeStreamCommand for Sleep { + fn name(&self) -> &str { + "sleep" + } + + fn signature(&self) -> Signature { + Signature::build("sleep") + .required("duration", SyntaxShape::Unit, "time to sleep") + .rest(SyntaxShape::Unit, "additional time") + } + + fn usage(&self) -> &str { + "delay for a specified amount of time" + } + + async fn run( + &self, + args: CommandArgs, + registry: &CommandRegistry, + ) -> Result { + sleep(args, registry).await + } + + fn examples(&self) -> Vec { + vec![ + Example { + description: "Sleep for 1sec", + example: "sleep 1sec", + result: None, + }, + Example { + description: "Sleep for 3sec", + example: "sleep 1sec 1sec 1sec", + result: None, + }, + ] + } +} + +async fn sleep(args: CommandArgs, registry: &CommandRegistry) -> Result { + let registry = registry.clone(); + + let (SleepArgs { dur, rest }, ..) = args.process(®istry).await?; + + let total_dur = dur.item + rest.iter().map(|val| val.item).sum::(); + let total_dur = time::Duration::from_nanos(total_dur); + thread::sleep(total_dur); + + Ok(OutputStream::empty()) +} + +#[cfg(test)] +mod tests { + use super::Sleep; + use std::time::Instant; + + #[test] + #[ignore] + fn examples_work_as_expected() { + use crate::examples::test as test_examples; + + let start = Instant::now(); + test_examples(Sleep {}); + let elapsed = start.elapsed(); + println!("{:?}", elapsed); + assert!(elapsed >= std::time::Duration::from_secs(4)); + } +} diff --git a/crates/nu-cli/src/deserializer.rs b/crates/nu-cli/src/deserializer.rs index 8d18e7e90..007a7f061 100644 --- a/crates/nu-cli/src/deserializer.rs +++ b/crates/nu-cli/src/deserializer.rs @@ -412,6 +412,15 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut ConfigDeserializer<'de> { let i: i64 = int.tagged(value.val.tag).coerce_into("converting to i64")?; visit::, _>(i.tagged(tag), name, fields, visitor) } + Value { + value: UntaggedValue::Primitive(Primitive::Duration(big_int)), + .. + } => { + let u_int: u64 = big_int + .tagged(value.val.tag) + .coerce_into("converting to u64")?; + visit::, _>(u_int.tagged(tag), name, fields, visitor) + } Value { value: UntaggedValue::Primitive(Primitive::Decimal(decimal)), .. diff --git a/crates/nu-parser/src/parse.rs b/crates/nu-parser/src/parse.rs index b600fe986..687079781 100644 --- a/crates/nu-parser/src/parse.rs +++ b/crates/nu-parser/src/parse.rs @@ -334,7 +334,7 @@ fn parse_unit(lite_arg: &Spanned) -> (SpannedExpression, Option() { let lhs_span = Span::new(lite_arg.span.start(), lite_arg.span.start() + lhs.len()); diff --git a/crates/nu-protocol/src/signature.rs b/crates/nu-protocol/src/signature.rs index 4144323b6..5fcc19461 100644 --- a/crates/nu-protocol/src/signature.rs +++ b/crates/nu-protocol/src/signature.rs @@ -293,6 +293,8 @@ impl Signature { } /// Set the type for the "rest" of the positional arguments + /// Note: Not naming the field in your struct holding the rest values "rest", can + /// cause errors when deserializing pub fn rest(mut self, ty: SyntaxShape, desc: impl Into) -> Signature { self.rest_positional = Some((ty, desc.into())); self diff --git a/docs/commands/sleep.md b/docs/commands/sleep.md new file mode 100644 index 000000000..d7c6a1432 --- /dev/null +++ b/docs/commands/sleep.md @@ -0,0 +1,21 @@ +# sleep + +Delay for a specified amount of time + +Syntax: `sleep