diff --git a/notebooks/IHaskell.ipynb b/notebooks/IHaskell.ipynb
index d1a040ba..b1972d9f 100644
--- a/notebooks/IHaskell.ipynb
+++ b/notebooks/IHaskell.ipynb
@@ -2670,6 +2670,11 @@
"collapsed": false
},
"outputs": [
+ {
+ "data": {},
+ "metadata": {},
+ "output_type": "display_data"
+ },
{
"data": {
"text/html": [
@@ -2769,10 +2774,119 @@
".suggestion-name {\n",
" font-weight: bold;\n",
"}\n",
- "InvalidUrlException \"https://www.haskell.org/hoogle/?hoogle=:: [a] -> [(a, b)]&mode=json\" \"Invalid URL\""
- ],
- "text/plain": [
- "InvalidUrlException \"https://www.haskell.org/hoogle/?hoogle=:: [a] -> [(a, b)]&mode=json\" \"Invalid URL\""
+ "zip ∷ [a] → [b] → [(a, b)](package base, module Prelude)
zip takes two lists and returns a list of corresponding pairs. If one input list is short, excess elements of the longer list are discarded. \n",
+ "
\n",
+ "
\n",
+ "(>*<) ∷ Monoidal f ⇒ f a → f b → f (a, b)(package bytestring, module Data.ByteString.Builder.Prim)A pairing/concatenation operator for builder primitives, both bounded and fixed size.\n",
+ "
\n",
+ "
\n",
+ "
For example,\n",
+ "
\n",
+ "
\n",
+ "
> toLazyByteString (primFixed (char7 >*< char7) ('x','y')) = \"xy\"\n",
+ "
\n",
+ "
\n",
+ "
We can combine multiple primitives using >*< multiple times.\n",
+ "
\n",
+ "
\n",
+ "
> toLazyByteString (primFixed (char7 >*< char7 >*< char7) ('x',('y','z'))) = \"xyz\" \n",
+ "
\n",
+ "
\n",
+ "listens ∷ MonadWriter w m ⇒ (w → b) → m a → m (a, b)(package mtl, module Control.Monad.Writer.Class)listens f m is an action that executes the action m and adds the result of applying f to the output to the value of the computation.\n",
+ "
\n",
+ "
\n",
+ "
* f m = liftM (id *** f) (listen\n",
+ "
\n",
+ "
> \n",
+ "
\n",
+ "
\n",
+ "listen ∷ MonadWriter w m ⇒ m a → m (a, w)(package mtl, module Control.Monad.Writer.Class)\n",
+ "lpre ∷ Graph gr ⇒ gr a b → Node → [(Node, b)](package fgl, module Data.Graph.Inductive.Graph)Find all Nodes that link to the given Node and the label of each link. \n",
+ "
\n",
+ "
\n",
+ "lsuc ∷ Graph gr ⇒ gr a b → Node → [(Node, b)](package fgl, module Data.Graph.Inductive.Graph)Find all Nodes that are linked from the given Node and the label of each link. \n",
+ "
\n",
+ "
\n",
+ "apply ∷ GT m g a → m g → m (a, g)(package fgl, module Data.Graph.Inductive.Query.Monad)\n",
+ "shrinkState ∷ ShrinkState s a ⇒ a → s → [(a, s)](package QuickCheck, module Test.QuickCheck.Modifiers)\n",
+ "execRWS ∷ RWS r w s a → r → s → (s, w)(package transformers, module Control.Monad.Trans.RWS.Lazy)Evaluate a computation with the given initial state and environment, returning the final state and output, discarding the final value. \n",
+ "
\n",
+ "
\n",
+ "genUNodes ∷ Int → [UNode](package fgl, module Data.Graph.Inductive.Example)generate list of unlabeled nodes \n",
+ "
\n",
+ "
\n",
+ "genLNodes ∷ Enum a ⇒ a → Int → [LNode a](package fgl, module Data.Graph.Inductive.Example)generate list of labeled nodes \n",
+ "
\n",
+ "
\n",
+ "elemAt ∷ Int → Map k a → (k, a)(package containers, module Data.Map.Lazy)O(log n). Retrieve an element by its index, i.e. by its zero-based index in the sequence sorted by keys. If the index is out of range (less than zero, greater or equal to size of the map), error is called.\n",
+ "
\n",
+ "
\n",
+ "
> elemAt 0 (fromList [(5,\"a\"), (3,\"b\")]) == (3,\"b\")\n",
+ "> elemAt 1 (fromList [(5,\"a\"), (3,\"b\")]) == (5, \"a\")\n",
+ "> elemAt 2 (fromList [(5,\"a\"), (3,\"b\")]) Error: index out of range \n",
+ "
\n",
+ "
\n",
+ "breakOnAll ∷ Text → Text → [(Text, Text)](package text, module Data.Text)O(n+m) Find all non-overlapping instances of needle in haystack. Each element of the returned list consists of a pair:\n",
+ "
\n",
+ "
\n",
+ "
* The entire string prior to the kth match (i.e. the prefix)\n",
+ "
\n",
+ "
* The kth match, followed by the remainder of the string\n",
+ "
\n",
+ "
\n",
+ "
Examples:\n",
+ "
\n",
+ "
\n",
+ "
> breakOnAll \"::\" \"\"\n",
+ "> ==> []\n",
+ "> breakOnAll \"/\" \"a/b/c/\"\n",
+ "> ==> [(\"a\", \"/b/c/\"), (\"a/b\", \"/c/\"), (\"a/b/c\", \"/\")]\n",
+ "
\n",
+ "
\n",
+ "
In (unlikely) bad cases, this function's time complexity degrades towards O(n*m).\n",
+ "
\n",
+ "
\n",
+ "
The needle parameter may not be empty. \n",
+ "
\n",
+ "
\n",
+ "breakOnAll ∷ Text → Text → [(Text, Text)](package text, module Data.Text.Lazy)O(n+m) Find all non-overlapping instances of needle in haystack. Each element of the returned list consists of a pair:\n",
+ "
\n",
+ "
\n",
+ "
* The entire string prior to the kth match (i.e. the prefix)\n",
+ "
\n",
+ "
* The kth match, followed by the remainder of the string\n",
+ "
\n",
+ "
\n",
+ "
Examples:\n",
+ "
\n",
+ "
\n",
+ "
> breakOnAll \"::\" \"\"\n",
+ "> ==> []\n",
+ "> breakOnAll \"/\" \"a/b/c/\"\n",
+ "> ==> [(\"a\", \"/b/c/\"), (\"a/b\", \"/c/\"), (\"a/b/c\", \"/\")]\n",
+ "
\n",
+ "
\n",
+ "
This function is strict in its first argument, and lazy in its second.\n",
+ "
\n",
+ "
\n",
+ "
In (unlikely) bad cases, this function's time complexity degrades towards O(n*m).\n",
+ "
\n",
+ "
\n",
+ "
The needle parameter may not be empty. \n",
+ "
\n",
+ "
\n",
+ "execRWST ∷ Monad m ⇒ RWST r w s m a → r → s → m (s, w)(package transformers, module Control.Monad.Trans.RWS.Lazy)Evaluate a computation with the given initial state and environment, returning the final state and output, discarding the final value. \n",
+ "
\n",
+ "
\n",
+ "level ∷ Graph gr ⇒ Node → gr a b → [(Node, Int)](package fgl, module Data.Graph.Inductive.Query.BFS)\n",
+ "iDom ∷ Graph gr ⇒ gr a b → Node → [(Node, Node)](package fgl, module Data.Graph.Inductive.Query.Dominators)return immediate dominators for each node of a graph, given a root \n",
+ "
\n",
+ "
\n",
+ "gmapAccumT ∷ Data d ⇒ (∀ e. Data e ⇒ a → e → (a, e)) → a → d → (a, d)(package syb, module Data.Generics.Twins)gmapT with accumulation \n",
+ "
\n",
+ "
\n",
+ "buf_span ∷ BufferOp a → (Char → Bool) → a → (a, a)(package HTTP, module Network.BufferType)\n",
+ "buf_splitAt ∷ BufferOp a → Int → a → (a, a)(package HTTP, module Network.BufferType)\n"
]
},
"metadata": {},
diff --git a/src/IHaskell/Eval/Evaluate.hs b/src/IHaskell/Eval/Evaluate.hs
index a40ee1ce..b3c44319 100644
--- a/src/IHaskell/Eval/Evaluate.hs
+++ b/src/IHaskell/Eval/Evaluate.hs
@@ -1212,6 +1212,7 @@ formatErrorWithClass cls =
replace "\n" "
" .
replace useDashV "" .
replace "Ghci" "IHaskell" .
+ replace "‘interactive:" "‘" .
fixDollarSigns .
rstrip .
typeCleaner
diff --git a/src/IHaskell/Eval/Hoogle.hs b/src/IHaskell/Eval/Hoogle.hs
index f6b2c690..bea06598 100644
--- a/src/IHaskell/Eval/Hoogle.hs
+++ b/src/IHaskell/Eval/Hoogle.hs
@@ -14,7 +14,9 @@ import Network.HTTP.Client.TLS
import Data.Aeson
import Data.String.Utils
import Data.List (elemIndex, (!!), last)
+import Data.Char (isAscii, isAlphaNum)
import qualified Data.ByteString.Lazy.Char8 as Char
+import qualified Prelude as P
import IHaskell.IPython
@@ -58,7 +60,7 @@ instance FromJSON HoogleResponse where
-- message or the successful JSON result.
query :: String -> IO (Either String String)
query str = do
- request <- parseUrl $ queryUrl str
+ request <- parseUrl $ queryUrl $ urlEncode str
response <- try $ withManager tlsManagerSettings $ httpLbs request
return $ case response of
Left err -> Left $ show (err :: SomeException)
@@ -67,6 +69,30 @@ query str = do
queryUrl :: String -> String
queryUrl = printf "https://www.haskell.org/hoogle/?hoogle=%s&mode=json"
+-- | Copied from the HTTP package.
+urlEncode :: String -> String
+urlEncode [] = []
+urlEncode (ch:t)
+ | (isAscii ch && isAlphaNum ch) || ch `P.elem` "-_.~" = ch : urlEncode t
+ | not (isAscii ch) = P.foldr escape (urlEncode t) (eightBs [] (P.fromEnum ch))
+ | otherwise = escape (P.fromEnum ch) (urlEncode t)
+ where
+ escape :: Int -> String -> String
+ escape b rs = '%':showH (b `P.div` 16) (showH (b `mod` 16) rs)
+
+ showH :: Int -> String -> String
+ showH x xs
+ | x <= 9 = toEnum (o_0 + x) : xs
+ | otherwise = toEnum (o_A + (x-10)) : xs
+ where
+ o_0 = P.fromEnum '0'
+ o_A = P.fromEnum 'A'
+
+ eightBs :: [Int] -> Int -> [Int]
+ eightBs acc x
+ | x <= 0xff = (x:acc)
+ | otherwise = eightBs ((x `mod` 256) : acc) (x `P.div` 256)
+
-- | Search for a query on Hoogle.
-- Return all search results.
search :: String -> IO [HoogleResult]