diff --git a/CHANGES.txt b/CHANGES.txt
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,5 +1,9 @@
 Changelog for Hoogle (* = breaking change)
 
+5.0.17.12, released 2019-11-02
+    Allow haskell-src-exts-1.22
+    #324, make unicode search work more
+    #323, fix escaping in packages list (on the left)
 5.0.17.11, released 2019-08-23
     #318, allow --json to get results JSON from the command line
 5.0.17.10, released 2019-08-02
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.17.11
+version:            5.0.17.12
 license:            BSD3
 license-file:       LICENSE
 category:           Development
@@ -15,7 +15,7 @@
     or by approximate type signature.
 homepage:           https://hoogle.haskell.org/
 bug-reports:        https://github.com/ndmitchell/hoogle/issues
-tested-with:        GHC==8.6.5, GHC==8.4.4, GHC==8.2.2, GHC==8.0.2
+tested-with:        GHC==8.8.1, GHC==8.6.5, GHC==8.4.4, GHC==8.2.2, GHC==8.0.2
 extra-doc-files:
     README.md
     CHANGES.txt
@@ -61,7 +61,7 @@
         foundation >= 0.0.13,
         old-locale,
         hashable,
-        haskell-src-exts >= 1.21 && < 1.22,
+        haskell-src-exts >= 1.22 && < 1.23,
         http-conduit >= 2.3,
         http-types,
         js-flot,
diff --git a/src/Action/Search.hs b/src/Action/Search.hs
--- a/src/Action/Search.hs
+++ b/src/Action/Search.hs
@@ -169,7 +169,7 @@
         "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" === hackage "ghc-lib-parser/docs/TyCon.html#v:visibleDataCons"
+        "visibleDataCons" === hackage "ghc/docs/TyCon.html#v:visibleDataCons"
         "sparkle" === hackage "sparkle" -- library without Hoogle docs
         "weeder" === hackage "weeder" -- executable in Stackage
         "supero" === hackage "supero"
diff --git a/src/Action/Server.hs b/src/Action/Server.hs
--- a/src/Action/Server.hs
+++ b/src/Action/Server.hs
@@ -205,10 +205,10 @@
             "&filter=" ++ intercalate "|" (mapMaybe (fmap fst . targetModule) ts) ++
             "&precise=on"
 
-        add x = ("?" ++) $ intercalate "&amp;" $ map (joinPair "=") $
+        add x = ("?" ++) $ intercalate "&" $ map (joinPair "=") $
             case break ((==) "hoogle" . fst) args of
-                (a,[]) -> a ++ [("hoogle", x)]
-                (a,(_,x1):b) -> a ++ [("hoogle", x1 ++ " " ++ x)] ++ b
+                (a,[]) -> a ++ [("hoogle", escapeURL x)]
+                (a,(_,x1):b) -> a ++ [("hoogle", escapeURL $ x1 ++ " " ++ x)] ++ b
 
         f cat val = do
             H.a ! H.class_" minus" ! H.href (H.stringValue $ add $ "-" ++ cat ++ ":" ++ val) $ ""
diff --git a/src/General/Util.hs b/src/General/Util.hs
--- a/src/General/Util.hs
+++ b/src/General/Util.hs
@@ -54,6 +54,8 @@
 import GHC.Stats
 import General.Str
 import Prelude
+import qualified Network.HTTP.Types.URI as URI
+import qualified Data.ByteString.UTF8 as UTF8
 
 
 type PkgName = Str
@@ -216,9 +218,7 @@
 unHTML = unescapeHTML . innerTextHTML
 
 escapeURL :: String -> String
-escapeURL = concatMap $ \x ->
-    if (isAscii x && isAlphaNum x) || x `elem` "-_.~" then [x]
-    else '%' : showHex (ord x) ""
+escapeURL = UTF8.toString . URI.urlEncode True . UTF8.fromString
 
 isUpper1 (x:xs) = isUpper x
 isUpper1 _ = False
diff --git a/src/General/Web.hs b/src/General/Web.hs
--- a/src/General/Web.hs
+++ b/src/General/Web.hs
@@ -29,6 +29,7 @@
 import System.Time.Extra
 import General.Log
 import Prelude
+import qualified Data.ByteString.UTF8 as UTF8
 
 
 data Input = Input
@@ -46,9 +47,9 @@
               . BS.pack
     badPath = any (all (== '.')) . filter (/= "")
     args = parseArgs b
-    parseArgs = map (BS.unpack *** maybe "" BS.unpack)
+    parseArgs = map (UTF8.toString *** maybe "" UTF8.toString)
               . parseQuery
-              . BS.pack
+              . UTF8.fromString
     badArgs = any (any (not . isLower))
             . map fst
 
diff --git a/src/Input/Item.hs b/src/Input/Item.hs
--- a/src/Input/Item.hs
+++ b/src/Input/Item.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE CPP, GeneralizedNewtypeDeriving, DeriveDataTypeable, DeriveFunctor, ViewPatterns #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving, DeriveDataTypeable, DeriveFunctor, ViewPatterns #-}
 {-# LANGUAGE RecordWildCards, OverloadedStrings, PatternGuards, ScopedTypeVariables #-}
 
 -- | Types used to generate the input.
@@ -213,20 +213,22 @@
             TVar a b -> TVar a (b ++ [ty y])
         ty (TyVar _ x) = TVar (fromName x) []
         ty (TyCon _ x) = TCon (fromQName x) []
-#if !defined(MIN_VERSION_haskell_src_exts) || MIN_VERSION_haskell_src_exts(1,20,0)
         ty (TyInfix an a (UnpromotedName _ b) c) = ty $ let ap = TyApp an in TyCon an b `ap` a `ap` c
-#else
-        ty (TyInfix an a b c) = ty $ let ap = TyApp an in TyCon an b `ap` a `ap` c
-#endif
         ty (TyKind _ x _) = ty x
         ty (TyBang _ _ _ x) = ty x
         ty (TyParen _ x) = ty x
         ty _ = TVar "_" []
 
         ctx (ParenA _ x) = ctx x
-        ctx (InfixA an a con b) = ctx $ ClassA an con [a,b]
-        ctx (ClassA _ con (TyVar _ var:_)) = [Ctx (fromQName con) (fromName var)]
+        ctx (TypeA _ x)  = ctxTy x
         ctx _ = []
+
+        ctxTy (TyInfix an a (UnpromotedName _ con) b) = ctxTy $ TyApp an (TyApp an (TyCon an con) a) b
+        ctxTy (fromTyApps -> TyCon _ con:TyVar _ var:_) = [Ctx (fromQName con) (fromName var)]
+        ctxTy _ = []
+
+        fromTyApps (TyApp _ x y) = fromTyApps x ++ [y]
+        fromTyApps x = [x]
 
 
 hseToItem :: Decl a -> [Item]
diff --git a/src/Input/Reorder.hs b/src/Input/Reorder.hs
--- a/src/Input/Reorder.hs
+++ b/src/Input/Reorder.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE RecordWildCards, OverloadedStrings #-}
 
 module Input.Reorder(reorderItems) where
 
@@ -10,10 +10,21 @@
 import General.Str
 
 
--- | Reorder items so the most popular ones are first, using reverse dependencies
+pkgGhc :: PkgName
+pkgGhc = strPack "ghc"
+
+packageOrderHacks :: (PkgName -> Int) -> PkgName -> Int
+-- 'ghc' is the canonical module that both 'ghc-lib-parser' and 'ghc-lib' copy from, so better to pick that
+-- even though ghc-lib-* are used more on Stackage (but a lot less on Hackage)
+packageOrderHacks f x | x == pkgGhc = min (f x) $ min (f $ strPack "ghc-lib-parser") (f $ strPack "ghc-lib") - 1
+packageOrderHacks f x = f x
+
+
+-- | Reorder items so the most popular ones are first, using reverse dependencies.
+--   Low numbers for the PkgName function mean the package is more popular.
 reorderItems :: Settings -> (PkgName -> Int) -> [(a, Item)] -> [(a, Item)]
 reorderItems Settings{..} packageOrder xs =
-    concatMap snd $ sortOn ((packageOrder &&& id) . fst) $ map rebase $ splitIPackage xs
+    concatMap snd $ sortOn ((packageOrderHacks packageOrder &&& id) . fst) $ map rebase $ splitIPackage xs
     where
         refunc = map $ second $ \(x:xs) -> x : sortOn (itemName . snd) xs
         rebase (x, xs) = (x, concatMap snd $ sortOn (((negate . f . strUnpack) &&& id) . fst) $ refunc $ splitIModule xs)
