X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=compiler%2Fghci%2FInteractiveUI.hs;h=486d40380dec9a48c3a80a3eb05f47ddaaa5350e;hb=e560c6b5a0c2ef4437ebca0c78c1775a09ba31c9;hp=3de1c7bc50862448e03d37ff57c7e9530f318c66;hpb=4da439a6b1e343fc5216d5c6bb51858c6d9aacd6;p=ghc-hetmet.git diff --git a/compiler/ghci/InteractiveUI.hs b/compiler/ghci/InteractiveUI.hs index 3de1c7b..486d403 100644 --- a/compiler/ghci/InteractiveUI.hs +++ b/compiler/ghci/InteractiveUI.hs @@ -110,6 +110,7 @@ builtin_commands = [ ("cd", keepGoing changeDirectory, False, completeFilename), ("check", keepGoing checkModule, False, completeHomeModule), ("continue", keepGoing continueCmd, False, completeNone), + ("cmd", keepGoing cmdCmd, False, completeIdentifier), ("ctags", keepGoing createCTagsFileCmd, False, completeFilename), ("def", keepGoing defineMacro, False, completeIdentifier), ("delete", keepGoing deleteCmd, False, completeNone), @@ -154,6 +155,7 @@ helpText = " :add ... add module(s) to the current target set\n" ++ " :browse [*] display the names defined by \n" ++ " :cd change directory to \n" ++ + " :cmd run the commands returned by ::IO String"++ " :ctags [] create tags file for Vi (default: \"tags\")\n" ++ " :def define a command :\n" ++ " :edit edit file\n" ++ @@ -184,11 +186,11 @@ helpText = " :forward go forward in the history (after :back)\n" ++ " :history [] show the last items in the history (after :trace)\n" ++ " :print [ ...] prints a value without forcing its computation\n" ++ + " :sprint [ ...] simplifed version of :print\n" ++ " :step single-step after stopping at a breakpoint\n"++ " :step single-step into \n"++ " :trace trace after stopping at a breakpoint\n"++ " :trace trace into (remembers breakpoints for :history)\n"++ - " :sprint [ ...] simplifed version of :print\n" ++ "\n" ++ " -- Commands for changing settings:\n" ++ @@ -287,7 +289,8 @@ interactiveUI session srcs maybe_expr = do prelude = prel_mod, break_ctr = 0, breaks = [], - tickarrays = emptyModuleEnv + tickarrays = emptyModuleEnv, + cmdqueue = [] } #ifdef USE_READLINE @@ -446,17 +449,9 @@ fileLoop hdl show_prompt = do Right l -> case removeSpaces l of "" -> fileLoop hdl show_prompt - l -> do quit <- runCommand l + l -> do quit <- runCommands l if quit then return () else fileLoop hdl show_prompt -stringLoop :: [String] -> GHCi Bool{-True: we quit-} -stringLoop [] = return False -stringLoop (s:ss) = do - case removeSpaces s of - "" -> stringLoop ss - l -> do quit <- runCommand l - if quit then return True else stringLoop ss - mkPrompt = do session <- getSession (toplevs,exports) <- io (GHC.getContext session) @@ -514,17 +509,31 @@ readlineLoop = do "" -> readlineLoop l -> do io (addHistory l) - quit <- runCommand l + quit <- runCommands l if quit then return () else readlineLoop #endif -runCommand :: String -> GHCi Bool -runCommand c = ghciHandle handler (doCommand c) - where - doCommand (':' : command) = specialCommand command - doCommand stmt - = do timeIt $ runStmt stmt GHC.RunToCompletion - return False +runCommands :: String -> GHCi Bool +runCommands cmd = do + q <- ghciHandle handler (doCommand cmd) + if q then return True else runNext + where + runNext = do + st <- getGHCiState + case cmdqueue st of + [] -> return False + c:cs -> do setGHCiState st{ cmdqueue = cs } + runCommands c + + doCommand (':' : cmd) = specialCommand cmd + doCommand stmt = do timeIt $ runStmt stmt GHC.RunToCompletion + return False + +enqueueCommands :: [String] -> GHCi () +enqueueCommands cmds = do + st <- getGHCiState + setGHCiState st{ cmdqueue = cmds ++ cmdqueue st } + -- This version is for the GHC command-line option -e. The only difference -- from runCommand is that it catches the ExitException exception and @@ -563,14 +572,15 @@ afterRunStmt run_result = do GHC.RunOk names -> do show_types <- isOptionSet ShowType when show_types $ mapM_ (showTypeOfName session) names - GHC.RunBreak _ names _ -> do + GHC.RunBreak _ names mb_info -> do resumes <- io $ GHC.getResumeContext session printForUser $ ptext SLIT("Stopped at") <+> ppr (GHC.resumeSpan (head resumes)) mapM_ (showTypeOfName session) names + maybe (return ()) runBreakCmd mb_info -- run the command set with ":set stop " st <- getGHCiState - runCommand (stop st) + enqueueCommands [stop st] return () _ -> return () @@ -581,6 +591,17 @@ afterRunStmt run_result = do return (case run_result of GHC.RunOk _ -> True; _ -> False) +runBreakCmd :: GHC.BreakInfo -> GHCi () +runBreakCmd info = do + let mod = GHC.breakInfo_module info + nm = GHC.breakInfo_number info + st <- getGHCiState + case [ loc | (i,loc) <- breaks st, + breakModule loc == mod, breakTick loc == nm ] of + [] -> return () + loc:_ | null cmd -> return () + | otherwise -> do enqueueCommands [cmd]; return () + where cmd = onBreakCmd loc showTypeOfName :: Session -> Name -> GHCi () showTypeOfName session n @@ -674,8 +695,7 @@ pprInfo exts (thing, fixity, insts) runMain :: String -> GHCi () runMain args = do let ss = concat $ intersperse "," (map (\ s -> ('"':s)++"\"") (toArgs args)) - runCommand $ '[': ss ++ "] `System.Environment.withArgs` main" - return () + enqueueCommands ['[': ss ++ "] `System.Environment.withArgs` main"] addModule :: [FilePath] -> GHCi () addModule files = do @@ -748,7 +768,8 @@ defineMacro s = do runMacro :: GHC.HValue{-String -> IO String-} -> String -> GHCi Bool runMacro fun s = do str <- io ((unsafeCoerce# fun :: String -> IO String) s) - stringLoop (lines str) + enqueueCommands (lines str) + return False undefineMacro :: String -> GHCi () undefineMacro macro_name = do @@ -763,6 +784,17 @@ undefineMacro macro_name = do else do io (writeIORef commands (filter ((/= macro_name) . cmdName) cmds)) +cmdCmd :: String -> GHCi () +cmdCmd str = do + let expr = '(' : str ++ ") :: IO String" + session <- getSession + maybe_hv <- io (GHC.compileExpr session expr) + case maybe_hv of + Nothing -> return () + Just hv -> do + cmds <- io $ (unsafeCoerce# hv :: IO String) + enqueueCommands (lines cmds) + return () loadModule :: [(FilePath, Maybe Phase)] -> GHCi SuccessFlag loadModule fs = timeIt (loadModule' fs) @@ -1064,6 +1096,19 @@ setEditor cmd = do st <- getGHCiState setGHCiState st{ editor = cmd } +setStop str@(c:_) | isDigit c + = do let (nm_str,rest) = break (not.isDigit) str + nm = read nm_str + st <- getGHCiState + let old_breaks = breaks st + if all ((/= nm) . fst) old_breaks + then printForUser (text "Breakpoint" <+> ppr nm <+> + text "does not exist") + else do + let new_breaks = map fn old_breaks + fn (i,loc) | i == nm = (i,loc { onBreakCmd = dropWhile isSpace rest }) + | otherwise = (i,loc) + setGHCiState st{ breaks = new_breaks } setStop cmd = do st <- getGHCiState setGHCiState st{ stop = cmd } @@ -1518,8 +1563,7 @@ backCmd = noArgs $ do mapM_ (showTypeOfName s) names -- run the command set with ":set stop " st <- getGHCiState - runCommand (stop st) - return () + enqueueCommands [stop st] forwardCmd :: String -> GHCi () forwardCmd = noArgs $ do @@ -1531,8 +1575,7 @@ forwardCmd = noArgs $ do mapM_ (showTypeOfName s) names -- run the command set with ":set stop " st <- getGHCiState - runCommand (stop st) - return () + enqueueCommands [stop st] -- handle the "break" command breakCmd :: String -> GHCi () @@ -1556,7 +1599,7 @@ breakSwitch session args@(arg1:rest) io $ putStrLn "Perhaps no modules are loaded for debugging?" | otherwise = do -- try parsing it as an identifier wantNameFromInterpretedModule noCanDo arg1 $ \name -> do - let loc = GHC.nameSrcLoc name + let loc = GHC.srcSpanStart (GHC.nameSrcSpan name) if GHC.isGoodSrcLoc loc then findBreakAndSet (GHC.nameModule name) $ findBreakByCoord (Just (GHC.srcLocFile loc)) @@ -1596,6 +1639,7 @@ findBreakAndSet mod lookupTickTree = do { breakModule = mod , breakLoc = span , breakTick = tick + , onBreakCmd = "" } printForUser $ text "Breakpoint " <> ppr nm <> @@ -1633,7 +1677,8 @@ findBreakByCoord :: Maybe FastString -> (Int,Int) -> TickArray findBreakByCoord mb_file (line, col) arr | not (inRange (bounds arr) line) = Nothing | otherwise = - listToMaybe (sortBy rightmost contains) + listToMaybe (sortBy rightmost contains) `mplus` + listToMaybe (sortBy leftmost_smallest after_here) where ticks = arr ! line @@ -1645,6 +1690,10 @@ findBreakByCoord mb_file (line, col) arr | Just f <- mb_file = GHC.srcSpanFile span == f | otherwise = True + after_here = [ tick | tick@(nm,span) <- ticks, + GHC.srcSpanStartLine span == line, + GHC.srcSpanStartCol span >= col ] + leftmost_smallest (_,a) (_,b) = a `compare` b leftmost_largest (_,a) (_,b) = (GHC.srcSpanStart a `compare` GHC.srcSpanStart b) @@ -1656,6 +1705,17 @@ spans :: SrcSpan -> (Int,Int) -> Bool spans span (l,c) = GHC.srcSpanStart span <= loc && loc <= GHC.srcSpanEnd span where loc = GHC.mkSrcLoc (GHC.srcSpanFile span) l c +-- for now, use ANSI bold on Unixy systems. On Windows, we add a line +-- of carets under the active expression instead. The Windows console +-- doesn't support ANSI escape sequences, and most Unix terminals +-- (including xterm) do, so this is a reasonable guess until we have a +-- proper termcap/terminfo library. +#if !defined(mingw32_TARGET_OS) +do_bold = True +#else +do_bold = False +#endif + start_bold = BS.pack "\ESC[1m" end_bold = BS.pack "\ESC[0m" @@ -1664,7 +1724,8 @@ listCmd "" = do mb_span <- getCurrentBreakSpan case mb_span of Nothing -> printForUser $ text "not stopped at a breakpoint; nothing to list" - Just span -> io $ listAround span True + Just span | GHC.isGoodSrcSpan span -> io $ listAround span True + | otherwise -> printForUser $ text "unable to list source for" <+> ppr span listCmd str = list2 (words str) list2 [arg] | all isDigit arg = do @@ -1678,7 +1739,7 @@ list2 [arg1,arg2] | looksLikeModuleName arg1, all isDigit arg2 = do listModuleLine mod (read arg2) list2 [arg] = do wantNameFromInterpretedModule noCanDo arg $ \name -> do - let loc = GHC.nameSrcLoc name + let loc = GHC.srcSpanStart (GHC.nameSrcSpan name) if GHC.isGoodSrcLoc loc then do tickArray <- getTickArray (GHC.nameModule name) @@ -1739,7 +1800,10 @@ listAround span do_highlight = do | otherwise = 1 pad_after = 1 - highlight no line + highlight | do_bold = highlight_bold + | otherwise = highlight_carets + + highlight_bold no line | no == line1 && no == line2 = let (a,r) = BS.splitAt col1 line (b,c) = BS.splitAt (col2-col1) r @@ -1753,6 +1817,20 @@ listAround span do_highlight = do BS.concat [a, end_bold, b] | otherwise = line + highlight_carets no line + | no == line1 && no == line2 + = BS.concat [line, nl, indent, BS.replicate col1 ' ', + BS.replicate (col2-col1) '^'] + | no == line1 + = BS.concat [line, nl, indent, BS.replicate col1 ' ', + BS.replicate (BS.length line-col1) '^'] + | no == line2 + = BS.concat [line, nl, indent, BS.replicate col2 '^'] + | otherwise = line + where + indent = BS.pack " " + nl = BS.singleton '\n' + -- -------------------------------------------------------------------------- -- Tick arrays