tiger_lib/report/
filter.rs1use glob::Pattern;
2use std::path::Path;
3
4use crate::block::Comparator;
5
6use crate::Token;
7use crate::fileset::FileKind;
8use crate::report::{
9 Confidence, ErrorKey, ErrorLoc, LogReportMetadata, LogReportPointers, Severity, err,
10};
11use crate::token::Loc;
12
13#[derive(Default, Debug)]
16pub struct ReportFilter {
17 pub show_vanilla: bool,
19 pub show_loaded_mods: bool,
21 pub predicate: FilterRule,
23}
24
25impl ReportFilter {
26 pub fn should_print_report(
32 &self,
33 report: &LogReportMetadata,
34 pointers: &LogReportPointers,
35 ) -> bool {
36 if report.key == ErrorKey::Config {
37 return true;
40 }
41 let out_of_scope = pointers.iter().map(|p| &p.loc).all(|loc| {
43 (loc.kind.counts_as_vanilla() && !self.show_vanilla)
44 || (matches!(loc.kind, FileKind::LoadedMod(_)) && !self.show_loaded_mods)
45 });
46 if out_of_scope {
47 return false;
48 }
49 self.predicate.apply(report, pointers)
50 }
51
52 pub fn should_maybe_print(&self, key: ErrorKey, loc: Loc) -> bool {
54 if key == ErrorKey::Config {
55 return true;
58 }
59 if (loc.kind.counts_as_vanilla() && !self.show_vanilla)
60 || (matches!(loc.kind, FileKind::LoadedMod(_)) && !self.show_loaded_mods)
61 {
62 return false;
63 }
64 true
65 }
66}
67
68#[derive(Default, Debug)]
69pub enum FilterRule {
70 #[default]
72 Tautology,
73 Contradiction,
75 Conjunction(Vec<FilterRule>),
78 Disjunction(Vec<FilterRule>),
81 Negation(Box<FilterRule>),
84 Severity(Comparator, Severity),
87 Confidence(Comparator, Confidence),
90 Key(ErrorKey),
92 File(Pattern),
94 Text(String),
96}
97
98impl FilterRule {
99 fn apply(&self, report: &LogReportMetadata, pointers: &LogReportPointers) -> bool {
100 match self {
101 FilterRule::Tautology => true,
102 FilterRule::Contradiction => false,
103 FilterRule::Conjunction(children) => {
104 children.iter().all(|child| child.apply(report, pointers))
105 }
106 FilterRule::Disjunction(children) => {
107 children.iter().any(|child| child.apply(report, pointers))
108 }
109 FilterRule::Negation(child) => !child.apply(report, pointers),
110 FilterRule::Severity(comparator, level) => match comparator {
111 Comparator::Equals(_) => report.severity == *level,
112 Comparator::NotEquals => report.severity != *level,
113 Comparator::GreaterThan => report.severity > *level,
114 Comparator::AtLeast => report.severity >= *level,
115 Comparator::LessThan => report.severity < *level,
116 Comparator::AtMost => report.severity <= *level,
117 },
118 FilterRule::Confidence(comparator, level) => match comparator {
119 Comparator::Equals(_) => report.confidence == *level,
120 Comparator::NotEquals => report.confidence != *level,
121 Comparator::GreaterThan => report.confidence > *level,
122 Comparator::AtLeast => report.confidence >= *level,
123 Comparator::LessThan => report.confidence < *level,
124 Comparator::AtMost => report.confidence <= *level,
125 },
126 FilterRule::Key(key) => report.key == *key,
127 FilterRule::File(pattern) => pointers.iter().any(|pointer| {
128 pattern.matches_path(pointer.loc.pathname())
129 || pointer.loc.pathname().starts_with(Path::new(pattern.as_str()))
130 }),
131 FilterRule::Text(s) => {
132 report.msg.to_ascii_lowercase().contains(&s.to_ascii_lowercase())
133 }
134 }
135 }
136 pub fn file_from_token(token: &Token) -> Option<FilterRule> {
137 let pattern = Pattern::new(token.as_str());
138 match pattern {
139 Ok(p) => Some(FilterRule::File(p)),
140 Err(e) => {
141 err(ErrorKey::Config)
142 .msg("Expected valid file path or glob pattern")
143 .loc_msg(
144 {
145 let mut loc = token.into_loc();
146 loc.column += u32::try_from(e.pos).unwrap_or(0);
147 loc
148 },
149 e.msg,
150 )
151 .push();
152 None
153 }
154 }
155 }
156}