store ctrlc_handlers on PersistentPlugin

This commit is contained in:
Andy Gayton 2024-07-04 16:39:50 -04:00
parent d055b9f17f
commit f6afe70947
5 changed files with 46 additions and 33 deletions

View File

@ -109,13 +109,15 @@ apparent the next time `nu` is next launched with that plugin registry file.
let custom_path = call.get_flag(engine_state, stack, "plugin-config")?;
// Start the plugin manually, to get the freshest signatures and to not affect engine
// state. Provide a GC config that will stop it ASAP
// state. Provide a GC config that will stop it ASAP. We don't pass ctrlc_handlers since
// this instance is temporary and won't be used to run commands.
let plugin = Arc::new(PersistentPlugin::new(
identity,
PluginGcConfig {
enabled: true,
stop_after: 0,
},
None,
));
let interface = plugin.clone().get_plugin(Some((engine_state, stack)))?;
let metadata = interface.get_metadata()?;

View File

@ -3838,7 +3838,7 @@ pub fn parse_register(working_set: &mut StateWorkingSet, lite_command: &LiteComm
let metadata_and_signatures = plugin
.clone()
.get(get_envs, None)
.get(get_envs)
.and_then(|p| {
let meta = p.get_metadata()?;
let sigs = p.get_signature()?;

View File

@ -295,7 +295,11 @@ pub fn add_plugin_to_working_set(
// Add it to / get it from the working set
let plugin = working_set.find_or_create_plugin(identity, || {
Arc::new(PersistentPlugin::new(identity.clone(), gc_config.clone()))
Arc::new(PersistentPlugin::new(
identity.clone(),
gc_config.clone(),
working_set.permanent_state.ctrlc_handlers.clone(),
))
});
plugin.set_gc_config(&gc_config);

View File

@ -37,6 +37,8 @@ struct MutableState {
preferred_mode: Option<PreferredCommunicationMode>,
/// Garbage collector config
gc_config: PluginGcConfig,
/// TODO: docs
ctrlc_handlers: Option<ctrlc::Handlers>,
}
#[derive(Debug, Clone, Copy)]
@ -58,7 +60,11 @@ struct RunningPlugin {
impl PersistentPlugin {
/// Create a new persistent plugin. The plugin will not be spawned immediately.
pub fn new(identity: PluginIdentity, gc_config: PluginGcConfig) -> PersistentPlugin {
pub fn new(
identity: PluginIdentity,
gc_config: PluginGcConfig,
ctrlc_handlers: Option<ctrlc::Handlers>,
) -> PersistentPlugin {
PersistentPlugin {
identity,
mutable: Mutex::new(MutableState {
@ -66,6 +72,7 @@ impl PersistentPlugin {
metadata: None,
preferred_mode: None,
gc_config,
ctrlc_handlers,
}),
}
}
@ -77,7 +84,6 @@ impl PersistentPlugin {
pub fn get(
self: Arc<Self>,
envs: impl FnOnce() -> Result<HashMap<String, String>, ShellError>,
ctrlc_handlers: Option<ctrlc::Handlers>,
) -> Result<PluginInterface, ShellError> {
let mut mutable = self.mutable.lock().map_err(|_| ShellError::NushellFailed {
msg: format!(
@ -99,9 +105,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, ctrlc_handlers.clone());
let result = self.clone().spawn(&envs, &mut mutable);
// Check if we were using an alternate communication mode and may need to fall back to
// stdio.
@ -116,7 +120,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, ctrlc_handlers)?;
self.clone().spawn(&envs, &mut mutable)?;
}
Ok(mutable
@ -135,7 +139,6 @@ impl PersistentPlugin {
self: Arc<Self>,
envs: &HashMap<String, String>,
mutable: &mut MutableState,
ctrlc_handlers: Option<ctrlc::Handlers>,
) -> Result<(), ShellError> {
// Make sure `running` is set to None to begin
if let Some(running) = mutable.running.take() {
@ -214,10 +217,12 @@ impl PersistentPlugin {
gc.stop_tracking();
// Set the mode and try again
mutable.preferred_mode = Some(PreferredCommunicationMode::LocalSocket);
return self.spawn(envs, mutable, ctrlc_handlers);
return self.spawn(envs, mutable);
}
let guard = ctrlc_handlers
let guard = mutable
.ctrlc_handlers
.as_mut()
.map(|ctrlc_handlers| {
let interface = interface.clone();
ctrlc_handlers.register(Box::new(move || {
@ -229,7 +234,7 @@ impl PersistentPlugin {
mutable.running = Some(RunningPlugin {
interface,
gc,
_ctrlc_guard: guard,
_ctrlc_guard: guard.clone(),
});
Ok(())
}
@ -335,26 +340,20 @@ impl GetPlugin for PersistentPlugin {
self: Arc<Self>,
mut context: Option<(&EngineState, &mut Stack)>,
) -> Result<PluginInterface, ShellError> {
let ctrlc_handlers = context
.as_ref()
.and_then(|(engine_state, _)| engine_state.ctrlc_handlers.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()?;
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())
},
ctrlc_handlers,
)
Ok(envs.unwrap_or_default())
})
}
}

View File

@ -11,6 +11,14 @@ pub struct Handlers {
next_id: Arc<Sequence>,
}
impl Debug for Handlers {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Handlers")
.field("next_id", &self.next_id)
.finish()
}
}
#[derive(Clone)]
pub struct Guard {
id: usize,