FIX #1765, #1766
authorSimon Marlow <simonmar@microsoft.com>
Wed, 7 Nov 2007 11:17:57 +0000 (11:17 +0000)
committerSimon Marlow <simonmar@microsoft.com>
Wed, 7 Nov 2007 11:17:57 +0000 (11:17 +0000)
- :def! now overwrites a previous command with the same name
- :def on its own lists the defined macros
- ":undef f g" undefines both f and g

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

index 045cf63..83b5966 100644 (file)
@@ -103,8 +103,8 @@ type Command = (String, String -> GHCi Bool, Bool, String -> IO [String])
 cmdName :: Command -> String
 cmdName (n,_,_,_) = n
 
 cmdName :: Command -> String
 cmdName (n,_,_,_) = n
 
-commands :: IORef [Command]
-GLOBAL_VAR(commands, builtin_commands, [Command])
+macros_ref :: IORef [Command]
+GLOBAL_VAR(macros_ref, [], [Command])
 
 builtin_commands :: [Command]
 builtin_commands = [
 
 builtin_commands :: [Command]
 builtin_commands = [
@@ -121,7 +121,8 @@ builtin_commands = [
   ("continue",  keepGoing continueCmd,          False, completeNone),
   ("cmd",       keepGoing cmdCmd,               False, completeIdentifier),
   ("ctags",    keepGoing createCTagsFileCmd,   False, completeFilename),
   ("continue",  keepGoing continueCmd,          False, completeNone),
   ("cmd",       keepGoing cmdCmd,               False, completeIdentifier),
   ("ctags",    keepGoing createCTagsFileCmd,   False, completeFilename),
-  ("def",      keepGoing defineMacro,          False, completeIdentifier),
+  ("def",      keepGoing (defineMacro False),  False, completeIdentifier),
+  ("def!",     keepGoing (defineMacro True),   False, completeIdentifier),
   ("delete",    keepGoing deleteCmd,            False, completeNone),
   ("e",        keepGoing editFile,             False, completeFilename),
   ("edit",     keepGoing editFile,             False, completeFilename),
   ("delete",    keepGoing deleteCmd,            False, completeNone),
   ("e",        keepGoing editFile,             False, completeFilename),
   ("edit",     keepGoing editFile,             False, completeFilename),
@@ -699,7 +700,8 @@ specialCommand str = do
 
 lookupCommand :: String -> IO (Maybe Command)
 lookupCommand str = do
 
 lookupCommand :: String -> IO (Maybe Command)
 lookupCommand str = do
-  cmds <- readIORef commands
+  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)
   -- look for exact match first, then the first prefix match
   case [ c | c <- cmds, str == cmdName c ] of
      c:_ -> return (Just c)
@@ -854,18 +856,24 @@ chooseEditFile =
   where fromTarget (GHC.Target (GHC.TargetFile f _) _) = Just f
         fromTarget _ = Nothing -- when would we get a module target?
 
   where fromTarget (GHC.Target (GHC.TargetFile f _) _) = Just f
         fromTarget _ = Nothing -- when would we get a module target?
 
-defineMacro :: String -> GHCi ()
-defineMacro s = do
+defineMacro :: Bool{-overwrite-} -> String -> GHCi ()
+defineMacro overwrite s = do
   let (macro_name, definition) = break isSpace s
   let (macro_name, definition) = break isSpace s
-  cmds <- io (readIORef commands)
+  macros <- io (readIORef macros_ref)
+  let defined = map cmdName macros
   if (null macro_name) 
   if (null macro_name) 
-       then throwDyn (CmdLineError "invalid macro name") 
+       then if null defined
+                then io $ putStrLn "no macros defined"
+                else io $ putStr ("the following macros are defined:\n" ++
+                                  unlines defined)
        else do
        else do
-  if (macro_name `elem` map cmdName cmds)
+  if (not overwrite && macro_name `elem` defined)
        then throwDyn (CmdLineError 
        then throwDyn (CmdLineError 
-               ("command '" ++ macro_name ++ "' is already defined"))
+               ("macro '" ++ macro_name ++ "' is already defined"))
        else do
 
        else do
 
+  let filtered = [ cmd | cmd <- macros, cmdName cmd /= macro_name ]
+
   -- give the expression a type signature, so we can be sure we're getting
   -- something of the right type.
   let new_expr = '(' : definition ++ ") :: String -> IO String"
   -- give the expression a type signature, so we can be sure we're getting
   -- something of the right type.
   let new_expr = '(' : definition ++ ") :: String -> IO String"
@@ -875,8 +883,8 @@ defineMacro s = do
   maybe_hv <- io (GHC.compileExpr cms new_expr)
   case maybe_hv of
      Nothing -> return ()
   maybe_hv <- io (GHC.compileExpr cms new_expr)
   case maybe_hv of
      Nothing -> return ()
-     Just hv -> io (writeIORef commands --
-                   (cmds ++ [(macro_name, runMacro hv, False, completeNone)]))
+     Just hv -> io (writeIORef macros_ref --
+                   (filtered ++ [(macro_name, runMacro hv, False, completeNone)]))
 
 runMacro :: GHC.HValue{-String -> IO String-} -> String -> GHCi Bool
 runMacro fun s = do
 
 runMacro :: GHC.HValue{-String -> IO String-} -> String -> GHCi Bool
 runMacro fun s = do
@@ -885,17 +893,14 @@ runMacro fun s = do
   return False
 
 undefineMacro :: String -> GHCi ()
   return False
 
 undefineMacro :: String -> GHCi ()
-undefineMacro macro_name = do
-  cmds <- io (readIORef commands)
-  if (macro_name `elem` map cmdName builtin_commands) 
-       then throwDyn (CmdLineError
-               ("command '" ++ macro_name ++ "' cannot be undefined"))
-       else do
-  if (macro_name `notElem` map cmdName cmds) 
-       then throwDyn (CmdLineError 
-               ("command '" ++ macro_name ++ "' not defined"))
-       else do
-  io (writeIORef commands (filter ((/= macro_name) . cmdName) cmds))
+undefineMacro str = mapM_ undef (words str) 
+ where undef macro_name = do
+        cmds <- io (readIORef macros_ref)
+        if (macro_name `notElem` map cmdName cmds) 
+          then throwDyn (CmdLineError 
+               ("macro '" ++ macro_name ++ "' is not defined"))
+          else do
+            io (writeIORef macros_ref (filter ((/= macro_name) . cmdName) cmds))
 
 cmdCmd :: String -> GHCi ()
 cmdCmd str = do
 
 cmdCmd :: String -> GHCi ()
 cmdCmd str = do
@@ -1533,13 +1538,13 @@ completeWord w start end = do
 
 completeCmd :: String -> IO [String]
 completeCmd w = do
 
 completeCmd :: String -> IO [String]
 completeCmd w = do
-  cmds <- readIORef commands
-  return (filter (w `isPrefixOf`) (map (':':) (map cmdName cmds)))
+  cmds <- readIORef macros_ref
+  return (filter (w `isPrefixOf`) (map (':':) 
+             (map cmdName (builtin_commands ++ cmds))))
 
 completeMacro w = do
 
 completeMacro w = do
-  cmds <- readIORef commands
-  let cmds' = [ cmd | cmd <- map cmdName cmds, cmd `elem` map cmdName builtin_commands ]
-  return (filter (w `isPrefixOf`) cmds')
+  cmds <- readIORef macros_ref
+  return (filter (w `isPrefixOf`) (map cmdName cmds))
 
 completeIdentifier w = do
   s <- restoreSession
 
 completeIdentifier w = do
   s <- restoreSession
index 28e9972..b092953 100644 (file)
@@ -1817,26 +1817,27 @@ $ ghci -lm
 
       <varlistentry>
        <term>
 
       <varlistentry>
        <term>
-          <literal>:def</literal> <replaceable>name</replaceable> <replaceable>expr</replaceable>
+          <literal>:def<optional>!</optional> <optional><replaceable>name</replaceable> <replaceable>expr</replaceable></optional></literal>
           <indexterm><primary><literal>:def</literal></primary></indexterm>
         </term>
        <listitem>
           <indexterm><primary><literal>:def</literal></primary></indexterm>
         </term>
        <listitem>
-         <para>The command <literal>:def</literal>
-         <replaceable>name</replaceable>
-         <replaceable>expr</replaceable> defines a new GHCi command
-         <literal>:<replaceable>name</replaceable></literal>,
-         implemented by the Haskell expression
-         <replaceable>expr</replaceable>, which must have type
-         <literal>String -> IO String</literal>.  When
-         <literal>:<replaceable>name</replaceable>
-         <replaceable>args</replaceable></literal> is typed at the
-         prompt, GHCi will run the expression
-         <literal>(<replaceable>name</replaceable>
-         <replaceable>args</replaceable>)</literal>, take the
-         resulting <literal>String</literal>, and feed it back into
-         GHCi as a new sequence of commands.  Separate commands in
-         the result must be separated by
-         &lsquo;<literal>\n</literal>&rsquo;.</para>
+          <para><literal>:def</literal> is used to define new
+          commands, or macros, in GHCi.  The command
+          <literal>:def</literal> <replaceable>name</replaceable>
+          <replaceable>expr</replaceable> defines a new GHCi command
+          <literal>:<replaceable>name</replaceable></literal>,
+          implemented by the Haskell expression
+          <replaceable>expr</replaceable>, which must have type
+          <literal>String -> IO String</literal>.  When
+          <literal>:<replaceable>name</replaceable>
+          <replaceable>args</replaceable></literal> is typed at the
+          prompt, GHCi will run the expression
+          <literal>(<replaceable>name</replaceable>
+          <replaceable>args</replaceable>)</literal>, take the
+          resulting <literal>String</literal>, and feed it back into
+          GHCi as a new sequence of commands.  Separate commands in
+          the result must be separated by
+          &lsquo;<literal>\n</literal>&rsquo;.</para>
 
          <para>That's all a little confusing, so here's a few
          examples.  To start with, here's a new GHCi command which
 
          <para>That's all a little confusing, so here's a few
          examples.  To start with, here's a new GHCi command which
@@ -1880,6 +1881,12 @@ Prelude> :. cmds.ghci
           <literal>:.</literal>, by analogy with the
           &lsquo;<literal>.</literal>&rsquo; Unix shell command that
           does the same thing.</para>
           <literal>:.</literal>, by analogy with the
           &lsquo;<literal>.</literal>&rsquo; Unix shell command that
           does the same thing.</para>
+
+          <para>Typing <literal>:def</literal> on its own lists the
+          currently-defined macros.  Attempting to redefine an
+          existing command name results in an error unless the
+          <literal>:def!</literal> form is used, in which case the old
+          command with that name is silently overwritten.</para>
        </listitem>
       </varlistentry>
 
        </listitem>
       </varlistentry>