[project @ 2004-08-13 13:04:50 by simonmar]
[ghc-hetmet.git] / ghc / compiler / ghci / InteractiveUI.hs
index 7f17397..38b2485 100644 (file)
@@ -1,51 +1,50 @@
 {-# OPTIONS -#include "Linker.h" #-}
 -----------------------------------------------------------------------------
 {-# OPTIONS -#include "Linker.h" #-}
 -----------------------------------------------------------------------------
--- $Id: InteractiveUI.hs,v 1.143 2003/02/12 15:01:35 simonpj Exp $
+-- $Id: InteractiveUI.hs,v 1.173 2004/08/13 13:06:42 simonmar Exp $
 --
 -- GHC Interactive User Interface
 --
 --
 -- GHC Interactive User Interface
 --
--- (c) The GHC Team 2000
+-- (c) The GHC Team 2004
 --
 -----------------------------------------------------------------------------
 module InteractiveUI ( 
 --
 -----------------------------------------------------------------------------
 module InteractiveUI ( 
-       interactiveUI,  -- :: CmState -> [FilePath] -> [LibrarySpec] -> IO ()
+       interactiveUI,  -- :: CmState -> [FilePath] -> IO ()
        ghciWelcomeMsg
    ) where
 
        ghciWelcomeMsg
    ) where
 
-#include "../includes/config.h"
+#include "../includes/ghcconfig.h"
 #include "HsVersions.h"
 
 import CompManager
 import HscTypes                ( TyThing(..), HomeModInfo(hm_linkable), HomePackageTable,
 #include "HsVersions.h"
 
 import CompManager
 import HscTypes                ( TyThing(..), HomeModInfo(hm_linkable), HomePackageTable,
-                         isObjectLinkable )
-import HsSyn           ( TyClDecl(..), ConDecl(..), Sig(..) )
-import MkIface         ( ifaceTyThing )
+                         isObjectLinkable, GhciMode(..) )
+import IfaceSyn                ( IfaceType, IfaceDecl(..), IfaceClassOp(..), IfaceConDecls(..), IfaceConDecl(..), 
+                         pprIfaceDeclHead, pprParendIfaceType, pprIfaceForAllPart )
+import FunDeps         ( pprFundeps )
 import DriverFlags
 import DriverState
 import DriverFlags
 import DriverState
-import DriverUtil      ( remove_spaces, handle )
-import Linker          ( initLinker, showLinkerState, linkLibraries, 
-                         linkPackages )
+import DriverUtil      ( remove_spaces )
+import Linker          ( showLinkerState, linkPackages )
 import Util
 import Util
-import Id              ( isRecordSelector, isImplicitId, recordSelectorFieldLabel, idName )
-import Class           ( className )
-import TyCon           ( tyConName, tyConClass_maybe, isPrimTyCon, DataConDetails(..) )
-import DataCon         ( dataConName )
-import FieldLabel      ( fieldLabelTyCon )
-import SrcLoc          ( isGoodSrcLoc )
 import Module          ( showModMsg, lookupModuleEnv )
 import Name            ( Name, isHomePackageName, nameSrcLoc, nameOccName,
                          NamedThing(..) )
 import Module          ( showModMsg, lookupModuleEnv )
 import Name            ( Name, isHomePackageName, nameSrcLoc, nameOccName,
                          NamedThing(..) )
-import OccName         ( isSymOcc )
-import BasicTypes      ( defaultFixity, SuccessFlag(..) )
+import OccName         ( OccName, isSymOcc, occNameUserString )
+import BasicTypes      ( StrictnessMark(..), Fixity, defaultFixity, SuccessFlag(..) )
 import Packages
 import Outputable
 import CmdLineOpts     ( DynFlag(..), DynFlags(..), getDynFlags, saveDynFlags,
                          restoreDynFlags, dopt_unset )
 import Packages
 import Outputable
 import CmdLineOpts     ( DynFlag(..), DynFlags(..), getDynFlags, saveDynFlags,
                          restoreDynFlags, dopt_unset )
-import Panic           ( GhcException(..), showGhcException )
+import Panic           hiding ( showException )
 import Config
 import Config
+import SrcLoc          ( SrcLoc, isGoodSrcLoc )
 
 
-#ifndef mingw32_TARGET_OS
+#ifndef mingw32_HOST_OS
+import DriverUtil( handle )
 import System.Posix
 import System.Posix
+#if __GLASGOW_HASKELL__ > 504
+       hiding (getEnv)
+#endif
 #endif
 
 #if HAVE_READLINE_HEADERS && HAVE_READLINE_LIBS
 #endif
 
 #if HAVE_READLINE_HEADERS && HAVE_READLINE_LIBS
@@ -61,6 +60,7 @@ import Control.Concurrent
 
 import Numeric
 import Data.List
 
 import Numeric
 import Data.List
+import Data.Int                ( Int64 )
 import System.Cmd
 import System.CPUTime
 import System.Environment
 import System.Cmd
 import System.CPUTime
 import System.Environment
@@ -73,34 +73,35 @@ import GHC.Exts             ( unsafeCoerce# )
 
 import Data.IORef      ( IORef, newIORef, readIORef, writeIORef )
 
 
 import Data.IORef      ( IORef, newIORef, readIORef, writeIORef )
 
-import GHC.Posix       ( setNonBlockingFD )
+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),
   ("set",      keepGoing setCmd),
   ("show",     keepGoing showCmd),
   ("type",     keepGoing typeOfExpr),
   ("module",   keepGoing setContext),
   ("reload",   keepGoing reloadModule),
   ("set",      keepGoing setCmd),
   ("show",     keepGoing showCmd),
   ("type",     keepGoing typeOfExpr),
+  ("kind",     keepGoing kindOfType),
   ("unset",    keepGoing unsetOptions),
   ("undef",     keepGoing undefineMacro),
   ("quit",     quit)
   ("unset",    keepGoing unsetOptions),
   ("undef",     keepGoing undefineMacro),
   ("quit",     quit)
@@ -109,79 +110,76 @@ 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
-   hFlush stdout
-   hSetBuffering stdout NoBuffering
-
+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 :: [FilePath] -> Maybe String -> IO ()
+interactiveUI srcs maybe_expr = do
    dflags <- getDynFlags
 
    dflags <- getDynFlags
 
-   initLinker
-
-       -- link packages requested explicitly on the command-line
-   expl <- readIORef v_ExplicitPackages
-   linkPackages dflags expl
+   cmstate <- cmInit Interactive dflags;
 
 
-       -- link libraries from the command-line
-   linkLibraries dflags cmdline_objs
+   hFlush stdout
+   hSetBuffering stdout NoBuffering
 
        -- Initialise buffering for the *interpreted* I/O system
 
        -- Initialise buffering for the *interpreted* I/O system
-   cmstate <- initInterpBuffering cmstate dflags
+   initInterpBuffering cmstate
 
        -- 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"]
+   cmstate <- cmSetContext cmstate [] ["Prelude"]
 
 #if HAVE_READLINE_HEADERS && HAVE_READLINE_LIBS
    Readline.initialize
 #endif
 
 
 #if HAVE_READLINE_HEADERS && HAVE_READLINE_LIBS
    Readline.initialize
 #endif
 
-   startGHCi (runGHCi paths dflags) 
+   startGHCi (runGHCi srcs dflags maybe_expr)
        GHCiState{ progname = "<interactive>",
                   args = [],
        GHCiState{ progname = "<interactive>",
                   args = [],
-                  targets = paths,
+                  targets = srcs,
                   cmstate = cmstate,
                   options = [] }
 
                   cmstate = cmstate,
                   options = [] }
 
@@ -191,8 +189,8 @@ interactiveUI cmstate paths cmdline_objs = do
 
    return ()
 
 
    return ()
 
-runGHCi :: [FilePath] -> DynFlags -> GHCi ()
-runGHCi paths dflags = do
+runGHCi :: [FilePath] -> DynFlags -> Maybe String -> GHCi ()
+runGHCi paths dflags maybe_expr = do
   read_dot_files <- io (readIORef v_Read_DotGHCi)
 
   when (read_dot_files) $ do
   read_dot_files <- io (readIORef v_Read_DotGHCi)
 
   when (read_dot_files) $ do
@@ -224,38 +222,42 @@ 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
+  -- Perform a :load for files given on the GHCi command line
   when (not (null paths)) $
      ghciHandle showException $
   when (not (null paths)) $
      ghciHandle showException $
-       loadModule (unwords paths)
+       loadModule 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
+  -- 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
-#endif
+  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
+           runCommand 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 (interactiveLoop is_tty show_prompt)
                        _other      -> return ()) $ do
 
   -- read commands from stdin
 #if HAVE_READLINE_HEADERS && HAVE_READLINE_LIBS
   if (is_tty) 
        then readlineLoop
                        _other      -> return ()) $ do
 
   -- read commands from stdin
 #if HAVE_READLINE_HEADERS && HAVE_READLINE_LIBS
   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
 
 
@@ -270,7 +272,7 @@ 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
   DriverUtil.handle (\_ -> return False) $ do
   return True
 #else
   DriverUtil.handle (\_ -> return False) $ do
@@ -352,6 +354,7 @@ runCommand c = ghciHandle handler (doCommand c)
 handler :: Exception -> GHCi Bool
 handler exception = do
   flushInterpBuffers
 handler :: Exception -> GHCi Bool
 handler exception = do
   flushInterpBuffers
+  io installSignalHandlers
   ghciHandle handler (showException exception >> return False)
 
 showException (DynException dyn) =
   ghciHandle handler (showException exception >> return False)
 
 showException (DynException dyn) =
@@ -376,10 +379,11 @@ runStmt stmt
  | otherwise
  = do st <- getGHCiState
       dflags <- io getDynFlags
  | otherwise
  = do st <- getGHCiState
       dflags <- io getDynFlags
-      let dflags' = dopt_unset dflags Opt_WarnUnusedBinds
+      let cm_state' = cmSetDFlags (cmstate st)
+                                 (dopt_unset dflags Opt_WarnUnusedBinds)
       (new_cmstate, result) <- 
        io $ withProgName (progname st) $ withArgs (args st) $
       (new_cmstate, result) <- 
        io $ withProgName (progname st) $ withArgs (args st) $
-       cmRunStmt (cmstate st) dflags' stmt
+            cmRunStmt cm_state' stmt
       setGHCiState st{cmstate = new_cmstate}
       case result of
        CmRunFailed      -> return []
       setGHCiState st{cmstate = new_cmstate}
       case result of
        CmRunFailed      -> return []
@@ -393,6 +397,7 @@ finishEvalExpr names
       when b (mapM_ (showTypeOfName cmstate) names)
 
       flushInterpBuffers
       when b (mapM_ (showTypeOfName cmstate) names)
 
       flushInterpBuffers
+      io installSignalHandlers
       b <- isOptionSet RevertCAFs
       io (when b revertCAFs)
       return True
       b <- isOptionSet RevertCAFs
       io (when b revertCAFs)
       return True
@@ -410,7 +415,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 ++ 
@@ -418,7 +423,7 @@ 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"))
 
 
 -----------------------------------------------------------------------------
 
 
 -----------------------------------------------------------------------------
@@ -432,22 +437,22 @@ 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"
 
             " Prelude.>> IO.hSetBuffering IO.stderr IO.NoBuffering"
 flush_cmd  = "IO.hFlush IO.stdout Prelude.>> IO.hFlush IO.stderr"
 
-initInterpBuffering :: CmState -> DynFlags -> IO CmState
-initInterpBuffering cmstate dflags
- = do (cmstate, maybe_hval) <- cmCompileExpr cmstate dflags no_buf_cmd
+initInterpBuffering :: CmState -> IO ()
+initInterpBuffering cmstate
+ = do maybe_hval <- cmCompileExpr cmstate 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 <- cmCompileExpr cmstate 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 ()
@@ -467,84 +472,130 @@ 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
+info "" = throwDyn (CmdLineError "syntax: ':i <thing-you-want-info-about>'")
+info s  = do { let names = words s
+            ; init_cms <- getCmState
+            ; mapM_ (infoThing init_cms) names }
+  where
+    infoThing cms name
+       = do { stuff <- io (cmInfoThing cms name)
+            ; io (putStrLn (showSDocForUser (cmGetPrintUnqual cms) $
+                  vcat (intersperse (text "") (map (showThing name) stuff)))) }
+
+showThing :: String -> (IfaceDecl, Fixity, SrcLoc) -> SDoc
+showThing name (thing, fixity, src_loc) 
+    = vcat [ showDecl (\occ -> name == occNameUserString occ) thing, 
+            showFixity fixity,
+            text "-- " <> showLoc src_loc]
+  where
+    showFixity 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 (ADataCon dc)
-       = hcat [ppr dc, text " is a data constructor", showSrcLoc (dataConName dc)]
-    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
-       | 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 ()
+       | otherwise            = ppr fix <+> text name
+
+    showLoc loc        -- The ppr function for SrcLocs is a bit wonky
+       | isGoodSrcLoc loc = ptext SLIT("Defined at") <+> ppr loc
+       | otherwise        = ppr loc
+
+-- 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 :: (OccName -> Bool) -> IfaceDecl -> SDoc
+showDecl want_name (IfaceForeign {ifName = tc})
+  = ppr tc <+> ptext SLIT("is a foreign type")
+
+showDecl want_name (IfaceId {ifName = var, ifType = ty})
+  = ppr var <+> dcolon <+> ppr ty 
+
+showDecl want_name (IfaceSyn {ifName = tycon, ifTyVars = tyvars, ifSynRhs = mono_ty})
+  = hang (ptext SLIT("type") <+> pprIfaceDeclHead [] tycon tyvars)
+       2 (equals <+> ppr mono_ty)
+
+showDecl want_name (IfaceData {ifCtxt = context, ifName = tycon, 
+                    ifTyVars = tyvars, ifCons = condecls})
+  = hang (pp_nd <+> pprIfaceDeclHead context tycon tyvars)
+       2 (add_bars (ppr_trim show_con cs))
+  where
+    show_con (IfaceConDecl con_name is_infix ex_tvs ex_cxt tys strs flds)
+       | want_name tycon || want_name con_name || any want_name flds
+       = Just (pprIfaceForAllPart ex_tvs ex_cxt (show_guts con_name is_infix tys_w_strs flds))
+       | otherwise = Nothing
+       where
+         tys_w_strs = tys `zip` (strs ++ repeat NotMarkedStrict)
+
+    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 want_name (IfaceClass {ifCtxt = context, ifName = clas, ifTyVars = tyvars, 
+                     ifFDs = fds, ifSigs = sigs})
+  = hang (ptext SLIT("class") <+> pprIfaceDeclHead context clas tyvars
+               <+> pprFundeps fds <+> ptext SLIT("where"))
+       2 (vcat (ppr_trim show_op sigs))
+  where
+    show_op (IfaceClassOp op dm ty) 
+       | want_name clas || want_name op = Just (ppr_bndr op <+> dcolon <+> ppr ty)
+       | otherwise                      = Nothing
+
+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 | isSymOcc occ = parens (ppr occ)
+            | otherwise    = ppr occ
+
+
+-----------------------------------------------------------------------------
+-- Commands
 
 
-addModule :: String -> GHCi ()
-addModule str = do
-  let files = words str
+addModule :: [FilePath] -> GHCi ()
+addModule files = do
   state <- getGHCiState
   state <- getGHCiState
-  dflags <- io (getDynFlags)
   io (revertCAFs)                      -- always revert CAFs on load/add.
   io (revertCAFs)                      -- always revert CAFs on load/add.
+  files <- mapM expandPath files
   let new_targets = files ++ targets state 
   let new_targets = files ++ targets state 
-  graph <- io (cmDepAnal (cmstate state) dflags new_targets)
-  (cmstate1, ok, mods) <- io (cmLoadModules (cmstate state) dflags graph)
+  graph <- io (cmDepAnal (cmstate state) new_targets)
+  (cmstate1, ok, mods) <- io (cmLoadModules (cmstate state) graph)
   setGHCiState state{ cmstate = cmstate1, targets = new_targets }
   setContextAfterLoad mods
   setGHCiState state{ cmstate = cmstate1, targets = new_targets }
   setContextAfterLoad mods
+  dflags <- io getDynFlags
   modulesLoadedMsg ok mods dflags
 
 changeDirectory :: String -> GHCi ()
   modulesLoadedMsg ok mods dflags
 
 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
+  state    <- getGHCiState
+  when (targets state /= []) $
+       io $ putStr "Warning: changing directory causes all loaded modules to be unloaded,\nbecause the search path has changed.\n"
+  cmstate1 <- io (cmUnload (cmstate state))
+  setGHCiState state{ cmstate = cmstate1, targets = [] }
+  setContextAfterLoad []
+  dir <- expandPath dir
+  io (setCurrentDirectory dir)
 
 defineMacro :: String -> GHCi ()
 defineMacro s = do
 
 defineMacro :: String -> GHCi ()
 defineMacro s = do
@@ -555,7 +606,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
@@ -564,9 +615,7 @@ defineMacro s = do
 
   -- compile the expression
   cms <- getCmState
 
   -- compile the expression
   cms <- getCmState
-  dflags <- io getDynFlags
-  (new_cmstate, maybe_hv) <- io (cmCompileExpr cms dflags new_expr)
-  setCmState new_cmstate
+  maybe_hv <- io (cmCompileExpr cms new_expr)
   case maybe_hv of
      Nothing -> return ()
      Just hv -> io (writeIORef commands --
   case maybe_hv of
      Nothing -> return ()
      Just hv -> io (writeIORef commands --
@@ -582,55 +631,58 @@ 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 :: [FilePath] -> GHCi ()
+loadModule fs = timeIt (loadModule' fs)
 
 
-loadModule' str = do
-  let files = words str
+loadModule' :: [FilePath] -> GHCi ()
+loadModule' files = do
   state <- getGHCiState
   state <- getGHCiState
-  dflags <- io getDynFlags
+
+  -- expand tildes
+  files <- mapM expandPath files
 
   -- do the dependency anal first, so that if it fails we don't throw
   -- away the current set of modules.
 
   -- 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)
+  graph <- io (cmDepAnal (cmstate state) files)
 
   -- Dependency anal ok, now unload everything
 
   -- Dependency anal ok, now unload everything
-  cmstate1 <- io (cmUnload (cmstate state) dflags)
+  cmstate1 <- io (cmUnload (cmstate state))
   setGHCiState state{ cmstate = cmstate1, targets = [] }
 
   io (revertCAFs)  -- always revert CAFs on load.
   setGHCiState state{ cmstate = cmstate1, targets = [] }
 
   io (revertCAFs)  -- always revert CAFs on load.
-  (cmstate2, ok, mods) <- io (cmLoadModules cmstate1 dflags graph)
+  (cmstate2, ok, mods) <- io (cmLoadModules cmstate1 graph)
   setGHCiState state{ cmstate = cmstate2, targets = files }
 
   setContextAfterLoad mods
   setGHCiState state{ cmstate = cmstate2, targets = files }
 
   setContextAfterLoad mods
+  dflags <- io (getDynFlags)
   modulesLoadedMsg ok mods dflags
 
 
 reloadModule :: String -> GHCi ()
 reloadModule "" = do
   state <- getGHCiState
   modulesLoadedMsg ok mods dflags
 
 
 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.
   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)
+       graph <- io (cmDepAnal (cmstate state) paths)
 
        io (revertCAFs)         -- always revert CAFs on reload.
        (cmstate1, ok, mods) 
 
        io (revertCAFs)         -- always revert CAFs on reload.
        (cmstate1, ok, mods) 
-               <- io (cmLoadModules (cmstate state) dflags graph)
+               <- io (cmLoadModules (cmstate state) graph)
         setGHCiState state{ cmstate=cmstate1 }
        setContextAfterLoad mods
         setGHCiState state{ cmstate=cmstate1 }
        setContextAfterLoad mods
+       dflags <- io getDynFlags
        modulesLoadedMsg ok mods dflags
 
 reloadModule _ = noArgs ":reload"
        modulesLoadedMsg ok mods dflags
 
 reloadModule _ = noArgs ":reload"
@@ -657,9 +709,15 @@ modulesLoadedMsg ok mods dflags =
 typeOfExpr :: String -> GHCi ()
 typeOfExpr str 
   = do cms <- getCmState
 typeOfExpr :: String -> GHCi ()
 typeOfExpr str 
   = do cms <- getCmState
-       dflags <- io getDynFlags
-       (new_cmstate, maybe_tystr) <- io (cmTypeOfExpr cms dflags str)
-       setCmState new_cmstate
+       maybe_tystr <- io (cmTypeOfExpr cms str)
+       case maybe_tystr of
+         Nothing    -> return ()
+         Just tystr -> io (putStrLn tystr)
+
+kindOfType :: String -> GHCi ()
+kindOfType str 
+  = do cms <- getCmState
+       maybe_tystr <- io (cmKindOfType cms str)
        case maybe_tystr of
          Nothing    -> return ()
          Just tystr -> io (putStrLn tystr)
        case maybe_tystr of
          Nothing    -> return ()
          Just tystr -> io (putStrLn tystr)
@@ -671,7 +729,7 @@ shellEscape :: String -> GHCi Bool
 shellEscape str = io (system str >> return False)
 
 -----------------------------------------------------------------------------
 shellEscape str = io (system str >> return False)
 
 -----------------------------------------------------------------------------
--- Browing a module's contents
+-- Browsing a module's contents
 
 browseCmd :: String -> GHCi ()
 browseCmd m = 
 
 browseCmd :: String -> GHCi ()
 browseCmd m = 
@@ -682,58 +740,25 @@ browseCmd m =
 
 browseModule m exports_only = do
   cms <- getCmState
 
 browseModule m exports_only = do
   cms <- getCmState
-  dflags <- io getDynFlags
 
   is_interpreted <- io (cmModuleIsInterpreted cms m)
   when (not is_interpreted && not exports_only) $
 
   is_interpreted <- io (cmModuleIsInterpreted cms m)
   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
   (as,bs) <- io (cmGetContext cms)
   -- 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)
+  cms1 <- io (if exports_only then cmSetContext cms [] [prel,m]
+                             else cmSetContext cms [m] [])
+  cms2 <- io (cmSetContext cms1 as bs)
 
 
-  (cms3, things) <- io (cmBrowseModule cms2 dflags m exports_only)
-
-  setCmState cms3
+  things <- io (cmBrowseModule cms2 m exports_only)
 
   let unqual = cmGetPrintUnqual cms1 -- NOTE: cms1 with the new context
 
 
   let unqual = cmGetPrintUnqual cms1 -- NOTE: cms1 with the new context
 
-      things' = filter wantToSee things
-
-      wantToSee (AnId id)    = not (isImplicitId id)
-      wantToSee (ADataCon _) = False   -- They'll come via their TyCon
-      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 (
   io (putStrLn (showSDocForUser unqual (
-        vcat (map (ppr . thingDecl) things')))
-   )
-
-  where
+        vcat (map (showDecl (const True)) things)
+      )))
 
 -----------------------------------------------------------------------------
 -- Setting the module context
 
 -----------------------------------------------------------------------------
 -- Setting the module context
@@ -752,17 +777,16 @@ setContext str
 
 newContext mods = do
   cms <- getCmState
 
 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
   (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')
+  cms' <- io (cmSetContext cms as bs')
   setCmState cms'
 
 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
   setCmState cms'
 
 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"))
+       else throwDyn (CmdLineError ("module '" ++ m ++ "' is not interpreted"))
 separate cmstate (m:ms)       as bs = separate cmstate ms as (m:bs)
 
 prel = "Prelude"
 separate cmstate (m:ms)       as bs = separate cmstate ms as (m:bs)
 
 prel = "Prelude"
@@ -770,7 +794,6 @@ prel = "Prelude"
 
 addToContext mods = do
   cms <- getCmState
 
 addToContext mods = do
   cms <- getCmState
-  dflags <- io getDynFlags
   (as,bs) <- io (cmGetContext cms)
 
   (as',bs') <- separate cms mods [] []
   (as,bs) <- io (cmGetContext cms)
 
   (as',bs') <- separate cms mods [] []
@@ -778,14 +801,13 @@ addToContext mods = do
   let as_to_add = as' \\ (as ++ bs)
       bs_to_add = bs' \\ (as ++ bs)
 
   let as_to_add = as' \\ (as ++ bs)
       bs_to_add = bs' \\ (as ++ bs)
 
-  cms' <- io (cmSetContext cms dflags 
+  cms' <- io (cmSetContext cms
                        (as ++ as_to_add) (bs ++ bs_to_add))
   setCmState cms'
 
 
 removeFromContext mods = do
   cms <- getCmState
                        (as ++ as_to_add) (bs ++ bs_to_add))
   setCmState cms'
 
 
 removeFromContext mods = do
   cms <- getCmState
-  dflags <- io getDynFlags
   (as,bs) <- io (cmGetContext cms)
 
   (as_to_remove,bs_to_remove) <- separate cms mods [] []
   (as,bs) <- io (cmGetContext cms)
 
   (as_to_remove,bs_to_remove) <- separate cms mods [] []
@@ -793,7 +815,7 @@ removeFromContext mods = do
   let as' = as \\ (as_to_remove ++ bs_to_remove)
       bs' = bs \\ (as_to_remove ++ bs_to_remove)
 
   let as' = as \\ (as_to_remove ++ bs_to_remove)
       bs' = bs \\ (as_to_remove ++ bs_to_remove)
 
-  cms' <- io (cmSetContext cms dflags as' bs')
+  cms' <- io (cmSetContext cms as' bs')
   setCmState cms'
 
 ----------------------------------------------------------------------------
   setCmState cms'
 
 ----------------------------------------------------------------------------
@@ -873,7 +895,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
@@ -891,12 +913,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)
@@ -912,9 +934,9 @@ optToStr RevertCAFs = "r"
 
 newPackages new_pkgs = do      -- The new packages are already in v_Packages
   state    <- getGHCiState
 
 newPackages new_pkgs = do      -- The new packages are already in v_Packages
   state    <- getGHCiState
-  dflags   <- io getDynFlags
-  cmstate1 <- io (cmUnload (cmstate state) dflags)
+  cmstate1 <- io (cmUnload (cmstate state))
   setGHCiState state{ cmstate = cmstate1, targets = [] }
   setGHCiState state{ cmstate = cmstate1, targets = [] }
+  dflags   <- io getDynFlags
   io (linkPackages dflags new_pkgs)
   setContextAfterLoad []
 
   io (linkPackages dflags new_pkgs)
   setContextAfterLoad []
 
@@ -949,7 +971,8 @@ showBindings = do
   cms <- getCmState
   let
        unqual = cmGetPrintUnqual cms
   cms <- getCmState
   let
        unqual = cmGetPrintUnqual cms
-       showBinding b = putStrLn (showSDocForUser unqual (ppr (ifaceTyThing b)))
+--     showBinding b = putStrLn (showSDocForUser unqual (ppr (ifaceTyThing b)))
+       showBinding b = putStrLn (showSDocForUser unqual (ppr (getName b)))
 
   io (mapM_ showBinding (cmGetBindings cms))
   return ()
 
   io (mapM_ showBinding (cmGetBindings cms))
   return ()
@@ -1039,18 +1062,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")))
+                        text (show allocs) <+> text "bytes")))
 
 -----------------------------------------------------------------------------
 -- reverting CAFs
 
 -----------------------------------------------------------------------------
 -- reverting CAFs
@@ -1064,3 +1089,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