refactor: Use strum for filter plugin type determination

Co-authored-by: aider (openai/andrew/openrouter/deepseek/deepseek-chat-v3.1) <aider@aider.chat>
This commit is contained in:
Andrew Phillips
2025-09-02 17:26:55 -03:00
parent 21b8267dcb
commit 9b7751fa50
2 changed files with 73 additions and 28 deletions

View File

@@ -51,7 +51,6 @@ sha2 = "0.10.0"
md5 = "0.7.0"
stderrlog = "0.6.0"
strum = { version = "0.27.2", features = ["derive"] }
strum_macros = "0.27.2"
term = "1.1.0"
termsize = "0.1.9"
tokio = { version = "1.0", features = ["full"] }

View File

@@ -1,4 +1,6 @@
use std::io::{Result, Read, Write};
use std::str::FromStr;
use strum::{EnumString, EnumVariantNames};
pub mod head;
pub mod tail;
@@ -11,6 +13,19 @@ pub trait FilterPlugin: Send {
fn filter(&mut self, reader: Box<&mut dyn Read>, writer: Box<&mut dyn Write>) -> Result<()>;
}
#[derive(Debug, EnumString, EnumVariantNames)]
#[strum(serialize_all = "snake_case")]
enum FilterType {
HeadBytes,
HeadLines,
TailBytes,
TailLines,
SkipBytes,
SkipLines,
Grep,
StripAnsi,
}
pub struct FilterChain {
plugins: Vec<Box<dyn FilterPlugin>>,
}
@@ -72,39 +87,70 @@ pub fn parse_filter_string(filter_str: &str) -> Result<FilterChain> {
continue;
}
// Define a macro to reduce duplication in filter parsing
macro_rules! parse_filter {
($prefix:expr, $suffix:expr, $constructor:expr) => {{
if let Some(stripped) = part.strip_prefix($prefix).and_then(|s| s.strip_suffix($suffix)) {
let count = utils::parse_number(stripped)?;
chain.add_plugin(Box::new($constructor(count)));
// Parse the filter type
if let Ok(filter_type) = FilterType::from_str(part) {
match filter_type {
FilterType::StripAnsi => {
chain.add_plugin(Box::new(strip_ansi::StripAnsiFilter::new()));
continue;
}
}};
_ => {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
format!("Filter '{}' requires parameters", part)
));
}
}
}
// Handle strip_ansi filter
if part == "strip_ansi" {
chain.add_plugin(Box::new(strip_ansi::StripAnsiFilter::new()));
continue;
// Handle filters with parameters
// Extract the filter name and parameters
if let Some((filter_name, params)) = part.split_once('(') {
if let Some(params) = params.strip_suffix(')') {
if let Ok(filter_type) = FilterType::from_str(filter_name) {
match filter_type {
FilterType::Grep => {
// Remove quotes if present
let pattern = params.trim_matches(|c| c == '\'' || c == '"');
chain.add_plugin(Box::new(grep::GrepFilter::new(pattern.to_string())?));
}
FilterType::HeadBytes => {
let count = utils::parse_number(params)?;
chain.add_plugin(Box::new(head::HeadBytesFilter::new(count)));
}
FilterType::HeadLines => {
let count = utils::parse_number(params)?;
chain.add_plugin(Box::new(head::HeadLinesFilter::new(count)));
}
FilterType::TailBytes => {
let count = utils::parse_number(params)?;
chain.add_plugin(Box::new(tail::TailBytesFilter::new(count)));
}
FilterType::TailLines => {
let count = utils::parse_number(params)?;
chain.add_plugin(Box::new(tail::TailLinesFilter::new(count)));
}
FilterType::SkipBytes => {
let count = utils::parse_number(params)?;
chain.add_plugin(Box::new(skip::SkipBytesFilter::new(count)));
}
FilterType::SkipLines => {
let count = utils::parse_number(params)?;
chain.add_plugin(Box::new(skip::SkipLinesFilter::new(count)));
}
FilterType::StripAnsi => {
// This should not happen as strip_ansi doesn't take parameters
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"strip_ansi filter doesn't take parameters"
));
}
}
continue;
}
}
}
// Handle grep filter
if let Some(stripped) = part.strip_prefix("grep(").and_then(|s| s.strip_suffix(')')) {
// Remove quotes if present
let pattern = stripped.trim_matches(|c| c == '\'' || c == '"');
chain.add_plugin(Box::new(grep::GrepFilter::new(pattern.to_string())?));
continue;
}
// Handle other filters using the macro
parse_filter!("head_bytes(", ")", head::HeadBytesFilter::new);
parse_filter!("head_lines(", ")", head::HeadLinesFilter::new);
parse_filter!("tail_bytes(", ")", tail::TailBytesFilter::new);
parse_filter!("tail_lines(", ")", tail::TailLinesFilter::new);
parse_filter!("skip_bytes(", ")", skip::SkipBytesFilter::new);
parse_filter!("skip_lines(", ")", skip::SkipLinesFilter::new);
// If we get here, the filter wasn't recognized
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,