| 1 | {-# OPTIONS -fno-cse #-} |
|---|
| 2 | -- -fno-cse is needed for GLOBAL_VAR's to behave properly |
|---|
| 3 | |
|---|
| 4 | ----------------------------------------------------------------------------- |
|---|
| 5 | -- |
|---|
| 6 | -- GHC Interactive User Interface |
|---|
| 7 | -- |
|---|
| 8 | -- (c) The GHC Team 2005-2006 |
|---|
| 9 | -- |
|---|
| 10 | ----------------------------------------------------------------------------- |
|---|
| 11 | |
|---|
| 12 | module InteractiveUI ( interactiveUI, ghciWelcomeMsg ) where |
|---|
| 13 | |
|---|
| 14 | #include "HsVersions.h" |
|---|
| 15 | |
|---|
| 16 | -- GHCi |
|---|
| 17 | import qualified GhciMonad ( args, runStmt ) |
|---|
| 18 | import GhciMonad hiding ( args, runStmt ) |
|---|
| 19 | import GhciTags |
|---|
| 20 | import Debugger |
|---|
| 21 | |
|---|
| 22 | -- The GHC interface |
|---|
| 23 | import DynFlags |
|---|
| 24 | import qualified GHC |
|---|
| 25 | import GHC ( LoadHowMuch(..), Target(..), TargetId(..), InteractiveImport(..), |
|---|
| 26 | TyThing(..), Phase, BreakIndex, Resume, SingleStep, Ghc, |
|---|
| 27 | handleSourceError ) |
|---|
| 28 | import HsImpExp |
|---|
| 29 | import HscTypes ( tyThingParent_maybe, handleFlagWarnings, getSafeMode, dep_pkgs ) |
|---|
| 30 | import Module |
|---|
| 31 | import Name |
|---|
| 32 | import Packages ( trusted, getPackageDetails, exposed, exposedModules, pkgIdMap ) |
|---|
| 33 | import PprTyThing |
|---|
| 34 | import RdrName ( getGRE_NameQualifier_maybes ) |
|---|
| 35 | import SrcLoc |
|---|
| 36 | import qualified Lexer |
|---|
| 37 | |
|---|
| 38 | import StringBuffer |
|---|
| 39 | import UniqFM ( eltsUFM ) |
|---|
| 40 | import Outputable hiding ( printForUser, printForUserPartWay, bold ) |
|---|
| 41 | |
|---|
| 42 | -- Other random utilities |
|---|
| 43 | import BasicTypes hiding ( isTopLevel ) |
|---|
| 44 | import Config |
|---|
| 45 | import Digraph |
|---|
| 46 | import Encoding |
|---|
| 47 | import FastString |
|---|
| 48 | import Linker |
|---|
| 49 | import Maybes ( orElse, expectJust ) |
|---|
| 50 | import NameSet |
|---|
| 51 | import Panic hiding ( showException ) |
|---|
| 52 | import StaticFlags |
|---|
| 53 | import Util ( on, global, toArgs, toCmdArgs, removeSpaces, getCmd, |
|---|
| 54 | filterOut, seqList, looksLikeModuleName, partitionWith ) |
|---|
| 55 | |
|---|
| 56 | -- Haskell Libraries |
|---|
| 57 | import System.Console.Haskeline as Haskeline |
|---|
| 58 | |
|---|
| 59 | import Control.Applicative hiding (empty) |
|---|
| 60 | import Control.Monad as Monad |
|---|
| 61 | import Control.Monad.Trans.Class |
|---|
| 62 | import Control.Monad.IO.Class |
|---|
| 63 | |
|---|
| 64 | import Data.Array |
|---|
| 65 | import qualified Data.ByteString.Char8 as BS |
|---|
| 66 | import Data.Char |
|---|
| 67 | import Data.IORef ( IORef, readIORef, writeIORef ) |
|---|
| 68 | import Data.List ( find, group, intercalate, intersperse, isPrefixOf, nub, |
|---|
| 69 | partition, sort, sortBy ) |
|---|
| 70 | import Data.Maybe |
|---|
| 71 | |
|---|
| 72 | import Exception hiding (catch) |
|---|
| 73 | |
|---|
| 74 | import Foreign.C |
|---|
| 75 | import Foreign.Safe |
|---|
| 76 | |
|---|
| 77 | import System.Cmd |
|---|
| 78 | import System.Directory |
|---|
| 79 | import System.Environment |
|---|
| 80 | import System.Exit ( exitWith, ExitCode(..) ) |
|---|
| 81 | import System.FilePath |
|---|
| 82 | import System.IO |
|---|
| 83 | import System.IO.Error |
|---|
| 84 | import System.IO.Unsafe ( unsafePerformIO ) |
|---|
| 85 | import Text.Printf |
|---|
| 86 | |
|---|
| 87 | #ifndef mingw32_HOST_OS |
|---|
| 88 | import System.Posix hiding ( getEnv ) |
|---|
| 89 | #else |
|---|
| 90 | import qualified System.Win32 |
|---|
| 91 | #endif |
|---|
| 92 | |
|---|
| 93 | import GHC.Exts ( unsafeCoerce# ) |
|---|
| 94 | import GHC.IO.Exception ( IOErrorType(InvalidArgument) ) |
|---|
| 95 | import GHC.IO.Handle ( hFlushAll ) |
|---|
| 96 | import GHC.TopHandler ( topHandler ) |
|---|
| 97 | |
|---|
| 98 | |
|---|
| 99 | ----------------------------------------------------------------------------- |
|---|
| 100 | |
|---|
| 101 | ghciWelcomeMsg :: String |
|---|
| 102 | ghciWelcomeMsg = "GHCi, version " ++ cProjectVersion ++ |
|---|
| 103 | ": http://www.haskell.org/ghc/ :? for help" |
|---|
| 104 | |
|---|
| 105 | cmdName :: Command -> String |
|---|
| 106 | cmdName (n,_,_) = n |
|---|
| 107 | |
|---|
| 108 | GLOBAL_VAR(macros_ref, [], [Command]) |
|---|
| 109 | |
|---|
| 110 | builtin_commands :: [Command] |
|---|
| 111 | builtin_commands = [ |
|---|
| 112 | -- Hugs users are accustomed to :e, so make sure it doesn't overlap |
|---|
| 113 | ("?", keepGoing help, noCompletion), |
|---|
| 114 | ("add", keepGoingPaths addModule, completeFilename), |
|---|
| 115 | ("abandon", keepGoing abandonCmd, noCompletion), |
|---|
| 116 | ("break", keepGoing breakCmd, completeIdentifier), |
|---|
| 117 | ("back", keepGoing backCmd, noCompletion), |
|---|
| 118 | ("browse", keepGoing' (browseCmd False), completeModule), |
|---|
| 119 | ("browse!", keepGoing' (browseCmd True), completeModule), |
|---|
| 120 | ("cd", keepGoing' changeDirectory, completeFilename), |
|---|
| 121 | ("check", keepGoing' checkModule, completeHomeModule), |
|---|
| 122 | ("continue", keepGoing continueCmd, noCompletion), |
|---|
| 123 | ("cmd", keepGoing cmdCmd, completeExpression), |
|---|
| 124 | ("ctags", keepGoing createCTagsWithLineNumbersCmd, completeFilename), |
|---|
| 125 | ("ctags!", keepGoing createCTagsWithRegExesCmd, completeFilename), |
|---|
| 126 | ("def", keepGoing (defineMacro False), completeExpression), |
|---|
| 127 | ("def!", keepGoing (defineMacro True), completeExpression), |
|---|
| 128 | ("delete", keepGoing deleteCmd, noCompletion), |
|---|
| 129 | ("edit", keepGoing' editFile, completeFilename), |
|---|
| 130 | ("etags", keepGoing createETagsFileCmd, completeFilename), |
|---|
| 131 | ("force", keepGoing forceCmd, completeExpression), |
|---|
| 132 | ("forward", keepGoing forwardCmd, noCompletion), |
|---|
| 133 | ("help", keepGoing help, noCompletion), |
|---|
| 134 | ("history", keepGoing historyCmd, noCompletion), |
|---|
| 135 | ("info", keepGoing' info, completeIdentifier), |
|---|
| 136 | ("issafe", keepGoing' isSafeCmd, completeModule), |
|---|
| 137 | ("kind", keepGoing' (kindOfType False), completeIdentifier), |
|---|
| 138 | ("kind!", keepGoing' (kindOfType True), completeIdentifier), |
|---|
| 139 | ("load", keepGoingPaths loadModule_, completeHomeModuleOrFile), |
|---|
| 140 | ("list", keepGoing' listCmd, noCompletion), |
|---|
| 141 | ("module", keepGoing moduleCmd, completeSetModule), |
|---|
| 142 | ("main", keepGoing runMain, completeFilename), |
|---|
| 143 | ("print", keepGoing printCmd, completeExpression), |
|---|
| 144 | ("quit", quit, noCompletion), |
|---|
| 145 | ("reload", keepGoing' reloadModule, noCompletion), |
|---|
| 146 | ("run", keepGoing runRun, completeFilename), |
|---|
| 147 | ("script", keepGoing' scriptCmd, completeFilename), |
|---|
| 148 | ("set", keepGoing setCmd, completeSetOptions), |
|---|
| 149 | ("seti", keepGoing setiCmd, completeSeti), |
|---|
| 150 | ("show", keepGoing showCmd, completeShowOptions), |
|---|
| 151 | ("showi", keepGoing showiCmd, completeShowiOptions), |
|---|
| 152 | ("sprint", keepGoing sprintCmd, completeExpression), |
|---|
| 153 | ("step", keepGoing stepCmd, completeIdentifier), |
|---|
| 154 | ("steplocal", keepGoing stepLocalCmd, completeIdentifier), |
|---|
| 155 | ("stepmodule",keepGoing stepModuleCmd, completeIdentifier), |
|---|
| 156 | ("type", keepGoing' typeOfExpr, completeExpression), |
|---|
| 157 | ("trace", keepGoing traceCmd, completeExpression), |
|---|
| 158 | ("undef", keepGoing undefineMacro, completeMacro), |
|---|
| 159 | ("unset", keepGoing unsetOptions, completeSetOptions) |
|---|
| 160 | ] |
|---|
| 161 | |
|---|
| 162 | |
|---|
| 163 | -- We initialize readline (in the interactiveUI function) to use |
|---|
| 164 | -- word_break_chars as the default set of completion word break characters. |
|---|
| 165 | -- This can be overridden for a particular command (for example, filename |
|---|
| 166 | -- expansion shouldn't consider '/' to be a word break) by setting the third |
|---|
| 167 | -- entry in the Command tuple above. |
|---|
| 168 | -- |
|---|
| 169 | -- NOTE: in order for us to override the default correctly, any custom entry |
|---|
| 170 | -- must be a SUBSET of word_break_chars. |
|---|
| 171 | word_break_chars :: String |
|---|
| 172 | word_break_chars = let symbols = "!#$%&*+/<=>?@\\^|-~" |
|---|
| 173 | specials = "(),;[]`{}" |
|---|
| 174 | spaces = " \t\n" |
|---|
| 175 | in spaces ++ specials ++ symbols |
|---|
| 176 | |
|---|
| 177 | flagWordBreakChars :: String |
|---|
| 178 | flagWordBreakChars = " \t\n" |
|---|
| 179 | |
|---|
| 180 | |
|---|
| 181 | keepGoing :: (String -> GHCi ()) -> (String -> InputT GHCi Bool) |
|---|
| 182 | keepGoing a str = keepGoing' (lift . a) str |
|---|
| 183 | |
|---|
| 184 | keepGoing' :: Monad m => (String -> m ()) -> String -> m Bool |
|---|
| 185 | keepGoing' a str = a str >> return False |
|---|
| 186 | |
|---|
| 187 | keepGoingPaths :: ([FilePath] -> InputT GHCi ()) -> (String -> InputT GHCi Bool) |
|---|
| 188 | keepGoingPaths a str |
|---|
| 189 | = do case toArgs str of |
|---|
| 190 | Left err -> liftIO $ hPutStrLn stderr err |
|---|
| 191 | Right args -> a args |
|---|
| 192 | return False |
|---|
| 193 | |
|---|
| 194 | shortHelpText :: String |
|---|
| 195 | shortHelpText = "use :? for help.\n" |
|---|
| 196 | |
|---|
| 197 | helpText :: String |
|---|
| 198 | helpText = |
|---|
| 199 | " Commands available from the prompt:\n" ++ |
|---|
| 200 | "\n" ++ |
|---|
| 201 | " <statement> evaluate/run <statement>\n" ++ |
|---|
| 202 | " : repeat last command\n" ++ |
|---|
| 203 | " :{\\n ..lines.. \\n:}\\n multiline command\n" ++ |
|---|
| 204 | " :add [*]<module> ... add module(s) to the current target set\n" ++ |
|---|
| 205 | " :browse[!] [[*]<mod>] display the names defined by module <mod>\n" ++ |
|---|
| 206 | " (!: more details; *: all top-level names)\n" ++ |
|---|
| 207 | " :cd <dir> change directory to <dir>\n" ++ |
|---|
| 208 | " :cmd <expr> run the commands returned by <expr>::IO String\n" ++ |
|---|
| 209 | " :ctags[!] [<file>] create tags file for Vi (default: \"tags\")\n" ++ |
|---|
| 210 | " (!: use regex instead of line number)\n" ++ |
|---|
| 211 | " :def <cmd> <expr> define a command :<cmd>\n" ++ |
|---|
| 212 | " :edit <file> edit file\n" ++ |
|---|
| 213 | " :edit edit last module\n" ++ |
|---|
| 214 | " :etags [<file>] create tags file for Emacs (default: \"TAGS\")\n" ++ |
|---|
| 215 | " :help, :? display this list of commands\n" ++ |
|---|
| 216 | " :info [<name> ...] display information about the given names\n" ++ |
|---|
| 217 | " :issafe [<mod>] display safe haskell information of module <mod>\n" ++ |
|---|
| 218 | " :kind <type> show the kind of <type>\n" ++ |
|---|
| 219 | " :load [*]<module> ... load module(s) and their dependents\n" ++ |
|---|
| 220 | " :main [<arguments> ...] run the main function with the given arguments\n" ++ |
|---|
| 221 | " :module [+/-] [*]<mod> ... set the context for expression evaluation\n" ++ |
|---|
| 222 | " :quit exit GHCi\n" ++ |
|---|
| 223 | " :reload reload the current module set\n" ++ |
|---|
| 224 | " :run function [<arguments> ...] run the function with the given arguments\n" ++ |
|---|
| 225 | " :script <filename> run the script <filename>\n" ++ |
|---|
| 226 | " :type <expr> show the type of <expr>\n" ++ |
|---|
| 227 | " :undef <cmd> undefine user-defined command :<cmd>\n" ++ |
|---|
| 228 | " :!<command> run the shell command <command>\n" ++ |
|---|
| 229 | "\n" ++ |
|---|
| 230 | " -- Commands for debugging:\n" ++ |
|---|
| 231 | "\n" ++ |
|---|
| 232 | " :abandon at a breakpoint, abandon current computation\n" ++ |
|---|
| 233 | " :back go back in the history (after :trace)\n" ++ |
|---|
| 234 | " :break [<mod>] <l> [<col>] set a breakpoint at the specified location\n" ++ |
|---|
| 235 | " :break <name> set a breakpoint on the specified function\n" ++ |
|---|
| 236 | " :continue resume after a breakpoint\n" ++ |
|---|
| 237 | " :delete <number> delete the specified breakpoint\n" ++ |
|---|
| 238 | " :delete * delete all breakpoints\n" ++ |
|---|
| 239 | " :force <expr> print <expr>, forcing unevaluated parts\n" ++ |
|---|
| 240 | " :forward go forward in the history (after :back)\n" ++ |
|---|
| 241 | " :history [<n>] after :trace, show the execution history\n" ++ |
|---|
| 242 | " :list show the source code around current breakpoint\n" ++ |
|---|
| 243 | " :list identifier show the source code for <identifier>\n" ++ |
|---|
| 244 | " :list [<module>] <line> show the source code around line number <line>\n" ++ |
|---|
| 245 | " :print [<name> ...] prints a value without forcing its computation\n" ++ |
|---|
| 246 | " :sprint [<name> ...] simplifed version of :print\n" ++ |
|---|
| 247 | " :step single-step after stopping at a breakpoint\n"++ |
|---|
| 248 | " :step <expr> single-step into <expr>\n"++ |
|---|
| 249 | " :steplocal single-step within the current top-level binding\n"++ |
|---|
| 250 | " :stepmodule single-step restricted to the current module\n"++ |
|---|
| 251 | " :trace trace after stopping at a breakpoint\n"++ |
|---|
| 252 | " :trace <expr> evaluate <expr> with tracing on (see :history)\n"++ |
|---|
| 253 | |
|---|
| 254 | "\n" ++ |
|---|
| 255 | " -- Commands for changing settings:\n" ++ |
|---|
| 256 | "\n" ++ |
|---|
| 257 | " :set <option> ... set options\n" ++ |
|---|
| 258 | " :seti <option> ... set options for interactive evaluation only\n" ++ |
|---|
| 259 | " :set args <arg> ... set the arguments returned by System.getArgs\n" ++ |
|---|
| 260 | " :set prog <progname> set the value returned by System.getProgName\n" ++ |
|---|
| 261 | " :set prompt <prompt> set the prompt used in GHCi\n" ++ |
|---|
| 262 | " :set editor <cmd> set the command used for :edit\n" ++ |
|---|
| 263 | " :set stop [<n>] <cmd> set the command to run when a breakpoint is hit\n" ++ |
|---|
| 264 | " :unset <option> ... unset options\n" ++ |
|---|
| 265 | "\n" ++ |
|---|
| 266 | " Options for ':set' and ':unset':\n" ++ |
|---|
| 267 | "\n" ++ |
|---|
| 268 | " +m allow multiline commands\n" ++ |
|---|
| 269 | " +r revert top-level expressions after each evaluation\n" ++ |
|---|
| 270 | " +s print timing/memory stats after each evaluation\n" ++ |
|---|
| 271 | " +t print type after evaluation\n" ++ |
|---|
| 272 | " -<flags> most GHC command line flags can also be set here\n" ++ |
|---|
| 273 | " (eg. -v2, -fglasgow-exts, etc.)\n" ++ |
|---|
| 274 | " for GHCi-specific flags, see User's Guide,\n"++ |
|---|
| 275 | " Flag reference, Interactive-mode options\n" ++ |
|---|
| 276 | "\n" ++ |
|---|
| 277 | " -- Commands for displaying information:\n" ++ |
|---|
| 278 | "\n" ++ |
|---|
| 279 | " :show bindings show the current bindings made at the prompt\n" ++ |
|---|
| 280 | " :show breaks show the active breakpoints\n" ++ |
|---|
| 281 | " :show context show the breakpoint context\n" ++ |
|---|
| 282 | " :show imports show the current imports\n" ++ |
|---|
| 283 | " :show modules show the currently loaded modules\n" ++ |
|---|
| 284 | " :show packages show the currently active package flags\n" ++ |
|---|
| 285 | " :show language show the currently active language flags\n" ++ |
|---|
| 286 | " :show <setting> show value of <setting>, which is one of\n" ++ |
|---|
| 287 | " [args, prog, prompt, editor, stop]\n" ++ |
|---|
| 288 | " :showi language show language flags for interactive evaluation\n" ++ |
|---|
| 289 | "\n" |
|---|
| 290 | |
|---|
| 291 | findEditor :: IO String |
|---|
| 292 | findEditor = do |
|---|
| 293 | getEnv "EDITOR" |
|---|
| 294 | `catchIO` \_ -> do |
|---|
| 295 | #if mingw32_HOST_OS |
|---|
| 296 | win <- System.Win32.getWindowsDirectory |
|---|
| 297 | return (win </> "notepad.exe") |
|---|
| 298 | #else |
|---|
| 299 | return "" |
|---|
| 300 | #endif |
|---|
| 301 | |
|---|
| 302 | foreign import ccall unsafe "rts_isProfiled" isProfiled :: IO CInt |
|---|
| 303 | |
|---|
| 304 | default_progname, default_prompt, default_stop :: String |
|---|
| 305 | default_progname = "<interactive>" |
|---|
| 306 | default_prompt = "%s> " |
|---|
| 307 | default_stop = "" |
|---|
| 308 | |
|---|
| 309 | default_args :: [String] |
|---|
| 310 | default_args = [] |
|---|
| 311 | |
|---|
| 312 | interactiveUI :: [(FilePath, Maybe Phase)] -> Maybe [String] |
|---|
| 313 | -> Ghc () |
|---|
| 314 | interactiveUI srcs maybe_exprs = do |
|---|
| 315 | -- although GHCi compiles with -prof, it is not usable: the byte-code |
|---|
| 316 | -- compiler and interpreter don't work with profiling. So we check for |
|---|
| 317 | -- this up front and emit a helpful error message (#2197) |
|---|
| 318 | i <- liftIO $ isProfiled |
|---|
| 319 | when (i /= 0) $ |
|---|
| 320 | ghcError (InstallationError "GHCi cannot be used when compiled with -prof") |
|---|
| 321 | |
|---|
| 322 | -- HACK! If we happen to get into an infinite loop (eg the user |
|---|
| 323 | -- types 'let x=x in x' at the prompt), then the thread will block |
|---|
| 324 | -- on a blackhole, and become unreachable during GC. The GC will |
|---|
| 325 | -- detect that it is unreachable and send it the NonTermination |
|---|
| 326 | -- exception. However, since the thread is unreachable, everything |
|---|
| 327 | -- it refers to might be finalized, including the standard Handles. |
|---|
| 328 | -- This sounds like a bug, but we don't have a good solution right |
|---|
| 329 | -- now. |
|---|
| 330 | _ <- liftIO $ newStablePtr stdin |
|---|
| 331 | _ <- liftIO $ newStablePtr stdout |
|---|
| 332 | _ <- liftIO $ newStablePtr stderr |
|---|
| 333 | |
|---|
| 334 | -- Initialise buffering for the *interpreted* I/O system |
|---|
| 335 | initInterpBuffering |
|---|
| 336 | |
|---|
| 337 | -- The initial set of DynFlags used for interactive evaluation is the same |
|---|
| 338 | -- as the global DynFlags, plus -XExtendedDefaultRules |
|---|
| 339 | dflags <- getDynFlags |
|---|
| 340 | GHC.setInteractiveDynFlags (xopt_set dflags Opt_ExtendedDefaultRules) |
|---|
| 341 | |
|---|
| 342 | liftIO $ when (isNothing maybe_exprs) $ do |
|---|
| 343 | -- Only for GHCi (not runghc and ghc -e): |
|---|
| 344 | |
|---|
| 345 | -- Turn buffering off for the compiled program's stdout/stderr |
|---|
| 346 | turnOffBuffering |
|---|
| 347 | -- Turn buffering off for GHCi's stdout |
|---|
| 348 | hFlush stdout |
|---|
| 349 | hSetBuffering stdout NoBuffering |
|---|
| 350 | -- We don't want the cmd line to buffer any input that might be |
|---|
| 351 | -- intended for the program, so unbuffer stdin. |
|---|
| 352 | hSetBuffering stdin NoBuffering |
|---|
| 353 | #if defined(mingw32_HOST_OS) |
|---|
| 354 | -- On Unix, stdin will use the locale encoding. The IO library |
|---|
| 355 | -- doesn't do this on Windows (yet), so for now we use UTF-8, |
|---|
| 356 | -- for consistency with GHC 6.10 and to make the tests work. |
|---|
| 357 | hSetEncoding stdin utf8 |
|---|
| 358 | #endif |
|---|
| 359 | |
|---|
| 360 | default_editor <- liftIO $ findEditor |
|---|
| 361 | |
|---|
| 362 | startGHCi (runGHCi srcs maybe_exprs) |
|---|
| 363 | GHCiState{ progname = default_progname, |
|---|
| 364 | GhciMonad.args = default_args, |
|---|
| 365 | prompt = default_prompt, |
|---|
| 366 | stop = default_stop, |
|---|
| 367 | editor = default_editor, |
|---|
| 368 | options = [], |
|---|
| 369 | line_number = 1, |
|---|
| 370 | break_ctr = 0, |
|---|
| 371 | breaks = [], |
|---|
| 372 | tickarrays = emptyModuleEnv, |
|---|
| 373 | last_command = Nothing, |
|---|
| 374 | cmdqueue = [], |
|---|
| 375 | remembered_ctx = [], |
|---|
| 376 | transient_ctx = [], |
|---|
| 377 | ghc_e = isJust maybe_exprs |
|---|
| 378 | } |
|---|
| 379 | |
|---|
| 380 | return () |
|---|
| 381 | |
|---|
| 382 | withGhcAppData :: (FilePath -> IO a) -> IO a -> IO a |
|---|
| 383 | withGhcAppData right left = do |
|---|
| 384 | either_dir <- tryIO (getAppUserDataDirectory "ghc") |
|---|
| 385 | case either_dir of |
|---|
| 386 | Right dir -> |
|---|
| 387 | do createDirectoryIfMissing False dir `catchIO` \_ -> return () |
|---|
| 388 | right dir |
|---|
| 389 | _ -> left |
|---|
| 390 | |
|---|
| 391 | runGHCi :: [(FilePath, Maybe Phase)] -> Maybe [String] -> GHCi () |
|---|
| 392 | runGHCi paths maybe_exprs = do |
|---|
| 393 | let |
|---|
| 394 | read_dot_files = not opt_IgnoreDotGhci |
|---|
| 395 | |
|---|
| 396 | current_dir = return (Just ".ghci") |
|---|
| 397 | |
|---|
| 398 | app_user_dir = liftIO $ withGhcAppData |
|---|
| 399 | (\dir -> return (Just (dir </> "ghci.conf"))) |
|---|
| 400 | (return Nothing) |
|---|
| 401 | |
|---|
| 402 | home_dir = do |
|---|
| 403 | either_dir <- liftIO $ tryIO (getEnv "HOME") |
|---|
| 404 | case either_dir of |
|---|
| 405 | Right home -> return (Just (home </> ".ghci")) |
|---|
| 406 | _ -> return Nothing |
|---|
| 407 | |
|---|
| 408 | canonicalizePath' :: FilePath -> IO (Maybe FilePath) |
|---|
| 409 | canonicalizePath' fp = liftM Just (canonicalizePath fp) |
|---|
| 410 | `catchIO` \_ -> return Nothing |
|---|
| 411 | |
|---|
| 412 | sourceConfigFile :: FilePath -> GHCi () |
|---|
| 413 | sourceConfigFile file = do |
|---|
| 414 | exists <- liftIO $ doesFileExist file |
|---|
| 415 | when exists $ do |
|---|
| 416 | dir_ok <- liftIO $ checkPerms (getDirectory file) |
|---|
| 417 | file_ok <- liftIO $ checkPerms file |
|---|
| 418 | when (dir_ok && file_ok) $ do |
|---|
| 419 | either_hdl <- liftIO $ tryIO (openFile file ReadMode) |
|---|
| 420 | case either_hdl of |
|---|
| 421 | Left _e -> return () |
|---|
| 422 | -- NOTE: this assumes that runInputT won't affect the terminal; |
|---|
| 423 | -- can we assume this will always be the case? |
|---|
| 424 | -- This would be a good place for runFileInputT. |
|---|
| 425 | Right hdl -> |
|---|
| 426 | do runInputTWithPrefs defaultPrefs defaultSettings $ |
|---|
| 427 | runCommands $ fileLoop hdl |
|---|
| 428 | liftIO (hClose hdl `catchIO` \_ -> return ()) |
|---|
| 429 | where |
|---|
| 430 | getDirectory f = case takeDirectory f of "" -> "."; d -> d |
|---|
| 431 | -- |
|---|
| 432 | |
|---|
| 433 | setGHCContextFromGHCiState |
|---|
| 434 | |
|---|
| 435 | dflags <- getDynFlags |
|---|
| 436 | when (read_dot_files) $ do |
|---|
| 437 | mcfgs0 <- sequence $ [ current_dir, app_user_dir, home_dir ] ++ map (return . Just ) (ghciScripts dflags) |
|---|
| 438 | mcfgs <- liftIO $ mapM canonicalizePath' (catMaybes mcfgs0) |
|---|
| 439 | mapM_ sourceConfigFile $ nub $ catMaybes mcfgs |
|---|
| 440 | -- nub, because we don't want to read .ghci twice if the |
|---|
| 441 | -- CWD is $HOME. |
|---|
| 442 | |
|---|
| 443 | -- Perform a :load for files given on the GHCi command line |
|---|
| 444 | -- When in -e mode, if the load fails then we want to stop |
|---|
| 445 | -- immediately rather than going on to evaluate the expression. |
|---|
| 446 | when (not (null paths)) $ do |
|---|
| 447 | ok <- ghciHandle (\e -> do showException e; return Failed) $ |
|---|
| 448 | -- TODO: this is a hack. |
|---|
| 449 | runInputTWithPrefs defaultPrefs defaultSettings $ |
|---|
| 450 | loadModule paths |
|---|
| 451 | when (isJust maybe_exprs && failed ok) $ |
|---|
| 452 | liftIO (exitWith (ExitFailure 1)) |
|---|
| 453 | |
|---|
| 454 | -- if verbosity is greater than 0, or we are connected to a |
|---|
| 455 | -- terminal, display the prompt in the interactive loop. |
|---|
| 456 | is_tty <- liftIO (hIsTerminalDevice stdin) |
|---|
| 457 | let show_prompt = verbosity dflags > 0 || is_tty |
|---|
| 458 | |
|---|
| 459 | -- reset line number |
|---|
| 460 | getGHCiState >>= \st -> setGHCiState st{line_number=1} |
|---|
| 461 | |
|---|
| 462 | case maybe_exprs of |
|---|
| 463 | Nothing -> |
|---|
| 464 | do |
|---|
| 465 | -- enter the interactive loop |
|---|
| 466 | runGHCiInput $ runCommands $ nextInputLine show_prompt is_tty |
|---|
| 467 | Just exprs -> do |
|---|
| 468 | -- just evaluate the expression we were given |
|---|
| 469 | enqueueCommands exprs |
|---|
| 470 | let hdle e = do st <- getGHCiState |
|---|
| 471 | -- flush the interpreter's stdout/stderr on exit (#3890) |
|---|
| 472 | flushInterpBuffers |
|---|
| 473 | -- Jump through some hoops to get the |
|---|
| 474 | -- current progname in the exception text: |
|---|
| 475 | -- <progname>: <exception> |
|---|
| 476 | liftIO $ withProgName (progname st) |
|---|
| 477 | $ topHandler e |
|---|
| 478 | -- this used to be topHandlerFastExit, see #2228 |
|---|
| 479 | runInputTWithPrefs defaultPrefs defaultSettings $ do |
|---|
| 480 | runCommands' hdle (return Nothing) |
|---|
| 481 | |
|---|
| 482 | -- and finally, exit |
|---|
| 483 | liftIO $ when (verbosity dflags > 0) $ putStrLn "Leaving GHCi." |
|---|
| 484 | |
|---|
| 485 | runGHCiInput :: InputT GHCi a -> GHCi a |
|---|
| 486 | runGHCiInput f = do |
|---|
| 487 | dflags <- getDynFlags |
|---|
| 488 | histFile <- if dopt Opt_GhciHistory dflags |
|---|
| 489 | then liftIO $ withGhcAppData (\dir -> return (Just (dir </> "ghci_history"))) |
|---|
| 490 | (return Nothing) |
|---|
| 491 | else return Nothing |
|---|
| 492 | runInputT |
|---|
| 493 | (setComplete ghciCompleteWord $ defaultSettings {historyFile = histFile}) |
|---|
| 494 | f |
|---|
| 495 | |
|---|
| 496 | -- | How to get the next input line from the user |
|---|
| 497 | nextInputLine :: Bool -> Bool -> InputT GHCi (Maybe String) |
|---|
| 498 | nextInputLine show_prompt is_tty |
|---|
| 499 | | is_tty = do |
|---|
| 500 | prmpt <- if show_prompt then lift mkPrompt else return "" |
|---|
| 501 | r <- getInputLine prmpt |
|---|
| 502 | incrementLineNo |
|---|
| 503 | return r |
|---|
| 504 | | otherwise = do |
|---|
| 505 | when show_prompt $ lift mkPrompt >>= liftIO . putStr |
|---|
| 506 | fileLoop stdin |
|---|
| 507 | |
|---|
| 508 | -- NOTE: We only read .ghci files if they are owned by the current user, |
|---|
| 509 | -- and aren't world writable. Otherwise, we could be accidentally |
|---|
| 510 | -- running code planted by a malicious third party. |
|---|
| 511 | |
|---|
| 512 | -- Furthermore, We only read ./.ghci if . is owned by the current user |
|---|
| 513 | -- and isn't writable by anyone else. I think this is sufficient: we |
|---|
| 514 | -- don't need to check .. and ../.. etc. because "." always refers to |
|---|
| 515 | -- the same directory while a process is running. |
|---|
| 516 | |
|---|
| 517 | checkPerms :: String -> IO Bool |
|---|
| 518 | #ifdef mingw32_HOST_OS |
|---|
| 519 | checkPerms _ = return True |
|---|
| 520 | #else |
|---|
| 521 | checkPerms name = |
|---|
| 522 | handleIO (\_ -> return False) $ do |
|---|
| 523 | st <- getFileStatus name |
|---|
| 524 | me <- getRealUserID |
|---|
| 525 | if fileOwner st /= me then do |
|---|
| 526 | putStrLn $ "WARNING: " ++ name ++ " is owned by someone else, IGNORING!" |
|---|
| 527 | return False |
|---|
| 528 | else do |
|---|
| 529 | let mode = System.Posix.fileMode st |
|---|
| 530 | if (groupWriteMode == (mode `intersectFileModes` groupWriteMode)) |
|---|
| 531 | || (otherWriteMode == (mode `intersectFileModes` otherWriteMode)) |
|---|
| 532 | then do |
|---|
| 533 | putStrLn $ "*** WARNING: " ++ name ++ |
|---|
| 534 | " is writable by someone else, IGNORING!" |
|---|
| 535 | return False |
|---|
| 536 | else return True |
|---|
| 537 | #endif |
|---|
| 538 | |
|---|
| 539 | incrementLineNo :: InputT GHCi () |
|---|
| 540 | incrementLineNo = do |
|---|
| 541 | st <- lift $ getGHCiState |
|---|
| 542 | let ln = 1+(line_number st) |
|---|
| 543 | lift $ setGHCiState st{line_number=ln} |
|---|
| 544 | |
|---|
| 545 | fileLoop :: Handle -> InputT GHCi (Maybe String) |
|---|
| 546 | fileLoop hdl = do |
|---|
| 547 | l <- liftIO $ tryIO $ hGetLine hdl |
|---|
| 548 | case l of |
|---|
| 549 | Left e | isEOFError e -> return Nothing |
|---|
| 550 | | InvalidArgument <- etype -> return Nothing |
|---|
| 551 | | otherwise -> liftIO $ ioError e |
|---|
| 552 | where etype = ioeGetErrorType e |
|---|
| 553 | -- treat InvalidArgument in the same way as EOF: |
|---|
| 554 | -- this can happen if the user closed stdin, or |
|---|
| 555 | -- perhaps did getContents which closes stdin at |
|---|
| 556 | -- EOF. |
|---|
| 557 | Right l' -> do |
|---|
| 558 | incrementLineNo |
|---|
| 559 | return (Just l') |
|---|
| 560 | |
|---|
| 561 | mkPrompt :: GHCi String |
|---|
| 562 | mkPrompt = do |
|---|
| 563 | imports <- GHC.getContext |
|---|
| 564 | resumes <- GHC.getResumeContext |
|---|
| 565 | |
|---|
| 566 | context_bit <- |
|---|
| 567 | case resumes of |
|---|
| 568 | [] -> return empty |
|---|
| 569 | r:_ -> do |
|---|
| 570 | let ix = GHC.resumeHistoryIx r |
|---|
| 571 | if ix == 0 |
|---|
| 572 | then return (brackets (ppr (GHC.resumeSpan r)) <> space) |
|---|
| 573 | else do |
|---|
| 574 | let hist = GHC.resumeHistory r !! (ix-1) |
|---|
| 575 | pan <- GHC.getHistorySpan hist |
|---|
| 576 | return (brackets (ppr (negate ix) <> char ':' |
|---|
| 577 | <+> ppr pan) <> space) |
|---|
| 578 | let |
|---|
| 579 | dots | _:rs <- resumes, not (null rs) = text "... " |
|---|
| 580 | | otherwise = empty |
|---|
| 581 | |
|---|
| 582 | rev_imports = reverse imports -- rightmost are the most recent |
|---|
| 583 | modules_bit = |
|---|
| 584 | hsep [ char '*' <> ppr m | IIModule m <- rev_imports ] <+> |
|---|
| 585 | hsep (map ppr [ myIdeclName d | IIDecl d <- rev_imports ]) |
|---|
| 586 | |
|---|
| 587 | -- use the 'as' name if there is one |
|---|
| 588 | myIdeclName d | Just m <- ideclAs d = m |
|---|
| 589 | | otherwise = unLoc (ideclName d) |
|---|
| 590 | |
|---|
| 591 | deflt_prompt = dots <> context_bit <> modules_bit |
|---|
| 592 | |
|---|
| 593 | f ('%':'s':xs) = deflt_prompt <> f xs |
|---|
| 594 | f ('%':'%':xs) = char '%' <> f xs |
|---|
| 595 | f (x:xs) = char x <> f xs |
|---|
| 596 | f [] = empty |
|---|
| 597 | |
|---|
| 598 | st <- getGHCiState |
|---|
| 599 | return (showSDoc (f (prompt st))) |
|---|
| 600 | |
|---|
| 601 | |
|---|
| 602 | queryQueue :: GHCi (Maybe String) |
|---|
| 603 | queryQueue = do |
|---|
| 604 | st <- getGHCiState |
|---|
| 605 | case cmdqueue st of |
|---|
| 606 | [] -> return Nothing |
|---|
| 607 | c:cs -> do setGHCiState st{ cmdqueue = cs } |
|---|
| 608 | return (Just c) |
|---|
| 609 | |
|---|
| 610 | -- | The main read-eval-print loop |
|---|
| 611 | runCommands :: InputT GHCi (Maybe String) -> InputT GHCi () |
|---|
| 612 | runCommands = runCommands' handler |
|---|
| 613 | |
|---|
| 614 | runCommands' :: (SomeException -> GHCi Bool) -- ^ Exception handler |
|---|
| 615 | -> InputT GHCi (Maybe String) -> InputT GHCi () |
|---|
| 616 | runCommands' eh gCmd = do |
|---|
| 617 | b <- ghandle (\e -> case fromException e of |
|---|
| 618 | Just UserInterrupt -> return $ Just False |
|---|
| 619 | _ -> case fromException e of |
|---|
| 620 | Just ghce -> |
|---|
| 621 | do liftIO (print (ghce :: GhcException)) |
|---|
| 622 | return Nothing |
|---|
| 623 | _other -> |
|---|
| 624 | liftIO (Exception.throwIO e)) |
|---|
| 625 | (runOneCommand eh gCmd) |
|---|
| 626 | case b of |
|---|
| 627 | Nothing -> return () |
|---|
| 628 | Just _ -> runCommands' eh gCmd |
|---|
| 629 | |
|---|
| 630 | -- | Evaluate a single line of user input (either :<command> or Haskell code) |
|---|
| 631 | runOneCommand :: (SomeException -> GHCi Bool) -> InputT GHCi (Maybe String) |
|---|
| 632 | -> InputT GHCi (Maybe Bool) |
|---|
| 633 | runOneCommand eh gCmd = do |
|---|
| 634 | -- run a previously queued command if there is one, otherwise get new |
|---|
| 635 | -- input from user |
|---|
| 636 | mb_cmd0 <- noSpace (lift queryQueue) |
|---|
| 637 | mb_cmd1 <- maybe (noSpace gCmd) (return . Just) mb_cmd0 |
|---|
| 638 | case mb_cmd1 of |
|---|
| 639 | Nothing -> return Nothing |
|---|
| 640 | Just c -> ghciHandle (\e -> lift $ eh e >>= return . Just) $ |
|---|
| 641 | handleSourceError printErrorAndKeepGoing |
|---|
| 642 | (doCommand c) |
|---|
| 643 | -- source error's are handled by runStmt |
|---|
| 644 | -- is the handler necessary here? |
|---|
| 645 | where |
|---|
| 646 | printErrorAndKeepGoing err = do |
|---|
| 647 | GHC.printException err |
|---|
| 648 | return $ Just True |
|---|
| 649 | |
|---|
| 650 | noSpace q = q >>= maybe (return Nothing) |
|---|
| 651 | (\c -> case removeSpaces c of |
|---|
| 652 | "" -> noSpace q |
|---|
| 653 | ":{" -> multiLineCmd q |
|---|
| 654 | c' -> return (Just c') ) |
|---|
| 655 | multiLineCmd q = do |
|---|
| 656 | st <- lift getGHCiState |
|---|
| 657 | let p = prompt st |
|---|
| 658 | lift $ setGHCiState st{ prompt = "%s| " } |
|---|
| 659 | mb_cmd <- collectCommand q "" |
|---|
| 660 | lift $ getGHCiState >>= \st' -> setGHCiState st'{ prompt = p } |
|---|
| 661 | return mb_cmd |
|---|
| 662 | -- we can't use removeSpaces for the sublines here, so |
|---|
| 663 | -- multiline commands are somewhat more brittle against |
|---|
| 664 | -- fileformat errors (such as \r in dos input on unix), |
|---|
| 665 | -- we get rid of any extra spaces for the ":}" test; |
|---|
| 666 | -- we also avoid silent failure if ":}" is not found; |
|---|
| 667 | -- and since there is no (?) valid occurrence of \r (as |
|---|
| 668 | -- opposed to its String representation, "\r") inside a |
|---|
| 669 | -- ghci command, we replace any such with ' ' (argh:-( |
|---|
| 670 | collectCommand q c = q >>= |
|---|
| 671 | maybe (liftIO (ioError collectError)) |
|---|
| 672 | (\l->if removeSpaces l == ":}" |
|---|
| 673 | then return (Just $ removeSpaces c) |
|---|
| 674 | else collectCommand q (c ++ "\n" ++ map normSpace l)) |
|---|
| 675 | where normSpace '\r' = ' ' |
|---|
| 676 | normSpace x = x |
|---|
| 677 | -- SDM (2007-11-07): is userError the one to use here? |
|---|
| 678 | collectError = userError "unterminated multiline command :{ .. :}" |
|---|
| 679 | |
|---|
| 680 | -- | Handle a line of input |
|---|
| 681 | doCommand :: String -> InputT GHCi (Maybe Bool) |
|---|
| 682 | |
|---|
| 683 | -- command |
|---|
| 684 | doCommand (':' : cmd) = do |
|---|
| 685 | result <- specialCommand cmd |
|---|
| 686 | case result of |
|---|
| 687 | True -> return Nothing |
|---|
| 688 | _ -> return $ Just True |
|---|
| 689 | |
|---|
| 690 | -- haskell |
|---|
| 691 | doCommand stmt = do |
|---|
| 692 | ml <- lift $ isOptionSet Multiline |
|---|
| 693 | if ml |
|---|
| 694 | then do |
|---|
| 695 | mb_stmt <- checkInputForLayout stmt gCmd |
|---|
| 696 | case mb_stmt of |
|---|
| 697 | Nothing -> return $ Just True |
|---|
| 698 | Just ml_stmt -> do |
|---|
| 699 | result <- timeIt $ lift $ runStmt ml_stmt GHC.RunToCompletion |
|---|
| 700 | return $ Just result |
|---|
| 701 | else do |
|---|
| 702 | result <- timeIt $ lift $ runStmt stmt GHC.RunToCompletion |
|---|
| 703 | return $ Just result |
|---|
| 704 | |
|---|
| 705 | -- #4316 |
|---|
| 706 | -- lex the input. If there is an unclosed layout context, request input |
|---|
| 707 | checkInputForLayout :: String -> InputT GHCi (Maybe String) |
|---|
| 708 | -> InputT GHCi (Maybe String) |
|---|
| 709 | checkInputForLayout stmt getStmt = do |
|---|
| 710 | dflags' <- lift $ getDynFlags |
|---|
| 711 | let dflags = xopt_set dflags' Opt_AlternativeLayoutRule |
|---|
| 712 | st0 <- lift $ getGHCiState |
|---|
| 713 | let buf' = stringToStringBuffer stmt |
|---|
| 714 | loc = mkRealSrcLoc (fsLit (progname st0)) (line_number st0) 1 |
|---|
| 715 | pstate = Lexer.mkPState dflags buf' loc |
|---|
| 716 | case Lexer.unP goToEnd pstate of |
|---|
| 717 | (Lexer.POk _ False) -> return $ Just stmt |
|---|
| 718 | _other -> do |
|---|
| 719 | st1 <- lift getGHCiState |
|---|
| 720 | let p = prompt st1 |
|---|
| 721 | lift $ setGHCiState st1{ prompt = "%s| " } |
|---|
| 722 | mb_stmt <- ghciHandle (\ex -> case fromException ex of |
|---|
| 723 | Just UserInterrupt -> return Nothing |
|---|
| 724 | _ -> case fromException ex of |
|---|
| 725 | Just ghce -> |
|---|
| 726 | do liftIO (print (ghce :: GhcException)) |
|---|
| 727 | return Nothing |
|---|
| 728 | _other -> liftIO (Exception.throwIO ex)) |
|---|
| 729 | getStmt |
|---|
| 730 | lift $ getGHCiState >>= \st' -> setGHCiState st'{ prompt = p } |
|---|
| 731 | -- the recursive call does not recycle parser state |
|---|
| 732 | -- as we use a new string buffer |
|---|
| 733 | case mb_stmt of |
|---|
| 734 | Nothing -> return Nothing |
|---|
| 735 | Just str -> if str == "" |
|---|
| 736 | then return $ Just stmt |
|---|
| 737 | else do |
|---|
| 738 | checkInputForLayout (stmt++"\n"++str) getStmt |
|---|
| 739 | where goToEnd = do |
|---|
| 740 | eof <- Lexer.nextIsEOF |
|---|
| 741 | if eof |
|---|
| 742 | then Lexer.activeContext |
|---|
| 743 | else Lexer.lexer return >> goToEnd |
|---|
| 744 | |
|---|
| 745 | enqueueCommands :: [String] -> GHCi () |
|---|
| 746 | enqueueCommands cmds = do |
|---|
| 747 | st <- getGHCiState |
|---|
| 748 | setGHCiState st{ cmdqueue = cmds ++ cmdqueue st } |
|---|
| 749 | |
|---|
| 750 | -- | If we one of these strings prefixes a command, then we treat it as a decl |
|---|
| 751 | -- rather than a stmt. |
|---|
| 752 | declPrefixes :: [String] |
|---|
| 753 | declPrefixes = ["class ","data ","newtype ","type ","instance ", "deriving ", |
|---|
| 754 | "foreign "] |
|---|
| 755 | |
|---|
| 756 | -- | Entry point to execute some haskell code from user |
|---|
| 757 | runStmt :: String -> SingleStep -> GHCi Bool |
|---|
| 758 | runStmt stmt step |
|---|
| 759 | -- empty |
|---|
| 760 | | null (filter (not.isSpace) stmt) |
|---|
| 761 | = return False |
|---|
| 762 | |
|---|
| 763 | -- import |
|---|
| 764 | | "import " `isPrefixOf` stmt |
|---|
| 765 | = do addImportToContext stmt; return False |
|---|
| 766 | |
|---|
| 767 | -- data, class, newtype... |
|---|
| 768 | | any (flip isPrefixOf stmt) declPrefixes |
|---|
| 769 | = do _ <- liftIO $ tryIO $ hFlushAll stdin |
|---|
| 770 | result <- GhciMonad.runDecls stmt |
|---|
| 771 | afterRunStmt (const True) (GHC.RunOk result) |
|---|
| 772 | |
|---|
| 773 | | otherwise |
|---|
| 774 | = do -- In the new IO library, read handles buffer data even if the Handle |
|---|
| 775 | -- is set to NoBuffering. This causes problems for GHCi where there |
|---|
| 776 | -- are really two stdin Handles. So we flush any bufferred data in |
|---|
| 777 | -- GHCi's stdin Handle here (only relevant if stdin is attached to |
|---|
| 778 | -- a file, otherwise the read buffer can't be flushed). |
|---|
| 779 | _ <- liftIO $ tryIO $ hFlushAll stdin |
|---|
| 780 | m_result <- GhciMonad.runStmt stmt step |
|---|
| 781 | case m_result of |
|---|
| 782 | Nothing -> return False |
|---|
| 783 | Just result -> afterRunStmt (const True) result |
|---|
| 784 | |
|---|
| 785 | -- | Clean up the GHCi environment after a statement has run |
|---|
| 786 | afterRunStmt :: (SrcSpan -> Bool) -> GHC.RunResult -> GHCi Bool |
|---|
| 787 | afterRunStmt _ (GHC.RunException e) = throw e |
|---|
| 788 | afterRunStmt step_here run_result = do |
|---|
| 789 | resumes <- GHC.getResumeContext |
|---|
| 790 | case run_result of |
|---|
| 791 | GHC.RunOk names -> do |
|---|
| 792 | show_types <- isOptionSet ShowType |
|---|
| 793 | when show_types $ printTypeOfNames names |
|---|
| 794 | GHC.RunBreak _ names mb_info |
|---|
| 795 | | isNothing mb_info || |
|---|
| 796 | step_here (GHC.resumeSpan $ head resumes) -> do |
|---|
| 797 | mb_id_loc <- toBreakIdAndLocation mb_info |
|---|
| 798 | let bCmd = maybe "" ( \(_,l) -> onBreakCmd l ) mb_id_loc |
|---|
| 799 | if (null bCmd) |
|---|
| 800 | then printStoppedAtBreakInfo (head resumes) names |
|---|
| 801 | else enqueueCommands [bCmd] |
|---|
| 802 | -- run the command set with ":set stop <cmd>" |
|---|
| 803 | st <- getGHCiState |
|---|
| 804 | enqueueCommands [stop st] |
|---|
| 805 | return () |
|---|
| 806 | | otherwise -> resume step_here GHC.SingleStep >>= |
|---|
| 807 | afterRunStmt step_here >> return () |
|---|
| 808 | _ -> return () |
|---|
| 809 | |
|---|
| 810 | flushInterpBuffers |
|---|
| 811 | liftIO installSignalHandlers |
|---|
| 812 | b <- isOptionSet RevertCAFs |
|---|
| 813 | when b revertCAFs |
|---|
| 814 | |
|---|
| 815 | return (case run_result of GHC.RunOk _ -> True; _ -> False) |
|---|
| 816 | |
|---|
| 817 | toBreakIdAndLocation :: |
|---|
| 818 | Maybe GHC.BreakInfo -> GHCi (Maybe (Int, BreakLocation)) |
|---|
| 819 | toBreakIdAndLocation Nothing = return Nothing |
|---|
| 820 | toBreakIdAndLocation (Just inf) = do |
|---|
| 821 | let md = GHC.breakInfo_module inf |
|---|
| 822 | nm = GHC.breakInfo_number inf |
|---|
| 823 | st <- getGHCiState |
|---|
| 824 | return $ listToMaybe [ id_loc | id_loc@(_,loc) <- breaks st, |
|---|
| 825 | breakModule loc == md, |
|---|
| 826 | breakTick loc == nm ] |
|---|
| 827 | |
|---|
| 828 | printStoppedAtBreakInfo :: Resume -> [Name] -> GHCi () |
|---|
| 829 | printStoppedAtBreakInfo res names = do |
|---|
| 830 | printForUser $ ptext (sLit "Stopped at") <+> |
|---|
| 831 | ppr (GHC.resumeSpan res) |
|---|
| 832 | -- printTypeOfNames session names |
|---|
| 833 | let namesSorted = sortBy compareNames names |
|---|
| 834 | tythings <- catMaybes `liftM` mapM GHC.lookupName namesSorted |
|---|
| 835 | docs <- mapM pprTypeAndContents [i | AnId i <- tythings] |
|---|
| 836 | printForUserPartWay $ vcat docs |
|---|
| 837 | |
|---|
| 838 | printTypeOfNames :: [Name] -> GHCi () |
|---|
| 839 | printTypeOfNames names |
|---|
| 840 | = mapM_ (printTypeOfName ) $ sortBy compareNames names |
|---|
| 841 | |
|---|
| 842 | compareNames :: Name -> Name -> Ordering |
|---|
| 843 | n1 `compareNames` n2 = compareWith n1 `compare` compareWith n2 |
|---|
| 844 | where compareWith n = (getOccString n, getSrcSpan n) |
|---|
| 845 | |
|---|
| 846 | printTypeOfName :: Name -> GHCi () |
|---|
| 847 | printTypeOfName n |
|---|
| 848 | = do maybe_tything <- GHC.lookupName n |
|---|
| 849 | case maybe_tything of |
|---|
| 850 | Nothing -> return () |
|---|
| 851 | Just thing -> printTyThing thing |
|---|
| 852 | |
|---|
| 853 | |
|---|
| 854 | data MaybeCommand = GotCommand Command | BadCommand | NoLastCommand |
|---|
| 855 | |
|---|
| 856 | -- | Entry point for execution a ':<command>' input from user |
|---|
| 857 | specialCommand :: String -> InputT GHCi Bool |
|---|
| 858 | specialCommand ('!':str) = lift $ shellEscape (dropWhile isSpace str) |
|---|
| 859 | specialCommand str = do |
|---|
| 860 | let (cmd,rest) = break isSpace str |
|---|
| 861 | maybe_cmd <- lift $ lookupCommand cmd |
|---|
| 862 | case maybe_cmd of |
|---|
| 863 | GotCommand (_,f,_) -> f (dropWhile isSpace rest) |
|---|
| 864 | BadCommand -> |
|---|
| 865 | do liftIO $ hPutStr stdout ("unknown command ':" ++ cmd ++ "'\n" |
|---|
| 866 | ++ shortHelpText) |
|---|
| 867 | return False |
|---|
| 868 | NoLastCommand -> |
|---|
| 869 | do liftIO $ hPutStr stdout ("there is no last command to perform\n" |
|---|
| 870 | ++ shortHelpText) |
|---|
| 871 | return False |
|---|
| 872 | |
|---|
| 873 | shellEscape :: String -> GHCi Bool |
|---|
| 874 | shellEscape str = liftIO (system str >> return False) |
|---|
| 875 | |
|---|
| 876 | lookupCommand :: String -> GHCi (MaybeCommand) |
|---|
| 877 | lookupCommand "" = do |
|---|
| 878 | st <- getGHCiState |
|---|
| 879 | case last_command st of |
|---|
| 880 | Just c -> return $ GotCommand c |
|---|
| 881 | Nothing -> return NoLastCommand |
|---|
| 882 | lookupCommand str = do |
|---|
| 883 | mc <- liftIO $ lookupCommand' str |
|---|
| 884 | st <- getGHCiState |
|---|
| 885 | setGHCiState st{ last_command = mc } |
|---|
| 886 | return $ case mc of |
|---|
| 887 | Just c -> GotCommand c |
|---|
| 888 | Nothing -> BadCommand |
|---|
| 889 | |
|---|
| 890 | lookupCommand' :: String -> IO (Maybe Command) |
|---|
| 891 | lookupCommand' ":" = return Nothing |
|---|
| 892 | lookupCommand' str' = do |
|---|
| 893 | macros <- readIORef macros_ref |
|---|
| 894 | let{ (str, cmds) = case str' of |
|---|
| 895 | ':' : rest -> (rest, builtin_commands) |
|---|
| 896 | _ -> (str', builtin_commands ++ macros) } |
|---|
| 897 | -- look for exact match first, then the first prefix match |
|---|
| 898 | -- We consider builtin commands first: since new macros are appended |
|---|
| 899 | -- on the *end* of the macros list, this is consistent with the view |
|---|
| 900 | -- that things defined earlier should take precedence. See also #3858 |
|---|
| 901 | return $ case [ c | c <- cmds, str == cmdName c ] of |
|---|
| 902 | c:_ -> Just c |
|---|
| 903 | [] -> case [ c | c@(s,_,_) <- cmds, str `isPrefixOf` s ] of |
|---|
| 904 | [] -> Nothing |
|---|
| 905 | c:_ -> Just c |
|---|
| 906 | |
|---|
| 907 | getCurrentBreakSpan :: GHCi (Maybe SrcSpan) |
|---|
| 908 | getCurrentBreakSpan = do |
|---|
| 909 | resumes <- GHC.getResumeContext |
|---|
| 910 | case resumes of |
|---|
| 911 | [] -> return Nothing |
|---|
| 912 | (r:_) -> do |
|---|
| 913 | let ix = GHC.resumeHistoryIx r |
|---|
| 914 | if ix == 0 |
|---|
| 915 | then return (Just (GHC.resumeSpan r)) |
|---|
| 916 | else do |
|---|
| 917 | let hist = GHC.resumeHistory r !! (ix-1) |
|---|
| 918 | pan <- GHC.getHistorySpan hist |
|---|
| 919 | return (Just pan) |
|---|
| 920 | |
|---|
| 921 | getCurrentBreakModule :: GHCi (Maybe Module) |
|---|
| 922 | getCurrentBreakModule = do |
|---|
| 923 | resumes <- GHC.getResumeContext |
|---|
| 924 | case resumes of |
|---|
| 925 | [] -> return Nothing |
|---|
| 926 | (r:_) -> do |
|---|
| 927 | let ix = GHC.resumeHistoryIx r |
|---|
| 928 | if ix == 0 |
|---|
| 929 | then return (GHC.breakInfo_module `liftM` GHC.resumeBreakInfo r) |
|---|
| 930 | else do |
|---|
| 931 | let hist = GHC.resumeHistory r !! (ix-1) |
|---|
| 932 | return $ Just $ GHC.getHistoryModule hist |
|---|
| 933 | |
|---|
| 934 | ----------------------------------------------------------------------------- |
|---|
| 935 | -- |
|---|
| 936 | -- Commands |
|---|
| 937 | -- |
|---|
| 938 | ----------------------------------------------------------------------------- |
|---|
| 939 | |
|---|
| 940 | noArgs :: GHCi () -> String -> GHCi () |
|---|
| 941 | noArgs m "" = m |
|---|
| 942 | noArgs _ _ = liftIO $ putStrLn "This command takes no arguments" |
|---|
| 943 | |
|---|
| 944 | withSandboxOnly :: String -> GHCi () -> GHCi () |
|---|
| 945 | withSandboxOnly cmd this = do |
|---|
| 946 | dflags <- getDynFlags |
|---|
| 947 | if not (dopt Opt_GhciSandbox dflags) |
|---|
| 948 | then printForUser (text cmd <+> |
|---|
| 949 | ptext (sLit "is not supported with -fno-ghci-sandbox")) |
|---|
| 950 | else this |
|---|
| 951 | |
|---|
| 952 | ----------------------------------------------------------------------------- |
|---|
| 953 | -- :help |
|---|
| 954 | |
|---|
| 955 | help :: String -> GHCi () |
|---|
| 956 | help _ = liftIO (putStr helpText) |
|---|
| 957 | |
|---|
| 958 | ----------------------------------------------------------------------------- |
|---|
| 959 | -- :info |
|---|
| 960 | |
|---|
| 961 | info :: String -> InputT GHCi () |
|---|
| 962 | info "" = ghcError (CmdLineError "syntax: ':i <thing-you-want-info-about>'") |
|---|
| 963 | info s = handleSourceError GHC.printException $ do |
|---|
| 964 | unqual <- GHC.getPrintUnqual |
|---|
| 965 | sdocs <- mapM infoThing (words s) |
|---|
| 966 | mapM_ (liftIO . putStrLn . showSDocForUser unqual) sdocs |
|---|
| 967 | |
|---|
| 968 | infoThing :: GHC.GhcMonad m => String -> m SDoc |
|---|
| 969 | infoThing str = do |
|---|
| 970 | dflags <- getDynFlags |
|---|
| 971 | let pefas = dopt Opt_PrintExplicitForalls dflags |
|---|
| 972 | names <- GHC.parseName str |
|---|
| 973 | mb_stuffs <- mapM GHC.getInfo names |
|---|
| 974 | let filtered = filterOutChildren (\(t,_f,_i) -> t) (catMaybes mb_stuffs) |
|---|
| 975 | return $ vcat (intersperse (text "") $ map (pprInfo pefas) filtered) |
|---|
| 976 | |
|---|
| 977 | -- Filter out names whose parent is also there Good |
|---|
| 978 | -- example is '[]', which is both a type and data |
|---|
| 979 | -- constructor in the same type |
|---|
| 980 | filterOutChildren :: (a -> TyThing) -> [a] -> [a] |
|---|
| 981 | filterOutChildren get_thing xs |
|---|
| 982 | = filterOut has_parent xs |
|---|
| 983 | where |
|---|
| 984 | all_names = mkNameSet (map (getName . get_thing) xs) |
|---|
| 985 | has_parent x = case tyThingParent_maybe (get_thing x) of |
|---|
| 986 | Just p -> getName p `elemNameSet` all_names |
|---|
| 987 | Nothing -> False |
|---|
| 988 | |
|---|
| 989 | pprInfo :: PrintExplicitForalls -> (TyThing, Fixity, [GHC.ClsInst]) -> SDoc |
|---|
| 990 | pprInfo pefas (thing, fixity, insts) |
|---|
| 991 | = pprTyThingInContextLoc pefas thing |
|---|
| 992 | $$ show_fixity fixity |
|---|
| 993 | $$ vcat (map GHC.pprInstance insts) |
|---|
| 994 | where |
|---|
| 995 | show_fixity fix |
|---|
| 996 | | fix == GHC.defaultFixity = empty |
|---|
| 997 | | otherwise = ppr fix <+> pprInfixName (GHC.getName thing) |
|---|
| 998 | |
|---|
| 999 | ----------------------------------------------------------------------------- |
|---|
| 1000 | -- :main |
|---|
| 1001 | |
|---|
| 1002 | runMain :: String -> GHCi () |
|---|
| 1003 | runMain s = case toArgs s of |
|---|
| 1004 | Left err -> liftIO (hPutStrLn stderr err) |
|---|
| 1005 | Right args -> |
|---|
| 1006 | do dflags <- getDynFlags |
|---|
| 1007 | case mainFunIs dflags of |
|---|
| 1008 | Nothing -> doWithArgs args "main" |
|---|
| 1009 | Just f -> doWithArgs args f |
|---|
| 1010 | |
|---|
| 1011 | ----------------------------------------------------------------------------- |
|---|
| 1012 | -- :run |
|---|
| 1013 | |
|---|
| 1014 | runRun :: String -> GHCi () |
|---|
| 1015 | runRun s = case toCmdArgs s of |
|---|
| 1016 | Left err -> liftIO (hPutStrLn stderr err) |
|---|
| 1017 | Right (cmd, args) -> doWithArgs args cmd |
|---|
| 1018 | |
|---|
| 1019 | doWithArgs :: [String] -> String -> GHCi () |
|---|
| 1020 | doWithArgs args cmd = enqueueCommands ["System.Environment.withArgs " ++ |
|---|
| 1021 | show args ++ " (" ++ cmd ++ ")"] |
|---|
| 1022 | |
|---|
| 1023 | ----------------------------------------------------------------------------- |
|---|
| 1024 | -- :cd |
|---|
| 1025 | |
|---|
| 1026 | changeDirectory :: String -> InputT GHCi () |
|---|
| 1027 | changeDirectory "" = do |
|---|
| 1028 | -- :cd on its own changes to the user's home directory |
|---|
| 1029 | either_dir <- liftIO $ tryIO getHomeDirectory |
|---|
| 1030 | case either_dir of |
|---|
| 1031 | Left _e -> return () |
|---|
| 1032 | Right dir -> changeDirectory dir |
|---|
| 1033 | changeDirectory dir = do |
|---|
| 1034 | graph <- GHC.getModuleGraph |
|---|
| 1035 | when (not (null graph)) $ |
|---|
| 1036 | liftIO $ putStrLn "Warning: changing directory causes all loaded modules to be unloaded,\nbecause the search path has changed." |
|---|
| 1037 | GHC.setTargets [] |
|---|
| 1038 | _ <- GHC.load LoadAllTargets |
|---|
| 1039 | lift $ setContextAfterLoad False [] |
|---|
| 1040 | GHC.workingDirectoryChanged |
|---|
| 1041 | dir' <- expandPath dir |
|---|
| 1042 | liftIO $ setCurrentDirectory dir' |
|---|
| 1043 | |
|---|
| 1044 | trySuccess :: GHC.GhcMonad m => m SuccessFlag -> m SuccessFlag |
|---|
| 1045 | trySuccess act = |
|---|
| 1046 | handleSourceError (\e -> do GHC.printException e |
|---|
| 1047 | return Failed) $ do |
|---|
| 1048 | act |
|---|
| 1049 | |
|---|
| 1050 | ----------------------------------------------------------------------------- |
|---|
| 1051 | -- :edit |
|---|
| 1052 | |
|---|
| 1053 | editFile :: String -> InputT GHCi () |
|---|
| 1054 | editFile str = |
|---|
| 1055 | do file <- if null str then lift chooseEditFile else return str |
|---|
| 1056 | st <- lift getGHCiState |
|---|
| 1057 | let cmd = editor st |
|---|
| 1058 | when (null cmd) |
|---|
| 1059 | $ ghcError (CmdLineError "editor not set, use :set editor") |
|---|
| 1060 | code <- liftIO $ system (cmd ++ ' ':file) |
|---|
| 1061 | when (code == ExitSuccess) |
|---|
| 1062 | $ reloadModule "" |
|---|
| 1063 | |
|---|
| 1064 | -- The user didn't specify a file so we pick one for them. |
|---|
| 1065 | -- Our strategy is to pick the first module that failed to load, |
|---|
| 1066 | -- or otherwise the first target. |
|---|
| 1067 | -- |
|---|
| 1068 | -- XXX: Can we figure out what happened if the depndecy analysis fails |
|---|
| 1069 | -- (e.g., because the porgrammeer mistyped the name of a module)? |
|---|
| 1070 | -- XXX: Can we figure out the location of an error to pass to the editor? |
|---|
| 1071 | -- XXX: if we could figure out the list of errors that occured during the |
|---|
| 1072 | -- last load/reaload, then we could start the editor focused on the first |
|---|
| 1073 | -- of those. |
|---|
| 1074 | chooseEditFile :: GHCi String |
|---|
| 1075 | chooseEditFile = |
|---|
| 1076 | do let hasFailed x = fmap not $ GHC.isLoaded $ GHC.ms_mod_name x |
|---|
| 1077 | |
|---|
| 1078 | graph <- GHC.getModuleGraph |
|---|
| 1079 | failed_graph <- filterM hasFailed graph |
|---|
| 1080 | let order g = flattenSCCs $ GHC.topSortModuleGraph True g Nothing |
|---|
| 1081 | pick xs = case xs of |
|---|
| 1082 | x : _ -> GHC.ml_hs_file (GHC.ms_location x) |
|---|
| 1083 | _ -> Nothing |
|---|
| 1084 | |
|---|
| 1085 | case pick (order failed_graph) of |
|---|
| 1086 | Just file -> return file |
|---|
| 1087 | Nothing -> |
|---|
| 1088 | do targets <- GHC.getTargets |
|---|
| 1089 | case msum (map fromTarget targets) of |
|---|
| 1090 | Just file -> return file |
|---|
| 1091 | Nothing -> ghcError (CmdLineError "No files to edit.") |
|---|
| 1092 | |
|---|
| 1093 | where fromTarget (GHC.Target (GHC.TargetFile f _) _ _) = Just f |
|---|
| 1094 | fromTarget _ = Nothing -- when would we get a module target? |
|---|
| 1095 | |
|---|
| 1096 | |
|---|
| 1097 | ----------------------------------------------------------------------------- |
|---|
| 1098 | -- :def |
|---|
| 1099 | |
|---|
| 1100 | defineMacro :: Bool{-overwrite-} -> String -> GHCi () |
|---|
| 1101 | defineMacro _ (':':_) = |
|---|
| 1102 | liftIO $ putStrLn "macro name cannot start with a colon" |
|---|
| 1103 | defineMacro overwrite s = do |
|---|
| 1104 | let (macro_name, definition) = break isSpace s |
|---|
| 1105 | macros <- liftIO (readIORef macros_ref) |
|---|
| 1106 | let defined = map cmdName macros |
|---|
| 1107 | if (null macro_name) |
|---|
| 1108 | then if null defined |
|---|
| 1109 | then liftIO $ putStrLn "no macros defined" |
|---|
| 1110 | else liftIO $ putStr ("the following macros are defined:\n" ++ |
|---|
| 1111 | unlines defined) |
|---|
| 1112 | else do |
|---|
| 1113 | if (not overwrite && macro_name `elem` defined) |
|---|
| 1114 | then ghcError (CmdLineError |
|---|
| 1115 | ("macro '" ++ macro_name ++ "' is already defined")) |
|---|
| 1116 | else do |
|---|
| 1117 | |
|---|
| 1118 | let filtered = [ cmd | cmd <- macros, cmdName cmd /= macro_name ] |
|---|
| 1119 | |
|---|
| 1120 | -- give the expression a type signature, so we can be sure we're getting |
|---|
| 1121 | -- something of the right type. |
|---|
| 1122 | let new_expr = '(' : definition ++ ") :: String -> IO String" |
|---|
| 1123 | |
|---|
| 1124 | -- compile the expression |
|---|
| 1125 | handleSourceError (\e -> GHC.printException e) $ |
|---|
| 1126 | do |
|---|
| 1127 | hv <- GHC.compileExpr new_expr |
|---|
| 1128 | liftIO (writeIORef macros_ref -- |
|---|
| 1129 | (filtered ++ [(macro_name, lift . runMacro hv, noCompletion)])) |
|---|
| 1130 | |
|---|
| 1131 | runMacro :: GHC.HValue{-String -> IO String-} -> String -> GHCi Bool |
|---|
| 1132 | runMacro fun s = do |
|---|
| 1133 | str <- liftIO ((unsafeCoerce# fun :: String -> IO String) s) |
|---|
| 1134 | -- make sure we force any exceptions in the result, while we are still |
|---|
| 1135 | -- inside the exception handler for commands: |
|---|
| 1136 | seqList str (return ()) |
|---|
| 1137 | enqueueCommands (lines str) |
|---|
| 1138 | return False |
|---|
| 1139 | |
|---|
| 1140 | |
|---|
| 1141 | ----------------------------------------------------------------------------- |
|---|
| 1142 | -- :undef |
|---|
| 1143 | |
|---|
| 1144 | undefineMacro :: String -> GHCi () |
|---|
| 1145 | undefineMacro str = mapM_ undef (words str) |
|---|
| 1146 | where undef macro_name = do |
|---|
| 1147 | cmds <- liftIO (readIORef macros_ref) |
|---|
| 1148 | if (macro_name `notElem` map cmdName cmds) |
|---|
| 1149 | then ghcError (CmdLineError |
|---|
| 1150 | ("macro '" ++ macro_name ++ "' is not defined")) |
|---|
| 1151 | else do |
|---|
| 1152 | liftIO (writeIORef macros_ref (filter ((/= macro_name) . cmdName) cmds)) |
|---|
| 1153 | |
|---|
| 1154 | |
|---|
| 1155 | ----------------------------------------------------------------------------- |
|---|
| 1156 | -- :cmd |
|---|
| 1157 | |
|---|
| 1158 | cmdCmd :: String -> GHCi () |
|---|
| 1159 | cmdCmd str = do |
|---|
| 1160 | let expr = '(' : str ++ ") :: IO String" |
|---|
| 1161 | handleSourceError (\e -> GHC.printException e) $ |
|---|
| 1162 | do |
|---|
| 1163 | hv <- GHC.compileExpr expr |
|---|
| 1164 | cmds <- liftIO $ (unsafeCoerce# hv :: IO String) |
|---|
| 1165 | enqueueCommands (lines cmds) |
|---|
| 1166 | return () |
|---|
| 1167 | |
|---|
| 1168 | |
|---|
| 1169 | ----------------------------------------------------------------------------- |
|---|
| 1170 | -- :check |
|---|
| 1171 | |
|---|
| 1172 | checkModule :: String -> InputT GHCi () |
|---|
| 1173 | checkModule m = do |
|---|
| 1174 | let modl = GHC.mkModuleName m |
|---|
| 1175 | ok <- handleSourceError (\e -> GHC.printException e >> return False) $ do |
|---|
| 1176 | r <- GHC.typecheckModule =<< GHC.parseModule =<< GHC.getModSummary modl |
|---|
| 1177 | liftIO $ putStrLn $ showSDoc $ |
|---|
| 1178 | case GHC.moduleInfo r of |
|---|
| 1179 | cm | Just scope <- GHC.modInfoTopLevelScope cm -> |
|---|
| 1180 | let |
|---|
| 1181 | (loc, glob) = ASSERT( all isExternalName scope ) |
|---|
| 1182 | partition ((== modl) . GHC.moduleName . GHC.nameModule) scope |
|---|
| 1183 | in |
|---|
| 1184 | (text "global names: " <+> ppr glob) $$ |
|---|
| 1185 | (text "local names: " <+> ppr loc) |
|---|
| 1186 | _ -> empty |
|---|
| 1187 | return True |
|---|
| 1188 | afterLoad (successIf ok) False |
|---|
| 1189 | |
|---|
| 1190 | |
|---|
| 1191 | ----------------------------------------------------------------------------- |
|---|
| 1192 | -- :load, :add, :reload |
|---|
| 1193 | |
|---|
| 1194 | loadModule :: [(FilePath, Maybe Phase)] -> InputT GHCi SuccessFlag |
|---|
| 1195 | loadModule fs = timeIt (loadModule' fs) |
|---|
| 1196 | |
|---|
| 1197 | loadModule_ :: [FilePath] -> InputT GHCi () |
|---|
| 1198 | loadModule_ fs = loadModule (zip fs (repeat Nothing)) >> return () |
|---|
| 1199 | |
|---|
| 1200 | loadModule' :: [(FilePath, Maybe Phase)] -> InputT GHCi SuccessFlag |
|---|
| 1201 | loadModule' files = do |
|---|
| 1202 | let (filenames, phases) = unzip files |
|---|
| 1203 | exp_filenames <- mapM expandPath filenames |
|---|
| 1204 | let files' = zip exp_filenames phases |
|---|
| 1205 | targets <- mapM (uncurry GHC.guessTarget) files' |
|---|
| 1206 | |
|---|
| 1207 | -- NOTE: we used to do the dependency anal first, so that if it |
|---|
| 1208 | -- fails we didn't throw away the current set of modules. This would |
|---|
| 1209 | -- require some re-working of the GHC interface, so we'll leave it |
|---|
| 1210 | -- as a ToDo for now. |
|---|
| 1211 | |
|---|
| 1212 | -- unload first |
|---|
| 1213 | _ <- GHC.abandonAll |
|---|
| 1214 | lift discardActiveBreakPoints |
|---|
| 1215 | GHC.setTargets [] |
|---|
| 1216 | _ <- GHC.load LoadAllTargets |
|---|
| 1217 | |
|---|
| 1218 | GHC.setTargets targets |
|---|
| 1219 | doLoad False LoadAllTargets |
|---|
| 1220 | |
|---|
| 1221 | |
|---|
| 1222 | -- :add |
|---|
| 1223 | addModule :: [FilePath] -> InputT GHCi () |
|---|
| 1224 | addModule files = do |
|---|
| 1225 | lift revertCAFs -- always revert CAFs on load/add. |
|---|
| 1226 | files' <- mapM expandPath files |
|---|
| 1227 | targets <- mapM (\m -> GHC.guessTarget m Nothing) files' |
|---|
| 1228 | -- remove old targets with the same id; e.g. for :add *M |
|---|
| 1229 | mapM_ GHC.removeTarget [ tid | Target tid _ _ <- targets ] |
|---|
| 1230 | mapM_ GHC.addTarget targets |
|---|
| 1231 | _ <- doLoad False LoadAllTargets |
|---|
| 1232 | return () |
|---|
| 1233 | |
|---|
| 1234 | |
|---|
| 1235 | -- :reload |
|---|
| 1236 | reloadModule :: String -> InputT GHCi () |
|---|
| 1237 | reloadModule m = do |
|---|
| 1238 | _ <- doLoad True $ |
|---|
| 1239 | if null m then LoadAllTargets |
|---|
| 1240 | else LoadUpTo (GHC.mkModuleName m) |
|---|
| 1241 | return () |
|---|
| 1242 | |
|---|
| 1243 | |
|---|
| 1244 | doLoad :: Bool -> LoadHowMuch -> InputT GHCi SuccessFlag |
|---|
| 1245 | doLoad retain_context howmuch = do |
|---|
| 1246 | -- turn off breakpoints before we load: we can't turn them off later, because |
|---|
| 1247 | -- the ModBreaks will have gone away. |
|---|
| 1248 | lift discardActiveBreakPoints |
|---|
| 1249 | ok <- trySuccess $ GHC.load howmuch |
|---|
| 1250 | afterLoad ok retain_context |
|---|
| 1251 | return ok |
|---|
| 1252 | |
|---|
| 1253 | |
|---|
| 1254 | afterLoad :: SuccessFlag |
|---|
| 1255 | -> Bool -- keep the remembered_ctx, as far as possible (:reload) |
|---|
| 1256 | -> InputT GHCi () |
|---|
| 1257 | afterLoad ok retain_context = do |
|---|
| 1258 | lift revertCAFs -- always revert CAFs on load. |
|---|
| 1259 | lift discardTickArrays |
|---|
| 1260 | loaded_mod_summaries <- getLoadedModules |
|---|
| 1261 | let loaded_mods = map GHC.ms_mod loaded_mod_summaries |
|---|
| 1262 | loaded_mod_names = map GHC.moduleName loaded_mods |
|---|
| 1263 | modulesLoadedMsg ok loaded_mod_names |
|---|
| 1264 | lift $ setContextAfterLoad retain_context loaded_mod_summaries |
|---|
| 1265 | |
|---|
| 1266 | |
|---|
| 1267 | setContextAfterLoad :: Bool -> [GHC.ModSummary] -> GHCi () |
|---|
| 1268 | setContextAfterLoad keep_ctxt [] = do |
|---|
| 1269 | setContextKeepingPackageModules keep_ctxt [] |
|---|
| 1270 | setContextAfterLoad keep_ctxt ms = do |
|---|
| 1271 | -- load a target if one is available, otherwise load the topmost module. |
|---|
| 1272 | targets <- GHC.getTargets |
|---|
| 1273 | case [ m | Just m <- map (findTarget ms) targets ] of |
|---|
| 1274 | [] -> |
|---|
| 1275 | let graph' = flattenSCCs (GHC.topSortModuleGraph True ms Nothing) in |
|---|
| 1276 | load_this (last graph') |
|---|
| 1277 | (m:_) -> |
|---|
| 1278 | load_this m |
|---|
| 1279 | where |
|---|
| 1280 | findTarget mds t |
|---|
| 1281 | = case filter (`matches` t) mds of |
|---|
| 1282 | [] -> Nothing |
|---|
| 1283 | (m:_) -> Just m |
|---|
| 1284 | |
|---|
| 1285 | summary `matches` Target (TargetModule m) _ _ |
|---|
| 1286 | = GHC.ms_mod_name summary == m |
|---|
| 1287 | summary `matches` Target (TargetFile f _) _ _ |
|---|
| 1288 | | Just f' <- GHC.ml_hs_file (GHC.ms_location summary) = f == f' |
|---|
| 1289 | _ `matches` _ |
|---|
| 1290 | = False |
|---|
| 1291 | |
|---|
| 1292 | load_this summary | m <- GHC.ms_mod summary = do |
|---|
| 1293 | is_interp <- GHC.moduleIsInterpreted m |
|---|
| 1294 | dflags <- getDynFlags |
|---|
| 1295 | let star_ok = is_interp && not (safeLanguageOn dflags) |
|---|
| 1296 | -- We import the module with a * iff |
|---|
| 1297 | -- - it is interpreted, and |
|---|
| 1298 | -- - -XSafe is off (it doesn't allow *-imports) |
|---|
| 1299 | let new_ctx | star_ok = [mkIIModule (GHC.moduleName m)] |
|---|
| 1300 | | otherwise = [mkIIDecl (GHC.moduleName m)] |
|---|
| 1301 | setContextKeepingPackageModules keep_ctxt new_ctx |
|---|
| 1302 | |
|---|
| 1303 | |
|---|
| 1304 | -- | Keep any package modules (except Prelude) when changing the context. |
|---|
| 1305 | setContextKeepingPackageModules |
|---|
| 1306 | :: Bool -- True <=> keep all of remembered_ctx |
|---|
| 1307 | -- False <=> just keep package imports |
|---|
| 1308 | -> [InteractiveImport] -- new context |
|---|
| 1309 | -> GHCi () |
|---|
| 1310 | |
|---|
| 1311 | setContextKeepingPackageModules keep_ctx trans_ctx = do |
|---|
| 1312 | |
|---|
| 1313 | st <- getGHCiState |
|---|
| 1314 | let rem_ctx = remembered_ctx st |
|---|
| 1315 | new_rem_ctx <- if keep_ctx then return rem_ctx |
|---|
| 1316 | else keepPackageImports rem_ctx |
|---|
| 1317 | setGHCiState st{ remembered_ctx = new_rem_ctx, |
|---|
| 1318 | transient_ctx = filterSubsumed new_rem_ctx trans_ctx } |
|---|
| 1319 | setGHCContextFromGHCiState |
|---|
| 1320 | |
|---|
| 1321 | |
|---|
| 1322 | keepPackageImports :: [InteractiveImport] -> GHCi [InteractiveImport] |
|---|
| 1323 | keepPackageImports = filterM is_pkg_import |
|---|
| 1324 | where |
|---|
| 1325 | is_pkg_import :: InteractiveImport -> GHCi Bool |
|---|
| 1326 | is_pkg_import (IIModule _) = return False |
|---|
| 1327 | is_pkg_import (IIDecl d) |
|---|
| 1328 | = do e <- gtry $ GHC.findModule mod_name (ideclPkgQual d) |
|---|
| 1329 | case e :: Either SomeException Module of |
|---|
| 1330 | Left _ -> return False |
|---|
| 1331 | Right m -> return (not (isHomeModule m)) |
|---|
| 1332 | where |
|---|
| 1333 | mod_name = unLoc (ideclName d) |
|---|
| 1334 | |
|---|
| 1335 | |
|---|
| 1336 | modulesLoadedMsg :: SuccessFlag -> [ModuleName] -> InputT GHCi () |
|---|
| 1337 | modulesLoadedMsg ok mods = do |
|---|
| 1338 | dflags <- getDynFlags |
|---|
| 1339 | when (verbosity dflags > 0) $ do |
|---|
| 1340 | let mod_commas |
|---|
| 1341 | | null mods = text "none." |
|---|
| 1342 | | otherwise = hsep ( |
|---|
| 1343 | punctuate comma (map ppr mods)) <> text "." |
|---|
| 1344 | case ok of |
|---|
| 1345 | Failed -> |
|---|
| 1346 | liftIO $ putStrLn $ showSDoc (text "Failed, modules loaded: " <> mod_commas) |
|---|
| 1347 | Succeeded -> |
|---|
| 1348 | liftIO $ putStrLn $ showSDoc (text "Ok, modules loaded: " <> mod_commas) |
|---|
| 1349 | |
|---|
| 1350 | |
|---|
| 1351 | ----------------------------------------------------------------------------- |
|---|
| 1352 | -- :type |
|---|
| 1353 | |
|---|
| 1354 | typeOfExpr :: String -> InputT GHCi () |
|---|
| 1355 | typeOfExpr str |
|---|
| 1356 | = handleSourceError GHC.printException |
|---|
| 1357 | $ do |
|---|
| 1358 | ty <- GHC.exprType str |
|---|
| 1359 | dflags <- getDynFlags |
|---|
| 1360 | let pefas = dopt Opt_PrintExplicitForalls dflags |
|---|
| 1361 | printForUser $ sep [text str, nest 2 (dcolon <+> pprTypeForUser pefas ty)] |
|---|
| 1362 | |
|---|
| 1363 | ----------------------------------------------------------------------------- |
|---|
| 1364 | -- :kind |
|---|
| 1365 | |
|---|
| 1366 | kindOfType :: Bool -> String -> InputT GHCi () |
|---|
| 1367 | kindOfType norm str |
|---|
| 1368 | = handleSourceError GHC.printException |
|---|
| 1369 | $ do |
|---|
| 1370 | (ty, kind) <- GHC.typeKind norm str |
|---|
| 1371 | printForUser $ vcat [ text str <+> dcolon <+> ppr kind |
|---|
| 1372 | , ppWhen norm $ equals <+> ppr ty ] |
|---|
| 1373 | |
|---|
| 1374 | |
|---|
| 1375 | ----------------------------------------------------------------------------- |
|---|
| 1376 | -- :quit |
|---|
| 1377 | |
|---|
| 1378 | quit :: String -> InputT GHCi Bool |
|---|
| 1379 | quit _ = return True |
|---|
| 1380 | |
|---|
| 1381 | |
|---|
| 1382 | ----------------------------------------------------------------------------- |
|---|
| 1383 | -- :script |
|---|
| 1384 | |
|---|
| 1385 | -- running a script file #1363 |
|---|
| 1386 | |
|---|
| 1387 | scriptCmd :: String -> InputT GHCi () |
|---|
| 1388 | scriptCmd ws = do |
|---|
| 1389 | case words ws of |
|---|
| 1390 | [s] -> runScript s |
|---|
| 1391 | _ -> ghcError (CmdLineError "syntax: :script <filename>") |
|---|
| 1392 | |
|---|
| 1393 | runScript :: String -- ^ filename |
|---|
| 1394 | -> InputT GHCi () |
|---|
| 1395 | runScript filename = do |
|---|
| 1396 | either_script <- liftIO $ tryIO (openFile filename ReadMode) |
|---|
| 1397 | case either_script of |
|---|
| 1398 | Left _err -> ghcError (CmdLineError $ "IO error: \""++filename++"\" " |
|---|
| 1399 | ++(ioeGetErrorString _err)) |
|---|
| 1400 | Right script -> do |
|---|
| 1401 | st <- lift $ getGHCiState |
|---|
| 1402 | let prog = progname st |
|---|
| 1403 | line = line_number st |
|---|
| 1404 | lift $ setGHCiState st{progname=filename,line_number=0} |
|---|
| 1405 | scriptLoop script |
|---|
| 1406 | liftIO $ hClose script |
|---|
| 1407 | new_st <- lift $ getGHCiState |
|---|
| 1408 | lift $ setGHCiState new_st{progname=prog,line_number=line} |
|---|
| 1409 | where scriptLoop script = do |
|---|
| 1410 | res <- runOneCommand handler $ fileLoop script |
|---|
| 1411 | case res of |
|---|
| 1412 | Nothing -> return () |
|---|
| 1413 | Just s -> if s |
|---|
| 1414 | then scriptLoop script |
|---|
| 1415 | else return () |
|---|
| 1416 | |
|---|
| 1417 | ----------------------------------------------------------------------------- |
|---|
| 1418 | -- :issafe |
|---|
| 1419 | |
|---|
| 1420 | -- Displaying Safe Haskell properties of a module |
|---|
| 1421 | |
|---|
| 1422 | isSafeCmd :: String -> InputT GHCi () |
|---|
| 1423 | isSafeCmd m = |
|---|
| 1424 | case words m of |
|---|
| 1425 | [s] | looksLikeModuleName s -> do |
|---|
| 1426 | md <- lift $ lookupModule s |
|---|
| 1427 | isSafeModule md |
|---|
| 1428 | [] -> do md <- guessCurrentModule "issafe" |
|---|
| 1429 | isSafeModule md |
|---|
| 1430 | _ -> ghcError (CmdLineError "syntax: :issafe <module>") |
|---|
| 1431 | |
|---|
| 1432 | isSafeModule :: Module -> InputT GHCi () |
|---|
| 1433 | isSafeModule m = do |
|---|
| 1434 | mb_mod_info <- GHC.getModuleInfo m |
|---|
| 1435 | when (isNothing mb_mod_info) |
|---|
| 1436 | (ghcError $ CmdLineError $ "unknown module: " ++ mname) |
|---|
| 1437 | |
|---|
| 1438 | dflags <- getDynFlags |
|---|
| 1439 | let iface = GHC.modInfoIface $ fromJust mb_mod_info |
|---|
| 1440 | when (isNothing iface) |
|---|
| 1441 | (ghcError $ CmdLineError $ "can't load interface file for module: " ++ |
|---|
| 1442 | (GHC.moduleNameString $ GHC.moduleName m)) |
|---|
| 1443 | |
|---|
| 1444 | let iface' = fromJust iface |
|---|
| 1445 | |
|---|
| 1446 | trust = showPpr $ getSafeMode $ GHC.mi_trust iface' |
|---|
| 1447 | pkgT = packageTrusted dflags m |
|---|
| 1448 | pkg = if pkgT then "trusted" else "untrusted" |
|---|
| 1449 | (good', bad') = tallyPkgs dflags $ |
|---|
| 1450 | map fst $ filter snd $ dep_pkgs $ GHC.mi_deps iface' |
|---|
| 1451 | (good, bad) = case GHC.mi_trust_pkg iface' of |
|---|
| 1452 | True | pkgT -> (modulePackageId m:good', bad') |
|---|
| 1453 | True -> (good', modulePackageId m:bad') |
|---|
| 1454 | False -> (good', bad') |
|---|
| 1455 | |
|---|
| 1456 | liftIO $ putStrLn $ "Trust type is (Module: " ++ trust ++ ", Package: " ++ pkg ++ ")" |
|---|
| 1457 | liftIO $ putStrLn $ "Package Trust: " |
|---|
| 1458 | ++ (if packageTrustOn dflags then "On" else "Off") |
|---|
| 1459 | |
|---|
| 1460 | when (packageTrustOn dflags && not (null good)) |
|---|
| 1461 | (liftIO $ putStrLn $ "Trusted package dependencies (trusted): " ++ |
|---|
| 1462 | (intercalate ", " $ map packageIdString good)) |
|---|
| 1463 | |
|---|
| 1464 | case goodTrust (getSafeMode $ GHC.mi_trust iface') of |
|---|
| 1465 | True | (null bad || not (packageTrustOn dflags)) -> |
|---|
| 1466 | liftIO $ putStrLn $ mname ++ " is trusted!" |
|---|
| 1467 | |
|---|
| 1468 | True -> do |
|---|
| 1469 | liftIO $ putStrLn $ "Trusted package dependencies (untrusted): " |
|---|
| 1470 | ++ (intercalate ", " $ map packageIdString bad) |
|---|
| 1471 | liftIO $ putStrLn $ mname ++ " is NOT trusted!" |
|---|
| 1472 | |
|---|
| 1473 | False -> liftIO $ putStrLn $ mname ++ " is NOT trusted!" |
|---|
| 1474 | |
|---|
| 1475 | where |
|---|
| 1476 | goodTrust t = t `elem` [Sf_Safe, Sf_SafeInfered, Sf_Trustworthy] |
|---|
| 1477 | |
|---|
| 1478 | mname = GHC.moduleNameString $ GHC.moduleName m |
|---|
| 1479 | |
|---|
| 1480 | packageTrusted dflags md |
|---|
| 1481 | | thisPackage dflags == modulePackageId md = True |
|---|
| 1482 | | otherwise = trusted $ getPackageDetails (pkgState dflags) |
|---|
| 1483 | (modulePackageId md) |
|---|
| 1484 | |
|---|
| 1485 | tallyPkgs dflags deps = partition part deps |
|---|
| 1486 | where state = pkgState dflags |
|---|
| 1487 | part pkg = trusted $ getPackageDetails state pkg |
|---|
| 1488 | |
|---|
| 1489 | ----------------------------------------------------------------------------- |
|---|
| 1490 | -- :browse |
|---|
| 1491 | |
|---|
| 1492 | -- Browsing a module's contents |
|---|
| 1493 | |
|---|
| 1494 | browseCmd :: Bool -> String -> InputT GHCi () |
|---|
| 1495 | browseCmd bang m = |
|---|
| 1496 | case words m of |
|---|
| 1497 | ['*':s] | looksLikeModuleName s -> do |
|---|
| 1498 | md <- lift $ wantInterpretedModule s |
|---|
| 1499 | browseModule bang md False |
|---|
| 1500 | [s] | looksLikeModuleName s -> do |
|---|
| 1501 | md <- lift $ lookupModule s |
|---|
| 1502 | browseModule bang md True |
|---|
| 1503 | [] -> do md <- guessCurrentModule ("browse" ++ if bang then "!" else "") |
|---|
| 1504 | browseModule bang md True |
|---|
| 1505 | _ -> ghcError (CmdLineError "syntax: :browse <module>") |
|---|
| 1506 | |
|---|
| 1507 | guessCurrentModule :: String -> InputT GHCi Module |
|---|
| 1508 | -- Guess which module the user wants to browse. Pick |
|---|
| 1509 | -- modules that are interpreted first. The most |
|---|
| 1510 | -- recently-added module occurs last, it seems. |
|---|
| 1511 | guessCurrentModule cmd |
|---|
| 1512 | = do imports <- GHC.getContext |
|---|
| 1513 | when (null imports) $ ghcError $ |
|---|
| 1514 | CmdLineError (':' : cmd ++ ": no current module") |
|---|
| 1515 | case (head imports) of |
|---|
| 1516 | IIModule m -> GHC.findModule m Nothing |
|---|
| 1517 | IIDecl d -> GHC.findModule (unLoc (ideclName d)) (ideclPkgQual d) |
|---|
| 1518 | |
|---|
| 1519 | -- without bang, show items in context of their parents and omit children |
|---|
| 1520 | -- with bang, show class methods and data constructors separately, and |
|---|
| 1521 | -- indicate import modules, to aid qualifying unqualified names |
|---|
| 1522 | -- with sorted, sort items alphabetically |
|---|
| 1523 | browseModule :: Bool -> Module -> Bool -> InputT GHCi () |
|---|
| 1524 | browseModule bang modl exports_only = do |
|---|
| 1525 | -- :browse reports qualifiers wrt current context |
|---|
| 1526 | unqual <- GHC.getPrintUnqual |
|---|
| 1527 | |
|---|
| 1528 | mb_mod_info <- GHC.getModuleInfo modl |
|---|
| 1529 | case mb_mod_info of |
|---|
| 1530 | Nothing -> ghcError (CmdLineError ("unknown module: " ++ |
|---|
| 1531 | GHC.moduleNameString (GHC.moduleName modl))) |
|---|
| 1532 | Just mod_info -> do |
|---|
| 1533 | dflags <- getDynFlags |
|---|
| 1534 | let names |
|---|
| 1535 | | exports_only = GHC.modInfoExports mod_info |
|---|
| 1536 | | otherwise = GHC.modInfoTopLevelScope mod_info |
|---|
| 1537 | `orElse` [] |
|---|
| 1538 | |
|---|
| 1539 | -- sort alphabetically name, but putting locally-defined |
|---|
| 1540 | -- identifiers first. We would like to improve this; see #1799. |
|---|
| 1541 | sorted_names = loc_sort local ++ occ_sort external |
|---|
| 1542 | where |
|---|
| 1543 | (local,external) = ASSERT( all isExternalName names ) |
|---|
| 1544 | partition ((==modl) . nameModule) names |
|---|
| 1545 | occ_sort = sortBy (compare `on` nameOccName) |
|---|
| 1546 | -- try to sort by src location. If the first name in our list |
|---|
| 1547 | -- has a good source location, then they all should. |
|---|
| 1548 | loc_sort ns |
|---|
| 1549 | | n:_ <- ns, isGoodSrcSpan (nameSrcSpan n) |
|---|
| 1550 | = sortBy (compare `on` nameSrcSpan) ns |
|---|
| 1551 | | otherwise |
|---|
| 1552 | = occ_sort ns |
|---|
| 1553 | |
|---|
| 1554 | mb_things <- mapM GHC.lookupName sorted_names |
|---|
| 1555 | let filtered_things = filterOutChildren (\t -> t) (catMaybes mb_things) |
|---|
| 1556 | |
|---|
| 1557 | rdr_env <- GHC.getGRE |
|---|
| 1558 | |
|---|
| 1559 | let pefas = dopt Opt_PrintExplicitForalls dflags |
|---|
| 1560 | things | bang = catMaybes mb_things |
|---|
| 1561 | | otherwise = filtered_things |
|---|
| 1562 | pretty | bang = pprTyThing |
|---|
| 1563 | | otherwise = pprTyThingInContext |
|---|
| 1564 | |
|---|
| 1565 | labels [] = text "-- not currently imported" |
|---|
| 1566 | labels l = text $ intercalate "\n" $ map qualifier l |
|---|
| 1567 | |
|---|
| 1568 | qualifier :: Maybe [ModuleName] -> String |
|---|
| 1569 | qualifier = maybe "-- defined locally" |
|---|
| 1570 | (("-- imported via "++) . intercalate ", " |
|---|
| 1571 | . map GHC.moduleNameString) |
|---|
| 1572 | importInfo = RdrName.getGRE_NameQualifier_maybes rdr_env |
|---|
| 1573 | |
|---|
| 1574 | modNames :: [[Maybe [ModuleName]]] |
|---|
| 1575 | modNames = map (importInfo . GHC.getName) things |
|---|
| 1576 | |
|---|
| 1577 | -- annotate groups of imports with their import modules |
|---|
| 1578 | -- the default ordering is somewhat arbitrary, so we group |
|---|
| 1579 | -- by header and sort groups; the names themselves should |
|---|
| 1580 | -- really come in order of source appearance.. (trac #1799) |
|---|
| 1581 | annotate mts = concatMap (\(m,ts)->labels m:ts) |
|---|
| 1582 | $ sortBy cmpQualifiers $ grp mts |
|---|
| 1583 | where cmpQualifiers = |
|---|
| 1584 | compare `on` (map (fmap (map moduleNameFS)) . fst) |
|---|
| 1585 | grp [] = [] |
|---|
| 1586 | grp mts@((m,_):_) = (m,map snd g) : grp ng |
|---|
| 1587 | where (g,ng) = partition ((==m).fst) mts |
|---|
| 1588 | |
|---|
| 1589 | let prettyThings, prettyThings' :: [SDoc] |
|---|
| 1590 | prettyThings = map (pretty pefas) things |
|---|
| 1591 | prettyThings' | bang = annotate $ zip modNames prettyThings |
|---|
| 1592 | | otherwise = prettyThings |
|---|
| 1593 | liftIO $ putStrLn $ showSDocForUser unqual (vcat prettyThings') |
|---|
| 1594 | -- ToDo: modInfoInstances currently throws an exception for |
|---|
| 1595 | -- package modules. When it works, we can do this: |
|---|
| 1596 | -- $$ vcat (map GHC.pprInstance (GHC.modInfoInstances mod_info)) |
|---|
| 1597 | |
|---|
| 1598 | |
|---|
| 1599 | ----------------------------------------------------------------------------- |
|---|
| 1600 | -- :module |
|---|
| 1601 | |
|---|
| 1602 | -- Setting the module context. For details on context handling see |
|---|
| 1603 | -- "remembered_ctx" and "transient_ctx" in GhciMonad. |
|---|
| 1604 | |
|---|
| 1605 | moduleCmd :: String -> GHCi () |
|---|
| 1606 | moduleCmd str |
|---|
| 1607 | | all sensible strs = cmd |
|---|
| 1608 | | otherwise = ghcError (CmdLineError "syntax: :module [+/-] [*]M1 ... [*]Mn") |
|---|
| 1609 | where |
|---|
| 1610 | (cmd, strs) = |
|---|
| 1611 | case str of |
|---|
| 1612 | '+':stuff -> rest addModulesToContext stuff |
|---|
| 1613 | '-':stuff -> rest remModulesFromContext stuff |
|---|
| 1614 | stuff -> rest setContext stuff |
|---|
| 1615 | |
|---|
| 1616 | rest op stuff = (op as bs, stuffs) |
|---|
| 1617 | where (as,bs) = partitionWith starred stuffs |
|---|
| 1618 | stuffs = words stuff |
|---|
| 1619 | |
|---|
| 1620 | sensible ('*':m) = looksLikeModuleName m |
|---|
| 1621 | sensible m = looksLikeModuleName m |
|---|
| 1622 | |
|---|
| 1623 | starred ('*':m) = Left (GHC.mkModuleName m) |
|---|
| 1624 | starred m = Right (GHC.mkModuleName m) |
|---|
| 1625 | |
|---|
| 1626 | |
|---|
| 1627 | -- ----------------------------------------------------------------------------- |
|---|
| 1628 | -- Four ways to manipulate the context: |
|---|
| 1629 | -- (a) :module +<stuff>: addModulesToContext |
|---|
| 1630 | -- (b) :module -<stuff>: remModulesFromContext |
|---|
| 1631 | -- (c) :module <stuff>: setContext |
|---|
| 1632 | -- (d) import <module>...: addImportToContext |
|---|
| 1633 | |
|---|
| 1634 | addModulesToContext :: [ModuleName] -> [ModuleName] -> GHCi () |
|---|
| 1635 | addModulesToContext starred unstarred = restoreContextOnFailure $ do |
|---|
| 1636 | addModulesToContext_ starred unstarred |
|---|
| 1637 | |
|---|
| 1638 | addModulesToContext_ :: [ModuleName] -> [ModuleName] -> GHCi () |
|---|
| 1639 | addModulesToContext_ starred unstarred = do |
|---|
| 1640 | mapM_ addII (map mkIIModule starred ++ map mkIIDecl unstarred) |
|---|
| 1641 | setGHCContextFromGHCiState |
|---|
| 1642 | |
|---|
| 1643 | remModulesFromContext :: [ModuleName] -> [ModuleName] -> GHCi () |
|---|
| 1644 | remModulesFromContext starred unstarred = do |
|---|
| 1645 | -- we do *not* call restoreContextOnFailure here. If the user |
|---|
| 1646 | -- is trying to fix up a context that contains errors by removing |
|---|
| 1647 | -- modules, we don't want GHC to silently put them back in again. |
|---|
| 1648 | mapM_ rm (starred ++ unstarred) |
|---|
| 1649 | setGHCContextFromGHCiState |
|---|
| 1650 | where |
|---|
| 1651 | rm :: ModuleName -> GHCi () |
|---|
| 1652 | rm str = do |
|---|
| 1653 | m <- moduleName <$> lookupModuleName str |
|---|
| 1654 | let filt = filter ((/=) m . iiModuleName) |
|---|
| 1655 | modifyGHCiState $ \st -> |
|---|
| 1656 | st { remembered_ctx = filt (remembered_ctx st) |
|---|
| 1657 | , transient_ctx = filt (transient_ctx st) } |
|---|
| 1658 | |
|---|
| 1659 | setContext :: [ModuleName] -> [ModuleName] -> GHCi () |
|---|
| 1660 | setContext starred unstarred = restoreContextOnFailure $ do |
|---|
| 1661 | modifyGHCiState $ \st -> st { remembered_ctx = [], transient_ctx = [] } |
|---|
| 1662 | -- delete the transient context |
|---|
| 1663 | addModulesToContext_ starred unstarred |
|---|
| 1664 | |
|---|
| 1665 | addImportToContext :: String -> GHCi () |
|---|
| 1666 | addImportToContext str = restoreContextOnFailure $ do |
|---|
| 1667 | idecl <- GHC.parseImportDecl str |
|---|
| 1668 | addII (IIDecl idecl) -- #5836 |
|---|
| 1669 | setGHCContextFromGHCiState |
|---|
| 1670 | |
|---|
| 1671 | -- Util used by addImportToContext and addModulesToContext |
|---|
| 1672 | addII :: InteractiveImport -> GHCi () |
|---|
| 1673 | addII iidecl = do |
|---|
| 1674 | checkAdd iidecl |
|---|
| 1675 | modifyGHCiState $ \st -> |
|---|
| 1676 | st { remembered_ctx = addNotSubsumed iidecl (remembered_ctx st) |
|---|
| 1677 | , transient_ctx = filter (not . (iidecl `iiSubsumes`)) |
|---|
| 1678 | (transient_ctx st) |
|---|
| 1679 | } |
|---|
| 1680 | |
|---|
| 1681 | -- Sometimes we can't tell whether an import is valid or not until |
|---|
| 1682 | -- we finally call 'GHC.setContext'. e.g. |
|---|
| 1683 | -- |
|---|
| 1684 | -- import System.IO (foo) |
|---|
| 1685 | -- |
|---|
| 1686 | -- will fail because System.IO does not export foo. In this case we |
|---|
| 1687 | -- don't want to store the import in the context permanently, so we |
|---|
| 1688 | -- catch the failure from 'setGHCContextFromGHCiState' and set the |
|---|
| 1689 | -- context back to what it was. |
|---|
| 1690 | -- |
|---|
| 1691 | -- See #6007 |
|---|
| 1692 | -- |
|---|
| 1693 | restoreContextOnFailure :: GHCi a -> GHCi a |
|---|
| 1694 | restoreContextOnFailure do_this = do |
|---|
| 1695 | st <- getGHCiState |
|---|
| 1696 | let rc = remembered_ctx st; tc = transient_ctx st |
|---|
| 1697 | do_this `gonException` (modifyGHCiState $ \st' -> |
|---|
| 1698 | st' { remembered_ctx = rc, transient_ctx = tc }) |
|---|
| 1699 | |
|---|
| 1700 | -- ----------------------------------------------------------------------------- |
|---|
| 1701 | -- Validate a module that we want to add to the context |
|---|
| 1702 | |
|---|
| 1703 | checkAdd :: InteractiveImport -> GHCi () |
|---|
| 1704 | checkAdd ii = do |
|---|
| 1705 | dflags <- getDynFlags |
|---|
| 1706 | let safe = safeLanguageOn dflags |
|---|
| 1707 | case ii of |
|---|
| 1708 | IIModule modname |
|---|
| 1709 | | safe -> ghcError $ CmdLineError "can't use * imports with Safe Haskell" |
|---|
| 1710 | | otherwise -> wantInterpretedModuleName modname >> return () |
|---|
| 1711 | |
|---|
| 1712 | IIDecl d -> do |
|---|
| 1713 | let modname = unLoc (ideclName d) |
|---|
| 1714 | pkgqual = ideclPkgQual d |
|---|
| 1715 | m <- GHC.lookupModule modname pkgqual |
|---|
| 1716 | when safe $ do |
|---|
| 1717 | t <- GHC.isModuleTrusted m |
|---|
| 1718 | when (not t) $ |
|---|
| 1719 | ghcError $ CmdLineError $ |
|---|
| 1720 | "can't import " ++ moduleNameString modname |
|---|
| 1721 | ++ " as it isn't trusted." |
|---|
| 1722 | |
|---|
| 1723 | |
|---|
| 1724 | -- ----------------------------------------------------------------------------- |
|---|
| 1725 | -- Update the GHC API's view of the context |
|---|
| 1726 | |
|---|
| 1727 | -- | Sets the GHC context from the GHCi state. The GHC context is |
|---|
| 1728 | -- always set this way, we never modify it incrementally. |
|---|
| 1729 | -- |
|---|
| 1730 | -- We ignore any imports for which the ModuleName does not currently |
|---|
| 1731 | -- exist. This is so that the remembered_ctx can contain imports for |
|---|
| 1732 | -- modules that are not currently loaded, perhaps because we just did |
|---|
| 1733 | -- a :reload and encountered errors. |
|---|
| 1734 | -- |
|---|
| 1735 | -- Prelude is added if not already present in the list. Therefore to |
|---|
| 1736 | -- override the implicit Prelude import you can say 'import Prelude ()' |
|---|
| 1737 | -- at the prompt, just as in Haskell source. |
|---|
| 1738 | -- |
|---|
| 1739 | setGHCContextFromGHCiState :: GHCi () |
|---|
| 1740 | setGHCContextFromGHCiState = do |
|---|
| 1741 | st <- getGHCiState |
|---|
| 1742 | -- re-use checkAdd to check whether the module is valid. If the |
|---|
| 1743 | -- module does not exist, we do *not* want to print an error |
|---|
| 1744 | -- here, we just want to silently keep the module in the context |
|---|
| 1745 | -- until such time as the module reappears again. So we ignore |
|---|
| 1746 | -- the actual exception thrown by checkAdd, using tryBool to |
|---|
| 1747 | -- turn it into a Bool. |
|---|
| 1748 | iidecls <- filterM (tryBool.checkAdd) (transient_ctx st ++ remembered_ctx st) |
|---|
| 1749 | dflags <- GHC.getSessionDynFlags |
|---|
| 1750 | GHC.setContext $ |
|---|
| 1751 | if xopt Opt_ImplicitPrelude dflags && not (any isPreludeImport iidecls) |
|---|
| 1752 | then iidecls ++ [implicitPreludeImport] |
|---|
| 1753 | else iidecls |
|---|
| 1754 | -- XXX put prel at the end, so that guessCurrentModule doesn't pick it up. |
|---|
| 1755 | |
|---|
| 1756 | |
|---|
| 1757 | -- ----------------------------------------------------------------------------- |
|---|
| 1758 | -- Utils on InteractiveImport |
|---|
| 1759 | |
|---|
| 1760 | mkIIModule :: ModuleName -> InteractiveImport |
|---|
| 1761 | mkIIModule = IIModule |
|---|
| 1762 | |
|---|
| 1763 | mkIIDecl :: ModuleName -> InteractiveImport |
|---|
| 1764 | mkIIDecl = IIDecl . simpleImportDecl |
|---|
| 1765 | |
|---|
| 1766 | iiModules :: [InteractiveImport] -> [ModuleName] |
|---|
| 1767 | iiModules is = [m | IIModule m <- is] |
|---|
| 1768 | |
|---|
| 1769 | iiModuleName :: InteractiveImport -> ModuleName |
|---|
| 1770 | iiModuleName (IIModule m) = m |
|---|
| 1771 | iiModuleName (IIDecl d) = unLoc (ideclName d) |
|---|
| 1772 | |
|---|
| 1773 | preludeModuleName :: ModuleName |
|---|
| 1774 | preludeModuleName = GHC.mkModuleName "Prelude" |
|---|
| 1775 | |
|---|
| 1776 | implicitPreludeImport :: InteractiveImport |
|---|
| 1777 | implicitPreludeImport = IIDecl (simpleImportDecl preludeModuleName) |
|---|
| 1778 | |
|---|
| 1779 | isPreludeImport :: InteractiveImport -> Bool |
|---|
| 1780 | isPreludeImport (IIModule {}) = True |
|---|
| 1781 | isPreludeImport (IIDecl d) = unLoc (ideclName d) == preludeModuleName |
|---|
| 1782 | |
|---|
| 1783 | addNotSubsumed :: InteractiveImport |
|---|
| 1784 | -> [InteractiveImport] -> [InteractiveImport] |
|---|
| 1785 | addNotSubsumed i is |
|---|
| 1786 | | any (`iiSubsumes` i) is = is |
|---|
| 1787 | | otherwise = i : filter (not . (i `iiSubsumes`)) is |
|---|
| 1788 | |
|---|
| 1789 | -- | @filterSubsumed is js@ returns the elements of @js@ not subsumed |
|---|
| 1790 | -- by any of @is@. |
|---|
| 1791 | filterSubsumed :: [InteractiveImport] -> [InteractiveImport] |
|---|
| 1792 | -> [InteractiveImport] |
|---|
| 1793 | filterSubsumed is js = filter (\j -> not (any (`iiSubsumes` j) is)) js |
|---|
| 1794 | |
|---|
| 1795 | -- | Returns True if the left import subsumes the right one. Doesn't |
|---|
| 1796 | -- need to be 100% accurate, conservatively returning False is fine. |
|---|
| 1797 | -- (EXCEPT: (IIModule m) *must* subsume itself, otherwise a panic in |
|---|
| 1798 | -- plusProv will ensue (#5904)) |
|---|
| 1799 | -- |
|---|
| 1800 | -- Note that an IIModule does not necessarily subsume an IIDecl, |
|---|
| 1801 | -- because e.g. a module might export a name that is only available |
|---|
| 1802 | -- qualified within the module itself. |
|---|
| 1803 | -- |
|---|
| 1804 | -- Note that 'import M' does not necessarily subsume 'import M(foo)', |
|---|
| 1805 | -- because M might not export foo and we want an error to be produced |
|---|
| 1806 | -- in that case. |
|---|
| 1807 | -- |
|---|
| 1808 | iiSubsumes :: InteractiveImport -> InteractiveImport -> Bool |
|---|
| 1809 | iiSubsumes (IIModule m1) (IIModule m2) = m1==m2 |
|---|
| 1810 | iiSubsumes (IIDecl d1) (IIDecl d2) -- A bit crude |
|---|
| 1811 | = unLoc (ideclName d1) == unLoc (ideclName d2) |
|---|
| 1812 | && ideclAs d1 == ideclAs d2 |
|---|
| 1813 | && (not (ideclQualified d1) || ideclQualified d2) |
|---|
| 1814 | && (ideclHiding d1 `hidingSubsumes` ideclHiding d2) |
|---|
| 1815 | where |
|---|
| 1816 | _ `hidingSubsumes` Just (False,[]) = True |
|---|
| 1817 | Just (False, xs) `hidingSubsumes` Just (False,ys) = all (`elem` xs) ys |
|---|
| 1818 | h1 `hidingSubsumes` h2 = h1 == h2 |
|---|
| 1819 | iiSubsumes _ _ = False |
|---|
| 1820 | |
|---|
| 1821 | |
|---|
| 1822 | ---------------------------------------------------------------------------- |
|---|
| 1823 | -- :set |
|---|
| 1824 | |
|---|
| 1825 | -- set options in the interpreter. Syntax is exactly the same as the |
|---|
| 1826 | -- ghc command line, except that certain options aren't available (-C, |
|---|
| 1827 | -- -E etc.) |
|---|
| 1828 | -- |
|---|
| 1829 | -- This is pretty fragile: most options won't work as expected. ToDo: |
|---|
| 1830 | -- figure out which ones & disallow them. |
|---|
| 1831 | |
|---|
| 1832 | setCmd :: String -> GHCi () |
|---|
| 1833 | setCmd "" = showOptions False |
|---|
| 1834 | setCmd "-a" = showOptions True |
|---|
| 1835 | setCmd str |
|---|
| 1836 | = case getCmd str of |
|---|
| 1837 | Right ("args", rest) -> |
|---|
| 1838 | case toArgs rest of |
|---|
| 1839 | Left err -> liftIO (hPutStrLn stderr err) |
|---|
| 1840 | Right args -> setArgs args |
|---|
| 1841 | Right ("prog", rest) -> |
|---|
| 1842 | case toArgs rest of |
|---|
| 1843 | Right [prog] -> setProg prog |
|---|
| 1844 | _ -> liftIO (hPutStrLn stderr "syntax: :set prog <progname>") |
|---|
| 1845 | Right ("prompt", rest) -> setPrompt $ dropWhile isSpace rest |
|---|
| 1846 | Right ("editor", rest) -> setEditor $ dropWhile isSpace rest |
|---|
| 1847 | Right ("stop", rest) -> setStop $ dropWhile isSpace rest |
|---|
| 1848 | _ -> case toArgs str of |
|---|
| 1849 | Left err -> liftIO (hPutStrLn stderr err) |
|---|
| 1850 | Right wds -> setOptions wds |
|---|
| 1851 | |
|---|
| 1852 | setiCmd :: String -> GHCi () |
|---|
| 1853 | setiCmd "" = GHC.getInteractiveDynFlags >>= liftIO . showDynFlags False |
|---|
| 1854 | setiCmd "-a" = GHC.getInteractiveDynFlags >>= liftIO . showDynFlags True |
|---|
| 1855 | setiCmd str = |
|---|
| 1856 | case toArgs str of |
|---|
| 1857 | Left err -> liftIO (hPutStrLn stderr err) |
|---|
| 1858 | Right wds -> newDynFlags True wds |
|---|
| 1859 | |
|---|
| 1860 | showOptions :: Bool -> GHCi () |
|---|
| 1861 | showOptions show_all |
|---|
| 1862 | = do st <- getGHCiState |
|---|
| 1863 | let opts = options st |
|---|
| 1864 | liftIO $ putStrLn (showSDoc ( |
|---|
| 1865 | text "options currently set: " <> |
|---|
| 1866 | if null opts |
|---|
| 1867 | then text "none." |
|---|
| 1868 | else hsep (map (\o -> char '+' <> text (optToStr o)) opts) |
|---|
| 1869 | )) |
|---|
| 1870 | getDynFlags >>= liftIO . showDynFlags show_all |
|---|
| 1871 | |
|---|
| 1872 | |
|---|
| 1873 | showDynFlags :: Bool -> DynFlags -> IO () |
|---|
| 1874 | showDynFlags show_all dflags = do |
|---|
| 1875 | showLanguages' show_all dflags |
|---|
| 1876 | putStrLn $ showSDoc $ |
|---|
| 1877 | text "GHCi-specific dynamic flag settings:" $$ |
|---|
| 1878 | nest 2 (vcat (map (setting dopt) ghciFlags)) |
|---|
| 1879 | putStrLn $ showSDoc $ |
|---|
| 1880 | text "other dynamic, non-language, flag settings:" $$ |
|---|
| 1881 | nest 2 (vcat (map (setting dopt) others)) |
|---|
| 1882 | putStrLn $ showSDoc $ |
|---|
| 1883 | text "warning settings:" $$ |
|---|
| 1884 | nest 2 (vcat (map (setting wopt) DynFlags.fWarningFlags)) |
|---|
| 1885 | where |
|---|
| 1886 | setting test (str, f, _) |
|---|
| 1887 | | quiet = empty |
|---|
| 1888 | | is_on = fstr str |
|---|
| 1889 | | otherwise = fnostr str |
|---|
| 1890 | where is_on = test f dflags |
|---|
| 1891 | quiet = not show_all && test f default_dflags == is_on |
|---|
| 1892 | |
|---|
| 1893 | default_dflags = defaultDynFlags (settings dflags) |
|---|
| 1894 | |
|---|
| 1895 | fstr str = text "-f" <> text str |
|---|
| 1896 | fnostr str = text "-fno-" <> text str |
|---|
| 1897 | |
|---|
| 1898 | (ghciFlags,others) = partition (\(_, f, _) -> f `elem` flgs) |
|---|
| 1899 | DynFlags.fFlags |
|---|
| 1900 | flgs = [Opt_PrintExplicitForalls |
|---|
| 1901 | ,Opt_PrintBindResult |
|---|
| 1902 | ,Opt_BreakOnException |
|---|
| 1903 | ,Opt_BreakOnError |
|---|
| 1904 | ,Opt_PrintEvldWithShow |
|---|
| 1905 | ] |
|---|
| 1906 | |
|---|
| 1907 | setArgs, setOptions :: [String] -> GHCi () |
|---|
| 1908 | setProg, setEditor, setStop, setPrompt :: String -> GHCi () |
|---|
| 1909 | |
|---|
| 1910 | setArgs args = do |
|---|
| 1911 | st <- getGHCiState |
|---|
| 1912 | setGHCiState st{ GhciMonad.args = args } |
|---|
| 1913 | |
|---|
| 1914 | setProg prog = do |
|---|
| 1915 | st <- getGHCiState |
|---|
| 1916 | setGHCiState st{ progname = prog } |
|---|
| 1917 | |
|---|
| 1918 | setEditor cmd = do |
|---|
| 1919 | st <- getGHCiState |
|---|
| 1920 | setGHCiState st{ editor = cmd } |
|---|
| 1921 | |
|---|
| 1922 | setStop str@(c:_) | isDigit c |
|---|
| 1923 | = do let (nm_str,rest) = break (not.isDigit) str |
|---|
| 1924 | nm = read nm_str |
|---|
| 1925 | st <- getGHCiState |
|---|
| 1926 | let old_breaks = breaks st |
|---|
| 1927 | if all ((/= nm) . fst) old_breaks |
|---|
| 1928 | then printForUser (text "Breakpoint" <+> ppr nm <+> |
|---|
| 1929 | text "does not exist") |
|---|
| 1930 | else do |
|---|
| 1931 | let new_breaks = map fn old_breaks |
|---|
| 1932 | fn (i,loc) | i == nm = (i,loc { onBreakCmd = dropWhile isSpace rest }) |
|---|
| 1933 | | otherwise = (i,loc) |
|---|
| 1934 | setGHCiState st{ breaks = new_breaks } |
|---|
| 1935 | setStop cmd = do |
|---|
| 1936 | st <- getGHCiState |
|---|
| 1937 | setGHCiState st{ stop = cmd } |
|---|
| 1938 | |
|---|
| 1939 | setPrompt value = do |
|---|
| 1940 | st <- getGHCiState |
|---|
| 1941 | if null value |
|---|
| 1942 | then liftIO $ hPutStrLn stderr $ "syntax: :set prompt <prompt>, currently \"" ++ prompt st ++ "\"" |
|---|
| 1943 | else case value of |
|---|
| 1944 | '\"' : _ -> case reads value of |
|---|
| 1945 | [(value', xs)] | all isSpace xs -> |
|---|
| 1946 | setGHCiState (st { prompt = value' }) |
|---|
| 1947 | _ -> |
|---|
| 1948 | liftIO $ hPutStrLn stderr "Can't parse prompt string. Use Haskell syntax." |
|---|
| 1949 | _ -> setGHCiState (st { prompt = value }) |
|---|
| 1950 | |
|---|
| 1951 | setOptions wds = |
|---|
| 1952 | do -- first, deal with the GHCi opts (+s, +t, etc.) |
|---|
| 1953 | let (plus_opts, minus_opts) = partitionWith isPlus wds |
|---|
| 1954 | mapM_ setOpt plus_opts |
|---|
| 1955 | -- then, dynamic flags |
|---|
| 1956 | newDynFlags False minus_opts |
|---|
| 1957 | |
|---|
| 1958 | newDynFlags :: Bool -> [String] -> GHCi () |
|---|
| 1959 | newDynFlags interactive_only minus_opts = do |
|---|
| 1960 | let lopts = map noLoc minus_opts |
|---|
| 1961 | |
|---|
| 1962 | idflags0 <- GHC.getInteractiveDynFlags |
|---|
| 1963 | (idflags1, leftovers, warns) <- GHC.parseDynamicFlags idflags0 lopts |
|---|
| 1964 | |
|---|
| 1965 | liftIO $ handleFlagWarnings idflags1 warns |
|---|
| 1966 | when (not $ null leftovers) |
|---|
| 1967 | (ghcError . CmdLineError |
|---|
| 1968 | $ "Some flags have not been recognized: " |
|---|
| 1969 | ++ (concat . intersperse ", " $ map unLoc leftovers)) |
|---|
| 1970 | |
|---|
| 1971 | when (interactive_only && |
|---|
| 1972 | packageFlags idflags1 /= packageFlags idflags0) $ do |
|---|
| 1973 | liftIO $ hPutStrLn stderr "cannot set package flags with :seti; use :set" |
|---|
| 1974 | GHC.setInteractiveDynFlags idflags1 |
|---|
| 1975 | |
|---|
| 1976 | dflags0 <- getDynFlags |
|---|
| 1977 | when (not interactive_only) $ do |
|---|
| 1978 | (dflags1, _, _) <- liftIO $ GHC.parseDynamicFlags dflags0 lopts |
|---|
| 1979 | new_pkgs <- GHC.setProgramDynFlags dflags1 |
|---|
| 1980 | |
|---|
| 1981 | -- if the package flags changed, reset the context and link |
|---|
| 1982 | -- the new packages. |
|---|
| 1983 | dflags2 <- getDynFlags |
|---|
| 1984 | when (packageFlags dflags2 /= packageFlags dflags0) $ do |
|---|
| 1985 | liftIO $ hPutStrLn stderr "package flags have changed, resetting and loading new packages..." |
|---|
| 1986 | GHC.setTargets [] |
|---|
| 1987 | _ <- GHC.load LoadAllTargets |
|---|
| 1988 | liftIO $ linkPackages dflags2 new_pkgs |
|---|
| 1989 | -- package flags changed, we can't re-use any of the old context |
|---|
| 1990 | setContextAfterLoad False [] |
|---|
| 1991 | -- and copy the package state to the interactive DynFlags |
|---|
| 1992 | idflags <- GHC.getInteractiveDynFlags |
|---|
| 1993 | GHC.setInteractiveDynFlags |
|---|
| 1994 | idflags{ pkgState = pkgState dflags2 |
|---|
| 1995 | , pkgDatabase = pkgDatabase dflags2 |
|---|
| 1996 | , packageFlags = packageFlags dflags2 } |
|---|
| 1997 | |
|---|
| 1998 | return () |
|---|
| 1999 | |
|---|
| 2000 | |
|---|
| 2001 | unsetOptions :: String -> GHCi () |
|---|
| 2002 | unsetOptions str |
|---|
| 2003 | = -- first, deal with the GHCi opts (+s, +t, etc.) |
|---|
| 2004 | let opts = words str |
|---|
| 2005 | (minus_opts, rest1) = partition isMinus opts |
|---|
| 2006 | (plus_opts, rest2) = partitionWith isPlus rest1 |
|---|
| 2007 | (other_opts, rest3) = partition (`elem` map fst defaulters) rest2 |
|---|
| 2008 | |
|---|
| 2009 | defaulters = |
|---|
| 2010 | [ ("args" , setArgs default_args) |
|---|
| 2011 | , ("prog" , setProg default_progname) |
|---|
| 2012 | , ("prompt", setPrompt default_prompt) |
|---|
| 2013 | , ("editor", liftIO findEditor >>= setEditor) |
|---|
| 2014 | , ("stop" , setStop default_stop) |
|---|
| 2015 | ] |
|---|
| 2016 | |
|---|
| 2017 | no_flag ('-':'f':rest) = return ("-fno-" ++ rest) |
|---|
| 2018 | no_flag f = ghcError (ProgramError ("don't know how to reverse " ++ f)) |
|---|
| 2019 | |
|---|
| 2020 | in if (not (null rest3)) |
|---|
| 2021 | then liftIO (putStrLn ("unknown option: '" ++ head rest3 ++ "'")) |
|---|
| 2022 | else do |
|---|
| 2023 | mapM_ (fromJust.flip lookup defaulters) other_opts |
|---|
| 2024 | |
|---|
| 2025 | mapM_ unsetOpt plus_opts |
|---|
| 2026 | |
|---|
| 2027 | no_flags <- mapM no_flag minus_opts |
|---|
| 2028 | newDynFlags False no_flags |
|---|
| 2029 | |
|---|
| 2030 | isMinus :: String -> Bool |
|---|
| 2031 | isMinus ('-':_) = True |
|---|
| 2032 | isMinus _ = False |
|---|
| 2033 | |
|---|
| 2034 | isPlus :: String -> Either String String |
|---|
| 2035 | isPlus ('+':opt) = Left opt |
|---|
| 2036 | isPlus other = Right other |
|---|
| 2037 | |
|---|
| 2038 | setOpt, unsetOpt :: String -> GHCi () |
|---|
| 2039 | |
|---|
| 2040 | setOpt str |
|---|
| 2041 | = case strToGHCiOpt str of |
|---|
| 2042 | Nothing -> liftIO (putStrLn ("unknown option: '" ++ str ++ "'")) |
|---|
| 2043 | Just o -> setOption o |
|---|
| 2044 | |
|---|
| 2045 | unsetOpt str |
|---|
| 2046 | = case strToGHCiOpt str of |
|---|
| 2047 | Nothing -> liftIO (putStrLn ("unknown option: '" ++ str ++ "'")) |
|---|
| 2048 | Just o -> unsetOption o |
|---|
| 2049 | |
|---|
| 2050 | strToGHCiOpt :: String -> (Maybe GHCiOption) |
|---|
| 2051 | strToGHCiOpt "m" = Just Multiline |
|---|
| 2052 | strToGHCiOpt "s" = Just ShowTiming |
|---|
| 2053 | strToGHCiOpt "t" = Just ShowType |
|---|
| 2054 | strToGHCiOpt "r" = Just RevertCAFs |
|---|
| 2055 | strToGHCiOpt _ = Nothing |
|---|
| 2056 | |
|---|
| 2057 | optToStr :: GHCiOption -> String |
|---|
| 2058 | optToStr Multiline = "m" |
|---|
| 2059 | optToStr ShowTiming = "s" |
|---|
| 2060 | optToStr ShowType = "t" |
|---|
| 2061 | optToStr RevertCAFs = "r" |
|---|
| 2062 | |
|---|
| 2063 | |
|---|
| 2064 | -- --------------------------------------------------------------------------- |
|---|
| 2065 | -- :show |
|---|
| 2066 | |
|---|
| 2067 | showCmd :: String -> GHCi () |
|---|
| 2068 | showCmd "" = showOptions False |
|---|
| 2069 | showCmd "-a" = showOptions True |
|---|
| 2070 | showCmd str = do |
|---|
| 2071 | st <- getGHCiState |
|---|
| 2072 | case words str of |
|---|
| 2073 | ["args"] -> liftIO $ putStrLn (show (GhciMonad.args st)) |
|---|
| 2074 | ["prog"] -> liftIO $ putStrLn (show (progname st)) |
|---|
| 2075 | ["prompt"] -> liftIO $ putStrLn (show (prompt st)) |
|---|
| 2076 | ["editor"] -> liftIO $ putStrLn (show (editor st)) |
|---|
| 2077 | ["stop"] -> liftIO $ putStrLn (show (stop st)) |
|---|
| 2078 | ["imports"] -> showImports |
|---|
| 2079 | ["modules" ] -> showModules |
|---|
| 2080 | ["bindings"] -> showBindings |
|---|
| 2081 | ["linker"] -> liftIO showLinkerState |
|---|
| 2082 | ["breaks"] -> showBkptTable |
|---|
| 2083 | ["context"] -> showContext |
|---|
| 2084 | ["packages"] -> showPackages |
|---|
| 2085 | ["languages"] -> showLanguages -- backwards compat |
|---|
| 2086 | ["language"] -> showLanguages |
|---|
| 2087 | ["lang"] -> showLanguages -- useful abbreviation |
|---|
| 2088 | _ -> ghcError (CmdLineError ("syntax: :show [ args | prog | prompt | editor | stop | modules | bindings\n"++ |
|---|
| 2089 | " | breaks | context | packages | language ]")) |
|---|
| 2090 | |
|---|
| 2091 | showiCmd :: String -> GHCi () |
|---|
| 2092 | showiCmd str = do |
|---|
| 2093 | case words str of |
|---|
| 2094 | ["languages"] -> showiLanguages -- backwards compat |
|---|
| 2095 | ["language"] -> showiLanguages |
|---|
| 2096 | ["lang"] -> showiLanguages -- useful abbreviation |
|---|
| 2097 | _ -> ghcError (CmdLineError ("syntax: :showi language")) |
|---|
| 2098 | |
|---|
| 2099 | showImports :: GHCi () |
|---|
| 2100 | showImports = do |
|---|
| 2101 | st <- getGHCiState |
|---|
| 2102 | let rem_ctx = reverse (remembered_ctx st) |
|---|
| 2103 | trans_ctx = transient_ctx st |
|---|
| 2104 | |
|---|
| 2105 | show_one (IIModule star_m) |
|---|
| 2106 | = ":module +*" ++ moduleNameString star_m |
|---|
| 2107 | show_one (IIDecl imp) = showSDoc (ppr imp) |
|---|
| 2108 | |
|---|
| 2109 | prel_imp |
|---|
| 2110 | | any isPreludeImport (rem_ctx ++ trans_ctx) = [] |
|---|
| 2111 | | otherwise = ["import Prelude -- implicit"] |
|---|
| 2112 | |
|---|
| 2113 | trans_comment s = s ++ " -- added automatically" |
|---|
| 2114 | -- |
|---|
| 2115 | liftIO $ mapM_ putStrLn (prel_imp ++ map show_one rem_ctx |
|---|
| 2116 | ++ map (trans_comment . show_one) trans_ctx) |
|---|
| 2117 | |
|---|
| 2118 | showModules :: GHCi () |
|---|
| 2119 | showModules = do |
|---|
| 2120 | loaded_mods <- getLoadedModules |
|---|
| 2121 | -- we want *loaded* modules only, see #1734 |
|---|
| 2122 | let show_one ms = do m <- GHC.showModule ms; liftIO (putStrLn m) |
|---|
| 2123 | mapM_ show_one loaded_mods |
|---|
| 2124 | |
|---|
| 2125 | getLoadedModules :: GHC.GhcMonad m => m [GHC.ModSummary] |
|---|
| 2126 | getLoadedModules = do |
|---|
| 2127 | graph <- GHC.getModuleGraph |
|---|
| 2128 | filterM (GHC.isLoaded . GHC.ms_mod_name) graph |
|---|
| 2129 | |
|---|
| 2130 | showBindings :: GHCi () |
|---|
| 2131 | showBindings = do |
|---|
| 2132 | bindings <- GHC.getBindings |
|---|
| 2133 | (insts, finsts) <- GHC.getInsts |
|---|
| 2134 | docs <- mapM makeDoc (reverse bindings) |
|---|
| 2135 | -- reverse so the new ones come last |
|---|
| 2136 | let idocs = map GHC.pprInstanceHdr insts |
|---|
| 2137 | fidocs = map GHC.pprFamInstHdr finsts |
|---|
| 2138 | mapM_ printForUserPartWay (docs ++ idocs ++ fidocs) |
|---|
| 2139 | where |
|---|
| 2140 | makeDoc (AnId i) = pprTypeAndContents i |
|---|
| 2141 | makeDoc tt = do |
|---|
| 2142 | dflags <- getDynFlags |
|---|
| 2143 | let pefas = dopt Opt_PrintExplicitForalls dflags |
|---|
| 2144 | mb_stuff <- GHC.getInfo (getName tt) |
|---|
| 2145 | return $ maybe (text "") (pprTT pefas) mb_stuff |
|---|
| 2146 | pprTT :: PrintExplicitForalls -> (TyThing, Fixity, [GHC.ClsInst]) -> SDoc |
|---|
| 2147 | pprTT pefas (thing, fixity, _insts) = |
|---|
| 2148 | pprTyThing pefas thing |
|---|
| 2149 | $$ show_fixity fixity |
|---|
| 2150 | where |
|---|
| 2151 | show_fixity fix |
|---|
| 2152 | | fix == GHC.defaultFixity = empty |
|---|
| 2153 | | otherwise = ppr fix <+> ppr (GHC.getName thing) |
|---|
| 2154 | |
|---|
| 2155 | |
|---|
| 2156 | printTyThing :: TyThing -> GHCi () |
|---|
| 2157 | printTyThing tyth = do dflags <- getDynFlags |
|---|
| 2158 | let pefas = dopt Opt_PrintExplicitForalls dflags |
|---|
| 2159 | printForUser (pprTyThing pefas tyth) |
|---|
| 2160 | |
|---|
| 2161 | showBkptTable :: GHCi () |
|---|
| 2162 | showBkptTable = do |
|---|
| 2163 | st <- getGHCiState |
|---|
| 2164 | printForUser $ prettyLocations (breaks st) |
|---|
| 2165 | |
|---|
| 2166 | showContext :: GHCi () |
|---|
| 2167 | showContext = do |
|---|
| 2168 | resumes <- GHC.getResumeContext |
|---|
| 2169 | printForUser $ vcat (map pp_resume (reverse resumes)) |
|---|
| 2170 | where |
|---|
| 2171 | pp_resume res = |
|---|
| 2172 | ptext (sLit "--> ") <> text (GHC.resumeStmt res) |
|---|
| 2173 | $$ nest 2 (ptext (sLit "Stopped at") <+> ppr (GHC.resumeSpan res)) |
|---|
| 2174 | |
|---|
| 2175 | showPackages :: GHCi () |
|---|
| 2176 | showPackages = do |
|---|
| 2177 | pkg_flags <- fmap packageFlags getDynFlags |
|---|
| 2178 | liftIO $ putStrLn $ showSDoc $ vcat $ |
|---|
| 2179 | text ("active package flags:"++if null pkg_flags then " none" else "") |
|---|
| 2180 | : map showFlag pkg_flags |
|---|
| 2181 | where showFlag (ExposePackage p) = text $ " -package " ++ p |
|---|
| 2182 | showFlag (HidePackage p) = text $ " -hide-package " ++ p |
|---|
| 2183 | showFlag (IgnorePackage p) = text $ " -ignore-package " ++ p |
|---|
| 2184 | showFlag (ExposePackageId p) = text $ " -package-id " ++ p |
|---|
| 2185 | showFlag (TrustPackage p) = text $ " -trust " ++ p |
|---|
| 2186 | showFlag (DistrustPackage p) = text $ " -distrust " ++ p |
|---|
| 2187 | |
|---|
| 2188 | showLanguages :: GHCi () |
|---|
| 2189 | showLanguages = getDynFlags >>= liftIO . showLanguages' False |
|---|
| 2190 | |
|---|
| 2191 | showiLanguages :: GHCi () |
|---|
| 2192 | showiLanguages = GHC.getInteractiveDynFlags >>= liftIO . showLanguages' False |
|---|
| 2193 | |
|---|
| 2194 | showLanguages' :: Bool -> DynFlags -> IO () |
|---|
| 2195 | showLanguages' show_all dflags = |
|---|
| 2196 | putStrLn $ showSDoc $ vcat |
|---|
| 2197 | [ text "base language is: " <> |
|---|
| 2198 | case language dflags of |
|---|
| 2199 | Nothing -> text "Haskell2010" |
|---|
| 2200 | Just Haskell98 -> text "Haskell98" |
|---|
| 2201 | Just Haskell2010 -> text "Haskell2010" |
|---|
| 2202 | , (if show_all then text "all active language options:" |
|---|
| 2203 | else text "with the following modifiers:") $$ |
|---|
| 2204 | nest 2 (vcat (map (setting xopt) DynFlags.xFlags)) |
|---|
| 2205 | ] |
|---|
| 2206 | where |
|---|
| 2207 | setting test (str, f, _) |
|---|
| 2208 | | quiet = empty |
|---|
| 2209 | | is_on = text "-X" <> text str |
|---|
| 2210 | | otherwise = text "-XNo" <> text str |
|---|
| 2211 | where is_on = test f dflags |
|---|
| 2212 | quiet = not show_all && test f default_dflags == is_on |
|---|
| 2213 | |
|---|
| 2214 | default_dflags = |
|---|
| 2215 | defaultDynFlags (settings dflags) `lang_set` |
|---|
| 2216 | case language dflags of |
|---|
| 2217 | Nothing -> Just Haskell2010 |
|---|
| 2218 | other -> other |
|---|
| 2219 | |
|---|
| 2220 | -- ----------------------------------------------------------------------------- |
|---|
| 2221 | -- Completion |
|---|
| 2222 | |
|---|
| 2223 | completeCmd, completeMacro, completeIdentifier, completeModule, |
|---|
| 2224 | completeSetModule, completeSeti, completeShowiOptions, |
|---|
| 2225 | completeHomeModule, completeSetOptions, completeShowOptions, |
|---|
| 2226 | completeHomeModuleOrFile, completeExpression |
|---|
| 2227 | :: CompletionFunc GHCi |
|---|
| 2228 | |
|---|
| 2229 | ghciCompleteWord :: CompletionFunc GHCi |
|---|
| 2230 | ghciCompleteWord line@(left,_) = case firstWord of |
|---|
| 2231 | ':':cmd | null rest -> completeCmd line |
|---|
| 2232 | | otherwise -> do |
|---|
| 2233 | completion <- lookupCompletion cmd |
|---|
| 2234 | completion line |
|---|
| 2235 | "import" -> completeModule line |
|---|
| 2236 | _ -> completeExpression line |
|---|
| 2237 | where |
|---|
| 2238 | (firstWord,rest) = break isSpace $ dropWhile isSpace $ reverse left |
|---|
| 2239 | lookupCompletion ('!':_) = return completeFilename |
|---|
| 2240 | lookupCompletion c = do |
|---|
| 2241 | maybe_cmd <- liftIO $ lookupCommand' c |
|---|
| 2242 | case maybe_cmd of |
|---|
| 2243 | Just (_,_,f) -> return f |
|---|
| 2244 | Nothing -> return completeFilename |
|---|
| 2245 | |
|---|
| 2246 | completeCmd = wrapCompleter " " $ \w -> do |
|---|
| 2247 | macros <- liftIO $ readIORef macros_ref |
|---|
| 2248 | let macro_names = map (':':) . map cmdName $ macros |
|---|
| 2249 | let command_names = map (':':) . map cmdName $ builtin_commands |
|---|
| 2250 | let{ candidates = case w of |
|---|
| 2251 | ':' : ':' : _ -> map (':':) command_names |
|---|
| 2252 | _ -> nub $ macro_names ++ command_names } |
|---|
| 2253 | return $ filter (w `isPrefixOf`) candidates |
|---|
| 2254 | |
|---|
| 2255 | completeMacro = wrapIdentCompleter $ \w -> do |
|---|
| 2256 | cmds <- liftIO $ readIORef macros_ref |
|---|
| 2257 | return (filter (w `isPrefixOf`) (map cmdName cmds)) |
|---|
| 2258 | |
|---|
| 2259 | completeIdentifier = wrapIdentCompleter $ \w -> do |
|---|
| 2260 | rdrs <- GHC.getRdrNamesInScope |
|---|
| 2261 | return (filter (w `isPrefixOf`) (map (showSDoc.ppr) rdrs)) |
|---|
| 2262 | |
|---|
| 2263 | completeModule = wrapIdentCompleter $ \w -> do |
|---|
| 2264 | dflags <- GHC.getSessionDynFlags |
|---|
| 2265 | let pkg_mods = allExposedModules dflags |
|---|
| 2266 | loaded_mods <- liftM (map GHC.ms_mod_name) getLoadedModules |
|---|
| 2267 | return $ filter (w `isPrefixOf`) |
|---|
| 2268 | $ map (showSDoc.ppr) $ loaded_mods ++ pkg_mods |
|---|
| 2269 | |
|---|
| 2270 | completeSetModule = wrapIdentCompleterWithModifier "+-" $ \m w -> do |
|---|
| 2271 | modules <- case m of |
|---|
| 2272 | Just '-' -> do |
|---|
| 2273 | imports <- GHC.getContext |
|---|
| 2274 | return $ map iiModuleName imports |
|---|
| 2275 | _ -> do |
|---|
| 2276 | dflags <- GHC.getSessionDynFlags |
|---|
| 2277 | let pkg_mods = allExposedModules dflags |
|---|
| 2278 | loaded_mods <- liftM (map GHC.ms_mod_name) getLoadedModules |
|---|
| 2279 | return $ loaded_mods ++ pkg_mods |
|---|
| 2280 | return $ filter (w `isPrefixOf`) $ map (showSDoc.ppr) modules |
|---|
| 2281 | |
|---|
| 2282 | completeHomeModule = wrapIdentCompleter listHomeModules |
|---|
| 2283 | |
|---|
| 2284 | listHomeModules :: String -> GHCi [String] |
|---|
| 2285 | listHomeModules w = do |
|---|
| 2286 | g <- GHC.getModuleGraph |
|---|
| 2287 | let home_mods = map GHC.ms_mod_name g |
|---|
| 2288 | return $ sort $ filter (w `isPrefixOf`) |
|---|
| 2289 | $ map (showSDoc.ppr) home_mods |
|---|
| 2290 | |
|---|
| 2291 | completeSetOptions = wrapCompleter flagWordBreakChars $ \w -> do |
|---|
| 2292 | return (filter (w `isPrefixOf`) opts) |
|---|
| 2293 | where opts = "args":"prog":"prompt":"editor":"stop":flagList |
|---|
| 2294 | flagList = map head $ group $ sort allFlags |
|---|
| 2295 | |
|---|
| 2296 | completeSeti = wrapCompleter flagWordBreakChars $ \w -> do |
|---|
| 2297 | return (filter (w `isPrefixOf`) flagList) |
|---|
| 2298 | where flagList = map head $ group $ sort allFlags |
|---|
| 2299 | |
|---|
| 2300 | completeShowOptions = wrapCompleter flagWordBreakChars $ \w -> do |
|---|
| 2301 | return (filter (w `isPrefixOf`) opts) |
|---|
| 2302 | where opts = ["args", "prog", "prompt", "editor", "stop", |
|---|
| 2303 | "modules", "bindings", "linker", "breaks", |
|---|
| 2304 | "context", "packages", "language"] |
|---|
| 2305 | |
|---|
| 2306 | completeShowiOptions = wrapCompleter flagWordBreakChars $ \w -> do |
|---|
| 2307 | return (filter (w `isPrefixOf`) ["language"]) |
|---|
| 2308 | |
|---|
| 2309 | completeHomeModuleOrFile = completeWord Nothing filenameWordBreakChars |
|---|
| 2310 | $ unionComplete (fmap (map simpleCompletion) . listHomeModules) |
|---|
| 2311 | listFiles |
|---|
| 2312 | |
|---|
| 2313 | unionComplete :: Monad m => (a -> m [b]) -> (a -> m [b]) -> a -> m [b] |
|---|
| 2314 | unionComplete f1 f2 line = do |
|---|
| 2315 | cs1 <- f1 line |
|---|
| 2316 | cs2 <- f2 line |
|---|
| 2317 | return (cs1 ++ cs2) |
|---|
| 2318 | |
|---|
| 2319 | wrapCompleter :: String -> (String -> GHCi [String]) -> CompletionFunc GHCi |
|---|
| 2320 | wrapCompleter breakChars fun = completeWord Nothing breakChars |
|---|
| 2321 | $ fmap (map simpleCompletion) . fmap sort . fun |
|---|
| 2322 | |
|---|
| 2323 | wrapIdentCompleter :: (String -> GHCi [String]) -> CompletionFunc GHCi |
|---|
| 2324 | wrapIdentCompleter = wrapCompleter word_break_chars |
|---|
| 2325 | |
|---|
| 2326 | wrapIdentCompleterWithModifier :: String -> (Maybe Char -> String -> GHCi [String]) -> CompletionFunc GHCi |
|---|
| 2327 | wrapIdentCompleterWithModifier modifChars fun = completeWordWithPrev Nothing word_break_chars |
|---|
| 2328 | $ \rest -> fmap (map simpleCompletion) . fmap sort . fun (getModifier rest) |
|---|
| 2329 | where |
|---|
| 2330 | getModifier = find (`elem` modifChars) |
|---|
| 2331 | |
|---|
| 2332 | allExposedModules :: DynFlags -> [ModuleName] |
|---|
| 2333 | allExposedModules dflags |
|---|
| 2334 | = concat (map exposedModules (filter exposed (eltsUFM pkg_db))) |
|---|
| 2335 | where |
|---|
| 2336 | pkg_db = pkgIdMap (pkgState dflags) |
|---|
| 2337 | |
|---|
| 2338 | completeExpression = completeQuotedWord (Just '\\') "\"" listFiles |
|---|
| 2339 | completeIdentifier |
|---|
| 2340 | |
|---|
| 2341 | |
|---|
| 2342 | -- ----------------------------------------------------------------------------- |
|---|
| 2343 | -- commands for debugger |
|---|
| 2344 | |
|---|
| 2345 | sprintCmd, printCmd, forceCmd :: String -> GHCi () |
|---|
| 2346 | sprintCmd = pprintCommand False False |
|---|
| 2347 | printCmd = pprintCommand True False |
|---|
| 2348 | forceCmd = pprintCommand False True |
|---|
| 2349 | |
|---|
| 2350 | pprintCommand :: Bool -> Bool -> String -> GHCi () |
|---|
| 2351 | pprintCommand bind force str = do |
|---|
| 2352 | pprintClosureCommand bind force str |
|---|
| 2353 | |
|---|
| 2354 | stepCmd :: String -> GHCi () |
|---|
| 2355 | stepCmd arg = withSandboxOnly ":step" $ step arg |
|---|
| 2356 | where |
|---|
| 2357 | step [] = doContinue (const True) GHC.SingleStep |
|---|
| 2358 | step expression = runStmt expression GHC.SingleStep >> return () |
|---|
| 2359 | |
|---|
| 2360 | stepLocalCmd :: String -> GHCi () |
|---|
| 2361 | stepLocalCmd arg = withSandboxOnly ":steplocal" $ step arg |
|---|
| 2362 | where |
|---|
| 2363 | step expr |
|---|
| 2364 | | not (null expr) = stepCmd expr |
|---|
| 2365 | | otherwise = do |
|---|
| 2366 | mb_span <- getCurrentBreakSpan |
|---|
| 2367 | case mb_span of |
|---|
| 2368 | Nothing -> stepCmd [] |
|---|
| 2369 | Just loc -> do |
|---|
| 2370 | Just md <- getCurrentBreakModule |
|---|
| 2371 | current_toplevel_decl <- enclosingTickSpan md loc |
|---|
| 2372 | doContinue (`isSubspanOf` current_toplevel_decl) GHC.SingleStep |
|---|
| 2373 | |
|---|
| 2374 | stepModuleCmd :: String -> GHCi () |
|---|
| 2375 | stepModuleCmd arg = withSandboxOnly ":stepmodule" $ step arg |
|---|
| 2376 | where |
|---|
| 2377 | step expr |
|---|
| 2378 | | not (null expr) = stepCmd expr |
|---|
| 2379 | | otherwise = do |
|---|
| 2380 | mb_span <- getCurrentBreakSpan |
|---|
| 2381 | case mb_span of |
|---|
| 2382 | Nothing -> stepCmd [] |
|---|
| 2383 | Just pan -> do |
|---|
| 2384 | let f some_span = srcSpanFileName_maybe pan == srcSpanFileName_maybe some_span |
|---|
| 2385 | doContinue f GHC.SingleStep |
|---|
| 2386 | |
|---|
| 2387 | -- | Returns the span of the largest tick containing the srcspan given |
|---|
| 2388 | enclosingTickSpan :: Module -> SrcSpan -> GHCi SrcSpan |
|---|
| 2389 | enclosingTickSpan _ (UnhelpfulSpan _) = panic "enclosingTickSpan UnhelpfulSpan" |
|---|
| 2390 | enclosingTickSpan md (RealSrcSpan src) = do |
|---|
| 2391 | ticks <- getTickArray md |
|---|
| 2392 | let line = srcSpanStartLine src |
|---|
| 2393 | ASSERT (inRange (bounds ticks) line) do |
|---|
| 2394 | let toRealSrcSpan (UnhelpfulSpan _) = panic "enclosingTickSpan UnhelpfulSpan" |
|---|
| 2395 | toRealSrcSpan (RealSrcSpan s) = s |
|---|
| 2396 | enclosing_spans = [ pan | (_,pan) <- ticks ! line |
|---|
| 2397 | , realSrcSpanEnd (toRealSrcSpan pan) >= realSrcSpanEnd src] |
|---|
| 2398 | return . head . sortBy leftmost_largest $ enclosing_spans |
|---|
| 2399 | |
|---|
| 2400 | traceCmd :: String -> GHCi () |
|---|
| 2401 | traceCmd arg |
|---|
| 2402 | = withSandboxOnly ":trace" $ tr arg |
|---|
| 2403 | where |
|---|
| 2404 | tr [] = doContinue (const True) GHC.RunAndLogSteps |
|---|
| 2405 | tr expression = runStmt expression GHC.RunAndLogSteps >> return () |
|---|
| 2406 | |
|---|
| 2407 | continueCmd :: String -> GHCi () |
|---|
| 2408 | continueCmd = noArgs $ withSandboxOnly ":continue" $ doContinue (const True) GHC.RunToCompletion |
|---|
| 2409 | |
|---|
| 2410 | -- doContinue :: SingleStep -> GHCi () |
|---|
| 2411 | doContinue :: (SrcSpan -> Bool) -> SingleStep -> GHCi () |
|---|
| 2412 | doContinue pre step = do |
|---|
| 2413 | runResult <- resume pre step |
|---|
| 2414 | _ <- afterRunStmt pre runResult |
|---|
| 2415 | return () |
|---|
| 2416 | |
|---|
| 2417 | abandonCmd :: String -> GHCi () |
|---|
| 2418 | abandonCmd = noArgs $ withSandboxOnly ":abandon" $ do |
|---|
| 2419 | b <- GHC.abandon -- the prompt will change to indicate the new context |
|---|
| 2420 | when (not b) $ liftIO $ putStrLn "There is no computation running." |
|---|
| 2421 | |
|---|
| 2422 | deleteCmd :: String -> GHCi () |
|---|
| 2423 | deleteCmd argLine = withSandboxOnly ":delete" $ do |
|---|
| 2424 | deleteSwitch $ words argLine |
|---|
| 2425 | where |
|---|
| 2426 | deleteSwitch :: [String] -> GHCi () |
|---|
| 2427 | deleteSwitch [] = |
|---|
| 2428 | liftIO $ putStrLn "The delete command requires at least one argument." |
|---|
| 2429 | -- delete all break points |
|---|
| 2430 | deleteSwitch ("*":_rest) = discardActiveBreakPoints |
|---|
| 2431 | deleteSwitch idents = do |
|---|
| 2432 | mapM_ deleteOneBreak idents |
|---|
| 2433 | where |
|---|
| 2434 | deleteOneBreak :: String -> GHCi () |
|---|
| 2435 | deleteOneBreak str |
|---|
| 2436 | | all isDigit str = deleteBreak (read str) |
|---|
| 2437 | | otherwise = return () |
|---|
| 2438 | |
|---|
| 2439 | historyCmd :: String -> GHCi () |
|---|
| 2440 | historyCmd arg |
|---|
| 2441 | | null arg = history 20 |
|---|
| 2442 | | all isDigit arg = history (read arg) |
|---|
| 2443 | | otherwise = liftIO $ putStrLn "Syntax: :history [num]" |
|---|
| 2444 | where |
|---|
| 2445 | history num = do |
|---|
| 2446 | resumes <- GHC.getResumeContext |
|---|
| 2447 | case resumes of |
|---|
| 2448 | [] -> liftIO $ putStrLn "Not stopped at a breakpoint" |
|---|
| 2449 | (r:_) -> do |
|---|
| 2450 | let hist = GHC.resumeHistory r |
|---|
| 2451 | (took,rest) = splitAt num hist |
|---|
| 2452 | case hist of |
|---|
| 2453 | [] -> liftIO $ putStrLn $ |
|---|
| 2454 | "Empty history. Perhaps you forgot to use :trace?" |
|---|
| 2455 | _ -> do |
|---|
| 2456 | pans <- mapM GHC.getHistorySpan took |
|---|
| 2457 | let nums = map (printf "-%-3d:") [(1::Int)..] |
|---|
| 2458 | names = map GHC.historyEnclosingDecls took |
|---|
| 2459 | printForUser (vcat(zipWith3 |
|---|
| 2460 | (\x y z -> x <+> y <+> z) |
|---|
| 2461 | (map text nums) |
|---|
| 2462 | (map (bold . hcat . punctuate colon . map text) names) |
|---|
| 2463 | (map (parens . ppr) pans))) |
|---|
| 2464 | liftIO $ putStrLn $ if null rest then "<end of history>" else "..." |
|---|
| 2465 | |
|---|
| 2466 | bold :: SDoc -> SDoc |
|---|
| 2467 | bold c | do_bold = text start_bold <> c <> text end_bold |
|---|
| 2468 | | otherwise = c |
|---|
| 2469 | |
|---|
| 2470 | backCmd :: String -> GHCi () |
|---|
| 2471 | backCmd = noArgs $ withSandboxOnly ":back" $ do |
|---|
| 2472 | (names, _, pan) <- GHC.back |
|---|
| 2473 | printForUser $ ptext (sLit "Logged breakpoint at") <+> ppr pan |
|---|
| 2474 | printTypeOfNames names |
|---|
| 2475 | -- run the command set with ":set stop <cmd>" |
|---|
| 2476 | st <- getGHCiState |
|---|
| 2477 | enqueueCommands [stop st] |
|---|
| 2478 | |
|---|
| 2479 | forwardCmd :: String -> GHCi () |
|---|
| 2480 | forwardCmd = noArgs $ withSandboxOnly ":forward" $ do |
|---|
| 2481 | (names, ix, pan) <- GHC.forward |
|---|
| 2482 | printForUser $ (if (ix == 0) |
|---|
| 2483 | then ptext (sLit "Stopped at") |
|---|
| 2484 | else ptext (sLit "Logged breakpoint at")) <+> ppr pan |
|---|
| 2485 | printTypeOfNames names |
|---|
| 2486 | -- run the command set with ":set stop <cmd>" |
|---|
| 2487 | st <- getGHCiState |
|---|
| 2488 | enqueueCommands [stop st] |
|---|
| 2489 | |
|---|
| 2490 | -- handle the "break" command |
|---|
| 2491 | breakCmd :: String -> GHCi () |
|---|
| 2492 | breakCmd argLine = withSandboxOnly ":break" $ breakSwitch $ words argLine |
|---|
| 2493 | |
|---|
| 2494 | breakSwitch :: [String] -> GHCi () |
|---|
| 2495 | breakSwitch [] = do |
|---|
| 2496 | liftIO $ putStrLn "The break command requires at least one argument." |
|---|
| 2497 | breakSwitch (arg1:rest) |
|---|
| 2498 | | looksLikeModuleName arg1 && not (null rest) = do |
|---|
| 2499 | md <- wantInterpretedModule arg1 |
|---|
| 2500 | breakByModule md rest |
|---|
| 2501 | | all isDigit arg1 = do |
|---|
| 2502 | imports <- GHC.getContext |
|---|
| 2503 | case iiModules imports of |
|---|
| 2504 | (mn : _) -> do |
|---|
| 2505 | md <- lookupModuleName mn |
|---|
| 2506 | breakByModuleLine md (read arg1) rest |
|---|
| 2507 | [] -> do |
|---|
| 2508 | liftIO $ putStrLn "No modules are loaded with debugging support." |
|---|
| 2509 | | otherwise = do -- try parsing it as an identifier |
|---|
| 2510 | wantNameFromInterpretedModule noCanDo arg1 $ \name -> do |
|---|
| 2511 | let loc = GHC.srcSpanStart (GHC.nameSrcSpan name) |
|---|
| 2512 | case loc of |
|---|
| 2513 | RealSrcLoc l -> |
|---|
| 2514 | ASSERT( isExternalName name ) |
|---|
| 2515 | findBreakAndSet (GHC.nameModule name) $ |
|---|
| 2516 | findBreakByCoord (Just (GHC.srcLocFile l)) |
|---|
| 2517 | (GHC.srcLocLine l, |
|---|
| 2518 | GHC.srcLocCol l) |
|---|
| 2519 | UnhelpfulLoc _ -> |
|---|
| 2520 | noCanDo name $ text "can't find its location: " <> ppr loc |
|---|
| 2521 | where |
|---|
| 2522 | noCanDo n why = printForUser $ |
|---|
| 2523 | text "cannot set breakpoint on " <> ppr n <> text ": " <> why |
|---|
| 2524 | |
|---|
| 2525 | breakByModule :: Module -> [String] -> GHCi () |
|---|
| 2526 | breakByModule md (arg1:rest) |
|---|
| 2527 | | all isDigit arg1 = do -- looks like a line number |
|---|
| 2528 | breakByModuleLine md (read arg1) rest |
|---|
| 2529 | breakByModule _ _ |
|---|
| 2530 | = breakSyntax |
|---|
| 2531 | |
|---|
| 2532 | breakByModuleLine :: Module -> Int -> [String] -> GHCi () |
|---|
| 2533 | breakByModuleLine md line args |
|---|
| 2534 | | [] <- args = findBreakAndSet md $ findBreakByLine line |
|---|
| 2535 | | [col] <- args, all isDigit col = |
|---|
| 2536 | findBreakAndSet md $ findBreakByCoord Nothing (line, read col) |
|---|
| 2537 | | otherwise = breakSyntax |
|---|
| 2538 | |
|---|
| 2539 | breakSyntax :: a |
|---|
| 2540 | breakSyntax = ghcError (CmdLineError "Syntax: :break [<mod>] <line> [<column>]") |
|---|
| 2541 | |
|---|
| 2542 | findBreakAndSet :: Module -> (TickArray -> Maybe (Int, SrcSpan)) -> GHCi () |
|---|
| 2543 | findBreakAndSet md lookupTickTree = do |
|---|
| 2544 | tickArray <- getTickArray md |
|---|
| 2545 | (breakArray, _) <- getModBreak md |
|---|
| 2546 | case lookupTickTree tickArray of |
|---|
| 2547 | Nothing -> liftIO $ putStrLn $ "No breakpoints found at that location." |
|---|
| 2548 | Just (tick, pan) -> do |
|---|
| 2549 | success <- liftIO $ setBreakFlag True breakArray tick |
|---|
| 2550 | if success |
|---|
| 2551 | then do |
|---|
| 2552 | (alreadySet, nm) <- |
|---|
| 2553 | recordBreak $ BreakLocation |
|---|
| 2554 | { breakModule = md |
|---|
| 2555 | , breakLoc = pan |
|---|
| 2556 | , breakTick = tick |
|---|
| 2557 | , onBreakCmd = "" |
|---|
| 2558 | } |
|---|
| 2559 | printForUser $ |
|---|
| 2560 | text "Breakpoint " <> ppr nm <> |
|---|
| 2561 | if alreadySet |
|---|
| 2562 | then text " was already set at " <> ppr pan |
|---|
| 2563 | else text " activated at " <> ppr pan |
|---|
| 2564 | else do |
|---|
| 2565 | printForUser $ text "Breakpoint could not be activated at" |
|---|
| 2566 | <+> ppr pan |
|---|
| 2567 | |
|---|
| 2568 | -- When a line number is specified, the current policy for choosing |
|---|
| 2569 | -- the best breakpoint is this: |
|---|
| 2570 | -- - the leftmost complete subexpression on the specified line, or |
|---|
| 2571 | -- - the leftmost subexpression starting on the specified line, or |
|---|
| 2572 | -- - the rightmost subexpression enclosing the specified line |
|---|
| 2573 | -- |
|---|
| 2574 | findBreakByLine :: Int -> TickArray -> Maybe (BreakIndex,SrcSpan) |
|---|
| 2575 | findBreakByLine line arr |
|---|
| 2576 | | not (inRange (bounds arr) line) = Nothing |
|---|
| 2577 | | otherwise = |
|---|
| 2578 | listToMaybe (sortBy (leftmost_largest `on` snd) comp) `mplus` |
|---|
| 2579 | listToMaybe (sortBy (leftmost_smallest `on` snd) incomp) `mplus` |
|---|
| 2580 | listToMaybe (sortBy (rightmost `on` snd) ticks) |
|---|
| 2581 | where |
|---|
| 2582 | ticks = arr ! line |
|---|
| 2583 | |
|---|
| 2584 | starts_here = [ tick | tick@(_,pan) <- ticks, |
|---|
| 2585 | GHC.srcSpanStartLine (toRealSpan pan) == line ] |
|---|
| 2586 | |
|---|
| 2587 | (comp, incomp) = partition ends_here starts_here |
|---|
| 2588 | where ends_here (_,pan) = GHC.srcSpanEndLine (toRealSpan pan) == line |
|---|
| 2589 | toRealSpan (RealSrcSpan pan) = pan |
|---|
| 2590 | toRealSpan (UnhelpfulSpan _) = panic "findBreakByLine UnhelpfulSpan" |
|---|
| 2591 | |
|---|
| 2592 | findBreakByCoord :: Maybe FastString -> (Int,Int) -> TickArray |
|---|
| 2593 | -> Maybe (BreakIndex,SrcSpan) |
|---|
| 2594 | findBreakByCoord mb_file (line, col) arr |
|---|
| 2595 | | not (inRange (bounds arr) line) = Nothing |
|---|
| 2596 | | otherwise = |
|---|
| 2597 | listToMaybe (sortBy (rightmost `on` snd) contains ++ |
|---|
| 2598 | sortBy (leftmost_smallest `on` snd) after_here) |
|---|
| 2599 | where |
|---|
| 2600 | ticks = arr ! line |
|---|
| 2601 | |
|---|
| 2602 | -- the ticks that span this coordinate |
|---|
| 2603 | contains = [ tick | tick@(_,pan) <- ticks, pan `spans` (line,col), |
|---|
| 2604 | is_correct_file pan ] |
|---|
| 2605 | |
|---|
| 2606 | is_correct_file pan |
|---|
| 2607 | | Just f <- mb_file = GHC.srcSpanFile (toRealSpan pan) == f |
|---|
| 2608 | | otherwise = True |
|---|
| 2609 | |
|---|
| 2610 | after_here = [ tick | tick@(_,pan) <- ticks, |
|---|
| 2611 | let pan' = toRealSpan pan, |
|---|
| 2612 | GHC.srcSpanStartLine pan' == line, |
|---|
| 2613 | GHC.srcSpanStartCol pan' >= col ] |
|---|
| 2614 | |
|---|
| 2615 | toRealSpan (RealSrcSpan pan) = pan |
|---|
| 2616 | toRealSpan (UnhelpfulSpan _) = panic "findBreakByCoord UnhelpfulSpan" |
|---|
| 2617 | |
|---|
| 2618 | -- For now, use ANSI bold on terminals that we know support it. |
|---|
| 2619 | -- Otherwise, we add a line of carets under the active expression instead. |
|---|
| 2620 | -- In particular, on Windows and when running the testsuite (which sets |
|---|
| 2621 | -- TERM to vt100 for other reasons) we get carets. |
|---|
| 2622 | -- We really ought to use a proper termcap/terminfo library. |
|---|
| 2623 | do_bold :: Bool |
|---|
| 2624 | do_bold = (`isPrefixOf` unsafePerformIO mTerm) `any` ["xterm", "linux"] |
|---|
| 2625 | where mTerm = System.Environment.getEnv "TERM" |
|---|
| 2626 | `catchIO` \_ -> return "TERM not set" |
|---|
| 2627 | |
|---|
| 2628 | start_bold :: String |
|---|
| 2629 | start_bold = "\ESC[1m" |
|---|
| 2630 | end_bold :: String |
|---|
| 2631 | end_bold = "\ESC[0m" |
|---|
| 2632 | |
|---|
| 2633 | |
|---|
| 2634 | ----------------------------------------------------------------------------- |
|---|
| 2635 | -- :list |
|---|
| 2636 | |
|---|
| 2637 | listCmd :: String -> InputT GHCi () |
|---|
| 2638 | listCmd c = listCmd' c |
|---|
| 2639 | |
|---|
| 2640 | listCmd' :: String -> InputT GHCi () |
|---|
| 2641 | listCmd' "" = do |
|---|
| 2642 | mb_span <- lift getCurrentBreakSpan |
|---|
| 2643 | case mb_span of |
|---|
| 2644 | Nothing -> |
|---|
| 2645 | printForUser $ text "Not stopped at a breakpoint; nothing to list" |
|---|
| 2646 | Just (RealSrcSpan pan) -> |
|---|
| 2647 | listAround pan True |
|---|
| 2648 | Just pan@(UnhelpfulSpan _) -> |
|---|
| 2649 | do resumes <- GHC.getResumeContext |
|---|
| 2650 | case resumes of |
|---|
| 2651 | [] -> panic "No resumes" |
|---|
| 2652 | (r:_) -> |
|---|
| 2653 | do let traceIt = case GHC.resumeHistory r of |
|---|
| 2654 | [] -> text "rerunning with :trace," |
|---|
| 2655 | _ -> empty |
|---|
| 2656 | doWhat = traceIt <+> text ":back then :list" |
|---|
| 2657 | printForUser (text "Unable to list source for" <+> |
|---|
| 2658 | ppr pan |
|---|
| 2659 | $$ text "Try" <+> doWhat) |
|---|
| 2660 | listCmd' str = list2 (words str) |
|---|
| 2661 | |
|---|
| 2662 | list2 :: [String] -> InputT GHCi () |
|---|
| 2663 | list2 [arg] | all isDigit arg = do |
|---|
| 2664 | imports <- GHC.getContext |
|---|
| 2665 | case iiModules imports of |
|---|
| 2666 | [] -> liftIO $ putStrLn "No module to list" |
|---|
| 2667 | (mn : _) -> do |
|---|
| 2668 | md <- lift $ lookupModuleName mn |
|---|
| 2669 | listModuleLine md (read arg) |
|---|
| 2670 | list2 [arg1,arg2] | looksLikeModuleName arg1, all isDigit arg2 = do |
|---|
| 2671 | md <- wantInterpretedModule arg1 |
|---|
| 2672 | listModuleLine md (read arg2) |
|---|
| 2673 | list2 [arg] = do |
|---|
| 2674 | wantNameFromInterpretedModule noCanDo arg $ \name -> do |
|---|
| 2675 | let loc = GHC.srcSpanStart (GHC.nameSrcSpan name) |
|---|
| 2676 | case loc of |
|---|
| 2677 | RealSrcLoc l -> |
|---|
| 2678 | do tickArray <- ASSERT( isExternalName name ) |
|---|
| 2679 | lift $ getTickArray (GHC.nameModule name) |
|---|
| 2680 | let mb_span = findBreakByCoord (Just (GHC.srcLocFile l)) |
|---|
| 2681 | (GHC.srcLocLine l, GHC.srcLocCol l) |
|---|
| 2682 | tickArray |
|---|
| 2683 | case mb_span of |
|---|
| 2684 | Nothing -> listAround (realSrcLocSpan l) False |
|---|
| 2685 | Just (_, UnhelpfulSpan _) -> panic "list2 UnhelpfulSpan" |
|---|
| 2686 | Just (_, RealSrcSpan pan) -> listAround pan False |
|---|
| 2687 | UnhelpfulLoc _ -> |
|---|
| 2688 | noCanDo name $ text "can't find its location: " <> |
|---|
| 2689 | ppr loc |
|---|
| 2690 | where |
|---|
| 2691 | noCanDo n why = printForUser $ |
|---|
| 2692 | text "cannot list source code for " <> ppr n <> text ": " <> why |
|---|
| 2693 | list2 _other = |
|---|
| 2694 | liftIO $ putStrLn "syntax: :list [<line> | <module> <line> | <identifier>]" |
|---|
| 2695 | |
|---|
| 2696 | listModuleLine :: Module -> Int -> InputT GHCi () |
|---|
| 2697 | listModuleLine modl line = do |
|---|
| 2698 | graph <- GHC.getModuleGraph |
|---|
| 2699 | let this = filter ((== modl) . GHC.ms_mod) graph |
|---|
| 2700 | case this of |
|---|
| 2701 | [] -> panic "listModuleLine" |
|---|
| 2702 | summ:_ -> do |
|---|
| 2703 | let filename = expectJust "listModuleLine" (ml_hs_file (GHC.ms_location summ)) |
|---|
| 2704 | loc = mkRealSrcLoc (mkFastString (filename)) line 0 |
|---|
| 2705 | listAround (realSrcLocSpan loc) False |
|---|
| 2706 | |
|---|
| 2707 | -- | list a section of a source file around a particular SrcSpan. |
|---|
| 2708 | -- If the highlight flag is True, also highlight the span using |
|---|
| 2709 | -- start_bold\/end_bold. |
|---|
| 2710 | |
|---|
| 2711 | -- GHC files are UTF-8, so we can implement this by: |
|---|
| 2712 | -- 1) read the file in as a BS and syntax highlight it as before |
|---|
| 2713 | -- 2) convert the BS to String using utf-string, and write it out. |
|---|
| 2714 | -- It would be better if we could convert directly between UTF-8 and the |
|---|
| 2715 | -- console encoding, of course. |
|---|
| 2716 | listAround :: MonadIO m => RealSrcSpan -> Bool -> InputT m () |
|---|
| 2717 | listAround pan do_highlight = do |
|---|
| 2718 | contents <- liftIO $ BS.readFile (unpackFS file) |
|---|
| 2719 | let ls = BS.split '\n' contents |
|---|
| 2720 | ls' = take (line2 - line1 + 1 + pad_before + pad_after) $ |
|---|
| 2721 | drop (line1 - 1 - pad_before) $ ls |
|---|
| 2722 | fst_line = max 1 (line1 - pad_before) |
|---|
| 2723 | line_nos = [ fst_line .. ] |
|---|
| 2724 | |
|---|
| 2725 | highlighted | do_highlight = zipWith highlight line_nos ls' |
|---|
| 2726 | | otherwise = [\p -> BS.concat[p,l] | l <- ls'] |
|---|
| 2727 | |
|---|
| 2728 | bs_line_nos = [ BS.pack (show l ++ " ") | l <- line_nos ] |
|---|
| 2729 | prefixed = zipWith ($) highlighted bs_line_nos |
|---|
| 2730 | output = BS.intercalate (BS.pack "\n") prefixed |
|---|
| 2731 | |
|---|
| 2732 | utf8Decoded <- liftIO $ BS.useAsCStringLen output |
|---|
| 2733 | $ \(p,n) -> utf8DecodeString (castPtr p) n |
|---|
| 2734 | liftIO $ putStrLn utf8Decoded |
|---|
| 2735 | where |
|---|
| 2736 | file = GHC.srcSpanFile pan |
|---|
| 2737 | line1 = GHC.srcSpanStartLine pan |
|---|
| 2738 | col1 = GHC.srcSpanStartCol pan - 1 |
|---|
| 2739 | line2 = GHC.srcSpanEndLine pan |
|---|
| 2740 | col2 = GHC.srcSpanEndCol pan - 1 |
|---|
| 2741 | |
|---|
| 2742 | pad_before | line1 == 1 = 0 |
|---|
| 2743 | | otherwise = 1 |
|---|
| 2744 | pad_after = 1 |
|---|
| 2745 | |
|---|
| 2746 | highlight | do_bold = highlight_bold |
|---|
| 2747 | | otherwise = highlight_carets |
|---|
| 2748 | |
|---|
| 2749 | highlight_bold no line prefix |
|---|
| 2750 | | no == line1 && no == line2 |
|---|
| 2751 | = let (a,r) = BS.splitAt col1 line |
|---|
| 2752 | (b,c) = BS.splitAt (col2-col1) r |
|---|
| 2753 | in |
|---|
| 2754 | BS.concat [prefix, a,BS.pack start_bold,b,BS.pack end_bold,c] |
|---|
| 2755 | | no == line1 |
|---|
| 2756 | = let (a,b) = BS.splitAt col1 line in |
|---|
| 2757 | BS.concat [prefix, a, BS.pack start_bold, b] |
|---|
| 2758 | | no == line2 |
|---|
| 2759 | = let (a,b) = BS.splitAt col2 line in |
|---|
| 2760 | BS.concat [prefix, a, BS.pack end_bold, b] |
|---|
| 2761 | | otherwise = BS.concat [prefix, line] |
|---|
| 2762 | |
|---|
| 2763 | highlight_carets no line prefix |
|---|
| 2764 | | no == line1 && no == line2 |
|---|
| 2765 | = BS.concat [prefix, line, nl, indent, BS.replicate col1 ' ', |
|---|
| 2766 | BS.replicate (col2-col1) '^'] |
|---|
| 2767 | | no == line1 |
|---|
| 2768 | = BS.concat [indent, BS.replicate (col1 - 2) ' ', BS.pack "vv", nl, |
|---|
| 2769 | prefix, line] |
|---|
| 2770 | | no == line2 |
|---|
| 2771 | = BS.concat [prefix, line, nl, indent, BS.replicate col2 ' ', |
|---|
| 2772 | BS.pack "^^"] |
|---|
| 2773 | | otherwise = BS.concat [prefix, line] |
|---|
| 2774 | where |
|---|
| 2775 | indent = BS.pack (" " ++ replicate (length (show no)) ' ') |
|---|
| 2776 | nl = BS.singleton '\n' |
|---|
| 2777 | |
|---|
| 2778 | |
|---|
| 2779 | -- -------------------------------------------------------------------------- |
|---|
| 2780 | -- Tick arrays |
|---|
| 2781 | |
|---|
| 2782 | getTickArray :: Module -> GHCi TickArray |
|---|
| 2783 | getTickArray modl = do |
|---|
| 2784 | st <- getGHCiState |
|---|
| 2785 | let arrmap = tickarrays st |
|---|
| 2786 | case lookupModuleEnv arrmap modl of |
|---|
| 2787 | Just arr -> return arr |
|---|
| 2788 | Nothing -> do |
|---|
| 2789 | (_breakArray, ticks) <- getModBreak modl |
|---|
| 2790 | let arr = mkTickArray (assocs ticks) |
|---|
| 2791 | setGHCiState st{tickarrays = extendModuleEnv arrmap modl arr} |
|---|
| 2792 | return arr |
|---|
| 2793 | |
|---|
| 2794 | discardTickArrays :: GHCi () |
|---|
| 2795 | discardTickArrays = do |
|---|
| 2796 | st <- getGHCiState |
|---|
| 2797 | setGHCiState st{tickarrays = emptyModuleEnv} |
|---|
| 2798 | |
|---|
| 2799 | mkTickArray :: [(BreakIndex,SrcSpan)] -> TickArray |
|---|
| 2800 | mkTickArray ticks |
|---|
| 2801 | = accumArray (flip (:)) [] (1, max_line) |
|---|
| 2802 | [ (line, (nm,pan)) | (nm,pan) <- ticks, |
|---|
| 2803 | let pan' = toRealSpan pan, |
|---|
| 2804 | line <- srcSpanLines pan' ] |
|---|
| 2805 | where |
|---|
| 2806 | max_line = foldr max 0 (map (GHC.srcSpanEndLine . toRealSpan . snd) ticks) |
|---|
| 2807 | srcSpanLines pan = [ GHC.srcSpanStartLine pan .. GHC.srcSpanEndLine pan ] |
|---|
| 2808 | toRealSpan (RealSrcSpan pan) = pan |
|---|
| 2809 | toRealSpan (UnhelpfulSpan _) = panic "mkTickArray UnhelpfulSpan" |
|---|
| 2810 | |
|---|
| 2811 | -- don't reset the counter back to zero? |
|---|
| 2812 | discardActiveBreakPoints :: GHCi () |
|---|
| 2813 | discardActiveBreakPoints = do |
|---|
| 2814 | st <- getGHCiState |
|---|
| 2815 | mapM_ (turnOffBreak.snd) (breaks st) |
|---|
| 2816 | setGHCiState $ st { breaks = [] } |
|---|
| 2817 | |
|---|
| 2818 | deleteBreak :: Int -> GHCi () |
|---|
| 2819 | deleteBreak identity = do |
|---|
| 2820 | st <- getGHCiState |
|---|
| 2821 | let oldLocations = breaks st |
|---|
| 2822 | (this,rest) = partition (\loc -> fst loc == identity) oldLocations |
|---|
| 2823 | if null this |
|---|
| 2824 | then printForUser (text "Breakpoint" <+> ppr identity <+> |
|---|
| 2825 | text "does not exist") |
|---|
| 2826 | else do |
|---|
| 2827 | mapM_ (turnOffBreak.snd) this |
|---|
| 2828 | setGHCiState $ st { breaks = rest } |
|---|
| 2829 | |
|---|
| 2830 | turnOffBreak :: BreakLocation -> GHCi Bool |
|---|
| 2831 | turnOffBreak loc = do |
|---|
| 2832 | (arr, _) <- getModBreak (breakModule loc) |
|---|
| 2833 | liftIO $ setBreakFlag False arr (breakTick loc) |
|---|
| 2834 | |
|---|
| 2835 | getModBreak :: Module -> GHCi (GHC.BreakArray, Array Int SrcSpan) |
|---|
| 2836 | getModBreak m = do |
|---|
| 2837 | Just mod_info <- GHC.getModuleInfo m |
|---|
| 2838 | let modBreaks = GHC.modInfoModBreaks mod_info |
|---|
| 2839 | let arr = GHC.modBreaks_flags modBreaks |
|---|
| 2840 | let ticks = GHC.modBreaks_locs modBreaks |
|---|
| 2841 | return (arr, ticks) |
|---|
| 2842 | |
|---|
| 2843 | setBreakFlag :: Bool -> GHC.BreakArray -> Int -> IO Bool |
|---|
| 2844 | setBreakFlag toggle arr i |
|---|
| 2845 | | toggle = GHC.setBreakOn arr i |
|---|
| 2846 | | otherwise = GHC.setBreakOff arr i |
|---|
| 2847 | |
|---|
| 2848 | |
|---|
| 2849 | -- --------------------------------------------------------------------------- |
|---|
| 2850 | -- User code exception handling |
|---|
| 2851 | |
|---|
| 2852 | -- This is the exception handler for exceptions generated by the |
|---|
| 2853 | -- user's code and exceptions coming from children sessions; |
|---|
| 2854 | -- it normally just prints out the exception. The |
|---|
| 2855 | -- handler must be recursive, in case showing the exception causes |
|---|
| 2856 | -- more exceptions to be raised. |
|---|
| 2857 | -- |
|---|
| 2858 | -- Bugfix: if the user closed stdout or stderr, the flushing will fail, |
|---|
| 2859 | -- raising another exception. We therefore don't put the recursive |
|---|
| 2860 | -- handler arond the flushing operation, so if stderr is closed |
|---|
| 2861 | -- GHCi will just die gracefully rather than going into an infinite loop. |
|---|
| 2862 | handler :: SomeException -> GHCi Bool |
|---|
| 2863 | |
|---|
| 2864 | handler exception = do |
|---|
| 2865 | flushInterpBuffers |
|---|
| 2866 | liftIO installSignalHandlers |
|---|
| 2867 | ghciHandle handler (showException exception >> return False) |
|---|
| 2868 | |
|---|
| 2869 | showException :: SomeException -> GHCi () |
|---|
| 2870 | showException se = |
|---|
| 2871 | liftIO $ case fromException se of |
|---|
| 2872 | -- omit the location for CmdLineError: |
|---|
| 2873 | Just (CmdLineError s) -> putException s |
|---|
| 2874 | -- ditto: |
|---|
| 2875 | Just ph@(PhaseFailed {}) -> putException (showGhcException ph "") |
|---|
| 2876 | Just other_ghc_ex -> putException (show other_ghc_ex) |
|---|
| 2877 | Nothing -> |
|---|
| 2878 | case fromException se of |
|---|
| 2879 | Just UserInterrupt -> putException "Interrupted." |
|---|
| 2880 | _ -> putException ("*** Exception: " ++ show se) |
|---|
| 2881 | where |
|---|
| 2882 | putException = hPutStrLn stderr |
|---|
| 2883 | |
|---|
| 2884 | |
|---|
| 2885 | ----------------------------------------------------------------------------- |
|---|
| 2886 | -- recursive exception handlers |
|---|
| 2887 | |
|---|
| 2888 | -- Don't forget to unblock async exceptions in the handler, or if we're |
|---|
| 2889 | -- in an exception loop (eg. let a = error a in a) the ^C exception |
|---|
| 2890 | -- may never be delivered. Thanks to Marcin for pointing out the bug. |
|---|
| 2891 | |
|---|
| 2892 | ghciHandle :: ExceptionMonad m => (SomeException -> m a) -> m a -> m a |
|---|
| 2893 | ghciHandle h m = gcatch m $ \e -> gunblock (h e) |
|---|
| 2894 | |
|---|
| 2895 | ghciTry :: GHCi a -> GHCi (Either SomeException a) |
|---|
| 2896 | ghciTry (GHCi m) = GHCi $ \s -> gtry (m s) |
|---|
| 2897 | |
|---|
| 2898 | tryBool :: GHCi a -> GHCi Bool |
|---|
| 2899 | tryBool m = do |
|---|
| 2900 | r <- ghciTry m |
|---|
| 2901 | case r of |
|---|
| 2902 | Left _ -> return False |
|---|
| 2903 | Right _ -> return True |
|---|
| 2904 | |
|---|
| 2905 | -- ---------------------------------------------------------------------------- |
|---|
| 2906 | -- Utils |
|---|
| 2907 | |
|---|
| 2908 | lookupModule :: GHC.GhcMonad m => String -> m Module |
|---|
| 2909 | lookupModule mName = lookupModuleName (GHC.mkModuleName mName) |
|---|
| 2910 | |
|---|
| 2911 | lookupModuleName :: GHC.GhcMonad m => ModuleName -> m Module |
|---|
| 2912 | lookupModuleName mName = GHC.lookupModule mName Nothing |
|---|
| 2913 | |
|---|
| 2914 | isHomeModule :: Module -> Bool |
|---|
| 2915 | isHomeModule m = GHC.modulePackageId m == mainPackageId |
|---|
| 2916 | |
|---|
| 2917 | -- TODO: won't work if home dir is encoded. |
|---|
| 2918 | -- (changeDirectory may not work either in that case.) |
|---|
| 2919 | expandPath :: MonadIO m => String -> InputT m String |
|---|
| 2920 | expandPath = liftIO . expandPathIO |
|---|
| 2921 | |
|---|
| 2922 | expandPathIO :: String -> IO String |
|---|
| 2923 | expandPathIO p = |
|---|
| 2924 | case dropWhile isSpace p of |
|---|
| 2925 | ('~':d) -> do |
|---|
| 2926 | tilde <- getHomeDirectory -- will fail if HOME not defined |
|---|
| 2927 | return (tilde ++ '/':d) |
|---|
| 2928 | other -> |
|---|
| 2929 | return other |
|---|
| 2930 | |
|---|
| 2931 | wantInterpretedModule :: GHC.GhcMonad m => String -> m Module |
|---|
| 2932 | wantInterpretedModule str = wantInterpretedModuleName (GHC.mkModuleName str) |
|---|
| 2933 | |
|---|
| 2934 | wantInterpretedModuleName :: GHC.GhcMonad m => ModuleName -> m Module |
|---|
| 2935 | wantInterpretedModuleName modname = do |
|---|
| 2936 | modl <- lookupModuleName modname |
|---|
| 2937 | let str = moduleNameString modname |
|---|
| 2938 | dflags <- getDynFlags |
|---|
| 2939 | when (GHC.modulePackageId modl /= thisPackage dflags) $ |
|---|
| 2940 | ghcError (CmdLineError ("module '" ++ str ++ "' is from another package;\nthis command requires an interpreted module")) |
|---|
| 2941 | is_interpreted <- GHC.moduleIsInterpreted modl |
|---|
| 2942 | when (not is_interpreted) $ |
|---|
| 2943 | ghcError (CmdLineError ("module '" ++ str ++ "' is not interpreted; try \':add *" ++ str ++ "' first")) |
|---|
| 2944 | return modl |
|---|
| 2945 | |
|---|
| 2946 | wantNameFromInterpretedModule :: GHC.GhcMonad m |
|---|
| 2947 | => (Name -> SDoc -> m ()) |
|---|
| 2948 | -> String |
|---|
| 2949 | -> (Name -> m ()) |
|---|
| 2950 | -> m () |
|---|
| 2951 | wantNameFromInterpretedModule noCanDo str and_then = |
|---|
| 2952 | handleSourceError GHC.printException $ do |
|---|
| 2953 | names <- GHC.parseName str |
|---|
| 2954 | case names of |
|---|
| 2955 | [] -> return () |
|---|
| 2956 | (n:_) -> do |
|---|
| 2957 | let modl = ASSERT( isExternalName n ) GHC.nameModule n |
|---|
| 2958 | if not (GHC.isExternalName n) |
|---|
| 2959 | then noCanDo n $ ppr n <> |
|---|
| 2960 | text " is not defined in an interpreted module" |
|---|
| 2961 | else do |
|---|
| 2962 | is_interpreted <- GHC.moduleIsInterpreted modl |
|---|
| 2963 | if not is_interpreted |
|---|
| 2964 | then noCanDo n $ text "module " <> ppr modl <> |
|---|
| 2965 | text " is not interpreted" |
|---|
| 2966 | else and_then n |
|---|