(ibuffer-accumulate-lines): Moved to replace.el.
[bpt/emacs.git] / lisp / macros.el
index 4cd6a34..0857dd3 100644 (file)
@@ -1,12 +1,15 @@
-;;; macros.el --- non-primitive commands for keyboard macros.
+;;; macros.el --- non-primitive commands for keyboard macros
 
-;; Copyright (C) 1985, 1986, 1987 Free Software Foundation, Inc.
+;; Copyright (C) 1985, 86, 87, 92, 94, 95 Free Software Foundation, Inc.
+
+;; Maintainer: FSF
+;; Keywords: abbrev
 
 ;; This file is part of GNU Emacs.
 
 ;; GNU Emacs is free software; you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 1, or (at your option)
+;; the Free Software Foundation; either version 2, or (at your option)
 ;; any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
 ;; GNU General Public License for more details.
 
 ;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING.  If not, write to
-;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;; Extension commands for keyboard macros.  These permit you to assign
+;; a name to the last-defined keyboard macro, expand and insert the
+;; lisp corresponding to a macro, query the user from within a macro,
+;; or apply a macro to each line in the reason.
 
+;;; Code:
 
 ;;;###autoload
 (defun name-last-kbd-macro (symbol)
@@ -30,15 +42,18 @@ Such a \"function\" cannot be called from Lisp, but it is a valid editor command
       (error "No keyboard macro defined"))
   (and (fboundp symbol)
        (not (stringp (symbol-function symbol)))
-       (error "Function %s is already defined and not a keyboard macro."
+       (not (vectorp (symbol-function symbol)))
+       (error "Function %s is already defined and not a keyboard macro"
              symbol))
+  (if (string-equal symbol "")
+      (error "No command name given"))
   (fset symbol last-kbd-macro))
 
 ;;;###autoload
 (defun insert-kbd-macro (macroname &optional keys)
   "Insert in buffer the definition of kbd macro NAME, as Lisp code.
 Optional second arg KEYS means also record the keys it is on
-(this is the prefix argument, when calling interactively).
+\(this is the prefix argument, when calling interactively).
 
 This Lisp code will, when executed, define the kbd macro with the same
 definition it has now.  If you say to record the keys, the Lisp code
@@ -46,23 +61,114 @@ will also rebind those keys to the macro.  Only global key bindings
 are recorded since executing this Lisp code always makes global
 bindings.
 
-To save a kbd macro, visit a file of Lisp code such as your ~/.emacs,
+To save a kbd macro, visit a file of Lisp code such as your `~/.emacs',
 use this command, and then save the file."
   (interactive "CInsert kbd macro (name): \nP")
-  (insert "(fset '")
-  (prin1 macroname (current-buffer))
-  (insert "\n   ")
-  (prin1 (symbol-function macroname) (current-buffer))
-  (insert ")\n")
-  (if keys
-      (let ((keys (where-is-internal macroname nil)))
-       (while keys
-         (insert "(global-set-key ")
-         (prin1 (car keys) (current-buffer))
-         (insert " '")
-         (prin1 macroname (current-buffer))
-         (insert ")\n")
-         (setq keys (cdr keys))))))
+  (let (definition)
+    (if (string= (symbol-name macroname) "")
+       (progn
+         (setq macroname 'last-kbd-macro definition last-kbd-macro)
+         (insert "(setq "))
+      (setq definition (symbol-function macroname))
+      (insert "(fset '"))
+    (prin1 macroname (current-buffer))
+    (insert "\n   ")
+    (if (stringp definition)
+       (let ((beg (point)) end)
+         (prin1 definition (current-buffer))
+         (setq end (point-marker))
+         (goto-char beg)
+         (while (< (point) end)
+           (let ((char (following-char)))
+             (cond ((= char 0)
+                    (delete-region (point) (1+ (point)))
+                    (insert "\\C-@"))
+                   ((< char 27)
+                    (delete-region (point) (1+ (point)))
+                    (insert "\\C-" (+ 96 char)))
+                   ((= char ?\C-\\)
+                    (delete-region (point) (1+ (point)))
+                    (insert "\\C-\\\\"))
+                   ((< char 32)
+                    (delete-region (point) (1+ (point)))
+                    (insert "\\C-" (+ 64 char)))
+                   ((< char 127)
+                    (forward-char 1))
+                   ((= char 127)
+                    (delete-region (point) (1+ (point)))
+                    (insert "\\C-?"))
+                   ((= char 128)
+                    (delete-region (point) (1+ (point)))
+                    (insert "\\M-\\C-@"))
+                   ((= char (aref "\M-\C-\\" 0))
+                    (delete-region (point) (1+ (point)))
+                    (insert "\\M-\\C-\\\\"))
+                   ((< char 155)
+                    (delete-region (point) (1+ (point)))
+                    (insert "\\M-\\C-" (- char 32)))
+                   ((< char 160)
+                    (delete-region (point) (1+ (point)))
+                    (insert "\\M-\\C-" (- char 64)))
+                   ((= char (aref "\M-\\" 0))
+                    (delete-region (point) (1+ (point)))
+                    (insert "\\M-\\\\"))
+                   ((< char 255)
+                    (delete-region (point) (1+ (point)))
+                    (insert "\\M-" (- char 128)))
+                   ((= char 255)
+                    (delete-region (point) (1+ (point)))
+                    (insert "\\M-\\C-?"))))))
+      (if (vectorp definition)
+         (let ((len (length definition)) (i 0) char mods)
+           (while (< i len)
+             (insert (if (zerop i) ?\[ ?\ ))
+             (setq char (aref definition i)
+                   i (1+ i))
+             (cond ((not (numberp char))
+                    (prin1 char (current-buffer)))
+                   (t
+                    (insert "?")
+                    (setq mods (event-modifiers char)
+                          char (event-basic-type char))
+                    (while mods
+                      (cond ((eq (car mods) 'control)
+                             (insert "\\C-"))
+                            ((eq (car mods) 'meta)
+                             (insert "\\M-"))
+                            ((eq (car mods) 'hyper)
+                             (insert "\\H-"))
+                            ((eq (car mods) 'super)
+                             (insert "\\s-"))
+                            ((eq (car mods) 'alt)
+                             (insert "\\A-"))
+                            ((and (eq (car mods) 'shift)
+                                  (>= char ?a)
+                                  (<= char ?z))
+                             (setq char (upcase char)))
+                            ((eq (car mods) 'shift)
+                             (insert "\\S-")))
+                      (setq mods (cdr mods)))
+                    (cond ((= char ?\\)
+                           (insert "\\\\"))
+                          ((= char ?\;)
+                           (insert "\\;"))
+                          ((= char 127)
+                           (insert "\\C-?"))
+                          ((< char 127)
+                           (insert char))
+                          (t (insert "\\" (format "%o" char)))))))
+           (insert ?\]))
+       (prin1 definition (current-buffer))))
+    (insert ")\n")
+    (if keys
+       (let ((keys (where-is-internal macroname '(keymap))))
+         (while keys
+           (insert "(global-set-key ")
+           (prin1 (car keys) (current-buffer))
+           (insert " '")
+           (prin1 macroname (current-buffer))
+           (insert ")\n")
+           (setq keys (cdr keys)))))))
 
 ;;;###autoload
 (defun kbd-macro-query (flag)
@@ -70,40 +176,65 @@ use this command, and then save the file."
   With prefix argument, enters recursive edit, reading keyboard
 commands even within a kbd macro.  You can give different commands
 each time the macro executes.
-  Without prefix argument, reads a character.  Your options are:
-Space -- execute the rest of the macro.
-DEL -- skip the rest of the macro; start next repetition.
-C-d -- skip rest of the macro and don't repeat it any more.
-C-r -- enter a recursive edit, then on exit ask again for a character
-C-l -- redisplay screen and ask again."
+  Without prefix argument, asks whether to continue running the macro.
+Your options are: \\<query-replace-map>
+\\[act]        Finish this iteration normally and continue with the next.
+\\[skip]       Skip the rest of this iteration, and start the next.
+\\[exit]       Stop the macro entirely right now.
+\\[recenter]   Redisplay the screen, then ask again.
+\\[edit]       Enter recursive edit; ask again when you exit from that."
   (interactive "P")
-  (or executing-macro
+  (or executing-kbd-macro
       defining-kbd-macro
       (error "Not defining or executing kbd macro"))
   (if flag
-      (let (executing-macro defining-kbd-macro)
+      (let (executing-kbd-macro defining-kbd-macro)
        (recursive-edit))
-    (if (not executing-macro)
+    (if (not executing-kbd-macro)
        nil
-      (let ((loop t))
+      (let ((loop t)
+           (msg (substitute-command-keys
+                 "Proceed with macro?\\<query-replace-map>\
+ (\\[act], \\[skip], \\[exit], \\[recenter], \\[edit]) ")))
        (while loop
-         (let ((char (let ((executing-macro nil)
-                           (defining-kbd-macro nil))
-                       (message "Proceed with macro? (Space, DEL, C-d, C-r or C-l) ")
-                       (read-char))))
-           (cond ((= char ? )
+         (let ((key (let ((executing-kbd-macro nil)
+                          (defining-kbd-macro nil))
+                      (message "%s" msg)
+                      (read-event)))
+               def)
+           (setq key (vector key))
+           (setq def (lookup-key query-replace-map key))
+           (cond ((eq def 'act)
                   (setq loop nil))
-                 ((= char ?\177)
+                 ((eq def 'skip)
                   (setq loop nil)
-                  (setq executing-macro ""))
-                 ((= char ?\C-d)
+                  (setq executing-kbd-macro ""))
+                 ((eq def 'exit)
                   (setq loop nil)
-                  (setq executing-macro t))
-                 ((= char ?\C-l)
+                  (setq executing-kbd-macro t))
+                 ((eq def 'recenter)
                   (recenter nil))
-                 ((= char ?\C-r)
-                  (let (executing-macro defining-kbd-macro)
-                    (recursive-edit))))))))))
+                 ((eq def 'edit)
+                  (let (executing-kbd-macro defining-kbd-macro)
+                    (recursive-edit)))
+                 ((eq def 'quit)
+                  (setq quit-flag t))
+                 (t
+                  (or (eq def 'help)
+                      (ding))
+                  (with-output-to-temp-buffer "*Help*"
+                    (princ
+                     (substitute-command-keys
+                      "Specify how to proceed with keyboard macro execution.
+Possibilities: \\<query-replace-map>
+\\[act]        Finish this iteration normally and continue with the next.
+\\[skip]       Skip the rest of this iteration, and start the next.
+\\[exit]       Stop the macro entirely right now.
+\\[recenter]   Redisplay the screen, then ask again.
+\\[edit]       Enter recursive edit; ask again when you exit from that."))
+                    (save-excursion
+                      (set-buffer standard-output)
+                      (help-mode)))))))))))
 
 ;;;###autoload
 (defun apply-macro-to-region-lines (top bottom &optional macro)
@@ -150,7 +281,7 @@ and then select the region of un-tablified names and use
   (or macro
       (progn
        (if (null last-kbd-macro)
-           (error "No keyboard macro has been defined."))
+           (error "No keyboard macro has been defined"))
        (setq macro last-kbd-macro)))
   (save-excursion
     (let ((end-marker (progn
@@ -172,7 +303,8 @@ and then select the region of un-tablified names and use
       (set-marker end-marker nil)
       (set-marker next-line-marker nil))))
 
-;;;###autoload
-(define-key ctl-x-map "q" 'kbd-macro-query)
+;;;###autoload (define-key ctl-x-map "q" 'kbd-macro-query)
+
+(provide 'macros)
 
 ;;; macros.el ends here