[project @ 2006-01-18 10:49:32 by simonmar]
[ghc-hetmet.git] / ghc / compiler / ghci / InteractiveUI.hs
index a203d94..dd4343f 100644 (file)
-{-# OPTIONS -#include "Linker.h" -#include "SchedAPI.h" #-}
+{-# OPTIONS -#include "Linker.h" #-}
 -----------------------------------------------------------------------------
 -----------------------------------------------------------------------------
--- $Id: InteractiveUI.hs,v 1.127 2002/07/02 10:16:35 wolfgang Exp $
 --
 -- GHC Interactive User Interface
 --
 --
 -- GHC Interactive User Interface
 --
--- (c) The GHC Team 2000
+-- (c) The GHC Team 2005
 --
 -----------------------------------------------------------------------------
 module InteractiveUI ( 
 --
 -----------------------------------------------------------------------------
 module InteractiveUI ( 
-       interactiveUI,  -- :: CmState -> [FilePath] -> [LibrarySpec] -> IO ()
-       LibrarySpec(..),
+       interactiveUI,
        ghciWelcomeMsg
    ) where
 
        ghciWelcomeMsg
    ) where
 
-#include "../includes/config.h"
 #include "HsVersions.h"
 
 #include "HsVersions.h"
 
-import Packages
-
-import CompManager
-import CmTypes         ( Linkable, isObjectLinkable, ModSummary(..) )
-import CmLink          ( findModuleLinkable_maybe )
-
-import HscTypes                ( TyThing(..), showModMsg, InteractiveContext(..) )
-import HsSyn           ( TyClDecl(..), ConDecl(..), Sig(..) )
-import MkIface         ( ifaceTyThing )
-import DriverFlags
-import DriverState
-import DriverUtil      ( handle, remove_spaces )
-import Linker
-import Finder          ( flushPackageCache )
-import Util
-import Id              ( isRecordSelector, recordSelectorFieldLabel, 
-                         isDataConWrapId, isDataConId, idName )
-import Class           ( className )
-import TyCon           ( tyConName, tyConClass_maybe, isPrimTyCon, DataConDetails(..) )
-import FieldLabel      ( fieldLabelTyCon )
-import SrcLoc          ( isGoodSrcLoc )
-import Module          ( moduleName )
-import NameEnv         ( nameEnvElts )
-import Name            ( Name, isHomePackageName, nameSrcLoc, nameOccName,
-                         NamedThing(..) )
-import OccName         ( isSymOcc )
-import BasicTypes      ( defaultFixity )
+-- The GHC interface
+import qualified GHC
+import GHC             ( Session, verbosity, dopt, DynFlag(..), Target(..),
+                         TargetId(..),
+                         mkModule, pprModule, Type, Module, SuccessFlag(..),
+                         TyThing(..), Name, LoadHowMuch(..), Phase,
+                         GhcException(..), showGhcException,
+                         CheckedModule(..), SrcLoc )
+import PprTyThing
 import Outputable
 import Outputable
-import CmdLineOpts     ( DynFlag(..), DynFlags(..), getDynFlags, saveDynFlags,
-                         restoreDynFlags, dopt_unset )
-import Panic           ( GhcException(..), showGhcException )
-import Config
 
 
-#ifndef mingw32_TARGET_OS
-import Posix
+-- for createtags (should these come via GHC?)
+import Module          ( moduleString )
+import Name            ( nameSrcLoc, nameModule, nameOccName )
+import OccName         ( pprOccName )
+import SrcLoc          ( isGoodSrcLoc, srcLocFile, srcLocLine, srcLocCol )
+
+-- Other random utilities
+import Digraph         ( flattenSCCs )
+import BasicTypes      ( failed, successIf )
+import Panic           ( panic, installSignalHandlers )
+import Config
+import StaticFlags     ( opt_IgnoreDotGhci )
+import Linker          ( showLinkerState )
+import Util            ( removeSpaces, handle, global, toArgs,
+                         looksLikeModuleName, prefixMatch, sortLe )
+
+#ifndef mingw32_HOST_OS
+import System.Posix
+#if __GLASGOW_HASKELL__ > 504
+       hiding (getEnv)
+#endif
+#else
+import GHC.ConsoleHandler ( flushConsole )
 #endif
 
 #endif
 
-import Exception
-import Dynamic
-#if HAVE_READLINE_HEADERS && HAVE_READLINE_LIBS
-import Readline 
+#ifdef USE_READLINE
+import Control.Concurrent      ( yield )       -- Used in readline loop
+import System.Console.Readline as Readline
 #endif
 #endif
-import Concurrent
-import IOExts
-import SystemExts
 
 
-import Numeric
-import List
-import System
-import CPUTime
-import Directory
-import IO
-import Char
-import Monad
+--import SystemExts
 
 
-import GlaExts         ( unsafeCoerce# )
+import Control.Exception as Exception
+import Data.Dynamic
+-- import Control.Concurrent
 
 
-import Foreign         ( nullPtr )
-import CString         ( CString, peekCString, withCString )
+import Numeric
+import Data.List
+import Data.Int                ( Int64 )
+import Data.Maybe      ( isJust, fromMaybe, catMaybes )
+import System.Cmd
+import System.CPUTime
+import System.Environment
+import System.Exit     ( exitWith, ExitCode(..) )
+import System.Directory
+import System.IO
+import System.IO.Error as IO
+import Data.Char
+import Control.Monad as Monad
+import Foreign.StablePtr       ( newStablePtr )
+
+import GHC.Exts                ( unsafeCoerce# )
+import GHC.IOBase      ( IOErrorType(InvalidArgument) )
+
+import Data.IORef      ( IORef, newIORef, readIORef, writeIORef )
+
+import System.Posix.Internals ( setNonBlockingFD )
 
 -----------------------------------------------------------------------------
 
 
 -----------------------------------------------------------------------------
 
-ghciWelcomeMsg = "\ 
-\   ___         ___ _\n\ 
-\  / _ \\ /\\  /\\/ __(_)\n\ 
-\ / /_\\// /_/ / /  | |      GHC Interactive, version " ++ cProjectVersion ++ ", for Haskell 98.\n\ 
-\/ /_\\\\/ __  / /___| |      http://www.haskell.org/ghc/\n\ 
-\\\____/\\/ /_/\\____/|_|      Type :? for help.\n"
+ghciWelcomeMsg =
+ "   ___         ___ _\n"++
+ "  / _ \\ /\\  /\\/ __(_)\n"++
+ " / /_\\// /_/ / /  | |      GHC Interactive, version " ++ cProjectVersion ++ ", for Haskell 98.\n"++
+ "/ /_\\\\/ __  / /___| |      http://www.haskell.org/ghc/\n"++
+ "\\____/\\/ /_/\\____/|_|      Type :? for help.\n"
 
 GLOBAL_VAR(commands, builtin_commands, [(String, String -> GHCi Bool)])
 
 builtin_commands :: [(String, String -> GHCi Bool)]
 builtin_commands = [
 
 GLOBAL_VAR(commands, builtin_commands, [(String, String -> GHCi Bool)])
 
 builtin_commands :: [(String, String -> GHCi Bool)]
 builtin_commands = [
-  ("add",      keepGoing addModule),
+  ("add",      keepGoingPaths addModule),
   ("browse",    keepGoing browseCmd),
   ("cd",       keepGoing changeDirectory),
   ("def",      keepGoing defineMacro),
   ("help",     keepGoing help),
   ("?",                keepGoing help),
   ("info",      keepGoing info),
   ("browse",    keepGoing browseCmd),
   ("cd",       keepGoing changeDirectory),
   ("def",      keepGoing defineMacro),
   ("help",     keepGoing help),
   ("?",                keepGoing help),
   ("info",      keepGoing info),
-  ("load",     keepGoing loadModule),
+  ("load",     keepGoingPaths loadModule_),
   ("module",   keepGoing setContext),
   ("module",   keepGoing setContext),
+  ("main",     keepGoing runMain),
   ("reload",   keepGoing reloadModule),
   ("reload",   keepGoing reloadModule),
+  ("check",    keepGoing checkModule),
   ("set",      keepGoing setCmd),
   ("show",     keepGoing showCmd),
   ("set",      keepGoing setCmd),
   ("show",     keepGoing showCmd),
+  ("etags",    keepGoing createETagsFileCmd),
+  ("ctags",    keepGoing createCTagsFileCmd),
   ("type",     keepGoing typeOfExpr),
   ("type",     keepGoing typeOfExpr),
+  ("kind",     keepGoing kindOfType),
   ("unset",    keepGoing unsetOptions),
   ("undef",     keepGoing undefineMacro),
   ("quit",     quit)
   ("unset",    keepGoing unsetOptions),
   ("undef",     keepGoing undefineMacro),
   ("quit",     quit)
@@ -110,103 +121,99 @@ builtin_commands = [
 keepGoing :: (String -> GHCi ()) -> (String -> GHCi Bool)
 keepGoing a str = a str >> return False
 
 keepGoing :: (String -> GHCi ()) -> (String -> GHCi Bool)
 keepGoing a str = a str >> return False
 
+keepGoingPaths :: ([FilePath] -> GHCi ()) -> (String -> GHCi Bool)
+keepGoingPaths a str = a (toArgs str) >> return False
+
 shortHelpText = "use :? for help.\n"
 
 -- NOTE: spaces at the end of each line to workaround CPP/string gap bug.
 shortHelpText = "use :? for help.\n"
 
 -- NOTE: spaces at the end of each line to workaround CPP/string gap bug.
-helpText = "\ 
-\ Commands available from the prompt:\n\ 
-\\n\ 
-\   <stmt>                    evaluate/run <stmt>\n\ 
-\   :add <filename> ...        add module(s) to the current target set\n\ 
-\   :browse [*]<module>               display the names defined by <module>\n\ 
-\   :cd <dir>                 change directory to <dir>\n\ 
-\   :def <cmd> <expr>          define a command :<cmd>\n\ 
-\   :help, :?                 display this list of commands\n\ 
-\   :info [<name> ...]         display information about the given names\n\ 
-\   :load <filename> ...       load module(s) and their dependents\n\ 
-\   :module [+/-] [*]<mod> ... set the context for expression evaluation\n\ 
-\   :reload                   reload the current module set\n\ 
-\\n\ 
-\   :set <option> ...         set options\n\ 
-\   :set args <arg> ...               set the arguments returned by System.getArgs\n\ 
-\   :set prog <progname>       set the value returned by System.getProgName\n\ 
-\\n\ 
-\   :show modules             show the currently loaded modules\n\ 
-\   :show bindings            show the current bindings made at the prompt\n\ 
-\\n\ 
-\   :type <expr>              show the type of <expr>\n\ 
-\   :undef <cmd>              undefine user-defined command :<cmd>\n\ 
-\   :unset <option> ...               unset options\n\ 
-\   :quit                     exit GHCi\n\ 
-\   :!<command>                       run the shell command <command>\n\ 
-\\n\ 
-\ Options for `:set' and `:unset':\n\ 
-\\n\ 
-\    +r                        revert top-level expressions after each evaluation\n\ 
-\    +s                 print timing/memory stats after each evaluation\n\ 
-\    +t                        print type after evaluation\n\ 
-\    -<flags>          most GHC command line flags can also be set here\n\ 
-\                         (eg. -v2, -fglasgow-exts, etc.)\n\ 
-\"
-
-interactiveUI :: CmState -> [FilePath] -> [LibrarySpec] -> IO ()
-interactiveUI cmstate paths cmdline_libs = do
+helpText =
+ " Commands available from the prompt:\n" ++
+ "\n" ++
+ "   <stmt>                      evaluate/run <stmt>\n" ++
+ "   :add <filename> ...         add module(s) to the current target set\n" ++
+ "   :browse [*]<module>         display the names defined by <module>\n" ++
+ "   :cd <dir>                   change directory to <dir>\n" ++
+ "   :def <cmd> <expr>           define a command :<cmd>\n" ++
+ "   :help, :?                   display this list of commands\n" ++
+ "   :info [<name> ...]          display information about the given names\n" ++
+ "   :load <filename> ...        load module(s) and their dependents\n" ++
+ "   :module [+/-] [*]<mod> ...  set the context for expression evaluation\n" ++
+ "   :main [<arguments> ...]     run the main function with the given arguments\n" ++
+ "   :reload                     reload the current module set\n" ++
+ "\n" ++
+ "   :set <option> ...           set options\n" ++
+ "   :set args <arg> ...         set the arguments returned by System.getArgs\n" ++
+ "   :set prog <progname>        set the value returned by System.getProgName\n" ++
+ "\n" ++
+ "   :show modules               show the currently loaded modules\n" ++
+ "   :show bindings              show the current bindings made at the prompt\n" ++
+ "\n" ++
+ "   :ctags [<file>]             create tags file for Vi (default: \"tags\")\n" ++
+ "   :etags [<file>]                    create tags file for Emacs (defauilt: \"TAGS\")\n" ++
+ "   :type <expr>                show the type of <expr>\n" ++
+ "   :kind <type>                show the kind of <type>\n" ++
+ "   :undef <cmd>                undefine user-defined command :<cmd>\n" ++
+ "   :unset <option> ...         unset options\n" ++
+ "   :quit                       exit GHCi\n" ++
+ "   :!<command>                 run the shell command <command>\n" ++
+ "\n" ++
+ " Options for ':set' and ':unset':\n" ++
+ "\n" ++
+ "    +r            revert top-level expressions after each evaluation\n" ++
+ "    +s            print timing/memory stats after each evaluation\n" ++
+ "    +t            print type after evaluation\n" ++
+ "    -<flags>      most GHC command line flags can also be set here\n" ++
+ "                         (eg. -v2, -fglasgow-exts, etc.)\n"
+
+
+interactiveUI :: Session -> [(FilePath, Maybe Phase)] -> Maybe String -> IO ()
+interactiveUI session srcs maybe_expr = do
+
+   -- HACK! If we happen to get into an infinite loop (eg the user
+   -- types 'let x=x in x' at the prompt), then the thread will block
+   -- on a blackhole, and become unreachable during GC.  The GC will
+   -- detect that it is unreachable and send it the NonTermination
+   -- exception.  However, since the thread is unreachable, everything
+   -- it refers to might be finalized, including the standard Handles.
+   -- This sounds like a bug, but we don't have a good solution right
+   -- now.
+   newStablePtr stdin
+   newStablePtr stdout
+   newStablePtr stderr
+
    hFlush stdout
    hSetBuffering stdout NoBuffering
 
    hFlush stdout
    hSetBuffering stdout NoBuffering
 
-   dflags <- getDynFlags
-
-   -- link in the available packages
-   pkgs <- getPackageInfo
-   initLinker
-   linkPackages dflags cmdline_libs pkgs
-
-   (cmstate, maybe_hval) 
-       <- cmCompileExpr cmstate dflags "IO.hSetBuffering IO.stdout IO.NoBuffering Prelude.>> IO.hSetBuffering IO.stderr IO.NoBuffering"
-   case maybe_hval of
-       Just hval -> unsafeCoerce# hval :: IO ()
-       _ -> panic "interactiveUI:buffering"
-
-   (cmstate, maybe_hval)
-       <- cmCompileExpr cmstate dflags "IO.hFlush IO.stderr"
-   case maybe_hval of
-       Just hval -> writeIORef flush_stderr (unsafeCoerce# hval :: IO ())
-       _ -> panic "interactiveUI:stderr"
-
-   (cmstate, maybe_hval) 
-       <- cmCompileExpr cmstate dflags "IO.hFlush IO.stdout"
-   case maybe_hval of
-       Just hval -> writeIORef flush_stdout (unsafeCoerce# hval :: IO ())
-       _ -> panic "interactiveUI:stdout"
+       -- Initialise buffering for the *interpreted* I/O system
+   initInterpBuffering session
 
        -- We don't want the cmd line to buffer any input that might be
        -- intended for the program, so unbuffer stdin.
 
        -- We don't want the cmd line to buffer any input that might be
        -- intended for the program, so unbuffer stdin.
-   hSetBuffering stdin  NoBuffering
+   hSetBuffering stdin NoBuffering
 
        -- initial context is just the Prelude
 
        -- initial context is just the Prelude
-   cmstate <- cmSetContext cmstate dflags [] ["Prelude"]
+   GHC.setContext session [] [prelude_mod]
 
 
-#if HAVE_READLINE_HEADERS && HAVE_READLINE_LIBS
+#ifdef USE_READLINE
    Readline.initialize
 #endif
 
    Readline.initialize
 #endif
 
-   startGHCi (runGHCi paths dflags) 
+   startGHCi (runGHCi srcs maybe_expr)
        GHCiState{ progname = "<interactive>",
                   args = [],
        GHCiState{ progname = "<interactive>",
                   args = [],
-                  targets = paths,
-                  cmstate = cmstate,
+                  session = session,
                   options = [] }
 
                   options = [] }
 
-#if HAVE_READLINE_HEADERS && HAVE_READLINE_LIBS
+#ifdef USE_READLINE
    Readline.resetTerminal Nothing
 #endif
 
    return ()
 
    Readline.resetTerminal Nothing
 #endif
 
    return ()
 
-
-runGHCi :: [FilePath] -> DynFlags -> GHCi ()
-runGHCi paths dflags = do
-  read_dot_files <- io (readIORef v_Read_DotGHCi)
+runGHCi :: [(FilePath, Maybe Phase)] -> Maybe String -> GHCi ()
+runGHCi paths maybe_expr = do
+  let read_dot_files = not opt_IgnoreDotGhci
 
   when (read_dot_files) $ do
     -- Read in ./.ghci.
 
   when (read_dot_files) $ do
     -- Read in ./.ghci.
@@ -237,32 +244,66 @@ runGHCi paths dflags = do
                  Left e    -> return ()
                  Right hdl -> fileLoop hdl False
 
                  Left e    -> return ()
                  Right hdl -> fileLoop hdl False
 
-  -- perform a :load for files given on the GHCi command line
-  when (not (null paths)) $
-     ghciHandle showException $
-       loadModule (unwords paths)
-
-  -- enter the interactive loop
+  -- Perform a :load for files given on the GHCi command line
+  -- When in -e mode, if the load fails then we want to stop
+  -- immediately rather than going on to evaluate the expression.
+  when (not (null paths)) $ do
+     ok <- ghciHandle (\e -> do showException e; return Failed) $ 
+               loadModule paths
+     when (isJust maybe_expr && failed ok) $
+       io (exitWith (ExitFailure 1))
+
+  -- if verbosity is greater than 0, or we are connected to a
+  -- terminal, display the prompt in the interactive loop.
   is_tty <- io (hIsTerminalDevice stdin)
   is_tty <- io (hIsTerminalDevice stdin)
-  interactiveLoop is_tty
+  dflags <- getDynFlags
+  let show_prompt = verbosity dflags > 0 || is_tty
+
+  case maybe_expr of
+       Nothing -> 
+#if defined(mingw32_HOST_OS)
+          do
+            -- The win32 Console API mutates the first character of 
+            -- type-ahead when reading from it in a non-buffered manner. Work
+            -- around this by flushing the input buffer of type-ahead characters,
+            -- but only if stdin is available.
+            flushed <- io (IO.try (GHC.ConsoleHandler.flushConsole stdin))
+            case flushed of 
+            Left err | isDoesNotExistError err -> return ()
+                     | otherwise -> io (ioError err)
+            Right () -> return ()
+#endif
+           -- enter the interactive loop
+           interactiveLoop is_tty show_prompt
+       Just expr -> do
+           -- just evaluate the expression we were given
+           runCommandEval expr
+           return ()
 
   -- and finally, exit
   io $ do when (verbosity dflags > 0) $ putStrLn "Leaving GHCi."
 
 
 
   -- and finally, exit
   io $ do when (verbosity dflags > 0) $ putStrLn "Leaving GHCi."
 
 
-interactiveLoop is_tty = do
-  -- ignore ^C exceptions caught here
+interactiveLoop is_tty show_prompt =
+  -- Ignore ^C exceptions caught here
   ghciHandleDyn (\e -> case e of 
   ghciHandleDyn (\e -> case e of 
-                       Interrupted -> ghciUnblock (interactiveLoop is_tty)
-                       _other      -> return ()) $ do
+                       Interrupted -> do
+#if defined(mingw32_HOST_OS)
+                               io (putStrLn "")
+#endif
+                               interactiveLoop is_tty show_prompt
+                       _other      -> return ()) $ 
+
+  ghciUnblock $ do -- unblock necessary if we recursed from the 
+                  -- exception handler above.
 
   -- read commands from stdin
 
   -- read commands from stdin
-#if HAVE_READLINE_HEADERS && HAVE_READLINE_LIBS
+#ifdef USE_READLINE
   if (is_tty) 
        then readlineLoop
   if (is_tty) 
        then readlineLoop
-       else fileLoop stdin False  -- turn off prompt for non-TTY input
+       else fileLoop stdin show_prompt
 #else
 #else
-  fileLoop stdin True
+  fileLoop stdin show_prompt
 #endif
 
 
 #endif
 
 
@@ -277,10 +318,10 @@ interactiveLoop is_tty = do
 
 checkPerms :: String -> IO Bool
 checkPerms name =
 
 checkPerms :: String -> IO Bool
 checkPerms name =
-#ifdef mingw32_TARGET_OS
+#ifdef mingw32_HOST_OS
   return True
 #else
   return True
 #else
-  DriverUtil.handle (\_ -> return False) $ do
+  Util.handle (\_ -> return False) $ do
      st <- getFileStatus name
      me <- getRealUserID
      if fileOwner st /= me then do
      st <- getFileStatus name
      me <- getRealUserID
      if fileOwner st /= me then do
@@ -299,15 +340,21 @@ checkPerms name =
 
 fileLoop :: Handle -> Bool -> GHCi ()
 fileLoop hdl prompt = do
 
 fileLoop :: Handle -> Bool -> GHCi ()
 fileLoop hdl prompt = do
-   cmstate <- getCmState
-   (mod,imports) <- io (cmGetContext cmstate)
+   session <- getSession
+   (mod,imports) <- io (GHC.getContext session)
    when prompt (io (putStr (mkPrompt mod imports)))
    l <- io (IO.try (hGetLine hdl))
    case l of
    when prompt (io (putStr (mkPrompt mod imports)))
    l <- io (IO.try (hGetLine hdl))
    case l of
-       Left e | isEOFError e -> return ()
-              | otherwise    -> throw e
+       Left e | isEOFError e              -> return ()
+              | InvalidArgument <- etype  -> return ()
+              | otherwise                 -> io (ioError e)
+               where etype = ioeGetErrorType e
+               -- treat InvalidArgument in the same way as EOF:
+               -- this can happen if the user closed stdin, or
+               -- perhaps did getContents which closes stdin at
+               -- EOF.
        Right l -> 
        Right l -> 
-         case remove_spaces l of
+         case removeSpaces l of
            "" -> fileLoop hdl prompt
            l  -> do quit <- runCommand l
                     if quit then return () else fileLoop hdl prompt
            "" -> fileLoop hdl prompt
            l  -> do quit <- runCommand l
                     if quit then return () else fileLoop hdl prompt
@@ -315,25 +362,30 @@ fileLoop hdl prompt = do
 stringLoop :: [String] -> GHCi ()
 stringLoop [] = return ()
 stringLoop (s:ss) = do
 stringLoop :: [String] -> GHCi ()
 stringLoop [] = return ()
 stringLoop (s:ss) = do
-   case remove_spaces s of
+   case removeSpaces s of
        "" -> stringLoop ss
        l  -> do quit <- runCommand l
                  if quit then return () else stringLoop ss
 
 mkPrompt toplevs exports
        "" -> stringLoop ss
        l  -> do quit <- runCommand l
                  if quit then return () else stringLoop ss
 
 mkPrompt toplevs exports
-   = concat (intersperse " " (map ('*':) toplevs ++ exports)) ++ "> "
+  = showSDoc (hsep (map (\m -> char '*' <> pprModule m) toplevs)
+            <+> hsep (map pprModule exports)
+            <> text "> ")
 
 
-#if HAVE_READLINE_HEADERS && HAVE_READLINE_LIBS
+#ifdef USE_READLINE
 readlineLoop :: GHCi ()
 readlineLoop = do
 readlineLoop :: GHCi ()
 readlineLoop = do
-   cmstate <- getCmState
-   (mod,imports) <- io (cmGetContext cmstate)
+   session <- getSession
+   (mod,imports) <- io (GHC.getContext session)
    io yield
    io yield
-   l <- io (readline (mkPrompt mod imports))
+   l <- io (readline (mkPrompt mod imports)
+               `finally` setNonBlockingFD 0)
+               -- readline sometimes puts stdin into blocking mode,
+               -- so we need to put it back for the IO library
    case l of
        Nothing -> return ()
        Just l  ->
    case l of
        Nothing -> return ()
        Just l  ->
-         case remove_spaces l of
+         case removeSpaces l of
            "" -> readlineLoop
            l  -> do
                  io (addHistory l)
            "" -> readlineLoop
            l  -> do
                  io (addHistory l)
@@ -341,16 +393,45 @@ readlineLoop = do
                  if quit then return () else readlineLoop
 #endif
 
                  if quit then return () else readlineLoop
 #endif
 
--- Top level exception handler, just prints out the exception 
--- and carries on.
 runCommand :: String -> GHCi Bool
 runCommand :: String -> GHCi Bool
-runCommand c = 
-  ghciHandle ( \exception -> do
-               flushEverything
-               showException exception
-               return False
-            ) $
-  doCommand c
+runCommand c = ghciHandle handler (doCommand c)
+  where 
+    doCommand (':' : command) = specialCommand command
+    doCommand stmt
+       = do timeIt (do nms <- runStmt stmt; finishEvalExpr nms)
+            return False
+
+-- This version is for the GHC command-line option -e.  The only difference
+-- from runCommand is that it catches the ExitException exception and
+-- exits, rather than printing out the exception.
+runCommandEval c = ghciHandle handleEval (doCommand c)
+  where 
+    handleEval (ExitException code) = io (exitWith code)
+    handleEval e                    = do showException e
+                                        io (exitWith (ExitFailure 1))
+
+    doCommand (':' : command) = specialCommand command
+    doCommand stmt
+       = do nms <- runStmt stmt
+           case nms of 
+               Nothing -> io (exitWith (ExitFailure 1))
+                 -- failure to run the command causes exit(1) for ghc -e.
+               _       -> finishEvalExpr nms
+
+-- This is the exception handler for exceptions generated by the
+-- user's code; it normally just prints out the exception.  The
+-- handler must be recursive, in case showing the exception causes
+-- more exceptions to be raised.
+--
+-- Bugfix: if the user closed stdout or stderr, the flushing will fail,
+-- raising another exception.  We therefore don't put the recursive
+-- handler arond the flushing operation, so if stderr is closed
+-- GHCi will just die gracefully rather than going into an infinite loop.
+handler :: Exception -> GHCi Bool
+handler exception = do
+  flushInterpBuffers
+  io installSignalHandlers
+  ghciHandle handler (showException exception >> return False)
 
 showException (DynException dyn) =
   case fromDynamic dyn of
 
 showException (DynException dyn) =
   case fromDynamic dyn of
@@ -363,66 +444,97 @@ showException (DynException dyn) =
 showException other_exception
   = io (putStrLn ("*** Exception: " ++ show other_exception))
 
 showException other_exception
   = io (putStrLn ("*** Exception: " ++ show other_exception))
 
-doCommand (':' : command) = specialCommand command
-doCommand stmt
-   = do timeIt (do nms <- runStmt stmt; finishEvalExpr nms)
-        return False
-
-runStmt :: String -> GHCi [Name]
+runStmt :: String -> GHCi (Maybe [Name])
 runStmt stmt
 runStmt stmt
- | null (filter (not.isSpace) stmt) = return []
+ | null (filter (not.isSpace) stmt) = return (Just [])
  | otherwise
  = do st <- getGHCiState
  | otherwise
  = do st <- getGHCiState
-      dflags <- io getDynFlags
-      let dflags' = dopt_unset dflags Opt_WarnUnusedBinds
-      (new_cmstate, result) <- 
-       io $ withProgName (progname st) $ withArgs (args st) $
-       cmRunStmt (cmstate st) dflags' stmt
-      setGHCiState st{cmstate = new_cmstate}
+      session <- getSession
+      result <- io $ withProgName (progname st) $ withArgs (args st) $
+                    GHC.runStmt session stmt
       case result of
       case result of
-       CmRunFailed      -> return []
-       CmRunException e -> showException e >> return []
-       CmRunOk names    -> return names
+       GHC.RunFailed      -> return Nothing
+       GHC.RunException e -> throw e  -- this is caught by runCommand(Eval)
+       GHC.RunOk names    -> return (Just names)
 
 -- possibly print the type and revert CAFs after evaluating an expression
 
 -- possibly print the type and revert CAFs after evaluating an expression
-finishEvalExpr names
+finishEvalExpr mb_names
  = do b <- isOptionSet ShowType
  = do b <- isOptionSet ShowType
-      cmstate <- getCmState
-      when b (mapM_ (showTypeOfName cmstate) names)
+      session <- getSession
+      case mb_names of
+       Nothing    -> return ()      
+       Just names -> when b (mapM_ (showTypeOfName session) names)
 
 
+      flushInterpBuffers
+      io installSignalHandlers
       b <- isOptionSet RevertCAFs
       io (when b revertCAFs)
       b <- isOptionSet RevertCAFs
       io (when b revertCAFs)
-      flushEverything
       return True
 
       return True
 
-showTypeOfName :: CmState -> Name -> GHCi ()
-showTypeOfName cmstate n
-   = do maybe_str <- io (cmTypeOfName cmstate n)
-       case maybe_str of
-         Nothing  -> return ()
-         Just str -> io (putStrLn (showSDoc (ppr n) ++ " :: " ++ str))
+showTypeOfName :: Session -> Name -> GHCi ()
+showTypeOfName session n
+   = do maybe_tything <- io (GHC.lookupName session n)
+       case maybe_tything of
+         Nothing    -> return ()
+         Just thing -> showTyThing thing
 
 
-flushEverything :: GHCi ()
-flushEverything
-   = io $ do Monad.join (readIORef flush_stdout)
-            Monad.join (readIORef flush_stderr)
-             return ()
+showForUser :: SDoc -> GHCi String
+showForUser doc = do
+  session <- getSession
+  unqual <- io (GHC.getPrintUnqual session)
+  return $! showSDocForUser unqual doc
 
 specialCommand :: String -> GHCi Bool
 specialCommand ('!':str) = shellEscape (dropWhile isSpace str)
 specialCommand str = do
   let (cmd,rest) = break isSpace str
   cmds <- io (readIORef commands)
 
 specialCommand :: String -> GHCi Bool
 specialCommand ('!':str) = shellEscape (dropWhile isSpace str)
 specialCommand str = do
   let (cmd,rest) = break isSpace str
   cmds <- io (readIORef commands)
-  case [ (s,f) | (s,f) <- cmds, prefixMatch cmd s ] of
-     []      -> io (hPutStr stdout ("unknown command `:" ++ cmd ++ "'\n" 
+  -- look for exact match first, then the first prefix match
+  case [ (s,f) | (s,f) <- cmds, cmd == s ] of
+     (_,f):_ -> f (dropWhile isSpace rest)
+     [] -> case [ (s,f) | (s,f) <- cmds, prefixMatch cmd s ] of
+               [] -> io (hPutStr stdout ("unknown command ':" ++ cmd ++ "'\n" 
                                    ++ shortHelpText) >> return False)
                                    ++ shortHelpText) >> return False)
-     [(_,f)] -> f (dropWhile isSpace rest)
-     cs      -> io (hPutStrLn stdout ("prefix " ++ cmd ++ 
-                                     " matches multiple commands (" ++ 
-                                      foldr1 (\a b -> a ++ ',':b) (map fst cs)
-                                        ++ ")") >> return False)
+               (_,f):_ -> f (dropWhile isSpace rest)
+
+-----------------------------------------------------------------------------
+-- To flush buffers for the *interpreted* computation we need
+-- to refer to *its* stdout/stderr handles
+
+GLOBAL_VAR(flush_interp,       error "no flush_interp", IO ())
+GLOBAL_VAR(turn_off_buffering, error "no flush_stdout", IO ())
+
+no_buf_cmd = "System.IO.hSetBuffering System.IO.stdout System.IO.NoBuffering" ++
+            " Prelude.>> System.IO.hSetBuffering System.IO.stderr System.IO.NoBuffering"
+flush_cmd  = "System.IO.hFlush System.IO.stdout Prelude.>> System.IO.hFlush IO.stderr"
+
+initInterpBuffering :: Session -> IO ()
+initInterpBuffering session
+ = do maybe_hval <- GHC.compileExpr session no_buf_cmd
+       
+      case maybe_hval of
+       Just hval -> writeIORef turn_off_buffering (unsafeCoerce# hval :: IO ())
+       other     -> panic "interactiveUI:setBuffering"
+       
+      maybe_hval <- GHC.compileExpr session flush_cmd
+      case maybe_hval of
+       Just hval -> writeIORef flush_interp (unsafeCoerce# hval :: IO ())
+       _         -> panic "interactiveUI:flush"
+
+      turnOffBuffering -- Turn it off right now
 
 
-noArgs c = throwDyn (CmdLineError ("command `" ++ c ++ "' takes no arguments"))
+      return ()
+
+
+flushInterpBuffers :: GHCi ()
+flushInterpBuffers
+ = io $ do Monad.join (readIORef flush_interp)
+           return ()
+
+turnOffBuffering :: IO ()
+turnOffBuffering
+ = do Monad.join (readIORef turn_off_buffering)
+      return ()
 
 -----------------------------------------------------------------------------
 -- Commands
 
 -----------------------------------------------------------------------------
 -- Commands
@@ -431,83 +543,71 @@ help :: String -> GHCi ()
 help _ = io (putStr helpText)
 
 info :: String -> GHCi ()
 help _ = io (putStr helpText)
 
 info :: String -> GHCi ()
-info "" = throwDyn (CmdLineError "syntax: `:i <thing-you-want-info-about>'")
-info s = do
-  let names = words s
-  init_cms <- getCmState
-  dflags <- io getDynFlags
-  let 
-    infoThings cms [] = return cms
-    infoThings cms (name:names) = do
-      (cms, stuff) <- io (cmInfoThing cms dflags name)
-      io (putStrLn (showSDocForUser unqual (
-           vcat (intersperse (text "") (map showThing stuff))))
-         )
-      infoThings cms names
-
-    unqual = cmGetPrintUnqual init_cms
-
-    showThing (ty_thing, fixity) 
-       = vcat [ text "-- " <> showTyThing ty_thing, 
-                showFixity fixity (getName ty_thing),
-                ppr (ifaceTyThing ty_thing) ]
-
-    showFixity fix name
-       | fix == defaultFixity = empty
-       | otherwise            = ppr fix <+> 
-                                (if isSymOcc (nameOccName name)
-                                       then ppr name
-                                       else char '`' <> ppr name <> char '`')
-
-    showTyThing (AClass cl)
-       = hcat [ppr cl, text " is a class", showSrcLoc (className cl)]
-    showTyThing (ATyCon ty)
-       | isPrimTyCon ty
-       = hcat [ppr ty, text " is a primitive type constructor"]
-       | otherwise
-       = hcat [ppr ty, text " is a type constructor", showSrcLoc (tyConName ty)]
-    showTyThing (AnId   id)
-       = hcat [ppr id, text " is a ", idDescr id, showSrcLoc (idName id)]
-
-    idDescr id
-       | isRecordSelector id = 
-               case tyConClass_maybe (fieldLabelTyCon (
-                               recordSelectorFieldLabel id)) of
-                       Nothing -> text "record selector"
-                       Just c  -> text "method in class " <> ppr c
-       | isDataConWrapId id  = text "data constructor"
-       | otherwise           = text "variable"
-
-       -- also print out the source location for home things
-    showSrcLoc name
-       | isHomePackageName name && isGoodSrcLoc loc
-       = hsep [ text ", defined at", ppr loc ]
-       | otherwise
-       = empty
-       where loc = nameSrcLoc name
-
-  cms <- infoThings init_cms names
-  setCmState cms
+info "" = throwDyn (CmdLineError "syntax: ':i <thing-you-want-info-about>'")
+info s  = do { let names = words s
+            ; session <- getSession
+            ; dflags <- getDynFlags
+            ; let exts = dopt Opt_GlasgowExts dflags
+            ; mapM_ (infoThing exts session) names }
+  where
+    infoThing exts session str = io $ do
+       names <- GHC.parseName session str
+       let filtered = filterOutChildren names
+       mb_stuffs <- mapM (GHC.getInfo session) filtered
+       unqual <- GHC.getPrintUnqual session
+       putStrLn (showSDocForUser unqual $
+                  vcat (intersperse (text "") $
+                  [ pprInfo exts stuff | Just stuff <-  mb_stuffs ]))
+
+  -- Filter out names whose parent is also there Good
+  -- example is '[]', which is both a type and data
+  -- constructor in the same type
+filterOutChildren :: [Name] -> [Name]
+filterOutChildren names = filter (not . parent_is_there) names
+ where parent_is_there n 
+        | Just p <- GHC.nameParent_maybe n = p `elem` names
+        | otherwise                       = False
+
+pprInfo exts (thing, fixity, insts)
+  =  pprTyThingInContextLoc exts thing 
+  $$ show_fixity fixity
+  $$ vcat (map GHC.pprInstance insts)
+  where
+    show_fixity fix 
+       | fix == GHC.defaultFixity = empty
+       | otherwise                = ppr fix <+> ppr (GHC.getName thing)
+
+-----------------------------------------------------------------------------
+-- Commands
+
+runMain :: String -> GHCi ()
+runMain args = do
+  let ss = concat $ intersperse "," (map (\ s -> ('"':s)++"\"") (toArgs args))
+  runCommand $ '[': ss ++ "] `System.Environment.withArgs` main"
   return ()
 
   return ()
 
-addModule :: String -> GHCi ()
-addModule str = do
-  let files = words str
-  state <- getGHCiState
-  dflags <- io (getDynFlags)
+addModule :: [FilePath] -> GHCi ()
+addModule files = do
   io (revertCAFs)                      -- always revert CAFs on load/add.
   io (revertCAFs)                      -- always revert CAFs on load/add.
-  let new_targets = files ++ targets state 
-  graph <- io (cmDepAnal (cmstate state) dflags new_targets)
-  (cmstate1, ok, mods) <- io (cmLoadModules (cmstate state) dflags graph)
-  setGHCiState state{ cmstate = cmstate1, targets = new_targets }
-  setContextAfterLoad mods
-  modulesLoadedMsg ok mods dflags
+  files <- mapM expandPath files
+  targets <- mapM (\m -> io (GHC.guessTarget m Nothing)) files
+  session <- getSession
+  io (mapM_ (GHC.addTarget session) targets)
+  ok <- io (GHC.load session LoadAllTargets)
+  afterLoad ok session
 
 changeDirectory :: String -> GHCi ()
 
 changeDirectory :: String -> GHCi ()
-changeDirectory ('~':d) = do
-   tilde <- io (getEnv "HOME") -- will fail if HOME not defined
-   io (setCurrentDirectory (tilde ++ '/':d))
-changeDirectory d = io (setCurrentDirectory d)
+changeDirectory dir = do
+  session <- getSession
+  graph <- io (GHC.getModuleGraph session)
+  when (not (null graph)) $
+       io $ putStr "Warning: changing directory causes all loaded modules to be unloaded,\nbecause the search path has changed.\n"
+  io (GHC.setTargets session [])
+  io (GHC.load session LoadAllTargets)
+  setContextAfterLoad session []
+  io (GHC.workingDirectoryChanged session)
+  dir <- expandPath dir
+  io (setCurrentDirectory dir)
 
 defineMacro :: String -> GHCi ()
 defineMacro s = do
 
 defineMacro :: String -> GHCi ()
 defineMacro s = do
@@ -518,7 +618,7 @@ defineMacro s = do
        else do
   if (macro_name `elem` map fst cmds) 
        then throwDyn (CmdLineError 
        else do
   if (macro_name `elem` map fst cmds) 
        then throwDyn (CmdLineError 
-               ("command `" ++ macro_name ++ "' is already defined"))
+               ("command '" ++ macro_name ++ "' is already defined"))
        else do
 
   -- give the expression a type signature, so we can be sure we're getting
        else do
 
   -- give the expression a type signature, so we can be sure we're getting
@@ -526,16 +626,14 @@ defineMacro s = do
   let new_expr = '(' : definition ++ ") :: String -> IO String"
 
   -- compile the expression
   let new_expr = '(' : definition ++ ") :: String -> IO String"
 
   -- compile the expression
-  cms <- getCmState
-  dflags <- io getDynFlags
-  (new_cmstate, maybe_hv) <- io (cmCompileExpr cms dflags new_expr)
-  setCmState new_cmstate
+  cms <- getSession
+  maybe_hv <- io (GHC.compileExpr cms new_expr)
   case maybe_hv of
      Nothing -> return ()
      Just hv -> io (writeIORef commands --
   case maybe_hv of
      Nothing -> return ()
      Just hv -> io (writeIORef commands --
-                   ((macro_name, keepGoing (runMacro hv)) : cmds))
+                   (cmds ++ [(macro_name, keepGoing (runMacro hv))]))
 
 
-runMacro :: HValue{-String -> IO String-} -> String -> GHCi ()
+runMacro :: GHC.HValue{-String -> IO String-} -> String -> GHCi ()
 runMacro fun s = do
   str <- io ((unsafeCoerce# fun :: String -> IO String) s)
   stringLoop (lines str)
 runMacro fun s = do
   str <- io ((unsafeCoerce# fun :: String -> IO String) s)
   stringLoop (lines str)
@@ -545,87 +643,145 @@ undefineMacro macro_name = do
   cmds <- io (readIORef commands)
   if (macro_name `elem` map fst builtin_commands) 
        then throwDyn (CmdLineError
   cmds <- io (readIORef commands)
   if (macro_name `elem` map fst builtin_commands) 
        then throwDyn (CmdLineError
-               ("command `" ++ macro_name ++ "' cannot be undefined"))
+               ("command '" ++ macro_name ++ "' cannot be undefined"))
        else do
   if (macro_name `notElem` map fst cmds) 
        then throwDyn (CmdLineError 
        else do
   if (macro_name `notElem` map fst cmds) 
        then throwDyn (CmdLineError 
-               ("command `" ++ macro_name ++ "' not defined"))
+               ("command '" ++ macro_name ++ "' not defined"))
        else do
   io (writeIORef commands (filter ((/= macro_name) . fst) cmds))
 
 
        else do
   io (writeIORef commands (filter ((/= macro_name) . fst) cmds))
 
 
-loadModule :: String -> GHCi ()
-loadModule str = timeIt (loadModule' str)
-
-loadModule' str = do
-  let files = words str
-  state <- getGHCiState
-  dflags <- io getDynFlags
-
-  -- do the dependency anal first, so that if it fails we don't throw
-  -- away the current set of modules.
-  graph <- io (cmDepAnal (cmstate state) dflags files)
-
-  -- Dependency anal ok, now unload everything
-  cmstate1 <- io (cmUnload (cmstate state) dflags)
-  setGHCiState state{ cmstate = cmstate1, targets = [] }
-
-  io (revertCAFs)  -- always revert CAFs on load.
-  (cmstate2, ok, mods) <- io (cmLoadModules cmstate1 dflags graph)
-  setGHCiState state{ cmstate = cmstate2, targets = files }
-
-  setContextAfterLoad mods
-  modulesLoadedMsg ok mods dflags
-
+loadModule :: [(FilePath, Maybe Phase)] -> GHCi SuccessFlag
+loadModule fs = timeIt (loadModule' fs)
+
+loadModule_ :: [FilePath] -> GHCi ()
+loadModule_ fs = do loadModule (zip fs (repeat Nothing)); return ()
+
+loadModule' :: [(FilePath, Maybe Phase)] -> GHCi SuccessFlag
+loadModule' files = do
+  session <- getSession
+
+  -- unload first
+  io (GHC.setTargets session [])
+  io (GHC.load session LoadAllTargets)
+
+  -- expand tildes
+  let (filenames, phases) = unzip files
+  exp_filenames <- mapM expandPath filenames
+  let files' = zip exp_filenames phases
+  targets <- io (mapM (uncurry GHC.guessTarget) files')
+
+  -- NOTE: we used to do the dependency anal first, so that if it
+  -- fails we didn't throw away the current set of modules.  This would
+  -- require some re-working of the GHC interface, so we'll leave it
+  -- as a ToDo for now.
+
+  io (GHC.setTargets session targets)
+  ok <- io (GHC.load session LoadAllTargets)
+  afterLoad ok session
+  return ok
+
+checkModule :: String -> GHCi ()
+checkModule m = do
+  let modl = mkModule m
+  session <- getSession
+  result <- io (GHC.checkModule session modl)
+  case result of
+    Nothing -> io $ putStrLn "Nothing"
+    Just r  -> io $ putStrLn (showSDoc (
+       case checkedModuleInfo r of
+          Just cm | Just scope <- GHC.modInfoTopLevelScope cm -> 
+               let
+                   (local,global) = partition ((== modl) . GHC.nameModule) scope
+               in
+                       (text "global names: " <+> ppr global) $$
+                       (text "local  names: " <+> ppr local)
+          _ -> empty))
+  afterLoad (successIf (isJust result)) session
 
 reloadModule :: String -> GHCi ()
 reloadModule "" = do
 
 reloadModule :: String -> GHCi ()
 reloadModule "" = do
-  state <- getGHCiState
-  dflags <- io getDynFlags
-  case targets state of
-   [] -> io (putStr "no current target\n")
-   paths -> do
-       -- do the dependency anal first, so that if it fails we don't throw
-       -- away the current set of modules.
-       graph <- io (cmDepAnal (cmstate state) dflags paths)
-
-       io (revertCAFs)         -- always revert CAFs on reload.
-       (cmstate1, ok, mods) 
-               <- io (cmLoadModules (cmstate state) dflags graph)
-        setGHCiState state{ cmstate=cmstate1 }
-       setContextAfterLoad mods
-       modulesLoadedMsg ok mods dflags
-
-reloadModule _ = noArgs ":reload"
-
-setContextAfterLoad [] = setContext prel
-setContextAfterLoad (m:_) = do
-  cmstate <- getCmState
-  b <- io (cmModuleIsInterpreted cmstate m)
-  if b then setContext ('*':m) else setContext m
-
-modulesLoadedMsg ok mods dflags =
+  io (revertCAFs)              -- always revert CAFs on reload.
+  session <- getSession
+  ok <- io (GHC.load session LoadAllTargets)
+  afterLoad ok session
+reloadModule m = do
+  io (revertCAFs)              -- always revert CAFs on reload.
+  session <- getSession
+  ok <- io (GHC.load session (LoadUpTo (mkModule m)))
+  afterLoad ok session
+
+afterLoad ok session = do
+  io (revertCAFs)  -- always revert CAFs on load.
+  graph <- io (GHC.getModuleGraph session)
+  graph' <- filterM (io . GHC.isLoaded session . GHC.ms_mod) graph
+  setContextAfterLoad session graph'
+  modulesLoadedMsg ok (map GHC.ms_mod graph')
+
+setContextAfterLoad session [] = do
+  io (GHC.setContext session [] [prelude_mod])
+setContextAfterLoad session ms = do
+  -- load a target if one is available, otherwise load the topmost module.
+  targets <- io (GHC.getTargets session)
+  case [ m | Just m <- map (findTarget ms) targets ] of
+       []    -> 
+         let graph' = flattenSCCs (GHC.topSortModuleGraph True ms Nothing) in
+         load_this (last graph')         
+       (m:_) -> 
+         load_this m
+ where
+   findTarget ms t
+    = case filter (`matches` t) ms of
+       []    -> Nothing
+       (m:_) -> Just m
+
+   summary `matches` Target (TargetModule m) _
+       = GHC.ms_mod summary == m
+   summary `matches` Target (TargetFile f _) _ 
+       | Just f' <- GHC.ml_hs_file (GHC.ms_location summary)   = f == f'
+   summary `matches` target
+       = False
+
+   load_this summary | m <- GHC.ms_mod summary = do
+       b <- io (GHC.moduleIsInterpreted session m)
+       if b then io (GHC.setContext session [m] []) 
+                    else io (GHC.setContext session []  [prelude_mod,m])
+
+
+modulesLoadedMsg :: SuccessFlag -> [Module] -> GHCi ()
+modulesLoadedMsg ok mods = do
+  dflags <- getDynFlags
   when (verbosity dflags > 0) $ do
    let mod_commas 
        | null mods = text "none."
        | otherwise = hsep (
   when (verbosity dflags > 0) $ do
    let mod_commas 
        | null mods = text "none."
        | otherwise = hsep (
-           punctuate comma (map text mods)) <> text "."
+           punctuate comma (map pprModule mods)) <> text "."
    case ok of
    case ok of
-    False ->
+    Failed ->
        io (putStrLn (showSDoc (text "Failed, modules loaded: " <> mod_commas)))
        io (putStrLn (showSDoc (text "Failed, modules loaded: " <> mod_commas)))
-    True  ->
+    Succeeded  ->
        io (putStrLn (showSDoc (text "Ok, modules loaded: " <> mod_commas)))
 
 
 typeOfExpr :: String -> GHCi ()
 typeOfExpr str 
        io (putStrLn (showSDoc (text "Ok, modules loaded: " <> mod_commas)))
 
 
 typeOfExpr :: String -> GHCi ()
 typeOfExpr str 
-  = do cms <- getCmState
-       dflags <- io getDynFlags
-       (new_cmstate, maybe_tystr) <- io (cmTypeOfExpr cms dflags str)
-       setCmState new_cmstate
-       case maybe_tystr of
+  = do cms <- getSession
+       maybe_ty <- io (GHC.exprType cms str)
+       case maybe_ty of
+         Nothing -> return ()
+         Just ty -> do ty' <- cleanType ty
+                       tystr <- showForUser (ppr ty')
+                       io (putStrLn (str ++ " :: " ++ tystr))
+
+kindOfType :: String -> GHCi ()
+kindOfType str 
+  = do cms <- getSession
+       maybe_ty <- io (GHC.typeKind cms str)
+       case maybe_ty of
          Nothing    -> return ()
          Nothing    -> return ()
-         Just tystr -> io (putStrLn tystr)
+         Just ty    -> do tystr <- showForUser (ppr ty)
+                          io (putStrLn (str ++ " :: " ++ tystr))
 
 quit :: String -> GHCi Bool
 quit _ = return True
 
 quit :: String -> GHCi Bool
 quit _ = return True
@@ -634,7 +790,118 @@ shellEscape :: String -> GHCi Bool
 shellEscape str = io (system str >> return False)
 
 -----------------------------------------------------------------------------
 shellEscape str = io (system str >> return False)
 
 -----------------------------------------------------------------------------
--- Browing a module's contents
+-- create tags file for currently loaded modules.
+
+createETagsFileCmd, createCTagsFileCmd :: String -> GHCi ()
+
+createCTagsFileCmd ""   = ghciCreateTagsFile CTags "tags"
+createCTagsFileCmd file = ghciCreateTagsFile CTags file
+
+createETagsFileCmd ""    = ghciCreateTagsFile ETags "TAGS"
+createETagsFileCmd file  = ghciCreateTagsFile ETags file
+
+data TagsKind = ETags | CTags
+
+ghciCreateTagsFile :: TagsKind -> FilePath -> GHCi ()
+ghciCreateTagsFile kind file = do
+  session <- getSession
+  io $ createTagsFile session kind file
+
+-- ToDo: 
+--     - remove restriction that all modules must be interpreted
+--       (problem: we don't know source locations for entities unless
+--       we compiled the module.
+--
+--     - extract createTagsFile so it can be used from the command-line
+--       (probably need to fix first problem before this is useful).
+--
+createTagsFile :: Session -> TagsKind -> FilePath -> IO ()
+createTagsFile session tagskind tagFile = do
+  graph <- GHC.getModuleGraph session
+  let ms = map GHC.ms_mod graph
+      tagModule m = do 
+        is_interpreted <- GHC.moduleIsInterpreted session m
+        -- should we just skip these?
+        when (not is_interpreted) $
+          throwDyn (CmdLineError ("module '" ++ moduleString m ++ "' is not interpreted"))
+
+        mbModInfo <- GHC.getModuleInfo session m
+        let unqual 
+             | Just modinfo <- mbModInfo,
+               Just unqual <- GHC.modInfoPrintUnqualified modinfo = unqual
+             | otherwise = GHC.alwaysQualify
+
+        case mbModInfo of 
+          Just modInfo -> return $! listTags unqual modInfo 
+          _            -> return []
+
+  mtags <- mapM tagModule ms
+  either_res <- collateAndWriteTags tagskind tagFile $ concat mtags
+  case either_res of
+    Left e  -> hPutStrLn stderr $ ioeGetErrorString e
+    Right _ -> return ()
+
+listTags :: PrintUnqualified -> GHC.ModuleInfo -> [TagInfo]
+listTags unqual modInfo =
+          [ tagInfo unqual name loc 
+           | name <- GHC.modInfoExports modInfo
+           , let loc = nameSrcLoc name
+           , isGoodSrcLoc loc
+           ]
+
+type TagInfo = (String -- tag name
+               ,String -- file name
+               ,Int    -- line number
+               ,Int    -- column number
+               )
+
+-- get tag info, for later translation into Vim or Emacs style
+tagInfo :: PrintUnqualified -> Name -> SrcLoc -> TagInfo
+tagInfo unqual name loc
+    = ( showSDocForUser unqual $ pprOccName (nameOccName name)
+      , showSDocForUser unqual $ ftext (srcLocFile loc)
+      , srcLocLine loc
+      , srcLocCol loc
+      )
+
+collateAndWriteTags :: TagsKind -> FilePath -> [TagInfo] -> IO (Either IOError ())
+collateAndWriteTags CTags file tagInfos = do -- ctags style, Vim et al
+  let tags = unlines $ sortLe (<=) $ nub $ map showTag tagInfos
+  IO.try (writeFile file tags)
+collateAndWriteTags ETags file tagInfos = do -- etags style, Emacs/XEmacs
+  let byFile op (_,f1,_,_) (_,f2,_,_) = f1 `op` f2
+      groups = groupBy (byFile (==)) $ sortLe (byFile (<=)) tagInfos
+  tagGroups <- mapM tagFileGroup groups 
+  IO.try (writeFile file $ concat tagGroups)
+  where
+    tagFileGroup group@[] = throwDyn (CmdLineError "empty tag file group??")
+    tagFileGroup group@((_,fileName,_,_):_) = do
+      file <- readFile fileName -- need to get additional info from sources..
+      let byLine (_,_,l1,_) (_,_,l2,_) = l1 <= l2
+          sortedGroup = sortLe byLine group
+          tags = unlines $ perFile sortedGroup 1 0 $ lines file
+      return $ "\x0c\n" ++ fileName ++ "," ++ show (length tags) ++ "\n" ++ tags
+    perFile (tagInfo@(tag,file,lNo,colNo):tags) count pos (line:lines) | lNo>count =
+      perFile (tagInfo:tags) (count+1) (pos+length line) lines
+    perFile (tagInfo@(tag,file,lNo,colNo):tags) count pos lines@(line:_) | lNo==count =
+      showETag tagInfo line pos : perFile tags count pos lines
+    perFile tags count pos lines = []
+
+-- simple ctags format, for Vim et al
+showTag :: TagInfo -> String
+showTag (tag,file,lineNo,colNo)
+    =  tag ++ "\t" ++ file ++ "\t" ++ show lineNo
+
+-- etags format, for Emacs/XEmacs
+showETag :: TagInfo -> String -> Int -> String
+showETag (tag,file,lineNo,colNo) line charPos
+    =  take colNo line ++ tag
+    ++ "\x7f" ++ tag
+    ++ "\x01" ++ show lineNo
+    ++ "," ++ show charPos
+
+-----------------------------------------------------------------------------
+-- Browsing a module's contents
 
 browseCmd :: String -> GHCi ()
 browseCmd m = 
 
 browseCmd :: String -> GHCi ()
 browseCmd m = 
@@ -644,58 +911,41 @@ browseCmd m =
     _ -> throwDyn (CmdLineError "syntax:  :browse <module>")
 
 browseModule m exports_only = do
     _ -> throwDyn (CmdLineError "syntax:  :browse <module>")
 
 browseModule m exports_only = do
-  cms <- getCmState
-  dflags <- io getDynFlags
+  s <- getSession
 
 
-  is_interpreted <- io (cmModuleIsInterpreted cms m)
+  let modl = mkModule m
+  is_interpreted <- io (GHC.moduleIsInterpreted s modl)
   when (not is_interpreted && not exports_only) $
   when (not is_interpreted && not exports_only) $
-       throwDyn (CmdLineError ("module `" ++ m ++ "' is not interpreted"))
+       throwDyn (CmdLineError ("module '" ++ m ++ "' is not interpreted"))
 
 
-  -- temporarily set the context to the module we're interested in,
+  -- Temporarily set the context to the module we're interested in,
   -- just so we can get an appropriate PrintUnqualified
   -- just so we can get an appropriate PrintUnqualified
-  (as,bs) <- io (cmGetContext cms)
-  cms1 <- io (if exports_only then cmSetContext cms dflags [] [prel,m]
-                             else cmSetContext cms dflags [m] [])
-  cms2 <- io (cmSetContext cms1 dflags as bs)
-
-  (cms3, things) <- io (cmBrowseModule cms2 dflags m exports_only)
-
-  setCmState cms3
-
-  let unqual = cmGetPrintUnqual cms1 -- NOTE: cms1 with the new context
-
-      things' = filter wantToSee things
-
-      wantToSee (AnId id) = not (isDataConId id || isDataConWrapId id)
-      wantToSee _ = True
-
-      thing_names = map getName things
-
-      thingDecl thing@(AnId id)  = ifaceTyThing thing
-
-      thingDecl thing@(AClass c) =
-        let rn_decl = ifaceTyThing thing in
-       case rn_decl of
-         ClassDecl { tcdSigs = cons } -> 
-               rn_decl{ tcdSigs = filter methodIsVisible cons }
-         other -> other
-        where
-           methodIsVisible (ClassOpSig n _ _ _) = n `elem` thing_names
-
-      thingDecl thing@(ATyCon t) =
-        let rn_decl = ifaceTyThing thing in
-       case rn_decl of
-         TyData { tcdCons = DataCons cons } -> 
-               rn_decl{ tcdCons = DataCons (filter conIsVisible cons) }
-         other -> other
-        where
-         conIsVisible (ConDecl n _ _ _ _ _) = n `elem` thing_names
-
-  io (putStrLn (showSDocForUser unqual (
-        vcat (map (ppr . thingDecl) things')))
-   )
+  (as,bs) <- io (GHC.getContext s)
+  io (if exports_only then GHC.setContext s [] [prelude_mod,modl]
+                     else GHC.setContext s [modl] [])
+  unqual <- io (GHC.getPrintUnqual s)
+  io (GHC.setContext s as bs)
+
+  mb_mod_info <- io $ GHC.getModuleInfo s modl
+  case mb_mod_info of
+    Nothing -> throwDyn (CmdLineError ("unknown module: " ++ m))
+    Just mod_info -> do
+        let names
+              | exports_only = GHC.modInfoExports mod_info
+              | otherwise    = fromMaybe [] (GHC.modInfoTopLevelScope mod_info)
+
+           filtered = filterOutChildren names
+       
+        things <- io $ mapM (GHC.lookupName s) filtered
 
 
-  where
+        dflags <- getDynFlags
+       let exts = dopt Opt_GlasgowExts dflags
+       io (putStrLn (showSDocForUser unqual (
+               vcat (map (pprTyThingInContext exts) (catMaybes things))
+          )))
+       -- ToDo: modInfoInstances currently throws an exception for
+       -- package modules.  When it works, we can do this:
+       --      $$ vcat (map GHC.pprInstance (GHC.modInfoInstances mod_info))
 
 -----------------------------------------------------------------------------
 -- Setting the module context
 
 -----------------------------------------------------------------------------
 -- Setting the module context
@@ -713,50 +963,46 @@ setContext str
     sensible m       = looksLikeModuleName m
 
 newContext mods = do
     sensible m       = looksLikeModuleName m
 
 newContext mods = do
-  cms <- getCmState
-  dflags <- io getDynFlags
-  (as,bs) <- separate cms mods [] []
-  let bs' = if null as && prel `notElem` bs then prel:bs else bs
-  cms' <- io (cmSetContext cms dflags as bs')
-  setCmState cms'
+  session <- getSession
+  (as,bs) <- separate session mods [] []
+  let bs' = if null as && prelude_mod `notElem` bs then prelude_mod:bs else bs
+  io (GHC.setContext session as bs')
 
 
-separate cmstate []           as bs = return (as,bs)
-separate cmstate (('*':m):ms) as bs = do
-   b <- io (cmModuleIsInterpreted cmstate m)
-   if b then separate cmstate ms (m:as) bs
-       else throwDyn (CmdLineError ("module `" ++ m ++ "' is not interpreted"))
-separate cmstate (m:ms)       as bs = separate cmstate ms as (m:bs)
+separate :: Session -> [String] -> [Module] -> [Module]
+  -> GHCi ([Module],[Module])
+separate session []           as bs = return (as,bs)
+separate session (('*':m):ms) as bs = do
+   let modl = mkModule m
+   b <- io (GHC.moduleIsInterpreted session modl)
+   if b then separate session ms (modl:as) bs
+       else throwDyn (CmdLineError ("module '" ++ m ++ "' is not interpreted"))
+separate session (m:ms)       as bs = separate session ms as (mkModule m:bs)
 
 
-prel = "Prelude"
+prelude_mod = mkModule "Prelude"
 
 
 addToContext mods = do
 
 
 addToContext mods = do
-  cms <- getCmState
-  dflags <- io getDynFlags
-  (as,bs) <- io (cmGetContext cms)
+  cms <- getSession
+  (as,bs) <- io (GHC.getContext cms)
 
   (as',bs') <- separate cms mods [] []
 
   let as_to_add = as' \\ (as ++ bs)
       bs_to_add = bs' \\ (as ++ bs)
 
 
   (as',bs') <- separate cms mods [] []
 
   let as_to_add = as' \\ (as ++ bs)
       bs_to_add = bs' \\ (as ++ bs)
 
-  cms' <- io (cmSetContext cms dflags 
-                       (as ++ as_to_add) (bs ++ bs_to_add))
-  setCmState cms'
+  io (GHC.setContext cms (as ++ as_to_add) (bs ++ bs_to_add))
 
 
 removeFromContext mods = do
 
 
 removeFromContext mods = do
-  cms <- getCmState
-  dflags <- io getDynFlags
-  (as,bs) <- io (cmGetContext cms)
+  cms <- getSession
+  (as,bs) <- io (GHC.getContext cms)
 
   (as_to_remove,bs_to_remove) <- separate cms mods [] []
 
   let as' = as \\ (as_to_remove ++ bs_to_remove)
       bs' = bs \\ (as_to_remove ++ bs_to_remove)
 
 
   (as_to_remove,bs_to_remove) <- separate cms mods [] []
 
   let as' = as \\ (as_to_remove ++ bs_to_remove)
       bs' = bs \\ (as_to_remove ++ bs_to_remove)
 
-  cms' <- io (cmSetContext cms dflags as' bs')
-  setCmState cms'
+  io (GHC.setContext cms as' bs')
 
 ----------------------------------------------------------------------------
 -- Code for `:set'
 
 ----------------------------------------------------------------------------
 -- Code for `:set'
@@ -799,22 +1045,19 @@ setOptions wds =
       let (plus_opts, minus_opts)  = partition isPlus wds
       mapM_ setOpt plus_opts
 
       let (plus_opts, minus_opts)  = partition isPlus wds
       mapM_ setOpt plus_opts
 
-      -- now, the GHC flags
-      pkgs_before <- io (readIORef v_Packages)
-      leftovers   <- io (processArgs static_flags minus_opts [])
-      pkgs_after  <- io (readIORef v_Packages)
-
-      -- update things if the users wants more packages
-      when (pkgs_before /= pkgs_after) $
-        newPackages (pkgs_after \\ pkgs_before)
-
       -- then, dynamic flags
       -- then, dynamic flags
-      io $ do 
-       restoreDynFlags
-        leftovers <- processArgs dynamic_flags leftovers []
-       saveDynFlags
-
-        if (not (null leftovers))
+      dflags <- getDynFlags
+      (dflags',leftovers) <- io $ GHC.parseDynamicFlags dflags minus_opts
+      setDynFlags dflags'
+
+        -- update things if the users wants more packages
+{- TODO:
+        let new_packages = pkgs_after \\ pkgs_before
+        when (not (null new_packages)) $
+          newPackages new_packages
+-}
+
+      if (not (null leftovers))
                then throwDyn (CmdLineError ("unrecognised flags: " ++ 
                                                unwords leftovers))
                else return ()
                then throwDyn (CmdLineError ("unrecognised flags: " ++ 
                                                unwords leftovers))
                else return ()
@@ -828,7 +1071,7 @@ unsetOptions str
           (plus_opts, rest2)  = partition isPlus rest1
 
        if (not (null rest2)) 
           (plus_opts, rest2)  = partition isPlus rest1
 
        if (not (null rest2)) 
-         then io (putStrLn ("unknown option: `" ++ head rest2 ++ "'"))
+         then io (putStrLn ("unknown option: '" ++ head rest2 ++ "'"))
          else do
 
        mapM_ unsetOpt plus_opts
          else do
 
        mapM_ unsetOpt plus_opts
@@ -846,12 +1089,12 @@ isPlus _ = False
 
 setOpt ('+':str)
   = case strToGHCiOpt str of
 
 setOpt ('+':str)
   = case strToGHCiOpt str of
-       Nothing -> io (putStrLn ("unknown option: `" ++ str ++ "'"))
+       Nothing -> io (putStrLn ("unknown option: '" ++ str ++ "'"))
        Just o  -> setOption o
 
 unsetOpt ('+':str)
   = case strToGHCiOpt str of
        Just o  -> setOption o
 
 unsetOpt ('+':str)
   = case strToGHCiOpt str of
-       Nothing -> io (putStrLn ("unknown option: `" ++ str ++ "'"))
+       Nothing -> io (putStrLn ("unknown option: '" ++ str ++ "'"))
        Just o  -> unsetOption o
 
 strToGHCiOpt :: String -> (Maybe GHCiOption)
        Just o  -> unsetOption o
 
 strToGHCiOpt :: String -> (Maybe GHCiOption)
@@ -865,51 +1108,54 @@ optToStr ShowTiming = "s"
 optToStr ShowType   = "t"
 optToStr RevertCAFs = "r"
 
 optToStr ShowType   = "t"
 optToStr RevertCAFs = "r"
 
-newPackages new_pkgs = do
-  state <- getGHCiState
-  dflags <- io getDynFlags
-  cmstate1 <- io (cmUnload (cmstate state) dflags)
-  setGHCiState state{ cmstate = cmstate1, targets = [] }
-
-  io $ do
-    pkgs <- getPackageInfo
-    flushPackageCache pkgs
-   
-    new_pkg_info <- getPackageDetails new_pkgs
-    mapM_ (linkPackage dflags) (reverse new_pkg_info)
-
------------------------------------------------------------------------------
+{- ToDo
+newPackages new_pkgs = do      -- The new packages are already in v_Packages
+  session <- getSession
+  io (GHC.setTargets session [])
+  io (GHC.load session Nothing)
+  dflags   <- getDynFlags
+  io (linkPackages dflags new_pkgs)
+  setContextAfterLoad []
+-}
+
+-- ---------------------------------------------------------------------------
 -- code for `:show'
 
 showCmd str =
   case words str of
        ["modules" ] -> showModules
        ["bindings"] -> showBindings
 -- code for `:show'
 
 showCmd str =
   case words str of
        ["modules" ] -> showModules
        ["bindings"] -> showBindings
+       ["linker"]   -> io showLinkerState
        _ -> throwDyn (CmdLineError "syntax:  :show [modules|bindings]")
 
 showModules = do
        _ -> throwDyn (CmdLineError "syntax:  :show [modules|bindings]")
 
 showModules = do
-  cms <- getCmState
-  let mg = cmGetModuleGraph cms
-      ls = cmGetLinkables   cms
-      maybe_linkables = map (findModuleLinkable_maybe ls) 
-                               (map (moduleName.ms_mod) mg)
-  zipWithM showModule mg maybe_linkables
-  return ()
-
-showModule :: ModSummary -> Maybe Linkable -> GHCi ()
-showModule m (Just l) = do
-  io (putStrLn (showModMsg (isObjectLinkable l) (ms_mod m) (ms_location m)))
-showModule _ Nothing = panic "missing linkable"
+  session <- getSession
+  let show_one ms = do m <- io (GHC.showModule session ms)
+                      io (putStrLn m)
+  graph <- io (GHC.getModuleGraph session)
+  mapM_ show_one graph
 
 showBindings = do
 
 showBindings = do
-  cms <- getCmState
-  let
-       unqual = cmGetPrintUnqual cms
-       showBinding b = putStrLn (showSDocForUser unqual (ppr (ifaceTyThing b)))
-
-  io (mapM_ showBinding (cmGetBindings cms))
+  s <- getSession
+  unqual <- io (GHC.getPrintUnqual s)
+  bindings <- io (GHC.getBindings s)
+  mapM_ showTyThing bindings
   return ()
 
   return ()
 
+showTyThing (AnId id) = do 
+  ty' <- cleanType (GHC.idType id)
+  str <- showForUser (ppr id <> text " :: " <> ppr ty')
+  io (putStrLn str)
+showTyThing _  = return ()
+
+-- if -fglasgow-exts is on we show the foralls, otherwise we don't.
+cleanType :: Type -> GHCi Type
+cleanType ty = do
+  dflags <- getDynFlags
+  if dopt Opt_GlasgowExts dflags 
+       then return ty
+       else return $! GHC.dropForAlls ty
+
 -----------------------------------------------------------------------------
 -- GHCi monad
 
 -----------------------------------------------------------------------------
 -- GHCi monad
 
@@ -917,8 +1163,7 @@ data GHCiState = GHCiState
      { 
        progname       :: String,
        args           :: [String],
      { 
        progname       :: String,
        args           :: [String],
-       targets        :: [FilePath],
-       cmstate        :: CmState,
+       session        :: GHC.Session,
        options        :: [GHCiOption]
      }
 
        options        :: [GHCiOption]
      }
 
@@ -928,9 +1173,6 @@ data GHCiOption
        | RevertCAFs            -- revert CAFs after every evaluation
        deriving Eq
 
        | RevertCAFs            -- revert CAFs after every evaluation
        deriving Eq
 
-GLOBAL_VAR(flush_stdout, error "no flush_stdout", IO ())
-GLOBAL_VAR(flush_stderr, error "no flush_stdout", IO ())
-
 newtype GHCi a = GHCi { unGHCi :: IORef GHCiState -> IO a }
 
 startGHCi :: GHCi a -> GHCiState -> IO a
 newtype GHCi a = GHCi { unGHCi :: IORef GHCiState -> IO a }
 
 startGHCi :: GHCi a -> GHCiState -> IO a
@@ -948,8 +1190,14 @@ getGHCiState   = GHCi $ \r -> readIORef r
 setGHCiState s = GHCi $ \r -> writeIORef r s
 
 -- for convenience...
 setGHCiState s = GHCi $ \r -> writeIORef r s
 
 -- for convenience...
-getCmState = getGHCiState >>= return . cmstate
-setCmState cms = do s <- getGHCiState; setGHCiState s{cmstate=cms}
+getSession = getGHCiState >>= return . session
+
+getDynFlags = do
+  s <- getSession
+  io (GHC.getSessionDynFlags s)
+setDynFlags dflags = do 
+  s <- getSession 
+  io (GHC.setSessionDynFlags s dflags)
 
 isOptionSet :: GHCiOption -> GHCi Bool
 isOptionSet opt
 
 isOptionSet :: GHCiOption -> GHCi Bool
 isOptionSet opt
@@ -979,225 +1227,12 @@ io m = GHCi { unGHCi = \s -> m >>= return }
 ghciHandle :: (Exception -> GHCi a) -> GHCi a -> GHCi a
 ghciHandle h (GHCi m) = GHCi $ \s -> 
    Exception.catch (m s) 
 ghciHandle :: (Exception -> GHCi a) -> GHCi a -> GHCi a
 ghciHandle h (GHCi m) = GHCi $ \s -> 
    Exception.catch (m s) 
-       (\e -> unGHCi (ghciHandle h (ghciUnblock (h e))) s)
+       (\e -> unGHCi (ghciUnblock (h e)) s)
 
 ghciUnblock :: GHCi a -> GHCi a
 ghciUnblock (GHCi a) = GHCi $ \s -> Exception.unblock (a s)
 
 -----------------------------------------------------------------------------
 
 ghciUnblock :: GHCi a -> GHCi a
 ghciUnblock (GHCi a) = GHCi $ \s -> Exception.unblock (a s)
 
 -----------------------------------------------------------------------------
--- package loader
-
--- Left: full path name of a .o file, including trailing .o
--- Right: "unadorned" name of a .DLL/.so
---        e.g.    On unix     "qt"  denotes "libqt.so"
---                On WinDoze  "burble"  denotes "burble.DLL"
---        addDLL is platform-specific and adds the lib/.so/.DLL
---        suffixes platform-dependently; we don't do that here.
--- 
--- For dynamic objects only, try to find the object file in all the 
--- directories specified in v_Library_Paths before giving up.
-
-data LibrarySpec = Object FilePath | DLL String
-#ifdef darwin_TARGET_OS
-                   | Framework String
-#endif
-
--- Packages that don't need loading, because the compiler shares them with
--- the interpreted program.
-dont_load_these = [ "rts" ]
-
--- Packages that are already linked into GHCi.  For mingw32, we only
--- skip gmp and rts, since std and after need to load the msvcrt.dll
--- library which std depends on.
-loaded_in_ghci
-#          ifndef mingw32_TARGET_OS
-           = [ "std", "concurrent", "posix", "text", "util" ]
-#          else
-          = [ ]
-#          endif
-
-showLS (Object nm)  = "(static) " ++ nm
-showLS (DLL nm) = "(dynamic) " ++ nm
-#ifdef darwin_TARGET_OS
-showLS (Framework nm) = "(framework) " ++ nm
-#endif
-
-linkPackages :: DynFlags -> [LibrarySpec] -> [PackageConfig] -> IO ()
-linkPackages dflags cmdline_lib_specs pkgs
-   = do mapM_ (linkPackage dflags) (reverse pkgs)
-        lib_paths <- readIORef v_Library_paths
-        mapM_ (preloadLib dflags lib_paths) cmdline_lib_specs
-       if (null cmdline_lib_specs)
-          then return ()
-          else do maybePutStr dflags "final link ... "
-
-                  ok <- resolveObjs
-                  if ok then maybePutStrLn dflags "done."
-                        else throwDyn (InstallationError 
-                                          "linking extra libraries/objects failed")
-     where
-        preloadLib :: DynFlags -> [String] -> LibrarySpec -> IO ()
-        preloadLib dflags lib_paths lib_spec
-           = do maybePutStr dflags ("Loading object " ++ showLS lib_spec ++ " ... ")
-                case lib_spec of
-                   Object static_ish
-                      -> do b <- preload_static lib_paths static_ish
-                            maybePutStrLn dflags (if b  then "done." 
-                                                       else "not found")
-                   DLL dll_unadorned
-                      -> -- We add "" to the set of paths to try, so that
-                         -- if none of the real paths match, we force addDLL
-                         -- to look in the default dynamic-link search paths.
-                         do maybe_errstr <- loadDynamic (lib_paths++[""]) 
-                                                            dll_unadorned
-                            case maybe_errstr of
-                               Nothing -> return ()
-                               Just mm -> preloadFailed mm lib_paths lib_spec
-                            maybePutStrLn dflags "done"
-
-        preloadFailed :: String -> [String] -> LibrarySpec -> IO ()
-        preloadFailed sys_errmsg paths spec
-           = do maybePutStr dflags
-                      ("failed.\nDynamic linker error message was:\n   " 
-                        ++ sys_errmsg  ++ "\nWhilst trying to load:  " 
-                        ++ showLS spec ++ "\nDirectories to search are:\n"
-                        ++ unlines (map ("   "++) paths) )
-                give_up
-
-        -- not interested in the paths in the static case.
-        preload_static paths name
-           = do b <- doesFileExist name
-                if not b then return False
-                         else loadObj name >> return True
-
-        give_up 
-           = (throwDyn . CmdLineError)
-                "user specified .o/.so/.DLL could not be loaded."
-
-linkPackage :: DynFlags -> PackageConfig -> IO ()
-linkPackage dflags pkg
-   | name pkg `elem` dont_load_these = return ()
-   | otherwise
-   = do 
-        let dirs      =  library_dirs pkg
-        let libs      =  hs_libraries pkg ++ extra_libraries pkg
-        classifieds   <- mapM (locateOneObj dirs) libs
-#ifdef darwin_TARGET_OS
-        let fwDirs    =  framework_dirs pkg
-        let frameworks=  extra_frameworks pkg
-#endif
-
-        -- Complication: all the .so's must be loaded before any of the .o's.  
-       let dlls = [ dll | DLL dll <- classifieds ]
-           objs = [ obj | Object obj <- classifieds ]
-
-       maybePutStr dflags ("Loading package " ++ name pkg ++ " ... ")
-
-       -- If this package is already part of the GHCi binary, we'll already
-       -- have the right DLLs for this package loaded, so don't try to
-       -- load them again.
-       when (name pkg `notElem` loaded_in_ghci) $ do
-#ifdef darwin_TARGET_OS
-           loadFrameworks fwDirs frameworks
-#endif
-           loadDynamics dirs dlls
-       
-       -- After loading all the DLLs, we can load the static objects.
-       mapM_ loadObj objs
-
-        maybePutStr dflags "linking ... "
-        ok <- resolveObjs
-       if ok then maybePutStrLn dflags "done."
-             else panic ("can't load package `" ++ name pkg ++ "'")
-
-loadDynamics dirs [] = return ()
-loadDynamics dirs (dll:dlls) = do
-  r <- loadDynamic dirs dll
-  case r of
-    Nothing  -> loadDynamics dirs dlls
-    Just err -> throwDyn (CmdLineError ("can't load .so/.DLL for: " 
-                                       ++ dll ++ " (" ++ err ++ ")" ))
-#ifdef darwin_TARGET_OS
-loadFrameworks dirs [] = return ()
-loadFrameworks dirs (fw:fws) = do
-  r <- loadFramework dirs fw
-  case r of
-    Nothing  -> loadFrameworks dirs fws
-    Just err -> throwDyn (CmdLineError ("can't load framework: " 
-                                       ++ fw ++ " (" ++ err ++ ")" ))
-#endif
-
--- Try to find an object file for a given library in the given paths.
--- If it isn't present, we assume it's a dynamic library.
-locateOneObj :: [FilePath] -> String -> IO LibrarySpec
-locateOneObj [] lib
-   = return (DLL lib) -- we assume
-locateOneObj (d:ds) lib
-   = do let path = d ++ '/':lib ++ ".o"
-        b <- doesFileExist path
-        if b then return (Object path) else locateOneObj ds lib
-
--- ----------------------------------------------------------------------------
--- Loading a dyanmic library (dlopen()-ish on Unix, LoadLibrary-ish on Win32)
-
-#if defined(mingw32_TARGET_OS) || defined(cygwin32_TARGET_OS)
-loadDynamic paths rootname = addDLL rootname
-  -- ignore paths on windows (why? --SDM)
-
-#else
-
--- return Nothing == success, else Just error message from dlopen
-loadDynamic (path:paths) rootname = do
-  let dll = path ++ '/':mkSOName rootname
-  b <- doesFileExist dll
-  if not b
-     then loadDynamic paths rootname
-     else addDLL dll
-loadDynamic [] rootname = do
-       -- tried all our known library paths, let dlopen() search its
-       -- own builtin paths now.
-   addDLL (mkSOName rootname)
-
-#ifdef darwin_TARGET_OS
-mkSOName root = "lib" ++ root ++ ".dylib"
-#else
-mkSOName root = "lib" ++ root ++ ".so"
-#endif
-
-#endif
-
--- Darwin / MacOS X only: load a framework
--- a framework is a dynamic library packaged inside a directory of the same
--- name. They are searched for in different paths than normal libraries.
-#ifdef darwin_TARGET_OS
-loadFramework extraPaths rootname
-   = loadFramework' (extraPaths ++ defaultFrameworkPaths) where
-   defaultFrameworkPaths = ["/Library/Frameworks", "/System/Library/Frameworks"]
-
-   loadFramework' (path:paths) = do
-      let dll = path ++ '/' : rootname ++ ".framework/" ++ rootname
-      b <- doesFileExist dll
-      if not b
-         then loadFramework' paths
-         else addDLL dll
-   loadFramework' [] = do
-       -- tried all our known library paths, but dlopen()
-       -- has no built-in paths for frameworks: give up
-      return $ Just $ "not found"
-#endif
-
-addDLL :: String -> IO (Maybe String)
-addDLL str = do
-  maybe_errmsg <- withCString str $ \dll -> c_addDLL dll
-  if maybe_errmsg == nullPtr
-       then return Nothing
-       else do str <- peekCString maybe_errmsg
-               return (Just str)
-
-foreign import ccall "addDLL" unsafe  
-  c_addDLL :: CString -> IO CString
-
------------------------------------------------------------------------------
 -- timing & statistics
 
 timeIt :: GHCi a -> GHCi a
 -- timing & statistics
 
 timeIt :: GHCi a -> GHCi a
@@ -1210,34 +1245,42 @@ timeIt action
                  a <- action
                  allocs2 <- io $ getAllocations
                  time2   <- io $ getCPUTime
                  a <- action
                  allocs2 <- io $ getAllocations
                  time2   <- io $ getCPUTime
-                 io $ printTimes (allocs2 - allocs1) (time2 - time1)
+                 io $ printTimes (fromIntegral (allocs2 - allocs1)) 
+                                 (time2 - time1)
                  return a
 
                  return a
 
-foreign import "getAllocations" getAllocations :: IO Int
+foreign import ccall unsafe "getAllocations" getAllocations :: IO Int64
+       -- defined in ghc/rts/Stats.c
 
 
-printTimes :: Int -> Integer -> IO ()
+printTimes :: Integer -> Integer -> IO ()
 printTimes allocs psecs
    = do let secs = (fromIntegral psecs / (10^12)) :: Float
            secs_str = showFFloat (Just 2) secs
        putStrLn (showSDoc (
                 parens (text (secs_str "") <+> text "secs" <> comma <+> 
 printTimes allocs psecs
    = do let secs = (fromIntegral psecs / (10^12)) :: Float
            secs_str = showFFloat (Just 2) secs
        putStrLn (showSDoc (
                 parens (text (secs_str "") <+> text "secs" <> comma <+> 
-                        int allocs <+> text "bytes")))
-
------------------------------------------------------------------------------
--- utils
-
-looksLikeModuleName [] = False
-looksLikeModuleName (c:cs) = isUpper c && all isAlphaNumEx cs
-
-isAlphaNumEx c = isAlphaNum c || c == '_' || c == '.'
-
-maybePutStr dflags s | verbosity dflags > 0 = putStr s
-                    | otherwise            = return ()
-
-maybePutStrLn dflags s | verbosity dflags > 0 = putStrLn s
-                      | otherwise            = return ()
+                        text (show allocs) <+> text "bytes")))
 
 -----------------------------------------------------------------------------
 -- reverting CAFs
        
 
 -----------------------------------------------------------------------------
 -- reverting CAFs
        
-foreign import revertCAFs :: IO ()     -- make it "safe", just in case
+revertCAFs :: IO ()
+revertCAFs = do
+  rts_revertCAFs
+  turnOffBuffering
+       -- Have to turn off buffering again, because we just 
+       -- reverted stdout, stderr & stdin to their defaults.
+
+foreign import ccall "revertCAFs" rts_revertCAFs  :: IO ()  
+       -- Make it "safe", just in case
+
+-- -----------------------------------------------------------------------------
+-- Utils
+
+expandPath :: String -> GHCi String
+expandPath path = 
+  case dropWhile isSpace path of
+   ('~':d) -> do
+       tilde <- io (getEnv "HOME")     -- will fail if HOME not defined
+       return (tilde ++ '/':d)
+   other -> 
+       return other