1992-07-16 21:47:34 +00:00
|
|
|
|
;;; edmacro.el --- keyboard macro editor
|
|
|
|
|
|
2004-12-08 01:10:13 +00:00
|
|
|
|
;; Copyright (C) 1993, 1994, 2004 Free Software Foundation, Inc.
|
1992-07-22 04:22:30 +00:00
|
|
|
|
|
1993-09-21 03:44:04 +00:00
|
|
|
|
;; Author: Dave Gillespie <daveg@synaptics.com>
|
|
|
|
|
;; Maintainer: Dave Gillespie <daveg@synaptics.com>
|
|
|
|
|
;; Version: 2.01
|
1993-03-18 21:29:42 +00:00
|
|
|
|
;; Keywords: abbrev
|
1990-10-22 07:14:13 +00:00
|
|
|
|
|
|
|
|
|
;; 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
|
1992-07-16 21:47:34 +00:00
|
|
|
|
;; the Free Software Foundation; either version 2, or (at your option)
|
1990-10-22 07:14:13 +00:00
|
|
|
|
;; 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
|
1996-01-14 07:34:30 +00:00
|
|
|
|
;; 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.
|
1990-10-22 07:14:13 +00:00
|
|
|
|
|
1992-07-16 21:47:34 +00:00
|
|
|
|
;;; Commentary:
|
1990-10-22 07:14:13 +00:00
|
|
|
|
|
1993-09-21 03:44:04 +00:00
|
|
|
|
;;; Usage:
|
|
|
|
|
;;
|
2004-12-08 01:10:13 +00:00
|
|
|
|
;; The `C-x C-k e' (`edit-kbd-macro') command edits a keyboard macro
|
1993-09-21 03:44:04 +00:00
|
|
|
|
;; in a special buffer. It prompts you to type a key sequence,
|
|
|
|
|
;; which should be one of:
|
|
|
|
|
;;
|
2003-02-04 11:26:42 +00:00
|
|
|
|
;; * RET or `C-x e' (call-last-kbd-macro), to edit the most
|
1993-09-21 03:44:04 +00:00
|
|
|
|
;; 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.
|
1992-07-16 21:47:34 +00:00
|
|
|
|
|
|
|
|
|
;;; Code:
|
1990-10-22 07:14:13 +00:00
|
|
|
|
|
1995-08-27 17:50:39 +00:00
|
|
|
|
(eval-when-compile
|
|
|
|
|
(require 'cl))
|
1993-09-21 03:44:04 +00:00
|
|
|
|
|
2004-09-30 13:27:35 +00:00
|
|
|
|
(require 'kmacro)
|
|
|
|
|
|
1990-10-22 07:14:13 +00:00
|
|
|
|
;;; The user-level commands for editing macros.
|
|
|
|
|
|
1993-09-21 03:44:04 +00:00
|
|
|
|
;;;###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))
|
|
|
|
|
|
1996-02-02 06:13:55 +00:00
|
|
|
|
(defvar edmacro-store-hook)
|
|
|
|
|
(defvar edmacro-finish-hook)
|
|
|
|
|
(defvar edmacro-original-buffer)
|
|
|
|
|
|
1991-05-09 21:50:55 +00:00
|
|
|
|
;;;###autoload
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(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))
|
2004-09-30 13:27:35 +00:00
|
|
|
|
(mac nil) (mac-counter nil) (mac-format nil)
|
|
|
|
|
kmacro)
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(cond (store-hook
|
|
|
|
|
(setq mac keys)
|
|
|
|
|
(setq cmd nil))
|
2003-02-04 11:26:42 +00:00
|
|
|
|
((or (memq cmd '(call-last-kbd-macro kmacro-call-macro
|
2002-09-11 20:00:58 +00:00
|
|
|
|
kmacro-end-or-call-macro kmacro-end-and-call-macro))
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(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 ""))
|
2004-09-30 13:27:35 +00:00
|
|
|
|
(setq keys nil)
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(setq cmd 'last-kbd-macro))
|
|
|
|
|
((eq cmd 'execute-extended-command)
|
|
|
|
|
(setq cmd (read-command "Name of keyboard macro to edit: "))
|
1996-01-28 03:07:15 +00:00
|
|
|
|
(if (string-equal cmd "")
|
|
|
|
|
(error "No command name given"))
|
2004-09-30 13:27:35 +00:00
|
|
|
|
(setq keys nil)
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(setq mac (symbol-function cmd)))
|
1998-12-27 08:04:05 +00:00
|
|
|
|
((memq cmd '(view-lossage electric-view-lossage))
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(setq mac (recent-keys))
|
2004-09-30 13:27:35 +00:00
|
|
|
|
(setq keys nil)
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(setq cmd 'last-kbd-macro))
|
1995-05-22 22:08:18 +00:00
|
|
|
|
((null cmd)
|
|
|
|
|
(error "Key sequence %s is not defined" (key-description keys)))
|
1993-09-21 03:44:04 +00:00
|
|
|
|
((symbolp cmd)
|
|
|
|
|
(setq mac (symbol-function cmd)))
|
|
|
|
|
(t
|
|
|
|
|
(setq mac cmd)
|
|
|
|
|
(setq cmd nil)))
|
2004-09-30 13:27:35 +00:00
|
|
|
|
(when (setq kmacro (kmacro-extract-lambda mac))
|
|
|
|
|
(setq mac (car kmacro)
|
|
|
|
|
mac-counter (nth 1 kmacro)
|
|
|
|
|
mac-format (nth 2 kmacro)))
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(unless (arrayp mac)
|
1995-05-22 22:08:18 +00:00
|
|
|
|
(error "Key sequence %s is not a keyboard macro"
|
|
|
|
|
(key-description keys)))
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(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")
|
2004-09-30 13:27:35 +00:00
|
|
|
|
(let ((gkeys (where-is-internal (or cmd mac) '(keymap))))
|
|
|
|
|
(if (and keys (not (member keys gkeys)))
|
|
|
|
|
(setq gkeys (cons keys gkeys)))
|
|
|
|
|
(if gkeys
|
|
|
|
|
(while gkeys
|
|
|
|
|
(insert "Key: " (edmacro-format-keys (pop gkeys) 1) "\n"))
|
|
|
|
|
(insert "Key: none\n")))
|
|
|
|
|
(when (and mac-counter mac-format)
|
|
|
|
|
(insert (format "Counter: %d\nFormat: \"%s\"\n" mac-counter mac-format))))
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(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)
|
1990-10-22 07:14:13 +00:00
|
|
|
|
"Edit the most recently defined keyboard macro."
|
|
|
|
|
(interactive "P")
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(edit-kbd-macro 'call-last-kbd-macro prefix))
|
1990-10-22 07:14:13 +00:00
|
|
|
|
|
1991-05-09 21:50:55 +00:00
|
|
|
|
;;;###autoload
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(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))
|
1990-10-22 07:14:13 +00:00
|
|
|
|
|
1991-05-09 21:50:55 +00:00
|
|
|
|
;;;###autoload
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(defun read-kbd-macro (start &optional end)
|
1990-10-22 07:14:13 +00:00
|
|
|
|
"Read the region as a keyboard macro definition.
|
1991-02-28 19:32:54 +00:00
|
|
|
|
The region is interpreted as spelled-out keystrokes, e.g., \"M-x abc RET\".
|
1993-09-21 03:44:04 +00:00
|
|
|
|
See documentation for `edmacro-mode' for details.
|
|
|
|
|
Leading/trailing \"C-x (\" and \"C-x )\" in the text are allowed and ignored.
|
1990-10-22 07:14:13 +00:00
|
|
|
|
The resulting macro is installed as the \"current\" keyboard macro.
|
|
|
|
|
|
1993-09-21 03:44:04 +00:00
|
|
|
|
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."
|
1990-10-22 07:14:13 +00:00
|
|
|
|
(interactive "r")
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(if (stringp start)
|
|
|
|
|
(edmacro-parse-keys start end)
|
|
|
|
|
(setq last-kbd-macro (edmacro-parse-keys (buffer-substring start end)))))
|
1990-10-22 07:14:13 +00:00
|
|
|
|
|
1993-09-21 03:44:04 +00:00
|
|
|
|
;;;###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))
|
1990-10-22 07:14:13 +00:00
|
|
|
|
|
1993-09-21 03:44:04 +00:00
|
|
|
|
;;; Commands for *Edit Macro* buffer.
|
1990-10-22 07:14:13 +00:00
|
|
|
|
|
|
|
|
|
(defun edmacro-finish-edit ()
|
|
|
|
|
(interactive)
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(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)
|
2004-09-30 13:27:35 +00:00
|
|
|
|
(mac-counter nil) (mac-format nil) (kmacro nil)
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(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 "")
|
1995-08-27 17:50:39 +00:00
|
|
|
|
(setq cmd (and (not (equal str "none"))
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(intern str)))
|
|
|
|
|
(and (fboundp cmd) (not (arrayp (symbol-function cmd)))
|
2004-09-30 13:27:35 +00:00
|
|
|
|
(not (setq kmacro (get cmd 'kmacro)))
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(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 "")
|
1995-08-27 17:50:39 +00:00
|
|
|
|
(if (equal key "none")
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(setq no-keys t)
|
|
|
|
|
(push key keys)
|
|
|
|
|
(let ((b (key-binding key)))
|
|
|
|
|
(and b (commandp b) (not (arrayp b))
|
2004-09-30 13:27:35 +00:00
|
|
|
|
(not (kmacro-extract-lambda b))
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(or (not (fboundp b))
|
2004-12-08 01:10:13 +00:00
|
|
|
|
(not (or (arrayp (symbol-function b))
|
|
|
|
|
(get b 'kmacro))))
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(not (y-or-n-p
|
|
|
|
|
(format "Key %s is already defined; %s"
|
|
|
|
|
(edmacro-format-keys key 1)
|
|
|
|
|
"proceed? ")))
|
|
|
|
|
(keyboard-quit))))))
|
|
|
|
|
t)
|
2004-09-30 13:27:35 +00:00
|
|
|
|
((looking-at "Counter:[ \t]*\\([^ \t\n]*\\)[ \t]*$")
|
|
|
|
|
(when edmacro-store-hook
|
|
|
|
|
(error "\"Counter\" line not allowed in this context"))
|
|
|
|
|
(let ((str (buffer-substring (match-beginning 1)
|
|
|
|
|
(match-end 1))))
|
|
|
|
|
(unless (equal str "")
|
|
|
|
|
(setq mac-counter (string-to-int str))))
|
|
|
|
|
t)
|
|
|
|
|
((looking-at "Format:[ \t]*\"\\([^\n]*\\)\"[ \t]*$")
|
|
|
|
|
(when edmacro-store-hook
|
|
|
|
|
(error "\"Format\" line not allowed in this context"))
|
|
|
|
|
(let ((str (buffer-substring (match-beginning 1)
|
|
|
|
|
(match-end 1))))
|
|
|
|
|
(unless (equal str "")
|
|
|
|
|
(setq mac-format str)))
|
|
|
|
|
t)
|
1993-09-21 03:44:04 +00:00
|
|
|
|
((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)
|
2004-09-30 13:27:35 +00:00
|
|
|
|
(fset cmd
|
|
|
|
|
(if (and mac-counter mac-format)
|
|
|
|
|
(kmacro-lambda-form mac mac-counter mac-format)
|
|
|
|
|
mac))))
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(if no-keys
|
|
|
|
|
(when cmd
|
1994-02-04 06:45:26 +00:00
|
|
|
|
(loop for key in (where-is-internal cmd '(keymap)) do
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(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
|
2004-09-30 13:27:35 +00:00
|
|
|
|
(global-set-key key
|
|
|
|
|
(or cmd
|
|
|
|
|
(if (and mac-counter mac-format)
|
|
|
|
|
(kmacro-lambda-form mac mac-counter mac-format)
|
|
|
|
|
mac))))))))))
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(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) " ")))
|
1990-10-22 07:14:13 +00:00
|
|
|
|
|
|
|
|
|
(defun edmacro-mode ()
|
1993-09-21 03:44:04 +00:00
|
|
|
|
"\\<edmacro-mode-map>Keyboard Macro Editing mode. Press
|
|
|
|
|
\\[edmacro-finish-edit] to save and exit.
|
1991-02-28 19:32:54 +00:00
|
|
|
|
To abort the edit, just kill this buffer with \\[kill-buffer] RET.
|
1990-10-22 07:14:13 +00:00
|
|
|
|
|
1993-09-21 03:44:04 +00:00
|
|
|
|
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."
|
1990-10-22 07:14:13 +00:00
|
|
|
|
(interactive)
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(error "This mode can be enabled only by `edit-kbd-macro'"))
|
1990-10-22 07:14:13 +00:00
|
|
|
|
(put 'edmacro-mode 'mode-class 'special)
|
1993-09-21 03:44:04 +00:00
|
|
|
|
|
|
|
|
|
;;; Formatting a keyboard macro as human-readable text.
|
1990-10-22 07:14:13 +00:00
|
|
|
|
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(defun edmacro-format-keys (macro &optional verbose)
|
|
|
|
|
(setq macro (edmacro-fix-menu-commands macro))
|
|
|
|
|
(let* ((maps (append (current-minor-mode-maps)
|
1994-10-01 03:53:40 +00:00
|
|
|
|
(if (current-local-map)
|
|
|
|
|
(list (current-local-map)))
|
|
|
|
|
(list (current-global-map))))
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(pkeys '(end-macro ?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9 ?- ?\C-u
|
|
|
|
|
?\M-- ?\M-0 ?\M-1 ?\M-2 ?\M-3 ?\M-4 ?\M-5 ?\M-6
|
|
|
|
|
?\M-7 ?\M-8 ?\M-9))
|
|
|
|
|
(mdigs (nthcdr 13 pkeys))
|
|
|
|
|
(maxkey (if edmacro-eight-bits 255 127))
|
|
|
|
|
(case-fold-search nil)
|
|
|
|
|
(res-words '("NUL" "TAB" "LFD" "RET" "ESC" "SPC" "DEL" "REM"))
|
|
|
|
|
(rest-mac (vconcat macro [end-macro]))
|
|
|
|
|
(res "")
|
|
|
|
|
(len 0)
|
|
|
|
|
(one-line (eq verbose 1)))
|
|
|
|
|
(if one-line (setq verbose nil))
|
|
|
|
|
(when (stringp macro)
|
|
|
|
|
(loop for i below (length macro) do
|
|
|
|
|
(when (>= (aref rest-mac i) 128)
|
1995-02-08 03:50:54 +00:00
|
|
|
|
(incf (aref rest-mac i) (- ?\M-\^@ 128)))))
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(while (not (eq (aref rest-mac 0) 'end-macro))
|
|
|
|
|
(let* ((prefix
|
|
|
|
|
(or (and (integerp (aref rest-mac 0))
|
|
|
|
|
(memq (aref rest-mac 0) mdigs)
|
1995-08-27 17:50:39 +00:00
|
|
|
|
(memq (key-binding (edmacro-subseq rest-mac 0 1))
|
1993-09-21 03:44:04 +00:00
|
|
|
|
'(digit-argument negative-argument))
|
|
|
|
|
(let ((i 1))
|
|
|
|
|
(while (memq (aref rest-mac i) (cdr mdigs))
|
|
|
|
|
(incf i))
|
|
|
|
|
(and (not (memq (aref rest-mac i) pkeys))
|
2003-08-06 01:04:34 +00:00
|
|
|
|
(prog1 (vconcat "M-" (edmacro-subseq rest-mac 0 i) " ")
|
1995-08-27 17:50:39 +00:00
|
|
|
|
(callf edmacro-subseq rest-mac i)))))
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(and (eq (aref rest-mac 0) ?\C-u)
|
|
|
|
|
(eq (key-binding [?\C-u]) 'universal-argument)
|
|
|
|
|
(let ((i 1))
|
|
|
|
|
(while (eq (aref rest-mac i) ?\C-u)
|
|
|
|
|
(incf i))
|
|
|
|
|
(and (not (memq (aref rest-mac i) pkeys))
|
|
|
|
|
(prog1 (loop repeat i concat "C-u ")
|
1995-08-27 17:50:39 +00:00
|
|
|
|
(callf edmacro-subseq rest-mac i)))))
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(and (eq (aref rest-mac 0) ?\C-u)
|
|
|
|
|
(eq (key-binding [?\C-u]) 'universal-argument)
|
|
|
|
|
(let ((i 1))
|
|
|
|
|
(when (eq (aref rest-mac i) ?-)
|
|
|
|
|
(incf i))
|
|
|
|
|
(while (memq (aref rest-mac i)
|
|
|
|
|
'(?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9))
|
|
|
|
|
(incf i))
|
|
|
|
|
(and (not (memq (aref rest-mac i) pkeys))
|
2003-08-06 01:04:34 +00:00
|
|
|
|
(prog1 (vconcat "C-u " (edmacro-subseq rest-mac 1 i) " ")
|
1995-08-27 17:50:39 +00:00
|
|
|
|
(callf edmacro-subseq rest-mac i)))))))
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(bind-len (apply 'max 1
|
|
|
|
|
(loop for map in maps
|
|
|
|
|
for b = (lookup-key map rest-mac)
|
|
|
|
|
when b collect b)))
|
1995-08-27 17:50:39 +00:00
|
|
|
|
(key (edmacro-subseq rest-mac 0 bind-len))
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(fkey nil) tlen tkey
|
|
|
|
|
(bind (or (loop for map in maps for b = (lookup-key map key)
|
|
|
|
|
thereis (and (not (integerp b)) b))
|
|
|
|
|
(and (setq fkey (lookup-key function-key-map rest-mac))
|
1995-08-27 17:50:39 +00:00
|
|
|
|
(setq tlen fkey tkey (edmacro-subseq rest-mac 0 tlen)
|
1993-09-21 03:44:04 +00:00
|
|
|
|
fkey (lookup-key function-key-map tkey))
|
|
|
|
|
(loop for map in maps
|
|
|
|
|
for b = (lookup-key map fkey)
|
|
|
|
|
when (and (not (integerp b)) b)
|
|
|
|
|
do (setq bind-len tlen key tkey)
|
|
|
|
|
and return b
|
|
|
|
|
finally do (setq fkey nil)))))
|
|
|
|
|
(first (aref key 0))
|
|
|
|
|
(text (loop for i from bind-len below (length rest-mac)
|
|
|
|
|
for ch = (aref rest-mac i)
|
|
|
|
|
while (and (integerp ch)
|
|
|
|
|
(> ch 32) (< ch maxkey) (/= ch 92)
|
|
|
|
|
(eq (key-binding (char-to-string ch))
|
|
|
|
|
'self-insert-command)
|
|
|
|
|
(or (> i (- (length rest-mac) 2))
|
|
|
|
|
(not (eq ch (aref rest-mac (+ i 1))))
|
|
|
|
|
(not (eq ch (aref rest-mac (+ i 2))))))
|
|
|
|
|
finally return i))
|
|
|
|
|
desc)
|
|
|
|
|
(if (stringp bind) (setq bind nil))
|
|
|
|
|
(cond ((and (eq bind 'self-insert-command) (not prefix)
|
|
|
|
|
(> text 1) (integerp first)
|
|
|
|
|
(> first 32) (<= first maxkey) (/= first 92)
|
|
|
|
|
(progn
|
|
|
|
|
(if (> text 30) (setq text 30))
|
1995-08-27 17:50:39 +00:00
|
|
|
|
(setq desc (concat (edmacro-subseq rest-mac 0 text)))
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(when (string-match "^[ACHMsS]-." desc)
|
|
|
|
|
(setq text 2)
|
|
|
|
|
(callf substring desc 0 2))
|
|
|
|
|
(not (string-match
|
|
|
|
|
"^;;\\|^<.*>$\\|^\\\\[0-9]+$\\|^[0-9]+\\*."
|
|
|
|
|
desc))))
|
|
|
|
|
(when (or (string-match "^\\^.$" desc)
|
|
|
|
|
(member desc res-words))
|
|
|
|
|
(setq desc (mapconcat 'char-to-string desc " ")))
|
|
|
|
|
(when verbose
|
|
|
|
|
(setq bind (format "%s * %d" bind text)))
|
|
|
|
|
(setq bind-len text))
|
|
|
|
|
((and (eq bind 'execute-extended-command)
|
|
|
|
|
(> text bind-len)
|
|
|
|
|
(memq (aref rest-mac text) '(return 13))
|
|
|
|
|
(progn
|
1995-08-27 17:50:39 +00:00
|
|
|
|
(setq desc (concat (edmacro-subseq rest-mac bind-len text)))
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(commandp (intern-soft desc))))
|
|
|
|
|
(if (commandp (intern-soft desc)) (setq bind desc))
|
|
|
|
|
(setq desc (format "<<%s>>" desc))
|
|
|
|
|
(setq bind-len (1+ text)))
|
|
|
|
|
(t
|
|
|
|
|
(setq desc (mapconcat
|
|
|
|
|
(function
|
|
|
|
|
(lambda (ch)
|
|
|
|
|
(cond
|
|
|
|
|
((integerp ch)
|
|
|
|
|
(concat
|
|
|
|
|
(loop for pf across "ACHMsS"
|
1995-02-08 03:50:54 +00:00
|
|
|
|
for bit in '(?\A-\^@ ?\C-\^@ ?\H-\^@
|
|
|
|
|
?\M-\^@ ?\s-\^@ ?\S-\^@)
|
|
|
|
|
when (/= (logand ch bit) 0)
|
1993-09-21 03:44:04 +00:00
|
|
|
|
concat (format "%c-" pf))
|
|
|
|
|
(let ((ch2 (logand ch (1- (lsh 1 18)))))
|
|
|
|
|
(cond ((<= ch2 32)
|
|
|
|
|
(case ch2
|
|
|
|
|
(0 "NUL") (9 "TAB") (10 "LFD")
|
|
|
|
|
(13 "RET") (27 "ESC") (32 "SPC")
|
|
|
|
|
(t
|
|
|
|
|
(format "C-%c"
|
|
|
|
|
(+ (if (<= ch2 26) 96 64)
|
|
|
|
|
ch2)))))
|
|
|
|
|
((= ch2 127) "DEL")
|
|
|
|
|
((<= ch2 maxkey) (char-to-string ch2))
|
|
|
|
|
(t (format "\\%o" ch2))))))
|
|
|
|
|
((symbolp ch)
|
|
|
|
|
(format "<%s>" ch))
|
|
|
|
|
(t
|
|
|
|
|
(error "Unrecognized item in macro: %s" ch)))))
|
|
|
|
|
(or fkey key) " "))))
|
2003-08-06 01:04:34 +00:00
|
|
|
|
(if prefix
|
|
|
|
|
(setq desc (concat (edmacro-sanitize-for-string prefix) desc)))
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(unless (string-match " " desc)
|
|
|
|
|
(let ((times 1) (pos bind-len))
|
1995-08-27 17:50:39 +00:00
|
|
|
|
(while (not (edmacro-mismatch rest-mac rest-mac
|
|
|
|
|
0 bind-len pos (+ bind-len pos)))
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(incf times)
|
|
|
|
|
(incf pos bind-len))
|
|
|
|
|
(when (> times 1)
|
|
|
|
|
(setq desc (format "%d*%s" times desc))
|
|
|
|
|
(setq bind-len (* bind-len times)))))
|
1995-08-27 17:50:39 +00:00
|
|
|
|
(setq rest-mac (edmacro-subseq rest-mac bind-len))
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(if verbose
|
|
|
|
|
(progn
|
|
|
|
|
(unless (equal res "") (callf concat res "\n"))
|
|
|
|
|
(callf concat res desc)
|
|
|
|
|
(when (and bind (or (stringp bind) (symbolp bind)))
|
|
|
|
|
(callf concat res
|
|
|
|
|
(make-string (max (- 3 (/ (length desc) 8)) 1) 9)
|
|
|
|
|
";; " (if (stringp bind) bind (symbol-name bind))))
|
|
|
|
|
(setq len 0))
|
|
|
|
|
(if (and (> (+ len (length desc) 2) 72) (not one-line))
|
|
|
|
|
(progn
|
|
|
|
|
(callf concat res "\n ")
|
|
|
|
|
(setq len 1))
|
|
|
|
|
(unless (equal res "")
|
|
|
|
|
(callf concat res " ")
|
|
|
|
|
(incf len)))
|
|
|
|
|
(callf concat res desc)
|
|
|
|
|
(incf len (length desc)))))
|
|
|
|
|
res))
|
|
|
|
|
|
1995-08-27 17:50:39 +00:00
|
|
|
|
(defun edmacro-mismatch (cl-seq1 cl-seq2 cl-start1 cl-end1 cl-start2 cl-end2)
|
|
|
|
|
"Compare SEQ1 with SEQ2, return index of first mismatching element.
|
|
|
|
|
Return nil if the sequences match. If one sequence is a prefix of the
|
|
|
|
|
other, the return value indicates the end of the shorted sequence."
|
|
|
|
|
(let (cl-test cl-test-not cl-key cl-from-end)
|
|
|
|
|
(or cl-end1 (setq cl-end1 (length cl-seq1)))
|
|
|
|
|
(or cl-end2 (setq cl-end2 (length cl-seq2)))
|
|
|
|
|
(if cl-from-end
|
|
|
|
|
(progn
|
|
|
|
|
(while (and (< cl-start1 cl-end1) (< cl-start2 cl-end2)
|
|
|
|
|
(cl-check-match (elt cl-seq1 (1- cl-end1))
|
|
|
|
|
(elt cl-seq2 (1- cl-end2))))
|
|
|
|
|
(setq cl-end1 (1- cl-end1) cl-end2 (1- cl-end2)))
|
|
|
|
|
(and (or (< cl-start1 cl-end1) (< cl-start2 cl-end2))
|
|
|
|
|
(1- cl-end1)))
|
|
|
|
|
(let ((cl-p1 (and (listp cl-seq1) (nthcdr cl-start1 cl-seq1)))
|
|
|
|
|
(cl-p2 (and (listp cl-seq2) (nthcdr cl-start2 cl-seq2))))
|
|
|
|
|
(while (and (< cl-start1 cl-end1) (< cl-start2 cl-end2)
|
|
|
|
|
(cl-check-match (if cl-p1 (car cl-p1)
|
|
|
|
|
(aref cl-seq1 cl-start1))
|
|
|
|
|
(if cl-p2 (car cl-p2)
|
|
|
|
|
(aref cl-seq2 cl-start2))))
|
|
|
|
|
(setq cl-p1 (cdr cl-p1) cl-p2 (cdr cl-p2)
|
|
|
|
|
cl-start1 (1+ cl-start1) cl-start2 (1+ cl-start2)))
|
|
|
|
|
(and (or (< cl-start1 cl-end1) (< cl-start2 cl-end2))
|
|
|
|
|
cl-start1)))))
|
|
|
|
|
|
|
|
|
|
(defun edmacro-subseq (seq start &optional end)
|
|
|
|
|
"Return the subsequence of SEQ from START to END.
|
|
|
|
|
If END is omitted, it defaults to the length of the sequence.
|
|
|
|
|
If START or END is negative, it counts from the end."
|
|
|
|
|
(if (stringp seq) (substring seq start end)
|
|
|
|
|
(let (len)
|
|
|
|
|
(and end (< end 0) (setq end (+ end (setq len (length seq)))))
|
|
|
|
|
(if (< start 0) (setq start (+ start (or len (setq len (length seq))))))
|
|
|
|
|
(cond ((listp seq)
|
|
|
|
|
(if (> start 0) (setq seq (nthcdr start seq)))
|
|
|
|
|
(if end
|
|
|
|
|
(let ((res nil))
|
|
|
|
|
(while (>= (setq end (1- end)) start)
|
2002-09-06 19:46:24 +00:00
|
|
|
|
(push (pop seq) res))
|
1995-08-27 17:50:39 +00:00
|
|
|
|
(nreverse res))
|
|
|
|
|
(copy-sequence seq)))
|
|
|
|
|
(t
|
|
|
|
|
(or end (setq end (or len (length seq))))
|
|
|
|
|
(let ((res (make-vector (max (- end start) 0) nil))
|
|
|
|
|
(i 0))
|
|
|
|
|
(while (< start end)
|
|
|
|
|
(aset res i (aref seq start))
|
|
|
|
|
(setq i (1+ i) start (1+ start)))
|
|
|
|
|
res))))))
|
|
|
|
|
|
2003-08-06 01:04:34 +00:00
|
|
|
|
(defun edmacro-sanitize-for-string (seq)
|
|
|
|
|
"Convert a key sequence vector into a string.
|
|
|
|
|
The string represents the same events; Meta is indicated by bit 7.
|
|
|
|
|
This function assumes that the events can be stored in a string."
|
|
|
|
|
(setq seq (copy-sequence seq))
|
|
|
|
|
(loop for i below (length seq) do
|
2004-12-08 01:10:13 +00:00
|
|
|
|
(when (logand (aref seq i) 128)
|
2003-08-06 01:04:34 +00:00
|
|
|
|
(setf (aref seq i) (logand (aref seq i) 127))))
|
|
|
|
|
seq)
|
|
|
|
|
|
2002-06-21 09:53:01 +00:00
|
|
|
|
(defun edmacro-fix-menu-commands (macro &optional noerror)
|
|
|
|
|
(if (vectorp macro)
|
|
|
|
|
(let (result)
|
|
|
|
|
;; Make a list of the elements.
|
|
|
|
|
(setq macro (append macro nil))
|
|
|
|
|
(dolist (ev macro)
|
|
|
|
|
(cond ((atom ev)
|
|
|
|
|
(push ev result))
|
|
|
|
|
((eq (car ev) 'help-echo))
|
|
|
|
|
((equal ev '(menu-bar))
|
|
|
|
|
(push 'menu-bar result))
|
|
|
|
|
((equal (cadadr ev) '(menu-bar))
|
|
|
|
|
(push (vector 'menu-bar (car ev)) result))
|
1993-09-21 03:44:04 +00:00
|
|
|
|
;; It would be nice to do pop-up menus, too, but not enough
|
|
|
|
|
;; info is recorded in macros to make this possible.
|
2002-06-21 09:53:01 +00:00
|
|
|
|
(noerror
|
|
|
|
|
;; Just ignore mouse events.
|
|
|
|
|
nil)
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(t
|
|
|
|
|
(error "Macros with mouse clicks are not %s"
|
|
|
|
|
"supported by this command"))))
|
2002-06-21 09:53:01 +00:00
|
|
|
|
;; Reverse them again and make them back into a vector.
|
|
|
|
|
(vconcat (nreverse result)))
|
|
|
|
|
macro))
|
1993-09-21 03:44:04 +00:00
|
|
|
|
|
|
|
|
|
;;; Parsing a human-readable keyboard macro.
|
|
|
|
|
|
|
|
|
|
(defun edmacro-parse-keys (string &optional need-vector)
|
|
|
|
|
(let ((case-fold-search nil)
|
|
|
|
|
(pos 0)
|
|
|
|
|
(res []))
|
|
|
|
|
(while (and (< pos (length string))
|
|
|
|
|
(string-match "[^ \t\n\f]+" string pos))
|
|
|
|
|
(let ((word (substring string (match-beginning 0) (match-end 0)))
|
|
|
|
|
(key nil)
|
|
|
|
|
(times 1))
|
|
|
|
|
(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)))))
|
|
|
|
|
(cond ((string-match "^<<.+>>$" word)
|
|
|
|
|
(setq key (vconcat (if (eq (key-binding [?\M-x])
|
|
|
|
|
'execute-extended-command)
|
|
|
|
|
[?\M-x]
|
|
|
|
|
(or (car (where-is-internal
|
|
|
|
|
'execute-extended-command))
|
|
|
|
|
[?\M-x]))
|
|
|
|
|
(substring word 2 -2) "\r")))
|
|
|
|
|
((and (string-match "^\\(\\([ACHMsS]-\\)*\\)<\\(.+\\)>$" word)
|
|
|
|
|
(progn
|
|
|
|
|
(setq word (concat (substring word (match-beginning 1)
|
|
|
|
|
(match-end 1))
|
|
|
|
|
(substring word (match-beginning 3)
|
|
|
|
|
(match-end 3))))
|
|
|
|
|
(not (string-match
|
|
|
|
|
"\\<\\(NUL\\|RET\\|LFD\\|ESC\\|SPC\\|DEL\\)$"
|
|
|
|
|
word))))
|
|
|
|
|
(setq key (list (intern word))))
|
|
|
|
|
((or (equal word "REM") (string-match "^;;" word))
|
|
|
|
|
(setq pos (string-match "$" string pos)))
|
|
|
|
|
(t
|
|
|
|
|
(let ((orig-word word) (prefix 0) (bits 0))
|
|
|
|
|
(while (string-match "^[ACHMsS]-." word)
|
1995-02-08 03:50:54 +00:00
|
|
|
|
(incf bits (cdr (assq (aref word 0)
|
|
|
|
|
'((?A . ?\A-\^@) (?C . ?\C-\^@)
|
|
|
|
|
(?H . ?\H-\^@) (?M . ?\M-\^@)
|
|
|
|
|
(?s . ?\s-\^@) (?S . ?\S-\^@)))))
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(incf prefix 2)
|
|
|
|
|
(callf substring word 2))
|
|
|
|
|
(when (string-match "^\\^.$" word)
|
1995-02-08 03:50:54 +00:00
|
|
|
|
(incf bits ?\C-\^@)
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(incf prefix)
|
|
|
|
|
(callf substring word 1))
|
|
|
|
|
(let ((found (assoc word '(("NUL" . "\0") ("RET" . "\r")
|
|
|
|
|
("LFD" . "\n") ("TAB" . "\t")
|
|
|
|
|
("ESC" . "\e") ("SPC" . " ")
|
|
|
|
|
("DEL" . "\177")))))
|
|
|
|
|
(when found (setq word (cdr found))))
|
|
|
|
|
(when (string-match "^\\\\[0-7]+$" word)
|
|
|
|
|
(loop for ch across word
|
|
|
|
|
for n = 0 then (+ (* n 8) ch -48)
|
|
|
|
|
finally do (setq word (vector n))))
|
|
|
|
|
(cond ((= bits 0)
|
|
|
|
|
(setq key word))
|
1995-02-08 03:50:54 +00:00
|
|
|
|
((and (= bits ?\M-\^@) (stringp word)
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(string-match "^-?[0-9]+$" word))
|
|
|
|
|
(setq key (loop for x across word collect (+ x bits))))
|
|
|
|
|
((/= (length word) 1)
|
|
|
|
|
(error "%s must prefix a single character, not %s"
|
|
|
|
|
(substring orig-word 0 prefix) word))
|
1995-02-08 03:50:54 +00:00
|
|
|
|
((and (/= (logand bits ?\C-\^@) 0) (stringp word)
|
1997-01-31 07:48:16 +00:00
|
|
|
|
;; We used to accept . and ? here,
|
|
|
|
|
;; but . is simply wrong,
|
|
|
|
|
;; and C-? is not used (we use DEL instead).
|
|
|
|
|
(string-match "[@-_a-z]" word))
|
1995-02-08 03:50:54 +00:00
|
|
|
|
(setq key (list (+ bits (- ?\C-\^@)
|
1997-02-05 01:33:07 +00:00
|
|
|
|
(logand (aref word 0) 31)))))
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(t
|
|
|
|
|
(setq key (list (+ bits (aref word 0)))))))))
|
|
|
|
|
(when key
|
|
|
|
|
(loop repeat times do (callf vconcat res key)))))
|
|
|
|
|
(when (and (>= (length res) 4)
|
|
|
|
|
(eq (aref res 0) ?\C-x)
|
|
|
|
|
(eq (aref res 1) ?\()
|
|
|
|
|
(eq (aref res (- (length res) 2)) ?\C-x)
|
|
|
|
|
(eq (aref res (- (length res) 1)) ?\)))
|
1995-08-27 17:50:39 +00:00
|
|
|
|
(setq res (edmacro-subseq res 2 -2)))
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(if (and (not need-vector)
|
|
|
|
|
(loop for ch across res
|
2000-05-21 19:51:14 +00:00
|
|
|
|
always (and (char-valid-p ch)
|
1995-02-08 03:50:54 +00:00
|
|
|
|
(let ((ch2 (logand ch (lognot ?\M-\^@))))
|
1993-09-21 03:44:04 +00:00
|
|
|
|
(and (>= ch2 0) (<= ch2 127))))))
|
|
|
|
|
(concat (loop for ch across res
|
1995-02-08 03:50:54 +00:00
|
|
|
|
collect (if (= (logand ch ?\M-\^@) 0)
|
1993-09-21 03:44:04 +00:00
|
|
|
|
ch (+ ch 128))))
|
|
|
|
|
res)))
|
|
|
|
|
|
|
|
|
|
(provide 'edmacro)
|
1992-05-30 23:54:21 +00:00
|
|
|
|
|
2003-09-01 15:45:59 +00:00
|
|
|
|
;;; arch-tag: 726807b4-3ae6-49de-b0ae-b9590973e0d7
|
1992-05-30 23:54:21 +00:00
|
|
|
|
;;; edmacro.el ends here
|