diff --git a/src/filter_plugin/mod.rs b/src/filter_plugin/mod.rs index 9100642..818534b 100644 --- a/src/filter_plugin/mod.rs +++ b/src/filter_plugin/mod.rs @@ -25,9 +25,9 @@ pub trait FilterPlugin: Send { fn options(&self) -> Vec; } -#[derive(Debug, EnumString, strum::VariantNames)] +#[derive(Debug, EnumString, strum::VariantNames, strum::Display)] #[strum(serialize_all = "snake_case")] -enum FilterType { +pub enum FilterType { HeadBytes, HeadLines, TailBytes, @@ -143,35 +143,7 @@ pub fn parse_filter_string(filter_str: &str) -> Result { // Create the appropriate filter plugin if let Ok(filter_type) = FilterType::from_str(filter_name) { - let plugin = match filter_type { - FilterType::Grep => { - create_filter_with_options::(&unnamed_params, &options)? - } - FilterType::HeadBytes => { - create_filter_with_options::(&unnamed_params, &options)? - } - FilterType::HeadLines => { - create_filter_with_options::(&unnamed_params, &options)? - } - FilterType::TailBytes => { - create_filter_with_options::(&unnamed_params, &options)? - } - FilterType::TailLines => { - create_filter_with_options::(&unnamed_params, &options)? - } - FilterType::SkipBytes => { - create_filter_with_options::(&unnamed_params, &options)? - } - FilterType::SkipLines => { - create_filter_with_options::(&unnamed_params, &options)? - } - FilterType::StripAnsi => { - return Err(std::io::Error::new( - std::io::ErrorKind::InvalidInput, - "strip_ansi filter doesn't take parameters" - )); - } - }; + let plugin = create_filter_with_options(filter_type, &unnamed_params, &options)?; chain.add_plugin(plugin); continue; } @@ -205,12 +177,23 @@ pub fn parse_filter_string(filter_str: &str) -> Result { } // Helper function to create filter with proper option handling -fn create_filter_with_options( +fn create_filter_with_options( + filter_type: FilterType, unnamed_params: &[serde_json::Value], named_options: &HashMap, ) -> Result> { - let mut plugin = T::default(); - let option_defs = plugin.options(); + // Get the default options for this filter type by creating a temporary instance + // To do this, we need to create a default instance of the appropriate filter + let option_defs = match filter_type { + FilterType::Grep => grep::GrepFilter::new("".to_string())?.options(), + FilterType::HeadBytes => head::HeadBytesFilter::new(0).options(), + FilterType::HeadLines => head::HeadLinesFilter::new(0).options(), + FilterType::TailBytes => tail::TailBytesFilter::new(0).options(), + FilterType::TailLines => tail::TailLinesFilter::new(0).options(), + FilterType::SkipBytes => skip::SkipBytesFilter::new(0).options(), + FilterType::SkipLines => skip::SkipLinesFilter::new(0).options(), + FilterType::StripAnsi => strip_ansi::StripAnsiFilter::new().options(), + }; let mut options = HashMap::new(); @@ -257,23 +240,95 @@ fn create_filter_with_options( } // Create the specific filter with the processed options - // This part needs to be implemented for each filter type - // For now, we'll use a match on the type name - // Note: This is a placeholder - you'll need to implement proper constructors for each filter - Ok(create_specific_filter::(&options)?) + create_specific_filter(filter_type, &options) } // Helper to create specific filter instances based on options -fn create_specific_filter( +fn create_specific_filter( + filter_type: FilterType, options: &HashMap, ) -> Result> { - // This is a simplified implementation - // In practice, you'd need to handle each filter type specifically - let mut plugin = T::default(); - - // For now, just return the default plugin - // You'll need to implement proper initialization based on options - Ok(Box::new(plugin)) + match filter_type { + FilterType::Grep => { + let pattern = options.get("pattern") + .and_then(|v| v.as_str()) + .ok_or_else(|| std::io::Error::new( + std::io::ErrorKind::InvalidInput, + "grep filter requires 'pattern' parameter" + ))?; + grep::GrepFilter::new(pattern.to_string()).map(|f| Box::new(f) as Box) + } + FilterType::HeadBytes => { + let count = options.get("count") + .and_then(|v| v.as_u64()) + .map(|n| n as usize) + .ok_or_else(|| std::io::Error::new( + std::io::ErrorKind::InvalidInput, + "head_bytes filter requires 'count' parameter" + ))?; + Ok(Box::new(head::HeadBytesFilter::new(count))) + } + FilterType::HeadLines => { + let count = options.get("count") + .and_then(|v| v.as_u64()) + .map(|n| n as usize) + .ok_or_else(|| std::io::Error::new( + std::io::ErrorKind::InvalidInput, + "head_lines filter requires 'count' parameter" + ))?; + Ok(Box::new(head::HeadLinesFilter::new(count))) + } + FilterType::TailBytes => { + let count = options.get("count") + .and_then(|v| v.as_u64()) + .map(|n| n as usize) + .ok_or_else(|| std::io::Error::new( + std::io::ErrorKind::InvalidInput, + "tail_bytes filter requires 'count' parameter" + ))?; + Ok(Box::new(tail::TailBytesFilter::new(count))) + } + FilterType::TailLines => { + let count = options.get("count") + .and_then(|v| v.as_u64()) + .map(|n| n as usize) + .ok_or_else(|| std::io::Error::new( + std::io::ErrorKind::InvalidInput, + "tail_lines filter requires 'count' parameter" + ))?; + Ok(Box::new(tail::TailLinesFilter::new(count))) + } + FilterType::SkipBytes => { + let count = options.get("count") + .and_then(|v| v.as_u64()) + .map(|n| n as usize) + .ok_or_else(|| std::io::Error::new( + std::io::ErrorKind::InvalidInput, + "skip_bytes filter requires 'count' parameter" + ))?; + Ok(Box::new(skip::SkipBytesFilter::new(count))) + } + FilterType::SkipLines => { + let count = options.get("count") + .and_then(|v| v.as_u64()) + .map(|n| n as usize) + .ok_or_else(|| std::io::Error::new( + std::io::ErrorKind::InvalidInput, + "skip_lines filter requires 'count' parameter" + ))?; + Ok(Box::new(skip::SkipLinesFilter::new(count))) + } + FilterType::StripAnsi => { + // StripAnsi doesn't take any parameters + if !options.is_empty() { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidInput, + "strip_ansi filter doesn't take parameters" + )); + } + Ok(Box::new(strip_ansi::StripAnsiFilter::new())) + } + } } // Helper function to parse option values