diff --git a/CHANGES.txt b/CHANGES.txt
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,5 +1,11 @@
 Changelog for Hoogle
 
+5.0.13
+    #219, treat the query "a->b" the same as "a -> b"
+    #215, if a specified module/package is missing, give no results
+    #220, start on port 8080 by default
+    Rely on the fact ghc API is now on Hackage
+    #217, fix the mode tag propagating to child links
 5.0.12
     #210, expose targetInfo and targetSearchDisplay
 5.0.11
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -67,7 +67,7 @@
 To ensure you have data files for the Hackage modules, you will first need to
 type:
 
-    hoogle data
+    hoogle generate
 
 Which will download and build Hoogle databases.
 
diff --git a/cbits/text_search.c b/cbits/text_search.c
--- a/cbits/text_search.c
+++ b/cbits/text_search.c
@@ -30,7 +30,7 @@
 
     for (char* cs = xs; ; cs++)
     {
-        char c = *cs;
+        unsigned char c = *cs;
         if (c == 0)
         {
             if (cs[1] == 0) break;
diff --git a/hoogle.cabal b/hoogle.cabal
--- a/hoogle.cabal
+++ b/hoogle.cabal
@@ -1,7 +1,7 @@
 cabal-version:      >= 1.18
 build-type:         Simple
 name:               hoogle
-version:            5.0.12
+version:            5.0.13
 license:            BSD3
 license-file:       LICENSE
 category:           Development
@@ -15,7 +15,7 @@
     or by approximate type signature.
 homepage:           http://hoogle.haskell.org/
 bug-reports:        https://github.com/ndmitchell/hoogle/issues
-tested-with:        GHC==8.0.2, GHC==7.10.3, GHC==7.8.4, GHC==7.6.3
+tested-with:        GHC==8.2.1, GHC==8.0.2, GHC==7.10.3
 extra-doc-files:
     README.md
     CHANGES.txt
@@ -66,13 +66,13 @@
         directory,
         extra >= 1.4,
         filepath,
+        old-locale,
         haskell-src-exts >= 1.18 && < 1.20,
         http-conduit,
         http-types,
         js-flot,
         js-jquery,
         mmap,
-        old-locale,
         process,
         process-extras,
         resourcet,
diff --git a/src/Action/CmdLine.hs b/src/Action/CmdLine.hs
--- a/src/Action/CmdLine.hs
+++ b/src/Action/CmdLine.hs
@@ -118,13 +118,13 @@
     {download = def &= help "Download all files from the web"
     ,insecure = def &= help "Allow insecure HTTPS connections"
     ,include = def &= args &= typ "PACKAGE"
-    ,local_ = def &= opt "" &= help "Index local packages"
+    ,local_ = def &= opt "" &= help "Index local packages and link to local haddock docs"
     ,haddock = def &= help "Use local haddocks"
     ,debug = def &= help "Generate debug information"
     } &= help "Generate Hoogle databases"
 
 server = Server
-    {port = 80 &= typ "INT" &= help "Port number"
+    {port = 8080 &= typ "INT" &= help "Port number"
     ,cdn = "" &= typ "URL" &= help "URL prefix to use"
     ,logs = "" &= opt "log.txt" &= typFile &= help "File to log requests to (defaults to stdout)"
     ,local = False &= help "Allow following file:// links, restricts to 127.0.0.1  Set --host explicitely (including to '*' for any host) to override the localhost-only behaviour"
diff --git a/src/Action/Generate.hs b/src/Action/Generate.hs
--- a/src/Action/Generate.hs
+++ b/src/Action/Generate.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE ViewPatterns, TupleSections, RecordWildCards, ScopedTypeVariables, PatternGuards #-}
+{-# OPTIONS_GHC -fno-warn-warnings-deprecations #-} -- getGCStats became getRTSStats
 
 module Action.Generate(actionGenerate) where
 
@@ -98,7 +99,6 @@
 readHaskellOnline timing settings download = do
     stackage <- download "haskell-stackage.txt" "https://www.stackage.org/lts/cabal.config"
     platform <- download "haskell-platform.txt" "https://raw.githubusercontent.com/haskell/haskell-platform/master/hptool/src/Releases2015.hs"
-    ghcapi   <- download "haskell-ghcapi.txt" $ "https://downloads.haskell.org/~ghc/" ++ ghcApiVersion ++ "/docs/html/libraries/ghc-" ++ ghcApiVersion ++ "/ghc.txt"
     cabals   <- download "haskell-cabal.tar.gz" "https://hackage.haskell.org/packages/index.tar.gz"
     hoogles  <- download "haskell-hoogle.tar.gz" "https://hackage.haskell.org/packages/hoogle.tar.gz"
 
@@ -120,9 +120,6 @@
             tar <- liftIO $ tarballReadFiles hoogles
             forM_ tar $ \(takeBaseName -> name, src) ->
                 yield (name, hackagePackageURL name, src)
-            src <- liftIO $ strReadFile ghcapi
-            let url = "https://downloads.haskell.org/~ghc/" ++ ghcApiVersion ++ "/docs/html/libraries/ghc-" ++ ghcApiVersion ++ "/"
-            yield ("ghc", url, lstrFromChunks [src])
     return (cbl, want, source)
 
 
diff --git a/src/Action/Search.hs b/src/Action/Search.hs
--- a/src/Action/Search.hs
+++ b/src/Action/Search.hs
@@ -23,7 +23,6 @@
 import Action.CmdLine
 import General.Util
 
-
 -- -- generate all
 -- @tagsoup -- generate tagsoup
 -- @tagsoup filter -- search the tagsoup package
@@ -80,7 +79,7 @@
 
 search :: StoreRead -> [Query] -> ([Query], [Target])
 search store qs = runIdentity $ do
-    (qs, exact, filt, list) <- return $ applyTags store qs
+    (qs, exact, filt, list) <- return $ applyTags store  qs
     is <- case (filter isQueryName qs, filter isQueryType qs) of
         ([], [] ) -> return list
         ([], t:_) -> return $ searchTypes store $ hseToSig $ fromQueryType t
@@ -94,6 +93,11 @@
 
 action_search_test :: Bool -> FilePath -> IO ()
 action_search_test sample database = testing "Action.Search.search" $ withSearch database $ \store -> do
+    let noResults a = do
+          res <- return $ snd $ search store (parseQuery a)
+          case res of
+              [] -> putChar '.'
+              _ -> error $ "Searching for: " ++ show a ++ "\nGot: " ++ show (take 1 res) ++ "\n expected none"
     let a ==$ f = do
             res <- return $ snd $ search store (parseQuery a)
             case res of
@@ -112,6 +116,8 @@
         "Prelude" === hackage "base/docs/Prelude.html"
         "map" === hackage "base/docs/Prelude.html#v:map"
         "map package:base" === hackage "base/docs/Prelude.html#v:map"
+        noResults "map package:package-not-in-db"
+        noResults "map module:Module.Not.In.Db"
         "True" === hackage "base/docs/Prelude.html#v:True"
         "Bool" === hackage "base/docs/Prelude.html#t:Bool"
         "String" === hackage "base/docs/Prelude.html#t:String"
@@ -136,14 +142,14 @@
         -- FIXME: "author:Neil-M" === hackage "filepath"
         -- FIXME: "Data.Se.insert" === hackage "containers/docs/Data-Set.html#v:insert"
         "set:-haskell-platform author:Neil-Mitchell" === hackage "safe"
-        "author:Neil-Mitchell category:Development" === hackage "derive"
+        "author:Neil-Mitchell category:Development" === hackage "hlint"
         "( )" ==$ flip seq True -- used to segfault
         "( -is:exact) package:base=" ==$ flip seq True
         "(a -> b) -> [a] -> [b]" === hackage "base/docs/Prelude.html#v:map"
         "Ord a => [a] -> [a]" === hackage "base/docs/Data-List.html#v:sort"
         "ShakeOptions -> Int" === hackage "shake/docs/Development-Shake.html#v:shakeThreads"
         "is:module" === hackage "base/docs/Prelude.html"
-        "visibleDataCons" === ("https://downloads.haskell.org/~ghc/" ++ ghcApiVersion ++ "/docs/html/libraries/ghc-" ++ ghcApiVersion ++ "/TyCon.html#v:visibleDataCons")
+        "visibleDataCons" === hackage "ghc/docs/TyCon.html#v:visibleDataCons"
 
         let tags = completionTags store
         let asserts b x = if b then putChar '.' else error $ "Assertion failed, got False for " ++ x
diff --git a/src/Action/Server.hs b/src/Action/Server.hs
--- a/src/Action/Server.hs
+++ b/src/Action/Server.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE ViewPatterns, TupleSections, RecordWildCards, ScopedTypeVariables, PatternGuards #-}
+{-# OPTIONS_GHC -fno-warn-warnings-deprecations #-} -- getGCStats became getRTSStats
 
 module Action.Server(actionServer, actionReplay, action_server_test_, action_server_test) where
 
@@ -85,7 +86,8 @@
         let qSource = grab "hoogle" ++ filter (/= "set:stackage") qScope
         let q = concatMap parseQuery qSource
         let (q2, results) = search store q
-        let body = showResults local haddock inputArgs q2 $ dedupeTake 25 (\t -> t{targetURL="",targetPackage=Nothing, targetModule=Nothing}) results
+        let body = showResults local haddock (filter ((/= "mode") . fst) inputArgs) q2 $
+                dedupeTake 25 (\t -> t{targetURL="",targetPackage=Nothing, targetModule=Nothing}) results
         case lookup "mode" $ reverse inputArgs of
             Nothing | qSource /= [] -> fmap OutputHTML $ templateRender templateIndex $ map (second str)
                         [("tags",tagOptions qScope)
diff --git a/src/General/Conduit.hs b/src/General/Conduit.hs
--- a/src/General/Conduit.hs
+++ b/src/General/Conduit.hs
@@ -4,10 +4,10 @@
 module General.Conduit(
     module Data.Conduit, MonadIO, liftIO,
     sourceList, sinkList, sourceLStr,
-    foldC, mapC, mapMaybeC, mapAccumC, filterC, concatC,
+    mapC, mapAccumC, filterC,
     mapMC, mapAccumMC,
     (|$|), pipelineC, groupOnLastC,
-    zipFromC, linesC, linesCR
+    zipFromC, linesCR
     ) where
 
 import Data.Conduit
@@ -23,11 +23,8 @@
 import Prelude
 
 
-concatC = C.concat
 mapC = C.map
 mapMC = C.mapM
-foldC = C.fold
-mapMaybeC = C.mapMaybe
 mapAccumC f = C.mapAccum (\x a -> a `seq` f a x)
 mapAccumMC f = C.mapAccumM (\x a -> a `seq` f a x)
 filterC = C.filter
diff --git a/src/General/Store.hs b/src/General/Store.hs
--- a/src/General/Store.hs
+++ b/src/General/Store.hs
@@ -2,7 +2,7 @@
 
 module General.Store(
     Typeable, Stored,
-    intSize, intFromBS, intToBS, encodeBS, decodeBS,
+    intSize, intFromBS, intToBS, encodeBS,
     StoreWrite, storeWriteFile, storeWrite, storeWritePart,
     StoreRead, storeReadFile, storeRead,
     Jagged, jaggedFromList, jaggedAsk,
diff --git a/src/General/Timing.hs b/src/General/Timing.hs
--- a/src/General/Timing.hs
+++ b/src/General/Timing.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE RecordWildCards #-}
+{-# OPTIONS_GHC -fno-warn-warnings-deprecations #-} -- getGCStats became getRTSStats
 
 module General.Timing(Timing, withTiming, timed, timedOverwrite) where
 
diff --git a/src/General/Util.hs b/src/General/Util.hs
--- a/src/General/Util.hs
+++ b/src/General/Util.hs
@@ -6,12 +6,12 @@
     fromDeclHead, fromContext, fromIParen, fromInstHead,
     tarballReadFiles,
     isUpper1, isAlpha1,
-    splitPair, joinPair,
-    testing, testing_, testEq,
+    joinPair,
+    testing, testEq,
     showUTCTime,
     strict,
     withs,
-    escapeHTML, unescapeHTML, innerTextHTML, unHTML, tag, tag_,
+    escapeHTML, unescapeHTML, unHTML, tag, tag_,
     takeSortOn,
     Average, toAverage, fromAverage,
     inRanges,
@@ -19,9 +19,8 @@
     parseTrailingVersion,
     exitFail,
     prettyTable,
-    ghcApiVersion,
     hackagePackageURL, hackageModuleURL, hackageDeclURL, ghcModuleURL,
-    minimum', maximum', minimumBy', maximumBy',
+    minimum', maximum',
     general_util_test
     ) where
 
@@ -56,9 +55,6 @@
 
 -- | A URL, complete with a @https:@ prefix.
 type URL = String
-
-ghcApiVersion :: String
-ghcApiVersion = "8.0.1"
 
 exitFail :: String -> IO ()
 exitFail msg = do
diff --git a/src/Output/Tags.hs b/src/Output/Tags.hs
--- a/src/Output/Tags.hs
+++ b/src/Output/Tags.hs
@@ -103,19 +103,20 @@
 ---------------------------------------------------------------------
 -- TAG SEMANTICS
 
--- | Given a tag, find the ranges of identifiers it covers
-resolveTag :: StoreRead -> Tag -> (Maybe Tag, [(TargetId,TargetId)])
+-- | Given a tag, find the ranges of identifiers it covers (if it restricts the range)
+-- An empty range means an empty result, while a Nothing means a search on the entire range
+resolveTag :: StoreRead -> Tag -> (Tag, Maybe [(TargetId,TargetId)])
 resolveTag store x = case x of
-    IsExact -> (Just IsExact, [])
-    IsPackage -> (Just IsPackage, map (dupe . fst) $ V.toList packageIds)
-    IsModule -> (Just IsModule, map (dupe . fst) $ V.toList moduleIds)
-    EqPackage (BS.pack . lower -> val)
+    IsExact -> (IsExact, Nothing)
+    IsPackage -> (IsPackage, Just $ map (dupe . fst) $ V.toList packageIds)
+    IsModule -> (IsModule, Just $ map (dupe . fst) $ V.toList moduleIds)
+    EqPackage orig@(BS.pack -> val)
         -- look for people who are an exact prefix, sort by remaining length, if there are ties, pick the first one
         | res@(_:_) <- [(BS.length x, (i,x)) | (i,x) <- zip [0..] $ split0 packageNames, val `BS.isPrefixOf` x]
-            -> let (i,x) = snd $ minimumBy (compare `on` fst) res in (Just $ EqPackage $ BS.unpack x, [packageIds V.! i])
-        | otherwise -> (Nothing, [])
-    EqModule x -> (Just $ EqModule x, map (moduleIds V.!) $ findIndices (eqModule $ lower x) $ split0 moduleNames)
-    EqCategory cat val -> (Just $ EqCategory cat val, concat
+            -> let (i,x) = snd $ minimumBy (compare `on` fst) res in (EqPackage $ BS.unpack x, Just [packageIds V.! i])
+        | otherwise -> (EqPackage orig , Just [])
+    EqModule x -> (EqModule x, Just $ map (moduleIds V.!) $ findIndices (eqModule $ lower x) $ split0 moduleNames)
+    EqCategory cat val -> (EqCategory cat val, Just $ concat
         [ V.toList $ jaggedAsk categoryIds i
         | i <- elemIndices (BS.pack (cat ++ ":" ++ val)) $ split0 categoryNames])
     where
@@ -143,21 +144,30 @@
     where fs = map (filterTags2 ts . snd) $ groupSort $ map (scopeCategory &&& id) $ filter isQueryScope qs
           exact = Just IsExact `elem` [parseTag a b | QueryScope True a b <- qs]
           redo (QueryScope sense cat val)
-              | Just (k,v) <- fmap showTag $ fst . resolveTag ts =<< parseTag cat val = QueryScope sense k v
+              | Just (k,v) <- fmap (showTag . fst . resolveTag ts) $ parseTag cat val = QueryScope sense k v
               | otherwise = QueryNone $ ['-' | not sense] ++ cat ++ ":" ++ val
           redo q = q
 
 
-filterTags2 ts qs = \i -> not (negq i) && (null pos || posq i)
+filterTags2 ts qs = \i -> not (negq i) && (noPosRestrict || posq i)
     where (posq,negq) = both inRanges (pos,neg)
-          (pos, neg) = both (map snd) $ partition fst $ concatMap f qs
-          f (QueryScope sense cat val) = map (sense,) $ maybe [] (snd . resolveTag ts) $ parseTag cat val
+          (pos, neg) = both (concatMap snd) $ partition fst xs
+          xs = catMaybes restrictions
+          noPosRestrict = all pred restrictions
+          restrictions = map getRestriction qs
+          pred Nothing = True
+          pred (Just (sense, _)) = not sense
+          getRestriction :: Query -> Maybe (Bool,[(TargetId, TargetId)])
+          getRestriction (QueryScope sense cat val) = do
+            tag <- parseTag cat val
+            ranges <- snd $ resolveTag ts tag
+            return (sense, ranges)
 
 
 -- | Given a search which has no type or string in it, run the query on the tag bits.
 --   Using for things like IsModule, EqCategory etc.
 searchTags :: StoreRead -> [Query] -> [TargetId]
 searchTags ts qs
-    | x:xs <- [map fst $ maybe [] (snd . resolveTag ts) $ parseTag cat val | QueryScope True cat val <- qs]
+    | x:xs <- [map fst $ maybe [] (fromMaybe [] . snd . resolveTag ts) $ parseTag cat val | QueryScope True cat val <- qs]
     = if null xs then x else filter (`Set.member` foldl1' Set.intersection (map Set.fromList xs)) x
-searchTags ts _ = map fst $ snd $ resolveTag ts IsPackage
+searchTags ts _ = map fst $ fromMaybe [] $  snd $ resolveTag ts IsPackage
diff --git a/src/Query.hs b/src/Query.hs
--- a/src/Query.hs
+++ b/src/Query.hs
@@ -73,7 +73,10 @@
     where bs = zipWith (++) openBrackets shutBrackets ++ openBrackets ++ shutBrackets
 lexer (x:xs)
     | isSpace x = " " : lexer (dropWhile isSpace xs)
-    | isAlpha x || x == '_' = let (a,b) = span (\x -> isAlphaNum x || x `elem` "_'#-") xs in (x:a) : lexer b
+    | isAlpha x || x == '_' =
+        let (a,b) = span (\x -> isAlphaNum x || x `elem` "_'#-") xs
+            (a1,a2) = spanEnd (== '-') a
+        in (x:a1) : lexer (a2 ++ b)
     | isSym x = let (a,b) = span isSym xs in (x:a) : lexer b
     | x == ',' = "," : lexer xs
     | otherwise = lexer xs -- drop invalid bits
@@ -192,6 +195,7 @@
     "Int#" === name "Int#"
     "concat map" === name "concat" . name "map"
     "a -> b" === typ "a -> b"
+    "a->b" === typ "a -> b"
     "(a b)" === typ "(a b)"
     "map :: a -> b" === typ "a -> b"
     "+Data.Map map" === scope True "module" "Data.Map" . name "map"
