From 7c596f244fc236e9e066e943d313858009ba0983 Mon Sep 17 00:00:00 2001 From: Andy Gayton Date: Thu, 20 Jun 2024 23:36:41 -0400 Subject: [PATCH] wip --- crates/nu-parser/src/parse_keywords.rs | 2 +- crates/nu-plugin-engine/src/persistent.rs | 108 ++++++++++++++++++---- 2 files changed, 90 insertions(+), 20 deletions(-) diff --git a/crates/nu-parser/src/parse_keywords.rs b/crates/nu-parser/src/parse_keywords.rs index 2849b4e39c..40c62c157b 100644 --- a/crates/nu-parser/src/parse_keywords.rs +++ b/crates/nu-parser/src/parse_keywords.rs @@ -3742,7 +3742,7 @@ pub fn parse_register(working_set: &mut StateWorkingSet, lite_command: &LiteComm let signatures = plugin .clone() - .get(get_envs) + .get(get_envs, None) .and_then(|p| p.get_signature()) .map_err(|err| { log::warn!("Error getting signatures: {err:?}"); diff --git a/crates/nu-plugin-engine/src/persistent.rs b/crates/nu-plugin-engine/src/persistent.rs index 9474f556c7..9da7d28f6d 100644 --- a/crates/nu-plugin-engine/src/persistent.rs +++ b/crates/nu-plugin-engine/src/persistent.rs @@ -1,4 +1,5 @@ use crate::{ + gc::PluginGcMsg, init::{create_command, make_plugin_interface}, PluginGc, }; @@ -74,6 +75,7 @@ impl PersistentPlugin { pub fn get( self: Arc, envs: impl FnOnce() -> Result, ShellError>, + ctrlc_subscribers: Option, ) -> Result { let mut mutable = self.mutable.lock().map_err(|_| ShellError::NushellFailed { msg: format!( @@ -95,7 +97,7 @@ impl PersistentPlugin { // TODO: We should probably store the envs somewhere, in case we have to launch without // envs (e.g. from a custom value) let envs = envs()?; - let result = self.clone().spawn(&envs, &mut mutable); + let result = self.clone().spawn(&envs, &mut mutable, ctrlc_subscribers); // Check if we were using an alternate communication mode and may need to fall back to // stdio. @@ -110,7 +112,7 @@ impl PersistentPlugin { mutable.preferred_mode); // Reset to stdio and try again, but this time don't catch any error mutable.preferred_mode = Some(PreferredCommunicationMode::Stdio); - self.clone().spawn(&envs, &mut mutable)?; + self.clone().spawn(&envs, &mut mutable, ctrlc_subscribers)?; } Ok(mutable @@ -129,6 +131,7 @@ impl PersistentPlugin { self: Arc, envs: &HashMap, mutable: &mut MutableState, + ctrlc_subscribers: Option, ) -> Result<(), ShellError> { // Make sure `running` is set to None to begin if let Some(running) = mutable.running.take() { @@ -180,8 +183,15 @@ impl PersistentPlugin { // Start the plugin garbage collector let gc = PluginGc::new(mutable.gc_config.clone(), &self)?; - // I need the current EngineState here - eprintln!("gc.sender: {:?}", gc.clone_sender()); + + if let Some(ctrlc_subscribers) = ctrlc_subscribers { + if let Some(ctrlc_subscribers) = ctrlc_subscribers.lock().ok() { + let tx = gc.clone_sender(); + let tx = tx.map_input(|()| PluginGcMsg::Ctrlc); + + ctrlc_subscribers.push(tx); + } + } let pid = child.id(); let interface = make_plugin_interface( @@ -209,7 +219,7 @@ impl PersistentPlugin { gc.stop_tracking(); // Set the mode and try again mutable.preferred_mode = Some(PreferredCommunicationMode::LocalSocket); - return self.spawn(envs, mutable); + return self.spawn(envs, mutable, ctrlc_subscribers); } mutable.running = Some(RunningPlugin { interface, gc }); @@ -307,20 +317,80 @@ impl GetPlugin for PersistentPlugin { self: Arc, mut context: Option<(&EngineState, &mut Stack)>, ) -> Result { - self.get(|| { - // Get envs from the context if provided. - let envs = context - .as_mut() - .map(|(engine_state, stack)| { - // We need the current environment variables for `python` based plugins. Or - // we'll likely have a problem when a plugin is implemented in a virtual Python - // environment. - let stack = &mut stack.start_capture(); - nu_engine::env::env_to_strings(engine_state, stack) - }) - .transpose()?; + let ctrlc_subscribers = context + .as_ref() + .and_then(|(engine_state, _)| engine_state.ctrlc_tx.clone()); + self.get( + || { + // Get envs from the context if provided. + let envs = context + .as_mut() + .map(|(engine_state, stack)| { + // We need the current environment variables for `python` based plugins. Or + // we'll likely have a problem when a plugin is implemented in a virtual Python + // environment. + let stack = &mut stack.start_capture(); + nu_engine::env::env_to_strings(engine_state, stack) + }) + .transpose()?; - Ok(envs.unwrap_or_default()) - }) + Ok(envs.unwrap_or_default()) + }, + ctrlc_subscribers, + ) + } +} + +use std::fmt; +use std::sync::mpsc::{SendError, Sender}; + +trait SenderExt { + type Err; + + fn send(&self, t: T) -> Result<(), SendError>; + + fn map_input(self, func: F) -> Map + where + Self: Sized, + F: Fn(NewT) -> T, + { + Map { sender: self, func } + } +} + +impl SenderExt for Sender { + type Err = T; + + fn send(&self, value: T) -> Result<(), SendError> { + self.send(value) + } +} + +#[derive(Clone, Copy)] +pub struct Map { + sender: S, + func: F, +} + +impl fmt::Debug for Map +where + S: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Map") + .field("sender", &self.sender) + .field("func", &"") + .finish() + } +} + +impl, F, T, U> SenderExt for Map +where + F: Fn(T) -> U, +{ + type Err = S::Err; + + fn send(&self, value: T) -> Result<(), SendError> { + self.sender.send((self.func)(value)) } }