packages feed

ihaskell 0.9.1.0 → 0.10.0.0

raw patch · 32 files changed

+741/−1158 lines, 32 filesdep +raw-strings-qqdep +timedep −bin-package-dbdep ~basedep ~ghcdep ~ghc-boot

Dependencies added: raw-strings-qq, time

Dependencies removed: bin-package-db

Dependency ranges changed: base, ghc, ghc-boot

Files

ihaskell.cabal view
@@ -1,20 +1,20 @@ -- The name of the package. name:                ihaskell --- The package version.  See the Haskell package versioning policy (PVP) +-- The package version.  See the Haskell package versioning policy (PVP) -- for standards guiding when and how versions should be incremented. -- http://www.haskell.org/haskellwiki/Package_versioning_policy--- PVP summary:      +-+------- breaking API changes---                   | | +----- non-breaking API additions---                   | | | +--- code changes with no API change-version:             0.9.1.0+-- PVP summary:      +--+------- breaking API changes+--                   |  | +----- non-breaking API additions+--                   |  | | +--- code changes with no API change+version:             0.10.0.0  -- A short (one-line) description of the package. synopsis:            A Haskell backend kernel for the IPython project.  -- A longer description of the package.-description:         IHaskell is a Haskell backend kernel for the IPython project. This allows using Haskell via -                     a console or notebook interface. Additional packages may be installed to provide richer data visualizations. +description:         IHaskell is a Haskell backend kernel for the IPython project. This allows using Haskell via+                     a console or notebook interface. Additional packages may be installed to provide richer data visualizations.  -- URL for the project homepage or repository. homepage:            http://github.com/gibiansky/IHaskell@@ -28,12 +28,12 @@ -- The package author(s). author:              Andrew Gibiansky --- An email address to which users can send suggestions, bug reports, and +-- An email address to which users can send suggestions, bug reports, and -- patches. maintainer:          andrew.gibiansky@gmail.com  -- A copyright notice.--- copyright:           +-- copyright:  category:            Development @@ -42,17 +42,18 @@ -- Constraint on the version of Cabal needed to build this package. cabal-version:       >=1.16 -data-files: +data-files:     html/kernel.js     html/logo-64x64.svg -flag binPkgDb-  default:             False-  description:         bin-package-db package needed (needed for GHC >= 7.10)- library   hs-source-dirs:      src   default-language:    Haskell2010+  ghc-options:         -Wall++  if impl (ghc >= 8.4)+    ghc-options:       -Wpartial-fields+   build-depends:                        aeson                >=1.0,                        base                 >=4.9,@@ -81,18 +82,15 @@                        strict               >=0.3,                        system-argv0         -any,                        text                 >=0.11,+                       time                 >= 1.6,                        transformers         -any,                        unix                 >= 2.6,                        unordered-containers -any,                        utf8-string          -any,                        uuid                 >=1.3,                        vector               -any,-                       ipython-kernel       >=0.9.1-  if flag(binPkgDb)-    build-depends:       bin-package-db--  if impl(ghc >= 8.0)-    build-depends:     ghc-boot             >=8.0 && <8.5+                       ipython-kernel       >=0.9.1,+                       ghc-boot             >=8.0 && <8.7    exposed-modules: IHaskell.Display                    IHaskell.Convert@@ -117,42 +115,50 @@                    IHaskell.BrokenPackages                    IHaskell.CSS                    Paths_ihaskell-  other-modules:                     IHaskellPrelude+  other-modules:                    StringUtils  executable ihaskell   -- .hs or .lhs file containing the Main module.   main-is:             Main.hs   hs-source-dirs: main-  other-modules: -                   IHaskellPrelude+  other-modules:                    Paths_ihaskell-  ghc-options: -threaded -rtsopts-  +  ghc-options: -threaded -rtsopts -Wall++  if os(darwin)+    ghc-options: -optP-Wno-nonportable-include-path++  if impl (ghc >= 8.4)+    ghc-options:       -Wpartial-fields+   -- Other library packages from which modules are imported.   default-language:    Haskell2010-  build-depends:       +  build-depends:                        ihaskell -any,-                       base                 >=4.6 && < 4.12,+                       base                 >=4.9 && < 4.13,                        text                 >=0.11,                        transformers         -any,-                       ghc                  >=7.6 || < 7.11,+                       ghc                  >=8.0 && < 8.7,                        process              >=1.1,                        aeson                >=0.7,                        bytestring           >=0.10,+                       unordered-containers -any,                        containers           >=0.5,                        strict               >=0.3,                        unix                 >= 2.6,                        directory            -any,-                       ipython-kernel       >=0.7--  if flag(binPkgDb)-    build-depends:       bin-package-db+                       ipython-kernel       >=0.7,+                       unordered-containers -any  Test-Suite hspec     Type: exitcode-stdio-1.0-    Ghc-Options: -threaded+    Ghc-Options: -threaded -Wall++    if impl (ghc >= 8.4)+      ghc-options:     -Wpartial-fields+     Main-Is: Hspec.hs     hs-source-dirs: src/tests     other-modules:@@ -160,6 +166,7 @@         IHaskell.Test.Completion         IHaskell.Test.Util         IHaskell.Test.Parser+        IHaskell.Test.Hoogle     default-language: Haskell2010     build-depends:         base,@@ -174,10 +181,8 @@         directory,         text,         shelly,+        raw-strings-qq,         setenv--    if flag(binPkgDb)-        build-depends: bin-package-db  source-repository head   type:     git
− main/IHaskellPrelude.hs
@@ -1,151 +0,0 @@-{-# language NoImplicitPrelude, DoAndIfThenElse, OverloadedStrings, ExtendedDefaultRules #-}{-# LANGUAGE CPP #-}-module IHaskellPrelude (-  module IHaskellPrelude,-  module X,--  -- Select reexports-  Data.Typeable.Typeable,-  Data.Typeable.cast,--#if MIN_VERSION_ghc(7,8,0)-  Data.Typeable.Proxy,--  GHC.Exts.IsString,-  GHC.Exts.IsList,-#endif--  System.IO.hPutStrLn,-  System.IO.hPutStr,-  System.IO.hPutChar,-  System.IO.hPrint,-  System.IO.stdout,-  System.IO.stderr,-  System.IO.stdin,-  System.IO.getChar,-  System.IO.getLine,-  System.IO.writeFile,-  System.IO.Handle,--  System.IO.Strict.readFile,-  System.IO.Strict.getContents,-  System.IO.Strict.hGetContents,--  Control.Exception.catch,-  Control.Exception.SomeException,--  Control.Applicative.Applicative(..),-  Control.Applicative.ZipList(..),-  (Control.Applicative.<$>),--  Control.Concurrent.MVar.MVar,-  Control.Concurrent.MVar.newMVar,-  Control.Concurrent.MVar.newEmptyMVar,-  Control.Concurrent.MVar.isEmptyMVar,-  Control.Concurrent.MVar.readMVar,-  Control.Concurrent.MVar.takeMVar,-  Control.Concurrent.MVar.putMVar,-  Control.Concurrent.MVar.modifyMVar,-  Control.Concurrent.MVar.modifyMVar_,--  Data.IORef.IORef,-  Data.IORef.readIORef,-  Data.IORef.writeIORef,-  Data.IORef.modifyIORef',-  Data.IORef.newIORef,--  --  -- Miscellaneous names-  Data.Map.Map,-  GHC.IO.FilePath,-  Data.Text.Text,-  Data.ByteString.ByteString,-  Text.Printf.printf,-  Data.Function.on,-  ) where--import           Prelude--import           Data.Monoid            as X-import           Data.Tuple             as X-import           Control.Monad          as X-import           Data.Maybe             as X-import           Data.Either            as X-import           Control.Monad.IO.Class as X-import           Data.Ord               as X-import           GHC.Show               as X-import           GHC.Enum               as X-import           GHC.Num                as X-import           GHC.Real               as X-import           GHC.Err                as X hiding (absentErr)-#if MIN_VERSION_ghc(8,0,0)-import           GHC.Base               as X hiding (Any, mapM, foldr, sequence, many, (<|>), Module(..))-#elif MIN_VERSION_ghc(7,10,0)-import           GHC.Base               as X hiding (Any, mapM, foldr, sequence, many, (<|>))-#else-import           GHC.Base               as X hiding (Any)-#endif-import           Data.List              as X hiding (head, last, tail, init, transpose, subsequences, permutations,-                                        foldl, foldl1, maximum, minimum, scanl, scanl1, scanr, scanr1,-                                        span, break, mapAccumL, mapAccumR, dropWhileEnd, (!!),-                                        elemIndices, elemIndex, findIndex, findIndices, zip5, zip6,-                                        zip7, zipWith5, zipWith6, zipWith7, unzip5, unzip6, unzip6,-                                        delete, union, lookup, intersect, insert, deleteBy,-                                        deleteFirstBy, unionBy, intersectBy, group, groupBy, insertBy,-                                        maximumBy, minimumBy, genericLength, genericDrop, genericTake,-                                        genericSplitAt, genericIndex, genericReplicate, inits, tails)--import qualified Control.Applicative-import qualified Data.Typeable-import qualified Data.IORef-import qualified Data.Map-import qualified Data.Text-import qualified Data.Text.Lazy-import qualified Data.ByteString-import qualified Data.ByteString.Lazy-import qualified Data.Function-import qualified GHC.Exts-import qualified System.IO-import qualified System.IO.Strict-import qualified GHC.IO-import qualified Text.Printf-import qualified Control.Exception-import qualified Control.Concurrent.MVar--import qualified Data.List-import qualified Prelude as P--type LByteString = Data.ByteString.Lazy.ByteString--type LText = Data.Text.Lazy.Text--(headMay, tailMay, lastMay, initMay, maximumMay, minimumMay) =-  (wrapEmpty head, wrapEmpty tail, wrapEmpty last,-   wrapEmpty init, wrapEmpty maximum, wrapEmpty minimum)-  where-    wrapEmpty :: ([a] -> b) -> [a] -> Maybe b-    wrapEmpty _ [] = Nothing-    wrapEmpty f xs = Just (f xs)--maximumByMay :: (a -> a -> Ordering) -> [a] -> Maybe a-maximumByMay _ [] = Nothing-maximumByMay f xs = Just (Data.List.maximumBy f xs)--minimumByMay :: (a -> a -> Ordering) -> [a] -> Maybe a-minimumByMay _ [] = Nothing-minimumByMay f xs = Just (Data.List.minimumBy f xs)--readMay :: Read a => String -> Maybe a-readMay = fmap fst . headMay . reads--putStrLn :: (MonadIO m) => String -> m ()-putStrLn = liftIO . P.putStrLn--putStr :: (MonadIO m) => String -> m ()-putStr = liftIO . P.putStr--putChar :: MonadIO m => Char -> m ()-putChar = liftIO . P.putChar--print :: (MonadIO m, Show a) => a -> m ()-print = liftIO . P.print
main/Main.hs view
@@ -7,27 +7,20 @@  import           IHaskellPrelude import qualified Data.Text as T-import qualified Data.Text.Lazy as LT-import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as LBS-import qualified Data.ByteString.Char8 as CBS  -- Standard library imports.-import           Control.Concurrent (threadDelay) import           Control.Concurrent.Chan import           Control.Arrow (second)-import           Data.Aeson-import           System.Directory+import           Data.Aeson hiding (Success) import           System.Process (readProcess, readProcessWithExitCode) import           System.Exit (exitSuccess, ExitCode(ExitSuccess)) import           Control.Exception (try, SomeException) import           System.Environment (getArgs)-#if MIN_VERSION_ghc(7,8,0) import           System.Environment (setEnv)-#endif import           System.Posix.Signals import qualified Data.Map as Map-import qualified Data.Text.Encoding as E+import qualified Data.HashMap.Strict as HashMap import           Data.List (break, last) import           Data.Version (showVersion) @@ -37,7 +30,6 @@ import           IHaskell.Eval.Inspect (inspect) import           IHaskell.Eval.Evaluate import           IHaskell.Display-import           IHaskell.Eval.Info import           IHaskell.Eval.Widgets (widgetHandler) import           IHaskell.Flags import           IHaskell.IPython@@ -51,31 +43,12 @@ -- Cabal imports. import           Paths_ihaskell(version) --- GHC API imports.-#if MIN_VERSION_ghc(8,4,0)-import           GHC hiding (extensions, language, convert)-#else-import           GHC hiding (extensions, language)-#endif---- | Compute the GHC API version number using the dist/build/autogen/cabal_macros.h-ghcVersionInts :: [Int]-ghcVersionInts = map (fromJust . readMay) . words . map dotToSpace $ VERSION_ghc-  where-    dotToSpace '.' = ' '-    dotToSpace x = x--consoleBanner :: Text-consoleBanner =-  "Welcome to IHaskell! Run `IHaskell --help` for more information.\n" <>-  "Enter `:help` to learn more about IHaskell built-ins."- main :: IO () main = do   args <- parseFlags <$> getArgs   case args of     Left errorMessage -> hPutStrLn stderr errorMessage-    Right args        -> ihaskell args+    Right xs          -> ihaskell xs  ihaskell :: Args -> IO () ihaskell (Args (ShowDefault helpStr) args) = showDefault helpStr args@@ -123,16 +96,16 @@       kernelSpecOpts { kernelSpecInstallPrefix = Just prefix }     addFlag kernelSpecOpts KernelspecUseStack =       kernelSpecOpts { kernelSpecUseStack = True }-    addFlag kernelSpecOpts flag = error $ "Unknown flag" ++ show flag+    addFlag _kernelSpecOpts flag = error $ "Unknown flag" ++ show flag  -- | Run the IHaskell language kernel. runKernel :: KernelSpecOptions -- ^ Various options from when the kernel was installed.           -> String            -- ^ File with kernel profile JSON (ports, etc).           -> IO ()-runKernel kernelOpts profileSrc = do-  let debug = kernelSpecDebug kernelOpts-      libdir = kernelSpecGhcLibdir kernelOpts-      useStack = kernelSpecUseStack kernelOpts+runKernel kOpts profileSrc = do+  let debug = kernelSpecDebug kOpts+      libdir = kernelSpecGhcLibdir kOpts+      useStack = kernelSpecUseStack kOpts    -- Parse the profile file.   let profileErr = error $ "ihaskell: "++profileSrc++": Failed to parse profile file"@@ -142,12 +115,11 @@   dir <- getIHaskellDir   Stdin.recordKernelProfile dir profile -#if MIN_VERSION_ghc(7,8,0)   when useStack $ do     -- Detect if we have stack     runResult <- try $ readProcessWithExitCode "stack" [] ""-    let stack = -          case runResult :: Either SomeException (ExitCode, String, String) of +    let stack =+          case runResult :: Either SomeException (ExitCode, String, String) of             Left _ -> False             Right (exitCode, stackStdout, _) -> exitCode == ExitSuccess && "The Haskell Tool Stack" `isInfixOf` stackStdout @@ -160,7 +132,6 @@         in case tailMay val of             Nothing -> return ()             Just val' -> setEnv var val'-#endif    -- Serve on all sockets and ports defined in the profile.   interface <- serveProfile profile debug@@ -174,21 +145,21 @@   interpret libdir True $ \hasSupportLibraries -> do     -- Ignore Ctrl-C the first time. This has to go inside the `interpret`, because GHC API resets the     -- signal handlers for some reason (completely unknown to me).-    liftIO ignoreCtrlC+    _ <- liftIO ignoreCtrlC      liftIO $ modifyMVar_ state $ \kernelState -> return $               kernelState { supportLibrariesAvailable = hasSupportLibraries }      -- Initialize the context by evaluating everything we got from the command line flags.-    let noPublish _ = return ()+    let noPublish _ _ = return ()         noWidget s _ = return s         evaluator line = void $ do           -- Create a new state each time.           stateVar <- liftIO initialKernelState-          state <- liftIO $ takeMVar stateVar-          evaluate state line noPublish noWidget+          st <- liftIO $ takeMVar stateVar+          evaluate st line noPublish noWidget -    confFile <- liftIO $ kernelSpecConfFile kernelOpts+    confFile <- liftIO $ kernelSpecConfFile kOpts     case confFile of       Just filename -> liftIO (readFile filename) >>= evaluator       Nothing       -> return ()@@ -225,7 +196,7 @@       installHandler keyboardSignal (CatchOnce $ putStrLn "Press Ctrl-C again to quit kernel.")         Nothing -    isCommMessage req = msgType (header req) `elem` [CommDataMessage, CommCloseMessage]+    isCommMessage req = mhMsgType (header req) `elem` [CommDataMessage, CommCloseMessage]  -- Initial kernel state. initialKernelState :: IO (MVar KernelState)@@ -236,19 +207,11 @@ createReplyHeader parent = do   -- Generate a new message UUID.   newMessageId <- liftIO UUID.random-  let repType = fromMaybe err (replyType $ msgType parent)-      err = error $ "No reply for message " ++ show (msgType parent)+  let repType = fromMaybe err (replyType $ mhMsgType parent)+      err = error $ "No reply for message " ++ show (mhMsgType parent) -  return-    MessageHeader-      { identifiers = identifiers parent-      , parentHeader = Just parent-      , metadata = Map.fromList []-      , messageId = newMessageId-      , sessionId = sessionId parent-      , username = username parent-      , msgType = repType-      }+  return $ MessageHeader (mhIdentifiers parent) (Just parent) mempty+            newMessageId (mhSessionId parent) (mhUsername parent) repType  -- | Compute a reply to a message. replyTo :: ZeroMQInterface -> Message -> MessageHeader -> KernelState -> Interpreter (KernelState, Message)@@ -258,7 +221,7 @@ replyTo interface KernelInfoRequest{} replyHeader state = do   let send msg = liftIO $ writeChan (iopubChannel interface) msg -  -- Notify the frontend that the Kernel is idle +  -- Notify the frontend that the Kernel is idle   idleHeader <- liftIO $ dupHeader replyHeader StatusMessage   send $ PublishStatus idleHeader Idle @@ -289,8 +252,8 @@  -- Reply to a shutdown request by exiting the main thread. Before shutdown, reply to the request to -- let the frontend know shutdown is happening.-replyTo interface ShutdownRequest { restartPending = restartPending } replyHeader _ = liftIO $ do-  writeChan (shellReplyChannel interface) $ ShutdownReply replyHeader restartPending+replyTo interface ShutdownRequest { restartPending = pending } replyHeader _ = liftIO $ do+  writeChan (shellReplyChannel interface) $ ShutdownReply replyHeader pending   exitSuccess  -- Reply to an execution request. The reply itself does not require computation, but this causes@@ -315,7 +278,7 @@   -- re-display with the updated output.   displayed <- liftIO $ newMVar []   updateNeeded <- liftIO $ newMVar False-  pagerOutput <- liftIO $ newMVar []+  pOut <- liftIO $ newMVar []    let execCount = getExecutionCounter state   -- Let all frontends know the execution count and code that's about to run@@ -324,7 +287,7 @@    -- Run code and publish to the frontend as we go.   let widgetMessageHandler = widgetHandler send replyHeader-      publish = publishResult send replyHeader displayed updateNeeded pagerOutput (usePager state)+      publish = publishResult send replyHeader displayed updateNeeded pOut (usePager state)   updatedState <- evaluate state (T.unpack code) publish widgetMessageHandler    -- Notify the frontend that we're done computing.@@ -333,7 +296,7 @@    -- Take pager output if we're using the pager.   pager <- if usePager state-             then liftIO $ readMVar pagerOutput+             then liftIO $ readMVar pOut              else return []   return     (updatedState, ExecuteReply@@ -366,7 +329,7 @@    let start = pos - length matchedText       end = pos-      reply = CompleteReply replyHeader (map T.pack completions) start end Map.empty True+      reply = CompleteReply replyHeader (map T.pack completions) start end (Metadata HashMap.empty) True   return (state, reply)  replyTo _ req@InspectRequest{} replyHeader state = do@@ -401,14 +364,14 @@ -- -- Sending the message only on the shell_reply channel doesn't work, so we send it as a comm message -- on the iopub channel and return the SendNothing message.-replyTo interface open@CommOpen{} replyHeader state = do-  let send msg = liftIO $ writeChan (iopubChannel interface) msg+replyTo interface ocomm@CommOpen{} replyHeader state = do+  let send = liftIO . writeChan (iopubChannel interface) -      incomingUuid = commUuid open-      target = commTargetName open+      incomingUuid = commUuid ocomm+      target = commTargetName ocomm        targetMatches = target == "ipython.widget"-      valueMatches = commData open == object ["widget_class" .= "ipywidgets.CommInfo"]+      valueMatches = commData ocomm == object ["widget_class" .= ("ipywidgets.CommInfo" :: Text)]        commMap = openComms state       uuidTargetPairs = map (second targetName) $ Map.toList commMap@@ -417,11 +380,11 @@        currentComms = object $ map pairProcessor $ (incomingUuid, "comm") : uuidTargetPairs -      replyValue = object [ "method" .= "custom"+      replyValue = object [ "method" .= ("custom" :: Text)                           , "content" .= object ["comms" .= currentComms]                           ] -      msg = CommData replyHeader (commUuid open) replyValue+      msg = CommData replyHeader (commUuid ocomm) replyValue    -- To the iopub channel you go   when (targetMatches && valueMatches) $ send msg@@ -439,7 +402,7 @@   -- MVars to hold intermediate data during publishing   displayed <- liftIO $ newMVar []   updateNeeded <- liftIO $ newMVar False-  pagerOutput <- liftIO $ newMVar []+  pOut <- liftIO $ newMVar []    let widgets = openComms kernelState       uuid = commUuid req@@ -453,7 +416,7 @@   -- a function that executes an IO action and publishes the output to   -- the frontend simultaneously.   let run = capturedIO publish kernelState-      publish = publishResult send replyHeader displayed updateNeeded pagerOutput toUsePager+      publish = publishResult send replyHeader displayed updateNeeded pOut toUsePager    -- Notify the frontend that the kernel is busy   busyHeader <- liftIO $ dupHeader replyHeader StatusMessage@@ -462,17 +425,20 @@   newState <- case Map.lookup uuid widgets of     Nothing -> return kernelState     Just (Widget widget) ->-      case msgType $ header req of+      case mhMsgType $ header req of         CommDataMessage -> do           disp <- run $ comm widget dat communicate-          pgrOut <- liftIO $ readMVar pagerOutput-          liftIO $ publish $ FinalResult disp (if toUsePager then pgrOut else []) []+          pgrOut <- liftIO $ readMVar pOut+          liftIO $ publish (FinalResult disp (if toUsePager then pgrOut else []) []) Success           return kernelState         CommCloseMessage -> do           disp <- run $ close widget dat-          pgrOut <- liftIO $ readMVar pagerOutput-          liftIO $ publish $ FinalResult disp (if toUsePager then pgrOut else []) []+          pgrOut <- liftIO $ readMVar pOut+          liftIO $ publish (FinalResult disp (if toUsePager then pgrOut else []) []) Success           return kernelState { openComms = Map.delete uuid widgets }+        _ ->+          -- Only sensible thing to do.+          return kernelState    -- Notify the frontend that the kernel is idle once again   idleHeader <- liftIO $ dupHeader replyHeader StatusMessage
src/IHaskell/BrokenPackages.hs view
@@ -4,27 +4,22 @@  import           IHaskellPrelude import qualified Data.Text as T-import qualified Data.Text.Lazy as LT-import qualified Data.ByteString as BS-import qualified Data.ByteString.Lazy as LBS-import qualified Data.ByteString.Char8 as CBS  import           Text.Parsec import           Text.Parsec.String-import           Control.Applicative hiding ((<|>), many)  import           Shelly -data BrokenPackage = BrokenPackage { packageID :: String, brokenDeps :: [String] }+data BrokenPackage = BrokenPackage String [String]  instance Show BrokenPackage where-  show = packageID+  show (BrokenPackage packageID _) = packageID  -- | Get a list of broken packages. This function internally shells out to `ghc-pkg`, and parses the -- output in order to determine what packages are broken. getBrokenPackages :: IO [String] getBrokenPackages = shelly $ do-  silently $ errExit False $ run "ghc-pkg" ["check"]+  _ <- silently $ errExit False $ run "ghc-pkg" ["check"]   checkOut <- lastStderr    -- Get rid of extraneous things@@ -34,7 +29,7 @@    return $     case parse (many check) "ghc-pkg output" ghcPkgOutput of-      Left err   -> []+      Left _     -> []       Right pkgs -> map show pkgs  check :: Parser BrokenPackage
src/IHaskell/CSS.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE NoImplicitPrelude #-} module IHaskell.CSS (ihaskellCSS) where  import           IHaskellPrelude@@ -5,7 +6,7 @@ ihaskellCSS :: String ihaskellCSS =   unlines-    [ +    [     -- Custom IHaskell CSS     "/* Styles used for the Hoogle display in the pager */"     , ".hoogle-doc {"@@ -42,7 +43,7 @@     , ".hoogle-class {"     , "font-weight: bold;"     , "}"-    , +    ,     -- Styles used for basic displays     ".get-type {"     , "color: green;"@@ -75,13 +76,13 @@     , ".err-msg.in.collapse {"     , "padding-top: 0.7em;"     , "}"-    , +    ,     -- Code that will get highlighted before it is highlighted     ".highlight-code {"     , "white-space: pre;"     , "font-family: monospace;"     , "}"-    , +    ,     -- Hlint styles     ".suggestion-warning { "     , "font-weight: bold;"
src/IHaskell/Convert.hs view
@@ -1,14 +1,9 @@ {-# LANGUAGE NoImplicitPrelude #-} --- | Description : mostly reversible conversion between ipynb and lhs +-- | Description : mostly reversible conversion between ipynb and lhs module IHaskell.Convert (convert) where  import           IHaskellPrelude-import qualified Data.Text as T-import qualified Data.Text.Lazy as LT-import qualified Data.ByteString as BS-import qualified Data.ByteString.Lazy as LBS-import qualified Data.ByteString.Char8 as CBS  import           Control.Monad.Identity (Identity(Identity), unless, when) import           IHaskell.Convert.Args (ConvertSpec(..), fromJustConvertSpec, toConvertSpec)
src/IHaskell/Convert/Args.hs view
@@ -4,18 +4,13 @@ module IHaskell.Convert.Args (ConvertSpec(..), fromJustConvertSpec, toConvertSpec) where  import           IHaskellPrelude-import qualified Data.Text as T import qualified Data.Text.Lazy as LT-import qualified Data.ByteString as BS-import qualified Data.ByteString.Lazy as LBS-import qualified Data.ByteString.Char8 as CBS  import           Control.Applicative ((<$>)) import           Control.Monad.Identity (Identity(Identity)) import           Data.Char (toLower) import           Data.List (partition) import           Data.Maybe (fromMaybe)-import qualified Data.Text.Lazy as T (pack, Text) import           IHaskell.Flags (Argument(..), LhsStyle, lhsStyleBird, NotebookFormat(..)) import           System.FilePath ((<.>), dropExtension, takeExtension) import           Text.Printf (printf)@@ -40,11 +35,11 @@   , convertLhsStyle = Identity $ fromMaybe (LT.pack <$> lhsStyleBird) (convertLhsStyle convertSpec)   }   where-    toIpynb = fromMaybe (error "Error: direction for conversion unknown")+    toIpynb = fromMaybe (error "fromJustConvertSpec: direction for conversion unknown")                 (convertToIpynb convertSpec)     (inputFile, outputFile) =       case (convertInput convertSpec, convertOutput convertSpec) of-        (Nothing, Nothing) -> error "Error: no files specified for conversion"+        (Nothing, Nothing) -> error "fromJustConvertSpec: no files specified for conversion"         (Just i, Nothing)           | toIpynb -> (i, dropExtension i <.> "ipynb")           | otherwise -> (i, dropExtension i <.> "lhs")
src/IHaskell/Convert/IpynbToLhs.hs view
@@ -4,11 +4,8 @@ module IHaskell.Convert.IpynbToLhs (ipynbToLhs) where  import           IHaskellPrelude-import qualified Data.Text as T import qualified Data.Text.Lazy as LT-import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as LBS-import qualified Data.ByteString.Char8 as CBS  import           Data.Aeson (decode, Object, Value(Array, Object, String)) import           Data.Vector (Vector)@@ -49,12 +46,12 @@   = s convCell sty object   | Just (String "code") <- lookup "cell_type" object,-    Just (Array i) <- lookup "source" object,+    Just (Array a) <- lookup "source" object,     Just (Array o) <- lookup "outputs" object,-    ~(Just i) <- concatWithPrefix (lhsCodePrefix sty) i,-    o <- fromMaybe mempty (convOutputs sty o)+    ~(Just i) <- concatWithPrefix (lhsCodePrefix sty) a,+    o2 <- fromMaybe mempty (convOutputs sty o)   = "\n" <>-    lhsBeginCode sty <> i <> lhsEndCode sty <> "\n" <> o <> "\n"+    lhsBeginCode sty <> i <> lhsEndCode sty <> "\n" <> o2 <> "\n" convCell _ _ = "IHaskell.Convert.convCell: unknown cell"  convOutputs :: LhsStyle LT.Text
src/IHaskell/Convert/LhsToIpynb.hs view
@@ -6,13 +6,11 @@ import           IHaskellPrelude import qualified Data.Text as T import qualified Data.Text.Lazy as LT-import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as LBS-import qualified Data.ByteString.Char8 as CBS  import           Data.Aeson ((.=), encode, object, Value(Array, Bool, Number, String, Null)) import           Data.Char (isSpace)-import qualified Data.Vector as V (fromList, singleton)+import qualified Data.Vector as V import qualified Data.List as List  import           IHaskell.Flags (LhsStyle(LhsStyle))@@ -97,12 +95,12 @@  groupClassified :: [CellLine LText] -> [Cell [LText]] groupClassified (CodeLine a:x)-  | (c, x) <- List.span isCode x,-    (_, x) <- List.span isEmptyMD x,-    (o, x) <- List.span isOutput x-  = Code (a : map untag c) (map untag o) : groupClassified x+  | (c, x1) <- List.span isCode x,+    (_, x2) <- List.span isEmptyMD x1,+    (o, x3) <- List.span isOutput x2+  = Code (a : map untag c) (map untag o) : groupClassified x3 groupClassified (MarkdownLine a:x)-  | (m, x) <- List.span isMD x = Markdown (a : map untag m) : groupClassified x+  | (m, x1) <- List.span isMD x = Markdown (a : map untag m) : groupClassified x1 groupClassified (OutputLine a:x) = Markdown [a] : groupClassified x groupClassified [] = [] 
src/IHaskell/Display.hs view
@@ -42,7 +42,7 @@     -- ** Image and data encoding functions     Width,     Height,-    Base64(..),+    Base64,     encode64,     base64, @@ -57,14 +57,10 @@  import           IHaskellPrelude import qualified Data.Text as T-import qualified Data.Text.Lazy as LT-import qualified Data.ByteString as BS-import qualified Data.ByteString.Lazy as LBS import qualified Data.ByteString.Char8 as CBS  import           Data.Serialize as Serialize import qualified Data.ByteString.Base64 as Base64-import           Data.Aeson (Value) import           System.Directory (getTemporaryDirectory, setCurrentDirectory)  import           Control.Concurrent.STM (atomically)@@ -80,28 +76,6 @@  type Base64 = Text --- | these instances cause the image, html etc. which look like:------ > Display--- > [Display]--- > IO [Display]--- > IO (IO Display)------ be run the IO and get rendered (if the frontend allows it) in the pretty form.-instance IHaskellDisplay a => IHaskellDisplay (IO a) where-  display = (display =<<)--instance IHaskellDisplay Display where-  display = return--instance IHaskellDisplay DisplayData where-  display disp = return $ Display [disp]--instance IHaskellDisplay a => IHaskellDisplay [a] where-  display disps = do-    displays <- mapM display disps-    return $ ManyDisplay displays- -- | Encode many displays into a single one. All will be output. many :: [Display] -> Display many = ManyDisplay@@ -201,6 +175,7 @@  -- | Convenience function for client libraries. Switch to a temporary directory so that any files we -- create aren't visible. On Unix, this is usually /tmp.+switchToTmpDir :: IO () switchToTmpDir = void (try switchDir :: IO (Either SomeException ()))   where     switchDir =
src/IHaskell/Eval/Completion.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE CPP, DoAndIfThenElse, TypeFamilies, FlexibleContexts #-}+{-# LANGUAGE CPP, NoImplicitPrelude, DoAndIfThenElse, TypeFamilies, FlexibleContexts #-}  {- | Description:    Generates tab completion options.@@ -13,37 +13,21 @@ module IHaskell.Eval.Completion (complete, completionTarget, completionType, CompletionType(..)) where  import           IHaskellPrelude-import qualified Data.Text as T-import qualified Data.Text.Lazy as LT-import qualified Data.ByteString as BS-import qualified Data.ByteString.Lazy as LBS-import qualified Data.ByteString.Char8 as CBS  import           Control.Applicative ((<$>))-import           Data.ByteString.UTF8 hiding (drop, take, lines, length) import           Data.Char-import           Data.List (nub, init, last, head, elemIndex, concatMap)+import           Data.List (nub, init, last, elemIndex, concatMap) import qualified Data.List.Split as Split import qualified Data.List.Split.Internals as Split-import           Data.Maybe (fromJust) import           System.Environment (getEnv) -import           GHC hiding (Qualified)-#if MIN_VERSION_ghc(8,2,0)+import           GHC import           GHC.PackageDb-#elif MIN_VERSION_ghc(7,10,0)-import           GHC.PackageDb (ExposedModule(exposedName))-#endif import           DynFlags import           GhcMonad-import qualified GhcMonad-import           PackageConfig import           Outputable (showPpr)-import           MonadUtils (MonadIO) - import           System.Directory-import           System.FilePath import           Control.Exception (try)  import           System.Console.Haskeline.Completion@@ -63,16 +47,15 @@                     | KernelOption String                     | Extension String   deriving (Show, Eq)+ #if MIN_VERSION_ghc(8,2,0)+exposedName :: (a, b) -> a exposedName = fst #endif-#if MIN_VERSION_ghc(7,10,0)++extName :: FlagSpec flag -> String extName (FlagSpec { flagSpecName = name }) = name-#else-extName (name, _, _) = name -exposedName = id-#endif complete :: String -> Int -> Interpreter (String, [String]) complete code posOffset = do   -- Get the line of code which is being completed and offset within that line@@ -93,11 +76,7 @@    let Just db = pkgDatabase flags       getNames = map (moduleNameString . exposedName) . exposedModules-#if MIN_VERSION_ghc(8,0,0)       moduleNames = nub $ concatMap getNames $ concatMap snd db-#else-      moduleNames = nub $ concatMap getNames db-#endif    let target = completionTarget line pos       completion = completionType line pos target@@ -106,7 +85,7 @@         case completion of           HsFilePath _ match -> match           FilePath _ match   -> match-          otherwise          -> intercalate "." target+          _                  -> intercalate "." target    options <- case completion of                Empty -> return []@@ -114,9 +93,8 @@                Identifier candidate ->                  return $ filter (candidate `isPrefixOf`) unqualNames -               Qualified moduleName candidate -> do-                 trueName <- getTrueModuleName moduleName-                 let prefix = intercalate "." [moduleName, candidate]+               Qualified mName candidate -> do+                 let prefix = intercalate "." [mName, candidate]                      completions = filter (prefix `isPrefixOf`) qualNames                  return completions @@ -127,17 +105,11 @@                  return $ filter (prefix `isPrefixOf`) moduleNames                 DynFlag ext -> do-                 -- Possibly leave out the fLangFlags? The -XUndecidableInstances vs. obsolete-                 -- -fallow-undecidable-instances.-                 let kernelOptNames = concatMap getSetName kernelOpts-                     otherNames = ["-package", "-Wall", "-w"]+                 -- Possibly leave out the fLangFlags?+                 let otherNames = ["-package", "-Wall", "-w"]                       fNames = map extName fFlags ++-#if MIN_VERSION_ghc(8,0,0)                               map extName wWarningFlags ++-#else-                              map extName fWarningFlags ++-#endif                               map extName fLangFlags                      fNoNames = map ("no" ++) fNames                      fAllNames = map ("-f" ++) (fNames ++ fNoNames)@@ -155,34 +127,17 @@                      xNoNames = map ("No" ++) xNames                  return $ filter (ext `isPrefixOf`) $ xNames ++ xNoNames -               HsFilePath lineUpToCursor match -> completePathWithExtensions [".hs", ".lhs"]+               HsFilePath lineUpToCursor _match -> completePathWithExtensions [".hs", ".lhs"]                                                     lineUpToCursor -               FilePath lineUpToCursor match -> completePath lineUpToCursor+               FilePath lineUpToCursor _match -> completePath lineUpToCursor                 KernelOption str -> return $                  filter (str `isPrefixOf`) (concatMap getOptionName kernelOpts)    return (matchedText, options) -getTrueModuleName :: String -> Interpreter String-getTrueModuleName name = do-  -- Only use the things that were actually imported-  let onlyImportDecl (IIDecl decl) = Just decl-      onlyImportDecl _ = Nothing -  -- Get all imports that we use.-  imports <- catMaybes <$> map onlyImportDecl <$> getContext--  -- Find the ones that have a qualified name attached. If this name isn't one of them, it already is-  -- the true name.-  flags <- getSessionDynFlags-  let qualifiedImports = filter (isJust . ideclAs) imports-      hasName imp = name == (showPpr flags . fromJust . ideclAs) imp-  case find hasName qualifiedImports of-    Nothing      -> return name-    Just trueImp -> return $ showPpr flags $ unLoc $ ideclName trueImp- -- | Get which type of completion this is from the surrounding context. completionType :: String            -- ^ The line on which the completion is being done.                -> Int                -- ^ Location of the cursor in the line.@@ -241,7 +196,7 @@             else []         Left _ -> Empty -    cursorInString str loc = nquotes (take loc str) `mod` 2 /= 0+    cursorInString str lcn = nquotes (take lcn str) `mod` 2 /= (0 :: Int)      nquotes ('\\':'"':xs) = nquotes xs     nquotes ('"':xs) = 1 + nquotes xs@@ -255,12 +210,12 @@       where         go acc rest =           case rest of-            '"':'\\':rem -> go ('"' : acc) rem-            '"':rem      -> acc-            ' ':'\\':rem -> go (' ' : acc) rem-            ' ':rem      -> acc-            x:rem        -> go (x : acc) rem-            []           -> acc+            '"':'\\':xs -> go ('"' : acc) xs+            '"':_       -> acc+            ' ':'\\':xs -> go (' ' : acc) xs+            ' ':_       -> acc+            x:xs        -> go (x : acc) xs+            []          -> acc  -- | Get the word under a given cursor location. completionTarget :: String -> Int -> [String]@@ -269,7 +224,7 @@     pieceToComplete = map fst <$> find (elem cursor . map snd) pieces     pieces = splitAlongCursor $ Split.split splitter $ zip code [1 ..]     splitter = Split.defaultSplitter-      { +      {       -- Split using only the characters, which are the first elements of the (char, index) tuple       Split.delimiter = Split.Delimiter [uncurry isDelim]       -- Condense multiple delimiters into one and then drop them.@@ -278,7 +233,7 @@       }      isDelim :: Char -> Int -> Bool-    isDelim char idx = char `elem` neverIdent || isSymbol char+    isDelim char _idx = char `elem` neverIdent || isSymbol char      splitAlongCursor :: [[(Char, Int)]] -> [[(Char, Int)]]     splitAlongCursor [] = []@@ -318,8 +273,8 @@     acceptAll = const True  completePathWithExtensions :: [String] -> String -> Interpreter [String]-completePathWithExtensions extensions line =-  completePathFilter (extensionIsOneOf extensions) acceptAll line ""+completePathWithExtensions extns line =+  completePathFilter (extensionIsOneOf extns) acceptAll line ""   where     acceptAll = const True     extensionIsOneOf exts str = any correctEnding exts
src/IHaskell/Eval/Evaluate.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE NoOverloadedStrings, TypeSynonymInstances, GADTs, CPP #-}+{-# LANGUAGE NoOverloadedStrings, NoImplicitPrelude, TypeSynonymInstances, GADTs, CPP #-}  {- | Description : Wrapper around GHC API, exposing a single `evaluate` interface that runs                    a statement, declaration, import, or directive.@@ -19,64 +19,36 @@     ) where  import           IHaskellPrelude-import qualified Data.Text as T-import qualified Data.Text.Lazy as LT-import qualified Data.ByteString as BS-import qualified Data.ByteString.Lazy as LBS-import qualified Data.ByteString.Char8 as CBS  import           Control.Concurrent (forkIO, threadDelay) import           Data.Foldable (foldMap)-import           Prelude (putChar, head, tail, last, init, (!!))-import           Data.List (findIndex, and, foldl1, nubBy)-import           Text.Printf+import           Prelude (head, tail, last, init)+import           Data.List (nubBy) import           Data.Char as Char import           Data.Dynamic-import           Data.Typeable import qualified Data.Serialize as Serialize import           System.Directory #if !MIN_VERSION_base(4,8,0) import           System.Posix.IO (createPipe) #endif import           System.Posix.IO (fdToHandle)-import           System.IO (hGetChar, hSetEncoding, utf8, hFlush)+import           System.IO (hGetChar, hSetEncoding, utf8) import           System.Random (getStdGen, randomRs)-import           Unsafe.Coerce-import           Control.Monad (guard) import           System.Process import           System.Exit-import           Data.Maybe (fromJust)-import qualified Control.Monad.IO.Class as MonadIO (MonadIO, liftIO)-import qualified MonadUtils (MonadIO, liftIO)+import           Data.Maybe (mapMaybe) import           System.Environment (getEnv)-import qualified Data.Map as Map  import qualified GHC.Paths-import           NameSet-import           Name-import           PprTyThing import           InteractiveEval import           DynFlags-import           Type import           Exception (gtry) import           HscTypes-import           HscMain-import qualified Linker-import           TcType-import           Unify-import           InstEnv-#if MIN_VERSION_ghc(7, 8, 0)-import           GhcMonad (liftIO, withSession)-#else-import           GhcMonad (withSession)-#endif+import           GhcMonad (liftIO) import           GHC hiding (Stmt, TypeSig) import           Exception hiding (evaluate) import           Outputable hiding ((<>)) import           Packages-import           Module hiding (Module)-import qualified Pretty-import           FastString import           Bag import qualified ErrUtils @@ -87,18 +59,18 @@ import           IHaskell.Display import qualified IHaskell.Eval.Hoogle as Hoogle import           IHaskell.Eval.Util-import           IHaskell.Eval.Widgets import           IHaskell.BrokenPackages-import qualified IHaskell.IPython.Message.UUID as UUID import           StringUtils (replace, split, strip, rstrip) +#if MIN_VERSION_ghc(8,2,0)+import           FastString (unpackFS)+#else import           Paths_ihaskell (version) import           Data.Version (versionBranch)+#endif -data ErrorOccurred = Success-                   | Failure-  deriving (Show, Eq) + -- | Set GHC's verbosity for debugging ghcVerbosity :: Maybe Int ghcVerbosity = Nothing -- Just 5@@ -126,12 +98,7 @@ write state x = when (kernelDebug state) $ liftIO $ hPutStrLn stderr $ "DEBUG: " ++ x  type Interpreter = Ghc-#if MIN_VERSION_ghc(7, 8, 0)-   -- GHC 7.8 exports a MonadIO instance for Ghc-#else-instance MonadIO.MonadIO Interpreter where-  liftIO = MonadUtils.liftIO-#endif+ requiredGlobalImports :: [String] requiredGlobalImports =   [ "import qualified Prelude as IHaskellPrelude"@@ -151,12 +118,12 @@  -- | Interpreting function for testing. testInterpret :: Interpreter a -> IO a-testInterpret val = interpret GHC.Paths.libdir False (const val)+testInterpret v = interpret GHC.Paths.libdir False (const v)  -- | Evaluation function for testing. testEvaluate :: String -> IO () testEvaluate str = void $ testInterpret $-  evaluate defaultKernelState str (const $ return ()) (\state _ -> return state)+  evaluate defaultKernelState str (\_ _ -> return ()) (\state _ -> return state)  -- | Run an interpreting action. This is effectively runGhc with initialization and importing. First -- argument indicates whether `stdin` is handled specially, which cannot be done in a testing@@ -194,23 +161,13 @@       Just cfg -> let         PackageName name = packageName cfg         in unpackFS name-#elif MIN_VERSION_ghc(8,0,0)-    fromMaybe "(unknown)" (unitIdPackageIdString dflags $ packageConfigId pkg_cfg)-#elif MIN_VERSION_ghc(7,10,2)-    fromMaybe "(unknown)" (packageKeyPackageIdString dflags $ packageConfigId pkg_cfg)-#elif MIN_VERSION_ghc(7,10,0)-    packageKeyPackageIdString dflags . packageConfigId #else-    packageIdString . packageConfigId+    fromMaybe "(unknown)" (unitIdPackageIdString dflags $ packageConfigId pkg_cfg) #endif  getPackageConfigs :: DynFlags -> [PackageConfig] getPackageConfigs dflags =-#if MIN_VERSION_ghc(8,0,0)     foldMap snd pkgDb-#else-    pkgDb-#endif   where     Just pkgDb = pkgDatabase dflags @@ -222,9 +179,9 @@   -- version of the ihaskell library. Also verify that the packages we load are not broken.   dflags <- getSessionDynFlags   broken <- liftIO getBrokenPackages-  (dflags, _) <- liftIO $ initPackages dflags-  let db = getPackageConfigs dflags-      packageNames = map (packageIdString' dflags) db+  (dflgs, _) <- liftIO $ initPackages dflags+  let db = getPackageConfigs dflgs+      packageNames = map (packageIdString' dflgs) db        initStr = "ihaskell-" @@ -236,17 +193,6 @@       iHaskellPkgName = initStr ++ intercalate "." (map show (versionBranch version)) #endif -#if !MIN_VERSION_ghc(8,0,0)-      unitId = packageId-#endif--      dependsOnRight pkg = not $ null $ do-        pkg <- db-        depId <- depends pkg-        dep <- filter ((== depId) . unitId) db-        let idString = packageIdString' dflags dep-        guard (iHaskellPkgName `isPrefixOf` idString)-       displayPkgs = [ pkgName                     | pkgName <- packageNames                     , Just (x:_) <- [stripPrefix initStr pkgName]@@ -257,17 +203,20 @@    -- Generate import statements all Display modules.   let capitalize :: String -> String+      capitalize [] = []       capitalize (first:rest) = Char.toUpper first : rest        importFmt = "import IHaskell.Display.%s" -      dropFirstAndLast :: [a] -> [a]-      dropFirstAndLast = reverse . drop 1 . reverse . drop 1 -      toImportStmt :: String -> String #if MIN_VERSION_ghc(8,2,0)+      toImportStmt :: String -> String       toImportStmt = printf importFmt . concatMap capitalize . drop 1 . split "-" #else+      dropFirstAndLast :: [a] -> [a]+      dropFirstAndLast = reverse . drop 1 . reverse . drop 1++      toImportStmt :: String -> String       toImportStmt = printf importFmt . concatMap capitalize . dropFirstAndLast . split "-" #endif @@ -297,8 +246,9 @@   void $ execStmt "let it = ()" execOptions  -- | Publisher for IHaskell outputs. The first argument indicates whether this output is final--- (true) or intermediate (false).-type Publisher = (EvaluationResult -> IO ())+-- (true) or intermediate (false). The second argument indicates whether the evaluation+-- completed successfully (Success) or an error occurred (Failure).+type Publisher = (EvaluationResult -> ErrorOccurred -> IO ())  -- | Output of a command evaluation. data EvalOut =@@ -311,11 +261,11 @@          }  cleanString :: String -> String-cleanString x = if allBrackets+cleanString istr = if allBrackets                   then clean-                  else str+                  else istr   where-    str = strip x+    str = strip istr     l = lines str     allBrackets = all (fAny [isPrefixOf ">", null]) l     fAny fs x = any ($ x) fs@@ -346,14 +296,16 @@                  when (getLintStatus kernelState /= LintOff) $ liftIO $ do                    lintSuggestions <- lint cmds                    unless (noResults lintSuggestions) $-                     output $ FinalResult lintSuggestions [] []+                     output (FinalResult lintSuggestions [] []) Success                   runUntilFailure kernelState (map unloc cmds ++ [storeItCommand execCount])                -- Print all parse errors.-               errs -> do+               _ -> do                  forM_ errs $ \err -> do                    out <- evalCommand output err kernelState-                   liftIO $ output $ FinalResult (evalResult out) [] []+                   liftIO $ output+                     (FinalResult (evalResult out) [] [])+                     (evalStatus out)                  return kernelState    return updated { getExecutionCounter = execCount + 1 }@@ -385,9 +337,10 @@               Just disps -> evalResult evalOut <> disps        -- Output things only if they are non-empty.-      let empty = noResults result && null (evalPager evalOut)-      unless empty $-        liftIO $ output $ FinalResult result (evalPager evalOut) []+      unless (noResults result && null (evalPager evalOut)) $+        liftIO $ output+          (FinalResult result (evalPager evalOut) [])+          (evalStatus evalOut)        let tempMsgs = evalMsgs evalOut           tempState = evalState evalOut { evalMsgs = [] }@@ -431,7 +384,7 @@                     -> [WidgetMsg]                     -> (KernelState -> [WidgetMsg] -> IO KernelState)                     -> Interpreter KernelState-flushWidgetMessages state evalMsgs widgetHandler = do+flushWidgetMessages state evalmsgs widgetHandler = do   -- Capture all widget messages queued during code execution   extracted <- extractValue "IHaskell.Eval.Widgets.relayWidgetMessages"   liftIO $@@ -444,16 +397,12 @@         messages <- messagesIO          -- Handle all the widget messages-        let commMessages = evalMsgs ++ messages+        let commMessages = evalmsgs ++ messages         widgetHandler state commMessages   getErrMsgDoc :: ErrUtils.ErrMsg -> SDoc-#if MIN_VERSION_ghc(8,0,0) getErrMsgDoc = ErrUtils.pprLocErrMsg-#else-getErrMsgDoc msg = ErrUtils.errMsgShortString msg $$ ErrUtils.errMsgContext msg-#endif  safely :: KernelState -> Interpreter EvalOut -> Interpreter EvalOut safely state = ghandle handler . ghandle sourceErrorHandler@@ -534,8 +483,8 @@       -- Return whether this module prevents the loading of the one we're trying to load. If a module B       -- exist, we cannot load A.B. All modules must have unique last names (where A.B has last name B).       -- However, we *can* just reload a module.-      preventsLoading mod =-        let pieces = moduleNameOf mod+      preventsLoading md =+        let pieces = moduleNameOf md         in last namePieces == last pieces && namePieces /= pieces    -- If we've loaded anything with the same last name, we can't use this. Otherwise, GHC tries to load@@ -551,7 +500,7 @@     Nothing -> doLoadModule modName modName  -- | Directives set via `:set`.-evalCommand output (Directive SetDynFlag flagsStr) state = safely state $ do+evalCommand _output (Directive SetDynFlag flagsStr) state = safely state $ do   write state $ "All Flags: " ++ flagsStr    -- Find which flags are IHaskell flags, and which are GHC flags@@ -569,14 +518,14 @@    if null flags     then do-      flags <- getSessionDynFlags+      flgs <- getSessionDynFlags       return         EvalOut           { evalStatus = Success           , evalResult = Display-                           [ plain $ showSDoc flags $ vcat-                                                        [ pprDynFlags False flags-                                                        , pprLanguages False flags+                           [ plain $ showSDoc flgs $ vcat+                                                        [ pprDynFlags False flgs+                                                        , pprLanguages False flgs                                                         ]                            ]           , evalState = state@@ -585,9 +534,9 @@           }     else do       -- Apply all IHaskell flag updaters to the state to get the new state-      let state' = foldl' (.) id (map (fromJust . ihaskellFlagUpdater) ihaskellFlags) state+      let state' = foldl' (.) id (mapMaybe ihaskellFlagUpdater ihaskellFlags) state       errs <- setFlags ghcFlags-      let display =+      let disp =             case errs of               [] -> mempty               _  -> displayError $ intercalate "\n" errs@@ -604,7 +553,7 @@       return         EvalOut           { evalStatus = Success-          , evalResult = display+          , evalResult = disp           , evalState = state'           , evalPager = []           , evalMsgs = []@@ -615,7 +564,7 @@   let set = concatMap (" -X" ++) $ words opts   evalCommand output (Directive SetDynFlag set) state -evalCommand output (Directive LoadModule mods) state = wrapExecution state $ do+evalCommand _output (Directive LoadModule mods) state = wrapExecution state $ do   write state $ "Load Module: " ++ mods   let stripped@(firstChar:remainder) = mods       (modules, removeModule) =@@ -630,9 +579,9 @@    return mempty -evalCommand a (Directive SetOption opts) state = do+evalCommand _output (Directive SetOption opts) state = do   write state $ "Option: " ++ opts-  let (existing, nonExisting) = partition optionExists $ words opts+  let nonExisting = filter (not . optionExists) $ words opts   if not $ null nonExisting     then let err = "No such options: " ++ intercalate ", " nonExisting          in return@@ -682,15 +631,16 @@                 doLoadModule filename modName   return (ManyDisplay displays) -evalCommand publish (Directive ShellCmd ('!':cmd)) state = wrapExecution state $-  case words cmd of+evalCommand publish (Directive ShellCmd cmd) state = wrapExecution state $+  -- Assume the first character of 'cmd' is '!'.+  case words $ drop 1 cmd of     "cd":dirs -> do       -- Get home so we can replace '~` with it.       homeEither <- liftIO (try $ getEnv "HOME" :: IO (Either SomeException String))       let home =             case homeEither of-              Left _    -> "~"-              Right val -> val+              Left _  -> "~"+              Right v -> v        let directory = replace "~" home $ unwords dirs       exists <- liftIO $ doesDirectoryExist directory@@ -701,19 +651,19 @@           liftIO $ setCurrentDirectory directory            -- Set the directory for user code.-          let cmd = printf "IHaskellDirectory.setCurrentDirectory \"%s\"" $+          let cmd1 = printf "IHaskellDirectory.setCurrentDirectory \"%s\"" $                 replace " " "\\ " $                   replace "\"" "\\\"" directory-          execStmt cmd execOptions+          _ <- execStmt cmd1 execOptions           return mempty         else return $ displayError $ printf "No such directory: '%s'" directory-    cmd -> liftIO $ do-      (pipe, handle) <- createPipe'-      let initProcSpec = shell $ unwords cmd+    cmd1 -> liftIO $ do+      (pipe, hdl) <- createPipe'+      let initProcSpec = shell $ unwords cmd1           procSpec = initProcSpec             { std_in = Inherit-            , std_out = UseHandle handle-            , std_err = UseHandle handle+            , std_out = UseHandle hdl+            , std_err = UseHandle hdl             }       (_, _, _, process) <- createProcess procSpec @@ -741,21 +691,17 @@             modifyMVar_ outputAccum (return . (++ nextChunk))              -- Check if we're done.-            exitCode <- getProcessExitCode process-            let computationDone = isJust exitCode--            when computationDone $ do-              nextChunk <- readChars pipe "" maxSize-              modifyMVar_ outputAccum (return . (++ nextChunk))--            if not computationDone-              then do+            mExitCode <- getProcessExitCode process+            case mExitCode of+              Nothing -> do                 -- Write to frontend and repeat.-                readMVar outputAccum >>= output+                readMVar outputAccum >>= flip output Success                 loop-              else do+              Just exitCode -> do+                next <- readChars pipe "" maxSize+                modifyMVar_ outputAccum (return . (++ next))                 out <- readMVar outputAccum-                case fromJust exitCode of+                case exitCode of                   ExitSuccess -> return $ Display [plain out]                   ExitFailure code -> do                     let errMsg = "Process exited with error code " ++ show code@@ -819,11 +765,11 @@   strings <- unlines <$> getDescription str    -- Make pager work without html by porting to newer architecture-  let htmlify str =+  let htmlify str1 =         html $           concat             [ "<div style='background: rgb(247, 247, 247);'><form><textarea id='code'>"-            , str+            , str1             , "</textarea></form></div>"             , "<script>CodeMirror.fromTextArea(document.getElementById('code'),"             , " {mode: 'haskell', readOnly: 'nocursor'});</script>"@@ -888,8 +834,8 @@     -- If it typechecks as a DecsQ, we do not want to display the DecsQ, we just want the     -- declaration made.     do-      write state "Suppressing display for template haskell declaration"-      GHC.runDecls expr+      _ <- write state "Suppressing display for template haskell declaration"+      _ <- GHC.runDecls expr       return         EvalOut           { evalStatus = Success@@ -941,7 +887,7 @@     removeSvg (Display disps) = Display $ filter (not . isSvg) disps     removeSvg (ManyDisplay disps) = ManyDisplay $ map removeSvg disps -    useDisplay displayExpr = do+    useDisplay _displayExpr = do       -- If there are instance matches, convert the object into a Display. We also serialize it into a       -- bytestring. We get the bytestring IO action as a dynamic and then convert back to a bytestring,       -- which we promptly unserialize. Note that attempting to do this without the serialization to@@ -957,8 +903,8 @@         Failure -> return evalOut         Success -> wrapExecution state $ do           -- Compile the display data into a bytestring.-          let compileExpr = "fmap IHaskell.Display.serializeDisplay (IHaskell.Display.display it)"-          displayedBytestring <- dynCompileExpr compileExpr+          let cexpr = "fmap IHaskell.Display.serializeDisplay (IHaskell.Display.display it)"+          displayedBytestring <- dynCompileExpr cexpr            -- Convert from the bytestring into a display.           case fromDynamic displayedBytestring of@@ -967,30 +913,27 @@               bytestring <- liftIO bytestringIO               case Serialize.decode bytestring of                 Left err -> error err-                Right display ->+                Right disp ->                   return $                     if useSvg state-                      then display :: Display-                      else removeSvg display+                      then disp :: Display+                      else removeSvg disp  #if MIN_VERSION_ghc(8,2,0)-    isIO expr = attempt $ exprType TM_Inst $ printf "((\\x -> x) :: IO a -> IO a) (%s)" expr+    isIO exp = attempt $ exprType TM_Inst $ printf "((\\x -> x) :: IO a -> IO a) (%s)" exp #else-    isIO expr = attempt $ exprType $ printf "((\\x -> x) :: IO a -> IO a) (%s)" expr+    isIO exp = attempt $ exprType $ printf "((\\x -> x) :: IO a -> IO a) (%s)" exp #endif      postprocessShowError :: EvalOut -> EvalOut     postprocessShowError evalOut = evalOut { evalResult = Display $ map postprocess disps }       where         Display disps = evalResult evalOut-        text = extractPlain disps+        txt = extractPlain disps -        postprocess (DisplayData MimeHtml _) = html $ printf-                                                        fmt-                                                        unshowableType-                                                        (formatErrorWithClass "err-msg collapse"-                                                           text)-                                                        script+        postprocess (DisplayData MimeHtml _) =+          html $ printf fmt unshowableType+                    (formatErrorWithClass "err-msg collapse" txt) script           where             fmt = "<div class='collapse-group'><span class='btn btn-default' href='#' id='unshowable'>Unshowable:<span class='show-type'>%s</span></span>%s</div><script>%s</script>"             script = unlines@@ -1005,7 +948,7 @@         postprocess other = other          unshowableType = fromMaybe "" $ do-          let pieces = words text+          let pieces = words txt               before = takeWhile (/= "arising") pieces               after = init $ unwords $ tail $ dropWhile (/= "(Show") before @@ -1052,7 +995,7 @@       , evalMsgs = []       } -evalCommand _ (Pragma (PragmaUnsupported pragmaType) pragmas) state = wrapExecution state $+evalCommand _ (Pragma (PragmaUnsupported pragmaType) _pragmas) state = wrapExecution state $   return $ displayError $ "Pragmas of type " ++ pragmaType ++ "\nare not supported."  evalCommand output (Pragma PragmaLanguage pragmas) state = do@@ -1080,14 +1023,10 @@     -- Compile loaded modules.     flags <- getSessionDynFlags     errRef <- liftIO $ newIORef []-    setSessionDynFlags $ flip gopt_set Opt_BuildDynamicToo+    _ <- setSessionDynFlags $ flip gopt_set Opt_BuildDynamicToo       flags         { hscTarget = objTarget flags-#if MIN_VERSION_ghc(8,0,0)-        , log_action = \dflags sev srcspan ppr _style msg -> modifyIORef' errRef (showSDoc flags msg :)-#else-        , log_action = \dflags sev srcspan ppr msg -> modifyIORef' errRef (showSDoc flags msg :)-#endif+        , log_action = \_dflags _sev _srcspan _ppr _style msg -> modifyIORef' errRef (showSDoc flags msg :)         }      -- Load the new target.@@ -1113,7 +1052,7 @@         Succeeded -> IIDecl (simpleImportDecl $ mkModuleName modName) : importedModules      -- Switch back to interpreted mode.-    setSessionDynFlags flags+    _ <- setSessionDynFlags flags      case result of       Succeeded -> return mempty@@ -1127,35 +1066,20 @@       print $ show exception       -- Explicitly clear targets       setTargets []-      load LoadAllTargets+      _ <- load LoadAllTargets        -- Switch to interpreted mode!       flags <- getSessionDynFlags-      setSessionDynFlags flags { hscTarget = HscInterpreted }+      _ <- setSessionDynFlags flags { hscTarget = HscInterpreted }        -- Return to old context, make sure we have `it`.       setContext imported       initializeItVariable        return $ displayError $ "Failed to load module " ++ modName ++ ": " ++ show exception-#if MIN_VERSION_ghc(7,8,0)-objTarget flags = defaultObjectTarget $ targetPlatform flags-#else-objTarget flags = defaultObjectTarget-#endif-keepingItVariable :: Interpreter a -> Interpreter a-keepingItVariable act = do-  -- Generate the it variable temp name-  gen <- liftIO getStdGen-  let rand = take 20 $ randomRs ('0', '9') gen-      var name = name ++ rand-      goStmt s = execStmt s execOptions-      itVariable = var "it_var_temp_" -  goStmt $ printf "let %s = it" itVariable-  val <- act-  goStmt $ printf "let it = %s" itVariable-  act+objTarget :: DynFlags -> HscTarget+objTarget flags = defaultObjectTarget $ targetPlatform flags  data Captured a = CapturedStmt String                 | CapturedIO (IO a)@@ -1208,44 +1132,24 @@        runWithResult (CapturedStmt str) = goStmt str       runWithResult (CapturedIO io) = do-        status <- gcatch (liftIO io >> return NoException) (return . AnyException)+        stat <- gcatch (liftIO io >> return NoException) (return . AnyException)         return $-          case status of+          case stat of             NoException    -> ExecComplete (Right []) 0             AnyException e -> ExecComplete (Left e)   0    -- Initialize evaluation context.-  results <- forM initStmts goStmt+  forM_ initStmts goStmt -#if __GLASGOW_HASKELL__ >= 800   -- This works fine on GHC 8.0 and newer   dyn <- dynCompileExpr readVariable   pipe <- case fromDynamic dyn of             Nothing -> fail "Evaluate: Bad pipe"             Just fd -> liftIO $ do-                handle <- fdToHandle fd-                hSetEncoding handle utf8-                return handle-#else-  -- Get the pipe to read printed output from. This is effectively the source code of dynCompileExpr-  -- from GHC API's InteractiveEval. However, instead of using a `Dynamic` as an intermediary, it just-  -- directly reads the value. This is incredibly unsafe! However, for some reason the `getContext`-  -- and `setContext` required by dynCompileExpr (to import and clear Data.Dynamic) cause issues with-  -- data declarations being updated (e.g. it drops newer versions of data declarations for older ones-  -- for unknown reasons). First, compile down to an HValue.-  let pipeExpr = printf "let %s = %s" (var "pipe_var_") readVariable-  Just (_, hValues, _) <- withSession $ liftIO . flip hscStmt pipeExpr-  -- Then convert the HValue into an executable bit, and read the value.-  pipe <- liftIO $ do-            fds <- unsafeCoerce hValues-            fd <- case fds of-              fd : _ -> return fd-              []     -> fail "Failed to evaluate pipes"-              _      -> fail $ "Expected one fd, saw "++show (length fds)-            handle <- fdToHandle fd-            hSetEncoding handle utf8-            return handle-#endif+                hdl <- fdToHandle fd+                hSetEncoding hdl utf8+                return hdl+   -- Keep track of whether execution has completed.   completed <- liftIO $ newMVar False   finishedReading <- liftIO newEmptyMVar@@ -1258,9 +1162,6 @@       ms = 1000       delay = 100 * ms -      -- How much to read each time.-      chunkSize = 100-       -- Maximum size of the output (after which we truncate).       maxSize = 100 * 1000 @@ -1286,7 +1187,7 @@             -- We're done reading.             putMVar finishedReading True -  liftIO $ forkIO loop+  _ <- liftIO $ forkIO loop    result <- gfinally (runWithResult stmt) $ do               -- Execution is done.@@ -1320,10 +1221,10 @@   case cmd of     CapturedStmt stmt ->       write state $ "Statement:\n" ++ stmt-    CapturedIO io ->+    CapturedIO _ ->       write state "Evaluating Action" -  (printed, result) <- capturedEval output cmd+  (printed, result) <- capturedEval (flip output Success) cmd   case result of     ExecComplete (Right names) _ -> do       dflags <- getSessionDynFlags@@ -1333,14 +1234,14 @@             name == "it" ||             name == "it" ++ show (getExecutionCounter state)           nonItNames = filter (not . isItName) allNames-          output = [ plain printed+          oput = [ plain printed                    | not . null $ strip printed ]        write state $ "Names: " ++ show allNames        -- Display the types of all bound names if the option is on. This is similar to GHCi :set +t.       if not $ useShowTypes state-        then return $ Display output+        then return $ Display oput         else do           -- Get all the type strings.           types <- forM nonItNames $ \name -> do@@ -1355,11 +1256,11 @@               htmled = unlines $ map formatGetType types            return $-            case extractPlain output of+            case extractPlain oput of               "" -> Display [html htmled]                -- Return plain and html versions. Previously there was only a plain version.-              text -> Display [plain $ joined ++ "\n" ++ text, html $ htmled ++ mono text]+              txt -> Display [plain $ joined ++ "\n" ++ txt, html $ htmled ++ mono txt]      ExecComplete (Left exception) _ -> throw exception     ExecBreak{} -> error "Should not break."@@ -1367,20 +1268,20 @@ -- Read from a file handle until we hit a delimiter or until we've read as many characters as -- requested readChars :: Handle -> String -> Int -> IO String-readChars handle delims 0 =+readChars _handle _delims 0 =   -- If we're done reading, return nothing.   return []-readChars handle delims nchars = do+readChars hdl delims nchars = do   -- Try reading a single character. It will throw an exception if the handle is already closed.-  tryRead <- gtry $ hGetChar handle :: IO (Either SomeException Char)+  tryRead <- gtry $ hGetChar hdl :: IO (Either SomeException Char)   case tryRead of-    Right char ->+    Right ch ->       -- If this is a delimiter, stop reading.-      if char `elem` delims-        then return [char]+      if ch `elem` delims+        then return [ch]         else do-          next <- readChars handle delims (nchars - 1)-          return $ char : next+          next <- readChars hdl delims (nchars - 1)+          return $ ch : next     -- An error occurs at the end of the stream, so just stop reading.     Left _ -> return [] @@ -1403,13 +1304,10 @@   where     fixDollarSigns = replace "$" "<span>&dollar;</span>"     useDashV = "\n    Use -v to see a list of the files searched for."-    isShowError err =-      "No instance for (Show" `isPrefixOf` err &&-      isInfixOf " arising from a use of `print'" err  formatParseError :: StringLoc -> String -> ErrMsg-formatParseError (Loc line col) =-  printf "Parse error (line %d, column %d): %s" line col+formatParseError (Loc ln col) =+  printf "Parse error (line %d, column %d): %s" ln col  formatGetType :: String -> String formatGetType = printf "<span class='get-type'>%s</span>"
src/IHaskell/Eval/Hoogle.hs view
@@ -1,29 +1,31 @@-{-# LANGUAGE NoImplicitPrelude, FlexibleInstances, OverloadedStrings #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE OverloadedStrings #-}  module IHaskell.Eval.Hoogle (     search,     document,     render,     OutputFormat(..),-    HoogleResult,+    HoogleResult(..),+    HoogleResponse(..),+    parseResponse,     ) where +import qualified Data.ByteString.Char8   as CBS+import qualified Data.ByteString.Lazy    as LBS+import           Data.Either             (either) import           IHaskellPrelude-import qualified Data.Text as T-import qualified Data.Text.Lazy as LT-import qualified Data.ByteString as BS-import qualified Data.ByteString.Lazy as LBS-import qualified Data.ByteString.Char8 as CBS +import           Data.Aeson+import           Data.Char               (isAlphaNum, isAscii)+import qualified Data.List               as List+import qualified Data.Text               as T+import           Data.Vector             (toList) import           Network.HTTP.Client import           Network.HTTP.Client.TLS-import           Data.Aeson-import qualified Data.List as List-import           Data.Char (isAscii, isAlphaNum) --import           IHaskell.IPython-import           StringUtils (split, strip, replace)+import           StringUtils             (replace, split, strip)  -- | Types of formats to render output to. data OutputFormat = Plain      -- ^ Render to plain text.@@ -40,17 +42,19 @@ data HoogleResponseList = HoogleResponseList [HoogleResponse]  instance FromJSON HoogleResponseList where-  parseJSON (Object obj) = do-    results <- obj .: "results"-    HoogleResponseList <$> mapM parseJSON results+  parseJSON (Array arr) =+    HoogleResponseList <$> mapM parseJSON (toList arr) -  parseJSON _ = fail "Expected object with 'results' field."+  parseJSON _ = fail "Expected array."  instance FromJSON HoogleResponse where   parseJSON (Object obj) =-    HoogleResponse <$> obj .: "location" <*> obj .: "self" <*> obj .: "docs"+    HoogleResponse+      <$>  obj .: "url"+      <*>  (removeMarkup <$> obj .: "item")+      <*>  obj .: "docs" -  parseJSON _ = fail "Expected object with fields: location, self, docs"+  parseJSON _ = fail "Expected object with fields: url, item, docs"  -- | Query Hoogle for the given string. This searches Hoogle using the internet. It returns either -- an error message or the successful JSON result.@@ -64,7 +68,7 @@    where     queryUrl :: String -> String-    queryUrl = printf "https://www.haskell.org/hoogle/?hoogle=%s&mode=json"+    queryUrl = printf "http://hoogle.haskell.org/?hoogle=%s&mode=json"  -- | Copied from the HTTP package. urlEncode :: String -> String@@ -92,27 +96,24 @@  -- | Search for a query on Hoogle. Return all search results. search :: String -> IO [HoogleResult]-search string = do-  response <- query string-  return $-    case response of-      Left err -> [NoResult err]-      Right json ->-        case eitherDecode $ LBS.fromStrict $ CBS.pack json of-          Left err -> [NoResult err]-          Right results ->-            case map SearchResult $ (\(HoogleResponseList l) -> l) results of-              []  -> [NoResult "no matching identifiers found."]-              res -> res+search string = either ((:[]) . NoResult) parseResponse <$> query string +parseResponse :: String -> [HoogleResult]+parseResponse jsn =+  case eitherDecode $ LBS.fromStrict $ CBS.pack jsn of+    Left err -> [NoResult err]+    Right results ->+      case map SearchResult $ (\(HoogleResponseList l) -> l) results of+        []  -> [NoResult "no matching identifiers found."]+        res -> res+ -- | Look up an identifier on Hoogle. Return documentation for that identifier. If there are many -- identifiers, include documentation for all of them. document :: String -> IO [HoogleResult] document string = do   matchingResults <- filter matches <$> search string-  let results = map toDocResult matchingResults   return $-    case results of+    case mapMaybe toDocResult matchingResults of       []  -> [NoResult "no matching identifiers found."]       res -> res @@ -123,12 +124,14 @@         _      -> False     matches _ = False -    toDocResult (SearchResult resp) = DocResult resp+    toDocResult (SearchResult resp) = Just $ DocResult resp+    toDocResult (DocResult _)       = Nothing+    toDocResult (NoResult _)        = Nothing  -- | Render a Hoogle search result into an output format. render :: OutputFormat -> HoogleResult -> String render Plain = renderPlain-render HTML = renderHtml+render HTML  = renderHtml  -- | Render a Hoogle result to plain text. renderPlain :: HoogleResult -> String@@ -163,7 +166,7 @@    | "module" `isPrefixOf` string =       let package = extractPackageName loc-      in mod ++ " " +++      in mdl ++ " " ++                 span "hoogle-module" (link loc $ extractModule string) ++                 packageSub package @@ -185,6 +188,12 @@                 span "hoogle-class" (link loc $ extractNewtype string) ++                 packageSub package +  | "type" `isPrefixOf` string =+      let package = extractPackageName loc+      in nwt ++ " " +++                span "hoogle-class" (link loc $ extractType string) +++                packageSub package+   | otherwise =       let [name, args] = split "::" string           package = extractPackageName loc@@ -201,8 +210,9 @@     extractClass = strip . replace "class" ""     extractData = strip . replace "data" ""     extractNewtype = strip . replace "newtype" ""+    extractType = strip . replace "newtype" ""     pkg = span "hoogle-head" "package"-    mod = span "hoogle-head" "module"+    mdl = span "hoogle-head" "module"     cls = span "hoogle-head" "class"     dat = span "hoogle-head" "data"     nwt = span "hoogle-head" "newtype"@@ -224,37 +234,22 @@     packageAndModuleSub (Just package) (Just modname) =       span "hoogle-sub" $         "(" ++ pkg ++ " " ++ span "hoogle-package" package ++-                             ", " ++ mod ++ " " ++ span "hoogle-module" modname ++ ")"+                             ", " ++ mdl ++ " " ++ span "hoogle-module" modname ++ ")"  renderDocs :: String -> String-renderDocs doc =-  let groups = List.groupBy bothAreCode $ lines doc-      nonull = filter (not . null . strip)-      bothAreCode s1 s2 =-                           isPrefixOf ">" (strip s1) &&-                           isPrefixOf ">" (strip s2)-      isCode (s:_) = isPrefixOf ">" $ strip s-      makeBlock lines =-                         if isCode lines-                           then div' "hoogle-code" $ unlines $ nonull lines-                           else div' "hoogle-text" $ unlines $ nonull lines-  in div' "hoogle-doc" $ unlines $ map makeBlock groups+renderDocs doc = div' "hoogle-doc" doc  extractPackageName :: String -> Maybe String-extractPackageName link = do-  let pieces = split "/" link+extractPackageName lnk = do+  let pieces = split "/" lnk   archiveLoc <- List.elemIndex "archive" pieces   latestLoc <- List.elemIndex "latest" pieces   guard $ latestLoc - archiveLoc == 2   return $ pieces List.!! (latestLoc - 1)  extractModuleName :: String -> Maybe String-extractModuleName link = do-  let pieces = split "/" link-  guard $ not $ null pieces-  let html = fromJust $ lastMay pieces-      mod = replace "-" "." $ takeWhile (/= '.') html-  return mod+extractModuleName lnk =+  replace "-" "." . takeWhile (/= '.') <$> lastMay (split "/" lnk)  div' :: String -> String -> String div' = printf "<div class='%s'>%s</div>"@@ -264,3 +259,19 @@  link :: String -> String -> String link = printf "<a target='_blank' href='%s'>%s</a>"++-- | very explicit cleaning of the type signature in the hoogle 5 response,+-- to remove html markup and escaped characters.+removeMarkup :: String -> String+removeMarkup s = T.unpack $ List.foldl (flip ($)) (T.pack s) replaceAll+  where replacements :: [ (T.Text, T.Text) ]+        replacements = [ ( "<span class=name>", "" )+                       , ( "</span>", "" )+                       , ( "<0>", "" )+                       , ( "</0>", "" )+                       , ( "&gt;", ">" )+                       , ( "&lt;", "<" )+                       , ( "<b>", "")+                       , ( "</b>", "")+                       ]+        replaceAll = uncurry T.replace <$> replacements
src/IHaskell/Eval/Info.hs view
@@ -4,11 +4,6 @@ module IHaskell.Eval.Info (info) where  import           IHaskellPrelude-import qualified Data.Text as T-import qualified Data.Text.Lazy as LT-import qualified Data.ByteString as BS-import qualified Data.ByteString.Lazy as LBS-import qualified Data.ByteString.Char8 as CBS  import           IHaskell.Eval.Evaluate (typeCleaner, Interpreter) 
src/IHaskell/Eval/Inspect.hs view
@@ -7,11 +7,6 @@ module IHaskell.Eval.Inspect (inspect) where  import           IHaskellPrelude-import qualified Data.Text as T-import qualified Data.Text.Lazy as LT-import qualified Data.ByteString as BS-import qualified Data.ByteString.Lazy as LBS-import qualified Data.ByteString.Char8 as CBS  import qualified Prelude as P @@ -22,7 +17,6 @@ import           IHaskell.Eval.Evaluate (Interpreter) import           IHaskell.Display import           IHaskell.Eval.Util (getType)-import           IHaskell.Types  -- | Characters used in Haskell operators. operatorChars :: String@@ -34,7 +28,7 @@  -- | Compute the identifier that is being queried. getIdentifier :: String -> Int -> String-getIdentifier code pos = identifier+getIdentifier code _pos = identifier   where     chunks = splitOn whitespace code     lastChunk = P.last chunks :: String
src/IHaskell/Eval/Lint.hs view
@@ -3,33 +3,21 @@ module IHaskell.Eval.Lint (lint) where  import           IHaskellPrelude-import qualified Data.Text as T-import qualified Data.Text.Lazy as LT-import qualified Data.ByteString as BS-import qualified Data.ByteString.Lazy as LBS-import qualified Data.ByteString.Char8 as CBS -import           Prelude (head, tail, last)-import           Control.Monad-import           Data.List (findIndex)-import           Data.Char-import           Data.Monoid+import           Prelude (last) import           Data.Maybe (mapMaybe) import           System.IO.Unsafe (unsafePerformIO)  import           Language.Haskell.Exts.Syntax hiding (Module) import qualified Language.Haskell.Exts.Syntax as SrcExts import           Language.Haskell.Exts (parseFileContentsWithMode)-import           Language.Haskell.Exts.Build (doE) import           Language.Haskell.Exts hiding (Module)-import           Language.Haskell.Exts.SrcLoc  import           Language.Haskell.HLint as HLint import           Language.Haskell.HLint3  import           IHaskell.Types import           IHaskell.Display-import           IHaskell.IPython import           IHaskell.Eval.Parser hiding (line) import           StringUtils (replace) @@ -65,10 +53,9 @@    -- Get hlint settings   (flags, classify, hint) <- readMVar hlintSettings-  let mode = hseFlags flags    -- create 'suggestions'-  let modules = mapMaybe (createModule mode) blocks+  let modules = mapMaybe (createModule (hseFlags flags)) blocks       ideas = applyHints classify hint (map (\m -> (m, [])) modules)       suggestions = mapMaybe showIdea $ filter (not . ignoredIdea) ideas @@ -78,33 +65,33 @@       else [plain $ concatMap plainSuggestion suggestions, html $ htmlSuggestions suggestions]   where     autoSettings' = do-      (fixities, classify, hints) <- autoSettings+      (fixts, classify, hints) <- autoSettings       let hidingIgnore = Classify Ignore "Unnecessary hiding" "" ""-      return (fixities, hidingIgnore:classify, hints)+      return (fixts, hidingIgnore:classify, hints)     ignoredIdea idea = ideaSeverity idea == Ignore  showIdea :: Idea -> Maybe LintSuggestion showIdea idea =   case ideaTo idea of     Nothing -> Nothing-    Just whyNot ->+    Just wn ->       Just         Suggest           { line = srcSpanStartLine $ ideaSpan idea           , found = showSuggestion $ ideaFrom idea-          , whyNot = showSuggestion whyNot+          , whyNot = showSuggestion wn           , severity = ideaSeverity idea           , suggestion = ideaHint idea           }  createModule :: ParseMode -> Located CodeBlock -> Maybe ExtsModule-createModule mode (Located line block) =+createModule md (Located ln block) =   case block of     Expression expr  -> unparse $ exprToModule expr     Declaration decl -> unparse $ declToModule decl     Statement stmt   -> unparse $ stmtToModule stmt     Import impt      -> unparse $ imptToModule impt-    Module mod       -> unparse $ parseModule mod+    Module mdl       -> unparse $ pModule mdl     _                -> Nothing   where     blockStr =@@ -113,8 +100,11 @@         Declaration decl -> decl         Statement stmt   -> stmt         Import impt      -> impt-        Module mod       -> mod+        Module mdl       -> mdl +        -- TODO: Properly handle the other constructors+        _ -> []+     unparse :: ParseResult a -> Maybe a     unparse (ParseOk a) = Just a     unparse _ = Nothing@@ -122,49 +112,47 @@     srcSpan :: SrcSpan     srcSpan = SrcSpan       { srcSpanFilename = "<interactive>"-      , srcSpanStartLine = line+      , srcSpanStartLine = ln       , srcSpanStartColumn = 0-      , srcSpanEndLine = line + length (lines blockStr)+      , srcSpanEndLine = ln + length (lines blockStr)       , srcSpanEndColumn = length $ last $ lines blockStr       } -    loc :: SrcSpanInfo-    loc = SrcSpanInfo srcSpan []+    lcn :: SrcSpanInfo+    lcn = SrcSpanInfo srcSpan []      moduleWithDecls :: Decl SrcSpanInfo -> ExtsModule-    moduleWithDecls decl = SrcExts.Module loc Nothing [] [] [decl]+    moduleWithDecls decl = SrcExts.Module lcn Nothing [] [] [decl] -    parseModule :: String -> ParseResult ExtsModule-    parseModule = parseFileContentsWithMode mode+    pModule :: String -> ParseResult ExtsModule+    pModule = parseFileContentsWithMode md      declToModule :: String -> ParseResult ExtsModule-    declToModule decl = moduleWithDecls <$> parseDeclWithMode mode decl+    declToModule decl = moduleWithDecls <$> parseDeclWithMode md decl      exprToModule :: String -> ParseResult ExtsModule-    exprToModule exp = moduleWithDecls <$> SpliceDecl loc <$> parseExpWithMode mode exp+    exprToModule exp = moduleWithDecls <$> SpliceDecl lcn <$> parseExpWithMode md exp      stmtToModule :: String -> ParseResult ExtsModule     stmtToModule stmtStr =-      case parseStmtWithMode mode stmtStr of-        ParseOk stmt    -> ParseOk mod+      case parseStmtWithMode md stmtStr of+        ParseOk _       -> ParseOk $ moduleWithDecls decl         ParseFailed a b -> ParseFailed a b       where-        mod = moduleWithDecls decl-         decl :: Decl SrcSpanInfo-        decl = SpliceDecl loc expr+        decl = SpliceDecl lcn expr          expr :: Exp SrcSpanInfo-        expr = Do loc [stmt, ret]+        expr = Do lcn [stmt, ret]          stmt :: Stmt SrcSpanInfo-        ParseOk stmt = parseStmtWithMode mode stmtStr+        ParseOk stmt = parseStmtWithMode md stmtStr          ret :: Stmt SrcSpanInfo-        ParseOk ret = Qualifier loc <$> parseExp lintIdent+        ParseOk ret = Qualifier lcn <$> parseExp lintIdent      imptToModule :: String -> ParseResult ExtsModule-    imptToModule = parseFileContentsWithMode mode+    imptToModule = parseFileContentsWithMode md  plainSuggestion :: LintSuggestion -> String plainSuggestion suggest =@@ -177,10 +165,10 @@     toHtml :: LintSuggestion -> String     toHtml suggest = concat                        [ named $ suggestion suggest-                       , floating "left" $ style severityClass "Found:" +++                       , floating "left" $ styl severityClass "Found:" ++                                            -- Things that look like this get highlighted.                                            styleId "highlight-code" "haskell" (found suggest)-                       , floating "left" $ style severityClass "Why Not:" +++                       , floating "left" $ styl severityClass "Why Not:" ++                                            -- Things that look like this get highlighted.                                            styleId "highlight-code" "haskell" (whyNot suggest)                        ]@@ -193,8 +181,8 @@             -- Should not occur             _ -> "warning" -    style :: String -> String -> String-    style = printf "<div class=\"suggestion-%s\">%s</div>"+    styl :: String -> String -> String+    styl = printf "<div class=\"suggestion-%s\">%s</div>"      named :: String -> String     named = printf "<div class=\"suggestion-name\" style=\"clear:both;\">%s</div>"
src/IHaskell/Eval/ParseShell.hs view
@@ -5,11 +5,6 @@ module IHaskell.Eval.ParseShell (parseShell) where  import           IHaskellPrelude-import qualified Data.Text as T-import qualified Data.Text.Lazy as LT-import qualified Data.ByteString as BS-import qualified Data.ByteString.Lazy as LBS-import qualified Data.ByteString.Char8 as CBS  import           Text.ParserCombinators.Parsec @@ -28,6 +23,7 @@              xs <- scan              return $ x : xs +manyTillEnd1 :: Parser a -> Parser [a] -> Parser [a] manyTillEnd1 p end = do   x <- p   xs <- manyTillEnd p end@@ -36,18 +32,21 @@ unescapedChar :: Parser Char -> Parser String unescapedChar p = try $ do   x <- noneOf "\\"-  lookAhead p+  _ <- lookAhead p   return [x] +quotedString :: Parser [Char] quotedString = do-  quote <?> "expected starting quote"+  _ <- quote <?> "expected starting quote"   (manyTillEnd anyChar (unescapedChar quote) <* quote) <?> "unexpected in quoted String " +unquotedString :: Parser [Char] unquotedString = manyTillEnd1 anyChar end   where     end = unescapedChar space           <|> (lookAhead eol >> return []) +word :: Parser [Char] word = quotedString <|> unquotedString <?> "word"  separator :: Parser String@@ -57,11 +56,11 @@ shellWords :: Parser [String] shellWords = try (eof *> return []) <|> do                x <- word-               rest1 <- lookAhead (many anyToken)-               ss <- separator-               rest2 <- lookAhead (many anyToken)+               _rest1 <- lookAhead (many anyToken)+               _ss <- separator+               _rest2 <- lookAhead (many anyToken)                xs <- shellWords                return $ x : xs  parseShell :: String -> Either ParseError [String]-parseShell string = parse shellWords "shell" (string ++ "\n")+parseShell str = parse shellWords "shell" (str ++ "\n")
src/IHaskell/Eval/Parser.hs view
@@ -16,11 +16,6 @@     ) where  import           IHaskellPrelude-import qualified Data.Text as T-import qualified Data.Text.Lazy as LT-import qualified Data.ByteString as BS-import qualified Data.ByteString.Lazy as LBS-import qualified Data.ByteString.Char8 as CBS  import           Data.Char (toLower) import           Data.List (maximumBy, inits)@@ -83,8 +78,8 @@   flags <- getSessionDynFlags   let output = runParser flags parserModule codeString   case output of-    Parsed mod-      | Just _ <- hsmodName (unLoc mod) -> return [Located 1 $ Module codeString]+    Parsed mdl+      | Just _ <- hsmodName (unLoc mdl) -> return [Located 1 $ Module codeString]     _ -> do       -- Split input into chunks based on indentation.       let chunks = layoutChunks $ removeComments codeString@@ -97,12 +92,12 @@    where     parseChunk :: GhcMonad m => String -> LineNumber -> m (Located CodeBlock)-    parseChunk chunk line = Located line <$> handleChunk chunk line+    parseChunk chunk ln = Located ln <$> handleChunk       where-        handleChunk chunk line-          | isDirective chunk = return $ parseDirective chunk line-          | isPragma chunk = return $ parsePragma chunk line-          | otherwise = parseCodeChunk chunk line+        handleChunk+          | isDirective chunk = return $ parseDirective chunk ln+          | isPragma chunk = return $ parsePragma chunk ln+          | otherwise = parseCodeChunk chunk ln      processChunks :: GhcMonad m => [Located CodeBlock] -> [Located String] -> m [Located CodeBlock]     processChunks accum remaining =@@ -111,10 +106,10 @@         [] -> return $ reverse accum          -- If we have more remaining, parse the current chunk and recurse.-        Located line chunk:remaining -> do-          block <- parseChunk chunk line+        Located ln chunk:remain -> do+          block <- parseChunk chunk ln           activateExtensions $ unloc block-          processChunks (block : accum) remaining+          processChunks (block : accum) remain      -- Test whether a given chunk is a directive.     isDirective :: String -> Bool@@ -130,11 +125,11 @@   case stripPrefix "-X" flags of     Just ext -> void $ setExtension ext     Nothing  -> return ()-activateExtensions (Pragma PragmaLanguage extensions) = void $ setAll extensions+activateExtensions (Pragma PragmaLanguage exts) = void $ setAll exts   where     setAll :: GhcMonad m => [String] -> m (Maybe String)-    setAll exts = do-      errs <- mapM setExtension exts+    setAll exts' = do+      errs <- mapM setExtension exts'       return $ msum errs activateExtensions _ = return () @@ -142,7 +137,7 @@ parseCodeChunk :: GhcMonad m => String -> LineNumber -> m CodeBlock parseCodeChunk code startLine = do   flags <- getSessionDynFlags-  let +  let       -- Try each parser in turn.       rawResults = map (tryParser code) (parsers flags) @@ -164,13 +159,13 @@      failures :: [ParseOutput a] -> [(ErrMsg, LineNumber, ColumnNumber)]     failures [] = []-    failures (Failure msg (Loc line col):rest) = (msg, line, col) : failures rest+    failures (Failure msg (Loc ln col):rest) = (msg, ln, col) : failures rest     failures (_:rest) = failures rest      bestError :: [(ErrMsg, LineNumber, ColumnNumber)] -> CodeBlock-    bestError errors = ParseError (Loc (line + startLine - 1) col) msg+    bestError errors = ParseError (Loc (ln + startLine - 1) col) msg       where-        (msg, line, col) = maximumBy compareLoc errors+        (msg, ln, col) = maximumBy compareLoc errors         compareLoc (_, line1, col1) (_, line2, col2) = compare line1 line2 <> compare col1 col2      statementToExpression :: DynFlags -> ParseOutput CodeBlock -> ParseOutput CodeBlock@@ -189,11 +184,11 @@         _        -> False      tryParser :: String -> (String -> CodeBlock, String -> ParseOutput String) -> ParseOutput CodeBlock-    tryParser string (blockType, parser) =-      case parser string of+    tryParser string (blockType, psr) =+      case psr string of         Parsed res      -> Parsed (blockType res)         Failure err loc -> Failure err loc-        otherwise       -> error "tryParser failed, output was neither Parsed nor Failure"+        _               -> error "tryParser failed, output was neither Parsed nor Failure"      parsers :: DynFlags -> [(String -> CodeBlock, String -> ParseOutput String)]     parsers flags =@@ -204,10 +199,10 @@       ]       where         unparser :: Parser a -> String -> ParseOutput String-        unparser parser code =-          case runParser flags parser code of-            Parsed out       -> Parsed code-            Partial out strs -> Partial code strs+        unparser psr cd =+          case runParser flags psr cd of+            Parsed _         -> Parsed cd+            Partial _ strs   -> Partial cd strs             Failure err loc  -> Failure err loc  -- | Find consecutive declarations of the same function and join them into a single declaration.@@ -239,11 +234,11 @@ parsePragma :: String       -- ^ Pragma string.             -> Int          -- ^ Line number at which the directive appears.             -> CodeBlock    -- ^ Pragma code block or a parse error.-parsePragma ('{':'-':'#':pragma) line =+parsePragma pragma _ln =   let commaToSpace :: Char -> Char       commaToSpace ',' = ' '       commaToSpace x = x-      pragmas = words $ takeWhile (/= '#') $ map commaToSpace pragma+      pragmas = words $ takeWhile (/= '#') $ map commaToSpace $ drop 3 pragma   in case pragmas of     --empty string pragmas are unsupported     [] -> Pragma (PragmaUnsupported "") []@@ -256,8 +251,8 @@ parseDirective :: String       -- ^ Directive string.                -> Int          -- ^ Line number at which the directive appears.                -> CodeBlock    -- ^ Directive code block or a parse error.-parseDirective (':':'!':directive) line = Directive ShellCmd $ '!' : directive-parseDirective (':':directive) line =+parseDirective (':':'!':directive) _ln = Directive ShellCmd $ '!' : directive+parseDirective (':':directive) ln =   case find rightDirective directives of     Just (directiveType, _) -> Directive directiveType arg       where arg = unwords restLine@@ -267,7 +262,7 @@                             case words directive of                               []      -> ""                               first:_ -> first-      in ParseError (Loc line 1) $ "Unknown directive: '" ++ directiveStart ++ "'."+      in ParseError (Loc ln 1) $ "Unknown directive: '" ++ directiveStart ++ "'."   where     rightDirective (_, dirname) =       case words directive of@@ -298,8 +293,8 @@   let output = runParser flags parserModule moduleSrc   case output of     Failure{} -> error "Module parsing failed."-    Parsed mod ->-      case unLoc <$> hsmodName (unLoc mod) of+    Parsed mdl ->+      case unLoc <$> hsmodName (unLoc mdl) of         Nothing   -> error "Module must have a name."         Just name -> return $ split "." $ moduleNameString name-    otherwise -> error "getModuleName failed, output was neither Parsed nor Failure"+    _ -> error "getModuleName failed, output was neither Parsed nor Failure"
src/IHaskell/Eval/Util.hs view
@@ -27,29 +27,25 @@     ) where  import           IHaskellPrelude-import qualified Data.Text as T-import qualified Data.Text.Lazy as LT-import qualified Data.ByteString as BS-import qualified Data.ByteString.Lazy as LBS+#if MIN_VERSION_ghc(8,6,0)+#else import qualified Data.ByteString.Char8 as CBS+#endif  -- GHC imports. import           DynFlags+#if MIN_VERSION_ghc(8,6,0)+#else import           FastString+#endif import           GHC import           GhcMonad-import           HsImpExp import           HscTypes-import           InteractiveEval-import           Module-import           Packages-import           RdrName import           NameSet import           Name import           PprTyThing import           InstEnv (ClsInst(..)) import           Unify (tcMatchTys)-import           VarSet (mkVarSet) import qualified Pretty import qualified Outputable as O @@ -63,11 +59,9 @@ import           CmdLineParser (warnMsg) #endif -#if MIN_VERSION_ghc(8,0,1) import           GHC.LanguageExtensions  type ExtensionFlag = Extension-#endif  -- | A extension flag that can be set or unset. data ExtFlag = SetFlag ExtensionFlag@@ -87,15 +81,11 @@         Nothing -> Nothing   where     -- Check if a FlagSpec matches an extension name.-    flagMatches ext fs = ext == flagSpecName fs+    flagMatches ex fs = ex == flagSpecName fs      -- Check if a FlagSpec matches "No<ExtensionName>". In that case, we disable the extension.-    flagMatchesNo ext fs = ext == "No" ++ flagSpecName fs-#if !MIN_VERSION_ghc(7,10,0)-flagSpecName (name, _, _) = name+    flagMatchesNo ex fs = ex == "No" ++ flagSpecName fs -flagSpecFlag (_, flag, _) = flag-#endif -- | Pretty-print dynamic flags (taken from 'InteractiveUI' module of `ghc-bin`) pprDynFlags :: Bool       -- ^ Whether to include flags which are on by default             -> DynFlags@@ -107,21 +97,14 @@     , O.text "other dynamic, non-language, flag settings:" O.$$       O.nest 2 (O.vcat (map (setting opt) others))     , O.text "warning settings:" O.$$-      O.nest 2 (O.vcat (map (setting wopt) warningFlags))+      O.nest 2 (O.vcat (map (setting wopt) wFlags))     ]   where -#if MIN_VERSION_ghc(8,0,0)-    warningFlags = DynFlags.wWarningFlags-#else-    warningFlags = DynFlags.fWarningFlags-#endif+    wFlags = DynFlags.wWarningFlags -#if MIN_VERSION_ghc(7,8,0)     opt = gopt-#else-    opt = dopt-#endif+     setting test flag       | quiet = O.empty :: O.SDoc       | is_on = fstr name :: O.SDoc@@ -131,28 +114,28 @@         f = flagSpecFlag flag         is_on = test f dflags         quiet = not show_all && test f default_dflags == is_on-    -#if MIN_VERSION_ghc(8,4,0)++#if MIN_VERSION_ghc(8,6,0)+    default_dflags = defaultDynFlags (settings dflags) (llvmTargets dflags, llvmPasses dflags)+#elif MIN_VERSION_ghc(8,4,0)     default_dflags = defaultDynFlags (settings dflags) (llvmTargets dflags) #else     default_dflags = defaultDynFlags (settings dflags) #endif-    +     fstr, fnostr :: String -> O.SDoc     fstr str = O.text "-f" O.<> O.text str-    +     fnostr str = O.text "-fno-" O.<> O.text str-    +     (ghciFlags, others) = partition (\f -> flagSpecFlag f `elem` flgs) DynFlags.fFlags-    +     flgs = concat [flgs1, flgs2, flgs3]-    +     flgs1 = [Opt_PrintExplicitForalls]-#if MIN_VERSION_ghc(7,8,0)     flgs2 = [Opt_PrintExplicitKinds]-#else-    flgs2 = []-#endif++flgs3 :: [GeneralFlag] flgs3 = [Opt_PrintBindResult, Opt_BreakOnException, Opt_BreakOnError, Opt_PrintEvldWithShow]  -- | Pretty-print the base language and active options (taken from `InteractiveUI` module of@@ -184,7 +167,9 @@         quiet = not show_all && test f default_dflags == is_on      default_dflags =-#if MIN_VERSION_ghc(8,4,0)+#if MIN_VERSION_ghc(8,6,0)+      defaultDynFlags (settings dflags) (llvmTargets dflags, llvmPasses dflags) `lang_set`+#elif MIN_VERSION_ghc(8,4,0)       defaultDynFlags (settings dflags) (llvmTargets dflags) `lang_set` #else       defaultDynFlags (settings dflags) `lang_set`@@ -201,7 +186,7 @@   case extensionFlag ext of     Nothing -> return $ Just $ "Could not parse extension name: " ++ ext     Just flag -> do-      setSessionDynFlags $+      _ <- setSessionDynFlags $         case flag of           SetFlag ghcFlag   -> xopt_set flags ghcFlag           UnsetFlag ghcFlag -> xopt_unset flags ghcFlag@@ -216,9 +201,8 @@   (flags', unrecognized, warnings) <- parseDynamicFlags flags (map noLoc ext)    -- First, try to check if this flag matches any extension name.-  let restorePkg x = x { packageFlags = packageFlags flags }   let restoredPkgs = flags' { packageFlags = packageFlags flags }-  GHC.setProgramDynFlags restoredPkgs+  _ <- GHC.setProgramDynFlags restoredPkgs   GHC.setInteractiveDynFlags restoredPkgs    -- Create the parse errors.@@ -251,10 +235,15 @@    where     string_txt :: Pretty.TextDetails -> String -> String+#if MIN_VERSION_ghc(8,6,0)+    string_txt = Pretty.txtPrinter+#else     string_txt (Pretty.Chr c) s = c : s     string_txt (Pretty.Str s1) s2 = s1 ++ s2     string_txt (Pretty.PStr s1) s2 = unpackFS s1 ++ s2     string_txt (Pretty.LStr s1 _) s2 = unpackLitString s1 ++ s2+    string_txt (Pretty.ZStr s1) s2 = CBS.unpack (fastZStringToByteString s1) ++ s2+#endif  -- | Initialize the GHC API. Run this as the first thing in the `runGhc`. This initializes some dyn -- flags (@ExtendedDefaultRules@,@@ -271,11 +260,7 @@   originalFlags <- getSessionDynFlags   let flag = flip xopt_set       unflag = flip xopt_unset-#if MIN_VERSION_ghc(8,0,0)       dflags = flag ExtendedDefaultRules . unflag MonomorphismRestriction $ originalFlags-#else-      dflags = flag Opt_ExtendedDefaultRules . unflag Opt_MonomorphismRestriction $ originalFlags-#endif #if MIN_VERSION_ghc(8,2,0)       pkgFlags =         case sandboxPackages of@@ -357,15 +342,14 @@         _              -> False  removeImport :: GhcMonad m => String -> m ()-removeImport moduleName = do-  flags <- getSessionDynFlags+removeImport modName = do   ctx <- getContext-  let ctx' = filter (not . (isImportOf $ mkModuleName moduleName)) ctx+  let ctx' = filter (not . (isImportOf $ mkModuleName modName)) ctx   setContext ctx'    where     isImportOf :: ModuleName -> InteractiveImport -> Bool-    isImportOf name (IIModule modName) = name == modName+    isImportOf name (IIModule mName) = name == mName     isImportOf name (IIDecl impDecl) = name == unLoc (ideclName impDecl)  -- | Evaluate a series of declarations. Return all names which were bound by these declarations.@@ -378,7 +362,7 @@  cleanUpDuplicateInstances :: GhcMonad m => m () cleanUpDuplicateInstances = modifySession $ \hscEnv ->-  let +  let       -- Get all class instances       ic = hsc_IC hscEnv       (clsInsts, famInsts) = ic_instances ic@@ -387,21 +371,9 @@   in hscEnv { hsc_IC = ic { ic_instances = (clsInsts', famInsts) } }   where     instEq :: ClsInst -> ClsInst -> Bool-#if MIN_VERSION_ghc(8,0,0)     -- Only support replacing instances on GHC 7.8 and up-    instEq c1 c2-      | ClsInst { is_tvs = tpl_tvs, is_tys = tpl_tys, is_cls = cls } <- c1,-        ClsInst { is_tys = tpl_tys', is_cls = cls' } <- c2-      = cls == cls' && isJust (tcMatchTys tpl_tys tpl_tys')-#elif MIN_VERSION_ghc(7,8,0)-    instEq c1 c2-      | ClsInst { is_tvs = tpl_tvs, is_tys = tpl_tys, is_cls = cls } <- c1,-        ClsInst { is_tys = tpl_tys', is_cls = cls' } <- c2-      = let tpl_tv_set = mkVarSet tpl_tvs-        in cls == cls' && isJust (tcMatchTys tpl_tv_set tpl_tys tpl_tys')-#else-    instEq _ _ = False-#endif+    instEq c1 c2 =+      is_cls c1 == is_cls c2 && isJust (tcMatchTys (is_tys c1) (is_tys c2))   -- | Get the type of an expression and convert it to a string.@@ -430,9 +402,9 @@    -- Filter out types that have parents in the same set. GHCi also does this.   let infos = catMaybes maybeInfos-      allNames = mkNameSet $ map (getName . getType) infos+      allNames = mkNameSet $ map (getName . getInfoType) infos       hasParent info =-        case tyThingParent_maybe (getType info) of+        case tyThingParent_maybe (getInfoType info) of           Just parent -> getName parent `elemNameSet` allNames           Nothing     -> False       filteredOutput = filter (not . hasParent) infos@@ -442,18 +414,12 @@    where -#if MIN_VERSION_ghc(7,8,0)     getInfo' = getInfo False-#else-    getInfo' = getInfo-#endif  #if MIN_VERSION_ghc(8,4,0)-    getType (theType, _, _, _, _) = theType-#elif MIN_VERSION_ghc(7,8,0)-    getType (theType, _, _, _) = theType+    getInfoType (theType, _, _, _, _) = theType #else-    getType (theType, _, _) = theType+    getInfoType (theType, _, _, _) = theType #endif  #if MIN_VERSION_ghc(8,4,0)@@ -462,16 +428,12 @@       showFixity thing fixity O.$$       O.vcat (map GHC.pprInstance classInstances) O.$$       O.vcat (map GHC.pprFamInst famInstances)-#elif MIN_VERSION_ghc(7,8,0)+#else     printInfo (thing, fixity, classInstances, famInstances) =       pprTyThingInContextLoc thing O.$$       showFixity thing fixity O.$$       O.vcat (map GHC.pprInstance classInstances) O.$$       O.vcat (map GHC.pprFamInst famInstances)-#else-    printInfo (thing, fixity, classInstances) =-      pprTyThingInContextLoc False thing O.$$ showFixity thing fixity O.$$-      O.vcat (map GHC.pprInstance classInstances) #endif     showFixity thing fixity =       if fixity == GHC.defaultFixity
src/IHaskell/Eval/Widgets.hs view
@@ -14,7 +14,6 @@  import           IHaskellPrelude -import           Control.Concurrent.Chan (writeChan) import           Control.Concurrent.STM (atomically) import           Control.Concurrent.STM.TChan import           Control.Monad (foldM)@@ -25,8 +24,6 @@ import           IHaskell.Display import           IHaskell.Eval.Util (unfoldM) import           IHaskell.IPython.Types (showMessageType)-import           IHaskell.IPython.Message.UUID-import           IHaskell.IPython.Message.Writer import           IHaskell.Types  -- All comm_open messages go here@@ -50,7 +47,7 @@ widgetSend :: IHaskellWidget a            => (Widget -> Value -> WidgetMsg)            -> a -> Value -> IO ()-widgetSend msgType widget value = queue $ msgType (Widget widget) value+widgetSend mtype widget value = queue $ mtype (Widget widget) value  -- | Send a message to open a comm widgetSendOpen :: IHaskellWidget a => a -> Value -> IO ()@@ -82,7 +79,7 @@  -- | Send a `clear_output` message as a [method .= custom] message widgetClearOutput :: IHaskellWidget a => a -> Bool -> IO ()-widgetClearOutput widget wait = queue $ ClrOutput (Widget widget) wait+widgetClearOutput widget w = queue $ ClrOutput (Widget widget) w  -- | Handle a single widget message. Takes necessary actions according to the message type, such as -- opening comms, storing and updating widget representation in the kernel state etc.@@ -111,8 +108,8 @@         then return state         else do           -- Send the comm open, with the initial state-          header <- dupHeader replyHeader CommOpenMessage-          send $ CommOpen header target_name target_module uuid value+          hdr <- dupHeader replyHeader CommOpenMessage+          send $ CommOpen hdr target_name target_module uuid value            -- Send anything else the widget requires.           open widget communicate@@ -130,8 +127,8 @@       -- If the widget is not present in the state, we don't close it.       if present         then do-          header <- dupHeader replyHeader CommCloseMessage-          send $ CommClose header uuid value+          hdr <- dupHeader replyHeader CommCloseMessage+          send $ CommClose hdr uuid value           return newState         else return state @@ -148,9 +145,9 @@       let dmsg = WidgetDisplay dispHeader $ unwrap disp       sendMessage widget (toJSON $ CustomContent $ toJSON dmsg) -    ClrOutput widget wait -> do-      header <- dupHeader replyHeader ClearOutputMessage-      let cmsg = WidgetClear header wait+    ClrOutput widget w -> do+      hdr <- dupHeader replyHeader ClearOutputMessage+      let cmsg = WidgetClear hdr w       sendMessage widget (toJSON $ CustomContent $ toJSON cmsg)    where@@ -161,8 +158,8 @@        -- If the widget is present, we send an update message on its comm.       when present $ do-        header <- dupHeader replyHeader CommDataMessage-        send $ CommData header uuid value+        hdr <- dupHeader replyHeader CommDataMessage+        send $ CommData hdr uuid value       return state      unwrap :: Display -> [DisplayData]@@ -174,27 +171,27 @@  instance ToJSON WidgetDisplay where   toJSON (WidgetDisplay replyHeader ddata) =-    let pbval = toJSON $ PublishDisplayData replyHeader ddata+    let pbval = toJSON $ PublishDisplayData replyHeader ddata Nothing     in toJSON $ IPythonMessage replyHeader pbval DisplayDataMessage  -- Override toJSON for ClearOutput data WidgetClear = WidgetClear MessageHeader Bool  instance ToJSON WidgetClear where-  toJSON (WidgetClear replyHeader wait) =-    let clrVal = toJSON $ ClearOutput replyHeader wait+  toJSON (WidgetClear replyHeader w) =+    let clrVal = toJSON $ ClearOutput replyHeader w     in toJSON $ IPythonMessage replyHeader clrVal ClearOutputMessage  data IPythonMessage = IPythonMessage MessageHeader Value MessageType  instance ToJSON IPythonMessage where-  toJSON (IPythonMessage replyHeader val msgType) =+  toJSON (IPythonMessage replyHeader val mtype) =     object       [ "header" .= replyHeader       , "parent_header" .= str ""       , "metadata" .= str "{}"       , "content" .= val-      , "msg_type" .= (toJSON . showMessageType $ msgType)+      , "msg_type" .= (toJSON . showMessageType $ mtype)       ]  str :: String -> String@@ -206,4 +203,4 @@               -> KernelState               -> [WidgetMsg]               -> IO KernelState-widgetHandler sender header = foldM (handleMessage sender header)+widgetHandler sender hdr = foldM (handleMessage sender hdr)
src/IHaskell/Flags.hs view
@@ -14,22 +14,17 @@  import           IHaskellPrelude hiding (Arg(..)) import qualified Data.Text as T-import qualified Data.Text.Lazy as LT-import qualified Data.ByteString as BS-import qualified Data.ByteString.Lazy as LBS-import qualified Data.ByteString.Char8 as CBS  import           System.Console.CmdArgs.Explicit import           System.Console.CmdArgs.Text import           Data.List (findIndex)-import           IHaskell.Types  -- Command line arguments to IHaskell. A set of arguments is annotated with the mode being invoked. data Args = Args IHaskellMode [Argument]   deriving Show  data Argument = ConfFile String     -- ^ A file with commands to load at startup.-              | OverwriteFiles      -- ^ Present when output should overwrite existing files. +              | OverwriteFiles      -- ^ Present when output should overwrite existing files.               | GhcLibDir String    -- ^ Where to find the GHC libraries.               | RTSFlags [String]   -- ^ Options for the GHC runtime (e.g. heap-size limit                                     --     or number of threads).@@ -70,7 +65,7 @@ -- | Given a list of command-line arguments, return the IHaskell mode and arguments to process. parseFlags :: [String] -> Either String Args parseFlags flags =-  let modeIndex = findIndex (`elem` modeFlags) flags+  let modeIndex = findIndex (`elem` modeFlgs) flags   in case modeIndex of     Nothing ->       -- Treat no mode as 'console'.@@ -82,18 +77,19 @@       let (start, first:end) = splitAt idx flags       in process ihaskellArgs $ first : start ++ end   where-    modeFlags = concatMap modeNames allModes+    modeFlgs = concatMap modeNames allModes  allModes :: [Mode Args] allModes = [installKernelSpec, kernel, convert]  -- | Get help text for a given IHaskell ode. help :: IHaskellMode -> String-help mode = showText (Wrap 100) $ helpText [] HelpFormatAll $ chooseMode mode+help md = showText (Wrap 100) $ helpText [] HelpFormatAll $ chooseMode md   where     chooseMode InstallKernelSpec = installKernelSpec     chooseMode (Kernel _) = kernel     chooseMode ConvertLhs = convert+    chooseMode (ShowDefault _) = error "IHaskell.Flags.help: Should never happen."  ghcLibFlag :: Flag Args ghcLibFlag = flagReq ["ghclib", "l"] (store GhcLibDir) "<path>" "Library directory for GHC."@@ -101,8 +97,8 @@ ghcRTSFlag :: Flag Args ghcRTSFlag = flagReq ["use-rtsopts"] storeRTS "\"<flags>\""                   "Runtime options (multithreading etc.). See `ghc +RTS -?`."- where storeRTS allRTSFlags (Args mode prev)-          = fmap (Args mode . (:prev) . RTSFlags)+ where storeRTS allRTSFlags (Args md prev)+          = fmap (Args md . (:prev) . RTSFlags)               . parseRTS . words $ filter (/='"') allRTSFlags        parseRTS ("+RTS":fs)  -- Ignore if this is included (we already wrap            = parseRTS fs     -- the ihaskell-kernel call in +RTS <flags> -RTS anyway)@@ -115,13 +111,13 @@ kernelDebugFlag :: Flag Args kernelDebugFlag = flagNone ["debug"] addDebug "Print debugging output from the kernel."   where-    addDebug (Args mode prev) = Args mode (KernelDebug : prev)+    addDebug (Args md prev) = Args md (KernelDebug : prev)  kernelStackFlag :: Flag Args kernelStackFlag = flagNone ["stack"] addStack                     "Inherit environment from `stack` when it is installed"   where-    addStack (Args mode prev) = Args mode (KernelspecUseStack : prev)+    addStack (Args md prev) = Args md (KernelspecUseStack : prev)  confFlag :: Flag Args confFlag = flagReq ["conf", "c"] (store ConfFile) "<rc.hs>"@@ -131,12 +127,14 @@ installPrefixFlag = flagReq ["prefix"] (store KernelspecInstallPrefix) "<install-dir>"                       "Installation prefix for kernelspec (see Jupyter's --prefix option)" +helpFlag :: Flag Args helpFlag = flagHelpSimple (add Help) -add flag (Args mode flags) = Args mode $ flag : flags+add :: Argument -> Args -> Args+add flag (Args md flags) = Args md $ flag : flags  store :: (String -> Argument) -> String -> Args -> Either String Args-store constructor str (Args mode prev) = Right $ Args mode $ constructor str : prev+store constructor str (Args md prev) = Right $ Args md $ constructor str : prev  installKernelSpec :: Mode Args installKernelSpec =@@ -168,14 +166,14 @@                    , helpFlag                    ] -    consForce (Args mode prev) = Args mode (OverwriteFiles : prev)+    consForce (Args md prev) = Args md (OverwriteFiles : prev)     unnamedArg = Arg (store ConvertFrom) "<file>" False-    consStyle style (Args mode prev) = Args mode (ConvertLhsStyle style : prev)+    consStyle style (Args md prev) = Args md (ConvertLhsStyle style : prev) -    storeFormat constructor str (Args mode prev) =+    storeFormat constructor str (Args md prev) =       case T.toLower (T.pack str) of-        "lhs"   -> Right $ Args mode $ constructor LhsMarkdown : prev-        "ipynb" -> Right $ Args mode $ constructor IpynbFile : prev+        "lhs"   -> Right $ Args md $ constructor LhsMarkdown : prev+        "ipynb" -> Right $ Args md $ constructor IpynbFile : prev         _       -> Left $ "Unknown format requested: " ++ str      storeLhs str previousArgs =@@ -196,13 +194,11 @@   let noMode = mode "IHaskell" defaultReport descr noArgs [helpFlag, versionFlag]       defaultReport = Args (ShowDefault helpStr) []       descr = "Haskell for Interactive Computing."-      helpFlag = flagHelpSimple (add Help)       versionFlag = flagVersion (add Version)       helpStr = showText (Wrap 100) $ helpText [] HelpFormatAll ihaskellArgs   in noMode { modeGroupModes = toGroup allModes }-  where-    add flag (Args mode flags) = Args mode $ flag : flags +noArgs :: Arg a noArgs = flagArg unexpected ""   where     unexpected a = error $ "Unexpected argument: " ++ a
src/IHaskell/IPython.hs view
@@ -1,5 +1,4 @@ {-# language NoImplicitPrelude, DoAndIfThenElse, OverloadedStrings, ExtendedDefaultRules #-}-{-# LANGUAGE CPP #-}  -- | Description : Shell scripting wrapper using @Shelly@ for the @notebook@, and --                 @console@ commands.@@ -17,11 +16,7 @@ import           IHaskellPrelude import qualified Data.Text as T import qualified Data.Text.Lazy as LT-import qualified Data.ByteString as BS-import qualified Data.ByteString.Lazy as LBS-import qualified Data.ByteString.Char8 as CBS -import           Control.Concurrent (threadDelay) import           System.Argv0 import qualified Shelly as SH import qualified System.IO as IO@@ -33,12 +28,10 @@ import           Data.Text.Lazy.Builder (toLazyText) import           Control.Monad (mplus) -import qualified System.IO.Strict as StrictIO import qualified Paths_ihaskell as Paths  import qualified GHC.Paths import           IHaskell.Types-import           System.Posix.Signals  import           StringUtils (replace, split) @@ -67,9 +60,6 @@ kernelName :: String kernelName = "haskell" -kernelArgs :: [String]-kernelArgs = ["--kernel", kernelName]- ipythonCommand :: SH.Sh SH.FilePath ipythonCommand = do   jupyterMay <- SH.which "jupyter"@@ -85,33 +75,6 @@     Nothing      -> SH.errorExit "The Jupyter binary could not be located"     Just ipython -> return ipython --- | Run the IPython command with any arguments. The kernel is set to IHaskell.-ipython :: Bool         -- ^ Whether to suppress output.-        -> [Text]       -- ^ IPython command line arguments.-        -> SH.Sh String    -- ^ IPython output.-ipython suppress args = do-  liftIO $ installHandler keyboardSignal (CatchOnce $ return ()) Nothing--  -- We have this because using `run` does not let us use stdin.-  cmd <- ipythonCommand-  SH.runHandles cmd args handles doNothing--  where-    handles = [SH.InHandle SH.Inherit, outHandle suppress, errorHandle suppress]-    outHandle True = SH.OutHandle SH.CreatePipe-    outHandle False = SH.OutHandle SH.Inherit-    errorHandle True = SH.ErrorHandle SH.CreatePipe-    errorHandle False = SH.ErrorHandle SH.Inherit-    doNothing _ stdout _ = if suppress-                             then liftIO $ StrictIO.hGetContents stdout-                             else return ""---- | Run while suppressing all output.-quietRun path args = SH.runHandles path args handles nothing-  where-    handles = [SH.InHandle SH.Inherit, SH.OutHandle SH.CreatePipe, SH.ErrorHandle SH.CreatePipe]-    nothing _ _ _ = return ()- fp :: SH.FilePath -> FilePath fp = T.unpack . SH.toTextIgnore @@ -126,17 +89,14 @@ ihaskellDir :: SH.Sh FilePath ihaskellDir = do   home <- maybe (error "$HOME not defined.") SH.fromText <$> SH.get_env "HOME"-  fp <$> ensure (return (home SH.</> ".ihaskell"))--notebookDir :: SH.Sh SH.FilePath-notebookDir = ensure $ (SH.</> "notebooks") <$> ihaskellDir+  fp <$> ensure (return (home SH.</> (".ihaskell" :: SH.FilePath)))  getIHaskellDir :: IO String getIHaskellDir = SH.shelly ihaskellDir  defaultConfFile :: IO (Maybe String) defaultConfFile = fmap (fmap fp) . SH.shelly $ do-  filename <- (SH.</> "rc.hs") <$> ihaskellDir+  filename <- (SH.</> ("rc.hs" :: SH.FilePath)) <$> ihaskellDir   exists <- SH.test_f filename   return $ if exists              then Just filename@@ -156,17 +116,17 @@     Nothing -> badIPython                  "No Jupyter / IPython detected -- install Jupyter 3.0+ before using IHaskell."     Just path -> do-      stdout <- SH.silently (SH.run path ["--version"])-      stderr <- SH.lastStderr+      sout <- SH.silently (SH.run path ["--version"])+      serr <- SH.lastStderr       let majorVersion = join . fmap listToMaybe . parseVersion . T.unpack-      case mplus (majorVersion stderr) (majorVersion stdout) of+      case mplus (majorVersion serr) (majorVersion sout) of         Nothing -> badIPython $ T.concat                                   [ "Detected Jupyter, but could not parse version number."                                   , "\n"                                   , "(stdout = "-                                  , stdout+                                  , sout                                   , ", stderr = "-                                  , stderr+                                  , serr                                   , ")"                                   ] @@ -183,7 +143,7 @@ -- | Install an IHaskell kernelspec into the right location. The right location is determined by -- using `ipython kernelspec install --user`. installKernelspec :: Bool -> KernelSpecOptions -> SH.Sh ()-installKernelspec replace opts = void $ do+installKernelspec repl opts = void $ do   ihaskellPath <- getIHaskellPath   confFile <- liftIO $ kernelSpecConfFile opts @@ -196,7 +156,7 @@         ++ ["--ghclib", kernelSpecGhcLibdir opts]         ++ (case kernelSpecRTSOptions opts of              [] -> []-             rtsOpts -> "+RTS" : kernelSpecRTSOptions opts ++ ["-RTS"])+             _ -> "+RTS" : kernelSpecRTSOptions opts ++ ["-RTS"])            ++ ["--stack" | kernelSpecUseStack opts]    let kernelSpec = KernelSpec@@ -209,7 +169,7 @@   -- shell out to IPython to install this kernelspec directory.   SH.withTmpDir $ \tmp -> do     let kernelDir = tmp SH.</> kernelName-    let filename = kernelDir SH.</> "kernel.json"+    let filename = kernelDir SH.</> ("kernel.json" :: SH.FilePath)      SH.mkdir_p kernelDir     SH.writefile filename $ LT.toStrict $ toLazyText $ encodeToTextBuilder $ toJSON kernelSpec@@ -220,43 +180,24 @@      ipython <- locateIPython -    let replaceFlag = ["--replace" | replace]+    let replaceFlag = ["--replace" | repl]         installPrefixFlag = maybe ["--user"] (\prefix -> ["--prefix", T.pack prefix]) (kernelSpecInstallPrefix opts)         cmd = concat [["kernelspec", "install"], installPrefixFlag, [SH.toTextIgnore kernelDir], replaceFlag]      SH.silently $ SH.run ipython cmd -kernelSpecCreated :: SH.Sh Bool-kernelSpecCreated = do-  ipython <- locateIPython-  out <- SH.silently $ SH.run ipython ["kernelspec", "list"]-  let kernelspecs = map T.strip $ T.lines out-  return $ T.pack kernelName `elem` kernelspecs- -- | Replace "~" with $HOME if $HOME is defined. Otherwise, do nothing. subHome :: String -> IO String subHome path = SH.shelly $ do   home <- T.unpack <$> fromMaybe "~" <$> SH.get_env "HOME"   return $ replace "~" home path --- | Get the path to an executable. If it doensn't exist, fail with an error message complaining--- about it.-path :: Text -> SH.Sh SH.FilePath-path exe = do-  path <- SH.which $ SH.fromText exe-  case path of-    Nothing -> do-      liftIO $ putStrLn $ "Could not find `" ++ T.unpack exe ++ "` executable."-      fail $ "`" ++ T.unpack exe ++ "` not on $PATH."-    Just exePath -> return exePath- -- | Parse an IPython version string into a list of integers. parseVersion :: String -> Maybe [Int] parseVersion versionStr =   let versions = map readMay $ split "." versionStr-      parsed = all isJust versions-  in if parsed-       then Just $ map fromJust versions+  in if all isJust versions+       then Just $ catMaybes versions        else Nothing  -- | Get the absolute path to this IHaskell executable.@@ -268,7 +209,7 @@   -- If we have an absolute path, that's the IHaskell we're interested in.   if FP.isAbsolute f     then return f-    else +    else     -- Check whether this is a relative path, or just 'IHaskell' with $PATH resolution done by     -- the shell. If it's just 'IHaskell', use the $PATH variable to find where IHaskell lives.     if FP.takeFileName f == f@@ -278,16 +219,6 @@           Nothing   -> error "ihaskell not on $PATH and not referenced relative to directory."           Just path -> return $ T.unpack $ SH.toTextIgnore path       else liftIO $ makeAbsolute f-#if !MIN_VERSION_directory(1, 2, 2)--- This is included in later versions of `directory`, but we cannot use later versions because GHC--- library depends on a particular version of it.-makeAbsolute :: FilePath -> IO FilePath-makeAbsolute = fmap FP.normalise . absolutize-  where-    absolutize path -- avoid the call to `getCurrentDirectory` if we can-      | FP.isRelative path = fmap (FP.</> path) getCurrentDirectory-      | otherwise = return path-#endif getSandboxPackageConf :: IO (Maybe String) getSandboxPackageConf = SH.shelly $ do   myPath <- getIHaskellPath
src/IHaskell/IPython/Stdin.hs view
@@ -26,21 +26,14 @@ module IHaskell.IPython.Stdin (fixStdin, recordParentHeader, recordKernelProfile) where  import           IHaskellPrelude-import qualified Data.Text as T-import qualified Data.Text.Lazy as LT-import qualified Data.ByteString as BS-import qualified Data.ByteString.Lazy as LBS-import qualified Data.ByteString.Char8 as CBS  import           Control.Concurrent import           Control.Applicative ((<$>))-import           Control.Concurrent.Chan-import           Control.Monad import           GHC.IO.Handle import           GHC.IO.Handle.Types+import           System.FilePath ((</>)) import           System.Posix.IO import           System.IO.Unsafe-import qualified Data.Map as Map  import           IHaskell.IPython.Types import           IHaskell.IPython.ZeroMQ@@ -55,7 +48,9 @@ fixStdin :: String -> IO () fixStdin dir = do   -- Initialize the stdin interface.-  profile <- fromJust . readMay <$> readFile (dir ++ "/.kernel-profile")+  let fpath = dir </> ".kernel-profile"+  profile <- fromMaybe (error $ "fixStdin: Failed reading " ++ fpath)+              . readMay <$> readFile fpath   interface <- serveStdin profile   putMVar stdinInterface interface   void $ forkIO $ stdinOnce dir@@ -79,8 +74,8 @@     loop stdinInput oldStdin newStdin = do       let FileHandle _ mvar = stdin       threadDelay $ 150 * 1000-      empty <- isEmptyMVar mvar-      if not empty+      e <- isEmptyMVar mvar+      if not e         then loop stdinInput oldStdin newStdin         else do           line <- getInputLine dir@@ -94,17 +89,12 @@    -- Send a request for input.   uuid <- UUID.random-  parentHeader <- fromJust . readMay <$> readFile (dir ++ "/.last-req-header")-  let header = MessageHeader-        { username = username parentHeader-        , identifiers = identifiers parentHeader-        , parentHeader = Just parentHeader-        , messageId = uuid-        , sessionId = sessionId parentHeader-        , metadata = Map.fromList []-        , msgType = InputRequestMessage-        }-  let msg = RequestInput header ""+  let fpath = dir </> ".last-req-header"+  parentHdr <- fromMaybe (error $ "getInputLine: Failed reading " ++ fpath)+                . readMay <$> readFile fpath+  let hdr = MessageHeader (mhIdentifiers parentHdr) (Just parentHdr) mempty+              uuid (mhSessionId parentHdr) (mhUsername parentHdr) InputRequestMessage+  let msg = RequestInput hdr ""   writeChan req msg    -- Get the reply.@@ -112,8 +102,8 @@   return value  recordParentHeader :: String -> MessageHeader -> IO ()-recordParentHeader dir header =-  writeFile (dir ++ "/.last-req-header") $ show header+recordParentHeader dir hdr =+  writeFile (dir ++ "/.last-req-header") $ show hdr  recordKernelProfile :: String -> Profile -> IO () recordKernelProfile dir profile =
src/IHaskell/Publish.hs view
@@ -1,10 +1,12 @@ {-# language NoImplicitPrelude, DoAndIfThenElse, OverloadedStrings, ExtendedDefaultRules #-}-module IHaskell.Publish (publishResult) where+module IHaskell.Publish+  ( publishResult+  ) where  import           IHaskellPrelude  import qualified Data.Text as T-import qualified Data.Text.Encoding as E+import qualified Data.Time as Time  import           IHaskell.Display import           IHaskell.Types@@ -24,23 +26,27 @@               -> MVar [DisplayData] -- ^ A MVar to use for storing pager output               -> Bool               -- ^ Whether to use the pager               -> EvaluationResult   -- ^ The evaluation result+              -> ErrorOccurred      -- ^ Whether evaluation completed successfully               -> IO ()-publishResult send replyHeader displayed updateNeeded pagerOutput usePager result = do+publishResult send replyHeader displayed updateNeeded poutput upager result success = do   let final =         case result of           IntermediateResult{} -> False           FinalResult{}        -> True-      outs = outputs result+      outs = evaluationOutputs result +  -- Get time to send to output for unique labels.+  uniqueLabel <- getUniqueLabel+   -- If necessary, clear all previous output and redraw.   clear <- readMVar updateNeeded   when clear $ do     clearOutput     disps <- readMVar displayed-    mapM_ sendOutput $ reverse disps+    mapM_ (sendOutput uniqueLabel) $ reverse disps    -- Draw this message.-  sendOutput outs+  sendOutput uniqueLabel outs    -- If this is the final message, add it to the list of completed messages. If it isn't, make sure we   -- clear it later by marking update needed as true.@@ -49,30 +55,45 @@     modifyMVar_ displayed (return . (outs :))      -- If this has some pager output, store it for later.-    let pager = pagerOut result-    unless (null pager) $-      if usePager-        then modifyMVar_ pagerOutput (return . (++ pager))-        else sendOutput $ Display pager+    case result of+      IntermediateResult _ -> pure ()+      FinalResult _ pager _ ->+        unless (null pager) $+          if upager+            then modifyMVar_ poutput (return . (++ pager))+            else sendOutput uniqueLabel $ Display pager    where     clearOutput = do-      header <- dupHeader replyHeader ClearOutputMessage-      send $ ClearOutput header True+      hdr <- dupHeader replyHeader ClearOutputMessage+      send $ ClearOutput hdr True -    sendOutput (ManyDisplay manyOuts) = mapM_ sendOutput manyOuts-    sendOutput (Display outs) = do-      header <- dupHeader replyHeader DisplayDataMessage-      send $ PublishDisplayData header $ map (convertSvgToHtml . prependCss) outs+    sendOutput uniqueLabel (ManyDisplay manyOuts) =+      mapM_ (sendOutput uniqueLabel) manyOuts+    sendOutput uniqueLabel (Display outs) = case success of+      Success -> do+        hdr <- dupHeader replyHeader DisplayDataMessage+        send $ PublishDisplayData hdr (map (makeUnique uniqueLabel . prependCss) outs) Nothing+      Failure -> do+        hdr <- dupHeader replyHeader ExecuteErrorMessage+        send $ ExecuteError hdr [T.pack (extractPlain outs)] "" "" -    convertSvgToHtml (DisplayData MimeSvg svg) = html $ makeSvgImg $ base64 $ E.encodeUtf8 svg-    convertSvgToHtml x = x+    prependCss (DisplayData MimeHtml h) =+      DisplayData MimeHtml $ mconcat ["<style>", T.pack ihaskellCSS, "</style>", h]+    prependCss x = x -    makeSvgImg :: Base64 -> String-    makeSvgImg base64data = T.unpack $ "<img src=\"data:image/svg+xml;base64," <>-                                       base64data <>-                                       "\"/>"+    makeUnique l (DisplayData MimeSvg s) =+      DisplayData MimeSvg+        . T.replace "glyph" ("glyph-" <> l)+        . T.replace "\"clip" ("\"clip-" <> l)+        . T.replace "#clip" ("#clip-" <> l)+        . T.replace "\"image" ("\"image-" <> l)+        . T.replace "#image" ("#image-" <> l)+        . T.replace "linearGradient id=\"linear" ("linearGradient id=\"linear-" <> l)+        . T.replace "#linear" ("#linear-" <> l)+        $ s+    makeUnique _ x = x -    prependCss (DisplayData MimeHtml html) =-      DisplayData MimeHtml $ mconcat ["<style>", T.pack ihaskellCSS, "</style>", html]-    prependCss x = x+    getUniqueLabel =+      fmap (\(Time.UTCTime d s) -> T.pack (show d) <> T.pack (show s))+        Time.getCurrentTime
src/IHaskell/Types.hs view
@@ -12,13 +12,15 @@     MessageType(..),     dupHeader,     Username,-    Metadata(..),+    Metadata,     replyType,     ExecutionState(..),     StreamType(..),     MimeType(..),     DisplayData(..),+    ErrorOccurred(..),     EvaluationResult(..),+    evaluationOutputs,     ExecuteReplyStatus(..),     KernelState(..),     LintStatus(..),@@ -39,17 +41,8 @@  import           IHaskellPrelude -import qualified Data.ByteString as BS-import qualified Data.ByteString.Char8 as CBS-import qualified Data.ByteString.Lazy as LBS-import qualified Data.Text as T-import qualified Data.Text.Lazy as LT--import           Data.Aeson (Value, (.=), object)-import           Data.Aeson.Types (emptyObject)-import qualified Data.ByteString.Char8 as Char+import           Data.Aeson (ToJSON (..), Value, (.=), object) import           Data.Function (on)-import           Data.Semigroup import           Data.Serialize import           GHC.Generics @@ -100,6 +93,28 @@         -> IO ()   close _ _ = return () +-- | these instances cause the image, html etc. which look like:+--+-- > Display+-- > [Display]+-- > IO [Display]+-- > IO (IO Display)+--+-- be run the IO and get rendered (if the frontend allows it) in the pretty form.+instance IHaskellDisplay a => IHaskellDisplay (IO a) where+  display = (display =<<)++instance IHaskellDisplay Display where+  display = return++instance IHaskellDisplay DisplayData where+  display disp = return $ Display [disp]++instance IHaskellDisplay a => IHaskellDisplay [a] where+  display disps = do+    displays <- mapM display disps+    return $ ManyDisplay displays+ data Widget = forall a. IHaskellWidget a => Widget a   deriving Typeable @@ -157,7 +172,7 @@ defaultKernelState = KernelState   { getExecutionCounter = 1   , getLintStatus = LintOn-  , useSvg = False+  , useSvg = True   , useShowErrors = False   , useShowTypes = False   , usePager = True@@ -230,29 +245,39 @@                   | DisplayWidget  instance ToJSON WidgetMethod where-  toJSON DisplayWidget = object ["method" .= "display"]-  toJSON (UpdateState v) = object ["method" .= "update", "state" .= v]-  toJSON (CustomContent v) = object ["method" .= "custom", "content" .= v]+  toJSON DisplayWidget = object ["method" .= ("display" :: Text)]+  toJSON (UpdateState v) = object ["method" .= ("update" :: Text), "state" .= v]+  toJSON (CustomContent v) = object ["method" .= ("custom" :: Text), "content" .= v]  -- | Output of evaluation.-data EvaluationResult =-                      -- | An intermediate result which communicates what has been printed thus-                      -- far.-                        IntermediateResult-                          { outputs :: Display -- ^ Display outputs.-                          }-                      |-                        FinalResult-                          { outputs :: Display       -- ^ Display outputs.-                          , pagerOut :: [DisplayData] -- ^ Mimebundles to display in the IPython-                                                      -- pager.-                          , commMsgs :: [WidgetMsg]  -- ^ Comm operations-                          }+--+-- A result can either be intermediate or final.+-- Final result has Mimebundles ('DisplayData') and Comm operations+-- ('WidgetMsg') on top of Display outputs.+data EvaluationResult+  -- | An intermediate result which communicates what has been printed thus far.+  = IntermediateResult+        !Display+  | FinalResult+        !Display+        ![DisplayData]+        ![WidgetMsg]   deriving Show ++evaluationOutputs :: EvaluationResult -> Display+evaluationOutputs er =+  case er of+    IntermediateResult outputs -> outputs+    FinalResult outputs _ _ -> outputs+ -- | Duplicate a message header, giving it a new UUID and message type. dupHeader :: MessageHeader -> MessageType -> IO MessageHeader-dupHeader header messageType = do+dupHeader hdr messageType = do   uuid <- liftIO random+  return hdr { mhMessageId = uuid, mhMsgType = messageType } -  return header { messageId = uuid, msgType = messageType }+-- | Whether or not an error occurred.+data ErrorOccurred = Success+                   | Failure+  deriving (Show, Eq)
src/IHaskellPrelude.hs view
@@ -8,12 +8,10 @@   Data.Typeable.Typeable,   Data.Typeable.cast, -#if MIN_VERSION_ghc(7,8,0)   Data.Typeable.Proxy,    GHC.Exts.IsString,   GHC.Exts.IsList,-#endif    System.IO.hPutStrLn,   System.IO.hPutStr,@@ -54,8 +52,8 @@   Data.IORef.modifyIORef',   Data.IORef.newIORef, -   +   -- Miscellaneous names   Data.Map.Map,   GHC.IO.FilePath,@@ -80,20 +78,14 @@ import           GHC.Num                as X import           GHC.Real               as X import           GHC.Err                as X hiding (absentErr)-#if MIN_VERSION_ghc(8,0,0) import           GHC.Base               as X hiding (Any, mapM, foldr, sequence, many, (<|>), Module(..))-#elif MIN_VERSION_ghc(7,10,0)-import           GHC.Base               as X hiding (Any, mapM, foldr, sequence, many, (<|>))-#else-import           GHC.Base               as X hiding (Any)-#endif import           Data.List              as X hiding (head, last, tail, init, transpose, subsequences, permutations,                                         foldl, foldl1, maximum, minimum, scanl, scanl1, scanr, scanr1,                                         span, break, mapAccumL, mapAccumR, dropWhileEnd, (!!),                                         elemIndices, elemIndex, findIndex, findIndices, zip5, zip6,                                         zip7, zipWith5, zipWith6, zipWith7, unzip5, unzip6, unzip6,                                         delete, union, lookup, intersect, insert, deleteBy,-                                        deleteFirstBy, unionBy, intersectBy, group, groupBy, insertBy,+                                        unionBy, intersectBy, group, groupBy, insertBy,                                         maximumBy, minimumBy, genericLength, genericDrop, genericTake,                                         genericSplitAt, genericIndex, genericReplicate, inits, tails) @@ -121,13 +113,27 @@  type LText = Data.Text.Lazy.Text -(headMay, tailMay, lastMay, initMay, maximumMay, minimumMay) =-  (wrapEmpty head, wrapEmpty tail, wrapEmpty last,-   wrapEmpty init, wrapEmpty maximum, wrapEmpty minimum)-  where-    wrapEmpty :: ([a] -> b) -> [a] -> Maybe b-    wrapEmpty _ [] = Nothing-    wrapEmpty f xs = Just (f xs)+headMay :: [a] -> Maybe a+headMay = wrapEmpty head++tailMay :: [a] -> Maybe [a]+tailMay = wrapEmpty tail++lastMay :: [a] -> Maybe a+lastMay = wrapEmpty last++initMay :: [a] -> Maybe [a]+initMay = wrapEmpty init++maximumMay :: Ord a => [a] -> Maybe a+maximumMay = wrapEmpty maximum++minimumMay :: Ord a => [a] -> Maybe a+minimumMay = wrapEmpty minimum++wrapEmpty :: ([a] -> b) -> [a] -> Maybe b+wrapEmpty _ [] = Nothing+wrapEmpty f xs = Just (f xs)  maximumByMay :: (a -> a -> Ordering) -> [a] -> Maybe a maximumByMay _ [] = Nothing
src/StringUtils.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE NoImplicitPrelude #-} module StringUtils (     strip,     lstrip,
src/tests/Hspec.hs view
@@ -7,10 +7,12 @@ import           IHaskell.Test.Completion (testCompletions) import           IHaskell.Test.Parser (testParser) import           IHaskell.Test.Eval (testEval)+import           IHaskell.Test.Hoogle (testHoogle)  main :: IO ()-main = +main =   hspec $ do     testParser     testEval     testCompletions+    testHoogle
src/tests/IHaskell/Test/Completion.hs view
@@ -1,5 +1,9 @@ {-# language NoImplicitPrelude, DoAndIfThenElse, OverloadedStrings, ExtendedDefaultRules #-} {-# LANGUAGE CPP #-}++-- Shelly's types are kinda borked.+{-# OPTIONS_GHC -Wno-type-defaults #-}+ module IHaskell.Test.Completion (testCompletions) where  import           Prelude@@ -23,12 +27,8 @@                                            completionTarget) import           IHaskell.Test.Util (replace, shouldBeAmong, ghc) -#if !MIN_VERSION_base(4,8,0)-import           Control.Applicative ((<$>))-#endif- -- | @readCompletePrompt "xs*ys"@ return @(xs, i)@ where i is the location of--- @'*'@ in the input string. +-- @'*'@ in the input string. readCompletePrompt :: String -> (String, Int) readCompletePrompt string =   case elemIndex '*' string of@@ -48,23 +48,20 @@  shouldHaveCompletionsInDirectory :: String -> [String] -> IO () shouldHaveCompletionsInDirectory string expected = do-  (matched, completions) <- completionEventInDirectory string-  let existsInCompletion = (`elem` completions)-      unmatched = filter (not . existsInCompletion) expected+  (_, completions) <- completionEventInDirectory string   expected `shouldBeAmong` completions +completionHas :: String -> [String] -> IO () completionHas string expected = do-  (matched, completions) <- ghc $ do+  (_, completions) <- ghc $ do                               initCompleter                               completionEvent string-  let existsInCompletion = (`elem` completions)-      unmatched = filter (not . existsInCompletion) expected   expected `shouldBeAmong` completions  initCompleter :: Interpreter () initCompleter = do   flags <- getSessionDynFlags-  setSessionDynFlags $ flags { hscTarget = HscInterpreted, ghcLink = LinkInMemory }+  _ <- setSessionDynFlags $ flags { hscTarget = HscInterpreted, ghcLink = LinkInMemory }    -- Import modules.   imports <- mapM parseImportDecl@@ -168,9 +165,8 @@   it "correctly interprets ~ as the environment HOME variable" $ do     let shouldHaveCompletions :: String -> [String] -> IO ()         shouldHaveCompletions string expected = do-          (matched, completions) <- withHsHome $ completionEvent string-          let existsInCompletion = (`elem` completions)-              unmatched = filter (not . existsInCompletion) expected+          (_, completions) <- withHsHome $ completionEvent string+           expected `shouldBeAmong` completions     ":! cd ~/*" `shouldHaveCompletions` ["~/dir/"]     ":! ~/*" `shouldHaveCompletions` ["~/dir/"]@@ -182,8 +178,6 @@         matchText <- withHsHome $ fst <$> uncurry complete (readCompletePrompt string)         matchText `shouldBe` expected -      setHomeEvent path = liftIO $ setEnv "HOME" (T.unpack $ toTextIgnore path)-   it "generates the correct matchingText on `:! cd ~/*` " $     ":! cd ~/*" `shouldHaveMatchingText` ("~/" :: String) @@ -197,7 +191,7 @@             -> [Shelly.FilePath] -- ^ files relative to temporary directory             -> (Shelly.FilePath -> Interpreter a)             -> IO a--- | Run an Interpreter action, but first make a temporary directory +-- | Run an Interpreter action, but first make a temporary directory --   with some files and folder and cd to it. inDirectory dirs files action = shelly $ withTmpDir $ \dirPath -> do   cd dirPath@@ -207,11 +201,11 @@   where     cdEvent path = liftIO $ setCurrentDirectory path     wrap :: String -> Interpreter a -> Interpreter a-    wrap path action = do+    wrap path actn = do       initCompleter       pwd <- IHaskell.Eval.Evaluate.liftIO getCurrentDirectory       cdEvent path   -- change to the temporary directory-      out <- action  -- run action+      out <- actn  -- run action       cdEvent pwd    -- change back to the original directory       return out @@ -223,4 +217,5 @@                     , p "dir" </> p "file2.lhs"                     ]   where+    p :: T.Text -> T.Text     p = id
src/tests/IHaskell/Test/Eval.hs view
@@ -24,34 +24,34 @@ eval string = do   outputAccum <- newIORef []   pagerAccum <- newIORef []-  let publish evalResult =+  let publish evalResult _ =         case evalResult of           IntermediateResult{} -> return ()-          FinalResult outs page [] -> do+          FinalResult outs page _ -> do             modifyIORef outputAccum (outs :)             modifyIORef pagerAccum (page :)       noWidgetHandling s _ = return s    getTemporaryDirectory >>= setCurrentDirectory   let state = defaultKernelState { getLintStatus = LintOff }-  interpret GHC.Paths.libdir False $ const $-    IHaskell.Eval.Evaluate.evaluate state string publish noWidgetHandling+  _ <- interpret GHC.Paths.libdir False $ const $+        IHaskell.Eval.Evaluate.evaluate state string publish noWidgetHandling   out <- readIORef outputAccum-  pagerOut <- readIORef pagerAccum-  return (reverse out, unlines . map extractPlain . reverse $ pagerOut)+  pagerout <- readIORef pagerAccum+  return (reverse out, unlines . map extractPlain . reverse $ pagerout)  becomes :: String -> [String] -> IO () becomes string expected = evaluationComparing comparison string   where     comparison :: ([Display], String) -> IO ()-    comparison (results, pageOut) = do+    comparison (results, _pageOut) = do       when (length results /= length expected) $         expectationFailure $ "Expected result to have " ++ show (length expected)                                                            ++ " results. Got " ++ show results -      forM_ (zip results expected) $ \(ManyDisplay [Display result], expected) -> case extractPlain result of-        ""  -> expectationFailure $ "No plain-text output in " ++ show result ++ "\nExpected: " ++ expected-        str -> str `shouldBe` expected+      forM_ (zip results expected) $ \(ManyDisplay [Display result], expect) -> case extractPlain result of+        ""  -> expectationFailure $ "No plain-text output in " ++ show result ++ "\nExpected: " ++ expect+        str -> str `shouldBe` expect  evaluationComparing :: (([Display], String) -> IO b) -> String -> IO b evaluationComparing comparison string = do@@ -66,37 +66,30 @@ pages :: String -> [String] -> IO () pages string expected = evaluationComparing comparison string   where-    comparison (results, pageOut) =+    comparison (_results, pageOut) =       strip (stripHtml pageOut) `shouldBe` strip (fixQuotes $ unlines expected)      -- A very, very hacky method for removing HTML     stripHtml str = go str       where-        go ('<':str) =-          case stripPrefix "script" str of+        go ('<':xs) =+          case stripPrefix "script" xs of             Nothing  -> go' str-            Just str -> dropScriptTag str+            Just s -> dropScriptTag s         go (x:xs) = x : go xs         go [] = [] -        go' ('>':str) = go str-        go' (x:xs) = go' xs+        go' ('>':xs) = go xs+        go' (_:xs) = go' xs         go' [] = error $ "Unending bracket html tag in string " ++ str -        dropScriptTag str =-          case stripPrefix "</script>" str of-            Just str -> go str-            Nothing  -> dropScriptTag $ tail str+        dropScriptTag str1 =+          case stripPrefix "</script>" str1 of+            Just s  -> go s+            Nothing -> dropScriptTag $ tail str      fixQuotes :: String -> String-#if MIN_VERSION_ghc(7, 8, 0)     fixQuotes = id-#else-    fixQuotes = map $ \char -> case char of-      '\8216' -> '`'-      '\8217' -> '\''-      c       -> c-#endif   testEval :: Spec@@ -163,6 +156,9 @@     it "prints Unicode characters correctly" $ do       "putStrLn \"Héllö, Üñiço∂e!\"" `becomes` ["Héllö, Üñiço∂e!"]       "putStrLn \"Привет!\"" `becomes` ["Привет!"]++    it "prints multiline output correctly" $ do+      ":! printf \"hello\\nworld\"" `becomes` ["hello\nworld"]      it "evaluates directives" $ do #if MIN_VERSION_ghc(8,2,0)
+ src/tests/IHaskell/Test/Hoogle.hs view
@@ -0,0 +1,63 @@+{-# LANGUAGE QuasiQuotes #-}++module IHaskell.Test.Hoogle ( testHoogle ) where++import           Test.Hspec+import           Text.RawString.QQ++import           IHaskell.Eval.Hoogle+-- import           Data.Text (unpack)+-- import qualified Data.Text.IO as T+preludeFmapJson :: String+preludeFmapJson = [r|+[+  {+    "url": "https://hackage.haskell.org/package/base/docs/Prelude.html#v:fmap",+    "module": {+      "url": "https://hackage.haskell.org/package/base/docs/Prelude.html",+      "name": "Prelude"+    },+    "package": {+      "url": "https://hackage.haskell.org/package/base",+      "name": "base"+    },+    "item": "<span class=name><0>fmap</0></span> :: Functor f =&gt; (a -&gt; b) -&gt; f a -&gt; f b",+    "type": "",+    "docs": ""+  }+]|]++moduleJson :: String+moduleJson = [r|+[+  {+    "url": "https://hackage.haskell.org/package/universum/docs/Universum-Functor-Fmap.html",+    "module": {},+    "package": {+      "url": "https://hackage.haskell.org/package/universum",+      "name": "universum"+    },+    "item": "<b>module</b> Universum.Functor.<span class=name><0>Fmap</0></span>",+    "type": "module",+    "docs": "This module contains useful functions to work with <a>Functor</a> type\nclass.\n"+  }+]|]++testHoogle :: Spec+testHoogle = describe "Hoogle Search" $ do+  describe "fmap search result" $ do+    let results = parseResponse preludeFmapJson :: [HoogleResult]+    it "should find 1 results" $ do+      length results `shouldBe` 1+    let (SearchResult (HoogleResponse loc signature _docUrl)) = head results+    it "should not contain html markup" $ do+      loc       `shouldBe` "https://hackage.haskell.org/package/base/docs/Prelude.html#v:fmap"+      signature `shouldBe` "fmap :: Functor f => (a -> b) -> f a -> f b"+  describe "module result" $ do+    let results = parseResponse moduleJson :: [HoogleResult]+    let (SearchResult (HoogleResponse _loc signature _docUrl)) = head results+    it "should not contain html markup" $ do+      signature `shouldBe` "module Universum.Functor.Fmap"+    it "should be renderable" $ do+      (render Plain $ head results) `shouldStartWith` "module Universum.Functor.Fmap"+      (render HTML  $ head results) `shouldStartWith` "<span class='hoogle-head'>module</span>"
src/tests/IHaskell/Test/Parser.hs view
@@ -1,25 +1,18 @@ {-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE CPP #-}-module IHaskell.Test.Parser (testParser) where +module IHaskell.Test.Parser (testParser) where  import           Prelude  import           Data.String.Here (hereLit)  import           Test.Hspec-import           Test.Hspec.Contrib.HUnit-import           Test.HUnit (assertBool, assertFailure)+import           Test.HUnit (assertFailure)  import           IHaskell.Test.Util (ghc, strip) import           IHaskell.Eval.Parser (parseString, getModuleName, unloc, layoutChunks, Located(..),                                        CodeBlock(..), DirectiveType(..), StringLoc(..), PragmaType(..)) import           IHaskell.Eval.ParseShell (parseShell) -#if !MIN_VERSION_base(4,8,0)-import           Control.Applicative ((<$>))-#endif-- parses :: String -> IO [CodeBlock] parses str = map unloc <$> ghc (parseString str) @@ -234,10 +227,4 @@        |]) >>= (`shouldBe` [Located 2 (Expression "first"), Located 4 (Expression "second")])   where     dataKindsError = ParseError (Loc 1 10) msg-#if MIN_VERSION_ghc(7, 10, 0)     msg = "Cannot parse data constructor in a data/newtype declaration: 3"-#elif MIN_VERSION_ghc(7, 8, 0)-    msg = "Illegal literal in type (use DataKinds to enable): 3"-#else-    msg = "Illegal literal in type (use -XDataKinds to enable): 3"-#endif