comparison lisp/utils/edmacro.el @ 151:59463afc5666 r20-3b2

Import from CVS: tag r20-3b2
author cvs
date Mon, 13 Aug 2007 09:37:19 +0200
parents b980b6286996
children 43dd3413c7c7
comparison
equal deleted inserted replaced
150:8ebb1c0f0f6f 151:59463afc5666
3 ;; Copyright (C) 1993, 1994 Free Software Foundation, Inc. 3 ;; Copyright (C) 1993, 1994 Free Software Foundation, Inc.
4 4
5 ;; Author: Dave Gillespie <daveg@synaptics.com> 5 ;; Author: Dave Gillespie <daveg@synaptics.com>
6 ;; Hrvoje Niksic <hniksic@srce.hr> -- XEmacs port 6 ;; Hrvoje Niksic <hniksic@srce.hr> -- XEmacs port
7 ;; Maintainer: Hrvoje Niksic <hniksic@srce.hr> 7 ;; Maintainer: Hrvoje Niksic <hniksic@srce.hr>
8 ;; Version: 3.10 8 ;; Version: 3.14
9 ;; Keywords: abbrev 9 ;; Keywords: abbrev
10 10
11 ;; This file is part of XEmacs. 11 ;; This file is part of XEmacs.
12 12
13 ;; XEmacs is free software; you can redistribute it and/or modify 13 ;; XEmacs is free software; you can redistribute it and/or modify
86 ;; This package requires GNU Emacs 19 or later, and daveg's CL 86 ;; This package requires GNU Emacs 19 or later, and daveg's CL
87 ;; package 2.02 or later. (CL 2.02 comes standard starting with 87 ;; package 2.02 or later. (CL 2.02 comes standard starting with
88 ;; Emacs 19.18.) This package does not work with Emacs 18 or 88 ;; Emacs 19.18.) This package does not work with Emacs 18 or
89 ;; Lucid Emacs. 89 ;; Lucid Emacs.
90 90
91 ;; Ported to XEmacs. -hniksic 91 ;; Ported to XEmacs. This code will not run on GNU Emacs 19. -hniksic
92 92
93 ;;; Code: 93 ;;; Code:
94 94
95 (eval-when-compile 95 (eval-when-compile
96 (require 'cl)) 96 (require 'cl))
97 97
98 (defgroup edmacro nil
99 "Keyboard macro editor."
100 :group 'keyboard)
101
102 (defcustom edmacro-eight-bits nil
103 "*Non-nil if edit-kbd-macro should leave 8-bit characters intact.
104 Default nil means to write characters above \\177 in octal notation."
105 :type 'boolean
106 :group 'edmacro)
107
108 (defcustom edmacro-format-hook nil
109 "*Hook run after formatting the keyboard macro."
110 :type 'hook
111 :group 'edmacro)
112
113 (defvar edmacro-finish-hook nil)
114 (defvar edmacro-store-hook nil)
115 (defvar edmacro-original-buffer nil)
116
98 ;;; The user-level commands for editing macros. 117 ;;; The user-level commands for editing macros.
99 118
100 ;;;###autoload (define-key ctl-x-map "\C-k" 'edit-kbd-macro) 119 ;;;###autoload (define-key ctl-x-map "\C-k" 'edit-kbd-macro)
101
102 ;;;###autoload
103 (defvar edmacro-eight-bits nil
104 "*Non-nil if edit-kbd-macro should leave 8-bit characters intact.
105 Default nil means to write characters above \\177 in octal notation.")
106
107 (if (fboundp 'mapvector)
108 (defalias 'edmacro-mapvector 'mapvector)
109 (defun edmacro-mapvector (fun seq)
110 (map 'vector fun seq)))
111 120
112 (defvar edmacro-mode-map nil) 121 (defvar edmacro-mode-map nil)
113 (unless edmacro-mode-map 122 (unless edmacro-mode-map
114 (setq edmacro-mode-map (make-sparse-keymap)) 123 (setq edmacro-mode-map (make-sparse-keymap))
115 (define-key edmacro-mode-map "\C-c\C-c" 'edmacro-finish-edit) 124 (define-key edmacro-mode-map "\C-c\C-c" 'edmacro-finish-edit)
116 (define-key edmacro-mode-map "\C-c\C-q" 'edmacro-insert-key)) 125 (define-key edmacro-mode-map "\C-c\C-q" 'edmacro-insert-key))
117 126
118 (defvar edmacro-store-hook)
119 (defvar edmacro-finish-hook)
120 (defvar edmacro-original-buffer)
121
122 ;; A lot of cruft here, but I got it to work eventually. Could use
123 ;; some cleaning up.
124 ;;;###autoload 127 ;;;###autoload
125 (defun edit-kbd-macro (keys &optional prefix finish-hook store-hook) 128 (defun edit-kbd-macro (keys &optional prefix finish-hook store-hook)
126 "Edit a keyboard macro. 129 "Edit a keyboard macro.
127 At the prompt, type any key sequence which is bound to a keyboard macro. 130 At the prompt, type any key sequence which is bound to a keyboard macro.
128 Or, type `C-x e' or RET to edit the last keyboard macro, `C-h l' to edit 131 Or, type `C-x e' or RET to edit the last keyboard macro, `C-h l' to edit
129 the last 100 keystrokes as a keyboard macro, or `M-x' to edit a macro by 132 the last 100 keystrokes as a keyboard macro, or `M-x' to edit a macro by
130 its command name. 133 its command name.
131 With a prefix argument, format the macro in a more concise way." 134 With a prefix argument, format the macro in a more concise way."
132 (interactive "kKeyboard macro to edit (C-x e, M-x, C-h l, or keys): \nP") 135 (interactive "kKeyboard macro to edit (C-x e, M-x, C-h l, or keys): \nP")
133 (when keys 136 (when (vectorp keys)
134 (setq keys (edmacro-events-to-keys keys)) 137 (setq keys (edmacro-events-to-keys keys)))
135 (let ((cmd (if (arrayp keys) (key-binding keys) keys)) 138 (let ((cmd (if (symbolp keys) keys (key-binding keys)))
136 (mac nil)) 139 (mac nil))
137 (cond (store-hook 140 (cond (store-hook
138 (setq mac keys) 141 (setq mac keys)
139 (setq cmd nil)) 142 (setq cmd nil))
140 ((or (eq cmd 'call-last-kbd-macro) 143 ((or (eq cmd 'call-last-kbd-macro)
141 (and (arrayp keys) 144 (and (arrayp keys)
142 (= 1 (length keys)) 145 (= 1 (length keys))
143 (eq ?\r (aref keys 0)))) 146 (or (eq 'return (aref keys 0))
144 (or last-kbd-macro 147 (eq ?\r (aref keys 0))
145 (y-or-n-p "No keyboard macro defined. Create one? ") 148 (equal '(control ?m) (aref keys 0)))))
146 (keyboard-quit)) 149 (or last-kbd-macro
147 (setq mac (or last-kbd-macro "")) 150 (y-or-n-p "No keyboard macro defined. Create one? ")
148 (setq cmd 'last-kbd-macro)) 151 (keyboard-quit))
149 ((eq cmd 'execute-extended-command) 152 (setq mac (or last-kbd-macro []))
150 (setq cmd (read-command "Name of keyboard macro to edit: ")) 153 (setq cmd 'last-kbd-macro))
151 (if (string-equal cmd "") 154 ((eq cmd 'execute-extended-command)
152 (error "No command name given")) 155 (setq cmd (edmacro-minibuf-read "Name of keyboard macro to edit: "))
153 (setq mac (symbol-function cmd))) 156 (if (string-equal cmd "")
154 ((eq cmd 'view-lossage) 157 (error "No command name given"))
155 (setq mac (recent-keys)) 158 (setq mac (symbol-function cmd)))
156 (setq cmd 'last-kbd-macro)) 159 ((eq cmd 'view-lossage)
157 ((null cmd) 160 (setq mac (recent-keys))
158 (error "Key sequence %s is not defined" (key-description keys))) 161 (setq cmd 'last-kbd-macro))
159 ((symbolp cmd) 162 ((null cmd)
160 (setq mac (symbol-function cmd))) 163 (error "Key sequence `%s' is not defined" (key-description keys)))
161 (t 164 ((symbolp cmd)
162 (setq mac cmd) 165 (setq mac (symbol-function cmd)))
163 (setq cmd nil))) 166 (t
164 (unless (arrayp mac) 167 (setq mac cmd)
165 (error "Key sequence %s is not a keyboard macro" 168 (setq cmd nil)))
166 (key-description keys))) 169 (unless (arrayp mac)
167 (message "Formatting keyboard macro...") 170 (error "Key sequence `%s' is not a keyboard macro"
168 (let* ((oldbuf (current-buffer)) 171 (key-description keys)))
169 (mmac (edmacro-fix-menu-commands mac)) 172 (message "Formatting keyboard macro...")
170 (fmt (edmacro-format-keys mmac 1)) 173 (let ((oldbuf (current-buffer))
171 (fmtv (edmacro-format-keys mmac (not prefix))) 174 (fmt (edmacro-format-keys mac))
172 (buf (get-buffer-create "*Edit Macro*"))) 175 (fmtv (edmacro-format-keys mac (not prefix)))
173 (message "Formatting keyboard macro...done") 176 (buf (get-buffer-create "*Edit Macro*")))
174 (switch-to-buffer buf) 177 (message "Formatting keyboard macro...done")
175 (kill-all-local-variables) 178 (switch-to-buffer buf)
176 (use-local-map edmacro-mode-map) 179 (kill-all-local-variables)
177 (setq buffer-read-only nil) 180 (use-local-map edmacro-mode-map)
178 (setq major-mode 'edmacro-mode) 181 (setq buffer-read-only nil)
179 (setq mode-name "Edit Macro") 182 (setq major-mode 'edmacro-mode)
180 (set (make-local-variable 'edmacro-original-buffer) oldbuf) 183 (setq mode-name "Edit Macro")
181 (set (make-local-variable 'edmacro-finish-hook) finish-hook) 184 (set (make-local-variable 'edmacro-original-buffer) oldbuf)
182 (set (make-local-variable 'edmacro-store-hook) store-hook) 185 (set (make-local-variable 'edmacro-finish-hook) finish-hook)
183 (erase-buffer) 186 (set (make-local-variable 'edmacro-store-hook) store-hook)
184 (insert ";; Keyboard Macro Editor. Press C-c C-c to finish; " 187 (erase-buffer)
185 "press C-x k RET to cancel.\n") 188 (insert ";; Keyboard Macro Editor. Press C-c C-c to finish; "
186 (insert ";; Original keys: " fmt "\n") 189 "press C-x k RET to cancel.\n")
187 (unless store-hook 190 (insert ";; Original keys: " fmt "\n")
188 (insert "\nCommand: " (if cmd (symbol-name cmd) "none") "\n") 191 (unless store-hook
189 (let ((keys (where-is-internal (or cmd mac)))) 192 (insert "\nCommand: " (if cmd (symbol-name cmd) "none") "\n")
190 (if keys 193 (let ((keys (where-is-internal (or cmd mac))))
191 (while keys 194 (if keys
192 (insert "Key: " (edmacro-format-keys (pop keys) 1) "\n")) 195 (insert "Key: " (edmacro-format-keys (car keys)) "\n")
193 (insert "Key: none\n")))) 196 (insert "Key: none\n"))))
194 (insert "\nMacro:\n\n") 197 (insert "\nMacro:\n\n")
195 (save-excursion 198 (save-excursion
196 (insert fmtv "\n")) 199 (insert fmtv "\n"))
197 (recenter '(4)) 200 (recenter '(4))
198 (when (eq mac mmac) 201 (run-hooks 'edmacro-format-hook))))
199 (set-buffer-modified-p nil))
200 (run-hooks 'edmacro-format-hook)))))
201 202
202 ;;; The next two commands are provided for convenience and backward 203 ;;; The next two commands are provided for convenience and backward
203 ;;; compatibility. 204 ;;; compatibility.
204 205
205 ;;;###autoload 206 ;;;###autoload
226 the result is returned rather than being installed as the current macro. 227 the result is returned rather than being installed as the current macro.
227 The result will be a string if possible, otherwise an event vector. 228 The result will be a string if possible, otherwise an event vector.
228 Second argument NEED-VECTOR means to return an event vector always." 229 Second argument NEED-VECTOR means to return an event vector always."
229 (interactive "r") 230 (interactive "r")
230 (if (stringp start) 231 (if (stringp start)
231 (edmacro-parse-keys start end) 232 (edmacro-parse-keys start)
232 (setq last-kbd-macro (edmacro-parse-keys (buffer-substring start end))))) 233 (setq last-kbd-macro (edmacro-parse-keys (buffer-substring start end)))))
233 234
234 ;;;###autoload 235 ;;;###autoload
235 (defmacro kbd (keys) 236 (defmacro kbd (keys)
236 "Convert KEYS to the internal Emacs key representation." 237 "Convert KEYS to the internal Emacs key representation."
243 Second argument VERBOSE means to put one command per line with comments. 244 Second argument VERBOSE means to put one command per line with comments.
244 If VERBOSE is `1', put everything on one line. If VERBOSE is omitted 245 If VERBOSE is `1', put everything on one line. If VERBOSE is omitted
245 or nil, use a compact 80-column format." 246 or nil, use a compact 80-column format."
246 (and macro (symbolp macro) (setq macro (symbol-function macro))) 247 (and macro (symbolp macro) (setq macro (symbol-function macro)))
247 (edmacro-format-keys (or macro last-kbd-macro) verbose)) 248 (edmacro-format-keys (or macro last-kbd-macro) verbose))
249
248 250
249 ;;; Commands for *Edit Macro* buffer. 251 ;;; Commands for *Edit Macro* buffer.
250 252
251 (defun edmacro-finish-edit () 253 (defun edmacro-finish-edit ()
252 (interactive) 254 (interactive)
287 (let ((b (key-binding key))) 289 (let ((b (key-binding key)))
288 (and b (commandp b) (not (arrayp b)) 290 (and b (commandp b) (not (arrayp b))
289 (or (not (fboundp b)) 291 (or (not (fboundp b))
290 (not (arrayp (symbol-function b)))) 292 (not (arrayp (symbol-function b))))
291 (not (y-or-n-p 293 (not (y-or-n-p
292 (format "Key %s is already defined; %s" 294 (format
293 (edmacro-format-keys key 1) 295 "Key `%s' is already defined; %s"
294 "proceed? "))) 296 (edmacro-format-keys key)
297 "proceed? ")))
295 (keyboard-quit)))))) 298 (keyboard-quit))))))
296 t) 299 t)
297 ((looking-at "Macro:[ \t\n]*") 300 ((looking-at "Macro:[ \t\n]*")
298 (goto-char (match-end 0)) 301 (goto-char (match-end 0))
299 nil) 302 nil)
303 (setq top (point))) 306 (setq top (point)))
304 (let* ((buf (current-buffer)) 307 (let* ((buf (current-buffer))
305 (str (buffer-substring top (point-max))) 308 (str (buffer-substring top (point-max)))
306 (modp (buffer-modified-p)) 309 (modp (buffer-modified-p))
307 (obuf edmacro-original-buffer) 310 (obuf edmacro-original-buffer)
308 (store-hook edmacro-store-hook) 311 (store-hook edmacro-store-hook))
309 (finish-hook edmacro-finish-hook))
310 (unless (or cmd keys store-hook (equal str "")) 312 (unless (or cmd keys store-hook (equal str ""))
311 (error "No command name or keys specified")) 313 (error "No command name or keys specified"))
312 (when modp 314 (when modp
313 (when (buffer-name obuf) 315 (when (buffer-name obuf)
314 (set-buffer obuf)) 316 (set-buffer obuf))
333 (loop for key in keys do (global-unset-key key)) 335 (loop for key in keys do (global-unset-key key))
334 (loop for key in keys do 336 (loop for key in keys do
335 (global-set-key key (or cmd mac))))))))) 337 (global-set-key key (or cmd mac)))))))))
336 (kill-buffer buf) 338 (kill-buffer buf)
337 (when (buffer-name obuf) 339 (when (buffer-name obuf)
338 (switch-to-buffer obuf)) 340 (switch-to-buffer obuf)))))
339 (when finish-hook
340 (funcall finish-hook)))))
341 341
342 (defun edmacro-insert-key (key) 342 (defun edmacro-insert-key (key)
343 "Insert the written name of a key in the buffer." 343 "Insert the written name of a key in the buffer."
344 (interactive "kKey to insert: ") 344 (interactive "kKey to insert: ")
345 (if (bolp) 345 (if (bolp)
419 is seven keys but `<right>' is a single function key. When in 419 is seven keys but `<right>' is a single function key. When in
420 doubt, use whitespace." 420 doubt, use whitespace."
421 (interactive) 421 (interactive)
422 (error "This mode can be enabled only by `edit-kbd-macro'")) 422 (error "This mode can be enabled only by `edit-kbd-macro'"))
423 (put 'edmacro-mode 'mode-class 'special) 423 (put 'edmacro-mode 'mode-class 'special)
424
424 425
425
426 (defun edmacro-int-char (int) 426 (defun edmacro-int-char (int)
427 (if (fboundp 'char-to-int) 427 (if (fboundp 'int-char)
428 (char-to-int int) 428 (int-char int)
429 int)) 429 int))
430 430
431 (defvar edmacro-read-history nil)
432
433 ;; Completing read on named keyboard macros only.
434 (defun edmacro-minibuf-read (prompt)
435 (intern (completing-read
436 prompt obarray
437 (lambda (arg)
438 (and (commandp arg)
439 (vectorp (symbol-function arg))))
440 t nil 'edmacro-read-history)))
441
431 442
443 (defvar edmacro-char-to-word
444 '((?\0 . "NUL")
445 (?\r . "RET")
446 (?\n . "LFD")
447 (?\t . "TAB")
448 (?\e . "ESC")
449 (?\ . "SPC")
450 (?\C-? . "DEL")))
451
452 (defvar edmacro-modifiers
453 '(("C" . control)
454 ("M" . meta)
455 ("S" . shift)
456 ("Sh" . shift)
457 ("A" . alt)
458 ("H" . hyper)
459 ("s" . super)))
460
432 ;;; Parsing a human-readable keyboard macro. 461 ;;; Parsing a human-readable keyboard macro.
433 462
434 ;; Changes for XEmacs -- these two functions re-written from scratch. 463 ;; Changes for XEmacs -- these two functions re-written from scratch.
435 ;; edmacro-parse-keys always returns a vector. edmacro-format-keys 464 ;; edmacro-parse-keys always returns a vector. edmacro-format-keys
436 ;; accepts a vector (but works with a string too). Vector may contain 465 ;; accepts a vector (but works with a string too). Vector may contain
437 ;; keypress events. -hniksic 466 ;; keypress events. -hniksic
438 (defun edmacro-parse-keys (string &optional ignored) 467 (defun edmacro-parse-keys (string)
439 (let* ((pos 0) 468 (let* ((pos 0)
440 (case-fold-search nil) 469 (case-fold-search nil)
441 (word-to-sym '(("NUL" . ?\0)
442 ("RET" . return)
443 ("LFD" . linefeed)
444 ("TAB" . tab)
445 ("ESC" . escape)
446 ("SPC" . space)
447 ("BS" . backspace)
448 ("DEL" . delete)))
449 (char-to-word '((?\0 . "NUL")
450 (?\r . "RET")
451 (?\n . "LFD")
452 (?\t . "TAB")
453 (?\e . "ESC")
454 (?\ . "SPC")
455 (?\C-? . "DEL")))
456 (modifier-prefix-alist '(("C" . control)
457 ("M" . meta)
458 ("S" . shift)
459 ("Sh" . shift)
460 ("A" . alt)
461 ("H" . hyper)
462 ("s" . super)))
463 ;; string-to-symbol-or-char converter
464 (conv (lambda (arg)
465 (if (= (length arg) 1)
466 (aref arg 0)
467 (if (string-match "^<\\([^>]+\\)>$" arg)
468 (setq arg (match-string 1 arg)))
469 (let ((match (assoc arg word-to-sym)))
470 (if match
471 (cdr match)
472 (intern arg))))))
473 (conv-chars (lambda (arg)
474 (let ((match (assoc arg char-to-word)))
475 (if match
476 (cdr (assoc (cdr match) word-to-sym))
477 arg))))
478 res) 470 res)
479 (while (and (< pos (length string)) 471 (while (and (< pos (length string))
480 (string-match "[^ \t\n\f]+" string pos)) 472 (string-match "[^ \t\r\n\f]+" string pos))
481 (let ((word (substring string (match-beginning 0) (match-end 0))) 473 (let ((word (substring string (match-beginning 0) (match-end 0))))
482 (times 1)
483 (force-sym nil)
484 (add nil)
485 match)
486 (setq pos (match-end 0)) 474 (setq pos (match-end 0))
487 (when (string-match "\\([0-9]+\\)\\*." word) 475 (if (or (equal word "REM") (string-match "^;;" word))
488 (setq times (string-to-int (substring word 0 (match-end 1)))) 476 ;; Comment (discard to EOL) .
489 (setq word (substring word (1+ (match-end 1))))) 477 (setq pos (string-match "$" string pos))
490 (when (string-match "^<\\([^<>]+\\)>$" word) 478 (push (edmacro-parse-word word) res))))
491 (setq word (match-string 1 word)) 479 (mapvector 'identity (apply 'nconc (nreverse res)))))
492 (setq force-sym t)) 480
493 (setq match (assoc word word-to-sym)) 481 ;; Parse a word.
494 ;; Add an element; `add' holds the list of elements to be 482 (defun edmacro-parse-word (word)
495 ;; added. 483 (let ((force-sym nil)
496 (cond ((string-match "^\\\\[0-7]+" word) 484 (times 1)
497 ;; Octal value of character. 485 abbr)
498 (setq add 486 (when (string-match "\\([0-9]+\\)\\*." word)
499 (list 487 (setq times (string-to-int (substring word 0 (match-end 1))))
500 (edmacro-int-char 488 (setq word (substring word (1+ (match-end 1)))))
501 (edmacro-octal-string-to-integer (substring word 1)))))) 489 (when (string-match "^<\\([^<>]+\\)>$" word)
502 ((string-match "^<<.+>>$" word) 490 (setq word (match-string 1 word))
503 ;; Extended command. 491 (setq force-sym t))
504 (setq add 492 (let* ((word-to-sym '(("NUL" . ?\0)
505 (nconc 493 ("RET" . return)
506 (list 494 ("LFD" . linefeed)
507 (if (eq (key-binding [(meta x)]) 495 ("TAB" . tab)
508 'execute-extended-command) 496 ("ESC" . escape)
509 '(meta x) 497 ("SPC" . space)
510 (or (car (where-is-internal 498 ("BS" . backspace)
511 'execute-extended-command)) 499 ("DEL" . delete)))
512 '(meta x)))) 500 (conv (lambda (arg)
513 (mapcar conv-chars (concat (substring word 2 -2) "\r"))) 501 ;; string-to-symbol-or-char converter
514 )) 502 (if (= (length arg) 1)
515 ((or (equal word "REM") (string-match "^;;" word)) 503 (aref arg 0)
516 ;; Comment (discard to EOL) . 504 (if (string-match "^<\\([^>]+\\)>$" arg)
517 (setq pos (string-match "$" string pos))) 505 (setq arg (match-string 1 arg)))
518 (match 506 (let ((match (assoc arg word-to-sym)))
519 ;; Convert to symbol. 507 (if match
520 (setq add (list (cdr match)))) 508 (cdr match)
521 ((string-match "^\\^" word) 509 (intern arg))))))
522 ;; ^X == C-x 510 (conv-chars (lambda (arg)
523 (if (/= (length word) 2) 511 (let ((match (assoc arg edmacro-char-to-word)))
524 (error "^ must be followed by one character")) 512 (if match
525 (setq add (list 'control (aref word 0)))) 513 (cdr (assoc (cdr match) word-to-sym))
526 ((string-match "^\\([MCSsAH]\\|Sh\\)-" word) 514 arg))))
527 ;; Parse C-* and stuff 515 (add
528 (setq 516 (cond
529 add 517 ((string-match "^\\\\[0-7]+" word)
530 (list 518 ;; Octal value of character.
531 (let ((pos1 0) 519 (list
532 (r1 nil) 520 (edmacro-int-char
533 follow curpart prefix) 521 (hexl-octal-string-to-integer (substring word 1)))))
534 (while (progn (setq curpart (substring word pos1)) 522 ((string-match "^<<.+>>$" word)
535 (string-match "^\\([MCSsAH]\\|Sh\\)-" 523 ;; Extended command.
536 curpart)) 524 (nconc
537 (setq prefix (assoc (match-string 1 curpart) 525 (list
538 modifier-prefix-alist)) 526 (if (eq (key-binding [(meta x)])
539 (setq r1 (nconc r1 (list (cdr prefix)))) 527 'execute-extended-command)
540 (callf + pos1 (1+ (length (car prefix))))) 528 '(meta x)
541 (setq follow (substring word pos1)) 529 (or (car (where-is-internal
542 (if (equal follow "") 530 'execute-extended-command))
543 (error "%s must precede a string" 531 '(meta x))))
544 (substring word 0 pos1))) 532 (mapcar conv-chars (concat (substring word 2 -2) "\r"))))
545 (nconc r1 (list (funcall conv follow))))))) 533 ((setq abbr (assoc word word-to-sym))
546 (force-sym 534 ;; Convert to symbol.
547 ;; This must be a symbol 535 (list (cdr abbr)))
548 (setq add (list (intern word)))) 536 ((string-match "^\\^" word)
549 (t 537 ;; ^X == C-x
550 ;; Characters 538 (if (/= (length word) 2)
551 (setq add (mapcar conv-chars word)))) 539 (error "^ must be followed by one character"))
552 (let ((new nil)) 540 `((control ,(aref word 1))))
553 (loop repeat times do (setq new (append new add))) 541 ((string-match "^\\([MCSsAH]\\|Sh\\)-" word)
554 (setq add new)) 542 ;; Parse C-* and stuff
555 (setq res (nconc res add)))) 543 (list
556 (edmacro-mapvector 'identity res))) 544 (let ((pos1 0)
557 545 (r1 nil)
546 follow curpart prefix)
547 (while (progn (setq curpart (substring word pos1))
548 (string-match "^\\([MCSsAH]\\|Sh\\)-"
549 curpart))
550 (setq prefix (assoc (match-string 1 curpart)
551 edmacro-modifiers))
552 (push (cdr prefix) r1)
553 (incf pos1 (1+ (length (car prefix)))))
554 (setq follow (substring word pos1))
555 (if (equal follow "")
556 (error "%s must precede a string"
557 (substring word 0 pos1)))
558 (nconc (nreverse r1) (list (funcall conv follow))))))
559 (force-sym
560 ;; This must be a symbol
561 (list (intern word)))
562 (t
563 ;; Characters
564 (mapcar conv-chars word))))
565 (new nil))
566 (loop repeat times do (setq new (append add new)))
567 new)))
568
569 ;; Convert the keypress events in vector x to keys, and return a
570 ;; vector of keys. If a list element is not a keypress event, ignore
571 ;; it.
572 (defun edmacro-events-to-keys (x &optional list)
573 (let (new)
574 (mapc (lambda (el)
575 (cond ((key-press-event-p el)
576 (push (let ((mods (event-modifiers el)))
577 (if mods
578 (append mods (list (event-key el)))
579 (event-key el)))
580 new))
581 ((or (characterp el)
582 (symbolp el)
583 (listp el))
584 (push el new))))
585 x)
586 (setq new (nreverse new))
587 (if list
588 new
589 (mapvector 'identity new))))
590
591 ;; Collapse a list of keys into a list of function keys, where
592 ;; applicable.
593 (defun edmacro-fkeys (keys)
594 (let (new k lookup)
595 (while keys
596 (setq k (nconc k (list (car keys))))
597 (setq lookup (lookup-key function-key-map (mapvector 'identity k)))
598 (cond ((vectorp lookup)
599 (push (mapcar 'identity lookup) new)
600 (setq k nil))
601 ((keymapp lookup)
602 nil)
603 ((null lookup)
604 (push k new)
605 (setq k nil))
606 (t
607 (setq k nil)))
608 (pop keys))
609 (when (keymapp lookup)
610 (push k new))
611 (apply 'nconc (nreverse new))))
612
613 ;; Convert a character or symbol to string
558 (defun edmacro-conv (char-or-sym add-<>) 614 (defun edmacro-conv (char-or-sym add-<>)
559 (let ((char-to-word '((?\0 . "NUL") 615 (let ((char-to-word '((?\0 . "NUL")
560 (?\r . "RET") 616 (?\r . "RET")
561 (?\n . "LFD") 617 (?\n . "LFD")
562 (?\t . "TAB") 618 (?\t . "TAB")
595 (defun edmacro-format-1 (keys command times togetherp) 651 (defun edmacro-format-1 (keys command times togetherp)
596 (let ((res "") 652 (let ((res "")
597 (start keys) 653 (start keys)
598 el) 654 el)
599 (while keys 655 (while keys
600 (unless (or (eq start keys) togetherp) 656 (when (or (eq (car keys) ?-)
657 (eq (car keys) '-)
658 (not (or togetherp (eq start keys))))
601 (callf concat res " ")) 659 (callf concat res " "))
602 (if (> times 1) 660 (if (> times 1)
603 (setq res (concat (format "%d*" times) res))) 661 (setq res (concat (format "%d*" times) res)))
604 (setq el (car keys)) 662 (setq el (car keys))
605 (callf concat res 663 (callf concat res
606 (cond ((listp el) 664 (cond ((listp el)
607 (let ((my "")) 665 (let ((my ""))
608 (if (or 666 (if (or
609 (let (cnv) 667 (let (cnv)
610 (while el 668 (while el
611 (let ((found (assq (car el) 669 (let ((found (find (car el) edmacro-modifiers
612 '((control . "C-") 670 :key 'cdr)))
613 (meta . "M-")
614 (shift . "S-")
615 (alt . "A-")
616 (hyper . "H-")
617 (super . "s-")))))
618 (callf concat my 671 (callf concat my
619 (if found 672 (if found
620 (cdr found) 673 (concat (car found) "-")
621 (setq cnv (edmacro-conv (car el) nil)) 674 (setq cnv (edmacro-conv (car el) nil))
622 (cdr cnv)))) 675 (cdr cnv))))
623 (setq el (cdr el))) 676 (pop el))
624 (car cnv)) 677 (car cnv))
625 (> times 1)) 678 (> times 1))
626 (concat "<" my ">") 679 (concat "<" my ">")
627 my))) 680 my)))
628 (t 681 (t
629 (cdr (edmacro-conv el t))))) 682 (cdr (edmacro-conv el t)))))
630 (setq keys (cdr keys))) 683 (pop keys))
631 (if command 684 (if command
632 (callf concat res 685 (callf concat res
633 (concat 686 (make-string (max (- 3 (/ (length res) tab-width)) 1) ?\t)
634 (make-string (max (- 3 (/ (length res) tab-width)) 1) ?\t) 687 ";; "
635 ";; " 688 (symbol-name command)
636 (symbol-name command) 689 (if togetherp (format " * %d" (length start)))))
637 (if togetherp (format " * %d" (length start))))))
638 res)) 690 res))
639 691
640 ;; Convert the keypress events in vector x to keys, and return a 692 (defsubst edmacro-seq-equal (seq1 seq2)
641 ;; vector of keys. If a list element is not a keypress event, ignore 693 (while (and seq1 seq2
642 ;; it. 694 (equal (car seq1) (car seq2)))
643 (defun edmacro-events-to-keys (x) 695 (pop seq1)
644 (if (or (not (fboundp 'events-to-keys)) 696 (pop seq2))
645 (not (arrayp x))) 697 (not seq1))
646 x
647 (let ((cnt 0)
648 (len (length x))
649 new el)
650 (while (< cnt len)
651 (setq el (aref x cnt))
652 (cond ((eventp el)
653 (if (mouse-event-p el)
654 (setq el nil)
655 (setq el (aref (events-to-keys (vector el)) 0))))
656 (t
657 nil)) ; leave it be.
658 (if el
659 (setq new (nconc new (list el))))
660 (incf cnt))
661 (edmacro-mapvector 'identity new))))
662
663 ;; Collapse a list of keys into a list of function keys, where
664 ;; applicable.
665 (defun edmacro-fkeys (keys)
666 (let (new k lookup)
667 (while keys
668 (setq k (nconc k (list (car keys))))
669 (setq lookup (lookup-key function-key-map (edmacro-mapvector 'identity k)))
670 (cond ((vectorp lookup)
671 (setq new (nconc new (mapcar 'identity lookup)))
672 (setq k nil))
673 ((keymapp lookup)
674 nil)
675 ((null lookup)
676 (setq new (nconc new k))
677 (setq k nil))
678 (t
679 (setq k nil)))
680 (setq keys (cdr keys)))
681 (if (keymapp lookup)
682 (setq new (nconc new k)))
683 new))
684 698
685 ;;; Formatting a keyboard macro as human-readable text. 699 ;;; Formatting a keyboard macro as human-readable text.
686 700
687 (defun edmacro-format-keys (macro &optional verbose) 701 (defun edmacro-format-keys (macro &optional verbose)
688 ;; XEmacs: 702 ;; XEmacs:
689 ;; If we're dealing with events, convert them to symbols first. 703 ;; If we're dealing with events, convert them to symbols first;
690 (setq macro (edmacro-events-to-keys macro)) 704 ;; also, deal with Fkeys.
691 (if (zerop (length macro)) 705 (setq macro (edmacro-fkeys (edmacro-events-to-keys macro t)))
692 "" 706 (let ((res ""))
693 (let ((res "")) 707 (while macro
694 ;; I'm not sure I understand the original code, but this seems to 708 (let (key lookup (times 1) self-insert-p)
695 ;; work. 709 (loop
696 (and (eq verbose 1) 710 do (setq key (nconc key (list (car macro)))
697 (setq verbose nil)) 711 macro (cdr macro)
698 712 lookup (lookup-key global-map (mapvector
699 ;; We prefer a list -- much easier to process... 713 'identity key)))
700 (setq macro (mapcar 'identity macro)) 714 while (and macro lookup (not (commandp lookup))))
701 (setq macro (edmacro-fkeys macro)) 715 ;; keyboard macro
702 (while macro 716 (if (vectorp lookup)
703 (let (key lookup (times 1) self-insert-p) 717 (setq lookup nil))
704 (loop do 718 (if (and (eq lookup 'self-insert-command)
705 (setq key (nconc key (list (car macro))) 719 (= (length key) 1)
706 macro (cdr macro) 720 (not (memq (car key)
707 lookup (lookup-key global-map (edmacro-mapvector 721 '(?\ ?\r ?\n space return linefeed tab))))
708 'identity key))) 722 (while (and (< (length key) 23)
709 while 723 (eq (lookup-key global-map (car macro))
710 (and macro lookup (not (commandp lookup)))) 724 'self-insert-command)
711 ;; keyboard macro 725 (not (memq
712 (if (vectorp lookup) 726 (car macro)
713 (setq lookup nil))
714 (if (and (eq lookup 'self-insert-command)
715 (= (length key) 1)
716 (not (memq (car key)
717 '(?\ ?\r ?\n space return linefeed tab)))) 727 '(?\ ?\r ?\n space return linefeed tab))))
718 (while (and (< (length key) 23) 728 (setq key (nconc key (list (car macro)))
719 (eq (lookup-key global-map (car macro)) 729 macro (cdr macro)
720 'self-insert-command) 730 self-insert-p t))
721 (not (memq 731 (let ((keysize (length key)))
722 (car macro)
723 '(?\ ?\r ?\n space return linefeed tab))))
724 (setq key (nconc key (list (car macro)))
725 macro (cdr macro)
726 self-insert-p t))
727 (while (edmacro-seq-equal key macro) 732 (while (edmacro-seq-equal key macro)
728 (setq macro (nthcdr (length key) macro)) 733 (setq macro (nthcdr keysize macro))
729 (incf times))) 734 (incf times))))
730 (if (or self-insert-p 735 (if (or self-insert-p
731 (null (cdr key)) 736 (null (cdr key))
732 (= times 1)) 737 (= times 1))
733 (callf concat res (edmacro-format-1 key (if verbose lookup 738 (callf concat res
734 nil) 739 (edmacro-format-1 key (if verbose lookup
735 times self-insert-p) 740 nil)
736 (and macro (if verbose "\n" " "))) 741 times self-insert-p)
737 (loop repeat times 742 (and macro (if verbose "\n" " ")))
738 do 743 (loop
739 (callf concat res 744 repeat times
740 (edmacro-format-1 key (if verbose lookup 745 do
741 nil) 746 (callf concat res
742 1 self-insert-p) 747 (edmacro-format-1 key (if verbose lookup
743 (and macro (if verbose "\n" " "))))))) 748 nil)
744 res))) 749 1 self-insert-p)
745 750 (and macro (if verbose "\n" " ")))))))
746 (defun edmacro-seq-equal (seq1 seq2) 751 res))
747 (while (and seq1 seq2
748 (equal (car seq1) (car seq2)))
749 (setq seq1 (cdr seq1)
750 seq2 (cdr seq2)))
751 (not seq1))
752
753 (defsubst edmacro-oct-char-to-integer (character)
754 "Take a char and return its value as if it was a octal digit."
755 (if (and (>= character ?0) (<= character ?7))
756 (- character ?0)
757 (error (format "Invalid octal digit `%c'." character))))
758
759 (defun edmacro-octal-string-to-integer (octal-string)
760 "Return decimal integer for OCTAL-STRING."
761 (interactive "sOctal number: ")
762 (let ((oct-num 0))
763 (while (not (equal octal-string ""))
764 (setq oct-num (+ (* oct-num 8)
765 (edmacro-oct-char-to-integer
766 (string-to-char octal-string))))
767 (setq octal-string (substring octal-string 1)))
768 oct-num))
769
770
771 (defun edmacro-fix-menu-commands (macro)
772 (when (vectorp macro)
773 (let ((i 0) ev)
774 (while (< i (length macro))
775 (when (and (consp (setq ev (aref macro i)))
776 (not (memq (car ev) ; ha ha
777 '(hyper super meta alt control shift))))
778 (cond ((equal (cadadr ev) '(menu-bar))
779 (setq macro (vconcat (edmacro-subseq macro 0 i)
780 (vector 'menu-bar (car ev))
781 (edmacro-subseq macro (1+ i))))
782 (incf i))
783 ;; It would be nice to do pop-up menus, too, but not enough
784 ;; info is recorded in macros to make this possible.
785 (t
786 (error "Macros with mouse clicks are not %s"
787 "supported by this command"))))
788 (incf i))))
789 macro)
790 752
791 753
792 ;;; The following probably ought to go in macros.el: 754 ;;; The following probably ought to go in macros.el:
793 755
794 ;;;###autoload 756 ;;;###autoload
820 (insert "))\n") 782 (insert "))\n")
821 (if keys 783 (if keys
822 (let ((keys (where-is-internal macroname))) 784 (let ((keys (where-is-internal macroname)))
823 (while keys 785 (while keys
824 (insert (format "(global-set-key %S '%s)\n" (car keys) macroname)) 786 (insert (format "(global-set-key %S '%s)\n" (car keys) macroname))
825 (setq keys (cdr keys))))))) 787 (pop keys))))))
826 788
827 (provide 'edmacro) 789 (provide 'edmacro)
828 790
829 ;;; edmacro.el ends here 791 ;;; edmacro.el ends here