use regex::bytes::Regex; use crate::tui::{ log_viewer::{FieldMatcher, InputTarget, LogViewer}, model::{LogEntry, pretty_print_value}, }; pub enum MatcherValue { Exact(String), Regex(Regex), Prefix(String), Contains(String), } impl MatcherValue { pub fn from_field_matcher(fm: FieldMatcher, selected: Option) -> Option { match fm { FieldMatcher::EqualTo => Some(Self::Exact(selected?)), FieldMatcher::Prefix(p) => Some(Self::Prefix(p)), FieldMatcher::Regex(r) => Some(Self::Regex(Regex::new(&r).ok()?)), FieldMatcher::Contains(c) => Some(Self::Contains(c)), } } pub fn matches(&self, v: &str) -> bool { match self { MatcherValue::Exact(e) => e == v, MatcherValue::Regex(regex) => regex.is_match(v.as_bytes()), MatcherValue::Prefix(p) => v.starts_with(p), MatcherValue::Contains(c) => v.contains(c), } } } pub enum Matcher { Field { name: String, value: MatcherValue }, Message { value: MatcherValue }, Specific { hash: u64 }, } impl Matcher { pub fn matches(&self, entry: &LogEntry) -> bool { match self { Matcher::Specific { hash } => entry.hash() == *hash, Matcher::Field { name, value } => entry .all_fields() .fields .get(name) .is_some_and(|v| value.matches(v)), Matcher::Message { value } => { entry.message_or_name().is_some_and(|v| value.matches(&v)) } } } pub fn from_input(target: InputTarget, lv: &LogViewer) -> Option { match target { InputTarget::Fields(fm) => { let value = lv.footer_fields().get(lv.footer_list.selected?)?.clone(); Some(Self::Field { name: value.0, value: MatcherValue::from_field_matcher(fm?, Some(value.1))?, }) } InputTarget::Text(fm) => Some(Self::Message { value: MatcherValue::from_field_matcher( fm, lv.selected().and_then(|(i, _)| i.message_or_name()), )?, }), InputTarget::This => lv .selected() .map(|(i, _)| Self::Specific { hash: i.hash() }), InputTarget::Surround => todo!(), } } } #[derive(Clone)] pub enum FilterKind { Inline, Remove, } pub struct Filter { pub matcher: Matcher, pub kind: FilterKind, } impl Filter { pub fn removes(&self, elem: &LogEntry) -> bool { match self.kind { FilterKind::Inline => false, FilterKind::Remove => self.matcher.matches(elem), } } }