mirror of
https://codeberg.org/icewind/logsmash.git
synced 2026-06-03 18:14:11 +02:00
case insentive filtering
This commit is contained in:
parent
a0624c4493
commit
831ae1a9e8
7 changed files with 91 additions and 24 deletions
74
src/app.rs
74
src/app.rs
|
|
@ -3,7 +3,9 @@ use crate::logline::LogLine;
|
|||
use crate::matcher::MatchResult;
|
||||
use crate::timegraph::TimeGraph;
|
||||
use logsmash_data::{LoggingStatementWithPathPrefix, StatementList};
|
||||
use regex::{escape, Regex, RegexBuilder};
|
||||
use std::collections::BTreeMap;
|
||||
use std::fmt::Display;
|
||||
|
||||
pub struct App<'a> {
|
||||
pub lines: Vec<LogLine<'a>>,
|
||||
|
|
@ -73,12 +75,12 @@ impl LogMatch {
|
|||
.filter_map(|index| app.log_statements.get(index))
|
||||
}
|
||||
|
||||
pub fn matches(&self, app: &App, filter: &str) -> bool {
|
||||
pub fn matches(&self, app: &App, filter: &Filter) -> bool {
|
||||
if filter.is_empty() {
|
||||
return true;
|
||||
}
|
||||
self.statements(app)
|
||||
.any(|statement| statement.pattern.contains(filter))
|
||||
.any(|statement| filter.matches(statement.pattern))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -130,11 +132,75 @@ impl GroupedLines {
|
|||
self.lines.len()
|
||||
}
|
||||
|
||||
pub fn matches(&self, app: &App, filter: &str) -> bool {
|
||||
pub fn matches(&self, app: &App, filter: &Filter) -> bool {
|
||||
if filter.is_empty() {
|
||||
return true;
|
||||
}
|
||||
let line = &app.lines[self.lines[0]];
|
||||
line.message.contains(filter)
|
||||
filter.matches(&line.message)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub struct Filter {
|
||||
filter: String,
|
||||
regex: Option<Regex>,
|
||||
}
|
||||
|
||||
pub static EMPTY_FILTER: Filter = Filter {
|
||||
filter: String::new(),
|
||||
regex: None,
|
||||
};
|
||||
|
||||
impl Filter {
|
||||
fn build_regex(filter: &str) -> Option<Regex> {
|
||||
if filter.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(
|
||||
RegexBuilder::new(&escape(&filter))
|
||||
.case_insensitive(true)
|
||||
.build()
|
||||
.unwrap(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn new(filter: String) -> Self {
|
||||
let regex = Self::build_regex(&filter);
|
||||
Filter { filter, regex }
|
||||
}
|
||||
|
||||
pub fn matches(&self, string: &str) -> bool {
|
||||
match &self.regex {
|
||||
Some(regex) => regex.is_match(string),
|
||||
None => true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.filter.is_empty()
|
||||
}
|
||||
|
||||
pub fn push(&mut self, c: char) {
|
||||
self.filter.push(c);
|
||||
self.regex = Self::build_regex(&self.filter);
|
||||
}
|
||||
|
||||
pub fn pop(&mut self) {
|
||||
self.filter.pop();
|
||||
self.regex = Self::build_regex(&self.filter);
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.filter.clear();
|
||||
self.regex = None;
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Filter {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.filter)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use crate::app::Filter;
|
||||
use ahash::AHasher;
|
||||
use logsmash_data::LogLevel;
|
||||
use serde::Deserialize;
|
||||
|
|
@ -126,12 +127,12 @@ impl<'a> LogLine<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn matches(&self, filter: &str) -> bool {
|
||||
pub fn matches(&self, filter: &Filter) -> bool {
|
||||
if filter.is_empty() {
|
||||
return true;
|
||||
}
|
||||
// todo: reqid, more?
|
||||
self.app.contains(filter) || self.message.contains(filter)
|
||||
filter.matches(&self.app) || filter.matches(&self.message)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::app::App;
|
||||
use crate::app::{App, Filter};
|
||||
use crate::ui::state::UiPage;
|
||||
use ratatui::layout::Constraint;
|
||||
use ratatui::prelude::Style;
|
||||
|
|
@ -8,7 +8,7 @@ use ratatui::widgets::{Row, Table};
|
|||
|
||||
pub enum FooterParams<'a> {
|
||||
Normal { page: UiPage },
|
||||
FilterInput { page: UiPage, filter: &'a str },
|
||||
FilterInput { page: UiPage, filter: &'a Filter },
|
||||
}
|
||||
|
||||
pub fn footer<'a>(app: &App<'a>, params: FooterParams<'a>) -> Table<'a> {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::app::{App, LogMatch};
|
||||
use crate::app::{App, Filter, LogMatch};
|
||||
use crate::ui::style::TABLE_HEADER_STYLE;
|
||||
use crate::ui::table::ScrollbarTable;
|
||||
use itertools::Either;
|
||||
|
|
@ -7,7 +7,7 @@ use ratatui::widgets::{Cell, Row};
|
|||
use std::fmt::Write;
|
||||
use std::iter::{empty, once};
|
||||
|
||||
pub fn match_list<'a>(app: &'a App<'a>, filter: &str) -> ScrollbarTable<'a> {
|
||||
pub fn match_list<'a>(app: &'a App<'a>, filter: &Filter) -> ScrollbarTable<'a> {
|
||||
let header = [
|
||||
Text::from("Statement"),
|
||||
Text::from("File"),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::app::App;
|
||||
use crate::app::{App, Filter};
|
||||
use crate::logline::{format_time, LogLine};
|
||||
use crate::ui::style::TABLE_HEADER_STYLE;
|
||||
use crate::ui::table::ScrollbarTable;
|
||||
|
|
@ -6,7 +6,7 @@ use ratatui::layout::{Alignment, Constraint};
|
|||
use ratatui::text::Text;
|
||||
use ratatui::widgets::{Cell, Row};
|
||||
|
||||
pub fn raw_logs<'a>(app: &'a App<'a>, lines: &[usize], filter: &str) -> ScrollbarTable<'a> {
|
||||
pub fn raw_logs<'a>(app: &'a App<'a>, lines: &[usize], filter: &Filter) -> ScrollbarTable<'a> {
|
||||
let lines = lines.iter().copied().map(|i| &app.lines[i]);
|
||||
let header = [
|
||||
Text::from("Level"),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::app::{App, GroupedLines, LogMatch};
|
||||
use crate::app::{App, Filter, GroupedLines, LogMatch};
|
||||
use crate::ui::style::TABLE_HEADER_STYLE;
|
||||
use crate::ui::table::ScrollbarTable;
|
||||
use ratatui::layout::Constraint;
|
||||
|
|
@ -8,7 +8,7 @@ use ratatui::widgets::{Cell, Row};
|
|||
pub fn grouped_lines<'a>(
|
||||
app: &'a App<'a>,
|
||||
log_match: &'a LogMatch,
|
||||
filter: &str,
|
||||
filter: &Filter,
|
||||
) -> ScrollbarTable<'a> {
|
||||
let grouped = &log_match.grouped;
|
||||
let header = [
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::app::{App, LogMatch};
|
||||
use crate::app::{App, Filter, LogMatch, EMPTY_FILTER};
|
||||
use crate::logline::{FullLogLine, LogLine};
|
||||
use crate::ui::footer::FooterParams;
|
||||
use crate::ui::table::ScrollbarTableState;
|
||||
|
|
@ -28,7 +28,7 @@ pub enum Mode {
|
|||
pub struct MatchListState<'a> {
|
||||
app: &'a App<'a>,
|
||||
pub table_state: ScrollbarTableState,
|
||||
pub filter: String,
|
||||
pub filter: Filter,
|
||||
mode: Mode,
|
||||
}
|
||||
|
||||
|
|
@ -58,7 +58,7 @@ impl<'a> MatchListState<'a> {
|
|||
result,
|
||||
table_state,
|
||||
previous: Box::new(self.into()),
|
||||
filter: String::new(),
|
||||
filter: Filter::default(),
|
||||
mode: Mode::Normal,
|
||||
})
|
||||
}
|
||||
|
|
@ -75,7 +75,7 @@ pub struct MatchState<'a> {
|
|||
pub result: &'a LogMatch,
|
||||
pub table_state: ScrollbarTableState,
|
||||
pub previous: Box<UiState<'a>>,
|
||||
pub filter: String,
|
||||
pub filter: Filter,
|
||||
mode: Mode,
|
||||
}
|
||||
|
||||
|
|
@ -104,7 +104,7 @@ impl<'a> MatchState<'a> {
|
|||
lines,
|
||||
table_state,
|
||||
previous: Box::new(self.into()),
|
||||
filter: String::new(),
|
||||
filter: Filter::default(),
|
||||
mode: Mode::Normal,
|
||||
})
|
||||
}
|
||||
|
|
@ -121,7 +121,7 @@ pub struct LogsState<'a> {
|
|||
pub lines: &'a [usize],
|
||||
pub table_state: ScrollbarTableState,
|
||||
pub previous: Box<UiState<'a>>,
|
||||
pub filter: String,
|
||||
pub filter: Filter,
|
||||
mode: Mode,
|
||||
}
|
||||
|
||||
|
|
@ -200,7 +200,7 @@ impl<'a> UiState<'a> {
|
|||
UiState::MatchList(MatchListState {
|
||||
app,
|
||||
table_state: ScrollbarTableState::new(app.match_lines()),
|
||||
filter: String::new(),
|
||||
filter: Filter::default(),
|
||||
mode: Mode::Normal,
|
||||
})
|
||||
}
|
||||
|
|
@ -233,7 +233,7 @@ impl<'a> UiState<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn filter(&self) -> Option<&str> {
|
||||
pub fn filter(&self) -> Option<&Filter> {
|
||||
match self {
|
||||
UiState::MatchList(state) => Some(&state.filter),
|
||||
UiState::Match(state) => Some(&state.filter),
|
||||
|
|
@ -242,7 +242,7 @@ impl<'a> UiState<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn filter_mut(&mut self) -> Option<&mut String> {
|
||||
pub fn filter_mut(&mut self) -> Option<&mut Filter> {
|
||||
match self {
|
||||
UiState::MatchList(state) => Some(&mut state.filter),
|
||||
UiState::Match(state) => Some(&mut state.filter),
|
||||
|
|
@ -468,7 +468,7 @@ impl<'a> UiState<'a> {
|
|||
match self.mode() {
|
||||
Mode::Normal => FooterParams::Normal { page: self.page() },
|
||||
Mode::FilterInput => FooterParams::FilterInput {
|
||||
filter: self.filter().unwrap_or_default(),
|
||||
filter: self.filter().unwrap_or(&EMPTY_FILTER),
|
||||
page: self.page(),
|
||||
},
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue