1 {-# OPTIONS -#include "Linker.h" #-}
2 -----------------------------------------------------------------------------
4 -- GHC Interactive User Interface
6 -- (c) The GHC Team 2005-2006
8 -----------------------------------------------------------------------------
14 #include "HsVersions.h"
22 import GHC ( Session, LoadHowMuch(..), Target(..), TargetId(..),
23 Type, Module, ModuleName, TyThing(..), Phase,
24 BreakIndex, Name, SrcSpan, Resume, SingleStep )
30 import Outputable hiding (printForUser)
31 import Module -- for ModuleEnv
33 -- Other random utilities
35 import BasicTypes hiding (isTopLevel)
36 import Panic hiding (showException)
43 #ifndef mingw32_HOST_OS
45 #if __GLASGOW_HASKELL__ > 504
49 import GHC.ConsoleHandler ( flushConsole )
50 import System.Win32 ( setConsoleCP, setConsoleOutputCP )
51 import qualified System.Win32
55 import Control.Concurrent ( yield ) -- Used in readline loop
56 import System.Console.Readline as Readline
61 import Control.Exception as Exception
62 -- import Control.Concurrent
64 import qualified Data.ByteString.Char8 as BS
68 import System.Environment
69 import System.Exit ( exitWith, ExitCode(..) )
70 import System.Directory
72 import System.IO.Error as IO
76 import Control.Monad as Monad
79 import Foreign.StablePtr ( newStablePtr )
80 import GHC.Exts ( unsafeCoerce# )
81 import GHC.IOBase ( IOErrorType(InvalidArgument) )
83 import Data.IORef ( IORef, readIORef, writeIORef )
85 import System.Posix.Internals ( setNonBlockingFD )
87 -----------------------------------------------------------------------------
91 " / _ \\ /\\ /\\/ __(_)\n"++
92 " / /_\\// /_/ / / | | GHC Interactive, version " ++ cProjectVersion ++ ", for Haskell 98.\n"++
93 "/ /_\\\\/ __ / /___| | http://www.haskell.org/ghc/\n"++
94 "\\____/\\/ /_/\\____/|_| Type :? for help.\n"
96 type Command = (String, String -> GHCi Bool, Bool, String -> IO [String])
99 GLOBAL_VAR(commands, builtin_commands, [Command])
101 builtin_commands :: [Command]
103 -- Hugs users are accustomed to :e, so make sure it doesn't overlap
104 ("?", keepGoing help, False, completeNone),
105 ("add", keepGoingPaths addModule, False, completeFilename),
106 ("abandon", keepGoing abandonCmd, False, completeNone),
107 ("break", keepGoing breakCmd, False, completeIdentifier),
108 ("back", keepGoing backCmd, False, completeNone),
109 ("browse", keepGoing browseCmd, False, completeModule),
110 ("cd", keepGoing changeDirectory, False, completeFilename),
111 ("check", keepGoing checkModule, False, completeHomeModule),
112 ("continue", continueCmd, False, completeNone),
113 ("ctags", keepGoing createCTagsFileCmd, False, completeFilename),
114 ("def", keepGoing defineMacro, False, completeIdentifier),
115 ("delete", keepGoing deleteCmd, False, completeNone),
116 ("e", keepGoing editFile, False, completeFilename),
117 ("edit", keepGoing editFile, False, completeFilename),
118 ("etags", keepGoing createETagsFileCmd, False, completeFilename),
119 ("force", keepGoing forceCmd, False, completeIdentifier),
120 ("forward", keepGoing forwardCmd, False, completeNone),
121 ("help", keepGoing help, False, completeNone),
122 ("history", keepGoing historyCmd, False, completeNone),
123 ("info", keepGoing info, False, completeIdentifier),
124 ("kind", keepGoing kindOfType, False, completeIdentifier),
125 ("load", keepGoingPaths loadModule_, False, completeHomeModuleOrFile),
126 ("list", keepGoing listCmd, False, completeNone),
127 ("module", keepGoing setContext, False, completeModule),
128 ("main", keepGoing runMain, False, completeIdentifier),
129 ("print", keepGoing printCmd, False, completeIdentifier),
130 ("quit", quit, False, completeNone),
131 ("reload", keepGoing reloadModule, False, completeNone),
132 ("set", keepGoing setCmd, True, completeSetOptions),
133 ("show", keepGoing showCmd, False, completeNone),
134 ("sprint", keepGoing sprintCmd, False, completeIdentifier),
135 ("step", stepCmd, False, completeIdentifier),
136 ("type", keepGoing typeOfExpr, False, completeIdentifier),
137 ("trace", traceCmd, False, completeIdentifier),
138 ("undef", keepGoing undefineMacro, False, completeMacro),
139 ("unset", keepGoing unsetOptions, True, completeSetOptions)
142 keepGoing :: (String -> GHCi ()) -> (String -> GHCi Bool)
143 keepGoing a str = a str >> return False
145 keepGoingPaths :: ([FilePath] -> GHCi ()) -> (String -> GHCi Bool)
146 keepGoingPaths a str = a (toArgs str) >> return False
148 shortHelpText = "use :? for help.\n"
151 " Commands available from the prompt:\n" ++
153 " <stmt> evaluate/run <stmt>\n" ++
154 " :add <filename> ... add module(s) to the current target set\n" ++
155 " :abandon at a breakpoint, abandon current computation\n" ++
156 " :break [<mod>] <l> [<col>] set a breakpoint at the specified location\n" ++
157 " :break <name> set a breakpoint on the specified function\n" ++
158 " :browse [*]<module> display the names defined by <module>\n" ++
159 " :cd <dir> change directory to <dir>\n" ++
160 " :continue resume after a breakpoint\n" ++
161 " :ctags [<file>] create tags file for Vi (default: \"tags\")\n" ++
162 " :def <cmd> <expr> define a command :<cmd>\n" ++
163 " :delete <number> delete the specified breakpoint\n" ++
164 " :delete * delete all breakpoints\n" ++
165 " :edit <file> edit file\n" ++
166 " :edit edit last module\n" ++
167 " :etags [<file>] create tags file for Emacs (default: \"TAGS\")\n" ++
168 -- " :force <expr> print <expr>, forcing unevaluated parts\n" ++
169 " :help, :? display this list of commands\n" ++
170 " :info [<name> ...] display information about the given names\n" ++
171 " :kind <type> show the kind of <type>\n" ++
172 " :load <filename> ... load module(s) and their dependents\n" ++
173 " :module [+/-] [*]<mod> ... set the context for expression evaluation\n" ++
174 " :main [<arguments> ...] run the main function with the given arguments\n" ++
175 " :print [<name> ...] prints a value without forcing its computation\n" ++
176 " :quit exit GHCi\n" ++
177 " :reload reload the current module set\n" ++
179 " :set <option> ... set options\n" ++
180 " :set args <arg> ... set the arguments returned by System.getArgs\n" ++
181 " :set prog <progname> set the value returned by System.getProgName\n" ++
182 " :set prompt <prompt> set the prompt used in GHCi\n" ++
183 " :set editor <cmd> set the command used for :edit\n" ++
184 " :set stop <cmd> set the command to run when a breakpoint is hit\n" ++
186 " :show breaks show active breakpoints\n" ++
187 " :show context show the breakpoint context\n" ++
188 " :show modules show the currently loaded modules\n" ++
189 " :show bindings show the current bindings made at the prompt\n" ++
191 " :sprint [<name> ...] simplifed version of :print\n" ++
192 " :step single-step after stopping at a breakpoint\n"++
193 " :step <expr> single-step into <expr>\n"++
194 " :type <expr> show the type of <expr>\n" ++
195 " :undef <cmd> undefine user-defined command :<cmd>\n" ++
196 " :unset <option> ... unset options\n" ++
197 " :!<command> run the shell command <command>\n" ++
199 " Options for ':set' and ':unset':\n" ++
201 " +r revert top-level expressions after each evaluation\n" ++
202 " +s print timing/memory stats after each evaluation\n" ++
203 " +t print type after evaluation\n" ++
204 " -<flags> most GHC command line flags can also be set here\n" ++
205 " (eg. -v2, -fglasgow-exts, etc.)\n" ++
207 -- Todo: add help for breakpoint commands here
213 win <- System.Win32.getWindowsDirectory
214 return (win `joinFileName` "notepad.exe")
219 interactiveUI :: Session -> [(FilePath, Maybe Phase)] -> Maybe String -> IO ()
220 interactiveUI session srcs maybe_expr = do
221 -- HACK! If we happen to get into an infinite loop (eg the user
222 -- types 'let x=x in x' at the prompt), then the thread will block
223 -- on a blackhole, and become unreachable during GC. The GC will
224 -- detect that it is unreachable and send it the NonTermination
225 -- exception. However, since the thread is unreachable, everything
226 -- it refers to might be finalized, including the standard Handles.
227 -- This sounds like a bug, but we don't have a good solution right
233 -- Initialise buffering for the *interpreted* I/O system
234 initInterpBuffering session
236 when (isNothing maybe_expr) $ do
237 -- Only for GHCi (not runghc and ghc -e):
238 -- Turn buffering off for the compiled program's stdout/stderr
240 -- Turn buffering off for GHCi's stdout
242 hSetBuffering stdout NoBuffering
243 -- We don't want the cmd line to buffer any input that might be
244 -- intended for the program, so unbuffer stdin.
245 hSetBuffering stdin NoBuffering
247 -- initial context is just the Prelude
248 prel_mod <- GHC.findModule session prel_name (Just basePackageId)
249 GHC.setContext session [] [prel_mod]
253 Readline.setAttemptedCompletionFunction (Just completeWord)
254 --Readline.parseAndBind "set show-all-if-ambiguous 1"
256 let symbols = "!#$%&*+/<=>?@\\^|-~"
257 specials = "(),;[]`{}"
259 word_break_chars = spaces ++ specials ++ symbols
261 Readline.setBasicWordBreakCharacters word_break_chars
262 Readline.setCompleterWordBreakCharacters word_break_chars
265 default_editor <- findEditor
267 startGHCi (runGHCi srcs maybe_expr)
268 GHCiState{ progname = "<interactive>",
272 editor = default_editor,
278 tickarrays = emptyModuleEnv
282 Readline.resetTerminal Nothing
287 prel_name = GHC.mkModuleName "Prelude"
289 runGHCi :: [(FilePath, Maybe Phase)] -> Maybe String -> GHCi ()
290 runGHCi paths maybe_expr = do
291 let read_dot_files = not opt_IgnoreDotGhci
293 when (read_dot_files) $ do
296 exists <- io (doesFileExist file)
298 dir_ok <- io (checkPerms ".")
299 file_ok <- io (checkPerms file)
300 when (dir_ok && file_ok) $ do
301 either_hdl <- io (IO.try (openFile "./.ghci" ReadMode))
304 Right hdl -> fileLoop hdl False
306 when (read_dot_files) $ do
307 -- Read in $HOME/.ghci
308 either_dir <- io (IO.try (getEnv "HOME"))
312 cwd <- io (getCurrentDirectory)
313 when (dir /= cwd) $ do
314 let file = dir ++ "/.ghci"
315 ok <- io (checkPerms file)
317 either_hdl <- io (IO.try (openFile file ReadMode))
320 Right hdl -> fileLoop hdl False
322 -- Perform a :load for files given on the GHCi command line
323 -- When in -e mode, if the load fails then we want to stop
324 -- immediately rather than going on to evaluate the expression.
325 when (not (null paths)) $ do
326 ok <- ghciHandle (\e -> do showException e; return Failed) $
328 when (isJust maybe_expr && failed ok) $
329 io (exitWith (ExitFailure 1))
331 -- if verbosity is greater than 0, or we are connected to a
332 -- terminal, display the prompt in the interactive loop.
333 is_tty <- io (hIsTerminalDevice stdin)
334 dflags <- getDynFlags
335 let show_prompt = verbosity dflags > 0 || is_tty
340 #if defined(mingw32_HOST_OS)
341 -- The win32 Console API mutates the first character of
342 -- type-ahead when reading from it in a non-buffered manner. Work
343 -- around this by flushing the input buffer of type-ahead characters,
344 -- but only if stdin is available.
345 flushed <- io (IO.try (GHC.ConsoleHandler.flushConsole stdin))
347 Left err | isDoesNotExistError err -> return ()
348 | otherwise -> io (ioError err)
349 Right () -> return ()
351 -- initialise the console if necessary
354 -- enter the interactive loop
355 interactiveLoop is_tty show_prompt
357 -- just evaluate the expression we were given
362 io $ do when (verbosity dflags > 0) $ putStrLn "Leaving GHCi."
365 interactiveLoop is_tty show_prompt =
366 -- Ignore ^C exceptions caught here
367 ghciHandleDyn (\e -> case e of
369 #if defined(mingw32_HOST_OS)
372 interactiveLoop is_tty show_prompt
373 _other -> return ()) $
375 ghciUnblock $ do -- unblock necessary if we recursed from the
376 -- exception handler above.
378 -- read commands from stdin
382 else fileLoop stdin show_prompt
384 fileLoop stdin show_prompt
388 -- NOTE: We only read .ghci files if they are owned by the current user,
389 -- and aren't world writable. Otherwise, we could be accidentally
390 -- running code planted by a malicious third party.
392 -- Furthermore, We only read ./.ghci if . is owned by the current user
393 -- and isn't writable by anyone else. I think this is sufficient: we
394 -- don't need to check .. and ../.. etc. because "." always refers to
395 -- the same directory while a process is running.
397 checkPerms :: String -> IO Bool
399 #ifdef mingw32_HOST_OS
402 Util.handle (\_ -> return False) $ do
403 st <- getFileStatus name
405 if fileOwner st /= me then do
406 putStrLn $ "WARNING: " ++ name ++ " is owned by someone else, IGNORING!"
409 let mode = fileMode st
410 if (groupWriteMode == (mode `intersectFileModes` groupWriteMode))
411 || (otherWriteMode == (mode `intersectFileModes` otherWriteMode))
413 putStrLn $ "*** WARNING: " ++ name ++
414 " is writable by someone else, IGNORING!"
419 fileLoop :: Handle -> Bool -> GHCi ()
420 fileLoop hdl show_prompt = do
421 when show_prompt $ do
424 l <- io (IO.try (hGetLine hdl))
426 Left e | isEOFError e -> return ()
427 | InvalidArgument <- etype -> return ()
428 | otherwise -> io (ioError e)
429 where etype = ioeGetErrorType e
430 -- treat InvalidArgument in the same way as EOF:
431 -- this can happen if the user closed stdin, or
432 -- perhaps did getContents which closes stdin at
435 case removeSpaces l of
436 "" -> fileLoop hdl show_prompt
437 l -> do quit <- runCommand l
438 if quit then return () else fileLoop hdl show_prompt
440 stringLoop :: [String] -> GHCi Bool{-True: we quit-}
441 stringLoop [] = return False
442 stringLoop (s:ss) = do
443 case removeSpaces s of
445 l -> do quit <- runCommand l
446 if quit then return True else stringLoop ss
449 session <- getSession
450 (toplevs,exports) <- io (GHC.getContext session)
451 resumes <- io $ GHC.getResumeContext session
457 let ix = GHC.resumeHistoryIx r
459 then return (brackets (ppr (GHC.resumeSpan r)) <> space)
461 let hist = GHC.resumeHistory r !! (ix-1)
462 span <- io $ GHC.getHistorySpan session hist
463 return (brackets (ppr (negate ix) <> char ':'
464 <+> ppr span) <> space)
466 dots | r:rs <- resumes, not (null rs) = text "... "
470 hsep (map (\m -> char '*' <> ppr (GHC.moduleName m)) toplevs) <+>
471 hsep (map (ppr . GHC.moduleName) exports)
473 deflt_prompt = dots <> context_bit <> modules_bit
475 f ('%':'s':xs) = deflt_prompt <> f xs
476 f ('%':'%':xs) = char '%' <> f xs
477 f (x:xs) = char x <> f xs
481 return (showSDoc (f (prompt st)))
485 readlineLoop :: GHCi ()
487 session <- getSession
488 (mod,imports) <- io (GHC.getContext session)
490 saveSession -- for use by completion
492 mb_span <- getCurrentBreakSpan
494 l <- io (readline prompt `finally` setNonBlockingFD 0)
495 -- readline sometimes puts stdin into blocking mode,
496 -- so we need to put it back for the IO library
501 case removeSpaces l of
506 if quit then return () else readlineLoop
509 runCommand :: String -> GHCi Bool
510 runCommand c = ghciHandle handler (doCommand c)
512 doCommand (':' : command) = specialCommand command
514 = do timeIt $ runStmt stmt GHC.RunToCompletion
517 -- This version is for the GHC command-line option -e. The only difference
518 -- from runCommand is that it catches the ExitException exception and
519 -- exits, rather than printing out the exception.
520 runCommandEval c = ghciHandle handleEval (doCommand c)
522 handleEval (ExitException code) = io (exitWith code)
523 handleEval e = do handler e
524 io (exitWith (ExitFailure 1))
526 doCommand (':' : command) = specialCommand command
528 = do r <- runStmt stmt GHC.RunToCompletion
530 False -> io (exitWith (ExitFailure 1))
531 -- failure to run the command causes exit(1) for ghc -e.
534 runStmt :: String -> SingleStep -> GHCi Bool
536 | null (filter (not.isSpace) stmt) = return False
538 = do st <- getGHCiState
539 session <- getSession
540 result <- io $ withProgName (progname st) $ withArgs (args st) $
541 GHC.runStmt session stmt step
543 return (isRunResultOk result)
546 afterRunStmt :: GHC.RunResult -> GHCi (Maybe (Bool,[Name]))
547 afterRunStmt run_result = do
548 mb_result <- switchOnRunResult run_result
549 -- possibly print the type and revert CAFs after evaluating an expression
550 show_types <- isOptionSet ShowType
551 session <- getSession
554 Just (is_break,names) ->
555 when (is_break || show_types) $
556 mapM_ (showTypeOfName session) names
559 io installSignalHandlers
560 b <- isOptionSet RevertCAFs
561 io (when b revertCAFs)
566 switchOnRunResult :: GHC.RunResult -> GHCi (Maybe (Bool,[Name]))
567 switchOnRunResult GHC.RunFailed = return Nothing
568 switchOnRunResult (GHC.RunException e) = throw e
569 switchOnRunResult (GHC.RunOk names) = return $ Just (False,names)
570 switchOnRunResult (GHC.RunBreak threadId names info) = do
571 session <- getSession
572 Just mod_info <- io $ GHC.getModuleInfo session (GHC.breakInfo_module info)
573 let modBreaks = GHC.modInfoModBreaks mod_info
574 let ticks = GHC.modBreaks_locs modBreaks
576 -- display information about the breakpoint
577 let location = ticks ! GHC.breakInfo_number info
578 printForUser $ ptext SLIT("Stopped at") <+> ppr location
580 -- run the command set with ":set stop <cmd>"
584 return (Just (True,names))
587 isRunResultOk :: GHC.RunResult -> Bool
588 isRunResultOk (GHC.RunOk _) = True
589 isRunResultOk _ = False
592 showTypeOfName :: Session -> Name -> GHCi ()
593 showTypeOfName session n
594 = do maybe_tything <- io (GHC.lookupName session n)
595 case maybe_tything of
597 Just thing -> showTyThing thing
599 specialCommand :: String -> GHCi Bool
600 specialCommand ('!':str) = shellEscape (dropWhile isSpace str)
601 specialCommand str = do
602 let (cmd,rest) = break isSpace str
603 maybe_cmd <- io (lookupCommand cmd)
605 Nothing -> io (hPutStr stdout ("unknown command ':" ++ cmd ++ "'\n"
606 ++ shortHelpText) >> return False)
607 Just (_,f,_,_) -> f (dropWhile isSpace rest)
609 lookupCommand :: String -> IO (Maybe Command)
610 lookupCommand str = do
611 cmds <- readIORef commands
612 -- look for exact match first, then the first prefix match
613 case [ c | c <- cmds, str == cmdName c ] of
614 c:_ -> return (Just c)
615 [] -> case [ c | c@(s,_,_,_) <- cmds, prefixMatch str s ] of
617 c:_ -> return (Just c)
620 getCurrentBreakSpan :: GHCi (Maybe SrcSpan)
621 getCurrentBreakSpan = do
622 session <- getSession
623 resumes <- io $ GHC.getResumeContext session
627 let ix = GHC.resumeHistoryIx r
629 then return (Just (GHC.resumeSpan r))
631 let hist = GHC.resumeHistory r !! (ix-1)
632 span <- io $ GHC.getHistorySpan session hist
635 -----------------------------------------------------------------------------
638 noArgs :: GHCi () -> String -> GHCi ()
640 noArgs m _ = io $ putStrLn "This command takes no arguments"
642 help :: String -> GHCi ()
643 help _ = io (putStr helpText)
645 info :: String -> GHCi ()
646 info "" = throwDyn (CmdLineError "syntax: ':i <thing-you-want-info-about>'")
647 info s = do { let names = words s
648 ; session <- getSession
649 ; dflags <- getDynFlags
650 ; let exts = dopt Opt_GlasgowExts dflags
651 ; mapM_ (infoThing exts session) names }
653 infoThing exts session str = io $ do
654 names <- GHC.parseName session str
655 let filtered = filterOutChildren names
656 mb_stuffs <- mapM (GHC.getInfo session) filtered
657 unqual <- GHC.getPrintUnqual session
658 putStrLn (showSDocForUser unqual $
659 vcat (intersperse (text "") $
660 [ pprInfo exts stuff | Just stuff <- mb_stuffs ]))
662 -- Filter out names whose parent is also there Good
663 -- example is '[]', which is both a type and data
664 -- constructor in the same type
665 filterOutChildren :: [Name] -> [Name]
666 filterOutChildren names = filter (not . parent_is_there) names
667 where parent_is_there n
668 -- | Just p <- GHC.nameParent_maybe n = p `elem` names
672 pprInfo exts (thing, fixity, insts)
673 = pprTyThingInContextLoc exts thing
674 $$ show_fixity fixity
675 $$ vcat (map GHC.pprInstance insts)
678 | fix == GHC.defaultFixity = empty
679 | otherwise = ppr fix <+> ppr (GHC.getName thing)
681 runMain :: String -> GHCi ()
683 let ss = concat $ intersperse "," (map (\ s -> ('"':s)++"\"") (toArgs args))
684 runCommand $ '[': ss ++ "] `System.Environment.withArgs` main"
687 addModule :: [FilePath] -> GHCi ()
689 io (revertCAFs) -- always revert CAFs on load/add.
690 files <- mapM expandPath files
691 targets <- mapM (\m -> io (GHC.guessTarget m Nothing)) files
692 session <- getSession
693 io (mapM_ (GHC.addTarget session) targets)
694 ok <- io (GHC.load session LoadAllTargets)
697 changeDirectory :: String -> GHCi ()
698 changeDirectory dir = do
699 session <- getSession
700 graph <- io (GHC.getModuleGraph session)
701 when (not (null graph)) $
702 io $ putStr "Warning: changing directory causes all loaded modules to be unloaded,\nbecause the search path has changed.\n"
703 io (GHC.setTargets session [])
704 io (GHC.load session LoadAllTargets)
705 setContextAfterLoad session []
706 io (GHC.workingDirectoryChanged session)
707 dir <- expandPath dir
708 io (setCurrentDirectory dir)
710 editFile :: String -> GHCi ()
713 -- find the name of the "topmost" file loaded
714 session <- getSession
715 graph0 <- io (GHC.getModuleGraph session)
716 graph1 <- filterM (io . GHC.isLoaded session . GHC.ms_mod_name) graph0
717 let graph2 = flattenSCCs (GHC.topSortModuleGraph True graph1 Nothing)
718 case GHC.ml_hs_file (GHC.ms_location (last graph2)) of
719 Just file -> do_edit file
720 Nothing -> throwDyn (CmdLineError "unknown file name")
721 | otherwise = do_edit str
727 throwDyn (CmdLineError "editor not set, use :set editor")
728 io $ system (cmd ++ ' ':file)
731 defineMacro :: String -> GHCi ()
733 let (macro_name, definition) = break isSpace s
734 cmds <- io (readIORef commands)
736 then throwDyn (CmdLineError "invalid macro name")
738 if (macro_name `elem` map cmdName cmds)
739 then throwDyn (CmdLineError
740 ("command '" ++ macro_name ++ "' is already defined"))
743 -- give the expression a type signature, so we can be sure we're getting
744 -- something of the right type.
745 let new_expr = '(' : definition ++ ") :: String -> IO String"
747 -- compile the expression
749 maybe_hv <- io (GHC.compileExpr cms new_expr)
752 Just hv -> io (writeIORef commands --
753 (cmds ++ [(macro_name, runMacro hv, False, completeNone)]))
755 runMacro :: GHC.HValue{-String -> IO String-} -> String -> GHCi Bool
757 str <- io ((unsafeCoerce# fun :: String -> IO String) s)
758 stringLoop (lines str)
760 undefineMacro :: String -> GHCi ()
761 undefineMacro macro_name = do
762 cmds <- io (readIORef commands)
763 if (macro_name `elem` map cmdName builtin_commands)
764 then throwDyn (CmdLineError
765 ("command '" ++ macro_name ++ "' cannot be undefined"))
767 if (macro_name `notElem` map cmdName cmds)
768 then throwDyn (CmdLineError
769 ("command '" ++ macro_name ++ "' not defined"))
771 io (writeIORef commands (filter ((/= macro_name) . cmdName) cmds))
774 loadModule :: [(FilePath, Maybe Phase)] -> GHCi SuccessFlag
775 loadModule fs = timeIt (loadModule' fs)
777 loadModule_ :: [FilePath] -> GHCi ()
778 loadModule_ fs = do loadModule (zip fs (repeat Nothing)); return ()
780 loadModule' :: [(FilePath, Maybe Phase)] -> GHCi SuccessFlag
781 loadModule' files = do
782 session <- getSession
785 io (GHC.setTargets session [])
786 io (GHC.load session LoadAllTargets)
789 let (filenames, phases) = unzip files
790 exp_filenames <- mapM expandPath filenames
791 let files' = zip exp_filenames phases
792 targets <- io (mapM (uncurry GHC.guessTarget) files')
794 -- NOTE: we used to do the dependency anal first, so that if it
795 -- fails we didn't throw away the current set of modules. This would
796 -- require some re-working of the GHC interface, so we'll leave it
797 -- as a ToDo for now.
799 io (GHC.setTargets session targets)
800 ok <- io (GHC.load session LoadAllTargets)
804 checkModule :: String -> GHCi ()
806 let modl = GHC.mkModuleName m
807 session <- getSession
808 result <- io (GHC.checkModule session modl)
810 Nothing -> io $ putStrLn "Nothing"
811 Just r -> io $ putStrLn (showSDoc (
812 case GHC.checkedModuleInfo r of
813 Just cm | Just scope <- GHC.modInfoTopLevelScope cm ->
815 (local,global) = partition ((== modl) . GHC.moduleName . GHC.nameModule) scope
817 (text "global names: " <+> ppr global) $$
818 (text "local names: " <+> ppr local)
820 afterLoad (successIf (isJust result)) session
822 reloadModule :: String -> GHCi ()
824 io (revertCAFs) -- always revert CAFs on reload.
825 session <- getSession
826 ok <- io (GHC.load session LoadAllTargets)
829 io (revertCAFs) -- always revert CAFs on reload.
830 session <- getSession
831 ok <- io (GHC.load session (LoadUpTo (GHC.mkModuleName m)))
834 afterLoad ok session = do
835 io (revertCAFs) -- always revert CAFs on load.
837 discardActiveBreakPoints
838 graph <- io (GHC.getModuleGraph session)
839 graph' <- filterM (io . GHC.isLoaded session . GHC.ms_mod_name) graph
840 setContextAfterLoad session graph'
841 modulesLoadedMsg ok (map GHC.ms_mod_name graph')
843 setContextAfterLoad session [] = do
844 prel_mod <- getPrelude
845 io (GHC.setContext session [] [prel_mod])
846 setContextAfterLoad session ms = do
847 -- load a target if one is available, otherwise load the topmost module.
848 targets <- io (GHC.getTargets session)
849 case [ m | Just m <- map (findTarget ms) targets ] of
851 let graph' = flattenSCCs (GHC.topSortModuleGraph True ms Nothing) in
852 load_this (last graph')
857 = case filter (`matches` t) ms of
861 summary `matches` Target (TargetModule m) _
862 = GHC.ms_mod_name summary == m
863 summary `matches` Target (TargetFile f _) _
864 | Just f' <- GHC.ml_hs_file (GHC.ms_location summary) = f == f'
865 summary `matches` target
868 load_this summary | m <- GHC.ms_mod summary = do
869 b <- io (GHC.moduleIsInterpreted session m)
870 if b then io (GHC.setContext session [m] [])
872 prel_mod <- getPrelude
873 io (GHC.setContext session [] [prel_mod,m])
876 modulesLoadedMsg :: SuccessFlag -> [ModuleName] -> GHCi ()
877 modulesLoadedMsg ok mods = do
878 dflags <- getDynFlags
879 when (verbosity dflags > 0) $ do
881 | null mods = text "none."
883 punctuate comma (map ppr mods)) <> text "."
886 io (putStrLn (showSDoc (text "Failed, modules loaded: " <> mod_commas)))
888 io (putStrLn (showSDoc (text "Ok, modules loaded: " <> mod_commas)))
891 typeOfExpr :: String -> GHCi ()
893 = do cms <- getSession
894 maybe_ty <- io (GHC.exprType cms str)
897 Just ty -> do ty' <- cleanType ty
898 printForUser $ text str <> text " :: " <> ppr ty'
900 kindOfType :: String -> GHCi ()
902 = do cms <- getSession
903 maybe_ty <- io (GHC.typeKind cms str)
906 Just ty -> printForUser $ text str <> text " :: " <> ppr ty
908 quit :: String -> GHCi Bool
911 shellEscape :: String -> GHCi Bool
912 shellEscape str = io (system str >> return False)
914 -----------------------------------------------------------------------------
915 -- Browsing a module's contents
917 browseCmd :: String -> GHCi ()
920 ['*':m] | looksLikeModuleName m -> browseModule m False
921 [m] | looksLikeModuleName m -> browseModule m True
922 _ -> throwDyn (CmdLineError "syntax: :browse <module>")
924 browseModule m exports_only = do
926 modl <- if exports_only then lookupModule m
927 else wantInterpretedModule m
929 -- Temporarily set the context to the module we're interested in,
930 -- just so we can get an appropriate PrintUnqualified
931 (as,bs) <- io (GHC.getContext s)
932 prel_mod <- getPrelude
933 io (if exports_only then GHC.setContext s [] [prel_mod,modl]
934 else GHC.setContext s [modl] [])
935 unqual <- io (GHC.getPrintUnqual s)
936 io (GHC.setContext s as bs)
938 mb_mod_info <- io $ GHC.getModuleInfo s modl
940 Nothing -> throwDyn (CmdLineError ("unknown module: " ++ m))
943 | exports_only = GHC.modInfoExports mod_info
944 | otherwise = fromMaybe [] (GHC.modInfoTopLevelScope mod_info)
946 filtered = filterOutChildren names
948 things <- io $ mapM (GHC.lookupName s) filtered
950 dflags <- getDynFlags
951 let exts = dopt Opt_GlasgowExts dflags
952 io (putStrLn (showSDocForUser unqual (
953 vcat (map (pprTyThingInContext exts) (catMaybes things))
955 -- ToDo: modInfoInstances currently throws an exception for
956 -- package modules. When it works, we can do this:
957 -- $$ vcat (map GHC.pprInstance (GHC.modInfoInstances mod_info))
959 -----------------------------------------------------------------------------
960 -- Setting the module context
963 | all sensible mods = fn mods
964 | otherwise = throwDyn (CmdLineError "syntax: :module [+/-] [*]M1 ... [*]Mn")
966 (fn, mods) = case str of
967 '+':stuff -> (addToContext, words stuff)
968 '-':stuff -> (removeFromContext, words stuff)
969 stuff -> (newContext, words stuff)
971 sensible ('*':m) = looksLikeModuleName m
972 sensible m = looksLikeModuleName m
974 separate :: Session -> [String] -> [Module] -> [Module]
975 -> GHCi ([Module],[Module])
976 separate session [] as bs = return (as,bs)
977 separate session (('*':str):ms) as bs = do
978 m <- io $ GHC.findModule session (GHC.mkModuleName str) Nothing
979 b <- io $ GHC.moduleIsInterpreted session m
980 if b then separate session ms (m:as) bs
981 else throwDyn (CmdLineError ("module '"
982 ++ GHC.moduleNameString (GHC.moduleName m)
983 ++ "' is not interpreted"))
984 separate session (str:ms) as bs = do
985 m <- io $ GHC.findModule session (GHC.mkModuleName str) Nothing
986 separate session ms as (m:bs)
988 newContext :: [String] -> GHCi ()
991 (as,bs) <- separate s strs [] []
992 prel_mod <- getPrelude
993 let bs' = if null as && prel_mod `notElem` bs then prel_mod:bs else bs
994 io $ GHC.setContext s as bs'
997 addToContext :: [String] -> GHCi ()
998 addToContext strs = do
1000 (as,bs) <- io $ GHC.getContext s
1002 (new_as,new_bs) <- separate s strs [] []
1004 let as_to_add = new_as \\ (as ++ bs)
1005 bs_to_add = new_bs \\ (as ++ bs)
1007 io $ GHC.setContext s (as ++ as_to_add) (bs ++ bs_to_add)
1010 removeFromContext :: [String] -> GHCi ()
1011 removeFromContext strs = do
1013 (as,bs) <- io $ GHC.getContext s
1015 (as_to_remove,bs_to_remove) <- separate s strs [] []
1017 let as' = as \\ (as_to_remove ++ bs_to_remove)
1018 bs' = bs \\ (as_to_remove ++ bs_to_remove)
1020 io $ GHC.setContext s as' bs'
1022 ----------------------------------------------------------------------------
1025 -- set options in the interpreter. Syntax is exactly the same as the
1026 -- ghc command line, except that certain options aren't available (-C,
1029 -- This is pretty fragile: most options won't work as expected. ToDo:
1030 -- figure out which ones & disallow them.
1032 setCmd :: String -> GHCi ()
1034 = do st <- getGHCiState
1035 let opts = options st
1036 io $ putStrLn (showSDoc (
1037 text "options currently set: " <>
1040 else hsep (map (\o -> char '+' <> text (optToStr o)) opts)
1043 = case toArgs str of
1044 ("args":args) -> setArgs args
1045 ("prog":prog) -> setProg prog
1046 ("prompt":prompt) -> setPrompt (after 6)
1047 ("editor":cmd) -> setEditor (after 6)
1048 ("stop":cmd) -> setStop (after 4)
1049 wds -> setOptions wds
1050 where after n = dropWhile isSpace $ drop n $ dropWhile isSpace str
1054 setGHCiState st{ args = args }
1058 setGHCiState st{ progname = prog }
1060 io (hPutStrLn stderr "syntax: :set prog <progname>")
1064 setGHCiState st{ editor = cmd }
1068 setGHCiState st{ stop = cmd }
1070 setPrompt value = do
1073 then io $ hPutStrLn stderr $ "syntax: :set prompt <prompt>, currently \"" ++ prompt st ++ "\""
1074 else setGHCiState st{ prompt = remQuotes value }
1076 remQuotes ('\"':xs) | not (null xs) && last xs == '\"' = init xs
1080 do -- first, deal with the GHCi opts (+s, +t, etc.)
1081 let (plus_opts, minus_opts) = partition isPlus wds
1082 mapM_ setOpt plus_opts
1084 -- then, dynamic flags
1085 dflags <- getDynFlags
1086 let pkg_flags = packageFlags dflags
1087 (dflags',leftovers) <- io $ GHC.parseDynamicFlags dflags minus_opts
1089 if (not (null leftovers))
1090 then throwDyn (CmdLineError ("unrecognised flags: " ++
1094 new_pkgs <- setDynFlags dflags'
1096 -- if the package flags changed, we should reset the context
1097 -- and link the new packages.
1098 dflags <- getDynFlags
1099 when (packageFlags dflags /= pkg_flags) $ do
1100 io $ hPutStrLn stderr "package flags have changed, ressetting and loading new packages..."
1101 session <- getSession
1102 io (GHC.setTargets session [])
1103 io (GHC.load session LoadAllTargets)
1104 io (linkPackages dflags new_pkgs)
1105 setContextAfterLoad session []
1109 unsetOptions :: String -> GHCi ()
1111 = do -- first, deal with the GHCi opts (+s, +t, etc.)
1112 let opts = words str
1113 (minus_opts, rest1) = partition isMinus opts
1114 (plus_opts, rest2) = partition isPlus rest1
1116 if (not (null rest2))
1117 then io (putStrLn ("unknown option: '" ++ head rest2 ++ "'"))
1120 mapM_ unsetOpt plus_opts
1122 -- can't do GHC flags for now
1123 if (not (null minus_opts))
1124 then throwDyn (CmdLineError "can't unset GHC command-line flags")
1127 isMinus ('-':s) = True
1130 isPlus ('+':s) = True
1134 = case strToGHCiOpt str of
1135 Nothing -> io (putStrLn ("unknown option: '" ++ str ++ "'"))
1136 Just o -> setOption o
1139 = case strToGHCiOpt str of
1140 Nothing -> io (putStrLn ("unknown option: '" ++ str ++ "'"))
1141 Just o -> unsetOption o
1143 strToGHCiOpt :: String -> (Maybe GHCiOption)
1144 strToGHCiOpt "s" = Just ShowTiming
1145 strToGHCiOpt "t" = Just ShowType
1146 strToGHCiOpt "r" = Just RevertCAFs
1147 strToGHCiOpt _ = Nothing
1149 optToStr :: GHCiOption -> String
1150 optToStr ShowTiming = "s"
1151 optToStr ShowType = "t"
1152 optToStr RevertCAFs = "r"
1154 -- ---------------------------------------------------------------------------
1160 ["args"] -> io $ putStrLn (show (args st))
1161 ["prog"] -> io $ putStrLn (show (progname st))
1162 ["prompt"] -> io $ putStrLn (show (prompt st))
1163 ["editor"] -> io $ putStrLn (show (editor st))
1164 ["stop"] -> io $ putStrLn (show (stop st))
1165 ["modules" ] -> showModules
1166 ["bindings"] -> showBindings
1167 ["linker"] -> io showLinkerState
1168 ["breaks"] -> showBkptTable
1169 ["context"] -> showContext
1170 _ -> throwDyn (CmdLineError "syntax: :show [args|prog|prompt|editor|stop|modules|bindings|breaks|context]")
1173 session <- getSession
1174 let show_one ms = do m <- io (GHC.showModule session ms)
1176 graph <- io (GHC.getModuleGraph session)
1177 mapM_ show_one graph
1181 unqual <- io (GHC.getPrintUnqual s)
1182 bindings <- io (GHC.getBindings s)
1183 mapM_ showTyThing bindings
1186 showTyThing (AnId id) = do
1187 ty' <- cleanType (GHC.idType id)
1188 printForUser $ ppr id <> text " :: " <> ppr ty'
1189 showTyThing _ = return ()
1191 -- if -fglasgow-exts is on we show the foralls, otherwise we don't.
1192 cleanType :: Type -> GHCi Type
1194 dflags <- getDynFlags
1195 if dopt Opt_GlasgowExts dflags
1197 else return $! GHC.dropForAlls ty
1199 showBkptTable :: GHCi ()
1202 printForUser $ prettyLocations (breaks st)
1204 showContext :: GHCi ()
1206 session <- getSession
1207 resumes <- io $ GHC.getResumeContext session
1208 printForUser $ vcat (map pp_resume (reverse resumes))
1211 ptext SLIT("--> ") <> text (GHC.resumeStmt resume)
1212 $$ nest 2 (ptext SLIT("Stopped at") <+> ppr (GHC.resumeSpan resume))
1215 -- -----------------------------------------------------------------------------
1218 completeNone :: String -> IO [String]
1219 completeNone w = return []
1222 completeWord :: String -> Int -> Int -> IO (Maybe (String, [String]))
1223 completeWord w start end = do
1224 line <- Readline.getLineBuffer
1226 ':':_ | all isSpace (take (start-1) line) -> wrapCompleter completeCmd w
1228 | Just c <- is_cmd line -> do
1229 maybe_cmd <- lookupCommand c
1230 let (n,w') = selectWord (words' 0 line)
1232 Nothing -> return Nothing
1233 Just (_,_,False,complete) -> wrapCompleter complete w
1234 Just (_,_,True,complete) -> let complete' w = do rets <- complete w
1235 return (map (drop n) rets)
1236 in wrapCompleter complete' w'
1238 --printf "complete %s, start = %d, end = %d\n" w start end
1239 wrapCompleter completeIdentifier w
1240 where words' _ [] = []
1241 words' n str = let (w,r) = break isSpace str
1242 (s,r') = span isSpace r
1243 in (n,w):words' (n+length w+length s) r'
1244 -- In a Haskell expression we want to parse 'a-b' as three words
1245 -- where a compiler flag (ie. -fno-monomorphism-restriction) should
1246 -- only be a single word.
1247 selectWord [] = (0,w)
1248 selectWord ((offset,x):xs)
1249 | offset+length x >= start = (start-offset,take (end-offset) x)
1250 | otherwise = selectWord xs
1253 | ((':':w) : _) <- words (dropWhile isSpace line) = Just w
1254 | otherwise = Nothing
1257 cmds <- readIORef commands
1258 return (filter (w `isPrefixOf`) (map (':':) (map cmdName cmds)))
1260 completeMacro w = do
1261 cmds <- readIORef commands
1262 let cmds' = [ cmd | cmd <- map cmdName cmds, cmd `elem` map cmdName builtin_commands ]
1263 return (filter (w `isPrefixOf`) cmds')
1265 completeIdentifier w = do
1267 rdrs <- GHC.getRdrNamesInScope s
1268 return (filter (w `isPrefixOf`) (map (showSDoc.ppr) rdrs))
1270 completeModule w = do
1272 dflags <- GHC.getSessionDynFlags s
1273 let pkg_mods = allExposedModules dflags
1274 return (filter (w `isPrefixOf`) (map (showSDoc.ppr) pkg_mods))
1276 completeHomeModule w = do
1278 g <- GHC.getModuleGraph s
1279 let home_mods = map GHC.ms_mod_name g
1280 return (filter (w `isPrefixOf`) (map (showSDoc.ppr) home_mods))
1282 completeSetOptions w = do
1283 return (filter (w `isPrefixOf`) options)
1284 where options = "args":"prog":allFlags
1286 completeFilename = Readline.filenameCompletionFunction
1288 completeHomeModuleOrFile = unionComplete completeHomeModule completeFilename
1290 unionComplete :: (String -> IO [String]) -> (String -> IO [String]) -> String -> IO [String]
1291 unionComplete f1 f2 w = do
1296 wrapCompleter :: (String -> IO [String]) -> String -> IO (Maybe (String,[String]))
1297 wrapCompleter fun w = do
1300 [] -> return Nothing
1301 [x] -> return (Just (x,[]))
1302 xs -> case getCommonPrefix xs of
1303 "" -> return (Just ("",xs))
1304 pref -> return (Just (pref,xs))
1306 getCommonPrefix :: [String] -> String
1307 getCommonPrefix [] = ""
1308 getCommonPrefix (s:ss) = foldl common s ss
1309 where common s "" = ""
1311 common (c:cs) (d:ds)
1312 | c == d = c : common cs ds
1315 allExposedModules :: DynFlags -> [ModuleName]
1316 allExposedModules dflags
1317 = map GHC.mkModuleName (concat (map exposedModules (filter exposed (eltsUFM pkg_db))))
1319 pkg_db = pkgIdMap (pkgState dflags)
1321 completeCmd = completeNone
1322 completeMacro = completeNone
1323 completeIdentifier = completeNone
1324 completeModule = completeNone
1325 completeHomeModule = completeNone
1326 completeSetOptions = completeNone
1327 completeFilename = completeNone
1328 completeHomeModuleOrFile=completeNone
1329 completeBkpt = completeNone
1332 -- ---------------------------------------------------------------------------
1333 -- User code exception handling
1335 -- This is the exception handler for exceptions generated by the
1336 -- user's code and exceptions coming from children sessions;
1337 -- it normally just prints out the exception. The
1338 -- handler must be recursive, in case showing the exception causes
1339 -- more exceptions to be raised.
1341 -- Bugfix: if the user closed stdout or stderr, the flushing will fail,
1342 -- raising another exception. We therefore don't put the recursive
1343 -- handler arond the flushing operation, so if stderr is closed
1344 -- GHCi will just die gracefully rather than going into an infinite loop.
1345 handler :: Exception -> GHCi Bool
1347 handler exception = do
1349 io installSignalHandlers
1350 ghciHandle handler (showException exception >> return False)
1352 showException (DynException dyn) =
1353 case fromDynamic dyn of
1354 Nothing -> io (putStrLn ("*** Exception: (unknown)"))
1355 Just Interrupted -> io (putStrLn "Interrupted.")
1356 Just (CmdLineError s) -> io (putStrLn s) -- omit the location for CmdLineError
1357 Just ph@PhaseFailed{} -> io (putStrLn (showGhcException ph "")) -- ditto
1358 Just other_ghc_ex -> io (print other_ghc_ex)
1360 showException other_exception
1361 = io (putStrLn ("*** Exception: " ++ show other_exception))
1363 -----------------------------------------------------------------------------
1364 -- recursive exception handlers
1366 -- Don't forget to unblock async exceptions in the handler, or if we're
1367 -- in an exception loop (eg. let a = error a in a) the ^C exception
1368 -- may never be delivered. Thanks to Marcin for pointing out the bug.
1370 ghciHandle :: (Exception -> GHCi a) -> GHCi a -> GHCi a
1371 ghciHandle h (GHCi m) = GHCi $ \s ->
1372 Exception.catch (m s)
1373 (\e -> unGHCi (ghciUnblock (h e)) s)
1375 ghciUnblock :: GHCi a -> GHCi a
1376 ghciUnblock (GHCi a) = GHCi $ \s -> Exception.unblock (a s)
1379 -- ----------------------------------------------------------------------------
1382 expandPath :: String -> GHCi String
1384 case dropWhile isSpace path of
1386 tilde <- io (getEnv "HOME") -- will fail if HOME not defined
1387 return (tilde ++ '/':d)
1391 wantInterpretedModule :: String -> GHCi Module
1392 wantInterpretedModule str = do
1393 session <- getSession
1394 modl <- lookupModule str
1395 is_interpreted <- io (GHC.moduleIsInterpreted session modl)
1396 when (not is_interpreted) $
1397 throwDyn (CmdLineError ("module '" ++ str ++ "' is not interpreted"))
1400 wantNameFromInterpretedModule noCanDo str and_then = do
1401 session <- getSession
1402 names <- io $ GHC.parseName session str
1406 let modl = GHC.nameModule n
1407 is_interpreted <- io (GHC.moduleIsInterpreted session modl)
1408 if not is_interpreted
1409 then noCanDo n $ text "module " <> ppr modl <>
1410 text " is not interpreted"
1413 -- ----------------------------------------------------------------------------
1414 -- Windows console setup
1416 setUpConsole :: IO ()
1418 #ifdef mingw32_HOST_OS
1419 -- On Windows we need to set a known code page, otherwise the characters
1420 -- we read from the console will be be in some strange encoding, and
1421 -- similarly for characters we write to the console.
1423 -- At the moment, GHCi pretends all input is Latin-1. In the
1424 -- future we should support UTF-8, but for now we set the code pages
1427 -- It seems you have to set the font in the console window to
1428 -- a Unicode font in order for output to work properly,
1429 -- otherwise non-ASCII characters are mapped wrongly. sigh.
1430 -- (see MSDN for SetConsoleOutputCP()).
1432 setConsoleCP 28591 -- ISO Latin-1
1433 setConsoleOutputCP 28591 -- ISO Latin-1
1437 -- -----------------------------------------------------------------------------
1438 -- commands for debugger
1440 sprintCmd = pprintCommand False False
1441 printCmd = pprintCommand True False
1442 forceCmd = pprintCommand False True
1444 pprintCommand bind force str = do
1445 session <- getSession
1446 io $ pprintClosureCommand session bind force str
1448 stepCmd :: String -> GHCi Bool
1449 stepCmd [] = doContinue GHC.SingleStep
1450 stepCmd expression = runStmt expression GHC.SingleStep
1452 traceCmd :: String -> GHCi Bool
1453 traceCmd [] = doContinue GHC.RunAndLogSteps
1454 traceCmd expression = runStmt expression GHC.RunAndLogSteps
1456 continueCmd :: String -> GHCi Bool
1457 continueCmd [] = doContinue GHC.RunToCompletion
1458 continueCmd other = do
1459 io $ putStrLn "The continue command accepts no arguments."
1462 doContinue :: SingleStep -> GHCi Bool
1463 doContinue step = do
1464 session <- getSession
1465 runResult <- io $ GHC.resume session step
1466 afterRunStmt runResult
1469 abandonCmd :: String -> GHCi ()
1470 abandonCmd = noArgs $ do
1472 b <- io $ GHC.abandon s -- the prompt will change to indicate the new context
1473 when (not b) $ io $ putStrLn "There is no computation running."
1476 deleteCmd :: String -> GHCi ()
1477 deleteCmd argLine = do
1478 deleteSwitch $ words argLine
1480 deleteSwitch :: [String] -> GHCi ()
1482 io $ putStrLn "The delete command requires at least one argument."
1483 -- delete all break points
1484 deleteSwitch ("*":_rest) = discardActiveBreakPoints
1485 deleteSwitch idents = do
1486 mapM_ deleteOneBreak idents
1488 deleteOneBreak :: String -> GHCi ()
1490 | all isDigit str = deleteBreak (read str)
1491 | otherwise = return ()
1493 historyCmd :: String -> GHCi ()
1495 | null arg = history 20
1496 | all isDigit arg = history (read arg)
1497 | otherwise = io $ putStrLn "Syntax: :history [num]"
1501 resumes <- io $ GHC.getResumeContext s
1503 [] -> io $ putStrLn "Not stopped at a breakpoint"
1505 let hist = GHC.resumeHistory r
1506 (took,rest) = splitAt num hist
1507 spans <- mapM (io . GHC.getHistorySpan s) took
1508 let nums = map (printf "-%-3d:") [(1::Int)..]
1509 printForUser (vcat (zipWith (<+>) (map text nums) (map ppr spans)))
1510 io $ putStrLn $ if null rest then "<end of history>" else "..."
1512 backCmd :: String -> GHCi ()
1513 backCmd = noArgs $ do
1515 (names, ix, span) <- io $ GHC.back s
1516 printForUser $ ptext SLIT("Logged breakpoint at") <+> ppr span
1517 mapM_ (showTypeOfName s) names
1518 -- run the command set with ":set stop <cmd>"
1520 runCommand (stop st)
1523 forwardCmd :: String -> GHCi ()
1524 forwardCmd = noArgs $ do
1526 (names, ix, span) <- io $ GHC.forward s
1527 printForUser $ (if (ix == 0)
1528 then ptext SLIT("Stopped at")
1529 else ptext SLIT("Logged breakpoint at")) <+> ppr span
1530 mapM_ (showTypeOfName s) names
1531 -- run the command set with ":set stop <cmd>"
1533 runCommand (stop st)
1536 -- handle the "break" command
1537 breakCmd :: String -> GHCi ()
1538 breakCmd argLine = do
1539 session <- getSession
1540 breakSwitch session $ words argLine
1542 breakSwitch :: Session -> [String] -> GHCi ()
1543 breakSwitch _session [] = do
1544 io $ putStrLn "The break command requires at least one argument."
1545 breakSwitch session args@(arg1:rest)
1546 | looksLikeModuleName arg1 = do
1547 mod <- wantInterpretedModule arg1
1548 breakByModule session mod rest
1549 | all isDigit arg1 = do
1550 (toplevel, _) <- io $ GHC.getContext session
1552 (mod : _) -> breakByModuleLine mod (read arg1) rest
1554 io $ putStrLn "Cannot find default module for breakpoint."
1555 io $ putStrLn "Perhaps no modules are loaded for debugging?"
1556 | otherwise = do -- try parsing it as an identifier
1557 wantNameFromInterpretedModule noCanDo arg1 $ \name -> do
1558 let loc = GHC.nameSrcLoc name
1559 if GHC.isGoodSrcLoc loc
1560 then findBreakAndSet (GHC.nameModule name) $
1561 findBreakByCoord (Just (GHC.srcLocFile loc))
1562 (GHC.srcLocLine loc,
1564 else noCanDo name $ text "can't find its location: " <> ppr loc
1566 noCanDo n why = printForUser $
1567 text "cannot set breakpoint on " <> ppr n <> text ": " <> why
1569 breakByModule :: Session -> Module -> [String] -> GHCi ()
1570 breakByModule session mod args@(arg1:rest)
1571 | all isDigit arg1 = do -- looks like a line number
1572 breakByModuleLine mod (read arg1) rest
1573 | otherwise = io $ putStrLn "Invalid arguments to :break"
1575 breakByModuleLine :: Module -> Int -> [String] -> GHCi ()
1576 breakByModuleLine mod line args
1577 | [] <- args = findBreakAndSet mod $ findBreakByLine line
1578 | [col] <- args, all isDigit col =
1579 findBreakAndSet mod $ findBreakByCoord Nothing (line, read col)
1580 | otherwise = io $ putStrLn "Invalid arguments to :break"
1582 findBreakAndSet :: Module -> (TickArray -> Maybe (Int, SrcSpan)) -> GHCi ()
1583 findBreakAndSet mod lookupTickTree = do
1584 tickArray <- getTickArray mod
1585 (breakArray, _) <- getModBreak mod
1586 case lookupTickTree tickArray of
1587 Nothing -> io $ putStrLn $ "No breakpoints found at that location."
1588 Just (tick, span) -> do
1589 success <- io $ setBreakFlag True breakArray tick
1590 session <- getSession
1594 recordBreak $ BreakLocation
1600 text "Breakpoint " <> ppr nm <>
1602 then text " was already set at " <> ppr span
1603 else text " activated at " <> ppr span
1605 printForUser $ text "Breakpoint could not be activated at"
1608 -- When a line number is specified, the current policy for choosing
1609 -- the best breakpoint is this:
1610 -- - the leftmost complete subexpression on the specified line, or
1611 -- - the leftmost subexpression starting on the specified line, or
1612 -- - the rightmost subexpression enclosing the specified line
1614 findBreakByLine :: Int -> TickArray -> Maybe (BreakIndex,SrcSpan)
1615 findBreakByLine line arr
1616 | not (inRange (bounds arr) line) = Nothing
1618 listToMaybe (sortBy leftmost_largest complete) `mplus`
1619 listToMaybe (sortBy leftmost_smallest incomplete) `mplus`
1620 listToMaybe (sortBy rightmost ticks)
1624 starts_here = [ tick | tick@(nm,span) <- ticks,
1625 GHC.srcSpanStartLine span == line ]
1627 (complete,incomplete) = partition ends_here starts_here
1628 where ends_here (nm,span) = GHC.srcSpanEndLine span == line
1630 findBreakByCoord :: Maybe FastString -> (Int,Int) -> TickArray
1631 -> Maybe (BreakIndex,SrcSpan)
1632 findBreakByCoord mb_file (line, col) arr
1633 | not (inRange (bounds arr) line) = Nothing
1635 listToMaybe (sortBy rightmost contains)
1639 -- the ticks that span this coordinate
1640 contains = [ tick | tick@(nm,span) <- ticks, span `spans` (line,col),
1641 is_correct_file span ]
1643 is_correct_file span
1644 | Just f <- mb_file = GHC.srcSpanFile span == f
1648 leftmost_smallest (_,a) (_,b) = a `compare` b
1649 leftmost_largest (_,a) (_,b) = (GHC.srcSpanStart a `compare` GHC.srcSpanStart b)
1651 (GHC.srcSpanEnd b `compare` GHC.srcSpanEnd a)
1652 rightmost (_,a) (_,b) = b `compare` a
1654 spans :: SrcSpan -> (Int,Int) -> Bool
1655 spans span (l,c) = GHC.srcSpanStart span <= loc && loc <= GHC.srcSpanEnd span
1656 where loc = GHC.mkSrcLoc (GHC.srcSpanFile span) l c
1658 start_bold = BS.pack "\ESC[1m"
1659 end_bold = BS.pack "\ESC[0m"
1661 listCmd :: String -> GHCi ()
1663 mb_span <- getCurrentBreakSpan
1665 Nothing -> printForUser $ text "not stopped at a breakpoint; nothing to list"
1666 Just span -> io $ listAround span True
1667 listCmd str = list2 (words str)
1669 list2 [arg] | all isDigit arg = do
1670 session <- getSession
1671 (toplevel, _) <- io $ GHC.getContext session
1673 [] -> io $ putStrLn "No module to list"
1674 (mod : _) -> listModuleLine mod (read arg)
1675 list2 [arg1,arg2] | looksLikeModuleName arg1, all isDigit arg2 = do
1676 mod <- wantInterpretedModule arg1
1677 listModuleLine mod (read arg2)
1679 wantNameFromInterpretedModule noCanDo arg $ \name -> do
1680 let loc = GHC.nameSrcLoc name
1681 if GHC.isGoodSrcLoc loc
1683 tickArray <- getTickArray (GHC.nameModule name)
1684 let mb_span = findBreakByCoord (Just (GHC.srcLocFile loc))
1685 (GHC.srcLocLine loc, GHC.srcLocCol loc)
1688 Nothing -> io $ listAround (GHC.srcLocSpan loc) False
1689 Just (_,span) -> io $ listAround span False
1691 noCanDo name $ text "can't find its location: " <>
1694 noCanDo n why = printForUser $
1695 text "cannot list source code for " <> ppr n <> text ": " <> why
1697 io $ putStrLn "syntax: :list [<line> | <module> <line> | <identifier>]"
1699 listModuleLine :: Module -> Int -> GHCi ()
1700 listModuleLine modl line = do
1701 session <- getSession
1702 graph <- io (GHC.getModuleGraph session)
1703 let this = filter ((== modl) . GHC.ms_mod) graph
1705 [] -> panic "listModuleLine"
1707 let filename = fromJust (ml_hs_file (GHC.ms_location summ))
1708 loc = GHC.mkSrcLoc (mkFastString (filename)) line 0
1709 io $ listAround (GHC.srcLocSpan loc) False
1711 -- | list a section of a source file around a particular SrcSpan.
1712 -- If the highlight flag is True, also highlight the span using
1713 -- start_bold/end_bold.
1714 listAround span do_highlight = do
1715 contents <- BS.readFile (unpackFS file)
1717 lines = BS.split '\n' contents
1718 these_lines = take (line2 - line1 + 1 + pad_before + pad_after) $
1719 drop (line1 - 1 - pad_before) $ lines
1720 fst_line = max 1 (line1 - pad_before)
1721 line_nos = [ fst_line .. ]
1723 highlighted | do_highlight = zipWith highlight line_nos these_lines
1724 | otherwise = these_lines
1726 bs_line_nos = [ BS.pack (show l ++ " ") | l <- line_nos ]
1727 prefixed = zipWith BS.append bs_line_nos highlighted
1729 BS.putStrLn (BS.join (BS.pack "\n") prefixed)
1731 file = GHC.srcSpanFile span
1732 line1 = GHC.srcSpanStartLine span
1733 col1 = GHC.srcSpanStartCol span
1734 line2 = GHC.srcSpanEndLine span
1735 col2 = GHC.srcSpanEndCol span
1737 pad_before | line1 == 1 = 0
1742 | no == line1 && no == line2
1743 = let (a,r) = BS.splitAt col1 line
1744 (b,c) = BS.splitAt (col2-col1) r
1746 BS.concat [a,start_bold,b,end_bold,c]
1748 = let (a,b) = BS.splitAt col1 line in
1749 BS.concat [a, start_bold, b]
1751 = let (a,b) = BS.splitAt col2 line in
1752 BS.concat [a, end_bold, b]
1755 -- --------------------------------------------------------------------------
1758 getTickArray :: Module -> GHCi TickArray
1759 getTickArray modl = do
1761 let arrmap = tickarrays st
1762 case lookupModuleEnv arrmap modl of
1763 Just arr -> return arr
1765 (breakArray, ticks) <- getModBreak modl
1766 let arr = mkTickArray (assocs ticks)
1767 setGHCiState st{tickarrays = extendModuleEnv arrmap modl arr}
1770 discardTickArrays :: GHCi ()
1771 discardTickArrays = do
1773 setGHCiState st{tickarrays = emptyModuleEnv}
1775 mkTickArray :: [(BreakIndex,SrcSpan)] -> TickArray
1777 = accumArray (flip (:)) [] (1, max_line)
1778 [ (line, (nm,span)) | (nm,span) <- ticks,
1779 line <- srcSpanLines span ]
1781 max_line = maximum (map GHC.srcSpanEndLine (map snd ticks))
1782 srcSpanLines span = [ GHC.srcSpanStartLine span ..
1783 GHC.srcSpanEndLine span ]
1785 lookupModule :: String -> GHCi Module
1786 lookupModule modName
1787 = do session <- getSession
1788 io (GHC.findModule session (GHC.mkModuleName modName) Nothing)
1790 -- don't reset the counter back to zero?
1791 discardActiveBreakPoints :: GHCi ()
1792 discardActiveBreakPoints = do
1794 mapM (turnOffBreak.snd) (breaks st)
1795 setGHCiState $ st { breaks = [] }
1797 deleteBreak :: Int -> GHCi ()
1798 deleteBreak identity = do
1800 let oldLocations = breaks st
1801 (this,rest) = partition (\loc -> fst loc == identity) oldLocations
1803 then printForUser (text "Breakpoint" <+> ppr identity <+>
1804 text "does not exist")
1806 mapM (turnOffBreak.snd) this
1807 setGHCiState $ st { breaks = rest }
1809 turnOffBreak loc = do
1810 (arr, _) <- getModBreak (breakModule loc)
1811 io $ setBreakFlag False arr (breakTick loc)
1813 getModBreak :: Module -> GHCi (GHC.BreakArray, Array Int SrcSpan)
1814 getModBreak mod = do
1815 session <- getSession
1816 Just mod_info <- io $ GHC.getModuleInfo session mod
1817 let modBreaks = GHC.modInfoModBreaks mod_info
1818 let array = GHC.modBreaks_flags modBreaks
1819 let ticks = GHC.modBreaks_locs modBreaks
1820 return (array, ticks)
1822 setBreakFlag :: Bool -> GHC.BreakArray -> Int -> IO Bool
1823 setBreakFlag toggle array index
1824 | toggle = GHC.setBreakOn array index
1825 | otherwise = GHC.setBreakOff array index