logviewer/src/tui/filter.rs

97 lines
2.8 KiB
Rust

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<String>) -> Option<Self> {
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<Self> {
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),
}
}
}