Mercurial > hg > xemacs-beta
diff lisp/utils/edmacro.el @ 22:8fc7fe29b841 r19-15b94
Import from CVS: tag r19-15b94
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:50:29 +0200 |
parents | |
children | 4103f0995bd7 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/utils/edmacro.el Mon Aug 13 08:50:29 2007 +0200 @@ -0,0 +1,715 @@ +;;; edmacro.el --- keyboard macro editor + +;; Copyright (C) 1993, 1994 Free Software Foundation, Inc. + +;; Author: Dave Gillespie <daveg@synaptics.com> +;; Maintainer: Dave Gillespie <daveg@synaptics.com> +;; Version: 2.01 +;; Keywords: abbrev + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;;; Usage: +;; +;; The `C-x C-k' (`edit-kbd-macro') command edits a keyboard macro +;; in a special buffer. It prompts you to type a key sequence, +;; which should be one of: +;; +;; * RET or `C-x e' (call-last-kbd-macro), to edit the most +;; recently defined keyboard macro. +;; +;; * `M-x' followed by a command name, to edit a named command +;; whose definition is a keyboard macro. +;; +;; * `C-h l' (view-lossage), to edit the 100 most recent keystrokes +;; and install them as the "current" macro. +;; +;; * any key sequence whose definition is a keyboard macro. +;; +;; This file includes a version of `insert-kbd-macro' that uses the +;; more readable format defined by these routines. +;; +;; Also, the `read-kbd-macro' command parses the region as +;; a keyboard macro, and installs it as the "current" macro. +;; This and `format-kbd-macro' can also be called directly as +;; Lisp functions. + +;; Type `C-h m', or see the documentation for `edmacro-mode' below, +;; for information about the format of written keyboard macros. + +;; `edit-kbd-macro' formats the macro with one command per line, +;; including the command names as comments on the right. If the +;; formatter gets confused about which keymap was used for the +;; characters, the command-name comments will be wrong but that +;; won't hurt anything. + +;; With a prefix argument, `edit-kbd-macro' will format the +;; macro in a more concise way that omits the comments. + +;; This package requires GNU Emacs 19 or later, and daveg's CL +;; package 2.02 or later. (CL 2.02 comes standard starting with +;; Emacs 19.18.) This package does not work with Emacs 18 or +;; Lucid Emacs. + +;; You bet it does. -hniksic + +;;; Code: + +(eval-when-compile + (require 'cl)) + +;;; The user-level commands for editing macros. + +;;;###autoload (define-key ctl-x-map "\C-k" 'edit-kbd-macro) + +;;;###autoload +(defvar edmacro-eight-bits nil + "*Non-nil if edit-kbd-macro should leave 8-bit characters intact. +Default nil means to write characters above \\177 in octal notation.") + +(defvar edmacro-mode-map nil) +(unless edmacro-mode-map + (setq edmacro-mode-map (make-sparse-keymap)) + (define-key edmacro-mode-map "\C-c\C-c" 'edmacro-finish-edit) + (define-key edmacro-mode-map "\C-c\C-q" 'edmacro-insert-key)) + +(defvar edmacro-store-hook) +(defvar edmacro-finish-hook) +(defvar edmacro-original-buffer) + +;;;###autoload +(defun edit-kbd-macro (keys &optional prefix finish-hook store-hook) + "Edit a keyboard macro. +At the prompt, type any key sequence which is bound to a keyboard macro. +Or, type `C-x e' or RET to edit the last keyboard macro, `C-h l' to edit +the last 100 keystrokes as a keyboard macro, or `M-x' to edit a macro by +its command name. +With a prefix argument, format the macro in a more concise way." + (interactive "kKeyboard macro to edit (C-x e, M-x, C-h l, or keys): \nP") + (when keys + (let ((cmd (if (arrayp keys) (key-binding keys) keys)) + (mac nil)) + (cond (store-hook + (setq mac keys) + (setq cmd nil)) + ((or (eq cmd 'call-last-kbd-macro) + (member keys '("\r" [return]))) + (or last-kbd-macro + (y-or-n-p "No keyboard macro defined. Create one? ") + (keyboard-quit)) + (setq mac (or last-kbd-macro "")) + (setq cmd 'last-kbd-macro)) + ((eq cmd 'execute-extended-command) + (setq cmd (read-command "Name of keyboard macro to edit: ")) + (if (string-equal cmd "") + (error "No command name given")) + (setq mac (symbol-function cmd))) + ((eq cmd 'view-lossage) + (setq mac (recent-keys)) + (setq cmd 'last-kbd-macro)) + ((null cmd) + (error "Key sequence %s is not defined" (key-description keys))) + ((symbolp cmd) + (setq mac (symbol-function cmd))) + (t + (setq mac cmd) + (setq cmd nil))) + (unless (arrayp mac) + (error "Key sequence %s is not a keyboard macro" + (key-description keys))) + (message "Formatting keyboard macro...") + (let* ((oldbuf (current-buffer)) + (mmac (edmacro-fix-menu-commands mac)) + (fmt (edmacro-format-keys mmac 1)) + (fmtv (edmacro-format-keys mmac (not prefix))) + (buf (get-buffer-create "*Edit Macro*"))) + (message "Formatting keyboard macro...done") + (switch-to-buffer buf) + (kill-all-local-variables) + (use-local-map edmacro-mode-map) + (setq buffer-read-only nil) + (setq major-mode 'edmacro-mode) + (setq mode-name "Edit Macro") + (set (make-local-variable 'edmacro-original-buffer) oldbuf) + (set (make-local-variable 'edmacro-finish-hook) finish-hook) + (set (make-local-variable 'edmacro-store-hook) store-hook) + (erase-buffer) + (insert ";; Keyboard Macro Editor. Press C-c C-c to finish; " + "press C-x k RET to cancel.\n") + (insert ";; Original keys: " fmt "\n") + (unless store-hook + (insert "\nCommand: " (if cmd (symbol-name cmd) "none") "\n") + (let ((keys (where-is-internal (or cmd mac)))) + (if keys + (while keys + (insert "Key: " (edmacro-format-keys (pop keys) 1) "\n")) + (insert "Key: none\n")))) + (insert "\nMacro:\n\n") + (save-excursion + (insert fmtv "\n")) + (recenter '(4)) + (when (eq mac mmac) + (set-buffer-modified-p nil)) + (run-hooks 'edmacro-format-hook))))) + +;;; The next two commands are provided for convenience and backward +;;; compatibility. + +;;;###autoload +(defun edit-last-kbd-macro (&optional prefix) + "Edit the most recently defined keyboard macro." + (interactive "P") + (edit-kbd-macro 'call-last-kbd-macro prefix)) + +;;;###autoload +(defun edit-named-kbd-macro (&optional prefix) + "Edit a keyboard macro which has been given a name by `name-last-kbd-macro'." + (interactive "P") + (edit-kbd-macro 'execute-extended-command prefix)) + +;;;###autoload +(defun read-kbd-macro (start &optional end) + "Read the region as a keyboard macro definition. +The region is interpreted as spelled-out keystrokes, e.g., \"M-x abc RET\". +See documentation for `edmacro-mode' for details. +Leading/trailing \"C-x (\" and \"C-x )\" in the text are allowed and ignored. +The resulting macro is installed as the \"current\" keyboard macro. + +In Lisp, may also be called with a single STRING argument in which case +the result is returned rather than being installed as the current macro. +The result will be a string if possible, otherwise an event vector. +Second argument NEED-VECTOR means to return an event vector always." + (interactive "r") + (if (stringp start) + (edmacro-parse-keys start end) + (setq last-kbd-macro (edmacro-parse-keys (buffer-substring start end))))) + +;;;###autoload +(defun format-kbd-macro (&optional macro verbose) + "Return the keyboard macro MACRO as a human-readable string. +This string is suitable for passing to `read-kbd-macro'. +Second argument VERBOSE means to put one command per line with comments. +If VERBOSE is `1', put everything on one line. If VERBOSE is omitted +or nil, use a compact 80-column format." + (and macro (symbolp macro) (setq macro (symbol-function macro))) + (edmacro-format-keys (or macro last-kbd-macro) verbose)) + +;;; Commands for *Edit Macro* buffer. + +(defun edmacro-finish-edit () + (interactive) + (unless (eq major-mode 'edmacro-mode) + (error + "This command is valid only in buffers created by `edit-kbd-macro'")) + (run-hooks 'edmacro-finish-hook) + (let ((cmd nil) (keys nil) (no-keys nil) + (top (point-min))) + (goto-char top) + (let ((case-fold-search nil)) + (while (cond ((looking-at "[ \t]*\\($\\|;;\\|REM[ \t\n]\\)") + t) + ((looking-at "Command:[ \t]*\\([^ \t\n]*\\)[ \t]*$") + (when edmacro-store-hook + (error "\"Command\" line not allowed in this context")) + (let ((str (buffer-substring (match-beginning 1) + (match-end 1)))) + (unless (equal str "") + (setq cmd (and (not (equal str "none")) + (intern str))) + (and (fboundp cmd) (not (arrayp (symbol-function cmd))) + (not (y-or-n-p + (format "Command %s is already defined; %s" + cmd "proceed? "))) + (keyboard-quit)))) + t) + ((looking-at "Key:\\(.*\\)$") + (when edmacro-store-hook + (error "\"Key\" line not allowed in this context")) + (let ((key (edmacro-parse-keys + (buffer-substring (match-beginning 1) + (match-end 1))))) + (unless (equal key "") + (if (equal key "none") + (setq no-keys t) + (push key keys) + (let ((b (key-binding key))) + (and b (commandp b) (not (arrayp b)) + (or (not (fboundp b)) + (not (arrayp (symbol-function b)))) + (not (y-or-n-p + (format "Key %s is already defined; %s" + (edmacro-format-keys key 1) + "proceed? "))) + (keyboard-quit)))))) + t) + ((looking-at "Macro:[ \t\n]*") + (goto-char (match-end 0)) + nil) + ((eobp) nil) + (t (error "Expected a `Macro:' line"))) + (forward-line 1)) + (setq top (point))) + (let* ((buf (current-buffer)) + (str (buffer-substring top (point-max))) + (modp (buffer-modified-p)) + (obuf edmacro-original-buffer) + (store-hook edmacro-store-hook) + (finish-hook edmacro-finish-hook)) + (unless (or cmd keys store-hook (equal str "")) + (error "No command name or keys specified")) + (when modp + (when (buffer-name obuf) + (set-buffer obuf)) + (message "Compiling keyboard macro...") + (let ((mac (edmacro-parse-keys str))) + (message "Compiling keyboard macro...done") + (if store-hook + (funcall store-hook mac) + (when (eq cmd 'last-kbd-macro) + (setq last-kbd-macro (and (> (length mac) 0) mac)) + (setq cmd nil)) + (when cmd + (if (= (length mac) 0) + (fmakunbound cmd) + (fset cmd mac))) + (if no-keys + (when cmd + (loop for key in (where-is-internal cmd '(keymap)) do + (global-unset-key key))) + (when keys + (if (= (length mac) 0) + (loop for key in keys do (global-unset-key key)) + (loop for key in keys do + (global-set-key key (or cmd mac))))))))) + (kill-buffer buf) + (when (buffer-name obuf) + (switch-to-buffer obuf)) + (when finish-hook + (funcall finish-hook))))) + +(defun edmacro-insert-key (key) + "Insert the written name of a key in the buffer." + (interactive "kKey to insert: ") + (if (bolp) + (insert (edmacro-format-keys key t) "\n") + (insert (edmacro-format-keys key) " "))) + +(defun edmacro-mode () + "\\<edmacro-mode-map>Keyboard Macro Editing mode. Press +\\[edmacro-finish-edit] to save and exit. +To abort the edit, just kill this buffer with \\[kill-buffer] RET. + +Press \\[edmacro-insert-key] to insert the name of any key by typing the key. + +The editing buffer contains a \"Command:\" line and any number of +\"Key:\" lines at the top. These are followed by a \"Macro:\" line +and the macro itself as spelled-out keystrokes: `C-x C-f foo RET'. + +The \"Command:\" line specifies the command name to which the macro +is bound, or \"none\" for no command name. Write \"last-kbd-macro\" +to refer to the current keyboard macro (as used by \\[call-last-kbd-macro]). + +The \"Key:\" lines specify key sequences to which the macro is bound, +or \"none\" for no key bindings. + +You can edit these lines to change the places where the new macro +is stored. + + +Format of keyboard macros during editing: + +Text is divided into \"words\" separated by whitespace. Except for +the words described below, the characters of each word go directly +as characters of the macro. The whitespace that separates words +is ignored. Whitespace in the macro must be written explicitly, +as in \"foo SPC bar RET\". + + * The special words RET, SPC, TAB, DEL, LFD, ESC, and NUL represent + special control characters. The words must be written in uppercase. + + * A word in angle brackets, e.g., <return>, <down>, or <f1>, represents + a function key. (Note that in the standard configuration, the + function key <return> and the control key RET are synonymous.) + You can use angle brackets on the words RET, SPC, etc., but they + are not required there. + + * Keys can be written by their ASCII code, using a backslash followed + by up to six octal digits. This is the only way to represent keys + with codes above \\377. + + * One or more prefixes M- (meta), C- (control), S- (shift), A- (alt), + H- (hyper), and s- (super) may precede a character or key notation. + For function keys, the prefixes may go inside or outside of the + brackets: C-<down> = <C-down>. The prefixes may be written in + any order: M-C-x = C-M-x. + + Prefixes are not allowed on multi-key words, e.g., C-abc, except + that the Meta prefix is allowed on a sequence of digits and optional + minus sign: M--123 = M-- M-1 M-2 M-3. + + * The `^' notation for control characters also works: ^M = C-m. + + * Double angle brackets enclose command names: <<next-line>> is + shorthand for M-x next-line RET. + + * Finally, REM or ;; causes the rest of the line to be ignored as a + comment. + +Any word may be prefixed by a multiplier in the form of a decimal +number and `*': 3*<right> = <right> <right> <right>, and +10*foo = foofoofoofoofoofoofoofoofoofoo. + +Multiple text keys can normally be strung together to form a word, +but you may need to add whitespace if the word would look like one +of the above notations: `; ; ;' is a keyboard macro with three +semicolons, but `;;;' is a comment. Likewise, `\\ 1 2 3' is four +keys but `\\123' is a single key written in octal, and `< right >' +is seven keys but `<right>' is a single function key. When in +doubt, use whitespace." + (interactive) + (error "This mode can be enabled only by `edit-kbd-macro'")) +(put 'edmacro-mode 'mode-class 'special) + + +(defun edmacro-int-char (int) + (if (fboundp 'char-to-int) + (char-to-int int) + int)) + +;;; Formatting a keyboard macro as human-readable text. + +;; Changes for XEmacs -- these two functions re-written from scratch. +;; edmacro-parse-keys always returns a vector. edmacro-format-keys +;; accepts a vector (but works with a string too). Vector may contain +;; keypress events. -hniksic +(defun edmacro-parse-keys (string &optional ignored) + (let ((pos 0) + (case-fold-search nil) + (word-to-sym '(("NUL" . (control space)) + ("RET" . return) + ("LFD" . linefeed) + ("TAB" . tab) + ("ESC" . escape) + ("SPC" . space) + ("BS" . backspace) + ("DEL" . delete))) + (char-to-word '((?\0 . "NUL") + (?\r . "RET") + (?\n . "LFD") + (?\t . "TAB") + (?\e . "ESC") + (?\ . "SPC") + (?\C-? . "DEL"))) + ;; string-to-symbol-or-char converter + (conv #'(lambda (arg) + (if (= (length arg) 1) + (aref arg 0) + (if (string-match "^<\\([^>]+\\)>$" arg) + (setq arg (match-string 1 arg))) + (let ((match (assoc arg word-to-sym))) + (if match + (cdr match) + (intern arg)))))) + (conv-chars #'(lambda (arg) + (let ((match (assoc arg char-to-word))) + (if match + (cdr (assoc (cdr match) word-to-sym)) + arg)))) + (force-sym nil) + res word found) + (while (and (< pos (length string)) + (string-match "[^ \t\n\f]+" string pos)) + (let ((word (substring string (match-beginning 0) (match-end 0))) + (times 1) + (add nil)) + (setq pos (match-end 0)) + (when (string-match "\\([0-9]+\\)\\*." word) + (setq times (string-to-int (substring word 0 (match-end 1)))) + (setq word (substring word (1+ (match-end 1))))) + (when (string-match "^<\\([^>]+\\)>$" word) + (setq word (match-string 1 word)) + (setq force-sym t)) + (setq match (assoc word word-to-sym)) + ;; Add an element. + (cond ((string-match "^\\\\[0-7]+" word) + ;; Octal value of character. + (setq add + (list + (edmacro-int-char (string-to-int (substring word 1)))))) + ((string-match "^<<.+>>$" word) + ;; Extended command. + (setq add + (nconc + (list + (if (eq (key-binding [(meta x)]) + 'execute-extended-command) + '(meta x) + (or (car (where-is-internal + 'execute-extended-command)) + '(meta x)))) + (mapcar conv-chars (concat (substring word 2 -2) "\r"))) + )) + ((or (equal word "REM") (string-match "^;;" word)) + ;; Comment. + (setq pos (string-match "$" string pos))) + (match + ;; Convert to symbol. + (setq add (list (cdr match)))) + ((string-match "^\\^" word) + ;; ^X == C-x + (if (/= (length word) 2) + (error "^ must be followed by one character")) + (setq add `((control ,(aref word 0))))) + ((string-match "^[MCSsAH]-" word) + ;; Parse C-* + (setq + add + (list + (let ((pos1 0) + (r1 nil) + follow) + (while (string-match "^[MCSsAH]-" (substring word pos1)) + (setq r1 (nconc + r1 + (list + (cdr (assq (aref word pos1) + '((?C . control) + (?M . meta) + (?S . shift) + (?A . alt) + (?H . hyper) + (?s . super))))))) + (setq pos1 (+ pos1 2))) + (setq follow (substring word pos1)) + (if (equal follow "") + (error "%s must precede a string" + (substring word 0 pos1))) + (nconc r1 (list (funcall conv follow))))))) + (force-sym + ;; This must be a symbol + (setq add (list (intern word)))) + (t + ;; Characters + (setq add (mapcar conv-chars word)))) + (let ((new nil)) + (loop repeat times do (setq new (append new add))) + (setq add new)) + (setq res (nconc res add)))) + (mapvector 'identity res))) + +(defun edmacro-conv (char-or-sym add-<>) + (let ((char-to-word '((?\0 . "NUL") + (?\r . "RET") + (?\n . "LFD") + (?\t . "TAB") + (?\e . "ESC") + (?\ . "SPC") + (?\C-? . "DEL"))) + (symbol-to-char '((return . ?\r) + (space . ?\ ) + (delete . ?\C-?) + (tab . ?\t) + (escape . ?\e)))) + (if (symbolp char-or-sym) + (if (= (length (symbol-name char-or-sym)) 1) + (setq char-or-sym (aref (symbol-name char-or-sym) 0)) + (let ((found (assq char-or-sym symbol-to-char))) + (if found + (setq char-or-sym (cdr found)))))) + ;; Return: + (cons (symbolp char-or-sym) + (if (symbolp char-or-sym) + (if add-<> + (concat "<" (symbol-name char-or-sym) ">") + (symbol-name char-or-sym)) + (let ((found (assq char-or-sym char-to-word))) + (if found + (cdr found) + (single-key-description char-or-sym))))))) + +(defun edmacro-format-1 (keys command times togetherp) + (let ((res "") + (start keys) + el) + (while keys + (unless (or (eq start keys) togetherp) + (callf concat res " ")) + (if (> times 1) + (setq res (concat (format "%d*" times) res))) + (setq el (car keys)) + (callf concat res + (cond ((listp el) + (let ((my "")) + (if (or + (let (cnv) + (while el + (let ((found (assq (car el) + '((control . "C-") + (meta . "M-") + (shift . "S-") + (alt . "A-") + (hyper . "H-") + (super . "s-"))))) + (callf concat my + (if found + (cdr found) + (setq cnv (edmacro-conv (car el) nil)) + (cdr cnv)))) + (setq el (cdr el))) + (car cnv)) + (> times 1)) + (concat "<" my ">") + my))) + (t + (cdr (edmacro-conv el t))))) + (setq keys (cdr keys))) + (if command + (callf concat res + (concat + (make-string (max (- 3 (/ (length res) tab-width)) 1) ?\t) + ";; " + (symbol-name command) + (if togetherp (format " * %d" (length start)))))) + res)) + +(defun edmacro-format-keys (macro &optional verbose) + (let ((cnt 0) + (res "")) + ;; XEmacs: + ;; If we're dealing with events, convert them to symbols first. + (and (fboundp 'events-to-keys) + (eventp (aref macro 0)) + (setq macro (events-to-keys macro t))) + + ;; I'm not sure I understand the original code, but this seems to + ;; work. + (and (eq verbose 1) + (setq verbose nil)) + + ;; Oh come on -- I want a list! Much easier to process... + (setq macro (mapcar 'identity macro)) + + (while macro + (let (key lookup (times 1) self-insert-p) + (loop do + (setq key (nconc key (list (car macro))) + macro (cdr macro) + lookup (lookup-key global-map (mapvector 'identity key))) + while + (and lookup (not (commandp lookup)))) + (if (and (eq lookup 'self-insert-command) + (= (length key) 1) + (not (memq (car key) + '(?\ ?\r ?\n space return linefeed tab)))) + (while (and (< (length key) 23) + (eq (lookup-key global-map (car macro)) + 'self-insert-command) + (not (memq (car macro) + '(?\ ?\r ?\n space return linefeed tab)))) + (setq key (nconc key (list (car macro))) + macro (cdr macro) + self-insert-p t)) + (while (edmacro-seq-equal key macro) + (setq macro (nthcdr (length key) macro)) + (incf times))) + (if (or self-insert-p + (null (cdr key)) + (= times 1)) + (callf concat res (edmacro-format-1 key (if verbose lookup + nil) + times self-insert-p) + (if verbose "\n" " ")) + (loop repeat times + do + (callf concat res + (edmacro-format-1 key (if verbose lookup + nil) + 1 self-insert-p) + (if verbose "\n" " ")))) + )) + res)) + +(defun edmacro-seq-equal (seq1 seq2) + (while (and seq1 seq2 + (equal (car seq1) (car seq2))) + (setq seq1 (cdr seq1) + seq2 (cdr seq2))) + (not seq1)) + +(defun edmacro-fix-menu-commands (macro) + (when (vectorp macro) + (let ((i 0) ev) + (while (< i (length macro)) + (when (consp (setq ev (aref macro i))) + (cond ((equal (cadadr ev) '(menu-bar)) + (setq macro (vconcat (edmacro-subseq macro 0 i) + (vector 'menu-bar (car ev)) + (edmacro-subseq macro (1+ i)))) + (incf i)) + ;; It would be nice to do pop-up menus, too, but not enough + ;; info is recorded in macros to make this possible. + (t + (error "Macros with mouse clicks are not %s" + "supported by this command")))) + (incf i)))) + macro) + +;;; Parsing a human-readable keyboard macro. + + + +;;; The following probably ought to go in macros.el: + +;;;###autoload +(defun insert-kbd-macro (macroname &optional keys) + "Insert in buffer the definition of kbd macro NAME, as Lisp code. +Optional second arg KEYS means also record the keys it is on +\(this is the prefix argument, when calling interactively). + +This Lisp code will, when executed, define the kbd macro with the same +definition it has now. If you say to record the keys, the Lisp code +will also rebind those keys to the macro. Only global key bindings +are recorded since executing this Lisp code always makes global +bindings. + +To save a kbd macro, visit a file of Lisp code such as your `~/.emacs', +use this command, and then save the file." + (interactive "CInsert kbd macro (name): \nP") + (let (definition) + (if (string= (symbol-name macroname) "") + (progn + (setq definition (format-kbd-macro)) + (insert "(setq last-kbd-macro")) + (setq definition (format-kbd-macro macroname)) + (insert (format "(defalias '%s" macroname))) + (if (> (length definition) 50) + (insert " (read-kbd-macro\n") + (insert "\n (read-kbd-macro ")) + (prin1 definition (current-buffer)) + (insert "))\n") + (if keys + (let ((keys (where-is-internal macroname '(keymap)))) + (while keys + (insert (format "(global-set-key %S '%s)\n" (car keys) macroname)) + (setq keys (cdr keys))))))) + +(provide 'edmacro) + +;;; edmacro.el ends here