diff --git a/crates/nu-plugin/src/plugin/interface/mod.rs b/crates/nu-plugin/src/plugin/interface/mod.rs index daf2d5b783..300ff6e496 100644 --- a/crates/nu-plugin/src/plugin/interface/mod.rs +++ b/crates/nu-plugin/src/plugin/interface/mod.rs @@ -11,9 +11,9 @@ use nu_plugin_protocol::{ PluginOutput, ProtocolInfo, }; use nu_protocol::{ - engine::{ctrlc, Closure, Sequence}, - Config, DeclId, LabeledError, PipelineData, PluginMetadata, PluginSignature, ShellError, - Signals, Span, Spanned, Value, + engine::{Closure, Sequence}, + Config, DeclId, Handler, HandlerGuard, Handlers, LabeledError, PipelineData, PluginMetadata, + PluginSignature, ShellError, SignalAction, Signals, Span, Spanned, Value, }; use nu_utils::SharedCow; use std::{ @@ -66,8 +66,8 @@ struct EngineInterfaceState { writer: Box>, // Mirror signals from `EngineState` signals: Signals, - /// Registered Ctrl-C handlers - ctrlc_handlers: ctrlc::Handlers, + /// Registered signal handlers + signal_handlers: Handlers, } impl std::fmt::Debug for EngineInterfaceState { @@ -122,7 +122,7 @@ impl EngineInterfaceManager { engine_call_subscription_sender: subscription_tx, writer: Box::new(writer), signals: Signals::new(Arc::new(AtomicBool::new(false))), - ctrlc_handlers: ctrlc::Handlers::new(), + signal_handlers: Handlers::new(), }), protocol_info_mut, plugin_call_sender: Some(plug_tx), @@ -337,9 +337,12 @@ impl InterfaceManager for EngineInterfaceManager { }); self.send_engine_call_response(id, response) } - PluginInput::Ctrlc => { - self.state.signals.trigger(); - self.state.ctrlc_handlers.run(); + PluginInput::Signal(action) => { + match action { + SignalAction::Interrupt => self.state.signals.trigger(), + SignalAction::Reset => self.state.signals.reset(), + } + self.state.signal_handlers.run(action); Ok(()) } } @@ -523,11 +526,8 @@ impl EngineInterface { /// Register a closure which will be called when the engine receives a Ctrl-C signal. Returns a /// RAII guard that will keep the closure alive until it is dropped. - pub fn register_ctrlc_handler( - &self, - handler: ctrlc::Handler, - ) -> Result { - self.state.ctrlc_handlers.register(handler) + pub fn register_signal_handler(&self, handler: Handler) -> Result { + self.state.signal_handlers.register(handler) } /// Get the full shell configuration from the engine. As this is quite a large object, it is diff --git a/crates/nu-protocol/src/pipeline/handlers.rs b/crates/nu-protocol/src/pipeline/handlers.rs index 5c979c5b02..3c1b1b820a 100644 --- a/crates/nu-protocol/src/pipeline/handlers.rs +++ b/crates/nu-protocol/src/pipeline/handlers.rs @@ -99,14 +99,14 @@ mod tests { let called1_clone = Arc::clone(&called1); let called2_clone = Arc::clone(&called2); - let _guard1 = handlers.register(Box::new(move || { + let _guard1 = handlers.register(Box::new(move |_| { called1_clone.store(true, Ordering::SeqCst); })); - let _guard2 = handlers.register(Box::new(move || { + let _guard2 = handlers.register(Box::new(move |_| { called2_clone.store(true, Ordering::SeqCst); })); - handlers.run(); + handlers.run(SignalAction::Interrupt); assert!(called1.load(Ordering::SeqCst)); assert!(called2.load(Ordering::SeqCst)); @@ -119,7 +119,7 @@ mod tests { let called = Arc::new(AtomicBool::new(false)); let called_clone = Arc::clone(&called); - let guard = handlers.register(Box::new(move || { + let guard = handlers.register(Box::new(move |_| { called_clone.store(true, Ordering::Relaxed); })); @@ -131,7 +131,7 @@ mod tests { // Ensure the handler is removed after dropping the guard assert_eq!(handlers.handlers.lock().unwrap().len(), 0); - handlers.run(); + handlers.run(SignalAction::Interrupt); // Ensure the handler is not called after being dropped assert!(!called.load(Ordering::Relaxed)); diff --git a/crates/nu-protocol/src/pipeline/signals.rs b/crates/nu-protocol/src/pipeline/signals.rs index be3dffe4f0..f712f1e7a8 100644 --- a/crates/nu-protocol/src/pipeline/signals.rs +++ b/crates/nu-protocol/src/pipeline/signals.rs @@ -77,15 +77,15 @@ impl Signals { self.signals.is_none() } - pub(crate) fn reset(&self) { + pub fn reset(&self) { if let Some(signals) = &self.signals { signals.store(false, Ordering::Relaxed); } } } -/// The types of things that can be signaled. Its anticipated this will change as we learn how we'd -/// like signals to be handled. +/// The types of things that can be signaled. It's anticipated this will change as we learn more +/// about how we'd like signals to be handled. #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub enum SignalAction { Interrupt, diff --git a/crates/nu_plugin_example/src/commands/ctrlc.rs b/crates/nu_plugin_example/src/commands/ctrlc.rs index f9851a451a..50da9d24da 100644 --- a/crates/nu_plugin_example/src/commands/ctrlc.rs +++ b/crates/nu_plugin_example/src/commands/ctrlc.rs @@ -16,7 +16,7 @@ impl PluginCommand for Ctrlc { } fn usage(&self) -> &str { - "Example command that demonstrates registering a ctrl-c handler" + "Example command that demonstrates registering an interrupt signal handler" } fn signature(&self) -> Signature { @@ -35,12 +35,12 @@ impl PluginCommand for Ctrlc { _input: PipelineData, ) -> Result { let (sender, receiver) = mpsc::channel::<()>(); - let _guard = engine.register_ctrlc_handler(Box::new(move || { + let _guard = engine.register_signal_handler(Box::new(move |_| { let _ = sender.send(()); })); eprintln!("interrupt status: {:?}", engine.signals().interrupted()); - eprintln!("waiting for ctrl-c signal..."); + eprintln!("waiting for interrupt signal..."); receiver.recv().expect("handler went away"); eprintln!("interrupt status: {:?}", engine.signals().interrupted()); eprintln!("peace.");