packages feed

hoogle 4.1.4 → 4.1.5

raw patch · 19 files changed

+162/−150 lines, 19 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

Files

datadir/resources/hoogle.css view
@@ -91,6 +91,10 @@     background-position: center right; } +#left .pad {+    padding-left: 16px;+}+ #left .minus {     color: #770E00;     padding-left: 16px;@@ -136,12 +140,10 @@ *  SPECIAL PAGES */ -#error {-    font-family: monospace;-}-#error u {-    border-bottom: 2px dotted red;+.error {+    border-bottom: 2px solid red;     text-decoration: none;+    white-space: pre; }  #example {
datadir/resources/hoogle.js view
@@ -7,6 +7,7 @@  var currentSearch; // String var oldSearches = cache(100);+var timeoutId;  $(function(){     currentSearch = $("#hoogle").focus().keyup(searchBoxChange).val();@@ -24,14 +25,21 @@         bod.html(old);     else     {+        if (timeoutId != undefined) window.clearTimeout(timeoutId);+        timeoutId = window.setTimeout(function(){timeoutId = undefined; $("h1").text("Still working...");}, 500);         $.ajax({             url: '?',             data: {mode:'ajax', hoogle:now},             dataType: 'html',             complete: function(s){return function(e){-                oldSearches.add(s,e.responseText);-                if (txt.val() == s)-                    bod.html(e.responseText);+                window.clearTimeout(timeoutId);+                timeoutId = undefined;+                if (e.status == 200) {+                    oldSearches.add(s,e.responseText);+                    if (txt.val() == s)+                        bod.html(e.responseText);+                } else+                    bod.html("<h1><b>Error:</b> status " + e.status + "</h1><p>" + e.responseText + "</p>");             }}(now)         });     }
hoogle.cabal view
@@ -1,7 +1,7 @@ cabal-version:      >= 1.6 build-type:         Simple name:               hoogle-version:            4.1.4+version:            4.1.5 license:            GPL license-file:       docs/LICENSE category:           Development
src/CmdLine/All.hs view
@@ -92,8 +92,9 @@   cmdLineWeb :: [(String,String)] -> IO CmdLine-cmdLineWeb args = cmdLineExpand $ blankSearch{web=True,-        start=askInt ["start"], count=askInt ["count"], webmode=ask ["mode"],-        queryChunks = maybeToList $ ask ["q","hoogle"]}+cmdLineWeb args = cmdLineExpand $ blankSearch+        {web=Just $ fromMaybe "web" $ ask ["mode"]+        ,start=askInt ["start"], count=askInt ["count"]+        ,queryChunks = maybeToList $ ask ["q","hoogle"]}     where ask x = listToMaybe [b | (a,b) <- args, a `elem` x]           askInt x = readMay =<< ask x
src/CmdLine/Type.hs view
@@ -11,74 +11,72 @@ import Hoogle  -isWebCmdLine Search{web=True} = True+isWebCmdLine Search{web=Just _} = True isWebCmdLine Server{} = True isWebCmdLine _ = False   data CmdLine     = Search-        {web :: Bool                        -- ^ Are you operating from the web (via CGI)+        {color :: Bool+        ,link :: Bool+        ,info :: Bool+        ,databases :: [FilePath]         ,start :: Maybe Int         ,count :: Maybe Int-        ,webmode :: Maybe String-        ,info :: Bool-        ,link :: Bool-        ,color :: Bool+        ,web :: Maybe String         ,repeat_ :: Int-        ,databases :: [FilePath]         ,queryChunks :: [String]                  ,queryParsed :: Either ParseError Query         ,queryText :: String         }+    | Data {redownload :: Bool, local :: [String], datadir :: FilePath, threads :: Int, actions :: [String]}+    | Server {port :: Int, local_ :: Bool, databases :: [FilePath], resources :: FilePath, nostdin :: Bool}+    | Combine {srcfiles :: [FilePath], outfile :: String}+    | Convert {srcfile :: String, outfile :: String}     | Test {testFiles :: [String], example :: Bool}-    | Server {port :: Int, databases :: [FilePath], resources :: FilePath, local_ :: Bool, nostdin :: Bool}     | Dump {database :: String, section :: [String]}     | Rank {srcfile :: FilePath}-    | Combine {srcfiles :: [FilePath], outfile :: String}-    | Convert {srcfile :: String, outfile :: String}-    | Data {datadir :: FilePath, threads :: Int, haddock :: Bool, redownload :: Bool, actions :: [String], local :: [String]}       deriving (Data,Typeable,Show)  emptyParseError = ParseError 0 0 "" $ Str ""-blankSearch = Search False Nothing Nothing Nothing False False False 1 [] [] (Left emptyParseError) ""+blankSearch = Search False False False [] Nothing Nothing Nothing 1 [] (Left emptyParseError) "" -cmdLineMode = cmdArgsMode $ modes [search_ &= auto,test,server,dump,rank,combine,convert,dataa]+cmdLineMode = cmdArgsMode $ modes [search_ &= auto,dataa,server,combine,convert,test,dump,rank]     &= verbosity &= program "hoogle"     &= summary ("Hoogle v" ++ showVersion version ++ ", (C) Neil Mitchell 2004-2011\nhttp://haskell.org/hoogle")  search_ = Search-    {web = def &= help "Operate as a web tool"-    ,start = def-    ,count = def &= name "n" &= help "Return the first N results"-    ,webmode = def-    ,queryChunks = def &= args-    ,info = def-    ,link = def-    ,color = def-    ,databases = ["."] &= typDir &= help "Which directories to find databases"-    ,repeat_ = 1+    {web = def &= typ "MODE" &= opt "web" &= help "Operate as a web tool"+    ,start = def &= help "Start displaying results from this point on (1 based)"+    ,count = def &= name "n" &= help "Maximum number of results to return"+    ,queryChunks = def &= args &= typ "QUERY"+    ,info = def &= help "Give extended information about the first result"+    ,link = def &= help "Give URL's for each result"+    ,color = def &= name "colour" &= help "Use colored output (requires ANSI terminal)"+    ,databases = ["."] &= typDir &= help "Directories to search for databases"+    ,repeat_ = 1 &= help "Run the search multiple times (for benchmarking)"     ,queryParsed = Left emptyParseError &= ignore     ,queryText = "" &= ignore-    }+    } &= help "Perform a search"  test = Test     {testFiles = def &= typFile &= args     ,example = def &= help "Test the full examples"-    } &= help "Run tests over a list of files"+    } &= help "Run tests"  server = Server     {port = 80 &= typ "INT" &= help "Port number"-    ,resources = ""+    ,resources = "" &= typDir &= help "Directory to use for resources (images, CSS etc)"     ,nostdin = def &= help "Don't read from stdin"-    ,local_ = def &= help "Rewrite file:/// links and serve them, can be a security hole"+    ,local_ = def &= help "Rewrite and serve file: links (potential security hole)"     } &= help "Start a Hoogle server"  dump = Dump     {database = def &= argPos 0 &= typ "DATABASE"     ,section = def &= args &= typ "SECTION"-    } &= help "Dump sections of the database to stdout"+    } &= help "Dump sections of a database to stdout"  rank = Rank     {srcfile = def &= argPos 0 &= typ "RANKFILE" &= opt ""@@ -87,20 +85,19 @@ combine = Combine     {srcfiles = def &= args &= typ "DATABASE"     ,outfile = "default.hoo" &= typFile &= help "Output file (defaults to default.hoo)"-    } &= help "Combine multiple inputs to produce one output"+    } &= help "Combine multiple databases into one"  convert = Convert-    {srcfile = def &= argPos 0 &= typ "TEXTBASE"+    {srcfile = def &= argPos 0 &= typ "INPUT"     ,outfile = def &= argPos 1 &= typ "DATABASE" &= opt ""-    } &= help "Convert a textbase to a database"+    } &= help "Convert an input file to a database"  dataa = Data     {datadir = def &= typDir &= help "Database directory"-    ,haddock = def &= help "Get haddock documentation directly from Hackage"-    ,redownload = def &= help "Always redownload files from the web"-    ,threads = def &= typ "INT" &= name "j" &= help "Number of threads to use"+    ,redownload = def &= help "Redownload all files from the web"+    ,threads = def &= typ "INT" &= name "j" &= help "Number of threads to use" &= ignore -- ignore until it works     ,actions = def &= args &= typ "RULE"-    ,local = def &= opt "" &= typ "FILEPATH" &= help "Use local documentation where found"+    ,local = def &= opt "" &= typ "FILEPATH" &= help "Use local documentation if available"     } &= help "Generate Hoogle databases"       &= details ["Each argument should be the name of a database you want to generate"                  ,"optionally followed by which files to combine. Common options:"
src/Console/All.hs view
@@ -35,6 +35,7 @@  action (Convert from to) = do     to <- return $ if null to then replaceExtension from "hoo" else to+    when (any isUpper $ takeBaseName to) $ putStrLn $ "Warning: Hoogle databases should be all lower case, " ++ takeBaseName to     putStrLn $ "Converting " ++ from     src <- readFileUtf8 from     let (err,db) = createDatabase Haskell [] src
src/Hoogle/DataBase/All.hs view
@@ -20,7 +20,7 @@     where         items = createItems xs         ys = entriesItems items-        ns = createSubstrSearch [(entryKey $ fromLink y, y) | y <- ys]+        ns = createSubstrSearch [(k, y) | y <- ys, let k = entryKey $ fromLink y, k /= ""]         as = createAliases (map aliases deps) facts         is = createInstances (map instances deps) facts         tys = [(sig, x) | x <- ys, Just sig <- [entryType $ fromLink x]]@@ -28,6 +28,7 @@   combineDataBase :: [DataBase] -> DataBase+combineDataBase [db] = db combineDataBase dbs = DataBase items_         ns (createTypeSearch as is tys)         ss as is
src/Hoogle/DataBase/SubstrSearch.hs view
@@ -13,6 +13,7 @@ import qualified Data.Binary as Bin import qualified Data.Binary.Get as Bin import qualified Data.Binary.Put as Bin+import qualified Data.Set as Set import General.Base import Hoogle.Type.All import Hoogle.Score.All@@ -61,7 +62,7 @@     }  -searchSubstrSearch :: Eq a => SubstrSearch a -> String -> [(a, EntryView, Score)]+searchSubstrSearch :: SubstrSearch a -> String -> [(a, EntryView, Score)] searchSubstrSearch x y = reverse (sPrefix sN) ++ reverse (sInfix sN)     where         view = FocusOn y@@ -79,8 +80,20 @@         addMatch t s = s{sPrefix=(inds x $ sCount s,view,textScore t):sPrefix s}  +data S2 = S2+    {_s2Focus :: !BS.ByteString -- where we are in the string+    ,s2Result :: Set.Set BS.ByteString+    }+ completionsSubstrSearch :: SubstrSearch a -> String -> [String]-completionsSubstrSearch _ _ = []+completionsSubstrSearch x y = map (\x -> y ++ drop ny (BSC.unpack x)) $ take 10 $ Set.toAscList $+                              s2Result $ BS.foldl f (S2 (text x) Set.empty) $ lens x+    where+        ny = length y+        ly = BSC.pack $ map toLower y+        f (S2 foc res) ii = S2 (BS.unsafeDrop i foc) (if ly `BS.isPrefixOf` x then Set.insert x res else res)+            where x = BS.unsafeTake i foc+                  i = fromIntegral ii   instance Show a => Show (SubstrSearch a) where
src/Hoogle/Language/Haskell.hs view
@@ -35,7 +35,7 @@ parseLine :: Int -> String -> Either ParseError ([Fact],[TextItem]) parseLine line x | "(##)" `isPrefixOf` x = Left $ parseErrorWith line 1 "Skipping due to HSE bug #206" "(##)" parseLine line ('@':str) = case a of-        "keyword" -> Right $ itemKeyword $ dropWhile isSpace b+        "entry" -> Right $ itemEntry $ dropWhile isSpace b         "package" -> Right $ itemPackage $ dropWhile isSpace b         _ -> Left $ parseErrorWith line 2 ("Unknown attribute: " ++ a) $ '@':str     where (a,b) = break isSpace str@@ -76,12 +76,14 @@  fact x y = (x,[y]) -itemPackage x = fact [] $ textItem{itemLevel=0, itemKey=x, itemName=x,+itemPackage x = fact [] $ textItem{itemLevel=0, itemKey="", itemName=x,     itemURL="http://hackage.haskell.org/package/" ++ x ++ "/",     itemDisp=Tags [emph "package",space,bold x]} -itemKeyword x = fact [] $ textItem{itemName=x, itemKey=x,-    itemDisp=Tags [emph "keyword",space,bold x]}+itemEntry x = fact [] $ textItem{itemName=ab, itemKey=ab,+    itemDisp= if null b then bold a else Tags [emph a,space,bold b]}+    where (a,b) = second (dropWhile isSpace) $ break isSpace x+          ab = if null b then a else b  itemModule xs = fact [] $ textItem{itemLevel=1, itemKey=last xs, itemName=intercalate "." xs,     itemURL="",
src/Hoogle/Query/Parser.hs view
@@ -201,7 +201,7 @@ bracketer :: String -> Either ParseError [Bracket] bracketer xs = case readBracket (1,xs) of     Left (msg,from,to) -> f msg from to-    Right (res,(i,_:_)) -> f "Unexpected closing bracket" i (length xs)+    Right (res,(i,_:_)) -> f "Unexpected closing bracket" i (1+length xs)     Right (res,_) -> Right res     where         f msg from to = Left $ ParseError 1 from msg $ formatTags xs [((from-1,to-1),TagEmph)]
src/Recipe/Download.hs view
@@ -12,9 +12,9 @@     createDirectoryIfMissing True "download"     wget opt keywords "http://haskell.org/haskellwiki/Keywords"     wget opt platform "http://code.haskell.org/haskell-platform/haskell-platform.cabal"+    wget opt inputBase "http://haskell.org/hoogle/base.txt"     downloadTarball opt cabals "http://hackage.haskell.org/packages/archive/00-index.tar.gz"-    if haddock opt then downloadHaddocks opt-                   else downloadTarball opt haddocks "http://haskell.org/hoogle/hackage-haddock.tar.gz"+    downloadTarball opt inputs "http://hackage.haskell.org/packages/archive/00-hoogle.tar.gz"   wgetMay :: CmdLine -> FilePath -> URL -> IO Bool@@ -42,19 +42,3 @@         withDirectory out $             system_ $ "tar -xzf .." </> takeFileName out <.> "tar.gz"         writeFile (out <.> "txt") ""---downloadHaddocks :: CmdLine -> IO ()-downloadHaddocks opt = do-    b <- doesFileExist $ haddocks <.> "txt"-    unless b $ do-        xs <- listing cabals-        forM_ xs $ \name -> do-            ver <- version cabals name-            let out = haddocks </> name </> ver </> name <.> "txt"-                url = "http://hackage.haskell.org/packages/archive/" ++ name ++ "/" ++ ver ++ "/doc/html/" ++ name ++ ".txt"-            createDirectoryIfMissing True $ takeDirectory out-            b <- wgetMay opt out url-            unless b $ writeFile out ""-        withDirectory haddocks $ system_ "tar -czf../hackage-haddock.tar.gz *"-        writeFile (haddocks <.> "txt") ""
src/Recipe/General.hs view
@@ -1,5 +1,5 @@ -module Recipe.General(convert, combine) where+module Recipe.General(convertSrc, convert, combine) where  import Recipe.Type import Hoogle@@ -7,11 +7,20 @@ import General.System import System.Console.CmdArgs.Verbosity +txt x = map toLower x <.> "txt"+hoo x = map toLower x <.> "hoo" ++convertSrc :: ([Name] -> IO ()) -> Name -> String -> IO ()+convertSrc make x src = do+    writeFileUtf8 (txt x) src+    convert make x++ -- convert a single database convert :: ([Name] -> IO ()) -> Name -> IO () convert make x = do-    b <- doesFileExist $ x <.> "txt"+    b <- doesFileExist $ txt x     if not b then         putWarning $ "Warning: " ++ x ++ " couldn't be converted, no input file found"      else do@@ -32,7 +41,7 @@  readInput :: Name -> IO ([Name], String) readInput x = do-    src <- readFileUtf8 $ x <.> "txt"+    src <- readFileUtf8 $ txt x     let (a,b) = span ("@depends " `isPrefixOf`) $ lines src     return (map (drop 9) a, unlines b) 
src/Recipe/Hackage.hs view
@@ -8,6 +8,7 @@ import General.System import General.Util import General.Web+import Control.Exception   -- FIXME: This is a list of hack@@ -25,7 +26,7 @@  makeAll :: ([Name] -> IO ()) -> IO () makeAll make = do-    xs <- listing haddocks+    xs <- listing inputs     make xs  @@ -38,36 +39,33 @@         let file = cabals </> name </> ver </> name <.> "cabal"         src <- readCabal file         return $ [""] ++ zipWith (++) ("-- | " : repeat "--   ") (cabalDescription src) ++-                 ["--","-- Version " ++ ver, "@package " ++ name]-    writeFile "package.txt" $ safeEncoding $ unlines $ concat xs-    convert noDeps "package"+                 ["--","-- Version " ++ ver, "@url package/" ++ name, "@entry package " ++ name]+    convertSrc noDeps "package" $ unlines $+        "@url http://hackage.haskell.org/" : "@package package" : concat xs   makeDefault :: ([Name] -> IO ()) -> [FilePath] -> Name -> IO () makeDefault make local name = do+    let base = name == "base"     b1 <- doesDirectoryExist $ cabals </> name-    b2 <- doesDirectoryExist $ haddocks </> name-    if not b1 || not b2 then+    b2 <- doesDirectoryExist $ inputs </> name+    if not base && (not b1 || not b2) then         putWarning $ "Warning: " ++ name ++ " couldn't find both Cabal and Haddock inputs"      else do         vc <- version cabals name-        vh <- version haddocks name+        vh <- if base then return vc else version inputs name         when (vc /= vh) $ putStrLn $ "Warning: Version mismatch for " ++ name ++ " (cabal=" ++ vc ++ ", haddock=" ++ vh ++ ")"-        let had = haddocks </> name </> vh </> name <.> "txt"+        let had = if base then inputBase else inputs </> name </> vh </> "doc" </> "html" </> name <.> "txt"             cab = cabals </> name </> vc </> name <.> "cabal"-        h <- openFile had ReadMode-        sz <- hFileSize h-        hClose h-        if sz == 0 then-            putWarning $ "Warning: " ++ name ++ " has no haddock output"-         else do-            had <- readFileUtf8' had-            cab <- readCabal cab-            loc <- findLocal local name-            writeFileUtf8 (name <.> "txt") $ unlines $-                ["@depends " ++ a | a <- cabalDepends cab \\ (name:avoid)] ++-                (maybe id haddockPackageUrl loc) (haddockHacks $ lines had)-            convert make name+        had <- try $ readFileUtf8' had+        case had of+            Left e -> putWarning $ "Warning: Exception when reading haddock for " ++ name ++ ", " ++ show (e :: SomeException)+            Right had -> do+                cab <- readCabal cab+                loc <- findLocal local name+                convertSrc make name $ unlines $+                    ["@depends " ++ a | a <- cabalDepends cab \\ (name:avoid)] +++                    (maybe id haddockPackageUrl loc) (haddockHacks $ lines had)   -- try and find a local filepath
src/Recipe/Keyword.hs view
@@ -9,8 +9,7 @@  makeKeyword :: IO () makeKeyword = do-    writeFileUtf8 "keyword.txt" . translate =<< readFile' keywords-    convert noDeps "keyword"+    convertSrc noDeps "keyword" . translate =<< readFile' keywords   translate :: String -> String@@ -30,7 +29,7 @@     ]  -keywordFormat x = concat ["" : docs ++ ["@url #" ++ concatMap g n, "@keyword " ++ noUnderscore n] | n <- name]+keywordFormat x = concat ["" : docs ++ ["@url #" ++ concatMap g n, "@entry keyword " ++ noUnderscore n] | n <- name]     where         noUnderscore "_" = "_"         noUnderscore xs = map (\x -> if x == '_' then ' ' else x) xs
src/Recipe/Type.hs view
@@ -1,7 +1,7 @@  module Recipe.Type(-    CmdLine(..), Name, hoo, noDeps, safeEncoding,-    keywords, platform, cabals, haddocks, listing, version,+    CmdLine(..), Name, noDeps, safeEncoding,+    keywords, platform, cabals, inputs, inputBase, listing, version,     resetWarnings, putWarning, recapWarnings,     outStr, outStrLn     ) where@@ -15,10 +15,7 @@  type Name = String -hoo :: Name -> FilePath-hoo x = x <.> "hoo" - noDeps :: [Name] -> IO () noDeps [] = return () noDeps xs = error "Internal error: package with no dependencies had dependencies"@@ -35,7 +32,8 @@ keywords = "download/keyword.txt" platform = "download/haskell-platform.cabal" cabals = "download/hackage-cabal"-haddocks = "download/hackage-haddock"+inputs = "download/hackage-hoogle"+inputBase = "download/base.txt" -- FIXME: Temporary, until base.txt ends up on Hackage  listing :: FilePath -> IO [Name] listing dir = do
src/Web/All.hs view
@@ -11,7 +11,6 @@ action q@Server{} = server q  -- FIXME: Should use datadir, but not sure how--- FIXME: Only server will preserve extra flags action q = do-    res <- response "datadir/resources" [] q+    res <- response "datadir/resources" q     putStrLn $ intercalate "\n" $ map show (rspHeaders res) ++ ["",rspBody res]
src/Web/Page.hs view
@@ -5,8 +5,8 @@ import General.Util  -searchLink :: Args -> String -> URL-searchLink extra x = "?" ++ concat [a ++ "=" ++% b ++ "&" | (a,b) <- extra, a /= "hoogle"] ++ "hoogle=" ++% x+searchLink :: String -> URL+searchLink x = "?hoogle=" ++% x   header resources query =@@ -56,7 +56,7 @@     ]  -welcome extra =+welcome =     ["<h1><b>Welcome to Hoogle</b></h1>"     ,"<p>"     ,"  Hoogle is a Haskell API search engine, which allows you to search many standard Haskell libraries"@@ -82,4 +82,4 @@     ,"</p>"     ]     where-        search x = "<a href='" ++ searchLink extra x ++ "'>" ++& x ++ "</a><br/>"+        search x = "<a href='" ++ searchLink x ++ "'>" ++& x ++ "</a><br/>"
src/Web/Response.hs view
@@ -13,14 +13,13 @@ import Data.Time.Clock import Data.Time.Calendar import Network.HTTP-import Paths_hoogle   logFile = "log.txt" --- extra is a hack, should be replaced with a local cookie, until it becomes the default-response :: FilePath -> Args -> CmdLine -> IO (Response String)-response resources extra q = do++response :: FilePath -> CmdLine -> IO (Response String)+response resources q = do     logMessage q     let response x = responseOk [Header HdrContentType x] @@ -28,17 +27,17 @@             dbs <- if isRight $ queryParsed q                    then fmap snd $ loadQueryDatabases (databases q) (fromRight $ queryParsed q)                    else return mempty-            return $ runQuery extra ajax dbs q+            return $ runQuery ajax dbs q -    case webmode q of+    case web q of         Just "ajax" -> do             res <- res True             return $ response "text/html" $ unlines res-        Nothing -> do+        Just "web" -> do             res <- res False             return $ response "text/html" $ unlines $ header resources (escapeHTML $ queryText q) ++ res ++ footer         Just "suggest" -> fmap (response "application/json") $ runSuggest q-        Just e -> return $ response "text/html" $ "Unknown webmode: " ++ show e+        Just e -> return $ response "text/html" $ "Unknown webmode: " ++ e   logMessage :: CmdLine -> IO ()@@ -52,39 +51,36 @@   runSuggest :: CmdLine -> IO String-runSuggest Search{queryText=q} = do-    root <- getDataDir-    db <- loadDatabase $ root </> "default.hoo"+runSuggest cq@Search{queryText=q} = do+    (_, db) <- loadQueryDatabases (databases cq) (Query [] Nothing [])     let res = queryCompletions db q     return $ "[" ++ show q ++ "," ++ show res ++ "]" runSuggest _ = return ""  -runQuery :: Args -> Bool -> Database -> CmdLine -> [String]-runQuery extra ajax dbs Search{queryParsed = Left err} =-    ["<h1><b>Parse error in user query</b></h1>"+runQuery :: Bool -> Database -> CmdLine -> [String]+runQuery ajax dbs Search{queryParsed = Left err} =+    ["<h1>" ++ showTagHTMLWith f (parseInput err) ++ "</h1>"     ,"<p>"-    ,"  Query: <span id='error'>" ++ showTagHTMLWith f (parseInput err) ++ "</span>"-    ,"</p><p>"-    ,"  Error: " ++& errorMessage err+    ,"  <b>Parse error:</b> " ++& errorMessage err     ,"</p><p>"     ,"  For information on what queries should look like, see the"     ,"  <a href='http://www.haskell.org/haskellwiki/Hoogle'>user manual</a>."     ,"</p>"     ]     where-        f (TagEmph x) = Just $ "<u>" ++ showTagHTMLWith f x ++ "</u>"+        f (TagEmph x) = Just $ "<span class='error'>" ++ showTagHTMLWith f x ++ "</span>"         f _ = Nothing  -runQuery extra ajax dbs q | isBlankQuery $ fromRight $ queryParsed q = welcome extra+runQuery ajax dbs q | isBlankQuery $ fromRight $ queryParsed q = welcome  -runQuery extra ajax dbs cq@Search{queryParsed = Right q, queryText = qt} =+runQuery ajax dbs cq@Search{queryParsed = Right q, queryText = qt} =     (if prefix then         ["<h1>" ++ qstr ++ "</h1>"] ++         ["<div id='left'>" ++ also ++ "</div>" | not $ null pkgs] ++-        ["<p>" ++ showTag extra sug ++ "</p>" | Just sug <- [querySuggestions dbs q]] +++        ["<p>" ++ showTag sug ++ "</p>" | Just sug <- [querySuggestions dbs q]] ++         if null res then             ["<p>No results found</p>"]         else@@ -98,25 +94,30 @@         count2 = maybe 20 (max 1) $ count cq          src = search dbs q-        res = [renderRes extra i (i /= 0 && i == start2 && prefix) x | (i,(_,x)) <- zip [0..] src]+        res = [renderRes i (i /= 0 && i == start2 && prefix) x | (i,(_,x)) <- zip [0..] src]         (pre,res2) = splitAt start2 res         (now,post) = splitAt count2 res2 -        also = "<ul><li><b>Packages</b></li>" ++ concatMap f (take 5 pkgs) ++ "</ul>"-        f x | PlusPackage x `elem` scope q =-                let q2 = showTagText $ renderQuery $ q{scope = filter (/= PlusPackage x) $ scope q} in-                "<li><a class='minus' href='" ++ searchLink extra (q2) ++ "'>" ++ x ++ "</a></li>"+        also = "<ul><li><b>Packages</b></li>" ++ concatMap f (take (5 + length minus) $ nub $ minus ++ pkgs) ++ "</ul>"+            where minus = [x | MinusPackage x <- scope q]+        f x | PlusPackage lx `elem` scope q =+                let q2 = showTagText $ renderQuery $ q{scope = filter (/= PlusPackage lx) $ scope q} in+                "<li><a class='minus' href='" ++ searchLink q2 ++ "'>" ++ x ++ "</a></li>"+            | MinusPackage lx `elem` scope q =+                let q2 = showTagText $ renderQuery $ q{scope = filter (/= MinusPackage lx) $ scope q} in+                "<li><a class='plus pad' href='" ++ searchLink q2 ++ "'>" ++ x ++ "</a></li>"             | otherwise =-                "<li><a class='minus' href='" ++ searchLink extra (qt ++ " -" ++ x) ++ "'></a>" ++-                "<a class='plus' href='" ++ searchLink extra (qt ++ " +" ++ x) ++ "'>" ++ x ++ "</a></li>"-        pkgs = nub [x | (_, (_,x):_)  <- concatMap (locations . snd) $ take (start2+count2) src]+                "<li><a class='minus' href='" ++ searchLink (qt ++ " -" ++ lx) ++ "'></a>" +++                "<a class='plus' href='" ++ searchLink (qt ++ " +" ++ lx) ++ "'>" ++ x ++ "</a></li>"+            where lx = map toLower x+        pkgs = [x | (_, (_,x):_)  <- concatMap (locations . snd) $ take (start2+count2) src] -        urlMore = searchLink extra qt ++ "&start=" ++ show (start2+count2+1) ++ "#more"+        urlMore = searchLink qt ++ "&start=" ++ show (start2+count2+1) ++ "#more"         qstr = showTagHTML (renderQuery q)  -renderRes :: Args -> Int -> Bool -> Result -> [String]-renderRes extra i more Result{..} =+renderRes :: Int -> Bool -> Result -> [String]+renderRes i more Result{..} =         ["<a name='more'></a>" | more] ++         ["<div class='ans'>" ++ href selfUrl (showTagHTMLWith url self) ++ "</div>"] ++         ["<div class='from'>" ++ intercalate ", " [unwords $ zipWith (f u) [1..] ps | (u,ps) <- locations] ++ "</div>" | not $ null locations] ++@@ -128,7 +129,7 @@          docs2 = ("<div id='d" ++ show i ++ "' class='shut'>" ++                    "<a class='docs' onclick='return docs(" ++ show i ++ ")' href='" ++& selfUrl ++ "'></a>") ++?-                   showTag extra docs ++?+                   showTag docs ++?                "</div>"          url (TagBold x)@@ -143,9 +144,9 @@         href url x = if null url then x else "<a class='dull' href='" ++& url ++ "'>" ++ x ++ "</a>"  -showTag :: Args -> TagStr -> String-showTag extra = showTagHTML . transform f+showTag :: TagStr -> String+showTag = showTagHTML . transform f     where-        f (TagLink "" x) = TagLink (if "http:" `isPrefixOf` str then str else searchLink extra str) x+        f (TagLink "" x) = TagLink (if "http:" `isPrefixOf` str then str else searchLink str) x             where str = showTagText x         f x = x
src/Web/Server.hs view
@@ -3,7 +3,6 @@ module Web.Server(server) where  import General.Base-import General.Util import General.Web import CmdLine.All import Web.Response@@ -64,7 +63,7 @@     | path `elem` ["/","/hoogle"] = do         let args = parseHttpQueryArgs $ drop 1 query         cmd <- cmdLineWeb args-        r <- response "/res" (reps ("mode","ajax") ("ajax","1") args) cmd{databases=databases}+        r <- response "/res" cmd{databases=databases}         return $ if local_ then fmap rewriteFileLinks r else r     | takeDirectory path == "/res" = serveFile True $ resources </> takeFileName path     | local_ && "/file/" `isPrefixOf` path = serveFile False $ drop 6 path