module Issue.Filter ( Filter, filterArg, applyFilters, ) where import Control.Applicative (liftA2) import Control.Arrow (second) import Data.Text (Text) import Data.Text qualified as T import Issue (Issue (..)) import Issue.Tag (Tag (..)) import Options.Applicative qualified as O data Filter = Filter Mode SimpleFilter deriving (Show) data Mode = Include | Exclude deriving (Show) data SimpleFilter = ByTag Text (Maybe Text) deriving (Show) filterArg :: O.Parser [Filter] filterArg = O.many ( O.option (O.maybeReader (parse . T.pack)) ( O.long "filter" <> O.short 'f' <> O.metavar "FILTER" <> O.help "Filters selected issues. Examples: @assigned, !@assigned joe" ) ) where parse s | "@" `T.isPrefixOf` s = Just (Filter Include (uncurry ByTag (splitValue (T.drop 1 s)))) | "!@" `T.isPrefixOf` s = Just (Filter Exclude (uncurry ByTag (splitValue (T.drop 2 s)))) | otherwise = Nothing splitValue :: Text -> (Text, Maybe Text) splitValue s = case second T.strip (T.breakOn " " s) of (k, "") -> (k, Nothing) (k, v) -> (k, Just v) applyFilters :: [Filter] -> ([Issue] -> [Issue]) applyFilters fs = filter (filtersPredicate fs) filtersPredicate :: [Filter] -> (Issue -> Bool) filtersPredicate [] = \_ -> True filtersPredicate fs = foldr1 (liftA2 (&&)) (map filterPredicate fs) filterPredicate :: Filter -> (Issue -> Bool) filterPredicate (Filter m sf) = modePredicate m (simpleFilterPredicate sf) modePredicate :: Mode -> (Issue -> Bool) -> (Issue -> Bool) modePredicate Include p = p modePredicate Exclude p = not . p simpleFilterPredicate :: SimpleFilter -> (Issue -> Bool) simpleFilterPredicate (ByTag k v) i = any ((&&) <$> matchKey <*> matchValue) i.tags where matchKey (Tag k' _) = k' == k matchValue (Tag _ v') = maybe True ((==) v') v