MERGED: Make ":" in GHCi repeat the last command
authorIan Lynagh <igloo@earth.li>
Sun, 25 Nov 2007 12:20:20 +0000 (12:20 +0000)
committerIan Lynagh <igloo@earth.li>
Sun, 25 Nov 2007 12:20:20 +0000 (12:20 +0000)
Ian Lynagh <igloo@earth.li>**20071124231857
 It used to be a synonym for ":r" in 6.6.1, but this wasn't documented or
 known about by the developers. In 6.8.1 it was accidentally broken.
 This patch brings it back, but as "repeat the last command", similar to
 pressing enter in gdb. This is almost as good for people who want it to
 reload, and means that it can also be used to repeat commands like :step.

compiler/ghci/GhciMonad.hs
compiler/ghci/InteractiveUI.hs
docs/users_guide/ghci.xml

index 2ccde55..4e8e65f 100644 (file)
@@ -46,6 +46,8 @@ import GHC.Exts
 -----------------------------------------------------------------------------
 -- GHCi monad
 
 -----------------------------------------------------------------------------
 -- GHCi monad
 
+type Command = (String, String -> GHCi Bool, Bool, String -> IO [String])
+
 data GHCiState = GHCiState
      { 
        progname       :: String,
 data GHCiState = GHCiState
      { 
        progname       :: String,
@@ -62,6 +64,9 @@ data GHCiState = GHCiState
                 -- tickarrays caches the TickArray for loaded modules,
                 -- so that we don't rebuild it each time the user sets
                 -- a breakpoint.
                 -- tickarrays caches the TickArray for loaded modules,
                 -- so that we don't rebuild it each time the user sets
                 -- a breakpoint.
+        -- ":" at the GHCi prompt repeats the last command, so we
+        -- remember is here:
+        last_command   :: Maybe Command,
         cmdqueue       :: [String],
         remembered_ctx :: Maybe ([Module],[Module])
                 -- modules we want to add to the context, but can't
         cmdqueue       :: [String],
         remembered_ctx :: Maybe ([Module],[Module])
                 -- modules we want to add to the context, but can't
index e5c6813..3ae37f5 100644 (file)
@@ -97,8 +97,6 @@ ghciWelcomeMsg :: String
 ghciWelcomeMsg = "GHCi, version " ++ cProjectVersion ++
                  ": http://www.haskell.org/ghc/  :? for help"
 
 ghciWelcomeMsg = "GHCi, version " ++ cProjectVersion ++
                  ": http://www.haskell.org/ghc/  :? for help"
 
-type Command = (String, String -> GHCi Bool, Bool, String -> IO [String])
-
 cmdName :: Command -> String
 cmdName (n,_,_,_) = n
 
 cmdName :: Command -> String
 cmdName (n,_,_,_) = n
 
@@ -165,6 +163,7 @@ helpText =
  " Commands available from the prompt:\n" ++
  "\n" ++
  "   <statement>                 evaluate/run <statement>\n" ++
  " Commands available from the prompt:\n" ++
  "\n" ++
  "   <statement>                 evaluate/run <statement>\n" ++
+ "   :                           repeat last command\n" ++
  "   :{\\n ..lines.. \\n:}\\n       multiline command\n" ++
  "   :add <filename> ...         add module(s) to the current target set\n" ++
  "   :browse[!] [[*]<mod>]       display the names defined by module <mod>\n" ++
  "   :{\\n ..lines.. \\n:}\\n       multiline command\n" ++
  "   :add <filename> ...         add module(s) to the current target set\n" ++
  "   :browse[!] [[*]<mod>]       display the names defined by module <mod>\n" ++
@@ -314,6 +313,7 @@ interactiveUI session srcs maybe_expr = do
                    break_ctr = 0,
                    breaks = [],
                    tickarrays = emptyModuleEnv,
                    break_ctr = 0,
                    breaks = [],
                    tickarrays = emptyModuleEnv,
+                   last_command = Nothing,
                    cmdqueue = [],
                    remembered_ctx = Nothing
                  }
                    cmdqueue = [],
                    remembered_ctx = Nothing
                  }
@@ -711,29 +711,48 @@ printTypeOfName session n
             Just thing -> printTyThing thing
 
 
             Just thing -> printTyThing thing
 
 
-
+data MaybeCommand = GotCommand Command | BadCommand | NoLastCommand
 
 specialCommand :: String -> GHCi Bool
 specialCommand ('!':str) = shellEscape (dropWhile isSpace str)
 specialCommand str = do
   let (cmd,rest) = break isSpace str
 
 specialCommand :: String -> GHCi Bool
 specialCommand ('!':str) = shellEscape (dropWhile isSpace str)
 specialCommand str = do
   let (cmd,rest) = break isSpace str
-  maybe_cmd <- io (lookupCommand cmd)
+  maybe_cmd <- lookupCommand cmd
   case maybe_cmd of
   case maybe_cmd of
-    Nothing -> io (hPutStr stdout ("unknown command ':" ++ cmd ++ "'\n" 
-                                   ++ shortHelpText) >> return False)
-    Just (_,f,_,_) -> f (dropWhile isSpace rest)
-
-lookupCommand :: String -> IO (Maybe Command)
+    GotCommand (_,f,_,_) -> f (dropWhile isSpace rest)
+    BadCommand ->
+      do io $ hPutStr stdout ("unknown command ':" ++ cmd ++ "'\n"
+                           ++ shortHelpText)
+         return False
+    NoLastCommand ->
+      do io $ hPutStr stdout ("there is no last command to perform\n"
+                           ++ shortHelpText)
+         return False
+
+lookupCommand :: String -> GHCi (MaybeCommand)
+lookupCommand "" = do
+  st <- getGHCiState
+  case last_command st of
+      Just c -> return $ GotCommand c
+      Nothing -> return NoLastCommand
 lookupCommand str = do
 lookupCommand str = do
+  mc <- io $ lookupCommand' str
+  st <- getGHCiState
+  setGHCiState st{ last_command = mc }
+  return $ case mc of
+           Just c -> GotCommand c
+           Nothing -> BadCommand
+
+lookupCommand' :: String -> IO (Maybe Command)
+lookupCommand' str = do
   macros <- readIORef macros_ref
   let cmds = builtin_commands ++ macros
   -- look for exact match first, then the first prefix match
   macros <- readIORef macros_ref
   let cmds = builtin_commands ++ macros
   -- look for exact match first, then the first prefix match
-  case [ c | c <- cmds, str == cmdName c ] of
-     c:_ -> return (Just c)
-     [] -> case [ c | c@(s,_,_,_) <- cmds, str `isPrefixOf` s ] of
-               [] -> return Nothing
-               c:_ -> return (Just c)
-
+  return $ case [ c | c <- cmds, str == cmdName c ] of
+           c:_ -> Just c
+           [] -> case [ c | c@(s,_,_,_) <- cmds, str `isPrefixOf` s ] of
+                 [] -> Nothing
+                 c:_ -> Just c
 
 getCurrentBreakSpan :: GHCi (Maybe SrcSpan)
 getCurrentBreakSpan = do
 
 getCurrentBreakSpan :: GHCi (Maybe SrcSpan)
 getCurrentBreakSpan = do
@@ -1594,7 +1613,7 @@ completeWord w start end = do
      ':':_ | all isSpace (take (start-1) line) -> wrapCompleter completeCmd w
      _other
        | ((':':c) : _) <- line_words -> do
      ':':_ | all isSpace (take (start-1) line) -> wrapCompleter completeCmd w
      _other
        | ((':':c) : _) <- line_words -> do
-          maybe_cmd <- lookupCommand c
+          maybe_cmd <- lookupCommand' c
            let (n,w') = selectWord (words' 0 line)
           case maybe_cmd of
             Nothing -> return Nothing
            let (n,w') = selectWord (words' 0 line)
           case maybe_cmd of
             Nothing -> return Nothing
index 98496d7..528a652 100644 (file)
@@ -1991,6 +1991,17 @@ Prelude> :. cmds.ghci
       </varlistentry>
 
       <varlistentry>
       </varlistentry>
 
       <varlistentry>
+       <term>
+          <literal>:</literal>
+          <indexterm><primary><literal>:</literal></primary></indexterm>
+        </term>
+       <listitem>
+         <para>Repeat the previous command.</para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+
        <term>
           <literal>:history [<replaceable>num</replaceable>]</literal>
           <indexterm><primary><literal>:history</literal></primary></indexterm>
        <term>
           <literal>:history [<replaceable>num</replaceable>]</literal>
           <indexterm><primary><literal>:history</literal></primary></indexterm>