Commit a1839f06 authored by Kim F. Storm's avatar Kim F. Storm
Browse files

(kmacro-keymap): Group related bindings in

initialization for clarity.  Bind C-s to start macro.
Remove C-r binding.
(kmacro-initial-counter-value): New defvar to hold initial counter
value in case we set the value before defining a macro.
(kmacro-insert-counter): Clear kmacro-initial-counter-value..
(kmacro-set-counter): Set kmacro-initial-counter-value if we are
not defining or executing macro.  Doc fix.
(kmacro-add-counter): Clear kmacro-initial-counter-value.
(kmacro-view-last-item, kmacro-view-item-no): New defvars used to
temporarily view older elements on the macro ring without cycling
the ring.
(kmacro-display): Doc fix.
(kmacro-exec-ring-item): New helper function.
(kmacro-call-ring-2nd): Use it.
(kmacro-call-ring-2nd-repeat): Doc fix.
(kmacro-start-macro): Use (and clear) kmacro-initial-counter-value.
(kmacro-end-or-call-macro): Execute last viewed macro (using
kmacro-exec-ring-item) from ring if this follows
kmacro-view-macro.  This allows us to find a macro on the ring
with C-x C-k C-v C-v ... and execute it (with C-k) without cycling
the ring to bring it to the head of the ring.
(kmacro-bind-to-key): Doc fix (describe reserved bindings).
Allow binding to reserved keys without specifying C-x C-k prefix.
Ask for confirmation if entered key sequence is already bound to
a non-macro command.
(kmacro-view-macro): Repeating command will show older elements
on the macro ring; C-k will execute the last viewed macro.
(kmacro-view-macro-repeat): Doc fix.  Change its kmacro-repeat
property from 'ring to 'head.
parent 100df214
......@@ -174,29 +174,37 @@ macro to be executed before appending to it."
(defvar kmacro-keymap
(let ((map (make-sparse-keymap)))
;; Start, end, execute macros
(define-key map "s" 'kmacro-start-macro)
(define-key map "\C-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-repeat)
(define-key map "\C-l" 'kmacro-call-ring-2nd-repeat)
(define-key map "\C-r" 'kmacro-view-ring-2nd)
(define-key map "r" 'apply-macro-to-region-lines)
(define-key map "q" 'kbd-macro-query) ;; Like C-x q
;; macro ring
(define-key map "\C-n" 'kmacro-cycle-ring-next)
(define-key map "\C-p" 'kmacro-cycle-ring-previous)
(define-key map "\C-v" 'kmacro-view-macro-repeat)
(define-key map "\C-d" 'kmacro-delete-ring-head)
(define-key map "\C-t" 'kmacro-swap-ring)
(define-key map "\C-l" 'kmacro-call-ring-2nd-repeat)
;; macro counter
(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-i" 'kmacro-insert-counter)
(define-key map "\C-a" 'kmacro-add-counter)
;; macro editing
(define-key map "\C-e" 'kmacro-edit-macro-repeat)
(define-key map "\r" 'kmacro-edit-macro)
(define-key map "e" 'edit-kbd-macro)
(define-key map "l" 'kmacro-edit-lossage)
(define-key map " " 'kmacro-step-edit-macro)
;; naming and binding
(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)
(define-key map "n" 'name-last-kbd-macro)
(define-key map "e" 'edit-kbd-macro)
(define-key map "r" 'apply-macro-to-region-lines)
map)
"Keymap for keyboard macro commands.")
(defalias 'kmacro-keymap kmacro-keymap)
......@@ -229,13 +237,18 @@ macro to be executed before appending to it."
(defvar kmacro-counter-value-start kmacro-counter
"Macro counter at start of macro execution.")
(defvar kmacro-last-counter 0 "Last counter inserted by key macro.")
(defvar kmacro-last-counter 0
"Last counter inserted by key macro.")
(defvar kmacro-initial-counter-value nil
"Initial counter value for the next keyboard macro to be defined.")
(defun kmacro-insert-counter (arg)
"Insert macro counter and increment with ARG or 1 if missing.
With \\[universal-argument], insert previous kmacro-counter (but do not modify counter)."
(interactive "P")
(setq kmacro-initial-counter-value nil)
(if (and arg (listp arg))
(insert (format kmacro-counter-format kmacro-last-counter))
(insert (format kmacro-counter-format kmacro-counter))
......@@ -260,12 +273,16 @@ With \\[universal-argument], insert previous kmacro-counter (but do not modify c
(defun kmacro-set-counter (arg)
"Set kmacro-counter to ARG or prompt if missing.
With \\[universal-argument], reset counter to its value prior to this iteration of the macro."
With \\[universal-argument] prefix, reset counter to its value prior to this iteration of the macro."
(interactive "NMacro counter value: ")
(setq kmacro-last-counter kmacro-counter
kmacro-counter (if (and current-prefix-arg (listp current-prefix-arg))
kmacro-counter-value-start
arg))
;; setup initial macro counter value if we are not executing a macro.
(setq kmacro-initial-counter-value
(and (not (or defining-kbd-macro executing-kbd-macro))
kmacro-counter))
(unless executing-kbd-macro
(kmacro-display-counter)))
......@@ -274,6 +291,7 @@ With \\[universal-argument], reset counter to its value prior to this iteration
"Add numeric prefix arg (prompt if missing) to macro counter.
With \\[universal-argument], restore previous counter value."
(interactive "NAdd to macro counter: ")
(setq kmacro-initial-counter-value nil)
(let ((last kmacro-last-counter))
(setq kmacro-last-counter kmacro-counter
kmacro-counter (if (and current-prefix-arg (listp current-prefix-arg))
......@@ -303,6 +321,11 @@ the macro ring (when defining or executing) is not stored in the ring;
instead it is available in the variables `last-kbd-macro', `kmacro-counter',
and `kmacro-counter-format'.")
;; Remember what we are currently looking at with kmacro-view-macro.
(defvar kmacro-view-last-item nil)
(defvar kmacro-view-item-no 0)
(defun kmacro-ring-head ()
"Return pseudo head element in macro ring."
......@@ -361,8 +384,11 @@ Check only `last-kbd-macro' if optional arg NONE is non-nil."
(t nil)))
(defun kmacro-display (macro &optional trunc descr empty )
"Display a keyboard MACRO."
(defun kmacro-display (macro &optional trunc descr empty)
"Display a keyboard MACRO.
Optional arg TRUNC non-nil specifies to limit width of macro to 60 chars.
Optional arg DESCR is descriptive text for macro; default is \"Macro:\".
Optional arg EMPTY is message to print if no macros are defined."
(if macro
(let* ((x 60)
(m (format-kbd-macro macro))
......@@ -410,19 +436,26 @@ Check only `last-kbd-macro' if optional arg NONE is non-nil."
keys)))
(defun kmacro-exec-ring-item (item arg)
"Execute item ITEM from the macro ring."
;; Use counter and format specific to the macro on the ring!
(let ((kmacro-counter (nth 1 item))
(kmacro-counter-format-start (nth 2 item)))
(execute-kbd-macro (car item) arg #'kmacro-loop-setup-function)
(setcar (cdr item) kmacro-counter)))
(defun kmacro-call-ring-2nd (arg)
"Execute second keyboard macro at in macro ring."
(interactive "P")
(unless (kmacro-ring-empty-p)
;; should use counter format specific to the macro on the ring!
(let ((kmacro-counter (nth 1 (car kmacro-ring)))
(kmacro-counter-format-start (nth 2 (car kmacro-ring))))
(execute-kbd-macro (car (car kmacro-ring)) arg #'kmacro-loop-setup-function)
(setcar (cdr (car kmacro-ring)) kmacro-counter))))
(kmacro-exec-ring-item (car kmacro-ring) arg)))
(defun kmacro-call-ring-2nd-repeat (arg)
"Like `kmacro-call-ring-2nd', but allow repeat without repeating prefix."
"Execute second keyboard macro at in macro ring.
This is like `kmacro-call-ring-2nd', but allows repeating macro commands
without repeating the prefix."
(interactive "P")
(let ((keys (kmacro-get-repeat-prefix)))
(kmacro-call-ring-2nd arg)
......@@ -439,7 +472,6 @@ Check only `last-kbd-macro' if optional arg NONE is non-nil."
(kmacro-display (car (car kmacro-ring)) "2nd macro")))
(defun kmacro-cycle-ring-next (&optional arg)
"Move to next keyboard macro in keyboard macro ring.
Displays the selected macro in the echo area."
......@@ -533,7 +565,10 @@ The format of the counter can be modified via \\[kmacro-set-format]."
kmacro-ring))
(if (>= len kmacro-ring-max)
(setcdr (nthcdr len kmacro-ring) nil))))
(setq kmacro-counter (if arg (prefix-numeric-value arg) 0)
(setq kmacro-counter (or (if arg (prefix-numeric-value arg))
kmacro-initial-counter-value
0)
kmacro-initial-counter-value nil
kmacro-counter-value-start kmacro-counter
kmacro-last-counter kmacro-counter
kmacro-counter-format-start kmacro-counter-format))
......@@ -645,6 +680,9 @@ With \\[universal-argument], call second macro in macro ring."
(if kmacro-call-repeat-key
(kmacro-call-macro arg no-repeat t)
(kmacro-end-macro arg)))
((and (eq this-command 'kmacro-view-macro) ;; We are in repeat mode!
kmacro-view-last-item)
(kmacro-exec-ring-item (car kmacro-view-last-item) arg))
((and arg (listp arg))
(kmacro-call-ring-2nd 1))
(t
......@@ -689,34 +727,97 @@ If kbd macro currently being defined end it before activating it."
;;; Misc. commands
;; An idea for macro bindings:
;; Create a separate keymap installed as a minor-mode keymap (e.g. in
;; the emulation-mode-map-alists) in which macro bindings are made
;; independent of any other bindings. When first binding is made,
;; the kemap is created, installed, and enabled. Key seq. C-x C-k +
;; can then be used to toggle the use of this keymap on and off.
;; This means that it would be safe(r) to bind ordinary keys like
;; letters and digits, provided that we inhibit the keymap while
;; executing the macro later on (but that's controversial...)
(defun kmacro-bind-to-key (arg)
"When not defining or executing a macro, offer to bind last macro to a key."
"When not defining or executing a macro, offer to bind last macro to a key.
The key sequences [C-x C-k 0] through [C-x C-k 9] and [C-x C-k A]
through [C-x C-k Z] are reserved for user bindings, and to bind to
one of these sequences, just enter the digit or letter, rather than
the whole sequence.
You can bind to any valid key sequence, but if you try to bind to
a key with an existing command binding, you will be asked for
confirmation whether to replace that binding. Note that the
binding is made in the `global-map' keymap, so the macro binding
may be shaded by a local key binding."
(interactive "p")
(if (or defining-kbd-macro executing-kbd-macro)
(if defining-kbd-macro
(message "Cannot save macro while defining it."))
(unless last-kbd-macro
(error "No keyboard macro defined"))
(let ((key-seq (read-key-sequence "Bind last macro to key: ")))
(unless (equal key-seq "")
(define-key global-map key-seq last-kbd-macro)))))
(let ((key-seq (read-key-sequence "Bind last macro to key: "))
ok cmd)
(when (= (length key-seq) 1)
(let ((ch (aref key-seq 0)))
(if (or (and (>= ch ?0) (<= ch ?9))
(and (>= ch ?A) (<= ch ?Z)))
(setq key-seq (concat "\C-x\C-k" key-seq)
ok t))))
(when (and (not (equal key-seq ""))
(or ok
(not (setq cmd (key-binding key-seq)))
(stringp cmd)
(vectorp cmd)
(yes-or-no-p (format "%s runs command %S. Bind anyway? "
(format-kbd-macro key-seq)
cmd))))
(define-key global-map key-seq last-kbd-macro)
(message "Keyboard macro bound to %s" (format-kbd-macro key-seq))))))
(defun kmacro-view-macro (&optional arg)
"Display the last keyboard macro."
"Display the last keyboard macro.
If repeated, it shows previous elements in the macro ring."
(interactive)
(kmacro-display last-kbd-macro))
(cond
((or (kmacro-ring-empty-p)
(not (eq last-command 'kmacro-view-macro)))
(setq kmacro-view-last-item nil))
((null kmacro-view-last-item)
(setq kmacro-view-last-item kmacro-ring
kmacro-view-item-no 2))
((consp kmacro-view-last-item)
(setq kmacro-view-last-item (cdr kmacro-view-last-item)
kmacro-view-item-no (1+ kmacro-view-item-no)))
(t
(setq kmacro-view-last-item nil)))
(setq this-command 'kmacro-view-macro
last-command this-command) ;; in case we repeat
(kmacro-display (if kmacro-view-last-item
(car (car kmacro-view-last-item))
last-kbd-macro)
nil
(if kmacro-view-last-item
(concat (cond ((= kmacro-view-item-no 2) "2nd")
((= kmacro-view-item-no 3) "3nd")
(t (format "%dth" kmacro-view-item-no)))
" previous macro")
"Last macro")))
(defun kmacro-view-macro-repeat (&optional arg)
"Like `kmacro-view-macro', but allow repeat without repeating prefix."
"Display the last keyboard macro.
If repeated, it shows previous elements in the macro ring.
To execute the displayed macro ring item without changing the macro ring,
just enter C-k.
This is like `kmacro-view-macro', but allows repeating macro commands
without repeating the prefix."
(interactive)
(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-repeat 'kmacro-repeat 'head)
(put 'kmacro-view-macro-repeat 'kmacro-repeat 'ring)
(defun kmacro-edit-macro-repeat (&optional arg)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment