[project @ 2006-01-03 16:15:37 by simonmar]
[ghc-hetmet.git] / ghc / compiler / ghci / InteractiveUI.hs
index 8660650..0bf37dc 100644 (file)
@@ -1,53 +1,55 @@
-{-# OPTIONS -#include "Linker.h" -#include "SchedAPI.h" #-}
+{-# OPTIONS -#include "Linker.h" #-}
 -----------------------------------------------------------------------------
 -----------------------------------------------------------------------------
--- $Id: InteractiveUI.hs,v 1.134 2002/09/13 15:02:32 simonpj 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 ()
+       interactiveUI,
        ghciWelcomeMsg
    ) where
 
        ghciWelcomeMsg
    ) where
 
-#include "../includes/config.h"
 #include "HsVersions.h"
 
 #include "HsVersions.h"
 
-import CompManager
-import HscTypes                ( TyThing(..), HomeModInfo(hm_linkable), HomePackageTable,
-                         isObjectLinkable )
-import HsSyn           ( TyClDecl(..), ConDecl(..), Sig(..) )
-import MkIface         ( ifaceTyThing )
-import DriverFlags
-import DriverState
-import DriverUtil      ( remove_spaces, handle )
-import Linker          ( initLinker, showLinkerState, linkLibraries )
-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          ( showModMsg, lookupModuleEnv )
-import Name            ( Name, isHomePackageName, nameSrcLoc, nameOccName,
-                         NamedThing(..) )
-import OccName         ( isSymOcc )
-import BasicTypes      ( defaultFixity, SuccessFlag(..) )
+-- 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 )
+
+-- for createtags (should these come via GHC?)
+import Module( moduleUserString )
+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 Config
+import StaticFlags     ( opt_IgnoreDotGhci )
+import Linker          ( showLinkerState )
+import Util            ( removeSpaces, handle, global, toArgs,
+                         looksLikeModuleName, prefixMatch, sortLe )
 
 
-#ifndef mingw32_TARGET_OS
+#ifndef mingw32_HOST_OS
 import System.Posix
 import System.Posix
+#if __GLASGOW_HASKELL__ > 504
+       hiding (getEnv)
+#endif
+#else
+import GHC.ConsoleHandler ( flushConsole )
 #endif
 
 #endif
 
-#if HAVE_READLINE_HEADERS && HAVE_READLINE_LIBS
+#ifdef USE_READLINE
 import Control.Concurrent      ( yield )       -- Used in readline loop
 import System.Console.Readline as Readline
 #endif
 import Control.Concurrent      ( yield )       -- Used in readline loop
 import System.Console.Readline as Readline
 #endif
@@ -56,50 +58,60 @@ import System.Console.Readline as Readline
 
 import Control.Exception as Exception
 import Data.Dynamic
 
 import Control.Exception as Exception
 import Data.Dynamic
-import Control.Concurrent
+-- import Control.Concurrent
 
 import Numeric
 import Data.List
 
 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.Cmd
 import System.CPUTime
 import System.Environment
+import System.Exit     ( exitWith, ExitCode(..) )
 import System.Directory
 import System.Directory
-import System.IO as IO
+import System.IO
+import System.IO.Error as IO
 import Data.Char
 import Control.Monad as Monad
 import Data.Char
 import Control.Monad as Monad
+import Foreign.StablePtr       ( newStablePtr )
 
 import GHC.Exts                ( unsafeCoerce# )
 
 import GHC.Exts                ( unsafeCoerce# )
+import GHC.IOBase      ( IOErrorType(InvalidArgument) )
 
 
-import Foreign         ( nullPtr )
-import Foreign.C.String        ( CString, peekCString, withCString )
 import Data.IORef      ( IORef, newIORef, readIORef, writeIORef )
 
 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),
   ("reload",   keepGoing reloadModule),
   ("module",   keepGoing setContext),
   ("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)
@@ -108,89 +120,98 @@ 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] -> [FilePath] -> IO ()
-interactiveUI cmstate paths cmdline_objs = 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" ++
+ "   :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
-   initLinker
-       --      Now that demand-loading works, we don't really need to pre-load the packages
-       --   pkgs <- getPackages
-       --   linkPackages dflags  pkgs
-   linkLibraries dflags cmdline_objs
-
        -- Initialise buffering for the *interpreted* I/O system
        -- Initialise buffering for the *interpreted* I/O system
-   cmstate <- initInterpBuffering cmstate dflags
+   initInterpBuffering session
 
        -- 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
 
        -- 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
-   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.
@@ -221,38 +242,63 @@ 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
-#if defined(mingw32_TARGET_OS)
-   -- always show prompt, since hIsTerminalDevice returns True for Consoles
-   -- only, which we may or may not be running under (cf. Emacs sub-shells.)
-  interactiveLoop True
-#else
+  -- 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
 #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 = do
+  -- Ignore ^C exceptions caught here
   ghciHandleDyn (\e -> case e of 
   ghciHandleDyn (\e -> case e of 
-                       Interrupted -> ghciUnblock (interactiveLoop is_tty)
+                       Interrupted -> ghciUnblock (
+#if defined(mingw32_HOST_OS)
+                                               io (putStrLn "") >> 
+#endif
+                                               interactiveLoop is_tty show_prompt)
                        _other      -> return ()) $ do
 
   -- read commands from stdin
                        _other      -> return ()) $ do
 
   -- 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 is_tty
+  fileLoop stdin show_prompt
 #endif
 
 
 #endif
 
 
@@ -267,10 +313,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
@@ -289,15 +335,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
@@ -305,25 +357,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)
@@ -331,16 +388,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
-               flushInterpBuffers
-               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
@@ -353,44 +439,45 @@ 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
 
       flushInterpBuffers
+      io installSignalHandlers
       b <- isOptionSet RevertCAFs
       io (when b revertCAFs)
       return True
 
       b <- isOptionSet RevertCAFs
       io (when b revertCAFs)
       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
+
+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)
@@ -398,7 +485,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 ++ 
@@ -406,9 +493,6 @@ 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"))
-
-
 -----------------------------------------------------------------------------
 -- To flush buffers for the *interpreted* computation we need
 -- to refer to *its* stdout/stderr handles
 -----------------------------------------------------------------------------
 -- To flush buffers for the *interpreted* computation we need
 -- to refer to *its* stdout/stderr handles
@@ -416,26 +500,26 @@ noArgs c = throwDyn (CmdLineError ("command `" ++ c ++ "' takes no arguments"))
 GLOBAL_VAR(flush_interp,       error "no flush_interp", IO ())
 GLOBAL_VAR(turn_off_buffering, error "no flush_stdout", IO ())
 
 GLOBAL_VAR(flush_interp,       error "no flush_interp", IO ())
 GLOBAL_VAR(turn_off_buffering, error "no flush_stdout", IO ())
 
-no_buf_cmd = "IO.hSetBuffering IO.stdout IO.NoBuffering" ++
-            " Prelude.>> IO.hSetBuffering IO.stderr IO.NoBuffering"
-flush_cmd  = "IO.hFlush IO.stdout Prelude.>> IO.hFlush IO.stderr"
+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 :: CmState -> DynFlags -> IO CmState
-initInterpBuffering cmstate dflags
- = do (cmstate, maybe_hval) <- cmCompileExpr cmstate dflags no_buf_cmd
+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"
        
        
       case maybe_hval of
        Just hval -> writeIORef turn_off_buffering (unsafeCoerce# hval :: IO ())
        other     -> panic "interactiveUI:setBuffering"
        
-      (cmstate, maybe_hval) <- cmCompileExpr cmstate dflags flush_cmd
+      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
 
       case maybe_hval of
        Just hval -> writeIORef flush_interp (unsafeCoerce# hval :: IO ())
        _         -> panic "interactiveUI:flush"
 
       turnOffBuffering -- Turn it off right now
 
-      return cmstate
+      return ()
 
 
 flushInterpBuffers :: GHCi ()
 
 
 flushInterpBuffers :: GHCi ()
@@ -455,83 +539,65 @@ 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
-  return ()
+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)
 
 
-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 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
@@ -542,7 +608,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
@@ -550,16 +616,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 --
                    ((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)
@@ -569,71 +633,120 @@ 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
     Failed ->
        io (putStrLn (showSDoc (text "Failed, modules loaded: " <> mod_commas)))
    case ok of
     Failed ->
        io (putStrLn (showSDoc (text "Failed, modules loaded: " <> mod_commas)))
@@ -643,13 +756,22 @@ modulesLoadedMsg ok mods dflags =
 
 typeOfExpr :: String -> GHCi ()
 typeOfExpr str 
 
 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
@@ -658,7 +780,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 '" ++ moduleUserString 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 = 
@@ -668,58 +901,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
@@ -737,50 +953,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'
@@ -823,22 +1035,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 ()
@@ -852,7 +1061,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
@@ -870,12 +1079,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)
@@ -889,18 +1098,17 @@ optToStr ShowTiming = "s"
 optToStr ShowType   = "t"
 optToStr RevertCAFs = "r"
 
 optToStr ShowType   = "t"
 optToStr RevertCAFs = "r"
 
+{- ToDo
 newPackages new_pkgs = do      -- The new packages are already in v_Packages
 newPackages new_pkgs = do      -- The new packages are already in v_Packages
-  state    <- getGHCiState
-  dflags   <- io getDynFlags
-  cmstate1 <- io (cmUnload (cmstate state) dflags)
-  setGHCiState state{ cmstate = cmstate1, targets = [] }
-
-  io $ do pkgs <- getPackageInfo
-         flushPackageCache pkgs
-
+  session <- getSession
+  io (GHC.setTargets session [])
+  io (GHC.load session Nothing)
+  dflags   <- getDynFlags
+  io (linkPackages dflags new_pkgs)
   setContextAfterLoad []
   setContextAfterLoad []
+-}
 
 
------------------------------------------------------------------------------
+-- ---------------------------------------------------------------------------
 -- code for `:show'
 
 showCmd str =
 -- code for `:show'
 
 showCmd str =
@@ -911,31 +1119,32 @@ showCmd str =
        _ -> throwDyn (CmdLineError "syntax:  :show [modules|bindings]")
 
 showModules = do
        _ -> throwDyn (CmdLineError "syntax:  :show [modules|bindings]")
 
 showModules = do
-  cms <- getCmState
-  let (mg, hpt) = cmGetModInfo cms
-  mapM_ (showModule hpt) mg
-
-
-showModule :: HomePackageTable -> ModSummary -> GHCi ()
-showModule hpt mod_summary
-  = case lookupModuleEnv hpt mod of
-       Nothing       -> panic "missing linkable"
-       Just mod_info -> io (putStrLn (showModMsg obj_linkable mod locn))
-                     where
-                        obj_linkable = isObjectLinkable (hm_linkable mod_info)
-  where
-    mod = ms_mod mod_summary
-    locn = ms_location mod_summary
+  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
@@ -944,8 +1153,7 @@ data GHCiState = GHCiState
      { 
        progname       :: String,
        args           :: [String],
      { 
        progname       :: String,
        args           :: [String],
-       targets        :: [FilePath],
-       cmstate        :: CmState,
+       session        :: GHC.Session,
        options        :: [GHCiOption]
      }
 
        options        :: [GHCiOption]
      }
 
@@ -972,8 +1180,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
@@ -1003,7 +1217,7 @@ 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)
@@ -1021,26 +1235,20 @@ 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 ccall "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 == '.'
+                        text (show allocs) <+> text "bytes")))
 
 -----------------------------------------------------------------------------
 -- reverting CAFs
 
 -----------------------------------------------------------------------------
 -- reverting CAFs
@@ -1054,3 +1262,15 @@ revertCAFs = do
 
 foreign import ccall "revertCAFs" rts_revertCAFs  :: IO ()  
        -- Make it "safe", just in case
 
 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