[project @ 2005-05-14 09:59:32 by panne]
[ghc-hetmet.git] / ghc / compiler / ghci / InteractiveUI.hs
index fb0732b..282ad93 100644 (file)
-{-# OPTIONS -#include "Linker.h" -#include "SchedAPI.h" #-}
+{-# OPTIONS -#include "Linker.h" #-}
 -----------------------------------------------------------------------------
 -----------------------------------------------------------------------------
--- $Id: InteractiveUI.hs,v 1.108 2002/01/22 16:50:29 simonmar Exp $
 --
 -- GHC Interactive User Interface
 --
 --
 -- GHC Interactive User Interface
 --
--- (c) The GHC Team 2000
+-- (c) The GHC Team 2005
 --
 -----------------------------------------------------------------------------
 --
 -----------------------------------------------------------------------------
-module InteractiveUI ( interactiveUI, ghciWelcomeMsg ) where
+module InteractiveUI ( 
+       interactiveUI,
+       ghciWelcomeMsg
+   ) where
 
 
-#include "../includes/config.h"
 #include "HsVersions.h"
 
 #include "HsVersions.h"
 
-import Packages
-import CompManager
-import HscTypes                ( TyThing(..) )
-import MkIface         ( ifaceTyThing )
-import DriverFlags
-import DriverState
-import DriverUtil      ( handle, remove_spaces )
-import Linker
-import Finder          ( flushPackageCache )
-import Util
-import Id              ( isRecordSelector, recordSelectorFieldLabel, 
-                         isDataConWrapId, idName )
-import Class           ( className )
-import TyCon           ( tyConName, tyConClass_maybe, isPrimTyCon )
-import FieldLabel      ( fieldLabelTyCon )
-import SrcLoc          ( isGoodSrcLoc )
-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(..),
+                         mkModule, pprModule, Type, Module, SuccessFlag(..),
+                         TyThing(..), Name, LoadHowMuch(..),
+                         GhcException(..), showGhcException,
+                         CheckedModule(..) )
 import Outputable
 import Outputable
-import CmdLineOpts     ( DynFlag(..), getDynFlags, saveDynFlags, restoreDynFlags, 
-                         dopt_unset )
-import Panic           ( GhcException(..), showGhcException )
-import Config
 
 
-#ifndef mingw32_TARGET_OS
-import Posix
+-- following all needed for :info... ToDo: remove
+import IfaceSyn                ( IfaceDecl(..), IfaceClassOp(..), IfaceConDecls(..),
+                         IfaceConDecl(..), IfaceType,
+                         pprIfaceDeclHead, pprParendIfaceType,
+                         pprIfaceForAllPart, pprIfaceType )
+import FunDeps         ( pprFundeps )
+import SrcLoc          ( SrcLoc, pprDefnLoc )
+import OccName         ( OccName, parenSymOcc, occNameUserString )
+import BasicTypes      ( StrictnessMark(..), defaultFixity, failed, successIf )
+
+-- Other random utilities
+import Panic           ( panic, installSignalHandlers )
+import Config
+import StaticFlags     ( opt_IgnoreDotGhci )
+import Linker          ( showLinkerState )
+import Util            ( removeSpaces, handle, global, toArgs,
+                         looksLikeModuleName, prefixMatch )
+import ErrUtils                ( printErrorsAndWarnings )
+
+#ifndef mingw32_HOST_OS
+import Util            ( handle )
+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 SystemExts
+
+import Control.Exception as Exception
+import Data.Dynamic
+-- import Control.Concurrent
 
 import Numeric
 
 import Numeric
-import List
-import System
-import CPUTime
-import Directory
-import IO
-import Char
-import Monad           ( when, join )
-
-import PrelGHC                 ( unsafeCoerce# )
-import Foreign         ( nullPtr )
-import CString         ( peekCString )
+import Data.List
+import Data.Int                ( Int64 )
+import Data.Maybe      ( isJust )
+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),
   ("cd",       keepGoing changeDirectory),
   ("def",      keepGoing defineMacro),
   ("help",     keepGoing help),
   ("?",                keepGoing help),
   ("info",      keepGoing info),
-  ("import",    keepGoing importModules),
-  ("load",     keepGoing loadModule),
+  ("load",     keepGoingPaths loadModule_),
   ("module",   keepGoing setContext),
   ("reload",   keepGoing reloadModule),
   ("module",   keepGoing setContext),
   ("reload",   keepGoing reloadModule),
+  ("check",    keepGoing checkModule),
   ("set",      keepGoing setCmd),
   ("set",      keepGoing setCmd),
+  ("show",     keepGoing showCmd),
   ("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)
@@ -97,92 +120,103 @@ 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"
 
 shortHelpText = "use :? for help.\n"
 
-helpText = "\ 
-\ Commands available from the prompt:\n\ 
-\\
-\   <stmt>                evaluate/run <stmt>\n\ 
-\   :add <filename> ...    add module(s) to the current target set\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 to <mod>\n\ 
-\   :reload               reload the current module set\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\ 
-\   :undef <cmd>          undefine user-defined command :<cmd>\n\ 
-\   :type <expr>          show the type of <expr>\n\ 
-\   :unset <option> ...           unset options\n\ 
-\   :quit                 exit GHCi\n\ 
-\   :!<command>                   run the shell command <command>\n\ 
-\\ 
-\ Options for `:set' and `:unset':\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
+-- 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" ++
+ "   :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 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
 
-   -- link in the available packages
-   pkgs <- getPackageInfo
-   initLinker
-   linkPackages cmdline_libs pkgs
-
-   dflags <- getDynFlags
-
-   (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"
+       -- Initialise buffering for the *interpreted* I/O system
+   initInterpBuffering session
 
 
-   (cmstate, maybe_hval)
-       <- cmCompileExpr cmstate dflags "IO.hFlush PrelHandle.stderr"
-   case maybe_hval of
-       Just hval -> writeIORef flush_stderr (unsafeCoerce# hval :: IO ())
-       _ -> panic "interactiveUI:stderr"
-
-   (cmstate, maybe_hval) 
-       <- cmCompileExpr cmstate dflags "IO.hFlush PrelHandle.stdout"
-   case maybe_hval of
-       Just hval -> writeIORef flush_stdout (unsafeCoerce# hval :: IO ())
-       _ -> panic "interactiveUI:stdout"
+       -- We don't want the cmd line to buffer any input that might be
+       -- intended for the program, so unbuffer stdin.
+   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) 
+#if defined(mingw32_HOST_OS)
+    -- 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.
+    -- 
+   GHC.ConsoleHandler.flushConsole stdin
+#endif
+   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] -> GHCi ()
-runGHCi paths = do
-  read_dot_files <- io (readIORef v_Read_DotGHCi)
+runGHCi :: [FilePath] -> 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.
@@ -213,28 +247,51 @@ runGHCi paths = 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
-  interactiveLoop
+  -- 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)
+  dflags <- getDynFlags
+  let show_prompt = verbosity dflags > 0 || is_tty
+
+  case maybe_expr of
+       Nothing -> 
+           -- 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
 
   -- and finally, exit
-  io $ do putStrLn "Leaving GHCi."
+  io $ do when (verbosity dflags > 0) $ putStrLn "Leaving GHCi."
 
 
 
 
-interactiveLoop = do
-  -- ignore ^C exceptions caught here
-  ghciHandleDyn (\e -> case e of Interrupted -> ghciUnblock interactiveLoop
-                                _other      -> return ()) $ do
+interactiveLoop is_tty show_prompt = do
+  -- Ignore ^C exceptions caught here
+  ghciHandleDyn (\e -> case e of 
+                       Interrupted -> ghciUnblock (
+#if defined(mingw32_HOST_OS)
+                                               io (putStrLn "") >> 
+#endif
+                                               interactiveLoop is_tty show_prompt)
+                       _other      -> return ()) $ do
 
   -- read commands from stdin
 
   -- read commands from stdin
-#if HAVE_READLINE_HEADERS && HAVE_READLINE_LIBS
-  readlineLoop
+#ifdef USE_READLINE
+  if (is_tty) 
+       then readlineLoop
+       else fileLoop stdin show_prompt
 #else
 #else
-  fileLoop stdin True
+  fileLoop stdin show_prompt
 #endif
 
 
 #endif
 
 
@@ -249,10 +306,10 @@ interactiveLoop = do
 
 checkPerms :: String -> IO Bool
 checkPerms name =
 
 checkPerms :: String -> IO Bool
 checkPerms name =
-  handle (\_ -> return False) $ do
-#ifdef mingw32_TARGET_OS
-     doesFileExist name
+#ifdef mingw32_HOST_OS
+  return True
 #else
 #else
+  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
@@ -271,15 +328,21 @@ checkPerms name =
 
 fileLoop :: Handle -> Bool -> GHCi ()
 fileLoop hdl prompt = do
 
 fileLoop :: Handle -> Bool -> GHCi ()
 fileLoop hdl prompt = do
-   st <- getGHCiState
-   (mod,imports) <- io (cmGetContext (cmstate st))
+   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
@@ -287,30 +350,30 @@ fileLoop hdl prompt = do
 stringLoop :: [String] -> GHCi ()
 stringLoop [] = return ()
 stringLoop (s:ss) = do
 stringLoop :: [String] -> GHCi ()
 stringLoop [] = return ()
 stringLoop (s:ss) = do
-   st <- getGHCiState
-   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 "," toplevs)
-   ++ (if not (null exports) 
-       then "[" ++ concat (intersperse "," exports) ++ "]" 
-       else "")
-   ++ "> "
+  = 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
-   st <- getGHCiState
-   (mod,imports) <- io (cmGetContext (cmstate st))
+   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)
@@ -318,16 +381,32 @@ 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)
+
+-- 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))
+
+-- 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
@@ -350,40 +429,38 @@ runStmt stmt
  | null (filter (not.isSpace) stmt) = return []
  | otherwise
  = do st <- getGHCiState
  | null (filter (not.isSpace) stmt) = return []
  | 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 []
+       GHC.RunException e -> throw e  -- this is caught by runCommand(Eval)
+       GHC.RunOk names    -> return names
 
 -- possibly print the type and revert CAFs after evaluating an expression
 finishEvalExpr names
  = do b <- isOptionSet ShowType
 
 -- possibly print the type and revert CAFs after evaluating an expression
 finishEvalExpr names
  = do b <- isOptionSet ShowType
-      st <- getGHCiState
-      when b (mapM_ (showTypeOfName (cmstate st)) names)
+      session <- getSession
+      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 :: String -> GHCi Bool
 specialCommand ('!':str) = shellEscape (dropWhile isSpace str)
@@ -391,7 +468,7 @@ specialCommand str = do
   let (cmd,rest) = break isSpace str
   cmds <- io (readIORef commands)
   case [ (s,f) | (s,f) <- cmds, prefixMatch cmd s ] of
   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" 
+     []      -> io (hPutStr stdout ("unknown command ':" ++ cmd ++ "'\n" 
                                    ++ shortHelpText) >> return False)
      [(_,f)] -> f (dropWhile isSpace rest)
      cs      -> io (hPutStrLn stdout ("prefix " ++ cmd ++ 
                                    ++ shortHelpText) >> return False)
      [(_,f)] -> f (dropWhile isSpace rest)
      cs      -> io (hPutStrLn stdout ("prefix " ++ cmd ++ 
@@ -399,7 +476,47 @@ specialCommand str = do
                                       foldr1 (\a b -> a ++ ',':b) (map fst cs)
                                         ++ ")") >> return False)
 
                                       foldr1 (\a b -> a ++ ',':b) (map fst cs)
                                         ++ ")") >> return False)
 
-noArgs c = throwDyn (CmdLineError ("command `" ++ c ++ "' takes no arguments"))
+noArgs c = throwDyn (CmdLineError ("command '" ++ c ++ "' takes no arguments"))
+
+
+-----------------------------------------------------------------------------
+-- 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
+
+      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
@@ -408,81 +525,159 @@ 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
-  state <- getGHCiState
-  dflags <- io getDynFlags
-  let 
-    infoThings cms [] = return cms
-    infoThings cms (name:names) = do
-      (cms, unqual, stuff) <- io (cmInfoThing cms dflags name)
-      io (putStrLn (showSDocForUser unqual (
-           vcat (intersperse (text "") (map showThing stuff))))
-         )
-      infoThings cms names
-
-    showThing (ty_thing, fixity) 
-       = vcat [ text "-- " <> showTyThing ty_thing, 
-                showFixity fixity (getName ty_thing),
-                ppr (ifaceTyThing ty_thing) ]
-
-    showFixity fix name
+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 name
+       = do { stuff <- io (GHC.getInfo session name)
+            ; unqual <- io (GHC.getPrintUnqual session)
+            ; io (putStrLn (showSDocForUser unqual $
+                  vcat (intersperse (text "") (map (showThing exts) stuff)))) }
+
+showThing :: Bool -> GHC.GetInfoResult -> SDoc
+showThing exts (wanted_str, thing, fixity, src_loc, insts) 
+    = vcat [ showWithLoc src_loc (showDecl exts want_name thing),
+            show_fixity fixity,
+            vcat (map show_inst insts)]
+  where
+    want_name occ = wanted_str == occNameUserString occ
+
+    show_fixity fix 
        | fix == defaultFixity = empty
        | 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            = ppr fix <+> text wanted_str
+
+    show_inst (inst_ty, loc)
+       = showWithLoc loc (ptext SLIT("instance") <+> ppr inst_ty)
+
+showWithLoc :: SrcLoc -> SDoc -> SDoc
+showWithLoc loc doc 
+    = hang doc 2 (char '\t' <> comment <+> pprDefnLoc loc)
+               -- The tab tries to make them line up a bit
+  where
+    comment = ptext SLIT("--")
+
+
+-- Now there is rather a lot of goop just to print declarations in a
+-- civilised way with "..." for the parts we are less interested in.
+
+showDecl :: Bool -> (OccName -> Bool) -> IfaceDecl -> SDoc
+showDecl exts want_name (IfaceForeign {ifName = tc})
+  = ppr tc <+> ptext SLIT("is a foreign type")
+
+showDecl exts want_name (IfaceId {ifName = var, ifType = ty})
+  = ppr var <+> dcolon <+> showIfaceType exts ty 
+
+showDecl exts want_name (IfaceSyn {ifName = tycon, ifTyVars = tyvars, ifSynRhs = mono_ty})
+  = hang (ptext SLIT("type") <+> pprIfaceDeclHead [] tycon tyvars)
+       2 (equals <+> ppr mono_ty)
+
+showDecl exts want_name (IfaceData {ifName = tycon, 
+                    ifTyVars = tyvars, ifCons = condecls, ifCtxt = context})
+  = hang (pp_nd <+> pprIfaceDeclHead context tycon tyvars)
+       2 (add_bars (ppr_trim show_con cs))
+  where
+    show_con (IfVanillaCon { ifConOcc = con_name, ifConInfix = is_infix, ifConArgTys = tys, 
+                            ifConStricts = strs, ifConFields = flds})
+       | want_name tycon || want_name con_name || any want_name flds
+       = Just (show_guts con_name is_infix tys_w_strs flds)
+       | otherwise = Nothing
+       where
+         tys_w_strs = tys `zip` (strs ++ repeat NotMarkedStrict)
+    show_con (IfGadtCon { ifConOcc = con_name, ifConTyVars = tvs, ifConCtxt = theta, 
+                         ifConArgTys = arg_tys, ifConResTys = res_tys, ifConStricts = strs })
+       | want_name tycon || want_name con_name
+       = Just (ppr_bndr con_name <+> colon <+> pprIfaceForAllPart tvs theta pp_tau)
+       | otherwise = Nothing
+       where
+         tys_w_strs = arg_tys `zip` (strs ++ repeat NotMarkedStrict)
+         pp_tau = foldr add pp_res_ty tys_w_strs
+         pp_res_ty = ppr_bndr tycon <+> hsep (map pprParendIfaceType res_tys)
+         add bty pp_ty = ppr_bangty bty <+> arrow <+> pp_ty
+
+    show_guts con True [ty1, ty2] flds = sep [ppr_bangty ty1, ppr con, ppr_bangty ty2]
+    show_guts con _ tys []   = ppr_bndr con <+> sep (map ppr_bangty tys)
+    show_guts con _ tys flds 
+       = ppr_bndr con <+> braces (sep (punctuate comma (ppr_trim show_fld (tys `zip` flds))))
+       where
+         show_fld (bty, fld) | want_name tycon || want_name con || want_name fld
+                             = Just (ppr_bndr fld <+> dcolon <+> ppr_bangty bty)
+                             | otherwise = Nothing
+
+    (pp_nd, cs) = case condecls of
+                   IfAbstractTyCon        -> (ptext SLIT("data"),   [])
+                   IfDataTyCon cs         -> (ptext SLIT("data"),   cs)
+                   IfNewTyCon c           -> (ptext SLIT("newtype"),[c])
+
+    add_bars []      = empty
+    add_bars [c]     = equals <+> c
+    add_bars (c:cs)  = equals <+> sep (c : map (char '|' <+>) cs)
+
+    ppr_bangty (ty, str) = ppr_str str <> pprParendIfaceType ty
+    ppr_str MarkedStrict    = char '!'
+    ppr_str MarkedUnboxed   = ptext SLIT("!!")
+    ppr_str NotMarkedStrict = empty
+
+showDecl exts want_name (IfaceClass {ifCtxt = context, ifName = clas, ifTyVars = tyvars, 
+                     ifFDs = fds, ifSigs = sigs})
+  = hang (ptext SLIT("class") <+> pprIfaceDeclHead context clas tyvars
+               <+> pprFundeps fds <+> opt_where)
+       2 (vcat (ppr_trim show_op sigs))
+  where
+    opt_where | null sigs = empty
+             | otherwise = ptext SLIT("where")
+    show_op (IfaceClassOp op dm ty) 
+       | want_name clas || want_name op 
+       = Just (ppr_bndr op <+> dcolon <+> showIfaceType exts ty)
        | otherwise
        | otherwise
-       = empty
-       where loc = nameSrcLoc name
+       = Nothing
+
+showIfaceType :: Bool -> IfaceType -> SDoc
+showIfaceType True  ty = pprIfaceType ty -- -fglasgow-exts: print with the foralls
+showIfaceType False ty = ppr ty            -- otherwise, print without the foralls
+
+ppr_trim :: (a -> Maybe SDoc) -> [a] -> [SDoc]
+ppr_trim show xs
+  = snd (foldr go (False, []) xs)
+  where
+    go x (eliding, so_far)
+       | Just doc <- show x = (False, doc : so_far)
+       | otherwise = if eliding then (True, so_far)
+                                else (True, ptext SLIT("...") : so_far)
+
+ppr_bndr :: OccName -> SDoc
+-- Wrap operators in ()
+ppr_bndr occ = parenSymOcc occ (ppr occ)
 
 
-  cms <- infoThings (cmstate state) names
-  setGHCiState state{ cmstate = cms }
-  return ()
 
 
-addModule :: String -> GHCi ()
-addModule str = do
-  let files = words str
-  state <- getGHCiState
-  dflags <- io (getDynFlags)
+-----------------------------------------------------------------------------
+-- Commands
+
+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
+  files <- mapM expandPath files
+  targets <- mapM (io . GHC.guessTarget) 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 []
+  io (GHC.workingDirectoryChanged session)
+  dir <- expandPath dir
+  io (setCurrentDirectory dir)
 
 defineMacro :: String -> GHCi ()
 defineMacro s = do
 
 defineMacro :: String -> GHCi ()
 defineMacro s = do
@@ -493,7 +688,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
@@ -501,16 +696,14 @@ defineMacro s = do
   let new_expr = '(' : definition ++ ") :: String -> IO String"
 
   -- compile the expression
   let new_expr = '(' : definition ++ ") :: String -> IO String"
 
   -- compile the expression
-  st <- getGHCiState
-  dflags <- io getDynFlags
-  (new_cmstate, maybe_hv) <- io (cmCompileExpr (cmstate st) dflags new_expr)
-  setGHCiState st{cmstate = new_cmstate}
+  cms <- getSession
+  maybe_hv <- io (GHC.compileExpr cms new_expr)
   case maybe_hv of
      Nothing -> return ()
      Just hv -> io (writeIORef commands --
                    ((macro_name, keepGoing (runMacro hv)) : cmds))
 
   case maybe_hv of
      Nothing -> return ()
      Just hv -> io (writeIORef commands --
                    ((macro_name, keepGoing (runMacro hv)) : cmds))
 
-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)
@@ -520,87 +713,123 @@ 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))
 
 
-importModules :: String -> GHCi ()
-importModules str = return ()
-
-
-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
-
+loadModule :: [FilePath] -> GHCi SuccessFlag
+loadModule fs = timeIt (loadModule' fs)
+
+loadModule_ :: [FilePath] -> GHCi ()
+loadModule_ fs = do loadModule fs; return ()
+
+loadModule' :: [FilePath] -> GHCi SuccessFlag
+loadModule' files = do
+  session <- getSession
+
+  -- unload first
+  io (GHC.setTargets session [])
+  io (GHC.load session LoadAllTargets)
+
+  -- expand tildes
+  files <- mapM expandPath files
+  targets <- io (mapM 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 printErrorsAndWarnings)
+  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
-
-reloadModule _ = noArgs ":reload"
-
-setContextAfterLoad [] = setContext prel
-setContextAfterLoad (m:_) = setContext m
-
+  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)
+  let mods = map GHC.ms_mod graph
+  mods' <- filterM (io . GHC.isLoaded session) mods
+  setContextAfterLoad mods'
+  modulesLoadedMsg ok mods'
+
+setContextAfterLoad [] = do
+  session <- getSession
+  io (GHC.setContext session [] [prelude_mod])
+setContextAfterLoad (m:_) = do
+  session <- getSession
+  b <- io (GHC.moduleIsInterpreted session m)
+  if b then io (GHC.setContext session [m] []) 
+       else io (GHC.setContext session []  [m])
+
+modulesLoadedMsg :: SuccessFlag -> [Module] -> GHCi ()
 modulesLoadedMsg ok mods = do
 modulesLoadedMsg ok mods = do
-  let mod_commas 
+  dflags <- getDynFlags
+  when (verbosity dflags > 0) $ do
+   let mod_commas 
        | null mods = text "none."
        | otherwise = hsep (
        | null mods = text "none."
        | otherwise = hsep (
-           punctuate comma (map text mods)) <> text "."
-  case ok of
-    False -> 
+           punctuate comma (map pprModule mods)) <> text "."
+   case ok of
+    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 st <- getGHCiState
-       dflags <- io getDynFlags
-       (new_cmstate, maybe_tystr) <- io (cmTypeOfExpr (cmstate st) dflags str)
-       setGHCiState st{cmstate = 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
@@ -609,60 +838,95 @@ shellEscape :: String -> GHCi Bool
 shellEscape str = io (system str >> return False)
 
 -----------------------------------------------------------------------------
 shellEscape str = io (system str >> return False)
 
 -----------------------------------------------------------------------------
+-- Browsing a module's contents
+
+browseCmd :: String -> GHCi ()
+browseCmd m = 
+  case words m of
+    ['*':m] | looksLikeModuleName m -> browseModule m False
+    [m]     | looksLikeModuleName m -> browseModule m True
+    _ -> throwDyn (CmdLineError "syntax:  :browse <module>")
+
+browseModule m exports_only = do
+  s <- getSession
+
+  let modl = mkModule m
+  is_interpreted <- io (GHC.moduleIsInterpreted s modl)
+  when (not is_interpreted && not exports_only) $
+       throwDyn (CmdLineError ("module '" ++ m ++ "' is not interpreted"))
+
+  -- Temporarily set the context to the module we're interested in,
+  -- just so we can get an appropriate PrintUnqualified
+  (as,bs) <- io (GHC.getContext s)
+  io (if exports_only then GHC.setContext s [] [prelude_mod,modl]
+                     else GHC.setContext s [modl] [])
+  io (GHC.setContext s as bs)
+
+  things <- io (GHC.browseModule s modl exports_only)
+  unqual <- io (GHC.getPrintUnqual s)
+
+  dflags <- getDynFlags
+  let exts = dopt Opt_GlasgowExts dflags
+  io (putStrLn (showSDocForUser unqual (
+        vcat (map (showDecl exts (const True)) things)
+      )))
+
+-----------------------------------------------------------------------------
 -- Setting the module context
 
 setContext str
 -- Setting the module context
 
 setContext str
- | all sensible  mods = newContext mods        -- default is to set the empty context
- | all plusminus mods = adjustContext mods
- | otherwise
-   = throwDyn (CmdLineError "syntax:  :module M1 .. Mn | :module [+/-]M1 ... [+/-]Mn")
- where
-    mods = words str
+  | all sensible mods = fn mods
+  | otherwise = throwDyn (CmdLineError "syntax:  :module [+/-] [*]M1 ... [*]Mn")
+  where
+    (fn, mods) = case str of 
+                       '+':stuff -> (addToContext,      words stuff)
+                       '-':stuff -> (removeFromContext, words stuff)
+                       stuff     -> (newContext,        words stuff) 
 
 
-    sensible (c:cs) = isUpper c && all isAlphaNumEx cs
-    isAlphaNumEx c = isAlphaNum c || c == '_'
-
-    plusminus ('-':mod) = sensible mod
-    plusminus ('+':mod) = sensible mod
-    plusminus _ = False
+    sensible ('*':m) = looksLikeModuleName m
+    sensible m       = looksLikeModuleName m
 
 newContext mods = do
 
 newContext mods = do
-  state@GHCiState{cmstate=cmstate} <- getGHCiState
-  dflags <- io getDynFlags
-
-  let separate [] as bs = return (as,bs)
-      separate (m:ms) as bs = do 
-        b <- io (cmModuleIsInterpreted cmstate m)
-        if b then separate ms (m:as) bs
-             else separate ms as (m:bs)
-                               
-  (as,bs) <- separate mods [] []
-  let bs' = if null as && prel `notElem` bs then prel:bs else bs
-  cmstate' <- io (cmSetContext cmstate dflags as bs')
-  setGHCiState state{cmstate=cmstate'}
-
-prel = "Prelude"
-
-adjustContext mods = do
-  state@GHCiState{cmstate=cmstate} <- getGHCiState
-  dflags <- io getDynFlags
-
-  let adjust [] as bs = return (as,bs)
-      adjust (('-':m) : ms) as bs
-       | m `elem` as  = adjust ms (delete m as) bs
-       | m `elem` bs  = adjust ms as (delete m bs)
-       | otherwise = throwDyn (CmdLineError ("module `" ++ m ++ "' is not currently in scope"))
-      adjust (('+':m) : ms) as bs
-       | m `elem` as || m `elem` bs = adjust ms as bs -- continue silently
-       | otherwise = do b <- io (cmModuleIsInterpreted cmstate m)
-                        if b then adjust ms (m:as) bs
-                             else adjust ms as (m:bs)
-
-  (as,bs) <- io (cmGetContext cmstate)
-  (as,bs) <- adjust mods as bs
-  let bs' = if null as && prel `notElem` bs then prel:bs else bs
-  cmstate' <- io (cmSetContext cmstate dflags as bs')
-  setGHCiState state{cmstate=cmstate'}
+  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 :: 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)
+
+prelude_mod = mkModule "Prelude"
+
+
+addToContext mods = do
+  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)
+
+  io (GHC.setContext cms (as ++ as_to_add) (bs ++ bs_to_add))
+
+
+removeFromContext mods = do
+  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)
+
+  io (GHC.setContext cms as' bs')
 
 ----------------------------------------------------------------------------
 -- Code for `:set'
 
 ----------------------------------------------------------------------------
 -- Code for `:set'
@@ -703,24 +967,21 @@ setProg _ = do
 setOptions wds =
    do -- first, deal with the GHCi opts (+s, +t, etc.)
       let (plus_opts, minus_opts)  = partition isPlus wds
 setOptions wds =
    do -- first, deal with the GHCi opts (+s, +t, etc.)
       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)
+      mapM_ setOpt plus_opts
 
       -- 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 ()
@@ -734,10 +995,10 @@ 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
 
          else do
 
-       mapM unsetOpt plus_opts
+       mapM_ unsetOpt plus_opts
  
        -- can't do GHC flags for now
        if (not (null minus_opts))
  
        -- can't do GHC flags for now
        if (not (null minus_opts))
@@ -752,12 +1013,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)
@@ -771,18 +1032,53 @@ 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 = [] }
+{- 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
+       ["linker"]   -> io showLinkerState
+       _ -> throwDyn (CmdLineError "syntax:  :show [modules|bindings]")
+
+showModules = do
+  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
+  s <- getSession
+  unqual <- io (GHC.getPrintUnqual s)
+  bindings <- io (GHC.getBindings s)
+  mapM_ showTyThing bindings
+  return ()
 
 
-  io $ do
-    pkgs <- getPackageInfo
-    flushPackageCache pkgs
-   
-    new_pkg_info <- getPackageDetails new_pkgs
-    mapM_ linkPackage (reverse new_pkg_info)
+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
@@ -791,8 +1087,7 @@ data GHCiState = GHCiState
      { 
        progname       :: String,
        args           :: [String],
      { 
        progname       :: String,
        args           :: [String],
-       targets        :: [FilePath],
-       cmstate        :: CmState,
+       session        :: GHC.Session,
        options        :: [GHCiOption]
      }
 
        options        :: [GHCiOption]
      }
 
@@ -802,9 +1097,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
@@ -821,6 +1113,16 @@ ghciHandleDyn h (GHCi m) = GHCi $ \s ->
 getGHCiState   = GHCi $ \r -> readIORef r
 setGHCiState s = GHCi $ \r -> writeIORef r s
 
 getGHCiState   = GHCi $ \r -> readIORef r
 setGHCiState s = GHCi $ \r -> writeIORef r s
 
+-- for convenience...
+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
  = do st <- getGHCiState
 isOptionSet :: GHCiOption -> GHCi Bool
 isOptionSet opt
  = do st <- getGHCiState
@@ -849,151 +1151,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.
-
-type LibrarySpec
-   = Either FilePath String
-
-showLS (Left nm)  = "(static) " ++ nm
-showLS (Right nm) = "(dynamic) " ++ nm
-
-linkPackages :: [LibrarySpec] -> [PackageConfig] -> IO ()
-linkPackages cmdline_lib_specs pkgs
-   = do mapM_ linkPackage (reverse pkgs)
-        lib_paths <- readIORef v_Library_paths
-        mapM_ (preloadLib lib_paths) cmdline_lib_specs
-       if (null cmdline_lib_specs)
-          then return ()
-          else do putStr "final link ... "
-                  ok <- resolveObjs
-                  if ok then putStrLn "done."
-                        else throwDyn (InstallationError 
-                                          "linking extra libraries/objects failed")
-     where
-        preloadLib :: [String] -> LibrarySpec -> IO ()
-        preloadLib lib_paths lib_spec
-           = do putStr ("Loading object " ++ showLS lib_spec ++ " ... ")
-                case lib_spec of
-                   Left static_ish
-                      -> do b <- preload_static lib_paths static_ish
-                            putStrLn (if b then "done." else "not found")
-                   Right 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 <- preload_dynamic (lib_paths++[""]) 
-                                                            dll_unadorned
-                            case maybe_errstr of
-                               Nothing -> return ()
-                               Just mm -> preloadFailed mm lib_paths lib_spec
-                            putStrLn "done"
-
-        preloadFailed :: String -> [String] -> LibrarySpec -> IO ()
-        preloadFailed sys_errmsg paths spec
-           = do putStr ("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
-
-        -- return Nothing == success, else Just error message from addDLL
-        preload_dynamic [] name
-           = return Nothing
-        preload_dynamic (path:paths) rootname
-           = do -- addDLL returns NULL on success
-                maybe_errmsg <- addDLL path rootname
-                if    maybe_errmsg == nullPtr
-                 then preload_dynamic paths rootname
-                 else do str <- peekCString maybe_errmsg
-                         return (Just str)
-
-        give_up 
-           = (throwDyn . CmdLineError)
-                "user specified .o/.so/.DLL could not be loaded."
-
--- Packages that don't need loading, because the compiler shares them with
--- the interpreted program.
-dont_load_these = [ "gmp", "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
-
-linkPackage :: PackageConfig -> IO ()
-linkPackage pkg
-   | name pkg `elem` dont_load_these = return ()
-   | otherwise
-   = do 
-        -- For each obj, try obj.o and if that fails, obj.so.
-        -- Complication: all the .so's must be loaded before any of the .o's.  
-        let dirs      =  library_dirs pkg
-        let objs      =  hs_libraries pkg ++ extra_libraries pkg
-        classifieds   <- mapM (locateOneObj dirs) objs
-
-       -- Don't load the .so libs if this is a package GHCi is already
-       -- linked against, because we'll already have the .so linked in.
-       let (so_libs, obj_libs) = partition isRight classifieds
-        let sos_first | name pkg `elem` loaded_in_ghci = obj_libs
-                     | otherwise                      = so_libs ++ obj_libs
-
-       putStr ("Loading package " ++ name pkg ++ " ... ")
-        mapM loadClassified sos_first
-        putStr "linking ... "
-        ok <- resolveObjs
-       if ok then putStrLn "done."
-             else panic ("can't load package `" ++ name pkg ++ "'")
-     where
-        isRight (Right _) = True
-        isRight (Left _)  = False
-
-loadClassified :: LibrarySpec -> IO ()
-loadClassified (Left obj_absolute_filename)
-   = do loadObj obj_absolute_filename
-loadClassified (Right dll_unadorned)
-   = do maybe_errmsg <- addDLL "" dll_unadorned -- doesn't seem right to me
-        if    maybe_errmsg == nullPtr
-         then return ()
-         else do str <- peekCString maybe_errmsg
-                 throwDyn (CmdLineError ("can't load .so/.DLL for: " 
-                                       ++ dll_unadorned ++ " (" ++ str ++ ")" ))
-
-locateOneObj :: [FilePath] -> String -> IO LibrarySpec
-locateOneObj []     obj 
-   = return (Right obj) -- we assume
-locateOneObj (d:ds) obj 
-   = do let path = d ++ '/':obj ++ ".o"
-        b <- doesFileExist path
-        if b then return (Left path) else locateOneObj ds obj
-
------------------------------------------------------------------------------
 -- timing & statistics
 
 timeIt :: GHCi a -> GHCi a
 -- timing & statistics
 
 timeIt :: GHCi a -> GHCi a
@@ -1006,20 +1169,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")))
+                        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