{-# LANGUAGE LambdaCase, MultiWayIf, RecordWildCards, ScopedTypeVariables,
             TupleSections #-}

module Action.Search
    (actionSearch, withSearch, search
    ,targetInfo
    ,targetResultDisplay
    ,action_search_test
    ) where

import Control.DeepSeq
import Control.Exception.Extra
import Control.Monad.Extra
import qualified Data.Aeson as JSON
import qualified Data.ByteString.Lazy.Char8 as LBS
import Data.Functor.Identity
import Data.List.Extra
import qualified Data.Map as Map
import Data.Maybe
import qualified Data.Set as Set
import System.Directory
import Text.Blaze.Renderer.Utf8

import Action.CmdLine
import General.Store
import General.Util
import Input.Item
import Output.Items
import Output.Names
import Output.Tags
import Output.Types
import Query

-- -- generate all
-- @tagsoup -- generate tagsoup
-- @tagsoup filter -- search the tagsoup package
-- filter -- search all

actionSearch :: CmdLine -> IO ()
actionSearch :: CmdLine -> IO ()
actionSearch Search{Bool
Int
FilePath
[FilePath]
Maybe Bool
Maybe Int
Language
compare_ :: CmdLine -> [FilePath]
language :: CmdLine -> Language
repeat_ :: CmdLine -> Int
query :: CmdLine -> [FilePath]
count :: CmdLine -> Maybe Int
database :: CmdLine -> FilePath
info :: CmdLine -> Bool
numbers :: CmdLine -> Bool
link :: CmdLine -> Bool
jsonl :: CmdLine -> Bool
json :: CmdLine -> Bool
color :: CmdLine -> Maybe Bool
compare_ :: [FilePath]
language :: Language
repeat_ :: Int
query :: [FilePath]
count :: Maybe Int
database :: FilePath
info :: Bool
numbers :: Bool
link :: Bool
jsonl :: Bool
json :: Bool
color :: Maybe Bool
..} = Int -> IO () -> IO ()
forall (m :: * -> *) a. Applicative m => Int -> m a -> m ()
replicateM_ Int
repeat_ (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ -- deliberately reopen the database each time
    FilePath -> (StoreRead -> IO ()) -> IO ()
forall a. NFData a => FilePath -> (StoreRead -> IO a) -> IO a
withSearch FilePath
database ((StoreRead -> IO ()) -> IO ()) -> (StoreRead -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \StoreRead
store ->
        if [FilePath] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [FilePath]
compare_ then do
            Int
count' <- Int -> IO Int
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Int -> IO Int) -> Int -> IO Int
forall a b. (a -> b) -> a -> b
$ Int -> Maybe Int -> Int
forall a. a -> Maybe a -> a
fromMaybe Int
10 Maybe Int
count
            ([Query]
q, [Target]
res) <- ([Query], [Target]) -> IO ([Query], [Target])
forall (f :: * -> *) a. Applicative f => a -> f a
pure (([Query], [Target]) -> IO ([Query], [Target]))
-> ([Query], [Target]) -> IO ([Query], [Target])
forall a b. (a -> b) -> a -> b
$ StoreRead -> [Query] -> ([Query], [Target])
search StoreRead
store ([Query] -> ([Query], [Target])) -> [Query] -> ([Query], [Target])
forall a b. (a -> b) -> a -> b
$ FilePath -> [Query]
parseQuery (FilePath -> [Query]) -> FilePath -> [Query]
forall a b. (a -> b) -> a -> b
$ [FilePath] -> FilePath
unwords [FilePath]
query
            IO () -> IO ()
whenLoud (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ FilePath -> IO ()
putStrLn (FilePath -> IO ()) -> FilePath -> IO ()
forall a b. (a -> b) -> a -> b
$ FilePath
"Query: " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath -> FilePath
unescapeHTML (ByteString -> FilePath
LBS.unpack (ByteString -> FilePath) -> ByteString -> FilePath
forall a b. (a -> b) -> a -> b
$ Markup -> ByteString
renderMarkup (Markup -> ByteString) -> Markup -> ByteString
forall a b. (a -> b) -> a -> b
$ [Query] -> Markup
renderQuery [Query]
q)
            let ([FilePath]
shown, [FilePath]
hidden) = Int -> [FilePath] -> ([FilePath], [FilePath])
forall a. Int -> [a] -> ([a], [a])
splitAt Int
count' ([FilePath] -> ([FilePath], [FilePath]))
-> [FilePath] -> ([FilePath], [FilePath])
forall a b. (a -> b) -> a -> b
$ [FilePath] -> [FilePath]
forall a. Ord a => [a] -> [a]
nubOrd ([FilePath] -> [FilePath]) -> [FilePath] -> [FilePath]
forall a b. (a -> b) -> a -> b
$ (Target -> FilePath) -> [Target] -> [FilePath]
forall a b. (a -> b) -> [a] -> [b]
map (Bool -> Target -> FilePath
targetResultDisplay Bool
link) [Target]
res
            if [Target] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Target]
res then
                FilePath -> IO ()
putStrLn FilePath
"No results found"
             else if Bool
info then do
                 FilePath -> IO ()
putStr (FilePath -> IO ()) -> FilePath -> IO ()
forall a b. (a -> b) -> a -> b
$ Target -> FilePath
targetInfo (Target -> FilePath) -> Target -> FilePath
forall a b. (a -> b) -> a -> b
$ [Target] -> Target
forall a. [a] -> a
head [Target]
res
             else do
                let toShow :: [FilePath]
toShow = if Bool
numbers Bool -> Bool -> Bool
&& Bool -> Bool
not Bool
info then [FilePath] -> [FilePath]
addCounter [FilePath]
shown else [FilePath]
shown
                if | Bool
json -> ByteString -> IO ()
LBS.putStrLn (ByteString -> IO ()) -> ByteString -> IO ()
forall a b. (a -> b) -> a -> b
$ [Target] -> ByteString
forall a. ToJSON a => a -> ByteString
JSON.encode ([Target] -> ByteString) -> [Target] -> ByteString
forall a b. (a -> b) -> a -> b
$ ([Target] -> [Target])
-> (Int -> [Target] -> [Target])
-> Maybe Int
-> [Target]
-> [Target]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [Target] -> [Target]
forall a. a -> a
id Int -> [Target] -> [Target]
forall a. Int -> [a] -> [a]
take Maybe Int
count ([Target] -> [Target]) -> [Target] -> [Target]
forall a b. (a -> b) -> a -> b
$ (Target -> Target) -> [Target] -> [Target]
forall a b. (a -> b) -> [a] -> [b]
map Target -> Target
unHTMLtargetItem [Target]
res
                   | Bool
jsonl -> (Target -> IO ()) -> [Target] -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (ByteString -> IO ()
LBS.putStrLn (ByteString -> IO ()) -> (Target -> ByteString) -> Target -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Target -> ByteString
forall a. ToJSON a => a -> ByteString
JSON.encode) ([Target] -> IO ()) -> [Target] -> IO ()
forall a b. (a -> b) -> a -> b
$ ([Target] -> [Target])
-> (Int -> [Target] -> [Target])
-> Maybe Int
-> [Target]
-> [Target]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [Target] -> [Target]
forall a. a -> a
id Int -> [Target] -> [Target]
forall a. Int -> [a] -> [a]
take Maybe Int
count ([Target] -> [Target]) -> [Target] -> [Target]
forall a b. (a -> b) -> a -> b
$ (Target -> Target) -> [Target] -> [Target]
forall a b. (a -> b) -> [a] -> [b]
map Target -> Target
unHTMLtargetItem [Target]
res
                   | Bool
otherwise -> FilePath -> IO ()
putStr (FilePath -> IO ()) -> FilePath -> IO ()
forall a b. (a -> b) -> a -> b
$ [FilePath] -> FilePath
unlines [FilePath]
toShow
                Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when ([FilePath]
hidden [FilePath] -> [FilePath] -> Bool
forall a. Eq a => a -> a -> Bool
/= [] Bool -> Bool -> Bool
&& Bool -> Bool
not Bool
json) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
                    IO () -> IO ()
whenNormal (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ FilePath -> IO ()
putStrLn (FilePath -> IO ()) -> FilePath -> IO ()
forall a b. (a -> b) -> a -> b
$ FilePath
"-- plus more results not shown, pass --count=" FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ Int -> FilePath
forall a. Show a => a -> FilePath
show (Int
count'Int -> Int -> Int
forall a. Num a => a -> a -> a
+Int
10) FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
" to see more"
        else do
            let parseType :: FilePath -> (FilePath, Sig FilePath)
parseType FilePath
x = case FilePath -> [Query]
parseQuery FilePath
x of
                                  [QueryType Type ()
t] -> (Type () -> FilePath
forall a. Pretty a => a -> FilePath
pretty Type ()
t, Type () -> Sig FilePath
forall a. Type a -> Sig FilePath
hseToSig Type ()
t)
                                  [Query]
_ -> FilePath -> (FilePath, Sig FilePath)
forall a. HasCallStack => FilePath -> a
error (FilePath -> (FilePath, Sig FilePath))
-> FilePath -> (FilePath, Sig FilePath)
forall a b. (a -> b) -> a -> b
$ FilePath
"Expected a type signature, got: " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
x
            FilePath -> IO ()
putStr (FilePath -> IO ()) -> FilePath -> IO ()
forall a b. (a -> b) -> a -> b
$ [FilePath] -> FilePath
unlines ([FilePath] -> FilePath) -> [FilePath] -> FilePath
forall a b. (a -> b) -> a -> b
$ StoreRead
-> (FilePath, Sig FilePath)
-> [(FilePath, Sig FilePath)]
-> [FilePath]
searchFingerprintsDebug StoreRead
store (FilePath -> (FilePath, Sig FilePath)
parseType (FilePath -> (FilePath, Sig FilePath))
-> FilePath -> (FilePath, Sig FilePath)
forall a b. (a -> b) -> a -> b
$ [FilePath] -> FilePath
unwords [FilePath]
query) ((FilePath -> (FilePath, Sig FilePath))
-> [FilePath] -> [(FilePath, Sig FilePath)]
forall a b. (a -> b) -> [a] -> [b]
map FilePath -> (FilePath, Sig FilePath)
parseType [FilePath]
compare_)

-- | Returns the details printed out when hoogle --info is called
targetInfo :: Target -> String
targetInfo :: Target -> FilePath
targetInfo Target{FilePath
Maybe (FilePath, FilePath)
targetDocs :: Target -> FilePath
targetItem :: Target -> FilePath
targetType :: Target -> FilePath
targetModule :: Target -> Maybe (FilePath, FilePath)
targetPackage :: Target -> Maybe (FilePath, FilePath)
targetURL :: Target -> FilePath
targetDocs :: FilePath
targetItem :: FilePath
targetType :: FilePath
targetModule :: Maybe (FilePath, FilePath)
targetPackage :: Maybe (FilePath, FilePath)
targetURL :: FilePath
..} =
    [FilePath] -> FilePath
unlines ([FilePath] -> FilePath) -> [FilePath] -> FilePath
forall a b. (a -> b) -> a -> b
$ [ FilePath -> FilePath
unHTML FilePath
targetItem ] [FilePath] -> [FilePath] -> [FilePath]
forall a. [a] -> [a] -> [a]
++
              [ [FilePath] -> FilePath
unwords [FilePath]
packageModule | Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ [FilePath] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [FilePath]
packageModule] [FilePath] -> [FilePath] -> [FilePath]
forall a. [a] -> [a] -> [a]
++
              [ FilePath -> FilePath
unHTML FilePath
targetDocs ]
            where packageModule :: [FilePath]
packageModule = ((FilePath, FilePath) -> FilePath)
-> [(FilePath, FilePath)] -> [FilePath]
forall a b. (a -> b) -> [a] -> [b]
map (FilePath, FilePath) -> FilePath
forall a b. (a, b) -> a
fst ([(FilePath, FilePath)] -> [FilePath])
-> [(FilePath, FilePath)] -> [FilePath]
forall a b. (a -> b) -> a -> b
$ [Maybe (FilePath, FilePath)] -> [(FilePath, FilePath)]
forall a. [Maybe a] -> [a]
catMaybes [Maybe (FilePath, FilePath)
targetPackage, Maybe (FilePath, FilePath)
targetModule]

-- | Returns the Target formatted as an item to display in the results
-- | Bool argument decides whether links are shown
targetResultDisplay :: Bool -> Target -> String
targetResultDisplay :: Bool -> Target -> FilePath
targetResultDisplay Bool
link Target{FilePath
Maybe (FilePath, FilePath)
targetDocs :: FilePath
targetItem :: FilePath
targetType :: FilePath
targetModule :: Maybe (FilePath, FilePath)
targetPackage :: Maybe (FilePath, FilePath)
targetURL :: FilePath
targetDocs :: Target -> FilePath
targetItem :: Target -> FilePath
targetType :: Target -> FilePath
targetModule :: Target -> Maybe (FilePath, FilePath)
targetPackage :: Target -> Maybe (FilePath, FilePath)
targetURL :: Target -> FilePath
..} = FilePath -> FilePath
unHTML (FilePath -> FilePath) -> FilePath -> FilePath
forall a b. (a -> b) -> a -> b
$ [FilePath] -> FilePath
unwords ([FilePath] -> FilePath) -> [FilePath] -> FilePath
forall a b. (a -> b) -> a -> b
$
        ((FilePath, FilePath) -> FilePath)
-> [(FilePath, FilePath)] -> [FilePath]
forall a b. (a -> b) -> [a] -> [b]
map (FilePath, FilePath) -> FilePath
forall a b. (a, b) -> a
fst (Maybe (FilePath, FilePath) -> [(FilePath, FilePath)]
forall a. Maybe a -> [a]
maybeToList Maybe (FilePath, FilePath)
targetModule) [FilePath] -> [FilePath] -> [FilePath]
forall a. [a] -> [a] -> [a]
++
        [FilePath
targetItem] [FilePath] -> [FilePath] -> [FilePath]
forall a. [a] -> [a] -> [a]
++
        [FilePath
"-- " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
targetURL | Bool
link]

unHTMLtargetItem :: Target -> Target
unHTMLtargetItem :: Target -> Target
unHTMLtargetItem Target
target = Target
target {targetItem :: FilePath
targetItem = FilePath -> FilePath
unHTML (FilePath -> FilePath) -> FilePath -> FilePath
forall a b. (a -> b) -> a -> b
$ Target -> FilePath
targetItem Target
target}

addCounter :: [String] -> [String]
addCounter :: [FilePath] -> [FilePath]
addCounter = (Integer -> FilePath -> FilePath)
-> Integer -> [FilePath] -> [FilePath]
forall a b c. Enum a => (a -> b -> c) -> a -> [b] -> [c]
zipWithFrom (\Integer
i FilePath
x -> Integer -> FilePath
forall a. Show a => a -> FilePath
show Integer
i FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
") " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
x) Integer
1

withSearch :: NFData a => FilePath -> (StoreRead -> IO a) -> IO a
withSearch :: FilePath -> (StoreRead -> IO a) -> IO a
withSearch FilePath
database StoreRead -> IO a
act = do
    IO Bool -> IO () -> IO ()
forall (m :: * -> *). Monad m => m Bool -> m () -> m ()
unlessM (FilePath -> IO Bool
doesFileExist FilePath
database) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
        FilePath -> IO ()
exitFail (FilePath -> IO ()) -> FilePath -> IO ()
forall a b. (a -> b) -> a -> b
$ FilePath
"Error, database does not exist (run 'hoogle generate' first)\n" FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++
                   FilePath
"    Filename: " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
database
    FilePath -> (StoreRead -> IO a) -> IO a
forall a. NFData a => FilePath -> (StoreRead -> IO a) -> IO a
storeReadFile FilePath
database StoreRead -> IO a
act


search :: StoreRead -> [Query] -> ([Query], [Target])
search :: StoreRead -> [Query] -> ([Query], [Target])
search StoreRead
store [Query]
qs = Identity ([Query], [Target]) -> ([Query], [Target])
forall a. Identity a -> a
runIdentity (Identity ([Query], [Target]) -> ([Query], [Target]))
-> Identity ([Query], [Target]) -> ([Query], [Target])
forall a b. (a -> b) -> a -> b
$ do
    ([Query]
qs, Bool
exact, TargetId -> Bool
filt, [TargetId]
list) <- ([Query], Bool, TargetId -> Bool, [TargetId])
-> Identity ([Query], Bool, TargetId -> Bool, [TargetId])
forall (f :: * -> *) a. Applicative f => a -> f a
pure (([Query], Bool, TargetId -> Bool, [TargetId])
 -> Identity ([Query], Bool, TargetId -> Bool, [TargetId]))
-> ([Query], Bool, TargetId -> Bool, [TargetId])
-> Identity ([Query], Bool, TargetId -> Bool, [TargetId])
forall a b. (a -> b) -> a -> b
$ StoreRead
-> [Query] -> ([Query], Bool, TargetId -> Bool, [TargetId])
applyTags StoreRead
store  [Query]
qs
    [TargetId]
is <- case ((Query -> Bool) -> [Query] -> [Query]
forall a. (a -> Bool) -> [a] -> [a]
filter Query -> Bool
isQueryName [Query]
qs, (Query -> Bool) -> [Query] -> [Query]
forall a. (a -> Bool) -> [a] -> [a]
filter Query -> Bool
isQueryType [Query]
qs) of
        ([], [] ) -> [TargetId] -> Identity [TargetId]
forall (f :: * -> *) a. Applicative f => a -> f a
pure [TargetId]
list
        ([], Query
t:[Query]
_) -> [TargetId] -> Identity [TargetId]
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([TargetId] -> Identity [TargetId])
-> [TargetId] -> Identity [TargetId]
forall a b. (a -> b) -> a -> b
$ StoreRead -> Sig FilePath -> [TargetId]
searchTypes StoreRead
store (Sig FilePath -> [TargetId]) -> Sig FilePath -> [TargetId]
forall a b. (a -> b) -> a -> b
$ Type () -> Sig FilePath
forall a. Type a -> Sig FilePath
hseToSig (Type () -> Sig FilePath) -> Type () -> Sig FilePath
forall a b. (a -> b) -> a -> b
$ Query -> Type ()
fromQueryType Query
t
        ([Query]
xs, [] ) -> [TargetId] -> Identity [TargetId]
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([TargetId] -> Identity [TargetId])
-> [TargetId] -> Identity [TargetId]
forall a b. (a -> b) -> a -> b
$ StoreRead -> Bool -> [FilePath] -> [TargetId]
searchNames StoreRead
store Bool
exact ([FilePath] -> [TargetId]) -> [FilePath] -> [TargetId]
forall a b. (a -> b) -> a -> b
$ (Query -> FilePath) -> [Query] -> [FilePath]
forall a b. (a -> b) -> [a] -> [b]
map Query -> FilePath
fromQueryName [Query]
xs
        ([Query]
xs, Query
t:[Query]
_) -> do
            Set TargetId
nam <- Set TargetId -> Identity (Set TargetId)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Set TargetId -> Identity (Set TargetId))
-> Set TargetId -> Identity (Set TargetId)
forall a b. (a -> b) -> a -> b
$ [TargetId] -> Set TargetId
forall a. Ord a => [a] -> Set a
Set.fromList ([TargetId] -> Set TargetId) -> [TargetId] -> Set TargetId
forall a b. (a -> b) -> a -> b
$ StoreRead -> Bool -> [FilePath] -> [TargetId]
searchNames StoreRead
store Bool
exact ([FilePath] -> [TargetId]) -> [FilePath] -> [TargetId]
forall a b. (a -> b) -> a -> b
$ (Query -> FilePath) -> [Query] -> [FilePath]
forall a b. (a -> b) -> [a] -> [b]
map Query -> FilePath
fromQueryName [Query]
xs
            [TargetId] -> Identity [TargetId]
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([TargetId] -> Identity [TargetId])
-> [TargetId] -> Identity [TargetId]
forall a b. (a -> b) -> a -> b
$ (TargetId -> Bool) -> [TargetId] -> [TargetId]
forall a. (a -> Bool) -> [a] -> [a]
filter (TargetId -> Set TargetId -> Bool
forall a. Ord a => a -> Set a -> Bool
`Set.member` Set TargetId
nam) ([TargetId] -> [TargetId]) -> [TargetId] -> [TargetId]
forall a b. (a -> b) -> a -> b
$ StoreRead -> Sig FilePath -> [TargetId]
searchTypes StoreRead
store (Sig FilePath -> [TargetId]) -> Sig FilePath -> [TargetId]
forall a b. (a -> b) -> a -> b
$ Type () -> Sig FilePath
forall a. Type a -> Sig FilePath
hseToSig (Type () -> Sig FilePath) -> Type () -> Sig FilePath
forall a b. (a -> b) -> a -> b
$ Query -> Type ()
fromQueryType Query
t
    let look :: TargetId -> Target
look = StoreRead -> TargetId -> Target
lookupItem StoreRead
store
    ([Query], [Target]) -> Identity ([Query], [Target])
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([Query]
qs, (TargetId -> Target) -> [TargetId] -> [Target]
forall a b. (a -> b) -> [a] -> [b]
map TargetId -> Target
look ([TargetId] -> [Target]) -> [TargetId] -> [Target]
forall a b. (a -> b) -> a -> b
$ (TargetId -> Bool) -> [TargetId] -> [TargetId]
forall a. (a -> Bool) -> [a] -> [a]
filter TargetId -> Bool
filt [TargetId]
is)

action_search_test :: Bool -> FilePath -> IO ()
action_search_test :: Bool -> FilePath -> IO ()
action_search_test Bool
sample FilePath
database = FilePath -> IO () -> IO ()
testing FilePath
"Action.Search.search" (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ FilePath -> (StoreRead -> IO ()) -> IO ()
forall a. NFData a => FilePath -> (StoreRead -> IO a) -> IO a
withSearch FilePath
database ((StoreRead -> IO ()) -> IO ()) -> (StoreRead -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \StoreRead
store -> do
    let noResults :: FilePath -> IO ()
noResults FilePath
a = do
          [Target]
res <- [Target] -> IO [Target]
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([Target] -> IO [Target]) -> [Target] -> IO [Target]
forall a b. (a -> b) -> a -> b
$ ([Query], [Target]) -> [Target]
forall a b. (a, b) -> b
snd (([Query], [Target]) -> [Target])
-> ([Query], [Target]) -> [Target]
forall a b. (a -> b) -> a -> b
$ StoreRead -> [Query] -> ([Query], [Target])
search StoreRead
store (FilePath -> [Query]
parseQuery FilePath
a)
          case [Target]
res of
              [] -> Char -> IO ()
putChar Char
'.'
              [Target]
_ -> FilePath -> IO ()
forall a. HasCallStack => FilePath -> IO a
errorIO (FilePath -> IO ()) -> FilePath -> IO ()
forall a b. (a -> b) -> a -> b
$ FilePath
"Searching for: " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath -> FilePath
forall a. Show a => a -> FilePath
show FilePath
a FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
"\nGot: " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ [Target] -> FilePath
forall a. Show a => a -> FilePath
show (Int -> [Target] -> [Target]
forall a. Int -> [a] -> [a]
take Int
1 [Target]
res) FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
"\n expected none"
    let FilePath
a ==$ :: FilePath -> (FilePath -> Bool) -> IO ()
==$ FilePath -> Bool
f = do
            [Target]
res <- [Target] -> IO [Target]
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([Target] -> IO [Target]) -> [Target] -> IO [Target]
forall a b. (a -> b) -> a -> b
$ ([Query], [Target]) -> [Target]
forall a b. (a, b) -> b
snd (([Query], [Target]) -> [Target])
-> ([Query], [Target]) -> [Target]
forall a b. (a -> b) -> a -> b
$ StoreRead -> [Query] -> ([Query], [Target])
search StoreRead
store (FilePath -> [Query]
parseQuery FilePath
a)
            case [Target]
res of
                Target{FilePath
Maybe (FilePath, FilePath)
targetDocs :: FilePath
targetItem :: FilePath
targetType :: FilePath
targetModule :: Maybe (FilePath, FilePath)
targetPackage :: Maybe (FilePath, FilePath)
targetURL :: FilePath
targetDocs :: Target -> FilePath
targetItem :: Target -> FilePath
targetType :: Target -> FilePath
targetModule :: Target -> Maybe (FilePath, FilePath)
targetPackage :: Target -> Maybe (FilePath, FilePath)
targetURL :: Target -> FilePath
..}:[Target]
_ | FilePath -> Bool
f FilePath
targetURL -> Char -> IO ()
putChar Char
'.'
                [Target]
_ -> FilePath -> IO ()
forall a. HasCallStack => FilePath -> IO a
errorIO (FilePath -> IO ()) -> FilePath -> IO ()
forall a b. (a -> b) -> a -> b
$ FilePath
"Searching for: " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath -> FilePath
forall a. Show a => a -> FilePath
show FilePath
a FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
"\nGot: " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ [Target] -> FilePath
forall a. Show a => a -> FilePath
show (Int -> [Target] -> [Target]
forall a. Int -> [a] -> [a]
take Int
1 [Target]
res)
    let FilePath
a === :: FilePath -> FilePath -> IO ()
=== FilePath
b = FilePath
a FilePath -> (FilePath -> Bool) -> IO ()
==$ (FilePath -> FilePath -> Bool
forall a. Eq a => a -> a -> Bool
== FilePath
b)

    let query :: String -> [ExpectedQueryResult] -> IO ()
        query :: FilePath -> [ExpectedQueryResult] -> IO ()
query FilePath
a [ExpectedQueryResult]
qrs = let results :: [[Target]]
results = [Target] -> [[Target]]
deDup ([Target] -> [[Target]]) -> [Target] -> [[Target]]
forall a b. (a -> b) -> a -> b
$ ([Query], [Target]) -> [Target]
forall a b. (a, b) -> b
snd (StoreRead -> [Query] -> ([Query], [Target])
search StoreRead
store (FilePath -> [Query]
parseQuery FilePath
a))
                      in [ExpectedQueryResult] -> (ExpectedQueryResult -> IO ()) -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [ExpectedQueryResult]
qrs ((ExpectedQueryResult -> IO ()) -> IO ())
-> (ExpectedQueryResult -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \ExpectedQueryResult
qr -> case ExpectedQueryResult -> [[Target]] -> TestResult
matchQR ExpectedQueryResult
qr [[Target]]
results of
                                              TestResult
Success           -> Char -> IO ()
putChar Char
'.'
                                              TestResult
ExpectedFailure   -> Char -> IO ()
putChar Char
'o'
                                              TestResult
_ -> FilePath -> IO ()
forall a. HasCallStack => FilePath -> IO a
errorIO (FilePath -> IO ()) -> FilePath -> IO ()
forall a b. (a -> b) -> a -> b
$ FilePath
"Searching for: " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath -> FilePath
forall a. Show a => a -> FilePath
show FilePath
a
                                                           FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
"\nGot: " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ [[Target]] -> FilePath
forall a. Show a => a -> FilePath
show (Int -> [[Target]] -> [[Target]]
forall a. Int -> [a] -> [a]
take Int
5 [[Target]]
results)
                                                           FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
"\n expected " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ ExpectedQueryResult -> FilePath
expected ExpectedQueryResult
qr

    let hackage :: FilePath -> FilePath
hackage FilePath
x = FilePath
"https://hackage.haskell.org/package/" FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
x
    if Bool
sample then do
        FilePath
"__prefix__" FilePath -> FilePath -> IO ()
=== FilePath
"http://henry.com?too_long"
        FilePath
"__suffix__" FilePath -> FilePath -> IO ()
=== FilePath
"http://henry.com?too_long"
        FilePath
"__infix__" FilePath -> FilePath -> IO ()
=== FilePath
"http://henry.com?too_long"
        FilePath
"Wife" FilePath -> FilePath -> IO ()
=== FilePath
"http://eghmitchell.com/Mitchell.html#a_wife"
        StoreRead -> [FilePath]
completionTags StoreRead
store [FilePath] -> [FilePath] -> IO ()
forall a. (Show a, Eq a) => a -> a -> IO ()
`testEq` [FilePath
"set:all",FilePath
"set:sample-data",FilePath
"package:emily",FilePath
"package:henry"]
     else do
        FilePath
"base" FilePath -> FilePath -> IO ()
=== FilePath -> FilePath
hackage FilePath
"base"
        FilePath
"Prelude" FilePath -> FilePath -> IO ()
=== FilePath -> FilePath
hackage FilePath
"base/docs/Prelude.html"
        FilePath
"map" FilePath -> FilePath -> IO ()
=== FilePath -> FilePath
hackage FilePath
"base/docs/Prelude.html#v:map"
        FilePath
"map is:ping" FilePath -> FilePath -> IO ()
=== FilePath -> FilePath
hackage FilePath
"base/docs/Prelude.html#v:map"
        FilePath
"map package:base" FilePath -> FilePath -> IO ()
=== FilePath -> FilePath
hackage FilePath
"base/docs/Prelude.html#v:map"
        FilePath -> IO ()
noResults FilePath
"map package:package-not-in-db"
        FilePath -> IO ()
noResults FilePath
"map module:Module.Not.In.Db"
        FilePath
"True" FilePath -> FilePath -> IO ()
=== FilePath -> FilePath
hackage FilePath
"base/docs/Prelude.html#v:True"
        FilePath
"Bool" FilePath -> FilePath -> IO ()
=== FilePath -> FilePath
hackage FilePath
"base/docs/Prelude.html#t:Bool"
        FilePath
"String" FilePath -> FilePath -> IO ()
=== FilePath -> FilePath
hackage FilePath
"base/docs/Prelude.html#t:String"
        FilePath
"Ord" FilePath -> FilePath -> IO ()
=== FilePath -> FilePath
hackage FilePath
"base/docs/Prelude.html#t:Ord"
        FilePath
">>=" FilePath -> FilePath -> IO ()
=== FilePath -> FilePath
hackage FilePath
"base/docs/Prelude.html#v:-62--62--61-"
        FilePath
"sequen" FilePath -> FilePath -> IO ()
=== FilePath -> FilePath
hackage FilePath
"base/docs/Prelude.html#v:sequence"
        FilePath
"foldl'" FilePath -> FilePath -> IO ()
=== FilePath -> FilePath
hackage FilePath
"base/docs/Data-List.html#v:foldl-39-"
        FilePath
"Action package:shake" FilePath -> FilePath -> IO ()
=== FilePath
"https://hackage.haskell.org/package/shake/docs/Development-Shake.html#t:Action"
        FilePath
"Action package:shake set:stackage" FilePath -> FilePath -> IO ()
=== FilePath
"https://hackage.haskell.org/package/shake/docs/Development-Shake.html#t:Action"
        FilePath
"map -package:base" FilePath -> (FilePath -> Bool) -> IO ()
==$ \FilePath
x -> Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ FilePath
"/base/" FilePath -> FilePath -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isInfixOf` FilePath
x
        FilePath
"<>" FilePath -> FilePath -> IO ()
=== FilePath -> FilePath
hackage FilePath
"base/docs/Prelude.html#v:-60--62-"
        FilePath
"Data.Set.insert" FilePath -> FilePath -> IO ()
=== FilePath -> FilePath
hackage FilePath
"containers/docs/Data-Set.html#v:insert"
        FilePath
"Set.insert" FilePath -> FilePath -> IO ()
=== FilePath -> FilePath
hackage FilePath
"containers/docs/Data-Set.html#v:insert"
        FilePath
"Prelude.mapM_" FilePath -> FilePath -> IO ()
=== FilePath -> FilePath
hackage FilePath
"base/docs/Prelude.html#v:mapM_"
        FilePath
"Data.Complex.(:+)" FilePath -> FilePath -> IO ()
=== FilePath -> FilePath
hackage FilePath
"base/docs/Data-Complex.html#v::-43-"
        FilePath
"\8801" FilePath -> FilePath -> IO ()
=== FilePath -> FilePath
hackage FilePath
"base-unicode-symbols/docs/Data-Eq-Unicode.html#v:-8801-"
        FilePath
"\8484" FilePath -> FilePath -> IO ()
=== FilePath -> FilePath
hackage FilePath
"base-unicode-symbols/docs/Prelude-Unicode.html#t:-8484-"
        FilePath
"copilot" FilePath -> FilePath -> IO ()
=== FilePath -> FilePath
hackage FilePath
"copilot"
        FilePath
"supero" FilePath -> FilePath -> IO ()
=== FilePath -> FilePath
hackage FilePath
"supero"
        FilePath
"set:stackage" FilePath -> FilePath -> IO ()
=== FilePath -> FilePath
hackage FilePath
"base"
        FilePath
"author:Neil-Mitchell" FilePath -> FilePath -> IO ()
=== FilePath -> FilePath
hackage FilePath
"filepath"
        -- FIXME: "author:Neil-M" === hackage "filepath"
        -- FIXME: "Data.Se.insert" === hackage "containers/docs/Data-Set.html#v:insert"
        FilePath
"set:-haskell-platform author:Neil-Mitchell" FilePath -> FilePath -> IO ()
=== FilePath -> FilePath
hackage FilePath
"safe"
        FilePath
"author:Neil-Mitchell category:Javascript" FilePath -> FilePath -> IO ()
=== FilePath -> FilePath
hackage FilePath
"js-jquery"
        FilePath
"( )" FilePath -> (FilePath -> Bool) -> IO ()
==$ (FilePath -> Bool -> Bool) -> Bool -> FilePath -> Bool
forall a b c. (a -> b -> c) -> b -> a -> c
flip FilePath -> Bool -> Bool
seq Bool
True -- used to segfault
        FilePath
"( -is:exact) package:base=" FilePath -> (FilePath -> Bool) -> IO ()
==$ (FilePath -> Bool -> Bool) -> Bool -> FilePath -> Bool
forall a b c. (a -> b -> c) -> b -> a -> c
flip FilePath -> Bool -> Bool
seq Bool
True
        FilePath
"(a -> b) -> [a] -> [b]" FilePath -> FilePath -> IO ()
=== FilePath -> FilePath
hackage FilePath
"base/docs/Prelude.html#v:map"
        FilePath
"Ord a => [a] -> [a]" FilePath -> FilePath -> IO ()
=== FilePath -> FilePath
hackage FilePath
"base/docs/Data-List.html#v:sort"
        FilePath
"ShakeOptions -> Int" FilePath -> FilePath -> IO ()
=== FilePath -> FilePath
hackage FilePath
"shake/docs/Development-Shake.html#v:shakeThreads"
        FilePath
"is:module" FilePath -> FilePath -> IO ()
=== FilePath -> FilePath
hackage FilePath
"base/docs/Prelude.html"
        FilePath
"visibleDataCons" FilePath -> FilePath -> IO ()
=== FilePath -> FilePath
hackage FilePath
"ghc/docs/TyCon.html#v:visibleDataCons"
        FilePath
"sparkle" FilePath -> FilePath -> IO ()
=== FilePath -> FilePath
hackage FilePath
"sparkle" -- library without Hoogle docs
        FilePath
"weeder" FilePath -> FilePath -> IO ()
=== FilePath -> FilePath
hackage FilePath
"weeder" -- executable in Stackage
        FilePath
"supero" FilePath -> FilePath -> IO ()
=== FilePath -> FilePath
hackage FilePath
"supero"

        FilePath -> [ExpectedQueryResult] -> IO ()
query FilePath
"(a -> [a]) -> [a] -> [a]"
            [ TargetMatcher -> ExpectedQueryResult
TopHit   (FilePath
"concatMap" FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base")
            , Int -> TargetMatcher -> ExpectedQueryResult
InTop Int
10 (FilePath
"(=<<)" FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base")
            , Int -> TargetMatcher -> ExpectedQueryResult
InTop Int
50 (FilePath
"(>>=)" FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base")
            ]
        FilePath -> [ExpectedQueryResult] -> IO ()
query FilePath
"[a] -> Maybe a"
            [ TargetMatcher -> ExpectedQueryResult
TopHit  (FilePath
"listToMaybe" FilePath -> FilePath -> TargetMatcher
`inModule` FilePath
"Data.Maybe")
            , Int -> TargetMatcher -> ExpectedQueryResult
InTop Int
10 (FilePath
"headMay"     FilePath -> FilePath -> TargetMatcher
`inModule` FilePath
"Safe")
            ]
        FilePath -> [ExpectedQueryResult] -> IO ()
query FilePath
"a -> [a]"
            [ Int -> TargetMatcher -> ExpectedQueryResult
InTop Int
10    (FilePath
"repeat"    FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base")
            , Int -> TargetMatcher -> ExpectedQueryResult
InTop Int
50    (FilePath
"singleton" FilePath -> FilePath -> TargetMatcher
`inModule` FilePath
"Util")
            , TargetMatcher -> ExpectedQueryResult
DoesNotFind (FilePath
"head"      FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base")
            , TargetMatcher -> ExpectedQueryResult
DoesNotFind (FilePath
"last"      FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base")
            , Int -> TargetMatcher -> ExpectedQueryResult
InTop Int
50    (FilePath
"pure"      FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base")
            , FilePath -> ExpectedQueryResult -> ExpectedQueryResult
KnownFailure FilePath
"" (ExpectedQueryResult -> ExpectedQueryResult)
-> ExpectedQueryResult -> ExpectedQueryResult
forall a b. (a -> b) -> a -> b
$ Int -> TargetMatcher -> ExpectedQueryResult
InTop Int
100   (FilePath
"return"    FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base")
            , FilePath -> ExpectedQueryResult -> ExpectedQueryResult
KnownFailure FilePath
"GitHub issue #267" (ExpectedQueryResult -> ExpectedQueryResult)
-> ExpectedQueryResult -> ExpectedQueryResult
forall a b. (a -> b) -> a -> b
$
                  (FilePath
"pure" FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base") TargetMatcher -> TargetMatcher -> ExpectedQueryResult
`AppearsBefore` (FilePath
"shrinkNothing" FilePath -> FilePath -> TargetMatcher
`inModule` FilePath
"Test.QuickCheck")
            -- , InTop 10 ("pure"   `inPackage` "base")
            -- , InTop 10 ("return" `inPackage` "base")
            ]
        FilePath -> [ExpectedQueryResult] -> IO ()
query FilePath
"[a] -> a"
            [ Int -> TargetMatcher -> ExpectedQueryResult
InTop Int
10 (FilePath
"head" FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base")
            , Int -> TargetMatcher -> ExpectedQueryResult
InTop Int
10 (FilePath
"last" FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base")
            , TargetMatcher -> ExpectedQueryResult
DoesNotFind (FilePath
"repeat" FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base")
            ]
        FilePath -> [ExpectedQueryResult] -> IO ()
query FilePath
"[Char] -> Char"
            [ Int -> TargetMatcher -> ExpectedQueryResult
InTop Int
10 (FilePath
"head" FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base")
            , Int -> TargetMatcher -> ExpectedQueryResult
RanksBelow Int
10 (FilePath
"mconcat" FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base")
            ]
        FilePath -> [ExpectedQueryResult] -> IO ()
query FilePath
"a -> b"
            [ TargetMatcher -> ExpectedQueryResult
TopHit (FilePath
"unsafeCoerce" FilePath -> FilePath -> TargetMatcher
`inModule` FilePath
"Unsafe.Coerce")
            , TargetMatcher -> ExpectedQueryResult
DoesNotFind (FilePath
"id" FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base") -- see GitHub issue #180
            , FilePath -> ExpectedQueryResult -> ExpectedQueryResult
KnownFailure FilePath
"GitHub issue #268" (ExpectedQueryResult -> ExpectedQueryResult)
-> ExpectedQueryResult -> ExpectedQueryResult
forall a b. (a -> b) -> a -> b
$
                  Int -> TargetMatcher -> ExpectedQueryResult
InTop Int
20 (FilePath
"coerce" FilePath -> FilePath -> TargetMatcher
`inModule` FilePath
"Data.Coerce")
            , FilePath -> ExpectedQueryResult -> ExpectedQueryResult
KnownFailure FilePath
"GitHub issue #268" (ExpectedQueryResult -> ExpectedQueryResult)
-> ExpectedQueryResult -> ExpectedQueryResult
forall a b. (a -> b) -> a -> b
$
                  Int -> TargetMatcher -> ExpectedQueryResult
InTop Int
5   (FilePath
"coerce" FilePath -> FilePath -> TargetMatcher
`inModule` FilePath
"Data.Coerce")
            ]
        FilePath -> [ExpectedQueryResult] -> IO ()
query FilePath
"String -> (Char -> Maybe Char) -> Maybe String" -- c/o @ndrssmn
            [ FilePath -> ExpectedQueryResult -> ExpectedQueryResult
KnownFailure FilePath
"GitHub issue #266" (ExpectedQueryResult -> ExpectedQueryResult)
-> ExpectedQueryResult -> ExpectedQueryResult
forall a b. (a -> b) -> a -> b
$
                  Int -> TargetMatcher -> ExpectedQueryResult
InTop Int
10 (FilePath
"traverse" FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base")
            , FilePath -> ExpectedQueryResult -> ExpectedQueryResult
KnownFailure FilePath
"GitHub issue #266" (ExpectedQueryResult -> ExpectedQueryResult)
-> ExpectedQueryResult -> ExpectedQueryResult
forall a b. (a -> b) -> a -> b
$
                  Int -> TargetMatcher -> ExpectedQueryResult
InTop Int
10 (FilePath
"mapM" FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base")
            , FilePath -> ExpectedQueryResult -> ExpectedQueryResult
KnownFailure FilePath
"GitHub issue #266" (ExpectedQueryResult -> ExpectedQueryResult)
-> ExpectedQueryResult -> ExpectedQueryResult
forall a b. (a -> b) -> a -> b
$
                  Int -> TargetMatcher -> ExpectedQueryResult
InTop Int
10 (FilePath
"forM" FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base")
            ]
        FilePath -> [ExpectedQueryResult] -> IO ()
query FilePath
"a -> [(a,b)] -> b"
            [ FilePath -> ExpectedQueryResult -> ExpectedQueryResult
KnownFailure FilePath
"GitHub issue #267" (ExpectedQueryResult -> ExpectedQueryResult)
-> ExpectedQueryResult -> ExpectedQueryResult
forall a b. (a -> b) -> a -> b
$
                  TargetMatcher -> ExpectedQueryResult
TopHit  (FilePath
"lookup" FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base")
            , Int -> TargetMatcher -> ExpectedQueryResult
InTop Int
3 (FilePath
"lookup" FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base")
            , TargetMatcher -> ExpectedQueryResult
DoesNotFind (FilePath
"zip" FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base")
            ]
        FilePath -> [ExpectedQueryResult] -> IO ()
query FilePath
"[(a,b)] -> a -> b"
            [ FilePath -> ExpectedQueryResult -> ExpectedQueryResult
KnownFailure FilePath
"GitHub issue #267" (ExpectedQueryResult -> ExpectedQueryResult)
-> ExpectedQueryResult -> ExpectedQueryResult
forall a b. (a -> b) -> a -> b
$
                  TargetMatcher -> ExpectedQueryResult
TopHit (FilePath
"lookup" FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base")
            , Int -> TargetMatcher -> ExpectedQueryResult
InTop Int
3 (FilePath
"lookup" FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base")
            , TargetMatcher -> ExpectedQueryResult
DoesNotFind (FilePath
"zip" FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base")
            ]
        FilePath -> [ExpectedQueryResult] -> IO ()
query FilePath
"(a -> m b) -> t a -> m (t b)" -- see GitHub issue #218
            [ Int -> TargetMatcher -> ExpectedQueryResult
InTop Int
10 (FilePath
"traverse" FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base")
            , Int -> TargetMatcher -> ExpectedQueryResult
InTop Int
10 (FilePath
"mapConcurrently" FilePath -> FilePath -> TargetMatcher
`inModule` FilePath
"Control.Concurrent.Async.Lifted")
            , Int -> TargetMatcher -> ExpectedQueryResult
InTop Int
10 (FilePath
"mapM" FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base")
            , Int -> TargetMatcher -> ExpectedQueryResult
InTop Int
50 (FilePath
"forM" FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base")
            ]
        FilePath -> [ExpectedQueryResult] -> IO ()
query FilePath
"m (m a) -> m a" -- see GitHub issue #252
            [ TargetMatcher -> ExpectedQueryResult
TopHit (FilePath
"join" FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base")
            ]
        FilePath -> [ExpectedQueryResult] -> IO ()
query FilePath
"(a -> b -> c) -> (a -> b) -> a -> c"
            [ FilePath -> ExpectedQueryResult -> ExpectedQueryResult
KnownFailure FilePath
"GitHub issue #269" (ExpectedQueryResult -> ExpectedQueryResult)
-> ExpectedQueryResult -> ExpectedQueryResult
forall a b. (a -> b) -> a -> b
$
                  Int -> TargetMatcher -> ExpectedQueryResult
InTop Int
5 (FilePath
"ap" FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base")
            , FilePath -> ExpectedQueryResult -> ExpectedQueryResult
KnownFailure FilePath
"GitHub issue #269" (ExpectedQueryResult -> ExpectedQueryResult)
-> ExpectedQueryResult -> ExpectedQueryResult
forall a b. (a -> b) -> a -> b
$
                  Int -> TargetMatcher -> ExpectedQueryResult
InTop Int
5 (FilePath
"(<*>)" FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base")
            ]
        FilePath -> [ExpectedQueryResult] -> IO ()
query FilePath
"String -> Int"
            [ TargetMatcher -> ExpectedQueryResult
DoesNotFind (FilePath
"cursorUpCode" FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"ansi-terminal")
            , FilePath -> ExpectedQueryResult -> ExpectedQueryResult
KnownFailure FilePath
"GitHub issue #266" (ExpectedQueryResult -> ExpectedQueryResult)
-> ExpectedQueryResult -> ExpectedQueryResult
forall a b. (a -> b) -> a -> b
$ Int -> TargetMatcher -> ExpectedQueryResult
InTop Int
20 (FilePath
"length" FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base")
            ]
        FilePath -> [ExpectedQueryResult] -> IO ()
query FilePath
"(a -> b) -> f a -> f b"
            [ TargetMatcher -> ExpectedQueryResult
TopHit (FilePath
"fmap" FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base")
            ]
        FilePath -> [ExpectedQueryResult] -> IO ()
query FilePath
"(a -> b) -> Maybe a -> Maybe b"
            [ Int -> TargetMatcher -> ExpectedQueryResult
InTop Int
3 (FilePath
"fmap" FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base")
            ]
        FilePath -> [ExpectedQueryResult] -> IO ()
query FilePath
"IO a -> m a"
            [ Int -> TargetMatcher -> ExpectedQueryResult
InTop Int
5 (FilePath
"liftIO" FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base")
            ]
        FilePath -> [ExpectedQueryResult] -> IO ()
query FilePath
"a -> m a" -- see GitHub issue #180
            [ Int -> TargetMatcher -> ExpectedQueryResult
InTop Int
20 (FilePath
"pure" FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base")
            , Int -> TargetMatcher -> ExpectedQueryResult
InTop Int
50 (FilePath
"return" FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base")
            , FilePath -> ExpectedQueryResult -> ExpectedQueryResult
KnownFailure FilePath
"GitHub issue #267" (ExpectedQueryResult -> ExpectedQueryResult)
-> ExpectedQueryResult -> ExpectedQueryResult
forall a b. (a -> b) -> a -> b
$
                  Int -> TargetMatcher -> ExpectedQueryResult
InTop Int
5 (FilePath
"pure" FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base")
            , FilePath -> ExpectedQueryResult -> ExpectedQueryResult
KnownFailure FilePath
"GitHub issue #267" (ExpectedQueryResult -> ExpectedQueryResult)
-> ExpectedQueryResult -> ExpectedQueryResult
forall a b. (a -> b) -> a -> b
$
                  Int -> TargetMatcher -> ExpectedQueryResult
InTop Int
3 (FilePath
"return" FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base")
            ]
        FilePath -> [ExpectedQueryResult] -> IO ()
query FilePath
"(a -> a) -> k -> Map k a -> Map k a" -- see GitHub issue #180
            [ TargetMatcher -> ExpectedQueryResult
TopHit (FilePath
"adjust" FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"containers")
            ]
        FilePath -> [ExpectedQueryResult] -> IO ()
query FilePath
"Int -> Integer" -- see GitHub issue #127
            [ Int -> TargetMatcher -> ExpectedQueryResult
InTop Int
40 (FilePath
"toInteger" FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base")
            , FilePath -> ExpectedQueryResult -> ExpectedQueryResult
KnownFailure FilePath
"GitHub issue #127" (ExpectedQueryResult -> ExpectedQueryResult)
-> ExpectedQueryResult -> ExpectedQueryResult
forall a b. (a -> b) -> a -> b
$
                  TargetMatcher -> ExpectedQueryResult
TopHit (FilePath
"toInteger" FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base")
            ]
        FilePath -> [ExpectedQueryResult] -> IO ()
query FilePath
"Integer -> Int" -- see GitHub issue #127
            [ Int -> TargetMatcher -> ExpectedQueryResult
InTop Int
40 (FilePath
"fromInteger" FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base")
            , FilePath -> ExpectedQueryResult -> ExpectedQueryResult
KnownFailure FilePath
"GitHub issue #127" (ExpectedQueryResult -> ExpectedQueryResult)
-> ExpectedQueryResult -> ExpectedQueryResult
forall a b. (a -> b) -> a -> b
$
                  TargetMatcher -> ExpectedQueryResult
TopHit (FilePath
"fromInteger" FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"base")
            ]
        FilePath -> [ExpectedQueryResult] -> IO ()
query FilePath
"[Parser a] -> Parser a" -- see GitHub issue #90
            [ FilePath -> ExpectedQueryResult -> ExpectedQueryResult
KnownFailure FilePath
"Todo" (ExpectedQueryResult -> ExpectedQueryResult)
-> ExpectedQueryResult -> ExpectedQueryResult
forall a b. (a -> b) -> a -> b
$ Int -> TargetMatcher -> ExpectedQueryResult
InTop Int
10 (FilePath
"choice" FilePath -> FilePath -> TargetMatcher
`inPackage` FilePath
"attoparsec")
            ]

        let tags :: [FilePath]
tags = StoreRead -> [FilePath]
completionTags StoreRead
store
        let asserts :: Bool -> FilePath -> IO ()
asserts Bool
b FilePath
x = if Bool
b then Char -> IO ()
putChar Char
'.' else FilePath -> IO ()
forall a. HasCallStack => FilePath -> IO a
errorIO (FilePath -> IO ()) -> FilePath -> IO ()
forall a b. (a -> b) -> a -> b
$ FilePath
"Assertion failed, got False for " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
x
        Bool -> FilePath -> IO ()
asserts (FilePath
"set:haskell-platform" FilePath -> [FilePath] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [FilePath]
tags) FilePath
"set:haskell-platform `elem` tags"
        Bool -> FilePath -> IO ()
asserts (FilePath
"author:Neil-Mitchell" FilePath -> [FilePath] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [FilePath]
tags) FilePath
"author:Neil-Mitchell `elem` tags"
        Bool -> FilePath -> IO ()
asserts (FilePath
"package:uniplate" FilePath -> [FilePath] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [FilePath]
tags) FilePath
"package:uniplate `elem` tags"
        Bool -> FilePath -> IO ()
asserts (FilePath
"package:supero" FilePath -> [FilePath] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [FilePath]
tags) FilePath
"package:supero `notElem` tags"


--------------------------------------------------------------------------------------------------
-- Test helpers

data ExpectedQueryResult
    = TopHit TargetMatcher
    | InTop Int TargetMatcher
    | RanksBelow Int TargetMatcher
    | DoesNotFind TargetMatcher
    | AppearsBefore TargetMatcher TargetMatcher
    | NoHits
    | KnownFailure String ExpectedQueryResult

expected :: ExpectedQueryResult -> String
expected :: ExpectedQueryResult -> FilePath
expected = \case
    TopHit TargetMatcher
tm       -> TargetMatcher -> FilePath
showTM TargetMatcher
tm FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
" as first hit."
    InTop Int
n TargetMatcher
tm      -> TargetMatcher -> FilePath
showTM TargetMatcher
tm FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
" in top " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ Int -> FilePath
forall a. Show a => a -> FilePath
show Int
n FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
" hits."
    RanksBelow Int
n TargetMatcher
tm -> TargetMatcher -> FilePath
showTM TargetMatcher
tm FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
" not in top " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ Int -> FilePath
forall a. Show a => a -> FilePath
show Int
n FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
" hits."
    DoesNotFind TargetMatcher
tm  -> FilePath
"to not match " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ TargetMatcher -> FilePath
showTM TargetMatcher
tm FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
"."
    AppearsBefore TargetMatcher
tm TargetMatcher
tm' -> TargetMatcher -> FilePath
showTM TargetMatcher
tm FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
" to appear before " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ TargetMatcher -> FilePath
showTM TargetMatcher
tm' FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
"."
    ExpectedQueryResult
NoHits          -> FilePath
"no results."
    KnownFailure FilePath
why ExpectedQueryResult
qr -> FilePath
"to see a failure (" FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
why FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
"): \"" FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ ExpectedQueryResult -> FilePath
expected ExpectedQueryResult
qr FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
"\" But it succeeded!"

data TestResult
    = Success
    | Failure
    | ExpectedFailure
    | UnexpectedSuccess

matchQR :: ExpectedQueryResult -> [[Target]] -> TestResult
matchQR :: ExpectedQueryResult -> [[Target]] -> TestResult
matchQR ExpectedQueryResult
qr [[Target]]
res = case ExpectedQueryResult
qr of
    TopHit TargetMatcher
tm        -> Bool -> TestResult
success (Bool -> TestResult) -> Bool -> TestResult
forall a b. (a -> b) -> a -> b
$ (Target -> Bool) -> [Target] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (TargetMatcher -> Target -> Bool
runTargetMatcher TargetMatcher
tm) ([[Target]] -> [Target]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([[Target]] -> [Target]) -> [[Target]] -> [Target]
forall a b. (a -> b) -> a -> b
$ Int -> [[Target]] -> [[Target]]
forall a. Int -> [a] -> [a]
take Int
1 [[Target]]
res)
    InTop Int
n TargetMatcher
tm       -> Bool -> TestResult
success (Bool -> TestResult) -> Bool -> TestResult
forall a b. (a -> b) -> a -> b
$ (Target -> Bool) -> [Target] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (TargetMatcher -> Target -> Bool
runTargetMatcher TargetMatcher
tm) ([[Target]] -> [Target]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([[Target]] -> [Target]) -> [[Target]] -> [Target]
forall a b. (a -> b) -> a -> b
$ Int -> [[Target]] -> [[Target]]
forall a. Int -> [a] -> [a]
take Int
n [[Target]]
res)
    RanksBelow Int
n TargetMatcher
tm  -> Bool -> TestResult
success (Bool -> TestResult) -> Bool -> TestResult
forall a b. (a -> b) -> a -> b
$ (Target -> Bool) -> [Target] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (TargetMatcher -> Target -> Bool
runTargetMatcher TargetMatcher
tm) ([[Target]] -> [Target]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([[Target]] -> [Target]) -> [[Target]] -> [Target]
forall a b. (a -> b) -> a -> b
$ Int -> [[Target]] -> [[Target]]
forall a. Int -> [a] -> [a]
drop Int
n [[Target]]
res)
    DoesNotFind TargetMatcher
tm   -> Bool -> TestResult
success (Bool -> TestResult) -> Bool -> TestResult
forall a b. (a -> b) -> a -> b
$ Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ (Target -> Bool) -> [Target] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (TargetMatcher -> Target -> Bool
runTargetMatcher TargetMatcher
tm) ([[Target]] -> [Target]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[Target]]
res)
    AppearsBefore TargetMatcher
tm TargetMatcher
tm' -> Bool -> TestResult
success (Bool -> TestResult) -> Bool -> TestResult
forall a b. (a -> b) -> a -> b
$ ( Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
(<) (Integer -> Integer -> Bool)
-> Maybe Integer -> Maybe (Integer -> Bool)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TargetMatcher -> Maybe Integer
forall b. (Enum b, Num b) => TargetMatcher -> Maybe b
matchIdx TargetMatcher
tm Maybe (Integer -> Bool) -> Maybe Integer -> Maybe Bool
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> TargetMatcher -> Maybe Integer
forall b. (Enum b, Num b) => TargetMatcher -> Maybe b
matchIdx TargetMatcher
tm' ) Maybe Bool -> Maybe Bool -> Bool
forall a. Eq a => a -> a -> Bool
== Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True
    ExpectedQueryResult
NoHits           -> Bool -> TestResult
success (Bool -> TestResult) -> Bool -> TestResult
forall a b. (a -> b) -> a -> b
$ [[Target]] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [[Target]]
res
    KnownFailure FilePath
_ ExpectedQueryResult
qr' -> case ExpectedQueryResult -> [[Target]] -> TestResult
matchQR ExpectedQueryResult
qr' [[Target]]
res of
        TestResult
Success           -> TestResult
UnexpectedSuccess
        TestResult
Failure           -> TestResult
ExpectedFailure
        TestResult
ExpectedFailure   -> TestResult
Failure
        TestResult
UnexpectedSuccess -> TestResult
Failure
  where
    success :: Bool -> TestResult
success Bool
p = if Bool
p then TestResult
Success else TestResult
Failure
    matchIdx :: TargetMatcher -> Maybe b
matchIdx TargetMatcher
tm = ((b, Target) -> b) -> Maybe (b, Target) -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (b, Target) -> b
forall a b. (a, b) -> a
fst (Maybe (b, Target) -> Maybe b) -> Maybe (b, Target) -> Maybe b
forall a b. (a -> b) -> a -> b
$ ((b, Target) -> Bool) -> [(b, Target)] -> Maybe (b, Target)
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find (TargetMatcher -> Target -> Bool
runTargetMatcher TargetMatcher
tm (Target -> Bool) -> ((b, Target) -> Target) -> (b, Target) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (b, Target) -> Target
forall a b. (a, b) -> b
snd) (b -> [Target] -> [(b, Target)]
forall a b. Enum a => a -> [b] -> [(a, b)]
zipFrom b
0 ([Target] -> [(b, Target)]) -> [Target] -> [(b, Target)]
forall a b. (a -> b) -> a -> b
$ [[Target]] -> [Target]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[Target]]
res)

data TargetMatcher
    = MatchFunctionInModule  String String
    | MatchFunctionInPackage String String

showTM :: TargetMatcher -> String
showTM :: TargetMatcher -> FilePath
showTM = \case
    MatchFunctionInModule  FilePath
f FilePath
m -> FilePath
m FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
"'s " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
f
    MatchFunctionInPackage FilePath
f FilePath
p -> FilePath
f FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
" from package " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
p

runTargetMatcher :: TargetMatcher -> Target -> Bool
runTargetMatcher :: TargetMatcher -> Target -> Bool
runTargetMatcher TargetMatcher
matcher Target{FilePath
Maybe (FilePath, FilePath)
targetDocs :: FilePath
targetItem :: FilePath
targetType :: FilePath
targetModule :: Maybe (FilePath, FilePath)
targetPackage :: Maybe (FilePath, FilePath)
targetURL :: FilePath
targetDocs :: Target -> FilePath
targetItem :: Target -> FilePath
targetType :: Target -> FilePath
targetModule :: Target -> Maybe (FilePath, FilePath)
targetPackage :: Target -> Maybe (FilePath, FilePath)
targetURL :: Target -> FilePath
..} = case TargetMatcher
matcher of
    MatchFunctionInModule FilePath
f FilePath
m ->
        FilePath -> Maybe FilePath
forall a. a -> Maybe a
Just FilePath
m Maybe FilePath -> Maybe FilePath -> Bool
forall a. Eq a => a -> a -> Bool
== ((FilePath, FilePath) -> FilePath)
-> Maybe (FilePath, FilePath) -> Maybe FilePath
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (FilePath, FilePath) -> FilePath
forall a b. (a, b) -> a
fst Maybe (FilePath, FilePath)
targetModule
        Bool -> Bool -> Bool
&& FilePath
f FilePath -> FilePath -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf` FilePath -> FilePath
unHTML FilePath
targetItem
    MatchFunctionInPackage FilePath
f FilePath
m ->
        FilePath -> Maybe FilePath
forall a. a -> Maybe a
Just FilePath
m Maybe FilePath -> Maybe FilePath -> Bool
forall a. Eq a => a -> a -> Bool
== ((FilePath, FilePath) -> FilePath)
-> Maybe (FilePath, FilePath) -> Maybe FilePath
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (FilePath, FilePath) -> FilePath
forall a b. (a, b) -> a
fst Maybe (FilePath, FilePath)
targetPackage
        Bool -> Bool -> Bool
&& FilePath
f FilePath -> FilePath -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf` FilePath -> FilePath
unHTML FilePath
targetItem

inModule :: String -> String -> TargetMatcher
inModule :: FilePath -> FilePath -> TargetMatcher
inModule = FilePath -> FilePath -> TargetMatcher
MatchFunctionInModule

inPackage :: String -> String -> TargetMatcher
inPackage :: FilePath -> FilePath -> TargetMatcher
inPackage = FilePath -> FilePath -> TargetMatcher
MatchFunctionInPackage

-- Group duplicated targets (e.g. re-exports) together.
deDup :: [Target] -> [[Target]]
deDup :: [Target] -> [[Target]]
deDup [Target]
tgts = Map Int [Target] -> [[Target]]
forall k a. Map k a -> [a]
Map.elems ([(Int, [Target])] -> Map Int [Target]
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList ([(Int, [Target])] -> Map Int [Target])
-> [(Int, [Target])] -> Map Int [Target]
forall a b. (a -> b) -> a -> b
$ Map Target (Int, [Target]) -> [(Int, [Target])]
forall k a. Map k a -> [a]
Map.elems Map Target (Int, [Target])
tgtMap)
  where
    tgtMap :: Map.Map Target (Int, [Target])
    tgtMap :: Map Target (Int, [Target])
tgtMap = ((Int, [Target]) -> (Int, [Target]) -> (Int, [Target]))
-> [(Target, (Int, [Target]))] -> Map Target (Int, [Target])
forall k a. Ord k => (a -> a -> a) -> [(k, a)] -> Map k a
Map.fromListWith (\(Int
n, [Target]
ts) (Int
n', [Target]
ts') -> (Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
n Int
n', [Target]
ts [Target] -> [Target] -> [Target]
forall a. [a] -> [a] -> [a]
++ [Target]
ts'))
             ([(Target, (Int, [Target]))] -> Map Target (Int, [Target]))
-> [(Target, (Int, [Target]))] -> Map Target (Int, [Target])
forall a b. (a -> b) -> a -> b
$ (Int -> Target -> (Target, (Int, [Target])))
-> Int -> [Target] -> [(Target, (Int, [Target]))]
forall a b c. Enum a => (a -> b -> c) -> a -> [b] -> [c]
zipWithFrom (\Int
n Target
t -> (Target -> Target
simple Target
t, (Int
n, [Target
t]))) Int
0 [Target]
tgts

    simple :: Target -> Target
    simple :: Target -> Target
simple Target
t = Target
t { targetURL :: FilePath
targetURL = FilePath
"", targetPackage :: Maybe (FilePath, FilePath)
targetPackage = Maybe (FilePath, FilePath)
forall a. Maybe a
Nothing, targetModule :: Maybe (FilePath, FilePath)
targetModule = Maybe (FilePath, FilePath)
forall a. Maybe a
Nothing }