(c-require-final-newline): Added a variable to make the initialization of
[bpt/emacs.git] / lisp / kmacro.el
index b44f4f7..4b890f2 100644 (file)
 ;; type to be really useful for doing small repeated tasks.
 
 ;; With kmacro, two function keys are dedicated to keyboard macros,
-;; by default F7 and F8.  Personally, I prefer F1 and F2, but those
+;; by default F3 and F4.  Personally, I prefer F1 and F2, but those
 ;; keys already have default bindings.
 ;;
-;; To start defining a keyboard macro, use F7.  To end the macro,
-;; use F8, and to call the macro also use F8.  This makes it very
+;; To start defining a keyboard macro, use F3.  To end the macro,
+;; use F4, and to call the macro also use F4.  This makes it very
 ;; easy to repeat a macro immediately after defining it.
 ;;
-;; You can call the macro repeatedly by pressing F8 multiple times, or
+;; You can call the macro repeatedly by pressing F4 multiple times, or
 ;; you can give a numeric prefix argument specifying the number of
 ;; times to repeat the macro.  Macro execution automatically
 ;; terminates when point reaches the end of the buffer or if an error
 ;; is signalled by ringing the bell.
 
-;; When you define a macro with F7/F8, it is automatically added to
-;; the head of the "keyboard macro ring", and F8 actually executes the
+;; When you define a macro with F3/F4, it is automatically added to
+;; the head of the "keyboard macro ring", and F4 actually executes the
 ;; first element of the macro ring.
 ;;
 ;; Note: an empty macro is never added to the macro ring.
 ;;
-;; You can execute the second element on the macro ring with C-u F8 or
+;; You can execute the second element on the macro ring with C-u F4 or
 ;; C-x C-k C-l, you can use C-x C-k C-p and C-x C-k C-n to cycle
 ;; through the macro ring, and you can swap the first and second
 ;; elements with C-x C-k C-t.  To delete the first element in the
 ;; the head macro with C-d, or edit the current macro with C-e without
 ;; repeating the C-x C-k prefix.
 
-;; If you enter F7 while defining the macro, the numeric value of
+;; If you enter F3 while defining the macro, the numeric value of
 ;; `kmacro-counter' is inserted using the `kmacro-counter-format', and
 ;; `kmacro-counter' is incremented by 1 (or the numeric prefix value
-;; of F7).
+;; of F3).
 ;;
 ;; The initial value of `kmacro-counter' is 0, or the numeric prefix
-;; value given to F7 when starting the macro.
+;; value given to F3 when starting the macro.
 ;;
-;; Now, each time you call the macro using F8, the current
+;; Now, each time you call the macro using F4, the current
 ;; value of `kmacro-counter' is inserted and incremented, making it
 ;; easy to insert incremental numbers in the buffer.
 ;;
 ;; Example:
 ;;
-;; The following sequence: M-5 F7 x M-2 F7 y F8 F8 F8 F8
+;; The following sequence: M-5 F3 x M-2 F3 y F4 F4 F4 F4
 ;; inserts the following string:  x5yx7yx9yx11y
 
 ;; A macro can also be called using a mouse click, default S-mouse-3.
@@ -88,7 +88,7 @@
 
 ;; You can edit the last macro using C-x C-k C-e.
 
-;; You can append to the last macro using C-u F7.
+;; You can append to the last macro using C-u F3.
 
 ;; You can set the macro counter using C-x C-k C-c, add to it using C-x C-k C-a,
 ;; and you can set the macro counter format with C-x C-k C-f.
 ;; 
 ;;           Normal                         While defining macro
 ;;           ---------------------------    ------------------------------
-;;  f7       Define macro                   Insert current counter value
+;;  f3       Define macro                   Insert current counter value
 ;;           Prefix arg specifies initial   and increase counter by prefix
 ;;           counter value (default 0)      (default increment: 1)
 ;;
-;;  C-u f7   APPENDs to last macro
+;;  C-u f3   APPENDs to last macro
 ;; 
-;;  f8       Call last macro                End macro 
+;;  f4       Call last macro                End macro 
 ;;           Prefix arg specifies number
 ;;           of times to execute macro.
 ;;
-;;  C-u f8   Swap last and head of macro ring.
+;;  C-u f4   Swap last and head of macro ring.
 ;; 
 ;;  S-mouse-3  Set point at click and       End macro and execute macro at
 ;;             execute last macro.          click.
@@ -152,27 +152,45 @@ macro to be executed before appending to it."
   :type 'boolean
   :group 'kmacro)
 
+(defcustom kmacro-call-repeat-key t
+  "Allow repeating macro call using last key or a specific key."
+  :type '(choice (const :tag "Disabled" nil)
+                (const :tag "Last key" t)
+                (character :tag "Character" :value ?e)
+                (symbol :tag "Key symbol" :value RET))
+  :group 'kmacro)
+
+(defcustom kmacro-call-repeat-with-arg nil
+  "Repeat macro call with original arg when non-nil; repeat once if nil."
+  :type 'boolean
+  :group 'kmacro)
+
+(defcustom kmacro-step-edit-mini-window-height 0.75
+  "Override `max-mini-window-height' when step edit keyboard macro."
+  :type 'number
+  :group 'kmacro)
 
 ;; Keymap
 
 (defvar kmacro-keymap
   (let ((map (make-sparse-keymap)))
-    (define-key map "\C-s" 'kmacro-start-macro)
-    (define-key map "\C-k" 'kmacro-end-or-call-macro-rep)
-    (define-key map "\C-e" 'kmacro-edit-macro)
-    (define-key map "\r"   'kmacro-edit-macro-nr)
+    (define-key map "s"    'kmacro-start-macro)
+    (define-key map "\C-k" 'kmacro-end-or-call-macro-repeat)
+    (define-key map "\C-e" 'kmacro-edit-macro-repeat)
+    (define-key map "\r"   'kmacro-edit-macro)
+    (define-key map " "    'kmacro-step-edit-macro)
     (define-key map "l"    'kmacro-edit-lossage)
     (define-key map "\C-i" 'kmacro-insert-counter)
     (define-key map "\C-a" 'kmacro-add-counter)
-    (define-key map "\C-v" 'kmacro-view-macro-rep)
-    (define-key map "\C-l" 'kmacro-call-ring-2nd-rep)
+    (define-key map "\C-v" 'kmacro-view-macro-repeat)
+    (define-key map "\C-l" 'kmacro-call-ring-2nd-repeat)
     (define-key map "\C-r" 'kmacro-view-ring-2nd)
     (define-key map "\C-n" 'kmacro-cycle-ring-next)
     (define-key map "\C-p" 'kmacro-cycle-ring-previous)
     (define-key map "\C-f" 'kmacro-set-format)
     (define-key map "\C-c" 'kmacro-set-counter)
     (define-key map "\C-t" 'kmacro-swap-ring)
-    (define-key map "\C-b" 'kmacro-bind-to-key)
+    (define-key map "b"    'kmacro-bind-to-key)
     (define-key map "\C-d" 'kmacro-delete-ring-head)
     ;; Compatibility bindings
     (define-key map "q"    'kbd-macro-query)
@@ -186,9 +204,9 @@ macro to be executed before appending to it."
 ;;; Provide some binding for startup:
 ;;;###autoload (global-set-key "\C-x(" 'kmacro-start-macro)
 ;;;###autoload (global-set-key "\C-x)" 'kmacro-end-macro)
-;;;###autoload (global-set-key "\C-xe" 'kmacro-call-macro)
-;;;###autoload (global-set-key [f7] 'kmacro-start-macro-or-insert-counter)
-;;;###autoload (global-set-key [f8] 'kmacro-end-or-call-macro)
+;;;###autoload (global-set-key "\C-xe" 'kmacro-end-and-call-macro)
+;;;###autoload (global-set-key [f3] 'kmacro-start-macro-or-insert-counter)
+;;;###autoload (global-set-key [f4] 'kmacro-end-or-call-macro)
 ;;;###autoload (global-set-key "\C-x\C-k" 'kmacro-keymap)
 ;;;###autoload (autoload 'kmacro-keymap "kmacro" "Keymap for keyboard macro commands." t 'keymap)
 
@@ -355,6 +373,43 @@ Check only `last-kbd-macro' if optional arg NONE is non-nil."
     (message (or empty "No keyboard macros defined"))))
 
 
+(defun kmacro-repeat-on-last-key (keys)
+  "Process kmacro commands keys immidiately after cycling the ring."
+  (setq keys (vconcat keys))
+  (let ((n (1- (length keys)))
+       cmd done repeat)
+    (while (and last-kbd-macro
+               (not done)
+               (aset keys n (read-event))
+               (setq cmd (key-binding keys t))
+               (setq repeat (get cmd 'kmacro-repeat)))
+      (clear-this-command-keys t)
+      (cond
+       ((eq repeat 'ring)
+       (if kmacro-ring
+           (let ((kmacro-repeat-no-prefix nil))
+             (funcall cmd nil))
+         (kmacro-display last-kbd-macro t)))
+       ((eq repeat 'head)
+       (let ((kmacro-repeat-no-prefix nil))
+         (funcall cmd nil)))
+       ((eq repeat 'stop)
+       (funcall cmd nil)
+       (setq done t)))
+      (setq last-input-event nil)))
+  (when last-input-event
+    (clear-this-command-keys t)
+    (setq unread-command-events (list last-input-event))))
+
+
+(defun kmacro-get-repeat-prefix ()
+  (let (keys)
+    (and kmacro-repeat-no-prefix
+        (setq keys (this-single-command-keys))
+        (> (length keys) 1)
+        keys)))
+
+
 (defun kmacro-call-ring-2nd (arg)
   "Execute second keyboard macro at in macro ring."
   (interactive "P")
@@ -366,14 +421,15 @@ Check only `last-kbd-macro' if optional arg NONE is non-nil."
       (setcar (cdr (car kmacro-ring)) kmacro-counter))))
 
 
-(defun kmacro-call-ring-2nd-rep (arg)
-  "Like `kmacro-call-ring-2nd', but allow repeat without kmacro prefix."
+(defun kmacro-call-ring-2nd-repeat (arg)
+  "Like `kmacro-call-ring-2nd', but allow repeat without repeating prefix."
   (interactive "P")
-  (kmacro-call-ring-2nd arg)
-  (if kmacro-ring
-      (kmacro-repeat-loop)))
+  (let ((keys (kmacro-get-repeat-prefix)))
+    (kmacro-call-ring-2nd arg)
+    (if (and kmacro-ring keys)
+       (kmacro-repeat-on-last-key keys))))
 
-(put 'kmacro-call-ring-2nd-rep 'kmacro-repeat 'head)
+(put 'kmacro-call-ring-2nd-repeat 'kmacro-repeat 'head)
 
 
 (defun kmacro-view-ring-2nd ()
@@ -383,31 +439,6 @@ Check only `last-kbd-macro' if optional arg NONE is non-nil."
     (kmacro-display (car (car kmacro-ring)) "2nd macro")))
 
 
-(defun kmacro-repeat-loop ()
-  "Process kmacro commands keys immidiately after cycling the ring."
-  (when kmacro-repeat-no-prefix
-    (let (cmd done repeat)
-      (while (and last-kbd-macro
-                 (not done)
-                 (setq cmd (lookup-key kmacro-keymap (vector (read-event))))
-                 (setq repeat (get cmd 'kmacro-repeat)))
-       (clear-this-command-keys t)
-       (cond
-        ((eq repeat 'ring)
-         (if kmacro-ring
-             (let ((kmacro-repeat-no-prefix nil))
-               (funcall cmd nil))
-           (kmacro-display last-kbd-macro t)))
-        ((eq repeat 'head)
-         (funcall cmd nil))
-        ((eq repeat 'stop)
-         (funcall cmd nil)
-         (setq done t)))
-       (setq last-input-event nil)))
-    (when last-input-event
-      (clear-this-command-keys t)
-      (setq unread-command-events (list last-input-event)))))
-
   
 (defun kmacro-cycle-ring-next (&optional arg)
   "Move to next keyboard macro in keyboard macro ring.
@@ -415,13 +446,15 @@ Displays the selected macro in the echo area."
   (interactive)
   (unless (kmacro-ring-empty-p)
     (kmacro-push-ring)
-    (let* ((len (length kmacro-ring))
+    (let* ((keys (kmacro-get-repeat-prefix))
+          (len (length kmacro-ring))
           (tail (nthcdr (- len 2) kmacro-ring))
           (elt (car (cdr tail))))
       (setcdr tail nil)
-      (kmacro-split-ring-element elt))
-    (kmacro-display last-kbd-macro t)
-    (kmacro-repeat-loop)))
+      (kmacro-split-ring-element elt)
+      (kmacro-display last-kbd-macro t)
+      (if keys
+         (kmacro-repeat-on-last-key keys)))))
 
 (put 'kmacro-cycle-ring-next 'kmacro-repeat 'ring)
 
@@ -431,13 +464,15 @@ Displays the selected macro in the echo area."
 Displays the selected macro in the echo area."
   (interactive)
   (unless (kmacro-ring-empty-p)
-    (let ((cur (kmacro-ring-head)))
+    (let ((keys (kmacro-get-repeat-prefix))
+         (cur (kmacro-ring-head)))
       (kmacro-pop-ring1)
       (if kmacro-ring
          (nconc kmacro-ring (list cur))
-       (setq kmacro-ring (list cur))))
-    (kmacro-display last-kbd-macro t)
-    (kmacro-repeat-loop)))
+       (setq kmacro-ring (list cur)))
+      (kmacro-display last-kbd-macro t)
+      (if keys
+         (kmacro-repeat-on-last-key keys)))))
 
 (put 'kmacro-cycle-ring-previous 'kmacro-repeat 'ring)
 
@@ -471,7 +506,7 @@ Displays the selected macro in the echo area."
   "Record subsequent keyboard input, defining a keyboard macro.
 The commands are recorded even as they are executed.
 Use \\[kmacro-end-macro] to finish recording and make the macro available.
-Use \\[call-last-kbd-macro] to execute the macro.
+Use \\[kmacro-end-and-call-macro] to execute the macro.
 Use \\[name-last-kbd-macro] to give it a permanent name.
 Non-nil arg (prefix arg) means append to last macro defined;
 
@@ -529,28 +564,67 @@ An argument of zero means repeat until error."
 
 
 ;;;###autoload
-(defun kmacro-call-macro (arg)
+(defun kmacro-call-macro (arg &optional no-repeat end-macro)
   "Call the last keyboard macro that you defined with \\[kmacro-start-macro].
-
 A prefix argument serves as a repeat count.  Zero means repeat until error.
 
-To make a macro permanent so you can call it even after
-defining others, use M-x name-last-kbd-macro."
-  (interactive "p")
-  (call-last-kbd-macro arg #'kmacro-loop-setup-function))
+When you call the macro, you can call the macro again by repeating
+just the last key in the key sequence that you used to call this
+command.  See `kmacro-call-repeat-key' and `kmacro-call-repeat-with-arg'
+for details on how to adjust or disable this behaviour.
 
+To make a macro permanent so you can call it even after defining
+others, use M-x name-last-kbd-macro."
+  (interactive "p")
+  (let ((repeat-key (and (null no-repeat)
+                        (> (length (this-single-command-keys)) 1)
+                        last-input-event))
+       repeat-key-str)
+    (if end-macro
+       (kmacro-end-macro arg)
+      (call-last-kbd-macro arg #'kmacro-loop-setup-function))
+    (when (consp arg)
+      (setq arg (car arg)))
+    (when (and (or (null arg) (> arg 0))
+              (setq repeat-key
+                    (if (eq kmacro-call-repeat-key t)
+                        repeat-key
+                      kmacro-call-repeat-key)))
+      (setq repeat-key-str (format-kbd-macro (vector repeat-key) nil))
+      (while repeat-key
+       (message "(Type %s to repeat macro%s)" 
+                repeat-key-str
+                (if (and kmacro-call-repeat-with-arg
+                         arg (> arg 1))
+                    (format " %d times" arg) ""))
+       (if (equal repeat-key (read-event))
+           (progn
+             (clear-this-command-keys t)
+             (call-last-kbd-macro (and kmacro-call-repeat-with-arg arg)
+                                  #'kmacro-loop-setup-function)
+             (setq last-input-event nil))
+         (setq repeat-key nil)))
+      (when last-input-event
+       (clear-this-command-keys t)
+       (setq unread-command-events (list last-input-event))))))
 
 
 ;;; Combined function key bindings:
 
 ;;;###autoload
 (defun kmacro-start-macro-or-insert-counter (arg)
-  "Set `kmacro-counter' to ARG or 0 if missing, and `start-kbd-macro'.
-With \\[universal-argument], append to current keyboard macro (keep kmacro-counter).
+  "Record subsequent keyboard input, defining a keyboard macro.
+The commands are recorded even as they are executed.
+
+Sets the `kmacro-counter' to ARG (or 0 if no prefix arg) before defining the
+macro.
 
-When defining/executing macro, insert macro counter and increment with 
-ARG or 1 if missing.
-With \\[universal-argument], insert previous kmacro-counter (but do not modify counter).
+With \\[universal-argument], appends to current keyboard macro (keeping
+the current value of `kmacro-counter').
+
+When defining/executing macro, inserts macro counter and increments
+the counter with ARG or 1 if missing.  With \\[universal-argument],
+inserts previous kmacro-counter (but do not modify counter).
 
 The macro counter can be modified via \\[kmacro-set-counter] and \\[kmacro-add-counter].
 The format of the counter can be modified via \\[kmacro-set-format]."
@@ -561,27 +635,41 @@ The format of the counter can be modified via \\[kmacro-set-format]."
 
 
 ;;;###autoload
-(defun kmacro-end-or-call-macro (arg)
+(defun kmacro-end-or-call-macro (arg &optional no-repeat)
   "End kbd macro if currently being defined; else call last kbd macro.
 With numeric prefix ARG, repeat macro that many times.
 With \\[universal-argument], call second macro in macro ring."
   (interactive "P")
   (cond 
    (defining-kbd-macro
-     (kmacro-end-macro arg))
+     (if kmacro-call-repeat-key
+        (kmacro-call-macro arg no-repeat t)
+       (kmacro-end-macro arg)))
    ((and arg (listp arg))
     (kmacro-call-ring-2nd 1))
    (t
-    (kmacro-call-macro arg))))
+    (kmacro-call-macro arg no-repeat))))
 
 
-(defun kmacro-end-or-call-macro-rep (arg)
-  "As `kmacro-end-or-call-macro' but allows repeat without kmacro prefix."
+(defun kmacro-end-or-call-macro-repeat (arg)
+  "As `kmacro-end-or-call-macro' but allows repeat without repeating prefix."
   (interactive "P")
-  (kmacro-end-or-call-macro arg)
-  (kmacro-repeat-loop))
+  (let ((keys (kmacro-get-repeat-prefix)))
+    (kmacro-end-or-call-macro arg t)
+    (if keys
+       (kmacro-repeat-on-last-key keys))))
 
-(put 'kmacro-end-or-call-macro-rep 'kmacro-repeat 'head)
+(put 'kmacro-end-or-call-macro-repeat 'kmacro-repeat 'head)
+
+
+;;;###autoload
+(defun kmacro-end-and-call-macro (arg &optional no-repeat)
+  "Call last keyboard macro, ending it first if currently being defined.
+With numeric prefix ARG, repeat macro that many times."
+  (interactive "P")
+  (if defining-kbd-macro
+      (kmacro-end-macro nil))
+  (kmacro-call-macro arg no-repeat))
 
 
 ;;;###autoload
@@ -592,7 +680,7 @@ If kbd macro currently being defined end it before activating it."
   (when defining-kbd-macro
     (end-kbd-macro))
   (mouse-set-point event)
-  (kmacro-call-macro nil))
+  (kmacro-call-macro nil t))
 
 
 ;;; Misc. commands
@@ -616,27 +704,29 @@ If kbd macro currently being defined end it before activating it."
   (kmacro-display last-kbd-macro))
 
 
-(defun kmacro-view-macro-rep (&optional arg)
-  "Like `kmacro-view-macro', but allow repeat without kmacro prefix."
+(defun kmacro-view-macro-repeat (&optional arg)
+  "Like `kmacro-view-macro', but allow repeat without repeating prefix."
   (interactive)
-  (kmacro-view-macro arg)
-  (if last-kbd-macro
-      (kmacro-repeat-loop)))
+  (let ((keys (kmacro-get-repeat-prefix)))
+    (kmacro-view-macro arg)
+    (if (and last-kbd-macro keys)
+       (kmacro-repeat-on-last-key keys))))
 
-(put 'kmacro-view-macro-rep 'kmacro-repeat 'head)
+(put 'kmacro-view-macro-repeat 'kmacro-repeat 'head)
 
-(defun kmacro-edit-macro (&optional arg)
+
+(defun kmacro-edit-macro-repeat (&optional arg)
   "Edit last keyboard macro."
   (interactive "P")
   (edit-kbd-macro "\r" arg))
 
-(put 'kmacro-edit-macro 'kmacro-repeat 'stop)
+(put 'kmacro-edit-macro-repeat 'kmacro-repeat 'stop)
 
 
-(defun kmacro-edit-macro-nr (&optional arg)
+(defun kmacro-edit-macro (&optional arg)
   "As edit last keyboard macro, but without kmacro-repeat property."
   (interactive "P")
-  (kmacro-edit-macro arg))
+  (edit-kbd-macro "\r" arg))
 
 
 (defun kmacro-edit-lossage ()
@@ -646,5 +736,368 @@ If kbd macro currently being defined end it before activating it."
   (edit-kbd-macro "\C-hl"))
 
 
+;;; Single-step editing of keyboard macros
+
+(defvar kmacro-step-edit-active)        ;; step-editing active
+(defvar kmacro-step-edit-new-macro)     ;; storage for new macro
+(defvar kmacro-step-edit-inserting)     ;; inserting into macro
+(defvar kmacro-step-edit-appending)     ;; append to end of macro
+(defvar kmacro-step-edit-replace)       ;; replace orig macro when done
+(defvar kmacro-step-edit-prefix-index)   ;; index of first prefix arg key
+(defvar kmacro-step-edit-key-index)      ;; index of current key
+(defvar kmacro-step-edit-action)        ;; automatic action on next pre-command hook
+(defvar kmacro-step-edit-help)          ;; kmacro step edit help enabled
+(defvar kmacro-step-edit-num-input-keys) ;; to ignore duplicate pre-command hook
+
+(defvar kmacro-step-edit-map (make-sparse-keymap)
+  "Keymap that defines the responses to questions in `kmacro-step-edit-macro'.
+This keymap is an extension to the `query-replace-map', allowing the
+following additional answers: `insert', `insert-1', `replace', `replace-1',
+`append', `append-end', `act-repeat', `skip-end', `skip-keep'.")
+
+;; query-replace-map answers include: `act', `skip', `act-and-show',
+;; `exit', `act-and-exit', `edit', `delete-and-edit', `recenter',
+;; `automatic', `backup', `exit-prefix', and `help'.")
+;; Also: `quit', `edit-replacement'
+
+(set-keymap-parent kmacro-step-edit-map query-replace-map)
+
+(define-key kmacro-step-edit-map "\t" 'act-repeat)
+(define-key kmacro-step-edit-map [tab] 'act-repeat)
+(define-key kmacro-step-edit-map "\C-k" 'skip-rest)
+(define-key kmacro-step-edit-map "c" 'automatic)
+(define-key kmacro-step-edit-map "f" 'skip-keep)
+(define-key kmacro-step-edit-map "q" 'quit)
+(define-key kmacro-step-edit-map "d" 'skip)
+(define-key kmacro-step-edit-map "\C-d" 'skip)
+(define-key kmacro-step-edit-map "i" 'insert)
+(define-key kmacro-step-edit-map "I" 'insert-1)
+(define-key kmacro-step-edit-map "r" 'replace)
+(define-key kmacro-step-edit-map "R" 'replace-1)
+(define-key kmacro-step-edit-map "a" 'append)
+(define-key kmacro-step-edit-map "A" 'append-end)
+
+(defvar kmacro-step-edit-prefix-commands
+  '(universal-argument universal-argument-more universal-argument-minus
+                      digit-argument negative-argument)
+  "Commands which builds up a prefix arg for the current command")
+
+(defun kmacro-step-edit-prompt (macro index)
+  ;; Show step-edit prompt
+  (let ((keys (and (not kmacro-step-edit-appending)
+                  index (substring macro index executing-macro-index)))
+       (future (and (not kmacro-step-edit-appending)
+                    (substring macro executing-macro-index)))
+       (message-log-max nil)
+       (curmsg (current-message)))
+
+    ;; TODO: Scroll macro if max-mini-window-height is too small.
+    (message (concat
+             (format "Macro: %s%s%s%s%s\n"
+                     (format-kbd-macro kmacro-step-edit-new-macro 1)
+                     (if (and kmacro-step-edit-new-macro (> (length kmacro-step-edit-new-macro) 0)) " " "")
+                     (propertize (if keys (format-kbd-macro keys) 
+                                   (if kmacro-step-edit-appending "<APPEND>" "<INSERT>")) 'face 'region)
+                     (if future " " "")
+                     (if future (format-kbd-macro future) ""))
+             (cond
+              ((minibufferp)
+               (format "%s\n%s\n"
+                         (propertize "\
+                         minibuffer                             " 'face 'header-line)
+                         (buffer-substring (point-min) (point-max))))
+              (curmsg
+               (format "%s\n%s\n"
+                       (propertize "\
+                         echo area                              " 'face 'header-line)
+                       curmsg))
+              (t ""))
+             (if keys
+                 (format "%s\n%s%s %S [yn iIaArR C-k kq!] " 
+                         (propertize "\
+--------------Step Edit Keyboard Macro  [?: help]---------------" 'face 'mode-line)
+                         (if kmacro-step-edit-help "\
+ Step: y/SPC: execute next,  d/n/DEL: skip next,  f: skip but keep
+       TAB: execute while same,  ?: toggle help
+ Edit: i: insert,  r: replace,  a: append,  A: append at end,
+       I/R: insert/replace with one sequence,
+ End:  !/c: execute rest,  C-k: skip rest and save,  q/C-g: quit
+----------------------------------------------------------------
+" "")
+                         (propertize "Next command:" 'face 'bold)
+                         this-command)
+               (propertize 
+                (format "Type key sequence%s to insert and execute%s: "
+                        (if (numberp kmacro-step-edit-inserting) ""  "s")
+                        (if (numberp kmacro-step-edit-inserting) ""  " (end with C-j)"))
+                'face 'bold))))))
+
+(defun kmacro-step-edit-query ()
+  ;; Pre-command hook function for step-edit in "command" mode
+  (let ((resize-mini-windows t)
+       (max-mini-window-height kmacro-step-edit-mini-window-height)
+       act restore-index next-index)
+
+    ;; Handle commands which reads additional input using read-char.
+    (cond
+     ((and (eq this-command 'quoted-insert)
+          (not (eq kmacro-step-edit-action t)))
+      ;; Find the actual end of this key sequence.
+      ;; Must be able to backtrack in case we actually execute it.
+      (setq restore-index executing-macro-index)
+      (let (unread-command-events)
+       (quoted-insert 0)
+       (when unread-command-events
+         (setq executing-macro-index (- executing-macro-index (length unread-command-events))
+               next-index executing-macro-index)))))
+
+    ;; Query the user; stop macro exection temporarily
+    (let ((macro executing-kbd-macro)
+         (executing-kbd-macro nil)
+         (defining-kbd-macro nil))
+
+      ;; Any action requested by previous command
+      (cond
+       ((eq kmacro-step-edit-action t)  ;; Reentry for actual command @ end of prefix arg.
+       (cond
+        ((eq this-command 'quoted-insert)
+         (clear-this-command-keys) ;; recent-keys actually
+         (let (unread-command-events)
+           (quoted-insert (prefix-numeric-value current-prefix-arg))
+           (setq kmacro-step-edit-new-macro 
+                 (vconcat kmacro-step-edit-new-macro (recent-keys)))
+           (when unread-command-events
+             (setq kmacro-step-edit-new-macro
+                   (substring kmacro-step-edit-new-macro 0 (- (length unread-command-events)))
+                   executing-macro-index (- executing-macro-index (length unread-command-events)))))
+         (setq current-prefix-arg nil
+               prefix-arg nil)
+         (setq act 'ignore))
+        (t
+         (setq act 'act)))
+       (setq kmacro-step-edit-action nil))
+       ((eq this-command kmacro-step-edit-action)  ;; TAB -> activate while same command
+       (setq act 'act))
+       (t
+       (setq kmacro-step-edit-action nil)))
+
+      ;; Handle prefix arg, or query user
+      (cond
+       (act act) ;; set above
+       ((memq this-command kmacro-step-edit-prefix-commands)
+       (unless kmacro-step-edit-prefix-index
+         (setq kmacro-step-edit-prefix-index kmacro-step-edit-key-index))
+       (setq act 'universal-argument))
+       ((eq this-command 'universal-argument-other-key)
+       (setq act 'universal-argument))
+       (t
+       (kmacro-step-edit-prompt macro (or kmacro-step-edit-prefix-index kmacro-step-edit-key-index))
+       (setq act (lookup-key kmacro-step-edit-map
+                             (vector (with-current-buffer (current-buffer) (read-event))))))))
+
+    ;; Resume macro execution and perform the action
+    (cond
+     ((eq act 'universal-argument)
+      nil)
+     ((cond
+       ((eq act 'act)
+       t)
+       ((eq act 'act-repeat)
+       (setq kmacro-step-edit-action this-command)
+       t)
+       ((eq act 'quit)
+       (setq kmacro-step-edit-replace nil)
+       (setq kmacro-step-edit-active 'ignore)
+       nil)
+       ((eq act 'skip)
+       (setq kmacro-step-edit-prefix-index nil)
+       nil)
+       ((eq act 'skip-keep)
+       (setq this-command 'ignore)
+       t)
+       ((eq act 'skip-rest)
+       (setq kmacro-step-edit-active 'ignore)
+       nil)
+       ((memq act '(automatic exit))
+       (setq kmacro-step-edit-active nil)
+       (setq act t)
+       t)
+       ((member act '(insert-1 insert))
+       (setq executing-macro-index (or kmacro-step-edit-prefix-index kmacro-step-edit-key-index))
+       (setq kmacro-step-edit-inserting (if (eq act 'insert-1) 1 t))
+       nil)
+       ((member act '(replace-1 replace))
+       (setq kmacro-step-edit-inserting (if (eq act 'replace-1) 1 t))
+       (setq kmacro-step-edit-prefix-index nil)
+       (if (= executing-macro-index (length executing-kbd-macro))
+           (setq executing-kbd-macro (vconcat executing-kbd-macro [nil])
+                 kmacro-step-edit-appending t))
+       nil)
+       ((eq act 'append)
+       (setq kmacro-step-edit-inserting t)
+       (if (= executing-macro-index (length executing-kbd-macro))
+           (setq executing-kbd-macro (vconcat executing-kbd-macro [nil])
+                 kmacro-step-edit-appending t))
+       t)
+       ((eq act 'append-end)
+       (if (= executing-macro-index (length executing-kbd-macro))
+           (setq executing-kbd-macro (vconcat executing-kbd-macro [nil])
+                 kmacro-step-edit-inserting t
+                 kmacro-step-edit-appending t)
+         (setq kmacro-step-edit-active 'append-end))
+       (setq act t)
+       t)
+       ((eq act 'help)
+       (setq executing-macro-index (or kmacro-step-edit-prefix-index kmacro-step-edit-key-index))
+       (setq kmacro-step-edit-help (not kmacro-step-edit-help))
+       nil)
+       (t ;; Ignore unknown responses
+       (setq executing-macro-index (or kmacro-step-edit-prefix-index kmacro-step-edit-key-index))
+       nil))
+      (if (> executing-macro-index (or kmacro-step-edit-prefix-index kmacro-step-edit-key-index))
+         (setq kmacro-step-edit-new-macro
+               (vconcat kmacro-step-edit-new-macro
+                        (substring executing-kbd-macro 
+                                   (or kmacro-step-edit-prefix-index kmacro-step-edit-key-index)
+                                   (if (eq act t) nil executing-macro-index)))
+               kmacro-step-edit-prefix-index nil))
+      (if restore-index
+         (setq executing-macro-index restore-index)))
+     (t
+      (setq this-command 'ignore)))
+    (setq kmacro-step-edit-key-index next-index)))
+
+(defun kmacro-step-edit-insert ()
+  ;; Pre-command hook function for step-edit in "insert" mode
+  (let ((resize-mini-windows t)
+       (max-mini-window-height kmacro-step-edit-mini-window-height)
+       (macro executing-kbd-macro)
+       (executing-kbd-macro nil)
+       (defining-kbd-macro nil)
+       cmd keys next-index)
+    (setq executing-macro-index (or kmacro-step-edit-prefix-index kmacro-step-edit-key-index)
+         kmacro-step-edit-prefix-index nil)
+    (kmacro-step-edit-prompt macro nil)
+    ;; Now, we have read a key sequence from the macro, but we don't want
+    ;; to execute it yet.  So push it back and read another sequence.
+    (reset-this-command-lengths)
+    (setq keys (read-key-sequence nil nil nil nil t))
+    (setq cmd (key-binding keys t nil))
+    (if (cond
+        ((null cmd)
+         t)
+        ((eq cmd 'quoted-insert)
+         (clear-this-command-keys) ;; recent-keys actually
+         (quoted-insert (prefix-numeric-value current-prefix-arg))
+         (setq current-prefix-arg nil
+               prefix-arg nil)
+         (setq keys (vconcat keys (recent-keys)))
+         (when (numberp kmacro-step-edit-inserting)
+           (setq kmacro-step-edit-inserting nil)
+           (when unread-command-events
+             (setq keys (substring keys 0 (- (length unread-command-events)))
+                   executing-macro-index (- executing-macro-index (length unread-command-events))
+                   next-index executing-macro-index
+                   unread-command-events nil)))
+         (setq cmd 'ignore)
+         nil)
+        ((memq cmd kmacro-step-edit-prefix-commands)
+         (setq universal-argument-num-events 0)
+         (reset-this-command-lengths)
+         nil)
+        ((eq cmd 'universal-argument-other-key)
+         (setq kmacro-step-edit-action t)
+         (setq universal-argument-num-events 0)
+         (reset-this-command-lengths)
+         (if (numberp kmacro-step-edit-inserting)
+             (setq kmacro-step-edit-inserting nil))
+         nil)
+        ((numberp kmacro-step-edit-inserting)
+         (setq kmacro-step-edit-inserting nil)
+         nil)
+        ((equal keys "\C-j")
+         (setq kmacro-step-edit-inserting nil)
+         (setq kmacro-step-edit-action nil)
+         ;; Forget any (partial) prefix arg from next command
+         (setq kmacro-step-edit-prefix-index nil)
+         (reset-this-command-lengths)
+         (setq overriding-terminal-local-map nil)
+         (setq universal-argument-num-events nil)
+         (setq next-index kmacro-step-edit-key-index)
+         t)
+        (t nil))
+       (setq this-command 'ignore)
+      (setq this-command cmd)
+      (if (memq this-command '(self-insert-command digit-argument))
+         (setq last-command-char (aref keys (1- (length keys)))))
+      (if keys
+         (setq kmacro-step-edit-new-macro (vconcat kmacro-step-edit-new-macro keys))))
+    (setq kmacro-step-edit-key-index next-index)))
+
+(defun kmacro-step-edit-pre-command ()
+  (remove-hook 'post-command-hook 'kmacro-step-edit-post-command)
+  (when kmacro-step-edit-active
+    (cond
+     ((eq kmacro-step-edit-active 'ignore)
+      (setq this-command 'ignore))
+     ((eq kmacro-step-edit-active 'append-end)
+      (if (= executing-macro-index (length executing-kbd-macro))
+         (setq executing-kbd-macro (vconcat executing-kbd-macro [nil])
+               kmacro-step-edit-inserting t
+               kmacro-step-edit-appending t
+               kmacro-step-edit-active t)))
+     ((/= kmacro-step-edit-num-input-keys num-input-keys)
+      (if kmacro-step-edit-inserting
+         (kmacro-step-edit-insert)
+       (kmacro-step-edit-query))
+      (setq kmacro-step-edit-num-input-keys num-input-keys)
+      (if (and kmacro-step-edit-appending (not kmacro-step-edit-inserting))
+         (setq kmacro-step-edit-appending nil
+               kmacro-step-edit-active 'ignore)))))
+  (when (eq kmacro-step-edit-active t)
+    (add-hook 'post-command-hook 'kmacro-step-edit-post-command t)))
+
+(defun kmacro-step-edit-minibuf-setup ()
+  (remove-hook 'pre-command-hook 'kmacro-step-edit-pre-command t)
+  (when kmacro-step-edit-active
+    (add-hook 'pre-command-hook 'kmacro-step-edit-pre-command nil t)))
+
+(defun kmacro-step-edit-post-command ()
+  (remove-hook 'pre-command-hook 'kmacro-step-edit-pre-command)
+  (when kmacro-step-edit-active
+    (add-hook 'pre-command-hook 'kmacro-step-edit-pre-command nil nil)
+    (if kmacro-step-edit-key-index
+       (setq executing-macro-index kmacro-step-edit-key-index)
+      (setq kmacro-step-edit-key-index executing-macro-index))))  
+
+
+(defun kmacro-step-edit-macro ()
+  "Step edit and execute last keyboard macro.
+
+To customize possible responses, change the \"bindings\" in `kmacro-step-edit-map'."
+  (interactive)
+  (let ((kmacro-step-edit-active t)
+       (kmacro-step-edit-new-macro "")
+       (kmacro-step-edit-inserting nil)
+       (kmacro-step-edit-appending nil)
+       (kmacro-step-edit-replace t)
+       (kmacro-step-edit-prefix-index nil)
+       (kmacro-step-edit-key-index 0)
+       (kmacro-step-edit-action nil)
+       (kmacro-step-edit-help nil)
+       (kmacro-step-edit-num-input-keys num-input-keys)
+       (pre-command-hook pre-command-hook)
+       (post-command-hook post-command-hook)
+       (minibuffer-setup-hook minibuffer-setup-hook))
+    (add-hook 'pre-command-hook 'kmacro-step-edit-pre-command nil)
+    (add-hook 'post-command-hook 'kmacro-step-edit-post-command t)
+    (add-hook 'minibuffer-setup-hook 'kmacro-step-edit-minibuf-setup t)
+    (call-last-kbd-macro nil nil)
+    (when (and kmacro-step-edit-replace
+              kmacro-step-edit-new-macro
+              (not (equal last-kbd-macro kmacro-step-edit-new-macro)))
+      (kmacro-push-ring)
+      (setq last-kbd-macro kmacro-step-edit-new-macro))))
+
 (provide 'kmacro)
 ;;; kmacro.el ends here