Mercurial > hg > xemacs-beta
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 |