aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/fexpr/grammar.lalrpop13
-rw-r--r--src/fexpr/mod.rs4
-rw-r--r--src/filters/player.rs26
-rw-r--r--src/main.rs1
-rw-r--r--src/playerclass.rs6
5 files changed, 47 insertions, 3 deletions
diff --git a/src/fexpr/grammar.lalrpop b/src/fexpr/grammar.lalrpop
index 654722b..f91da19 100644
--- a/src/fexpr/grammar.lalrpop
+++ b/src/fexpr/grammar.lalrpop
@@ -3,6 +3,7 @@ use super::{
FErrorKind,
FightOutcome,
filters,
+ PlayerClass,
SearchField,
};
use evtclib::Boss;
@@ -77,6 +78,8 @@ PlayerPredicate: Box<dyn filters::player::PlayerFilter> = {
filters::player::account(<>.clone())
| filters::player::character(<>),
+ "-class" <Comma<PlayerClass>> => filters::player::class(<>),
+
"(" <PlayerFilter> ")",
}
@@ -135,6 +138,16 @@ Boss: Boss = {
}),
}
+PlayerClass: PlayerClass = {
+ <l:@L> <w:word> =>? w.parse().map_err(|_| ParseError::User {
+ error: FError {
+ location: l,
+ data: w.into(),
+ kind: FErrorKind::InvalidClass,
+ }
+ }),
+}
+
Date: DateTime<Utc> = {
<l:@L> <d:datetime> =>? Local.datetime_from_str(d, "%Y-%m-%d %H:%M:%S")
.map_err(|error| ParseError::User {
diff --git a/src/fexpr/mod.rs b/src/fexpr/mod.rs
index 2bdbfe7..452d66c 100644
--- a/src/fexpr/mod.rs
+++ b/src/fexpr/mod.rs
@@ -3,7 +3,7 @@
//! This module contains methods to parse a given string into an abstract filter tree, check its
//! type and convert it to a [`Filter`][super::filters::Filter].
// Make it available in the grammar mod.
-use super::{filters, FightOutcome, SearchField};
+use super::{filters, playerclass::PlayerClass, FightOutcome, SearchField};
use std::{error, fmt};
@@ -44,6 +44,8 @@ pub enum FErrorKind {
InvalidTimestamp(#[from] chrono::format::ParseError),
#[error("invalid boss name")]
InvalidBoss,
+ #[error("invalid class name")]
+ InvalidClass,
}
/// Shortcut to create a new parser and parse the given input.
diff --git a/src/filters/player.rs b/src/filters/player.rs
index 3af2be2..2b14eb0 100644
--- a/src/filters/player.rs
+++ b/src/filters/player.rs
@@ -3,12 +3,12 @@
//! Additionally, it provides methods to lift a player filter to a log filter with [`any`][any] and
//! [`all`][all].
use super::{
- super::{guilds, EarlyLogResult, LogResult, Player, SearchField},
+ super::{guilds, playerclass::PlayerClass, EarlyLogResult, LogResult, Player, SearchField},
log::LogFilter,
Filter, Inclusion,
};
-use std::convert::TryFrom;
+use std::{collections::HashSet, convert::TryFrom};
use evtclib::{Agent, AgentKind};
@@ -113,3 +113,25 @@ pub fn character(regex: Regex) -> Box<dyn PlayerFilter> {
pub fn account(regex: Regex) -> Box<dyn PlayerFilter> {
name(SearchField::Account, regex)
}
+
+#[derive(Clone, Debug)]
+struct ClassFilter(HashSet<PlayerClass>);
+
+impl Filter<Agent, Player> for ClassFilter {
+ fn filter_early(&self, agent: &Agent) -> Inclusion {
+ if let AgentKind::Player(ref player) = agent.kind() {
+ self.0.contains(&player.into()).into()
+ } else {
+ Inclusion::Unknown
+ }
+ }
+
+ fn filter(&self, player: &Player) -> bool {
+ self.0.contains(&player.profession)
+ }
+}
+
+/// Construct a `PlayerFilter` that matches only the given classes.
+pub fn class(classes: HashSet<PlayerClass>) -> Box<dyn PlayerFilter> {
+ Box::new(ClassFilter(classes))
+}
diff --git a/src/main.rs b/src/main.rs
index d9f0817..bf4c472 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -43,6 +43,7 @@ const APP_NAME: &str = "raidgrep";
/// -character REGEX True if the character name matches the regex.
/// -account REGEX True if the account name matches the regex.
/// -name REGEX True if either character or account name match.
+/// -class CLASSES True if the player has one of the listed classes.
///
/// -success Only include successful logs.
/// -wipe Only include failed logs.
diff --git a/src/playerclass.rs b/src/playerclass.rs
index 77b9794..247e8b1 100644
--- a/src/playerclass.rs
+++ b/src/playerclass.rs
@@ -59,6 +59,12 @@ impl From<(Profession, Option<EliteSpec>)> for PlayerClass {
}
}
+impl From<&evtclib::Player> for PlayerClass {
+ fn from(player: &evtclib::Player) -> Self {
+ (player.profession(), player.elite()).into()
+ }
+}
+
impl fmt::Display for PlayerClass {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use EliteSpec::*;