nu_command/platform/
sleep.rs1use nu_engine::command_prelude::*;
2
3use std::{
4 thread,
5 time::{Duration, Instant},
6};
7
8const CTRL_C_CHECK_INTERVAL: Duration = Duration::from_millis(100);
9
10#[derive(Clone)]
11pub struct Sleep;
12
13impl Command for Sleep {
14 fn name(&self) -> &str {
15 "sleep"
16 }
17
18 fn description(&self) -> &str {
19 "Delay for a specified amount of time."
20 }
21
22 fn signature(&self) -> Signature {
23 Signature::build("sleep")
24 .input_output_types(vec![(Type::Nothing, Type::Nothing)])
25 .required("duration", SyntaxShape::Duration, "Time to sleep.")
26 .rest(
27 "rest",
28 SyntaxShape::Duration,
29 "Additional time duration to sleep.",
30 )
31 .category(Category::Platform)
32 }
33
34 fn search_terms(&self) -> Vec<&str> {
35 vec!["delay", "wait", "timer"]
36 }
37
38 fn run(
39 &self,
40 engine_state: &EngineState,
41 stack: &mut Stack,
42 call: &Call,
43 _input: PipelineData,
44 ) -> Result<PipelineData, ShellError> {
45 fn duration_from_i64(val: i64) -> Duration {
46 Duration::from_nanos(if val < 0 { 0 } else { val as u64 })
47 }
48
49 let duration: i64 = call.req(engine_state, stack, 0)?;
50 let rest: Vec<i64> = call.rest(engine_state, stack, 1)?;
51
52 let total_dur =
53 duration_from_i64(duration) + rest.into_iter().map(duration_from_i64).sum::<Duration>();
54 let deadline = Instant::now() + total_dur;
55
56 loop {
57 let time_until_deadline = deadline.saturating_duration_since(Instant::now());
59 if time_until_deadline.is_zero() {
60 break;
61 }
62 thread::sleep(CTRL_C_CHECK_INTERVAL.min(time_until_deadline));
63 engine_state.signals().check(&call.head)?;
64 }
65
66 Ok(Value::nothing(call.head).into_pipeline_data())
67 }
68
69 fn examples(&self) -> Vec<Example<'_>> {
70 vec![
71 Example {
72 description: "Sleep for 1 second.",
73 example: "sleep 1sec",
74 result: Some(Value::nothing(Span::test_data())),
75 },
76 Example {
77 description: "Use multiple arguments to write a duration with multiple units, which is unsupported by duration literals.",
78 example: "sleep 1min 30sec",
79 result: None,
80 },
81 Example {
82 description: "Send output after 1 second.",
83 example: "sleep 1sec; echo done",
84 result: None,
85 },
86 ]
87 }
88}
89
90#[cfg(test)]
91mod tests {
92 use super::Sleep;
93
94 #[test]
95 fn examples_work_as_expected() {
96 use crate::test_examples;
97 use std::time::Instant;
98
99 let start = Instant::now();
100 test_examples(Sleep {});
101
102 let elapsed = start.elapsed();
103
104 assert!(elapsed >= std::time::Duration::from_secs(1));
106 assert!(elapsed < std::time::Duration::from_secs(2));
107 }
108}