{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Language.PureScript.Ide.Filter
( Filter
, moduleFilter
, namespaceFilter
, exactFilter
, prefixFilter
, declarationTypeFilter
, applyFilters
) where
import Protolude hiding (isPrefixOf, Prefix)
import Data.Bifunctor (first)
import Data.Aeson
import Data.Text (isPrefixOf)
import qualified Data.Set as Set
import qualified Data.Map as Map
import Language.PureScript.Ide.Filter.Declaration (DeclarationType, declarationType)
import Language.PureScript.Ide.Types
import Language.PureScript.Ide.Util
import qualified Language.PureScript as P
newtype Filter = Filter (Either (Set P.ModuleName) DeclarationFilter)
deriving Show
unFilter :: Filter -> Either (Set P.ModuleName) DeclarationFilter
unFilter (Filter f) = f
data DeclarationFilter
= Prefix Text
| Exact Text
| Namespace (Set IdeNamespace)
| DeclType (Set DeclarationType)
deriving Show
moduleFilter :: Set P.ModuleName -> Filter
moduleFilter = Filter . Left
namespaceFilter :: Set IdeNamespace -> Filter
namespaceFilter nss = Filter (Right (Namespace nss))
exactFilter :: Text -> Filter
exactFilter t = Filter (Right (Exact t))
prefixFilter :: Text -> Filter
prefixFilter t = Filter (Right (Prefix t))
declarationTypeFilter :: Set DeclarationType -> Filter
declarationTypeFilter dts = Filter (Right (DeclType dts))
optimizeFilters :: [Filter] -> (Maybe (Set P.ModuleName), [DeclarationFilter])
optimizeFilters = first smashModuleFilters . partitionEithers . map unFilter
where
smashModuleFilters [] =
Nothing
smashModuleFilters (x:xs) =
Just (foldr Set.intersection x xs)
applyFilters :: [Filter] -> ModuleMap [IdeDeclarationAnn] -> ModuleMap [IdeDeclarationAnn]
applyFilters fs modules = case optimizeFilters fs of
(Nothing, declarationFilters) ->
applyDeclarationFilters declarationFilters modules
(Just moduleFilter', declarationFilters) ->
applyDeclarationFilters declarationFilters (Map.restrictKeys modules moduleFilter')
applyDeclarationFilters
:: [DeclarationFilter]
-> ModuleMap [IdeDeclarationAnn]
-> ModuleMap [IdeDeclarationAnn]
applyDeclarationFilters fs =
Map.filter (not . null)
. Map.map (foldr (.) identity (map applyDeclarationFilter fs))
applyDeclarationFilter
:: DeclarationFilter
-> [IdeDeclarationAnn]
-> [IdeDeclarationAnn]
applyDeclarationFilter f = case f of
Prefix prefix -> prefixFilter' prefix
Exact t -> exactFilter' t
Namespace namespaces -> namespaceFilter' namespaces
DeclType dts -> declarationTypeFilter' dts
namespaceFilter' :: Set IdeNamespace -> [IdeDeclarationAnn] -> [IdeDeclarationAnn]
namespaceFilter' namespaces =
filter (\decl -> elem (namespaceForDeclaration (discardAnn decl)) namespaces)
exactFilter' :: Text -> [IdeDeclarationAnn] -> [IdeDeclarationAnn]
exactFilter' search =
filter (\decl -> identifierFromIdeDeclaration (discardAnn decl) == search)
prefixFilter' :: Text -> [IdeDeclarationAnn] -> [IdeDeclarationAnn]
prefixFilter' prefix =
filter (\decl -> prefix `isPrefixOf` identifierFromIdeDeclaration (discardAnn decl))
declarationTypeFilter' :: Set DeclarationType -> [IdeDeclarationAnn] -> [IdeDeclarationAnn]
declarationTypeFilter' declTypes =
filter (\decl -> declarationType (discardAnn decl) `Set.member` declTypes)
instance FromJSON Filter where
parseJSON = withObject "filter" $ \o -> do
(filter' :: Text) <- o .: "filter"
case filter' of
"modules" -> do
params <- o .: "params"
modules <- map P.moduleNameFromString <$> params .: "modules"
pure (moduleFilter (Set.fromList modules))
"exact" -> do
params <- o .: "params"
search <- params .: "search"
pure (exactFilter search)
"prefix" -> do
params <- o.: "params"
search <- params .: "search"
pure (prefixFilter search)
"namespace" -> do
params <- o .: "params"
namespaces <- params .: "namespaces"
pure (namespaceFilter (Set.fromList namespaces))
"declarations" -> do
declarations <- o.: "params"
pure (declarationTypeFilter (Set.fromList declarations))
_ -> mzero