[project @ 2002-02-12 15:17:13 by simonmar]
[ghc-hetmet.git] / ghc / compiler / ghci / InteractiveUI.hs
index 040f2cc..1e98d0c 100644 (file)
@@ -1,6 +1,6 @@
 {-# OPTIONS -#include "Linker.h" -#include "SchedAPI.h" #-}
 -----------------------------------------------------------------------------
 {-# OPTIONS -#include "Linker.h" -#include "SchedAPI.h" #-}
 -----------------------------------------------------------------------------
--- $Id: InteractiveUI.hs,v 1.106 2002/01/09 12:41:47 simonmar Exp $
+-- $Id: InteractiveUI.hs,v 1.113 2002/02/12 15:17:15 simonmar Exp $
 --
 -- GHC Interactive User Interface
 --
 --
 -- GHC Interactive User Interface
 --
@@ -13,28 +13,35 @@ module InteractiveUI ( interactiveUI, ghciWelcomeMsg ) where
 #include "HsVersions.h"
 
 import Packages
 #include "HsVersions.h"
 
 import Packages
+
 import CompManager
 import CompManager
-import HscTypes                ( TyThing(..) )
-import MkIface
-import ByteCodeLink
+import CmTypes         ( Linkable, isObjectLinkable, ModSummary(..) )
+import CmLink          ( findModuleLinkable_maybe )
+
+import HscTypes                ( TyThing(..), showModMsg, InteractiveContext(..) )
+import HsSyn           ( TyClDecl(..), ConDecl(..), Sig(..) )
+import MkIface         ( ifaceTyThing )
 import DriverFlags
 import DriverState
 import DriverFlags
 import DriverState
-import DriverUtil
+import DriverUtil      ( handle, remove_spaces )
 import Linker
 import Finder          ( flushPackageCache )
 import Util
 import Id              ( isRecordSelector, recordSelectorFieldLabel, 
 import Linker
 import Finder          ( flushPackageCache )
 import Util
 import Id              ( isRecordSelector, recordSelectorFieldLabel, 
-                         isDataConWrapId, idName )
+                         isDataConWrapId, isDataConId, idName )
 import Class           ( className )
 import TyCon           ( tyConName, tyConClass_maybe, isPrimTyCon )
 import FieldLabel      ( fieldLabelTyCon )
 import SrcLoc          ( isGoodSrcLoc )
 import Class           ( className )
 import TyCon           ( tyConName, tyConClass_maybe, isPrimTyCon )
 import FieldLabel      ( fieldLabelTyCon )
 import SrcLoc          ( isGoodSrcLoc )
+import Module          ( moduleName )
+import NameEnv         ( nameEnvElts )
 import Name            ( Name, isHomePackageName, nameSrcLoc, nameOccName,
                          NamedThing(..) )
 import OccName         ( isSymOcc )
 import BasicTypes      ( defaultFixity )
 import Outputable
 import Name            ( Name, isHomePackageName, nameSrcLoc, nameOccName,
                          NamedThing(..) )
 import OccName         ( isSymOcc )
 import BasicTypes      ( defaultFixity )
 import Outputable
-import CmdLineOpts     ( DynFlag(..), getDynFlags, saveDynFlags, restoreDynFlags, dopt_unset )
+import CmdLineOpts     ( DynFlag(..), DynFlags(..), getDynFlags, saveDynFlags,
+                         restoreDynFlags, dopt_unset )
 import Panic           ( GhcException(..), showGhcException )
 import Config
 
 import Panic           ( GhcException(..), showGhcException )
 import Config
 
@@ -58,9 +65,10 @@ import CPUTime
 import Directory
 import IO
 import Char
 import Directory
 import IO
 import Char
-import Monad           ( when, join )
+import Monad
+
+import GlaExts         ( unsafeCoerce# )
 
 
-import PrelGHC                 ( unsafeCoerce# )
 import Foreign         ( nullPtr )
 import CString         ( peekCString )
 
 import Foreign         ( nullPtr )
 import CString         ( peekCString )
 
@@ -78,16 +86,17 @@ GLOBAL_VAR(commands, builtin_commands, [(String, String -> GHCi Bool)])
 builtin_commands :: [(String, String -> GHCi Bool)]
 builtin_commands = [
   ("add",      keepGoing addModule),
 builtin_commands :: [(String, String -> GHCi Bool)]
 builtin_commands = [
   ("add",      keepGoing addModule),
+  ("browse",    keepGoing browseCmd),
   ("cd",       keepGoing changeDirectory),
   ("def",      keepGoing defineMacro),
   ("help",     keepGoing help),
   ("?",                keepGoing help),
   ("info",      keepGoing info),
   ("cd",       keepGoing changeDirectory),
   ("def",      keepGoing defineMacro),
   ("help",     keepGoing help),
   ("?",                keepGoing help),
   ("info",      keepGoing info),
-  ("import",    keepGoing importModules),
   ("load",     keepGoing loadModule),
   ("module",   keepGoing setContext),
   ("reload",   keepGoing reloadModule),
   ("set",      keepGoing setCmd),
   ("load",     keepGoing loadModule),
   ("module",   keepGoing setContext),
   ("reload",   keepGoing reloadModule),
   ("set",      keepGoing setCmd),
+  ("show",     keepGoing showCmd),
   ("type",     keepGoing typeOfExpr),
   ("unset",    keepGoing unsetOptions),
   ("undef",     keepGoing undefineMacro),
   ("type",     keepGoing typeOfExpr),
   ("unset",    keepGoing unsetOptions),
   ("undef",     keepGoing undefineMacro),
@@ -104,6 +113,7 @@ helpText = "\
 \\
 \   <stmt>                evaluate/run <stmt>\n\ 
 \   :add <filename> ...    add module(s) to the current target set\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\ 
 \   :cd <dir>             change directory to <dir>\n\ 
 \   :def <cmd> <expr>      define a command :<cmd>\n\ 
 \   :help, :?             display this list of commands\n\ 
@@ -111,11 +121,16 @@ helpText = "\
 \   :load <filename> ...   load module(s) and their dependents\n\ 
 \   :module <mod>         set the context for expression evaluation to <mod>\n\ 
 \   :reload               reload the current module set\n\ 
 \   :load <filename> ...   load module(s) and their dependents\n\ 
 \   :module <mod>         set the context for expression evaluation to <mod>\n\ 
 \   :reload               reload the current module set\n\ 
+\\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\ 
 \   :set <option> ...     set options\n\ 
 \   :set args <arg> ...           set the arguments returned by System.getArgs\n\ 
 \   :set prog <progname>   set the value returned by System.getProgName\n\ 
-\   :undef <cmd>          undefine user-defined command :<cmd>\n\ 
+\\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\ 
 \   :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\ 
 \   :unset <option> ...           unset options\n\ 
 \   :quit                 exit GHCi\n\ 
 \   :!<command>                   run the shell command <command>\n\ 
@@ -134,12 +149,12 @@ interactiveUI cmstate paths cmdline_libs = do
    hFlush stdout
    hSetBuffering stdout NoBuffering
 
    hFlush stdout
    hSetBuffering stdout NoBuffering
 
+   dflags <- getDynFlags
+
    -- link in the available packages
    pkgs <- getPackageInfo
    initLinker
    -- link in the available packages
    pkgs <- getPackageInfo
    initLinker
-   linkPackages cmdline_libs pkgs
-
-   dflags <- getDynFlags
+   linkPackages dflags cmdline_libs pkgs
 
    (cmstate, maybe_hval) 
        <- cmCompileExpr cmstate dflags "IO.hSetBuffering IO.stdout IO.NoBuffering Prelude.>> IO.hSetBuffering IO.stderr IO.NoBuffering"
 
    (cmstate, maybe_hval) 
        <- cmCompileExpr cmstate dflags "IO.hSetBuffering IO.stdout IO.NoBuffering Prelude.>> IO.hSetBuffering IO.stderr IO.NoBuffering"
@@ -159,6 +174,10 @@ interactiveUI cmstate paths cmdline_libs = do
        Just hval -> writeIORef flush_stdout (unsafeCoerce# hval :: IO ())
        _ -> panic "interactiveUI:stdout"
 
        Just hval -> writeIORef flush_stdout (unsafeCoerce# hval :: IO ())
        _ -> panic "interactiveUI:stdout"
 
+       -- We don't want the cmd line to buffer any input that might be
+       -- intended for the program, so unbuffer stdin.
+   hSetBuffering stdin  NoBuffering
+
        -- initial context is just the Prelude
    cmstate <- cmSetContext cmstate dflags [] ["Prelude"]
 
        -- initial context is just the Prelude
    cmstate <- cmSetContext cmstate dflags [] ["Prelude"]
 
@@ -166,7 +185,7 @@ interactiveUI cmstate paths cmdline_libs = do
    Readline.initialize
 #endif
 
    Readline.initialize
 #endif
 
-   startGHCi (runGHCi paths) 
+   startGHCi (runGHCi paths dflags) 
        GHCiState{ progname = "<interactive>",
                   args = [],
                   targets = paths,
        GHCiState{ progname = "<interactive>",
                   args = [],
                   targets = paths,
@@ -180,8 +199,8 @@ interactiveUI cmstate paths cmdline_libs = do
    return ()
 
 
    return ()
 
 
-runGHCi :: [FilePath] -> GHCi ()
-runGHCi paths = do
+runGHCi :: [FilePath] -> DynFlags -> GHCi ()
+runGHCi paths dflags = 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
@@ -219,20 +238,24 @@ runGHCi paths = do
        loadModule (unwords paths)
 
   -- enter the interactive loop
        loadModule (unwords paths)
 
   -- enter the interactive loop
-  interactiveLoop
+  is_tty <- io (hIsTerminalDevice stdin)
+  interactiveLoop is_tty
 
   -- and finally, exit
 
   -- and finally, exit
-  io $ do putStrLn "Leaving GHCi."
+  io $ do when (verbosity dflags > 0) $ putStrLn "Leaving GHCi."
 
 
 
 
-interactiveLoop = do
+interactiveLoop is_tty = do
   -- ignore ^C exceptions caught here
   -- ignore ^C exceptions caught here
-  ghciHandleDyn (\e -> case e of Interrupted -> ghciUnblock interactiveLoop
-                                _other      -> return ()) $ do
+  ghciHandleDyn (\e -> case e of 
+                       Interrupted -> ghciUnblock (interactiveLoop is_tty)
+                       _other      -> return ()) $ do
 
   -- read commands from stdin
 #if HAVE_READLINE_HEADERS && HAVE_READLINE_LIBS
 
   -- read commands from stdin
 #if HAVE_READLINE_HEADERS && HAVE_READLINE_LIBS
-  readlineLoop
+  if (is_tty) 
+       then readlineLoop
+       else fileLoop stdin False  -- turn off prompt for non-TTY input
 #else
   fileLoop stdin True
 #endif
 #else
   fileLoop stdin True
 #endif
@@ -249,7 +272,7 @@ interactiveLoop = do
 
 checkPerms :: String -> IO Bool
 checkPerms name =
 
 checkPerms :: String -> IO Bool
 checkPerms name =
-  handle (\_ -> return False) $ do
+  DriverUtil.handle (\_ -> return False) $ do
 #ifdef mingw32_TARGET_OS
      doesFileExist name
 #else
 #ifdef mingw32_TARGET_OS
      doesFileExist name
 #else
@@ -271,8 +294,8 @@ checkPerms name =
 
 fileLoop :: Handle -> Bool -> GHCi ()
 fileLoop hdl prompt = do
 
 fileLoop :: Handle -> Bool -> GHCi ()
 fileLoop hdl prompt = do
-   st <- getGHCiState
-   (mod,imports) <- io (cmGetContext (cmstate st))
+   cmstate <- getCmState
+   (mod,imports) <- io (cmGetContext cmstate)
    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
@@ -287,24 +310,19 @@ fileLoop hdl prompt = do
 stringLoop :: [String] -> GHCi ()
 stringLoop [] = return ()
 stringLoop (s:ss) = do
 stringLoop :: [String] -> GHCi ()
 stringLoop [] = return ()
 stringLoop (s:ss) = do
-   st <- getGHCiState
    case remove_spaces s of
        "" -> stringLoop ss
        l  -> do quit <- runCommand l
                  if quit then return () else stringLoop ss
 
 mkPrompt toplevs exports
    case remove_spaces s of
        "" -> stringLoop ss
        l  -> do quit <- runCommand l
                  if quit then return () else stringLoop ss
 
 mkPrompt toplevs exports
-   =  concat (intersperse "," toplevs)
-   ++ (if not (null exports) 
-       then "[" ++ concat (intersperse "," exports) ++ "]" 
-       else "")
-   ++ "> "
+   = concat (intersperse " " (toplevs ++ map ('*':) exports)) ++ "> "
 
 #if HAVE_READLINE_HEADERS && HAVE_READLINE_LIBS
 readlineLoop :: GHCi ()
 readlineLoop = do
 
 #if HAVE_READLINE_HEADERS && HAVE_READLINE_LIBS
 readlineLoop :: GHCi ()
 readlineLoop = do
-   st <- getGHCiState
-   (mod,imports) <- io (cmGetContext (cmstate st))
+   cmstate <- getCmState
+   (mod,imports) <- io (cmGetContext cmstate)
    io yield
    l <- io (readline (mkPrompt mod imports))
    case l of
    io yield
    l <- io (readline (mkPrompt mod imports))
    case l of
@@ -359,14 +377,13 @@ runStmt stmt
       case result of
        CmRunFailed      -> return []
        CmRunException e -> showException e >> return []
       case result of
        CmRunFailed      -> return []
        CmRunException e -> showException e >> return []
-       CmRunDeadlocked  -> io (putStrLn "Deadlocked.") >> return []
        CmRunOk names    -> return names
 
 -- possibly print the type and revert CAFs after evaluating an expression
 finishEvalExpr names
  = do b <- isOptionSet ShowType
        CmRunOk names    -> return names
 
 -- possibly print the type and revert CAFs after evaluating an expression
 finishEvalExpr names
  = do b <- isOptionSet ShowType
-      st <- getGHCiState
-      when b (mapM_ (showTypeOfName (cmstate st)) names)
+      cmstate <- getCmState
+      when b (mapM_ (showTypeOfName cmstate) names)
 
       b <- isOptionSet RevertCAFs
       io (when b revertCAFs)
 
       b <- isOptionSet RevertCAFs
       io (when b revertCAFs)
@@ -412,17 +429,19 @@ info :: String -> GHCi ()
 info "" = throwDyn (CmdLineError "syntax: `:i <thing-you-want-info-about>'")
 info s = do
   let names = words s
 info "" = throwDyn (CmdLineError "syntax: `:i <thing-you-want-info-about>'")
 info s = do
   let names = words s
-  state <- getGHCiState
+  init_cms <- getCmState
   dflags <- io getDynFlags
   let 
     infoThings cms [] = return cms
     infoThings cms (name:names) = do
   dflags <- io getDynFlags
   let 
     infoThings cms [] = return cms
     infoThings cms (name:names) = do
-      (cms, unqual, stuff) <- io (cmInfoThing cms dflags name)
+      (cms, stuff) <- io (cmInfoThing cms dflags name)
       io (putStrLn (showSDocForUser unqual (
            vcat (intersperse (text "") (map showThing stuff))))
          )
       infoThings cms names
 
       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),
     showThing (ty_thing, fixity) 
        = vcat [ text "-- " <> showTyThing ty_thing, 
                 showFixity fixity (getName ty_thing),
@@ -462,8 +481,8 @@ info s = do
        = empty
        where loc = nameSrcLoc name
 
        = empty
        where loc = nameSrcLoc name
 
-  cms <- infoThings (cmstate state) names
-  setGHCiState state{ cmstate = cms }
+  cms <- infoThings init_cms names
+  setCmState cms
   return ()
 
 addModule :: String -> GHCi ()
   return ()
 
 addModule :: String -> GHCi ()
@@ -477,7 +496,7 @@ addModule str = do
   (cmstate1, ok, mods) <- io (cmLoadModules (cmstate state) dflags graph)
   setGHCiState state{ cmstate = cmstate1, targets = new_targets }
   setContextAfterLoad mods
   (cmstate1, ok, mods) <- io (cmLoadModules (cmstate state) dflags graph)
   setGHCiState state{ cmstate = cmstate1, targets = new_targets }
   setContextAfterLoad mods
-  modulesLoadedMsg ok mods
+  modulesLoadedMsg ok mods dflags
 
 changeDirectory :: String -> GHCi ()
 changeDirectory ('~':d) = do
 
 changeDirectory :: String -> GHCi ()
 changeDirectory ('~':d) = do
@@ -502,10 +521,10 @@ defineMacro s = do
   let new_expr = '(' : definition ++ ") :: String -> IO String"
 
   -- compile the expression
   let new_expr = '(' : definition ++ ") :: String -> IO String"
 
   -- compile the expression
-  st <- getGHCiState
+  cms <- getCmState
   dflags <- io getDynFlags
   dflags <- io getDynFlags
-  (new_cmstate, maybe_hv) <- io (cmCompileExpr (cmstate st) dflags new_expr)
-  setGHCiState st{cmstate = new_cmstate}
+  (new_cmstate, maybe_hv) <- io (cmCompileExpr cms dflags new_expr)
+  setCmState new_cmstate
   case maybe_hv of
      Nothing -> return ()
      Just hv -> io (writeIORef commands --
   case maybe_hv of
      Nothing -> return ()
      Just hv -> io (writeIORef commands --
@@ -530,10 +549,6 @@ undefineMacro macro_name = do
   io (writeIORef commands (filter ((/= macro_name) . fst) cmds))
 
 
   io (writeIORef commands (filter ((/= macro_name) . fst) cmds))
 
 
-importModules :: String -> GHCi ()
-importModules str = return ()
-
-
 loadModule :: String -> GHCi ()
 loadModule str = timeIt (loadModule' str)
 
 loadModule :: String -> GHCi ()
 loadModule str = timeIt (loadModule' str)
 
@@ -555,7 +570,7 @@ loadModule' str = do
   setGHCiState state{ cmstate = cmstate2, targets = files }
 
   setContextAfterLoad mods
   setGHCiState state{ cmstate = cmstate2, targets = files }
 
   setContextAfterLoad mods
-  modulesLoadedMsg ok mods
+  modulesLoadedMsg ok mods dflags
 
 
 reloadModule :: String -> GHCi ()
 
 
 reloadModule :: String -> GHCi ()
@@ -574,19 +589,23 @@ reloadModule "" = do
                <- io (cmLoadModules (cmstate state) dflags graph)
         setGHCiState state{ cmstate=cmstate1 }
        setContextAfterLoad mods
                <- io (cmLoadModules (cmstate state) dflags graph)
         setGHCiState state{ cmstate=cmstate1 }
        setContextAfterLoad mods
-       modulesLoadedMsg ok mods
+       modulesLoadedMsg ok mods dflags
 
 reloadModule _ = noArgs ":reload"
 
 setContextAfterLoad [] = setContext prel
 
 reloadModule _ = noArgs ":reload"
 
 setContextAfterLoad [] = setContext prel
-setContextAfterLoad (m:_) = setContext m
-
-modulesLoadedMsg ok mods = do
-  let mod_commas 
+setContextAfterLoad (m:_) = do
+  cmstate <- getCmState
+  b <- io (cmModuleIsInterpreted cmstate m)
+  if b then setContext m else setContext ('*':m)
+
+modulesLoadedMsg ok mods dflags =
+  when (verbosity dflags > 0) $ do
+   let mod_commas 
        | null mods = text "none."
        | otherwise = hsep (
            punctuate comma (map text mods)) <> text "."
        | null mods = text "none."
        | otherwise = hsep (
            punctuate comma (map text mods)) <> text "."
-  case ok of
+   case ok of
     False -> 
        io (putStrLn (showSDoc (text "Failed, modules loaded: " <> mod_commas)))
     True  -> 
     False -> 
        io (putStrLn (showSDoc (text "Failed, modules loaded: " <> mod_commas)))
     True  -> 
@@ -595,10 +614,10 @@ modulesLoadedMsg ok mods = do
 
 typeOfExpr :: String -> GHCi ()
 typeOfExpr str 
 
 typeOfExpr :: String -> GHCi ()
 typeOfExpr str 
-  = do st <- getGHCiState
+  = do cms <- getCmState
        dflags <- io getDynFlags
        dflags <- io getDynFlags
-       (new_cmstate, maybe_tystr) <- io (cmTypeOfExpr (cmstate st) dflags str)
-       setGHCiState st{cmstate = new_cmstate}
+       (new_cmstate, maybe_tystr) <- io (cmTypeOfExpr cms dflags str)
+       setCmState new_cmstate
        case maybe_tystr of
          Nothing    -> return ()
          Just tystr -> io (putStrLn tystr)
        case maybe_tystr of
          Nothing    -> return ()
          Just tystr -> io (putStrLn tystr)
@@ -610,60 +629,129 @@ shellEscape :: String -> GHCi Bool
 shellEscape str = io (system str >> return False)
 
 -----------------------------------------------------------------------------
 shellEscape str = io (system str >> return False)
 
 -----------------------------------------------------------------------------
+-- Browing a module's contents
+
+browseCmd :: String -> GHCi ()
+browseCmd m = 
+  case words m of
+    ['*':m] | looksLikeModuleName m -> browseModule m True
+    [m]     | looksLikeModuleName m -> browseModule m False
+    _ -> throwDyn (CmdLineError "syntax:  :browse <module>")
+
+browseModule m exports_only = do
+  cms <- getCmState
+  dflags <- io getDynFlags
+
+  is_interpreted <- io (cmModuleIsInterpreted cms m)
+  when (not is_interpreted && not exports_only) $
+       throwDyn (CmdLineError ("module `" ++ m ++ "' is not interpreted"))
+
+  -- temporarily set the context to the module we're interested in,
+  -- just so we can get an appropriate PrintUnqualified
+  (as,bs) <- io (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 = cons } -> 
+               rn_decl{ tcdCons = filter conIsVisible cons }
+         other -> other
+        where
+         conIsVisible (ConDecl n _ _ _ _ _) = n `elem` thing_names
+
+  io (putStrLn (showSDocForUser unqual (
+        vcat (map (ppr . thingDecl) things')))
+   )
+
+  where
+
+-----------------------------------------------------------------------------
 -- Setting the module context
 
 setContext str
 -- Setting the module context
 
 setContext str
- | all sensible  mods = newContext mods        -- default is to set the empty context
- | all plusminus mods = adjustContext mods
- | otherwise
-   = throwDyn (CmdLineError "syntax:  :module M1 .. Mn | :module [+/-]M1 ... [+/-]Mn")
- where
-    mods = words str
+  | all sensible mods = fn mods
+  | otherwise = throwDyn (CmdLineError "syntax:  :module [+/-] [*]M1 ... [*]Mn")
+  where
+    (fn, mods) = case str of 
+                       '+':stuff -> (addToContext,      words stuff)
+                       '-':stuff -> (removeFromContext, words stuff)
+                       stuff     -> (newContext,        words stuff) 
 
 
-    sensible (c:cs) = isUpper c && all isAlphaNumEx cs
-    isAlphaNumEx c = isAlphaNum c || c == '_'
-
-    plusminus ('-':mod) = sensible mod
-    plusminus ('+':mod) = sensible mod
-    plusminus _ = False
+    sensible ('*':m) = looksLikeModuleName m
+    sensible m       = looksLikeModuleName m
 
 newContext mods = do
 
 newContext mods = do
-  state@GHCiState{cmstate=cmstate} <- getGHCiState
+  cms <- getCmState
   dflags <- io getDynFlags
   dflags <- io getDynFlags
-
-  let separate [] as bs = return (as,bs)
-      separate (m:ms) as bs = do 
-        b <- io (cmModuleIsInterpreted cmstate m)
-        if b then separate ms (m:as) bs
-             else separate ms as (m:bs)
-                               
-  (as,bs) <- separate mods [] []
+  (as,bs) <- separate cms mods [] []
   let bs' = if null as && prel `notElem` bs then prel:bs else bs
   let bs' = if null as && prel `notElem` bs then prel:bs else bs
-  cmstate' <- io (cmSetContext cmstate dflags as bs')
-  setGHCiState state{cmstate=cmstate'}
-
+  cms' <- io (cmSetContext cms dflags as bs')
+  setCmState cms'
+
+separate cmstate []           as bs = return (as,bs)
+separate cmstate (('*':m):ms) as bs = separate cmstate ms as (m: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"))
+       
 prel = "Prelude"
 
 prel = "Prelude"
 
-adjustContext mods = do
-  state@GHCiState{cmstate=cmstate} <- getGHCiState
+
+addToContext mods = do
+  cms <- getCmState
   dflags <- io getDynFlags
   dflags <- io getDynFlags
+  (as,bs) <- io (cmGetContext cms)
 
 
-  let adjust [] as bs = return (as,bs)
-      adjust (('-':m) : ms) as bs
-       | m `elem` as  = adjust ms (delete m as) bs
-       | m `elem` bs  = adjust ms as (delete m bs)
-       | otherwise = throwDyn (CmdLineError ("module `" ++ m ++ "' is not currently in scope"))
-      adjust (('+':m) : ms) as bs
-       | m `elem` as || m `elem` bs = adjust ms as bs -- continue silently
-       | otherwise = do b <- io (cmModuleIsInterpreted cmstate m)
-                        if b then adjust ms (m:as) bs
-                             else adjust ms as (m:bs)
-
-  (as,bs) <- io (cmGetContext cmstate)
-  (as,bs) <- adjust mods as bs
-  let bs' = if null as && prel `notElem` bs then prel:bs else bs
-  cmstate' <- io (cmSetContext cmstate dflags as bs')
-  setGHCiState state{cmstate=cmstate'}
+  (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'
+
+
+removeFromContext mods = do
+  cms <- getCmState
+  dflags <- io getDynFlags
+  (as,bs) <- io (cmGetContext 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)
+
+  cms' <- io (cmSetContext cms dflags as' bs')
+  setCmState cms'
 
 ----------------------------------------------------------------------------
 -- Code for `:set'
 
 ----------------------------------------------------------------------------
 -- Code for `:set'
@@ -783,7 +871,39 @@ newPackages new_pkgs = do
     flushPackageCache pkgs
    
     new_pkg_info <- getPackageDetails new_pkgs
     flushPackageCache pkgs
    
     new_pkg_info <- getPackageDetails new_pkgs
-    mapM_ linkPackage (reverse new_pkg_info)
+    mapM_ (linkPackage dflags) (reverse new_pkg_info)
+
+-----------------------------------------------------------------------------
+-- code for `:show'
+
+showCmd str =
+  case words str of
+       ["modules" ] -> showModules
+       ["bindings"] -> showBindings
+       _ -> throwDyn (CmdLineError "syntax:  :show [modules|bindings]")
+
+showModules = do
+  cms <- getCmState
+  let mg = cmGetModuleGraph cms
+      ls = cmGetLinkables   cms
+      maybe_linkables = map (findModuleLinkable_maybe ls) 
+                               (map (moduleName.ms_mod) mg)
+  zipWithM showModule mg maybe_linkables
+  return ()
+
+showModule :: ModSummary -> Maybe Linkable -> GHCi ()
+showModule m (Just l) = do
+  io (putStrLn (showModMsg (isObjectLinkable l) (ms_mod m) (ms_location m)))
+showModule _ Nothing = panic "missing linkable"
+
+showBindings = do
+  cms <- getCmState
+  let
+       unqual = cmGetPrintUnqual cms
+       showBinding b = putStrLn (showSDocForUser unqual (ppr (ifaceTyThing b)))
+
+  io (mapM showBinding (cmGetBindings cms))
+  return ()
 
 -----------------------------------------------------------------------------
 -- GHCi monad
 
 -----------------------------------------------------------------------------
 -- GHCi monad
@@ -822,6 +942,10 @@ ghciHandleDyn h (GHCi m) = GHCi $ \s ->
 getGHCiState   = GHCi $ \r -> readIORef r
 setGHCiState s = GHCi $ \r -> writeIORef r s
 
 getGHCiState   = GHCi $ \r -> readIORef r
 setGHCiState s = GHCi $ \r -> writeIORef r s
 
+-- for convenience...
+getCmState = getGHCiState >>= return . cmstate
+setCmState cms = do s <- getGHCiState; setGHCiState s{cmstate=cms}
+
 isOptionSet :: GHCiOption -> GHCi Bool
 isOptionSet opt
  = do st <- getGHCiState
 isOptionSet :: GHCiOption -> GHCi Bool
 isOptionSet opt
  = do st <- getGHCiState
@@ -874,26 +998,27 @@ type LibrarySpec
 showLS (Left nm)  = "(static) " ++ nm
 showLS (Right nm) = "(dynamic) " ++ nm
 
 showLS (Left nm)  = "(static) " ++ nm
 showLS (Right nm) = "(dynamic) " ++ nm
 
-linkPackages :: [LibrarySpec] -> [PackageConfig] -> IO ()
-linkPackages cmdline_lib_specs pkgs
-   = do mapM_ linkPackage (reverse pkgs)
+linkPackages :: DynFlags -> [LibrarySpec] -> [PackageConfig] -> IO ()
+linkPackages dflags cmdline_lib_specs pkgs
+   = do mapM_ (linkPackage dflags) (reverse pkgs)
         lib_paths <- readIORef v_Library_paths
         lib_paths <- readIORef v_Library_paths
-        mapM_ (preloadLib lib_paths) cmdline_lib_specs
+        mapM_ (preloadLib dflags lib_paths) cmdline_lib_specs
        if (null cmdline_lib_specs)
           then return ()
        if (null cmdline_lib_specs)
           then return ()
-          else do putStr "final link ... "
+          else do maybePutStr dflags "final link ... "
                   ok <- resolveObjs
                   ok <- resolveObjs
-                  if ok then putStrLn "done."
+                  if ok then maybePutStrLn dflags "done."
                         else throwDyn (InstallationError 
                                           "linking extra libraries/objects failed")
      where
                         else throwDyn (InstallationError 
                                           "linking extra libraries/objects failed")
      where
-        preloadLib :: [String] -> LibrarySpec -> IO ()
-        preloadLib lib_paths lib_spec
-           = do putStr ("Loading object " ++ showLS lib_spec ++ " ... ")
+        preloadLib :: DynFlags -> [String] -> LibrarySpec -> IO ()
+        preloadLib dflags lib_paths lib_spec
+           = do maybePutStr dflags ("Loading object " ++ showLS lib_spec ++ " ... ")
                 case lib_spec of
                    Left static_ish
                       -> do b <- preload_static lib_paths static_ish
                 case lib_spec of
                    Left static_ish
                       -> do b <- preload_static lib_paths static_ish
-                            putStrLn (if b then "done." else "not found")
+                            maybePutStrLn dflags (if b  then "done." 
+                                                       else "not found")
                    Right dll_unadorned
                       -> -- We add "" to the set of paths to try, so that
                          -- if none of the real paths match, we force addDLL
                    Right dll_unadorned
                       -> -- We add "" to the set of paths to try, so that
                          -- if none of the real paths match, we force addDLL
@@ -903,11 +1028,12 @@ linkPackages cmdline_lib_specs pkgs
                             case maybe_errstr of
                                Nothing -> return ()
                                Just mm -> preloadFailed mm lib_paths lib_spec
                             case maybe_errstr of
                                Nothing -> return ()
                                Just mm -> preloadFailed mm lib_paths lib_spec
-                            putStrLn "done"
+                            maybePutStrLn dflags "done"
 
         preloadFailed :: String -> [String] -> LibrarySpec -> IO ()
         preloadFailed sys_errmsg paths spec
 
         preloadFailed :: String -> [String] -> LibrarySpec -> IO ()
         preloadFailed sys_errmsg paths spec
-           = do putStr ("failed.\nDynamic linker error message was:\n   " 
+           = do maybePutStr dflags
+                      ("failed.\nDynamic linker error message was:\n   " 
                         ++ sys_errmsg  ++ "\nWhilst trying to load:  " 
                         ++ showLS spec ++ "\nDirectories to search are:\n"
                         ++ unlines (map ("   "++) paths) )
                         ++ sys_errmsg  ++ "\nWhilst trying to load:  " 
                         ++ showLS spec ++ "\nDirectories to search are:\n"
                         ++ unlines (map ("   "++) paths) )
@@ -948,8 +1074,8 @@ loaded_in_ghci
           = [ ]
 #          endif
 
           = [ ]
 #          endif
 
-linkPackage :: PackageConfig -> IO ()
-linkPackage pkg
+linkPackage :: DynFlags -> PackageConfig -> IO ()
+linkPackage dflags pkg
    | name pkg `elem` dont_load_these = return ()
    | otherwise
    = do 
    | name pkg `elem` dont_load_these = return ()
    | otherwise
    = do 
@@ -965,11 +1091,11 @@ linkPackage pkg
         let sos_first | name pkg `elem` loaded_in_ghci = obj_libs
                      | otherwise                      = so_libs ++ obj_libs
 
         let sos_first | name pkg `elem` loaded_in_ghci = obj_libs
                      | otherwise                      = so_libs ++ obj_libs
 
-       putStr ("Loading package " ++ name pkg ++ " ... ")
+       maybePutStr dflags ("Loading package " ++ name pkg ++ " ... ")
         mapM loadClassified sos_first
         mapM loadClassified sos_first
-        putStr "linking ... "
+        maybePutStr dflags "linking ... "
         ok <- resolveObjs
         ok <- resolveObjs
-       if ok then putStrLn "done."
+       if ok then maybePutStrLn dflags "done."
              else panic ("can't load package `" ++ name pkg ++ "'")
      where
         isRight (Right _) = True
              else panic ("can't load package `" ++ name pkg ++ "'")
      where
         isRight (Right _) = True
@@ -1021,6 +1147,20 @@ printTimes allocs psecs
                         int allocs <+> text "bytes")))
 
 -----------------------------------------------------------------------------
                         int allocs <+> text "bytes")))
 
 -----------------------------------------------------------------------------
+-- utils
+
+looksLikeModuleName [] = False
+looksLikeModuleName (c:cs) = isUpper c && all isAlphaNumEx cs
+
+isAlphaNumEx c = isAlphaNum c || c == '_'
+
+maybePutStr dflags s | verbosity dflags > 0 = putStr s
+                    | otherwise            = return ()
+
+maybePutStrLn dflags s | verbosity dflags > 0 = putStrLn s
+                      | otherwise            = return ()
+
+-----------------------------------------------------------------------------
 -- reverting CAFs
        
 foreign import revertCAFs :: IO ()     -- make it "safe", just in case
 -- reverting CAFs
        
 foreign import revertCAFs :: IO ()     -- make it "safe", just in case