Sort names before printing them in the debugger so output order is consistent
[ghc-hetmet.git] / compiler / ghci / InteractiveUI.hs
index 74133dd..4494f22 100644 (file)
@@ -6,10 +6,7 @@
 -- (c) The GHC Team 2005-2006
 --
 -----------------------------------------------------------------------------
-module InteractiveUI ( 
-       interactiveUI,
-       ghciWelcomeMsg
-   ) where
+module InteractiveUI ( interactiveUI ) where
 
 #include "HsVersions.h"
 
@@ -21,7 +18,7 @@ import Debugger
 import qualified GHC
 import GHC              ( Session, LoadHowMuch(..), Target(..),  TargetId(..),
                           Type, Module, ModuleName, TyThing(..), Phase,
-                          BreakIndex, Name, SrcSpan, Resume, SingleStep )
+                          BreakIndex, SrcSpan, Resume, SingleStep )
 import DynFlags
 import Packages
 import PackageConfig
@@ -29,6 +26,7 @@ import UniqFM
 import PprTyThing
 import Outputable       hiding (printForUser)
 import Module           -- for ModuleEnv
+import Name
 
 -- Other random utilities
 import Digraph
@@ -41,10 +39,7 @@ import Util
 import FastString
 
 #ifndef mingw32_HOST_OS
-import System.Posix
-#if __GLASGOW_HASKELL__ > 504
-       hiding (getEnv)
-#endif
+import System.Posix hiding (getEnv)
 #else
 import GHC.ConsoleHandler ( flushConsole )
 import System.Win32      ( setConsoleCP, setConsoleOutputCP )
@@ -70,7 +65,6 @@ import System.Exit    ( exitWith, ExitCode(..) )
 import System.Directory
 import System.IO
 import System.IO.Error as IO
-import System.FilePath
 import Data.Char
 import Data.Dynamic
 import Data.Array
@@ -94,6 +88,10 @@ ghciWelcomeMsg =
  "/ /_\\\\/ __  / /___| |    http://www.haskell.org/ghc/\n"++
  "\\____/\\/ /_/\\____/|_|    Type :? for help.\n"
 
+ghciShortWelcomeMsg =
+    "GHCi, version " ++ cProjectVersion ++
+    ": http://www.haskell.org/ghc/  :? for help"
+
 type Command = (String, String -> GHCi Bool, Bool, String -> IO [String])
 cmdName (n,_,_,_) = n
 
@@ -156,7 +154,7 @@ helpText =
  "   :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" ++
- "   :cmd <expr>                 run the commands returned by <expr>::IO String"++
+ "   :cmd <expr>                 run the commands returned by <expr>::IO String\n" ++
  "   :ctags [<file>]             create tags file for Vi (default: \"tags\")\n" ++
  "   :def <cmd> <expr>           define a command :<cmd>\n" ++
  "   :edit <file>                edit file\n" ++
@@ -245,21 +243,22 @@ interactiveUI session srcs maybe_expr = do
    newStablePtr stdout
    newStablePtr stderr
 
-       -- Initialise buffering for the *interpreted* I/O system
+    -- Initialise buffering for the *interpreted* I/O system
    initInterpBuffering session
 
    when (isNothing maybe_expr) $ do
-       -- Only for GHCi (not runghc and ghc -e):
-       -- Turn buffering off for the compiled program's stdout/stderr
-       turnOffBuffering
-       -- Turn buffering off for GHCi's stdout
-       hFlush stdout
-       hSetBuffering stdout NoBuffering
-       -- 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
+        -- Only for GHCi (not runghc and ghc -e):
+
+        -- Turn buffering off for the compiled program's stdout/stderr
+        turnOffBuffering
+        -- Turn buffering off for GHCi's stdout
+        hFlush stdout
+        hSetBuffering stdout NoBuffering
+        -- 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
    prel_mod <- GHC.findModule session prel_name (Just basePackageId)
    GHC.setContext session [] [prel_mod]
 
@@ -351,28 +350,33 @@ runGHCi paths maybe_expr = do
   let show_prompt = verbosity dflags > 0 || is_tty
 
   case maybe_expr of
-       Nothing -> 
+        Nothing ->
           do
 #if defined(mingw32_HOST_OS)
-            -- The win32 Console API mutates the first character of 
+            -- 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 ()
+            case flushed of
+             Left err | isDoesNotExistError err -> return ()
+                      | otherwise -> io (ioError err)
+             Right () -> return ()
 #endif
-           -- initialise the console if necessary
-           io setUpConsole
+            -- initialise the console if necessary
+            io setUpConsole
+
+            let msg = if dopt Opt_ShortGhciBanner dflags
+                      then ghciShortWelcomeMsg
+                      else ghciWelcomeMsg
+            when (verbosity dflags >= 1) $ io $ putStrLn msg
 
-           -- enter the interactive loop
-           interactiveLoop is_tty show_prompt
-       Just expr -> do
-           -- just evaluate the expression we were given
-           runCommandEval expr
-           return ()
+            -- 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."
@@ -573,12 +577,12 @@ afterRunStmt run_result = do
   case run_result of
      GHC.RunOk names -> do
         show_types <- isOptionSet ShowType
-        when show_types $ mapM_ (showTypeOfName session) names
+        when show_types $ printTypeOfNames session names
      GHC.RunBreak _ names mb_info -> do
         resumes <- io $ GHC.getResumeContext session
         printForUser $ ptext SLIT("Stopped at") <+> 
                        ppr (GHC.resumeSpan (head resumes))
-        mapM_ (showTypeOfName session) names
+        printTypeOfNames session names
         maybe (return ()) runBreakCmd mb_info
         -- run the command set with ":set stop <cmd>"
         st <- getGHCiState
@@ -605,12 +609,18 @@ runBreakCmd info = do
               | otherwise -> do enqueueCommands [cmd]; return ()
               where cmd = onBreakCmd loc
 
-showTypeOfName :: Session -> Name -> GHCi ()
-showTypeOfName session n
+printTypeOfNames :: Session -> [Name] -> GHCi ()
+printTypeOfNames session names
+ = mapM_ (printTypeOfName session) $ sortBy compareFun names
+    where compareWith n = (getOccString n, getSrcSpan n)
+          compareFun n1 n2 = compareWith n1 `compare` compareWith n2
+
+printTypeOfName :: Session -> Name -> GHCi ()
+printTypeOfName session n
    = do maybe_tything <- io (GHC.lookupName session n)
-       case maybe_tything of
-         Nothing    -> return ()
-         Just thing -> showTyThing thing
+        case maybe_tything of
+            Nothing    -> return ()
+            Just thing -> printTyThing thing
 
 specialCommand :: String -> GHCi Bool
 specialCommand ('!':str) = shellEscape (dropWhile isSpace str)
@@ -868,17 +878,12 @@ checkModule m = do
   afterLoad (successIf (isJust result)) session
 
 reloadModule :: String -> GHCi ()
-reloadModule "" = do
-  io (revertCAFs)              -- always revert CAFs on reload.
-  discardActiveBreakPoints
-  session <- getSession
-  doLoad session LoadAllTargets
-  return ()
 reloadModule m = do
   io (revertCAFs)              -- always revert CAFs on reload.
   discardActiveBreakPoints
   session <- getSession
-  doLoad session (LoadUpTo (GHC.mkModuleName m))
+  doLoad session $ if null m then LoadAllTargets 
+                             else LoadUpTo (GHC.mkModuleName m)
   return ()
 
 doLoad session howmuch = do
@@ -1253,13 +1258,14 @@ showBindings = do
   s <- getSession
   unqual <- io (GHC.getPrintUnqual s)
   bindings <- io (GHC.getBindings s)
-  mapM_ showTyThing bindings
+  mapM_ printTyThing bindings
   return ()
 
-showTyThing (AnId id) = do 
+printTyThing :: TyThing -> GHCi ()
+printTyThing (AnId id) = do
   ty' <- cleanType (GHC.idType id)
   printForUser $ ppr id <> text " :: " <> ppr ty'
-showTyThing _  = return ()
+printTyThing _ = return ()
 
 -- if -fglasgow-exts is on we show the foralls, otherwise we don't.
 cleanType :: Type -> GHCi Type
@@ -1477,6 +1483,10 @@ wantNameFromInterpretedModule noCanDo str and_then = do
       []    -> return ()
       (n:_) -> do
             let modl = GHC.nameModule n
+            if not (GHC.isExternalName n)
+               then noCanDo n $ ppr n <>
+                                text " is not defined in an interpreted module"
+               else do
             is_interpreted <- io (GHC.moduleIsInterpreted session modl)
             if not is_interpreted
                then noCanDo n $ text "module " <> ppr modl <>
@@ -1584,7 +1594,7 @@ backCmd = noArgs $ do
   s <- getSession
   (names, ix, span) <- io $ GHC.back s
   printForUser $ ptext SLIT("Logged breakpoint at") <+> ppr span
-  mapM_ (showTypeOfName s) names
+  printTypeOfNames s names
    -- run the command set with ":set stop <cmd>"
   st <- getGHCiState
   enqueueCommands [stop st]
@@ -1596,7 +1606,7 @@ forwardCmd = noArgs $ do
   printForUser $ (if (ix == 0)
                     then ptext SLIT("Stopped at")
                     else ptext SLIT("Logged breakpoint at")) <+> ppr span
-  mapM_ (showTypeOfName s) names
+  printTypeOfNames s names
    -- run the command set with ":set stop <cmd>"
   st <- getGHCiState
   enqueueCommands [stop st]
@@ -1799,7 +1809,7 @@ listModuleLine modl line = do
 -- start_bold/end_bold.
 listAround span do_highlight = do
       pwd      <- getEnv "PWD" 
-      contents <- BS.readFile (pwd </> unpackFS file)
+      contents <- BS.readFile (pwd `joinFileName` unpackFS file)
       let 
           lines = BS.split '\n' contents
           these_lines = take (line2 - line1 + 1 + pad_before + pad_after) $