1 {-# OPTIONS -#include "Linker.h" #-}
2 -----------------------------------------------------------------------------
4 -- GHC Interactive User Interface
6 -- (c) The GHC Team 2005
8 -----------------------------------------------------------------------------
14 #include "HsVersions.h"
18 import GHC ( Session, verbosity, dopt, DynFlag(..), Target(..),
20 mkModule, pprModule, Type, Module, SuccessFlag(..),
21 TyThing(..), Name, LoadHowMuch(..), Phase,
22 GhcException(..), showGhcException,
23 CheckedModule(..), SrcLoc )
27 -- for createtags (should these come via GHC?)
28 import Module ( moduleString )
29 import Name ( nameSrcLoc, nameModule, nameOccName )
30 import OccName ( pprOccName )
31 import SrcLoc ( isGoodSrcLoc, srcLocFile, srcLocLine, srcLocCol )
33 -- Other random utilities
34 import Digraph ( flattenSCCs )
35 import BasicTypes ( failed, successIf )
36 import Panic ( panic, installSignalHandlers )
38 import StaticFlags ( opt_IgnoreDotGhci )
39 import Linker ( showLinkerState )
40 import Util ( removeSpaces, handle, global, toArgs,
41 looksLikeModuleName, prefixMatch, sortLe )
43 #ifndef mingw32_HOST_OS
45 #if __GLASGOW_HASKELL__ > 504
49 import GHC.ConsoleHandler ( flushConsole )
53 import Control.Concurrent ( yield ) -- Used in readline loop
54 import System.Console.Readline as Readline
59 import Control.Exception as Exception
61 -- import Control.Concurrent
65 import Data.Int ( Int64 )
66 import Data.Maybe ( isJust, fromMaybe, catMaybes )
69 import System.Environment
70 import System.Exit ( exitWith, ExitCode(..) )
71 import System.Directory
73 import System.IO.Error as IO
75 import Control.Monad as Monad
76 import Foreign.StablePtr ( newStablePtr )
78 import GHC.Exts ( unsafeCoerce# )
79 import GHC.IOBase ( IOErrorType(InvalidArgument) )
81 import Data.IORef ( IORef, newIORef, readIORef, writeIORef )
83 import System.Posix.Internals ( setNonBlockingFD )
85 -----------------------------------------------------------------------------
89 " / _ \\ /\\ /\\/ __(_)\n"++
90 " / /_\\// /_/ / / | | GHC Interactive, version " ++ cProjectVersion ++ ", for Haskell 98.\n"++
91 "/ /_\\\\/ __ / /___| | http://www.haskell.org/ghc/\n"++
92 "\\____/\\/ /_/\\____/|_| Type :? for help.\n"
94 GLOBAL_VAR(commands, builtin_commands, [(String, String -> GHCi Bool)])
96 builtin_commands :: [(String, String -> GHCi Bool)]
98 ("add", keepGoingPaths addModule),
99 ("browse", keepGoing browseCmd),
100 ("cd", keepGoing changeDirectory),
101 ("def", keepGoing defineMacro),
102 ("help", keepGoing help),
103 ("?", keepGoing help),
104 ("info", keepGoing info),
105 ("load", keepGoingPaths loadModule_),
106 ("module", keepGoing setContext),
107 ("reload", keepGoing reloadModule),
108 ("check", keepGoing checkModule),
109 ("set", keepGoing setCmd),
110 ("show", keepGoing showCmd),
111 ("etags", keepGoing createETagsFileCmd),
112 ("ctags", keepGoing createCTagsFileCmd),
113 ("type", keepGoing typeOfExpr),
114 ("kind", keepGoing kindOfType),
115 ("unset", keepGoing unsetOptions),
116 ("undef", keepGoing undefineMacro),
120 keepGoing :: (String -> GHCi ()) -> (String -> GHCi Bool)
121 keepGoing a str = a str >> return False
123 keepGoingPaths :: ([FilePath] -> GHCi ()) -> (String -> GHCi Bool)
124 keepGoingPaths a str = a (toArgs str) >> return False
126 shortHelpText = "use :? for help.\n"
128 -- NOTE: spaces at the end of each line to workaround CPP/string gap bug.
130 " Commands available from the prompt:\n" ++
132 " <stmt> evaluate/run <stmt>\n" ++
133 " :add <filename> ... add module(s) to the current target set\n" ++
134 " :browse [*]<module> display the names defined by <module>\n" ++
135 " :cd <dir> change directory to <dir>\n" ++
136 " :def <cmd> <expr> define a command :<cmd>\n" ++
137 " :help, :? display this list of commands\n" ++
138 " :info [<name> ...] display information about the given names\n" ++
139 " :load <filename> ... load module(s) and their dependents\n" ++
140 " :module [+/-] [*]<mod> ... set the context for expression evaluation\n" ++
141 " :reload reload the current module set\n" ++
143 " :set <option> ... set options\n" ++
144 " :set args <arg> ... set the arguments returned by System.getArgs\n" ++
145 " :set prog <progname> set the value returned by System.getProgName\n" ++
147 " :show modules show the currently loaded modules\n" ++
148 " :show bindings show the current bindings made at the prompt\n" ++
150 " :ctags [<file>] create tags file for Vi (default: \"tags\")\n" ++
151 " :etags [<file>] create tags file for Emacs (defauilt: \"TAGS\")\n" ++
152 " :type <expr> show the type of <expr>\n" ++
153 " :kind <type> show the kind of <type>\n" ++
154 " :undef <cmd> undefine user-defined command :<cmd>\n" ++
155 " :unset <option> ... unset options\n" ++
156 " :quit exit GHCi\n" ++
157 " :!<command> run the shell command <command>\n" ++
159 " Options for ':set' and ':unset':\n" ++
161 " +r revert top-level expressions after each evaluation\n" ++
162 " +s print timing/memory stats after each evaluation\n" ++
163 " +t print type after evaluation\n" ++
164 " -<flags> most GHC command line flags can also be set here\n" ++
165 " (eg. -v2, -fglasgow-exts, etc.)\n"
168 interactiveUI :: Session -> [(FilePath, Maybe Phase)] -> Maybe String -> IO ()
169 interactiveUI session srcs maybe_expr = do
171 -- HACK! If we happen to get into an infinite loop (eg the user
172 -- types 'let x=x in x' at the prompt), then the thread will block
173 -- on a blackhole, and become unreachable during GC. The GC will
174 -- detect that it is unreachable and send it the NonTermination
175 -- exception. However, since the thread is unreachable, everything
176 -- it refers to might be finalized, including the standard Handles.
177 -- This sounds like a bug, but we don't have a good solution right
184 hSetBuffering stdout NoBuffering
186 -- Initialise buffering for the *interpreted* I/O system
187 initInterpBuffering session
189 -- We don't want the cmd line to buffer any input that might be
190 -- intended for the program, so unbuffer stdin.
191 hSetBuffering stdin NoBuffering
193 -- initial context is just the Prelude
194 GHC.setContext session [] [prelude_mod]
200 startGHCi (runGHCi srcs maybe_expr)
201 GHCiState{ progname = "<interactive>",
207 Readline.resetTerminal Nothing
212 runGHCi :: [(FilePath, Maybe Phase)] -> Maybe String -> GHCi ()
213 runGHCi paths maybe_expr = do
214 let read_dot_files = not opt_IgnoreDotGhci
216 when (read_dot_files) $ do
219 exists <- io (doesFileExist file)
221 dir_ok <- io (checkPerms ".")
222 file_ok <- io (checkPerms file)
223 when (dir_ok && file_ok) $ do
224 either_hdl <- io (IO.try (openFile "./.ghci" ReadMode))
227 Right hdl -> fileLoop hdl False
229 when (read_dot_files) $ do
230 -- Read in $HOME/.ghci
231 either_dir <- io (IO.try (getEnv "HOME"))
235 cwd <- io (getCurrentDirectory)
236 when (dir /= cwd) $ do
237 let file = dir ++ "/.ghci"
238 ok <- io (checkPerms file)
240 either_hdl <- io (IO.try (openFile file ReadMode))
243 Right hdl -> fileLoop hdl False
245 -- Perform a :load for files given on the GHCi command line
246 -- When in -e mode, if the load fails then we want to stop
247 -- immediately rather than going on to evaluate the expression.
248 when (not (null paths)) $ do
249 ok <- ghciHandle (\e -> do showException e; return Failed) $
251 when (isJust maybe_expr && failed ok) $
252 io (exitWith (ExitFailure 1))
254 -- if verbosity is greater than 0, or we are connected to a
255 -- terminal, display the prompt in the interactive loop.
256 is_tty <- io (hIsTerminalDevice stdin)
257 dflags <- getDynFlags
258 let show_prompt = verbosity dflags > 0 || is_tty
262 #if defined(mingw32_HOST_OS)
264 -- The win32 Console API mutates the first character of
265 -- type-ahead when reading from it in a non-buffered manner. Work
266 -- around this by flushing the input buffer of type-ahead characters,
267 -- but only if stdin is available.
268 flushed <- io (IO.try (GHC.ConsoleHandler.flushConsole stdin))
270 Left err | isDoesNotExistError err -> return ()
271 | otherwise -> io (ioError err)
272 Right () -> return ()
274 -- enter the interactive loop
275 interactiveLoop is_tty show_prompt
277 -- just evaluate the expression we were given
282 io $ do when (verbosity dflags > 0) $ putStrLn "Leaving GHCi."
285 interactiveLoop is_tty show_prompt =
286 -- Ignore ^C exceptions caught here
287 ghciHandleDyn (\e -> case e of
289 #if defined(mingw32_HOST_OS)
292 interactiveLoop is_tty show_prompt
293 _other -> return ()) $
295 ghciUnblock $ do -- unblock necessary if we recursed from the
296 -- exception handler above.
298 -- read commands from stdin
302 else fileLoop stdin show_prompt
304 fileLoop stdin show_prompt
308 -- NOTE: We only read .ghci files if they are owned by the current user,
309 -- and aren't world writable. Otherwise, we could be accidentally
310 -- running code planted by a malicious third party.
312 -- Furthermore, We only read ./.ghci if . is owned by the current user
313 -- and isn't writable by anyone else. I think this is sufficient: we
314 -- don't need to check .. and ../.. etc. because "." always refers to
315 -- the same directory while a process is running.
317 checkPerms :: String -> IO Bool
319 #ifdef mingw32_HOST_OS
322 Util.handle (\_ -> return False) $ do
323 st <- getFileStatus name
325 if fileOwner st /= me then do
326 putStrLn $ "WARNING: " ++ name ++ " is owned by someone else, IGNORING!"
329 let mode = fileMode st
330 if (groupWriteMode == (mode `intersectFileModes` groupWriteMode))
331 || (otherWriteMode == (mode `intersectFileModes` otherWriteMode))
333 putStrLn $ "*** WARNING: " ++ name ++
334 " is writable by someone else, IGNORING!"
339 fileLoop :: Handle -> Bool -> GHCi ()
340 fileLoop hdl prompt = do
341 session <- getSession
342 (mod,imports) <- io (GHC.getContext session)
343 when prompt (io (putStr (mkPrompt mod imports)))
344 l <- io (IO.try (hGetLine hdl))
346 Left e | isEOFError e -> return ()
347 | InvalidArgument <- etype -> return ()
348 | otherwise -> io (ioError e)
349 where etype = ioeGetErrorType e
350 -- treat InvalidArgument in the same way as EOF:
351 -- this can happen if the user closed stdin, or
352 -- perhaps did getContents which closes stdin at
355 case removeSpaces l of
356 "" -> fileLoop hdl prompt
357 l -> do quit <- runCommand l
358 if quit then return () else fileLoop hdl prompt
360 stringLoop :: [String] -> GHCi ()
361 stringLoop [] = return ()
362 stringLoop (s:ss) = do
363 case removeSpaces s of
365 l -> do quit <- runCommand l
366 if quit then return () else stringLoop ss
368 mkPrompt toplevs exports
369 = showSDoc (hsep (map (\m -> char '*' <> pprModule m) toplevs)
370 <+> hsep (map pprModule exports)
374 readlineLoop :: GHCi ()
376 session <- getSession
377 (mod,imports) <- io (GHC.getContext session)
379 l <- io (readline (mkPrompt mod imports)
380 `finally` setNonBlockingFD 0)
381 -- readline sometimes puts stdin into blocking mode,
382 -- so we need to put it back for the IO library
386 case removeSpaces l of
391 if quit then return () else readlineLoop
394 runCommand :: String -> GHCi Bool
395 runCommand c = ghciHandle handler (doCommand c)
397 doCommand (':' : command) = specialCommand command
399 = do timeIt (do nms <- runStmt stmt; finishEvalExpr nms)
402 -- This version is for the GHC command-line option -e. The only difference
403 -- from runCommand is that it catches the ExitException exception and
404 -- exits, rather than printing out the exception.
405 runCommandEval c = ghciHandle handleEval (doCommand c)
407 handleEval (ExitException code) = io (exitWith code)
408 handleEval e = do showException e
409 io (exitWith (ExitFailure 1))
411 doCommand (':' : command) = specialCommand command
413 = do nms <- runStmt stmt
415 Nothing -> io (exitWith (ExitFailure 1))
416 -- failure to run the command causes exit(1) for ghc -e.
417 _ -> finishEvalExpr nms
419 -- This is the exception handler for exceptions generated by the
420 -- user's code; it normally just prints out the exception. The
421 -- handler must be recursive, in case showing the exception causes
422 -- more exceptions to be raised.
424 -- Bugfix: if the user closed stdout or stderr, the flushing will fail,
425 -- raising another exception. We therefore don't put the recursive
426 -- handler arond the flushing operation, so if stderr is closed
427 -- GHCi will just die gracefully rather than going into an infinite loop.
428 handler :: Exception -> GHCi Bool
429 handler exception = do
431 io installSignalHandlers
432 ghciHandle handler (showException exception >> return False)
434 showException (DynException dyn) =
435 case fromDynamic dyn of
436 Nothing -> io (putStrLn ("*** Exception: (unknown)"))
437 Just Interrupted -> io (putStrLn "Interrupted.")
438 Just (CmdLineError s) -> io (putStrLn s) -- omit the location for CmdLineError
439 Just ph@PhaseFailed{} -> io (putStrLn (showGhcException ph "")) -- ditto
440 Just other_ghc_ex -> io (print other_ghc_ex)
442 showException other_exception
443 = io (putStrLn ("*** Exception: " ++ show other_exception))
445 runStmt :: String -> GHCi (Maybe [Name])
447 | null (filter (not.isSpace) stmt) = return (Just [])
449 = do st <- getGHCiState
450 session <- getSession
451 result <- io $ withProgName (progname st) $ withArgs (args st) $
452 GHC.runStmt session stmt
454 GHC.RunFailed -> return Nothing
455 GHC.RunException e -> throw e -- this is caught by runCommand(Eval)
456 GHC.RunOk names -> return (Just names)
458 -- possibly print the type and revert CAFs after evaluating an expression
459 finishEvalExpr mb_names
460 = do b <- isOptionSet ShowType
461 session <- getSession
464 Just names -> when b (mapM_ (showTypeOfName session) names)
467 io installSignalHandlers
468 b <- isOptionSet RevertCAFs
469 io (when b revertCAFs)
472 showTypeOfName :: Session -> Name -> GHCi ()
473 showTypeOfName session n
474 = do maybe_tything <- io (GHC.lookupName session n)
475 case maybe_tything of
477 Just thing -> showTyThing thing
479 showForUser :: SDoc -> GHCi String
481 session <- getSession
482 unqual <- io (GHC.getPrintUnqual session)
483 return $! showSDocForUser unqual doc
485 specialCommand :: String -> GHCi Bool
486 specialCommand ('!':str) = shellEscape (dropWhile isSpace str)
487 specialCommand str = do
488 let (cmd,rest) = break isSpace str
489 cmds <- io (readIORef commands)
490 case [ (s,f) | (s,f) <- cmds, prefixMatch cmd s ] of
491 [] -> io (hPutStr stdout ("unknown command ':" ++ cmd ++ "'\n"
492 ++ shortHelpText) >> return False)
493 [(_,f)] -> f (dropWhile isSpace rest)
494 cs -> io (hPutStrLn stdout ("prefix " ++ cmd ++
495 " matches multiple commands (" ++
496 foldr1 (\a b -> a ++ ',':b) (map fst cs)
497 ++ ")") >> return False)
499 -----------------------------------------------------------------------------
500 -- To flush buffers for the *interpreted* computation we need
501 -- to refer to *its* stdout/stderr handles
503 GLOBAL_VAR(flush_interp, error "no flush_interp", IO ())
504 GLOBAL_VAR(turn_off_buffering, error "no flush_stdout", IO ())
506 no_buf_cmd = "System.IO.hSetBuffering System.IO.stdout System.IO.NoBuffering" ++
507 " Prelude.>> System.IO.hSetBuffering System.IO.stderr System.IO.NoBuffering"
508 flush_cmd = "System.IO.hFlush System.IO.stdout Prelude.>> System.IO.hFlush IO.stderr"
510 initInterpBuffering :: Session -> IO ()
511 initInterpBuffering session
512 = do maybe_hval <- GHC.compileExpr session no_buf_cmd
515 Just hval -> writeIORef turn_off_buffering (unsafeCoerce# hval :: IO ())
516 other -> panic "interactiveUI:setBuffering"
518 maybe_hval <- GHC.compileExpr session flush_cmd
520 Just hval -> writeIORef flush_interp (unsafeCoerce# hval :: IO ())
521 _ -> panic "interactiveUI:flush"
523 turnOffBuffering -- Turn it off right now
528 flushInterpBuffers :: GHCi ()
530 = io $ do Monad.join (readIORef flush_interp)
533 turnOffBuffering :: IO ()
535 = do Monad.join (readIORef turn_off_buffering)
538 -----------------------------------------------------------------------------
541 help :: String -> GHCi ()
542 help _ = io (putStr helpText)
544 info :: String -> GHCi ()
545 info "" = throwDyn (CmdLineError "syntax: ':i <thing-you-want-info-about>'")
546 info s = do { let names = words s
547 ; session <- getSession
548 ; dflags <- getDynFlags
549 ; let exts = dopt Opt_GlasgowExts dflags
550 ; mapM_ (infoThing exts session) names }
552 infoThing exts session str = io $ do
553 names <- GHC.parseName session str
554 let filtered = filterOutChildren names
555 mb_stuffs <- mapM (GHC.getInfo session) filtered
556 unqual <- GHC.getPrintUnqual session
557 putStrLn (showSDocForUser unqual $
558 vcat (intersperse (text "") $
559 [ pprInfo exts stuff | Just stuff <- mb_stuffs ]))
561 -- Filter out names whose parent is also there Good
562 -- example is '[]', which is both a type and data
563 -- constructor in the same type
564 filterOutChildren :: [Name] -> [Name]
565 filterOutChildren names = filter (not . parent_is_there) names
566 where parent_is_there n
567 | Just p <- GHC.nameParent_maybe n = p `elem` names
570 pprInfo exts (thing, fixity, insts)
571 = pprTyThingInContextLoc exts thing
572 $$ show_fixity fixity
573 $$ vcat (map GHC.pprInstance insts)
576 | fix == GHC.defaultFixity = empty
577 | otherwise = ppr fix <+> ppr (GHC.getName thing)
579 -----------------------------------------------------------------------------
582 addModule :: [FilePath] -> GHCi ()
584 io (revertCAFs) -- always revert CAFs on load/add.
585 files <- mapM expandPath files
586 targets <- mapM (\m -> io (GHC.guessTarget m Nothing)) files
587 session <- getSession
588 io (mapM_ (GHC.addTarget session) targets)
589 ok <- io (GHC.load session LoadAllTargets)
592 changeDirectory :: String -> GHCi ()
593 changeDirectory dir = do
594 session <- getSession
595 graph <- io (GHC.getModuleGraph session)
596 when (not (null graph)) $
597 io $ putStr "Warning: changing directory causes all loaded modules to be unloaded,\nbecause the search path has changed.\n"
598 io (GHC.setTargets session [])
599 io (GHC.load session LoadAllTargets)
600 setContextAfterLoad session []
601 io (GHC.workingDirectoryChanged session)
602 dir <- expandPath dir
603 io (setCurrentDirectory dir)
605 defineMacro :: String -> GHCi ()
607 let (macro_name, definition) = break isSpace s
608 cmds <- io (readIORef commands)
610 then throwDyn (CmdLineError "invalid macro name")
612 if (macro_name `elem` map fst cmds)
613 then throwDyn (CmdLineError
614 ("command '" ++ macro_name ++ "' is already defined"))
617 -- give the expression a type signature, so we can be sure we're getting
618 -- something of the right type.
619 let new_expr = '(' : definition ++ ") :: String -> IO String"
621 -- compile the expression
623 maybe_hv <- io (GHC.compileExpr cms new_expr)
626 Just hv -> io (writeIORef commands --
627 ((macro_name, keepGoing (runMacro hv)) : cmds))
629 runMacro :: GHC.HValue{-String -> IO String-} -> String -> GHCi ()
631 str <- io ((unsafeCoerce# fun :: String -> IO String) s)
632 stringLoop (lines str)
634 undefineMacro :: String -> GHCi ()
635 undefineMacro macro_name = do
636 cmds <- io (readIORef commands)
637 if (macro_name `elem` map fst builtin_commands)
638 then throwDyn (CmdLineError
639 ("command '" ++ macro_name ++ "' cannot be undefined"))
641 if (macro_name `notElem` map fst cmds)
642 then throwDyn (CmdLineError
643 ("command '" ++ macro_name ++ "' not defined"))
645 io (writeIORef commands (filter ((/= macro_name) . fst) cmds))
648 loadModule :: [(FilePath, Maybe Phase)] -> GHCi SuccessFlag
649 loadModule fs = timeIt (loadModule' fs)
651 loadModule_ :: [FilePath] -> GHCi ()
652 loadModule_ fs = do loadModule (zip fs (repeat Nothing)); return ()
654 loadModule' :: [(FilePath, Maybe Phase)] -> GHCi SuccessFlag
655 loadModule' files = do
656 session <- getSession
659 io (GHC.setTargets session [])
660 io (GHC.load session LoadAllTargets)
663 let (filenames, phases) = unzip files
664 exp_filenames <- mapM expandPath filenames
665 let files' = zip exp_filenames phases
666 targets <- io (mapM (uncurry GHC.guessTarget) files')
668 -- NOTE: we used to do the dependency anal first, so that if it
669 -- fails we didn't throw away the current set of modules. This would
670 -- require some re-working of the GHC interface, so we'll leave it
671 -- as a ToDo for now.
673 io (GHC.setTargets session targets)
674 ok <- io (GHC.load session LoadAllTargets)
678 checkModule :: String -> GHCi ()
680 let modl = mkModule m
681 session <- getSession
682 result <- io (GHC.checkModule session modl)
684 Nothing -> io $ putStrLn "Nothing"
685 Just r -> io $ putStrLn (showSDoc (
686 case checkedModuleInfo r of
687 Just cm | Just scope <- GHC.modInfoTopLevelScope cm ->
689 (local,global) = partition ((== modl) . GHC.nameModule) scope
691 (text "global names: " <+> ppr global) $$
692 (text "local names: " <+> ppr local)
694 afterLoad (successIf (isJust result)) session
696 reloadModule :: String -> GHCi ()
698 io (revertCAFs) -- always revert CAFs on reload.
699 session <- getSession
700 ok <- io (GHC.load session LoadAllTargets)
703 io (revertCAFs) -- always revert CAFs on reload.
704 session <- getSession
705 ok <- io (GHC.load session (LoadUpTo (mkModule m)))
708 afterLoad ok session = do
709 io (revertCAFs) -- always revert CAFs on load.
710 graph <- io (GHC.getModuleGraph session)
711 graph' <- filterM (io . GHC.isLoaded session . GHC.ms_mod) graph
712 setContextAfterLoad session graph'
713 modulesLoadedMsg ok (map GHC.ms_mod graph')
715 setContextAfterLoad session [] = do
716 io (GHC.setContext session [] [prelude_mod])
717 setContextAfterLoad session ms = do
718 -- load a target if one is available, otherwise load the topmost module.
719 targets <- io (GHC.getTargets session)
720 case [ m | Just m <- map (findTarget ms) targets ] of
722 let graph' = flattenSCCs (GHC.topSortModuleGraph True ms Nothing) in
723 load_this (last graph')
728 = case filter (`matches` t) ms of
732 summary `matches` Target (TargetModule m) _
733 = GHC.ms_mod summary == m
734 summary `matches` Target (TargetFile f _) _
735 | Just f' <- GHC.ml_hs_file (GHC.ms_location summary) = f == f'
736 summary `matches` target
739 load_this summary | m <- GHC.ms_mod summary = do
740 b <- io (GHC.moduleIsInterpreted session m)
741 if b then io (GHC.setContext session [m] [])
742 else io (GHC.setContext session [] [prelude_mod,m])
745 modulesLoadedMsg :: SuccessFlag -> [Module] -> GHCi ()
746 modulesLoadedMsg ok mods = do
747 dflags <- getDynFlags
748 when (verbosity dflags > 0) $ do
750 | null mods = text "none."
752 punctuate comma (map pprModule mods)) <> text "."
755 io (putStrLn (showSDoc (text "Failed, modules loaded: " <> mod_commas)))
757 io (putStrLn (showSDoc (text "Ok, modules loaded: " <> mod_commas)))
760 typeOfExpr :: String -> GHCi ()
762 = do cms <- getSession
763 maybe_ty <- io (GHC.exprType cms str)
766 Just ty -> do ty' <- cleanType ty
767 tystr <- showForUser (ppr ty')
768 io (putStrLn (str ++ " :: " ++ tystr))
770 kindOfType :: String -> GHCi ()
772 = do cms <- getSession
773 maybe_ty <- io (GHC.typeKind cms str)
776 Just ty -> do tystr <- showForUser (ppr ty)
777 io (putStrLn (str ++ " :: " ++ tystr))
779 quit :: String -> GHCi Bool
782 shellEscape :: String -> GHCi Bool
783 shellEscape str = io (system str >> return False)
785 -----------------------------------------------------------------------------
786 -- create tags file for currently loaded modules.
788 createETagsFileCmd, createCTagsFileCmd :: String -> GHCi ()
790 createCTagsFileCmd "" = ghciCreateTagsFile CTags "tags"
791 createCTagsFileCmd file = ghciCreateTagsFile CTags file
793 createETagsFileCmd "" = ghciCreateTagsFile ETags "TAGS"
794 createETagsFileCmd file = ghciCreateTagsFile ETags file
796 data TagsKind = ETags | CTags
798 ghciCreateTagsFile :: TagsKind -> FilePath -> GHCi ()
799 ghciCreateTagsFile kind file = do
800 session <- getSession
801 io $ createTagsFile session kind file
804 -- - remove restriction that all modules must be interpreted
805 -- (problem: we don't know source locations for entities unless
806 -- we compiled the module.
808 -- - extract createTagsFile so it can be used from the command-line
809 -- (probably need to fix first problem before this is useful).
811 createTagsFile :: Session -> TagsKind -> FilePath -> IO ()
812 createTagsFile session tagskind tagFile = do
813 graph <- GHC.getModuleGraph session
814 let ms = map GHC.ms_mod graph
816 is_interpreted <- GHC.moduleIsInterpreted session m
817 -- should we just skip these?
818 when (not is_interpreted) $
819 throwDyn (CmdLineError ("module '" ++ moduleString m ++ "' is not interpreted"))
821 mbModInfo <- GHC.getModuleInfo session m
823 | Just modinfo <- mbModInfo,
824 Just unqual <- GHC.modInfoPrintUnqualified modinfo = unqual
825 | otherwise = GHC.alwaysQualify
828 Just modInfo -> return $! listTags unqual modInfo
831 mtags <- mapM tagModule ms
832 either_res <- collateAndWriteTags tagskind tagFile $ concat mtags
834 Left e -> hPutStrLn stderr $ ioeGetErrorString e
837 listTags :: PrintUnqualified -> GHC.ModuleInfo -> [TagInfo]
838 listTags unqual modInfo =
839 [ tagInfo unqual name loc
840 | name <- GHC.modInfoExports modInfo
841 , let loc = nameSrcLoc name
845 type TagInfo = (String -- tag name
848 ,Int -- column number
851 -- get tag info, for later translation into Vim or Emacs style
852 tagInfo :: PrintUnqualified -> Name -> SrcLoc -> TagInfo
853 tagInfo unqual name loc
854 = ( showSDocForUser unqual $ pprOccName (nameOccName name)
855 , showSDocForUser unqual $ ftext (srcLocFile loc)
860 collateAndWriteTags :: TagsKind -> FilePath -> [TagInfo] -> IO (Either IOError ())
861 collateAndWriteTags CTags file tagInfos = do -- ctags style, Vim et al
862 let tags = unlines $ sortLe (<=) $ nub $ map showTag tagInfos
863 IO.try (writeFile file tags)
864 collateAndWriteTags ETags file tagInfos = do -- etags style, Emacs/XEmacs
865 let byFile op (_,f1,_,_) (_,f2,_,_) = f1 `op` f2
866 groups = groupBy (byFile (==)) $ sortLe (byFile (<=)) tagInfos
867 tagGroups <- mapM tagFileGroup groups
868 IO.try (writeFile file $ concat tagGroups)
870 tagFileGroup group@[] = throwDyn (CmdLineError "empty tag file group??")
871 tagFileGroup group@((_,fileName,_,_):_) = do
872 file <- readFile fileName -- need to get additional info from sources..
873 let byLine (_,_,l1,_) (_,_,l2,_) = l1 <= l2
874 sortedGroup = sortLe byLine group
875 tags = unlines $ perFile sortedGroup 1 0 $ lines file
876 return $ "\x0c\n" ++ fileName ++ "," ++ show (length tags) ++ "\n" ++ tags
877 perFile (tagInfo@(tag,file,lNo,colNo):tags) count pos (line:lines) | lNo>count =
878 perFile (tagInfo:tags) (count+1) (pos+length line) lines
879 perFile (tagInfo@(tag,file,lNo,colNo):tags) count pos lines@(line:_) | lNo==count =
880 showETag tagInfo line pos : perFile tags count pos lines
881 perFile tags count pos lines = []
883 -- simple ctags format, for Vim et al
884 showTag :: TagInfo -> String
885 showTag (tag,file,lineNo,colNo)
886 = tag ++ "\t" ++ file ++ "\t" ++ show lineNo
888 -- etags format, for Emacs/XEmacs
889 showETag :: TagInfo -> String -> Int -> String
890 showETag (tag,file,lineNo,colNo) line charPos
891 = take colNo line ++ tag
893 ++ "\x01" ++ show lineNo
894 ++ "," ++ show charPos
896 -----------------------------------------------------------------------------
897 -- Browsing a module's contents
899 browseCmd :: String -> GHCi ()
902 ['*':m] | looksLikeModuleName m -> browseModule m False
903 [m] | looksLikeModuleName m -> browseModule m True
904 _ -> throwDyn (CmdLineError "syntax: :browse <module>")
906 browseModule m exports_only = do
909 let modl = mkModule m
910 is_interpreted <- io (GHC.moduleIsInterpreted s modl)
911 when (not is_interpreted && not exports_only) $
912 throwDyn (CmdLineError ("module '" ++ m ++ "' is not interpreted"))
914 -- Temporarily set the context to the module we're interested in,
915 -- just so we can get an appropriate PrintUnqualified
916 (as,bs) <- io (GHC.getContext s)
917 io (if exports_only then GHC.setContext s [] [prelude_mod,modl]
918 else GHC.setContext s [modl] [])
919 unqual <- io (GHC.getPrintUnqual s)
920 io (GHC.setContext s as bs)
922 mb_mod_info <- io $ GHC.getModuleInfo s modl
924 Nothing -> throwDyn (CmdLineError ("unknown module: " ++ m))
927 | exports_only = GHC.modInfoExports mod_info
928 | otherwise = fromMaybe [] (GHC.modInfoTopLevelScope mod_info)
930 filtered = filterOutChildren names
932 things <- io $ mapM (GHC.lookupName s) filtered
934 dflags <- getDynFlags
935 let exts = dopt Opt_GlasgowExts dflags
936 io (putStrLn (showSDocForUser unqual (
937 vcat (map (pprTyThingInContext exts) (catMaybes things))
939 -- ToDo: modInfoInstances currently throws an exception for
940 -- package modules. When it works, we can do this:
941 -- $$ vcat (map GHC.pprInstance (GHC.modInfoInstances mod_info))
943 -----------------------------------------------------------------------------
944 -- Setting the module context
947 | all sensible mods = fn mods
948 | otherwise = throwDyn (CmdLineError "syntax: :module [+/-] [*]M1 ... [*]Mn")
950 (fn, mods) = case str of
951 '+':stuff -> (addToContext, words stuff)
952 '-':stuff -> (removeFromContext, words stuff)
953 stuff -> (newContext, words stuff)
955 sensible ('*':m) = looksLikeModuleName m
956 sensible m = looksLikeModuleName m
959 session <- getSession
960 (as,bs) <- separate session mods [] []
961 let bs' = if null as && prelude_mod `notElem` bs then prelude_mod:bs else bs
962 io (GHC.setContext session as bs')
964 separate :: Session -> [String] -> [Module] -> [Module]
965 -> GHCi ([Module],[Module])
966 separate session [] as bs = return (as,bs)
967 separate session (('*':m):ms) as bs = do
968 let modl = mkModule m
969 b <- io (GHC.moduleIsInterpreted session modl)
970 if b then separate session ms (modl:as) bs
971 else throwDyn (CmdLineError ("module '" ++ m ++ "' is not interpreted"))
972 separate session (m:ms) as bs = separate session ms as (mkModule m:bs)
974 prelude_mod = mkModule "Prelude"
977 addToContext mods = do
979 (as,bs) <- io (GHC.getContext cms)
981 (as',bs') <- separate cms mods [] []
983 let as_to_add = as' \\ (as ++ bs)
984 bs_to_add = bs' \\ (as ++ bs)
986 io (GHC.setContext cms (as ++ as_to_add) (bs ++ bs_to_add))
989 removeFromContext mods = do
991 (as,bs) <- io (GHC.getContext cms)
993 (as_to_remove,bs_to_remove) <- separate cms mods [] []
995 let as' = as \\ (as_to_remove ++ bs_to_remove)
996 bs' = bs \\ (as_to_remove ++ bs_to_remove)
998 io (GHC.setContext cms as' bs')
1000 ----------------------------------------------------------------------------
1003 -- set options in the interpreter. Syntax is exactly the same as the
1004 -- ghc command line, except that certain options aren't available (-C,
1007 -- This is pretty fragile: most options won't work as expected. ToDo:
1008 -- figure out which ones & disallow them.
1010 setCmd :: String -> GHCi ()
1012 = do st <- getGHCiState
1013 let opts = options st
1014 io $ putStrLn (showSDoc (
1015 text "options currently set: " <>
1018 else hsep (map (\o -> char '+' <> text (optToStr o)) opts)
1022 ("args":args) -> setArgs args
1023 ("prog":prog) -> setProg prog
1024 wds -> setOptions wds
1028 setGHCiState st{ args = args }
1032 setGHCiState st{ progname = prog }
1034 io (hPutStrLn stderr "syntax: :set prog <progname>")
1037 do -- first, deal with the GHCi opts (+s, +t, etc.)
1038 let (plus_opts, minus_opts) = partition isPlus wds
1039 mapM_ setOpt plus_opts
1041 -- then, dynamic flags
1042 dflags <- getDynFlags
1043 (dflags',leftovers) <- io $ GHC.parseDynamicFlags dflags minus_opts
1046 -- update things if the users wants more packages
1048 let new_packages = pkgs_after \\ pkgs_before
1049 when (not (null new_packages)) $
1050 newPackages new_packages
1053 if (not (null leftovers))
1054 then throwDyn (CmdLineError ("unrecognised flags: " ++
1059 unsetOptions :: String -> GHCi ()
1061 = do -- first, deal with the GHCi opts (+s, +t, etc.)
1062 let opts = words str
1063 (minus_opts, rest1) = partition isMinus opts
1064 (plus_opts, rest2) = partition isPlus rest1
1066 if (not (null rest2))
1067 then io (putStrLn ("unknown option: '" ++ head rest2 ++ "'"))
1070 mapM_ unsetOpt plus_opts
1072 -- can't do GHC flags for now
1073 if (not (null minus_opts))
1074 then throwDyn (CmdLineError "can't unset GHC command-line flags")
1077 isMinus ('-':s) = True
1080 isPlus ('+':s) = True
1084 = case strToGHCiOpt str of
1085 Nothing -> io (putStrLn ("unknown option: '" ++ str ++ "'"))
1086 Just o -> setOption o
1089 = case strToGHCiOpt str of
1090 Nothing -> io (putStrLn ("unknown option: '" ++ str ++ "'"))
1091 Just o -> unsetOption o
1093 strToGHCiOpt :: String -> (Maybe GHCiOption)
1094 strToGHCiOpt "s" = Just ShowTiming
1095 strToGHCiOpt "t" = Just ShowType
1096 strToGHCiOpt "r" = Just RevertCAFs
1097 strToGHCiOpt _ = Nothing
1099 optToStr :: GHCiOption -> String
1100 optToStr ShowTiming = "s"
1101 optToStr ShowType = "t"
1102 optToStr RevertCAFs = "r"
1105 newPackages new_pkgs = do -- The new packages are already in v_Packages
1106 session <- getSession
1107 io (GHC.setTargets session [])
1108 io (GHC.load session Nothing)
1109 dflags <- getDynFlags
1110 io (linkPackages dflags new_pkgs)
1111 setContextAfterLoad []
1114 -- ---------------------------------------------------------------------------
1119 ["modules" ] -> showModules
1120 ["bindings"] -> showBindings
1121 ["linker"] -> io showLinkerState
1122 _ -> throwDyn (CmdLineError "syntax: :show [modules|bindings]")
1125 session <- getSession
1126 let show_one ms = do m <- io (GHC.showModule session ms)
1128 graph <- io (GHC.getModuleGraph session)
1129 mapM_ show_one graph
1133 unqual <- io (GHC.getPrintUnqual s)
1134 bindings <- io (GHC.getBindings s)
1135 mapM_ showTyThing bindings
1138 showTyThing (AnId id) = do
1139 ty' <- cleanType (GHC.idType id)
1140 str <- showForUser (ppr id <> text " :: " <> ppr ty')
1142 showTyThing _ = return ()
1144 -- if -fglasgow-exts is on we show the foralls, otherwise we don't.
1145 cleanType :: Type -> GHCi Type
1147 dflags <- getDynFlags
1148 if dopt Opt_GlasgowExts dflags
1150 else return $! GHC.dropForAlls ty
1152 -----------------------------------------------------------------------------
1155 data GHCiState = GHCiState
1159 session :: GHC.Session,
1160 options :: [GHCiOption]
1164 = ShowTiming -- show time/allocs after evaluation
1165 | ShowType -- show the type of expressions
1166 | RevertCAFs -- revert CAFs after every evaluation
1169 newtype GHCi a = GHCi { unGHCi :: IORef GHCiState -> IO a }
1171 startGHCi :: GHCi a -> GHCiState -> IO a
1172 startGHCi g state = do ref <- newIORef state; unGHCi g ref
1174 instance Monad GHCi where
1175 (GHCi m) >>= k = GHCi $ \s -> m s >>= \a -> unGHCi (k a) s
1176 return a = GHCi $ \s -> return a
1178 ghciHandleDyn :: Typeable t => (t -> GHCi a) -> GHCi a -> GHCi a
1179 ghciHandleDyn h (GHCi m) = GHCi $ \s ->
1180 Exception.catchDyn (m s) (\e -> unGHCi (h e) s)
1182 getGHCiState = GHCi $ \r -> readIORef r
1183 setGHCiState s = GHCi $ \r -> writeIORef r s
1185 -- for convenience...
1186 getSession = getGHCiState >>= return . session
1190 io (GHC.getSessionDynFlags s)
1191 setDynFlags dflags = do
1193 io (GHC.setSessionDynFlags s dflags)
1195 isOptionSet :: GHCiOption -> GHCi Bool
1197 = do st <- getGHCiState
1198 return (opt `elem` options st)
1200 setOption :: GHCiOption -> GHCi ()
1202 = do st <- getGHCiState
1203 setGHCiState (st{ options = opt : filter (/= opt) (options st) })
1205 unsetOption :: GHCiOption -> GHCi ()
1207 = do st <- getGHCiState
1208 setGHCiState (st{ options = filter (/= opt) (options st) })
1210 io :: IO a -> GHCi a
1211 io m = GHCi { unGHCi = \s -> m >>= return }
1213 -----------------------------------------------------------------------------
1214 -- recursive exception handlers
1216 -- Don't forget to unblock async exceptions in the handler, or if we're
1217 -- in an exception loop (eg. let a = error a in a) the ^C exception
1218 -- may never be delivered. Thanks to Marcin for pointing out the bug.
1220 ghciHandle :: (Exception -> GHCi a) -> GHCi a -> GHCi a
1221 ghciHandle h (GHCi m) = GHCi $ \s ->
1222 Exception.catch (m s)
1223 (\e -> unGHCi (ghciUnblock (h e)) s)
1225 ghciUnblock :: GHCi a -> GHCi a
1226 ghciUnblock (GHCi a) = GHCi $ \s -> Exception.unblock (a s)
1228 -----------------------------------------------------------------------------
1229 -- timing & statistics
1231 timeIt :: GHCi a -> GHCi a
1233 = do b <- isOptionSet ShowTiming
1236 else do allocs1 <- io $ getAllocations
1237 time1 <- io $ getCPUTime
1239 allocs2 <- io $ getAllocations
1240 time2 <- io $ getCPUTime
1241 io $ printTimes (fromIntegral (allocs2 - allocs1))
1245 foreign import ccall unsafe "getAllocations" getAllocations :: IO Int64
1246 -- defined in ghc/rts/Stats.c
1248 printTimes :: Integer -> Integer -> IO ()
1249 printTimes allocs psecs
1250 = do let secs = (fromIntegral psecs / (10^12)) :: Float
1251 secs_str = showFFloat (Just 2) secs
1252 putStrLn (showSDoc (
1253 parens (text (secs_str "") <+> text "secs" <> comma <+>
1254 text (show allocs) <+> text "bytes")))
1256 -----------------------------------------------------------------------------
1263 -- Have to turn off buffering again, because we just
1264 -- reverted stdout, stderr & stdin to their defaults.
1266 foreign import ccall "revertCAFs" rts_revertCAFs :: IO ()
1267 -- Make it "safe", just in case
1269 -- -----------------------------------------------------------------------------
1272 expandPath :: String -> GHCi String
1274 case dropWhile isSpace path of
1276 tilde <- io (getEnv "HOME") -- will fail if HOME not defined
1277 return (tilde ++ '/':d)