mirror of
https://github.com/nushell/nushell
synced 2025-01-08 19:29:08 +00:00
669659f974
# Description This improves the resolution of the sleep commands by simply not clamping to the default 100ms ctrl+c signal checking loop if the passed-in duration is shorter. # User-Facing Changes You can use smaller values in sleep. ``` # Before timeit { 0..100 | each { |row| print $row; sleep 10ms; } } # +10sec # After timeit { 0..100 | each { |row| print $row; sleep 10ms; } } # +1sec ``` It still depends on the internal behavior of thread::sleep and the OS timers. In windows it doesn't seem to go much lower than 15 or 10ms, or 0 if you asked for that. # After Submitting Sleep didn't have anything documenting its minimum value, so this should be more in line with its standard procedure. It will still never sleep for less time than allocated. Did you know `sleep` can take multiple durations, and it'll add them up? I didn't
113 lines
3.1 KiB
Rust
113 lines
3.1 KiB
Rust
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, SyntaxShape,
|
|
Type, Value,
|
|
};
|
|
use std::{
|
|
thread,
|
|
time::{Duration, Instant},
|
|
};
|
|
|
|
const CTRL_C_CHECK_INTERVAL: Duration = Duration::from_millis(100);
|
|
|
|
#[derive(Clone)]
|
|
pub struct Sleep;
|
|
|
|
impl Command for Sleep {
|
|
fn name(&self) -> &str {
|
|
"sleep"
|
|
}
|
|
|
|
fn usage(&self) -> &str {
|
|
"Delay for a specified amount of time."
|
|
}
|
|
|
|
fn signature(&self) -> Signature {
|
|
Signature::build("sleep")
|
|
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
|
|
.required("duration", SyntaxShape::Duration, "Time to sleep.")
|
|
.rest("rest", SyntaxShape::Duration, "Additional time.")
|
|
.category(Category::Platform)
|
|
}
|
|
|
|
fn search_terms(&self) -> Vec<&str> {
|
|
vec!["delay", "wait", "timer"]
|
|
}
|
|
|
|
fn run(
|
|
&self,
|
|
engine_state: &EngineState,
|
|
stack: &mut Stack,
|
|
call: &Call,
|
|
_input: PipelineData,
|
|
) -> Result<PipelineData, ShellError> {
|
|
fn duration_from_i64(val: i64) -> Duration {
|
|
Duration::from_nanos(if val < 0 { 0 } else { val as u64 })
|
|
}
|
|
|
|
let duration: i64 = call.req(engine_state, stack, 0)?;
|
|
let rest: Vec<i64> = call.rest(engine_state, stack, 1)?;
|
|
|
|
let total_dur =
|
|
duration_from_i64(duration) + rest.into_iter().map(duration_from_i64).sum::<Duration>();
|
|
|
|
let ctrlc_ref = &engine_state.ctrlc.clone();
|
|
let start = Instant::now();
|
|
loop {
|
|
thread::sleep(CTRL_C_CHECK_INTERVAL.min(total_dur));
|
|
if start.elapsed() >= total_dur {
|
|
break;
|
|
}
|
|
|
|
if nu_utils::ctrl_c::was_pressed(ctrlc_ref) {
|
|
return Err(ShellError::InterruptedByUser {
|
|
span: Some(call.head),
|
|
});
|
|
}
|
|
}
|
|
|
|
Ok(Value::nothing(call.head).into_pipeline_data())
|
|
}
|
|
|
|
fn examples(&self) -> Vec<Example> {
|
|
vec![
|
|
Example {
|
|
description: "Sleep for 1sec",
|
|
example: "sleep 1sec",
|
|
result: Some(Value::nothing(Span::test_data())),
|
|
},
|
|
Example {
|
|
description: "Sleep for 3sec",
|
|
example: "sleep 1sec 1sec 1sec",
|
|
result: None,
|
|
},
|
|
Example {
|
|
description: "Send output after 1sec",
|
|
example: "sleep 1sec; echo done",
|
|
result: None,
|
|
},
|
|
]
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::Sleep;
|
|
|
|
#[test]
|
|
fn examples_work_as_expected() {
|
|
use crate::test_examples;
|
|
use std::time::Instant;
|
|
|
|
let start = Instant::now();
|
|
test_examples(Sleep {});
|
|
|
|
let elapsed = start.elapsed();
|
|
|
|
// only examples with actual output are run
|
|
assert!(elapsed >= std::time::Duration::from_secs(1));
|
|
assert!(elapsed < std::time::Duration::from_secs(2));
|
|
}
|
|
}
|