This commit is contained in:
Andy Gayton 2024-08-01 12:47:51 -04:00
parent 354fc28e5d
commit b206b55c17
4 changed files with 25 additions and 25 deletions

View File

@ -11,9 +11,9 @@ use nu_plugin_protocol::{
PluginOutput, ProtocolInfo, PluginOutput, ProtocolInfo,
}; };
use nu_protocol::{ use nu_protocol::{
engine::{ctrlc, Closure, Sequence}, engine::{Closure, Sequence},
Config, DeclId, LabeledError, PipelineData, PluginMetadata, PluginSignature, ShellError, Config, DeclId, Handler, HandlerGuard, Handlers, LabeledError, PipelineData, PluginMetadata,
Signals, Span, Spanned, Value, PluginSignature, ShellError, SignalAction, Signals, Span, Spanned, Value,
}; };
use nu_utils::SharedCow; use nu_utils::SharedCow;
use std::{ use std::{
@ -66,8 +66,8 @@ struct EngineInterfaceState {
writer: Box<dyn PluginWrite<PluginOutput>>, writer: Box<dyn PluginWrite<PluginOutput>>,
// Mirror signals from `EngineState` // Mirror signals from `EngineState`
signals: Signals, signals: Signals,
/// Registered Ctrl-C handlers /// Registered signal handlers
ctrlc_handlers: ctrlc::Handlers, signal_handlers: Handlers,
} }
impl std::fmt::Debug for EngineInterfaceState { impl std::fmt::Debug for EngineInterfaceState {
@ -122,7 +122,7 @@ impl EngineInterfaceManager {
engine_call_subscription_sender: subscription_tx, engine_call_subscription_sender: subscription_tx,
writer: Box::new(writer), writer: Box::new(writer),
signals: Signals::new(Arc::new(AtomicBool::new(false))), signals: Signals::new(Arc::new(AtomicBool::new(false))),
ctrlc_handlers: ctrlc::Handlers::new(), signal_handlers: Handlers::new(),
}), }),
protocol_info_mut, protocol_info_mut,
plugin_call_sender: Some(plug_tx), plugin_call_sender: Some(plug_tx),
@ -337,9 +337,12 @@ impl InterfaceManager for EngineInterfaceManager {
}); });
self.send_engine_call_response(id, response) self.send_engine_call_response(id, response)
} }
PluginInput::Ctrlc => { PluginInput::Signal(action) => {
self.state.signals.trigger(); match action {
self.state.ctrlc_handlers.run(); SignalAction::Interrupt => self.state.signals.trigger(),
SignalAction::Reset => self.state.signals.reset(),
}
self.state.signal_handlers.run(action);
Ok(()) Ok(())
} }
} }
@ -523,11 +526,8 @@ impl EngineInterface {
/// Register a closure which will be called when the engine receives a Ctrl-C signal. Returns a /// 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. /// RAII guard that will keep the closure alive until it is dropped.
pub fn register_ctrlc_handler( pub fn register_signal_handler(&self, handler: Handler) -> Result<HandlerGuard, ShellError> {
&self, self.state.signal_handlers.register(handler)
handler: ctrlc::Handler,
) -> Result<ctrlc::Guard, ShellError> {
self.state.ctrlc_handlers.register(handler)
} }
/// Get the full shell configuration from the engine. As this is quite a large object, it is /// Get the full shell configuration from the engine. As this is quite a large object, it is

View File

@ -99,14 +99,14 @@ mod tests {
let called1_clone = Arc::clone(&called1); let called1_clone = Arc::clone(&called1);
let called2_clone = Arc::clone(&called2); 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); 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); called2_clone.store(true, Ordering::SeqCst);
})); }));
handlers.run(); handlers.run(SignalAction::Interrupt);
assert!(called1.load(Ordering::SeqCst)); assert!(called1.load(Ordering::SeqCst));
assert!(called2.load(Ordering::SeqCst)); assert!(called2.load(Ordering::SeqCst));
@ -119,7 +119,7 @@ mod tests {
let called = Arc::new(AtomicBool::new(false)); let called = Arc::new(AtomicBool::new(false));
let called_clone = Arc::clone(&called); 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); called_clone.store(true, Ordering::Relaxed);
})); }));
@ -131,7 +131,7 @@ mod tests {
// Ensure the handler is removed after dropping the guard // Ensure the handler is removed after dropping the guard
assert_eq!(handlers.handlers.lock().unwrap().len(), 0); assert_eq!(handlers.handlers.lock().unwrap().len(), 0);
handlers.run(); handlers.run(SignalAction::Interrupt);
// Ensure the handler is not called after being dropped // Ensure the handler is not called after being dropped
assert!(!called.load(Ordering::Relaxed)); assert!(!called.load(Ordering::Relaxed));

View File

@ -77,15 +77,15 @@ impl Signals {
self.signals.is_none() self.signals.is_none()
} }
pub(crate) fn reset(&self) { pub fn reset(&self) {
if let Some(signals) = &self.signals { if let Some(signals) = &self.signals {
signals.store(false, Ordering::Relaxed); signals.store(false, Ordering::Relaxed);
} }
} }
} }
/// The types of things that can be signaled. Its anticipated this will change as we learn how we'd /// The types of things that can be signaled. It's anticipated this will change as we learn more
/// like signals to be handled. /// about how we'd like signals to be handled.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum SignalAction { pub enum SignalAction {
Interrupt, Interrupt,

View File

@ -16,7 +16,7 @@ impl PluginCommand for Ctrlc {
} }
fn usage(&self) -> &str { 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 { fn signature(&self) -> Signature {
@ -35,12 +35,12 @@ impl PluginCommand for Ctrlc {
_input: PipelineData, _input: PipelineData,
) -> Result<PipelineData, LabeledError> { ) -> Result<PipelineData, LabeledError> {
let (sender, receiver) = mpsc::channel::<()>(); 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(()); let _ = sender.send(());
})); }));
eprintln!("interrupt status: {:?}", engine.signals().interrupted()); eprintln!("interrupt status: {:?}", engine.signals().interrupted());
eprintln!("waiting for ctrl-c signal..."); eprintln!("waiting for interrupt signal...");
receiver.recv().expect("handler went away"); receiver.recv().expect("handler went away");
eprintln!("interrupt status: {:?}", engine.signals().interrupted()); eprintln!("interrupt status: {:?}", engine.signals().interrupted());
eprintln!("peace."); eprintln!("peace.");