aboutsummaryrefslogtreecommitdiffstats
path: root/app/Issue/Filter.hs
blob: fb6d205628df7de2c1fb0b48e41a1bc4289a10a6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
module Issue.Filter
  ( Filter,
    filterArg,
    applyFilters,
  )
where

import Control.Applicative (liftA2)
import Control.Arrow (second)
import Data.Maybe (fromMaybe)
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') = fromMaybe True ((==) <$> v' <*> v)