46083
|
1 ;;; kmacro.el --- enhanced keyboard macros
|
|
2
|
|
3 ;; Copyright (C) 1996-2002 Free Software Foundation, Inc.
|
|
4
|
|
5 ;; Author: Kim F. Storm <storm@cua.dk>
|
|
6 ;; Based on: iswitchb by Stephen Eglen <stephen@cns.ed.ac.uk>
|
|
7 ;; Keywords: extensions convenience
|
|
8
|
|
9 ;; This file is part of GNU Emacs.
|
|
10
|
|
11 ;; GNU Emacs is free software; you can redistribute it and/or modify
|
|
12 ;; it under the terms of the GNU General Public License as published by
|
|
13 ;; the Free Software Foundation; either version 2, or (at your option)
|
|
14 ;; any later version.
|
|
15
|
|
16 ;; GNU Emacs is distributed in the hope that it will be useful,
|
|
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
19 ;; GNU General Public License for more details.
|
|
20
|
|
21 ;; You should have received a copy of the GNU General Public License
|
|
22 ;; along with GNU Emacs; see the file COPYING. If not, write to the
|
|
23 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
24 ;; Boston, MA 02111-1307, USA.
|
|
25
|
|
26 ;;; Commentary:
|
|
27
|
|
28 ;; The kmacro package is an alternative user interface to emacs'
|
|
29 ;; keyboard macro functionality. This functionality is normally bound
|
|
30 ;; to C-x (, C-x ), and C-x C-e, but these bindings are too hard to
|
|
31 ;; type to be really useful for doing small repeated tasks.
|
|
32
|
|
33 ;; With kmacro, two function keys are dedicated to keyboard macros,
|
|
34 ;; by default F7 and F8. Personally, I prefer F1 and F2, but those
|
|
35 ;; keys already have default bindings.
|
|
36 ;;
|
|
37 ;; To start defining a keyboard macro, use F7. To end the macro,
|
|
38 ;; use F8, and to call the macro also use F8. This makes it very
|
|
39 ;; easy to repeat a macro immediately after defining it.
|
|
40 ;;
|
|
41 ;; You can call the macro repeatedly by pressing F8 multiple times, or
|
|
42 ;; you can give a numeric prefix argument specifying the number of
|
|
43 ;; times to repeat the macro. Macro execution automatically
|
|
44 ;; terminates when point reaches the end of the buffer or if an error
|
|
45 ;; is signalled by ringing the bell.
|
|
46
|
|
47 ;; If you enter F7 while defining the macro, the numeric value of
|
|
48 ;; `kmacro-counter' is inserted using the `kmacro-counter-format', and
|
|
49 ;; `kmacro-counter' is incremented by 1 (or the numeric prefix value
|
|
50 ;; of F7).
|
|
51 ;;
|
|
52 ;; The initial value of `kmacro-counter' is 0, or the numeric prefix
|
|
53 ;; value given to F7 when starting the macro.
|
|
54 ;;
|
|
55 ;; Now, each time you call the macro using F8, the current
|
|
56 ;; value of `kmacro-counter' is inserted and incremented, making it
|
|
57 ;; easy to insert incremental numbers in the buffer.
|
|
58 ;;
|
|
59 ;; Example:
|
|
60 ;;
|
|
61 ;; The following sequence: M-5 F7 x M-2 F7 y F8 F8 F8 F8
|
|
62 ;; inserts the following string: x5yx7yx9yx11y
|
|
63
|
|
64 ;; A macro can also be call using a mouse click, default S-mouse-3.
|
|
65 ;; This calls the macro at the point where you click the mouse.
|
|
66
|
|
67 ;; When you have defined another macro, which is thus called via F8,
|
|
68 ;; the previous macro is pushed onto a keyboard macro ring. The head
|
|
69 ;; macro on the ring can be executed using S-F8. You can cycle the
|
|
70 ;; macro ring using C-F8. You can also swap the last macro and the
|
|
71 ;; head of the macro ring using C-u F8.
|
|
72
|
|
73 ;; You can edit the last macro using M-F7.
|
|
74
|
|
75 ;; You can append to the last macro using C-u F7.
|
|
76
|
|
77 ;; You can set the macro counter using C-F7, and you can set
|
|
78 ;; the macro counter format with S-F7..
|
|
79
|
|
80 ;; The following key bindings are performed:
|
|
81 ;;
|
|
82 ;; Normal While defining macro
|
|
83 ;; --------------------------- ------------------------------
|
|
84 ;; f7 Define macro Insert current counter value
|
|
85 ;; Prefix arg specifies initial and increase counter by prefix
|
|
86 ;; counter value (default 0) (default increment: 1)
|
|
87 ;;
|
|
88 ;; C-u f7 APPENDs to last macro
|
|
89 ;;
|
|
90 ;; f8 Call last macro End macro
|
|
91 ;; Prefix arg specifies number
|
|
92 ;; of times to execute macro.
|
|
93 ;;
|
|
94 ;; C-u f8 Swap last and head of macro ring.
|
|
95 ;;
|
|
96 ;; S-f7 Set the format of the macro Ditto, but notice that the
|
|
97 ;; counter (default: %d). format is reset at the next
|
|
98 ;; invocation of the macro.
|
|
99 ;;
|
|
100 ;; C-f7 Set the macro counter value Increase/decrease counter value
|
|
101 ;; to the prefix value. by the prefix value, or if prefix
|
|
102 ;; is C-u, set counter to 0.
|
|
103 ;;
|
|
104 ;; M-f7 Edit the last macro.
|
|
105 ;;
|
|
106 ;; S-f8 Call the previous macro.
|
|
107 ;;
|
|
108 ;; C-f8 Cycle the macro ring.
|
|
109 ;;
|
|
110 ;; S-mouse-3 Set point at click and End macro and execute macro at
|
|
111 ;; execute last macro. click.
|
|
112
|
|
113 ;;; Code:
|
|
114
|
|
115 (provide 'kmacro)
|
|
116
|
|
117 ;;; Customization:
|
|
118
|
|
119 (defgroup kmacro nil
|
|
120 "Simplified keyboard macro user interface."
|
|
121 :group 'keyboard
|
|
122 :group 'convenience
|
|
123 :link '(emacs-commentary-link :tag "Commentary" "kmacro.el")
|
|
124 :link '(emacs-library-link :tag "Lisp File" "kmacro.el"))
|
|
125
|
|
126 ;;;###autoload
|
|
127 (defcustom kmacro-initialize nil
|
|
128 "Setting this variable turns on the kmacro functionality.
|
|
129 This binds the kmacro function keys in the global-map, so
|
|
130 unsetting this variable does not have any effect!"
|
|
131 :set #'(lambda (symbol value)
|
|
132 (if value (kmacro-initialize))
|
|
133 (set symbol value))
|
|
134 :initialize 'custom-initialize-default
|
|
135 :require 'kmacro
|
|
136 :link '(emacs-commentary-link "kmacro.el")
|
|
137 :set-after '(kmacro-start-key kmacro-call-key kmacro-mouse-button)
|
|
138 :version "21.4"
|
|
139 :type 'boolean
|
|
140 :group 'kmacro)
|
|
141
|
|
142 (defcustom kmacro-start-key 'f7
|
|
143 "The function key used by kmacro to start a macro."
|
|
144 :type 'symbol
|
|
145 :group 'kmacro)
|
|
146
|
|
147 (defcustom kmacro-call-key 'f8
|
|
148 "The function key used by kmacro to end and call a macro."
|
|
149 :type 'symbol
|
|
150 :group 'kmacro)
|
|
151
|
|
152 (defcustom kmacro-call-mouse-event 'S-mouse-3
|
|
153 "The mouse event used by kmacro to call a macro."
|
|
154 :type 'symbol
|
|
155 :group 'kmacro)
|
|
156
|
|
157 ;; State variables
|
|
158
|
|
159 (defvar kmacro-counter 0
|
|
160 "*Current keyboard macro counter")
|
|
161
|
|
162 (defvar kmacro-counter-format "%d"
|
|
163 "*Current keyboard macro counter format")
|
|
164
|
|
165 (defvar kmacro-counter-format-start kmacro-counter-format
|
|
166 "Macro format at start of macro execution.")
|
|
167
|
|
168 (defvar kmacro-last-counter 0 "Last counter inserted by key macro")
|
|
169 (defvar kmacro-append-to nil "Last key macro if appending to macro")
|
|
170 (defvar kmacro-ring nil "Key macro ring")
|
|
171
|
|
172 (defvar kmacro-ring-max 4
|
|
173 "*Maximum number of key macros to save in key macro ring")
|
|
174
|
|
175 (defun kmacro-display (macro)
|
|
176 "Display a keyboard macro."
|
|
177 (let (s)
|
|
178 (if (stringp macro)
|
|
179 (setq s (if (> (length macro) 50)
|
|
180 (concat (substring macro 0 50) "...")
|
|
181 macro))
|
|
182 (if (vectorp macro)
|
|
183 (let (v (i 0) (n (length macro)))
|
|
184 (setq s "")
|
|
185 (while (and (< i n) (< (length s) 50))
|
|
186 (setq v (aref macro i))
|
|
187 (setq s (cond
|
|
188 ((numberp v) (concat s (char-to-string v)))
|
|
189 ((stringp v) (concat s v))
|
|
190 ((symbolp v) (concat s "[" (symbol-name v) "]"))
|
|
191 (t s)))
|
|
192 (setq i (1+ i)))
|
|
193 (if (< i n)
|
|
194 (setq s (concat s "..."))))))
|
|
195 (message (format "Macro: %s" s))))
|
|
196
|
|
197
|
|
198 (defun kmacro-start-macro (arg)
|
|
199 "Set kmacro-counter to ARG or 0 if missing, and start-kbd-macro.
|
|
200 With \\[universal-argument], append to current keyboard macro (keep kmacro-counter).
|
|
201
|
|
202 When defining/executing macro, insert macro counter and increment with
|
|
203 ARG or 1 if missing.
|
|
204 With \\[universal-argument], insert previous kmacro-counter (but do not modify counter).
|
|
205
|
|
206 The macro counter can be modified via \\[kmacro-set-counter].
|
|
207 The format of the counter can be modified via \\[kmacro-set-format]."
|
|
208 (interactive "p")
|
|
209 (if (or defining-kbd-macro executing-kbd-macro)
|
|
210 (if (and current-prefix-arg (listp current-prefix-arg))
|
|
211 (insert (format kmacro-counter-format kmacro-last-counter))
|
|
212 (insert (format kmacro-counter-format kmacro-counter))
|
|
213 (setq kmacro-last-counter kmacro-counter
|
|
214 kmacro-counter (+ kmacro-counter arg)))
|
|
215 (if (and current-prefix-arg (listp current-prefix-arg))
|
|
216 (setq kmacro-append-to last-kbd-macro)
|
|
217 (setq kmacro-append-to nil
|
|
218 kmacro-counter (if current-prefix-arg arg 0)
|
|
219 kmacro-last-counter kmacro-counter))
|
|
220 (if last-kbd-macro
|
|
221 (let ((len (length kmacro-ring)))
|
|
222 (setq kmacro-ring (cons last-kbd-macro kmacro-ring))
|
|
223 (if (>= len kmacro-ring-max)
|
|
224 (setcdr (nthcdr len kmacro-ring) nil))))
|
|
225 (setq kmacro-counter-format-start kmacro-counter-format)
|
|
226 (start-kbd-macro nil)
|
|
227 (if kmacro-append-to (message "Appending to keyboard macro..."))
|
|
228 ))
|
|
229
|
|
230 (defun kmacro-call-macro (arg)
|
|
231 "End kbd macro if currently being defined; else call last kbd macro.
|
|
232 With numeric prefix argument, repeat macro that many times.
|
|
233 With \\[universal-argument], swap current macro with head of macro ring."
|
|
234 (interactive "p")
|
|
235 (cond
|
|
236 (defining-kbd-macro
|
|
237 (end-kbd-macro)
|
|
238 (if kmacro-append-to
|
|
239 (setq last-kbd-macro (concat kmacro-append-to last-kbd-macro)
|
|
240 kmacro-append-to nil)))
|
|
241 ((and current-prefix-arg (listp current-prefix-arg))
|
|
242 (when kmacro-ring
|
|
243 (let ((head (car kmacro-ring)))
|
|
244 (setq kmacro-ring (cons last-kbd-macro (cdr kmacro-ring)))
|
|
245 (setq last-kbd-macro head)))
|
|
246 (kmacro-display last-kbd-macro))
|
|
247 (t
|
|
248 (setq kmacro-counter-format kmacro-counter-format-start)
|
|
249 (call-last-kbd-macro arg))))
|
|
250
|
|
251 (defun kmacro-call-macro-ring (arg)
|
|
252 "End kbd macro if currently being defined; else call last kbd macro.
|
|
253 With \\[universal-argument], display current macro."
|
|
254 (interactive "p")
|
|
255 (if kmacro-ring
|
|
256 (execute-kbd-macro (car kmacro-ring) arg)))
|
|
257
|
|
258 (defun kmacro-end-call-mouse (event)
|
|
259 "Move point to the position clicked with the mouse and call last kbd macro.
|
|
260 If kbd macro currently being defined end it before activating it."
|
|
261 (interactive "e")
|
|
262 (when defining-kbd-macro
|
|
263 (end-kbd-macro)
|
|
264 (if kmacro-append-to
|
|
265 (setq last-kbd-macro (concat kmacro-append-to last-kbd-macro)
|
|
266 kmacro-append-to nil)))
|
|
267 (mouse-set-point event)
|
|
268 (call-last-kbd-macro nil))
|
|
269
|
|
270 (defun kmacro-cycle-macro-ring (&optional previous)
|
|
271 "Cycle the keyboard macro ring on \\[kmacro-call-macro-ring].
|
|
272 Moves to the next element in the keyboard macro ring.
|
|
273 With \\[universal-argument] prefix, move to the previous element in the ring.
|
|
274 Displays the selected macro in the echo area."
|
|
275 (interactive "p")
|
|
276 (if (null kmacro-ring)
|
|
277 (message "No keymacros in ring")
|
|
278 (cond
|
|
279 ((not (eq this-command last-command))
|
|
280 nil)
|
|
281 ((= (length kmacro-ring) 1)
|
|
282 nil)
|
|
283 (previous
|
|
284 (let* ((len (length kmacro-ring))
|
|
285 (tail (nthcdr (- len 2) kmacro-ring))
|
|
286 (elt (car (cdr tail))))
|
|
287 (setcdr tail nil)
|
|
288 (setq kmacro-ring (cons elt kmacro-ring))))
|
|
289 (t
|
|
290 (let ((elt (car kmacro-ring)))
|
|
291 (setq kmacro-ring (cdr kmacro-ring))
|
|
292 (nconc kmacro-ring (list elt)))))
|
|
293 (kmacro-display (car kmacro-ring))))
|
|
294
|
|
295 (defun kmacro-save-macro-on-key (arg)
|
|
296 "When not defining or executing a macro, offer to save last macro on a key."
|
|
297 (interactive "p")
|
|
298 (if (or defining-kbd-macro executing-kbd-macro)
|
|
299 nil
|
|
300 (or last-kbd-macro
|
|
301 (error "No keyboard macro defined"))
|
|
302 (let ((key-seq (read-key-sequence "Save last macro on key: ")))
|
|
303 (or (equal key-seq "")
|
|
304 (define-key global-map key-seq last-kbd-macro))))
|
|
305 )
|
|
306
|
|
307 (defun kmacro-set-counter (arg)
|
|
308 "Set kmacro-counter to ARG or 0 if missing.
|
|
309 While defining/executing key macro, increase or decrease counter.
|
|
310 With \\[universal-argument], unconditionally set counter to 0."
|
|
311 (interactive "p")
|
|
312 (setq kmacro-counter
|
|
313 (cond ((and current-prefix-arg (listp current-prefix-arg)) 0)
|
|
314 ((or defining-kbd-macro executing-kbd-macro) (+ kmacro-counter arg))
|
|
315 (current-prefix-arg arg)
|
|
316 (t 0))))
|
|
317
|
|
318 (defun kmacro-set-format (format)
|
|
319 "Set macro counter format"
|
|
320 (interactive "sMacro Counter Format (printf format): ")
|
|
321 (setq kmacro-counter-format
|
|
322 (if (equal format "")
|
|
323 "%d"
|
|
324 format))
|
|
325
|
|
326 ;; redefine initial macro counter if we are not executing a macro.
|
|
327 (if (not (or defining-kbd-macro executing-kbd-macro))
|
|
328 (setq kmacro-counter-format-start kmacro-counter-format))
|
|
329 )
|
|
330
|
|
331 (defun kmacro-edit-macro ()
|
|
332 "Edit keyboard macro."
|
|
333 (interactive)
|
|
334 (edit-kbd-macro "\r"))
|
|
335
|
|
336 ;;;###autoload
|
|
337 (defun kmacro-initialize (&optional start-key call-key call-mouse)
|
|
338 "Setup key bindings for the keyboard macro package.
|
|
339 If specified, use keys START-KEY, CALL-KEY, and CALL-MOUSE.
|
|
340 Don't bind to any mouse event if CALL-MOUSE is t.
|
|
341 Otherwise, use customized keys."
|
|
342
|
|
343 (setq start-key (or start-key kmacro-start-key 'f7))
|
|
344 (setq call-key (or call-key kmacro-call-key 'f8))
|
|
345 (setq call-mouse (or call-mouse kmacro-call-mouse-event 'S-mouse-3))
|
|
346
|
|
347 (global-set-key (vector start-key) 'kmacro-start-macro)
|
|
348 (global-set-key (vector (list 'shift start-key)) 'kmacro-set-format)
|
|
349 (global-set-key (vector (list 'control start-key)) 'kmacro-set-counter)
|
|
350 (global-set-key (vector (list 'meta start-key)) 'kmacro-edit-macro)
|
|
351
|
|
352 (global-set-key (vector call-key) 'kmacro-call-macro)
|
|
353 (global-set-key (vector (list 'shift call-key)) 'kmacro-call-macro-ring)
|
|
354 (global-set-key (vector (list 'control call-key)) 'kmacro-cycle-macro-ring)
|
|
355
|
|
356 (unless (eq call-mouse t)
|
|
357 (global-set-key (vector call-mouse) 'kmacro-end-call-mouse)))
|
|
358
|