summaryrefslogtreecommitdiff
path: root/lisp/edmacro.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/edmacro.el')
-rw-r--r--lisp/edmacro.el194
1 files changed, 68 insertions, 126 deletions
diff --git a/lisp/edmacro.el b/lisp/edmacro.el
index 11d5541203a..bdc50c5885a 100644
--- a/lisp/edmacro.el
+++ b/lisp/edmacro.el
@@ -62,6 +62,7 @@
;;; Code:
(require 'cl-lib)
+(require 'seq)
(require 'kmacro)
;;; The user-level commands for editing macros.
@@ -72,11 +73,35 @@ Default nil means to write characters above \\177 in octal notation."
:type 'boolean
:group 'kmacro)
-(defvar edmacro-mode-map
- (let ((map (make-sparse-keymap)))
- (define-key map "\C-c\C-c" #'edmacro-finish-edit)
- (define-key map "\C-c\C-q" #'edmacro-insert-key)
- map))
+(defvar-keymap edmacro-mode-map
+ "C-c C-c" #'edmacro-finish-edit
+ "C-c C-q" #'edmacro-insert-key)
+
+(defface edmacro-label
+ '((default :inherit bold)
+ (((class color) (background dark)) :foreground "light blue")
+ (((min-colors 88) (class color) (background light)) :foreground "DarkBlue")
+ (((class color) (background light)) :foreground "blue")
+ (t :inherit bold))
+ "Face used for labels in `edit-kbd-macro'."
+ :version "29.1"
+ :group 'kmacro)
+
+(defvar edmacro-mode-font-lock-keywords
+ `((,(rx bol (group (or "Command" "Key" "Macro") ":")) 0 'edmacro-label)
+ (,(rx bol
+ (group ";; Keyboard Macro Editor. Press ")
+ (group (*? any))
+ (group " to finish; press "))
+ (1 'font-lock-comment-face)
+ (2 'help-key-binding)
+ (3 'font-lock-comment-face)
+ (,(rx (group (*? any))
+ (group " to cancel" (* any)))
+ nil nil
+ (1 'help-key-binding)
+ (2 'font-lock-comment-face)))
+ (,(rx (one-or-more ";") (zero-or-more any)) 0 'font-lock-comment-face)))
(defvar edmacro-store-hook)
(defvar edmacro-finish-hook)
@@ -86,7 +111,7 @@ Default nil means to write characters above \\177 in octal notation."
(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 `\\[kmacro-end-and-call-macro]' or RET to edit the last
+Or, type `\\[kmacro-end-and-call-macro]' or \\`RET' to edit the last
keyboard macro, `\\[view-lossage]' to edit the last 300
keystrokes as a keyboard macro, or `\\[execute-extended-command]'
to edit a macro by its command name.
@@ -99,8 +124,7 @@ With a prefix argument, format the macro in a more concise way."
(when keys
(let ((cmd (if (arrayp keys) (key-binding keys) keys))
(cmd-noremap (when (arrayp keys) (key-binding keys nil t)))
- (mac nil) (mac-counter nil) (mac-format nil)
- kmacro)
+ (mac nil) (mac-counter nil) (mac-format nil))
(cond (store-hook
(setq mac keys)
(setq cmd nil))
@@ -131,10 +155,10 @@ With a prefix argument, format the macro in a more concise way."
(t
(setq mac cmd)
(setq cmd nil)))
- (when (setq kmacro (kmacro-extract-lambda mac))
- (setq mac (car kmacro)
- mac-counter (nth 1 kmacro)
- mac-format (nth 2 kmacro)))
+ (when (kmacro-p mac)
+ (setq mac (kmacro--keys mac)
+ mac-counter (kmacro--counter mac)
+ mac-format (kmacro--format mac)))
(unless (arrayp mac)
(error "Key sequence %s is not a keyboard macro"
(key-description keys)))
@@ -154,9 +178,18 @@ With a prefix argument, format the macro in a more concise way."
(setq-local edmacro-original-buffer oldbuf)
(setq-local edmacro-finish-hook finish-hook)
(setq-local edmacro-store-hook store-hook)
+ (setq-local font-lock-defaults
+ '(edmacro-mode-font-lock-keywords nil nil nil nil))
+ (setq font-lock-multiline nil)
(erase-buffer)
- (insert ";; Keyboard Macro Editor. Press C-c C-c to finish; "
- "press C-x k RET to cancel.\n")
+ (insert (substitute-command-keys
+ (concat
+ ;; When editing this, make sure to update
+ ;; `edmacro-mode-font-lock-keywords' to match.
+ ";; Keyboard Macro Editor. Press \\[edmacro-finish-edit] "
+ "to finish; press \\[kill-buffer] \\`RET' to cancel.\n")
+ ;; Use 'no-face argument to not conflict with font-lock.
+ 'no-face))
(insert ";; Original keys: " fmt "\n")
(unless store-hook
(insert "\nCommand: " (if cmd (symbol-name cmd) "none") "\n")
@@ -222,7 +255,7 @@ or nil, use a compact 80-column format."
;;; Commands for *Edit Macro* buffer.
(defun edmacro-finish-edit ()
- (interactive)
+ (interactive nil edmacro-mode)
(unless (eq major-mode 'edmacro-mode)
(error
"This command is valid only in buffers created by `edit-kbd-macro'"))
@@ -252,15 +285,14 @@ or nil, use a compact 80-column format."
((looking-at "Key:\\(.*\\)$")
(when edmacro-store-hook
(error "\"Key\" line not allowed in this context"))
- (let ((key (edmacro-parse-keys
- (match-string 1))))
+ (let ((key (kbd (match-string 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))
- (not (kmacro-extract-lambda b))
+ (not (kmacro-p b))
(or (not (fboundp b))
(not (or (arrayp (symbol-function b))
(get b 'kmacro))))
@@ -313,10 +345,7 @@ or nil, use a compact 80-column format."
(when cmd
(if (= (length mac) 0)
(fmakunbound cmd)
- (fset cmd
- (if (and mac-counter mac-format)
- (kmacro-lambda-form mac mac-counter mac-format)
- mac))))
+ (fset cmd (kmacro mac mac-counter mac-format))))
(if no-keys
(when cmd
(cl-loop for key in (where-is-internal cmd '(keymap)) do
@@ -327,10 +356,8 @@ or nil, use a compact 80-column format."
(cl-loop for key in keys do
(global-set-key key
(or cmd
- (if (and mac-counter mac-format)
- (kmacro-lambda-form
- mac mac-counter mac-format)
- mac))))))))))
+ (kmacro mac mac-counter
+ mac-format))))))))))
(kill-buffer buf)
(when (buffer-name obuf)
(switch-to-buffer obuf))
@@ -339,7 +366,7 @@ or nil, use a compact 80-column format."
(defun edmacro-insert-key (key)
"Insert the written name of a KEY in the buffer."
- (interactive "kKey to insert: ")
+ (interactive "kKey to insert: " edmacro-mode)
(if (bolp)
(insert (edmacro-format-keys key t) "\n")
(insert (edmacro-format-keys key) " ")))
@@ -347,7 +374,7 @@ or nil, use a compact 80-column format."
(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.
+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.
@@ -537,8 +564,8 @@ doubt, use whitespace."
((integerp ch)
(concat
(cl-loop for pf across "ACHMsS"
- for bit in '(?\A-\^@ ?\C-\^@ ?\H-\^@
- ?\M-\^@ ?\s-\^@ ?\S-\^@)
+ for bit in '( ?\A-\0 ?\C-\0 ?\H-\0
+ ?\M-\0 ?\s-\0 ?\S-\0)
when (/= (logand ch bit) 0)
concat (format "%c-" pf))
(let ((ch2 (logand ch (1- (ash 1 18)))))
@@ -610,6 +637,12 @@ This function assumes that the events can be stored in a string."
(defun edmacro-fix-menu-commands (macro &optional noerror)
(if (vectorp macro)
(let (result)
+ ;; Not preloaded in without-x builds.
+ (require 'mwheel)
+ (defvar mouse-wheel-down-event)
+ (defvar mouse-wheel-left-event)
+ (defvar mouse-wheel-right-event)
+ (defvar mouse-wheel-up-event)
;; Make a list of the elements.
(setq macro (append macro nil))
(dolist (ev macro)
@@ -639,102 +672,11 @@ This function assumes that the events can be stored in a string."
;;; Parsing a human-readable keyboard macro.
-(defun edmacro-parse-keys (string &optional need-vector)
- (let ((case-fold-search nil)
- (len (length string)) ; We won't alter string in the loop below.
- (pos 0)
- (res []))
- (while (and (< pos len)
- (string-match "[^ \t\n\f]+" string pos))
- (let* ((word-beg (match-beginning 0))
- (word-end (match-end 0))
- (word (substring string word-beg len))
- (times 1)
- key)
- ;; Try to catch events of the form "<as df>".
- (if (string-match "\\`<[^ <>\t\n\f][^>\t\n\f]*>" word)
- (setq word (match-string 0 word)
- pos (+ word-beg (match-end 0)))
- (setq word (substring string word-beg word-end)
- pos word-end))
- (when (string-match "\\([0-9]+\\)\\*." word)
- (setq times (string-to-number (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 (match-string 1 word)
- (match-string 3 word)))
- (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)
- (cl-incf bits (cdr (assq (aref word 0)
- '((?A . ?\A-\^@) (?C . ?\C-\^@)
- (?H . ?\H-\^@) (?M . ?\M-\^@)
- (?s . ?\s-\^@) (?S . ?\S-\^@)))))
- (cl-incf prefix 2)
- (cl-callf substring word 2))
- (when (string-match "^\\^.$" word)
- (cl-incf bits ?\C-\^@)
- (cl-incf prefix)
- (cl-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)
- (cl-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))
- ((and (= bits ?\M-\^@) (stringp word)
- (string-match "^-?[0-9]+$" word))
- (setq key (cl-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))
- ((and (/= (logand bits ?\C-\^@) 0) (stringp word)
- ;; We used to accept . and ? here,
- ;; but . is simply wrong,
- ;; and C-? is not used (we use DEL instead).
- (string-match "[@-_a-z]" word))
- (setq key (list (+ bits (- ?\C-\^@)
- (logand (aref word 0) 31)))))
- (t
- (setq key (list (+ bits (aref word 0)))))))))
- (when key
- (cl-loop repeat times do (cl-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)) ?\)))
- (setq res (cl-subseq res 2 -2)))
- (if (and (not need-vector)
- (cl-loop for ch across res
- always (and (characterp ch)
- (let ((ch2 (logand ch (lognot ?\M-\^@))))
- (and (>= ch2 0) (<= ch2 127))))))
- (concat (cl-loop for ch across res
- collect (if (= (logand ch ?\M-\^@) 0)
- ch (+ ch 128))))
- res)))
+(defun edmacro-parse-keys (string &optional _need-vector)
+ (let ((result (kbd string)))
+ (if (stringp result)
+ (seq-into result 'vector)
+ result)))
(provide 'edmacro)