Files
keep/src/meta_plugin/shell.rs
Andrew Phillips 2a4a7d46c4 docs: Add comprehensive Rustdoc for shell meta plugin
Co-authored-by: aider (openai/andrew/openrouter/sonoma-sky-alpha) <aider@aider.chat>
2025-09-10 15:31:53 -03:00

249 lines
7.6 KiB
Rust

use std::env;
use crate::meta_plugin::{MetaPlugin, MetaPluginType};
#[derive(Debug, Clone, Default)]
/// Meta plugin for capturing shell environment information.
///
/// This plugin retrieves the current shell from the SHELL environment variable
/// and provides it as metadata. It runs once during initialization and does not
/// process input data.
pub struct ShellMetaPlugin {
is_finalized: bool,
outputs: std::collections::HashMap<String, serde_yaml::Value>,
options: std::collections::HashMap<String, serde_yaml::Value>,
}
impl ShellMetaPlugin {
/// Creates a new ShellMetaPlugin instance.
///
/// Initializes with default outputs and options, overridden by provided values.
/// Defaults to "shell" as the output key.
///
/// # Arguments
///
/// * `_options` - Optional configuration options (unused currently).
/// * `outputs` - Optional output mappings to override defaults.
///
/// # Returns
///
/// * `ShellMetaPlugin` - A new instance with processed options and outputs.
///
/// # Examples
///
/// ```
/// let plugin = ShellMetaPlugin::new(None, None);
/// ```
pub fn new(
_options: Option<std::collections::HashMap<String, serde_yaml::Value>>,
outputs: Option<std::collections::HashMap<String, serde_yaml::Value>>,
) -> ShellMetaPlugin {
// Start with default options
let mut final_options = std::collections::HashMap::new();
if let Some(opts) = _options {
for (key, value) in opts {
final_options.insert(key, value);
}
}
// Start with default outputs
let mut final_outputs = std::collections::HashMap::new();
let default_outputs = Self::default().default_outputs();
for output_name in default_outputs {
final_outputs.insert(output_name.clone(), serde_yaml::Value::String(output_name));
}
if let Some(outs) = outputs {
for (key, value) in outs {
final_outputs.insert(key, value);
}
}
ShellMetaPlugin {
is_finalized: false,
outputs: final_outputs,
options: final_options,
}
}
}
impl MetaPlugin for ShellMetaPlugin {
/// Checks if the plugin has been finalized.
///
/// # Returns
///
/// * `bool` - True if finalized, false otherwise.
fn is_finalized(&self) -> bool {
self.is_finalized
}
/// Sets the finalized state of the plugin.
///
/// # Arguments
///
/// * `finalized` - The new finalized state.
fn set_finalized(&mut self, finalized: bool) {
self.is_finalized = finalized;
}
/// Finalizes the plugin without processing data.
///
/// For this plugin, finalization is handled in `initialize`, so this returns empty metadata.
///
/// # Returns
///
/// * `MetaPluginResponse` - Response with no metadata and finalized state.
fn finalize(&mut self) -> crate::meta_plugin::MetaPluginResponse {
// If already finalized, don't process again
if self.is_finalized {
return crate::meta_plugin::MetaPluginResponse {
metadata: Vec::new(),
is_finalized: true,
};
}
// Mark as finalized
self.is_finalized = true;
crate::meta_plugin::MetaPluginResponse {
metadata: Vec::new(),
is_finalized: true,
}
}
/// Updates the plugin with data (not used for shell).
///
/// Shell plugin doesn't process data streams; returns empty response unless not finalized.
///
/// # Arguments
///
/// * `_data` - Byte slice of input data (ignored).
///
/// # Returns
///
/// * `MetaPluginResponse` - Empty metadata response.
fn update(&mut self, _data: &[u8]) -> crate::meta_plugin::MetaPluginResponse {
// If already finalized, don't process more data
if self.is_finalized {
return crate::meta_plugin::MetaPluginResponse {
metadata: Vec::new(),
is_finalized: true,
};
}
crate::meta_plugin::MetaPluginResponse {
metadata: Vec::new(),
is_finalized: false,
}
}
/// Returns the type of this meta plugin.
///
/// # Returns
///
/// * `MetaPluginType::Shell` - The shell plugin type.
fn meta_type(&self) -> MetaPluginType {
MetaPluginType::Shell
}
/// Initializes the plugin and extracts shell metadata.
///
/// Retrieves the SHELL environment variable and adds it to metadata.
/// Marks the plugin as finalized after one run.
///
/// # Returns
///
/// * `MetaPluginResponse` - Response with shell metadata and finalized state.
///
/// # Examples
///
/// ```
/// let mut plugin = ShellMetaPlugin::new(None, None);
/// let response = plugin.initialize();
/// assert!(response.is_finalized);
/// ```
fn initialize(&mut self) -> crate::meta_plugin::MetaPluginResponse {
// If already finalized, don't process again
if self.is_finalized {
return crate::meta_plugin::MetaPluginResponse {
metadata: Vec::new(),
is_finalized: true,
};
}
let mut metadata = Vec::new();
let shell = match env::var("SHELL") {
Ok(shell) => shell,
Err(_) => "unknown".to_string(),
};
// Use process_metadata_outputs to handle output mapping
if let Some(meta_data) = crate::meta_plugin::process_metadata_outputs(
"shell",
serde_yaml::Value::String(shell),
&self.outputs
) {
metadata.push(meta_data);
}
// Mark as finalized since this plugin only needs to run once
self.is_finalized = true;
crate::meta_plugin::MetaPluginResponse {
metadata,
is_finalized: true,
}
}
/// Returns a reference to the plugin's outputs.
///
/// # Returns
///
/// * `&HashMap<String, serde_yaml::Value>` - The outputs map.
fn outputs(&self) -> &std::collections::HashMap<String, serde_yaml::Value> {
&self.outputs
}
/// Returns a mutable reference to the plugin's outputs.
///
/// # Returns
///
/// * `&mut HashMap<String, serde_yaml::Value>` - Mutable outputs map.
fn outputs_mut(&mut self) -> &mut std::collections::HashMap<String, serde_yaml::Value> {
&mut self.outputs
}
/// Returns a reference to the plugin's options.
///
/// # Returns
///
/// * `&HashMap<String, serde_yaml::Value>` - The options map.
fn options(&self) -> &std::collections::HashMap<String, serde_yaml::Value> {
&self.options
}
/// Returns a mutable reference to the plugin's options.
///
/// # Returns
///
/// * `&mut HashMap<String, serde_yaml::Value>` - Mutable options map.
fn options_mut(&mut self) -> &mut std::collections::HashMap<String, serde_yaml::Value> {
&mut self.options
}
}
/// Registers the shell meta plugin with the global registry.
///
/// This constructor function is called at module load time using ctor crate.
/// It creates the plugin with provided options and outputs.
use crate::meta_plugin::register_meta_plugin;
// Register the plugin at module initialization time
#[ctor::ctor]
fn register_shell_plugin() {
register_meta_plugin(MetaPluginType::Shell, |options, outputs| {
Box::new(ShellMetaPlugin::new(options, outputs))
});
}