feat: Add --filters option to --get and parse filters early
Co-authored-by: aider (openai/andrew/openrouter/deepseek/deepseek-chat-v3.1) <aider@aider.chat>
This commit is contained in:
@@ -90,6 +90,10 @@ pub struct ItemArgs {
|
|||||||
#[arg(help_heading("Item Options"), short('M'), long, env("KEEP_META_PLUGINS"))]
|
#[arg(help_heading("Item Options"), short('M'), long, env("KEEP_META_PLUGINS"))]
|
||||||
#[arg(help("Meta plugins to use when saving items"))]
|
#[arg(help("Meta plugins to use when saving items"))]
|
||||||
pub meta_plugins: Vec<String>,
|
pub meta_plugins: Vec<String>,
|
||||||
|
|
||||||
|
#[arg(help_heading("Item Options"), long, env("KEEP_FILTERS"))]
|
||||||
|
#[arg(help("Filter string to apply to content when getting items"))]
|
||||||
|
pub filters: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
18
src/main.rs
18
src/main.rs
@@ -176,12 +176,24 @@ fn main() -> Result<(), Error> {
|
|||||||
// Initialize database
|
// Initialize database
|
||||||
let mut conn = db::open(db_path.clone())?;
|
let mut conn = db::open(db_path.clone())?;
|
||||||
|
|
||||||
// Create an empty filters vector for the get mode
|
// Parse filter chain early for better error reporting
|
||||||
let filters: Vec<String> = Vec::new();
|
let filter_chain = if let Some(filter_str) = &args.item.filters {
|
||||||
|
match keep::filter_plugin::parse_filter_string(filter_str) {
|
||||||
|
Ok(chain) => Some(chain),
|
||||||
|
Err(e) => {
|
||||||
|
cmd.error(
|
||||||
|
ErrorKind::InvalidValue,
|
||||||
|
format!("Invalid filter string: {}", e)
|
||||||
|
).exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
match mode {
|
match mode {
|
||||||
KeepModes::Save => modes::save::mode_save(&mut cmd, &settings, ids, tags, &mut conn, data_path),
|
KeepModes::Save => modes::save::mode_save(&mut cmd, &settings, ids, tags, &mut conn, data_path),
|
||||||
KeepModes::Get => modes::get::mode_get(&mut cmd, &settings, ids, tags, &mut conn, data_path, &filters),
|
KeepModes::Get => modes::get::mode_get(&mut cmd, &settings, ids, tags, &mut conn, data_path, filter_chain),
|
||||||
KeepModes::Diff => modes::diff::mode_diff(&mut cmd, &settings, &settings, ids, tags, &mut conn, data_path),
|
KeepModes::Diff => modes::diff::mode_diff(&mut cmd, &settings, &settings, ids, tags, &mut conn, data_path),
|
||||||
KeepModes::List => modes::list::mode_list(&mut cmd, &settings, ids, tags, &mut conn, data_path),
|
KeepModes::List => modes::list::mode_list(&mut cmd, &settings, ids, tags, &mut conn, data_path),
|
||||||
KeepModes::Delete => modes::delete::mode_delete(&mut cmd, &settings, &settings, ids, tags, &mut conn, data_path),
|
KeepModes::Delete => modes::delete::mode_delete(&mut cmd, &settings, &settings, ids, tags, &mut conn, data_path),
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ use std::io::Write;
|
|||||||
use crate::common::is_binary::is_binary;
|
use crate::common::is_binary::is_binary;
|
||||||
use crate::common::PIPESIZE;
|
use crate::common::PIPESIZE;
|
||||||
use crate::config;
|
use crate::config;
|
||||||
|
use crate::filter_plugin::FilterChain;
|
||||||
use crate::services::item_service::ItemService;
|
use crate::services::item_service::ItemService;
|
||||||
use clap::Command;
|
use clap::Command;
|
||||||
use is_terminal::IsTerminal;
|
use is_terminal::IsTerminal;
|
||||||
@@ -17,7 +18,7 @@ pub fn mode_get(
|
|||||||
tags: &mut Vec<String>,
|
tags: &mut Vec<String>,
|
||||||
conn: &mut rusqlite::Connection,
|
conn: &mut rusqlite::Connection,
|
||||||
data_path: PathBuf,
|
data_path: PathBuf,
|
||||||
filters: &Vec<String>,
|
filter_chain: Option<FilterChain>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
if !ids.is_empty() && !tags.is_empty() {
|
if !ids.is_empty() && !tags.is_empty() {
|
||||||
cmd.error(clap::error::ErrorKind::InvalidValue, "Both ID and tags given, you must supply either IDs or tags when using --get").exit();
|
cmd.error(clap::error::ErrorKind::InvalidValue, "Both ID and tags given, you must supply either IDs or tags when using --get").exit();
|
||||||
@@ -48,18 +49,11 @@ pub fn mode_get(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Join all filter strings with | to create a single filter string
|
// Get a reader that applies the filters using the pre-parsed filter chain
|
||||||
let filter_str = if filters.is_empty() {
|
let (mut reader, _, _) = item_service.get_item_content_info_streaming_with_chain(
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(filters.join(" | "))
|
|
||||||
};
|
|
||||||
|
|
||||||
// Get a reader that applies the filters
|
|
||||||
let (mut reader, _, _) = item_service.get_item_content_info_streaming(
|
|
||||||
conn,
|
conn,
|
||||||
item_id,
|
item_id,
|
||||||
filter_str.clone(),
|
filter_chain,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
if detect_binary {
|
if detect_binary {
|
||||||
@@ -72,10 +66,10 @@ pub fn mode_get(
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
// We need to create a new reader since we consumed some bytes
|
// We need to create a new reader since we consumed some bytes
|
||||||
let (new_reader, _, _) = item_service.get_item_content_info_streaming(
|
let (new_reader, _, _) = item_service.get_item_content_info_streaming_with_chain(
|
||||||
conn,
|
conn,
|
||||||
item_id,
|
item_id,
|
||||||
filter_str.clone(),
|
filter_chain,
|
||||||
)?;
|
)?;
|
||||||
reader = new_reader;
|
reader = new_reader;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -181,6 +181,23 @@ impl ItemService {
|
|||||||
conn: &Connection,
|
conn: &Connection,
|
||||||
id: i64,
|
id: i64,
|
||||||
filter: Option<String>,
|
filter: Option<String>,
|
||||||
|
) -> Result<(Box<dyn Read + Send>, String, bool), CoreError> {
|
||||||
|
// Convert filter string to FilterChain if provided
|
||||||
|
let filter_chain = if let Some(filter_str) = filter {
|
||||||
|
self.filter_service.create_filter_chain(Some(&filter_str))
|
||||||
|
.map_err(|e| CoreError::InvalidInput(format!("Failed to create filter chain: {}", e)))?
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
self.get_item_content_info_streaming_with_chain(conn, id, filter_chain)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_item_content_info_streaming_with_chain(
|
||||||
|
&self,
|
||||||
|
conn: &Connection,
|
||||||
|
id: i64,
|
||||||
|
filter_chain: Option<filter_plugin::FilterChain>,
|
||||||
) -> Result<(Box<dyn Read + Send>, String, bool), CoreError> {
|
) -> Result<(Box<dyn Read + Send>, String, bool), CoreError> {
|
||||||
let item_with_meta = self.get_item(conn, id)?;
|
let item_with_meta = self.get_item(conn, id)?;
|
||||||
let item_id = item_with_meta.item.id.ok_or_else(|| CoreError::InvalidInput("Item missing ID".to_string()))?;
|
let item_id = item_with_meta.item.id.ok_or_else(|| CoreError::InvalidInput("Item missing ID".to_string()))?;
|
||||||
@@ -197,10 +214,6 @@ impl ItemService {
|
|||||||
&item_with_meta.item.compression
|
&item_with_meta.item.compression
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Create filter chain
|
|
||||||
let filter_chain = self.filter_service.create_filter_chain(filter.as_deref())
|
|
||||||
.map_err(|e| CoreError::InvalidInput(format!("Failed to create filter chain: {}", e)))?;
|
|
||||||
|
|
||||||
// Wrap the reader with filtering
|
// Wrap the reader with filtering
|
||||||
let filtered_reader = Box::new(FilteringReader::new(reader, filter_chain));
|
let filtered_reader = Box::new(FilteringReader::new(reader, filter_chain));
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user