From: Earl Hyatt Date: Sat, 19 Aug 2023 22:26:45 +0000 (-0400) Subject: Make using Edmacro easier for long sequences of keys X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=f25cd560654e25b1fb1b65a571a5d93059b46a9d;p=emacs.git Make using Edmacro easier for long sequences of keys * lisp/edmacro.el (edmacro-set-macro-to-region-lines) (edmacro-reverse-key-order): New command and user option to make working with longer lists of keys, such as from 'kmacro-edit-lossage', easier. (edit-kbd-macro): Move regexps used to identify parts of buffer to internal variables. (edmacro--macro-lines-regexp, edmacro-mode-font-lock-keywords): Allow noting whether the most recent line of keys is displayed first. (edmacro-mode-map): Bind the new command to 'C-c C-r'. (edmacro-mode): Describe the new command in the mode documentation string. * doc/emacs/kmacro.texi (Edit Keyboard Macro): Mention 'edmacro-insert-key' and the newly added 'edmacro-set-macro-to-region-lines' and 'edmacro-reverse-key-line-order'. * etc/NEWS (Edmacro): Add section describing the new features. (Bug#65605) --- diff --git a/doc/emacs/kmacro.texi b/doc/emacs/kmacro.texi index fc1402b489d..05095bc68b8 100644 --- a/doc/emacs/kmacro.texi +++ b/doc/emacs/kmacro.texi @@ -515,6 +515,19 @@ editing it. Type @kbd{C-h m} once in that buffer to display details of how to edit the macro. When you are finished editing, type @kbd{C-c C-c}. +@findex edmacro-insert-key +@findex edmacro-set-macro-to-region-lines + @code{edmacro-mode}, the major mode used by +@code{kmacro-edit-macro}, provides commands for more easily editing +the formatted macro. Use @kbd{C-c C-q} (@code{edmacro-insert-key}) to +insert the next key sequence that you type into the buffer using the +correct format, similar to @kbd{C-q} (@code{quoted-insert}). Use +@kbd{C-c C-r} (@code{edmacro-set-macro-to-region-lines}) to replace +the macro's text with the text in the region. If the region does not +begin at the start of a line or if it does not end at the end of a +line, the region is extended to include complete lines. If the region +ends at the beginning of a line, that final line is excluded. + @findex edit-kbd-macro @kindex C-x C-k e You can edit a named keyboard macro or a macro bound to a key by typing @@ -523,9 +536,13 @@ keyboard input that you would use to invoke the macro---@kbd{C-x e} or @kbd{M-x @var{name}} or some other key sequence. @findex kmacro-edit-lossage +@vindex edmacro-reverse-macro-lines @kindex C-x C-k l You can edit the last 300 keystrokes as a macro by typing -@kbd{C-x C-k l} (@code{kmacro-edit-lossage}). +@kbd{C-x C-k l} (@code{kmacro-edit-lossage}). By default, +your most recent keystrokes are listed at the bottom of the buffer. +To list a macro's key sequences in reverse order, set +@code{edmacro-reverse-macro-lines} to @code{t}. @node Keyboard Macro Step-Edit @section Stepwise Editing a Keyboard Macro diff --git a/etc/NEWS b/etc/NEWS index c146f464585..4e7ad25b484 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -772,6 +772,20 @@ neither of which have been supported by Emacs since version 23.1. The user option 'url-gateway-nslookup-program' and the function 'url-gateway-nslookup-host' are consequently also obsolete. ++++ +** Edmacro + +*** New command 'edmacro-set-macro-to-region-lines'. +Bound to 'C-c C-r', this command replaces the macro text with the +lines of the region. If needed, the region is extended to include +whole lines. If the region ends at the beginning of a line, that last +line is excluded. + +*** New user option 'edmacro-reverse-macro-lines'. +When this is non-nil, the lines of key sequences are displayed with +the most recent line fist. This is can be useful when working with +macros with many lines, such as from 'kmacro-edit-lossage'. + * New Modes and Packages in Emacs 30.1 diff --git a/lisp/edmacro.el b/lisp/edmacro.el index bbf5a7f0495..6cad8158321 100644 --- a/lisp/edmacro.el +++ b/lisp/edmacro.el @@ -73,9 +73,19 @@ Default nil means to write characters above \\177 in octal notation." :type 'boolean :group 'kmacro) +(defcustom edmacro-reverse-macro-lines nil + "Non-nil if `edit-kbd-macro' should show the most recent line of key sequences first. + +This is useful when dealing with long lists of key sequences, such as +from `kmacro-edit-lossage'." + :type 'boolean + :group 'kmacro + :version "30.1") + (defvar-keymap edmacro-mode-map "C-c C-c" #'edmacro-finish-edit - "C-c C-q" #'edmacro-insert-key) + "C-c C-q" #'edmacro-insert-key + "C-c C-r" #'edmacro-set-macro-to-region-lines) (defface edmacro-label '((default :inherit bold) @@ -88,7 +98,10 @@ Default nil means to write characters above \\177 in octal notation." :group 'kmacro) (defvar edmacro-mode-font-lock-keywords - `((,(rx bol (group (or "Command" "Key" "Macro") ":")) 0 'edmacro-label) + `((,(rx bol (group (or "Command" "Key" + (seq "Macro" (zero-or-one " (most recent line first)"))) + ":")) + 0 'edmacro-label) (,(rx bol (group ";; Keyboard Macro Editor. Press ") (group (*? nonl)) @@ -166,7 +179,13 @@ With a prefix argument, format the macro in a more concise way." (let* ((oldbuf (current-buffer)) (mmac (edmacro-fix-menu-commands mac)) (fmt (edmacro-format-keys mmac 1)) - (fmtv (edmacro-format-keys mmac (not prefix))) + (fmtv (let ((fmtv (edmacro-format-keys mmac (not prefix)))) + (if (not edmacro-reverse-macro-lines) + fmtv + (with-temp-buffer + (insert fmtv) + (reverse-region (point-min) (point-max)) + (buffer-string))))) (buf (get-buffer-create "*Edit Macro*"))) (message "Formatting keyboard macro...done") (switch-to-buffer buf) @@ -181,6 +200,9 @@ With a prefix argument, format the macro in a more concise way." (setq-local font-lock-defaults '(edmacro-mode-font-lock-keywords nil nil ((?\" . "w")))) (setq font-lock-multiline nil) + ;; Make buffer-local so that the commands still work + ;; even if the default value changes. + (make-local-variable 'edmacro-reverse-macro-lines) (erase-buffer) (insert (substitute-command-keys (concat @@ -202,7 +224,9 @@ With a prefix argument, format the macro in a more concise way." (insert "Key: none\n"))) (when (and mac-counter mac-format) (insert (format "Counter: %d\nFormat: \"%s\"\n" mac-counter mac-format)))) - (insert "\nMacro:\n\n") + (insert (format "\nMacro%s:\n\n" (if edmacro-reverse-macro-lines + " (most recent line first)" + ""))) (save-excursion (insert fmtv "\n")) (recenter '(4)) @@ -255,6 +279,33 @@ or nil, use a compact 80-column format." ;;; Commands for *Edit Macro* buffer. +(defvar edmacro--skip-line-regexp + "[ \t]*\\($\\|;;\\|REM[ \t\n]\\)" + "A regexp identifying lines that should be ignored.") + +(defvar edmacro--command-line-regexp + "Command:[ \t]*\\([^ \t\n]*\\)[ \t]*$" + "A regexp identifying the line containing the command name.") + +(defvar edmacro--key-line-regexp + "Key:\\(.*\\)$" + "A regexp identifying the line containing the bound key sequence.") + +(defvar edmacro--counter-line-regexp + "Counter:[ \t]*\\([^ \t\n]*\\)[ \t]*$" + "A regexp identifying the line containing the counter value.") + +(defvar edmacro--format-line-regexp + "Format:[ \t]*\"\\([^\n]*\\)\"[ \t]*$" + "A regexp identifying the line containing the counter format.") + +(defvar edmacro--macro-lines-regexp + (rx "Macro" + (zero-or-one " (most recent line first)") + ":" + (zero-or-more (any " \t\n"))) + "A regexp identifying the lines that precede the macro's contents.") + (defun edmacro-finish-edit () (interactive nil edmacro-mode) (unless (eq major-mode 'edmacro-mode) @@ -266,9 +317,9 @@ or nil, use a compact 80-column format." (top (point-min))) (goto-char top) (let ((case-fold-search nil)) - (while (cond ((looking-at "[ \t]*\\($\\|;;\\|REM[ \t\n]\\)") + (while (cond ((looking-at edmacro--skip-line-regexp) t) - ((looking-at "Command:[ \t]*\\([^ \t\n]*\\)[ \t]*$") + ((looking-at edmacro--command-line-regexp) (when edmacro-store-hook (error "\"Command\" line not allowed in this context")) (let ((str (match-string 1))) @@ -283,7 +334,7 @@ or nil, use a compact 80-column format." cmd))) (keyboard-quit)))) t) - ((looking-at "Key:\\(.*\\)$") + ((looking-at edmacro--key-line-regexp) (when edmacro-store-hook (error "\"Key\" line not allowed in this context")) (let ((key (kbd (match-string 1)))) @@ -303,21 +354,21 @@ or nil, use a compact 80-column format." (edmacro-format-keys key 1)))) (keyboard-quit)))))) t) - ((looking-at "Counter:[ \t]*\\([^ \t\n]*\\)[ \t]*$") + ((looking-at edmacro--counter-line-regexp) (when edmacro-store-hook (error "\"Counter\" line not allowed in this context")) (let ((str (match-string 1))) (unless (equal str "") (setq mac-counter (string-to-number str)))) t) - ((looking-at "Format:[ \t]*\"\\([^\n]*\\)\"[ \t]*$") + ((looking-at edmacro--format-line-regexp) (when edmacro-store-hook (error "\"Format\" line not allowed in this context")) (let ((str (match-string 1))) (unless (equal str "") (setq mac-format str))) t) - ((looking-at "Macro:[ \t\n]*") + ((looking-at edmacro--macro-lines-regexp) (goto-char (match-end 0)) nil) ((eobp) nil) @@ -336,7 +387,13 @@ or nil, use a compact 80-column format." (when (buffer-name obuf) (set-buffer obuf)) (message "Compiling keyboard macro...") - (let ((mac (edmacro-parse-keys str))) + (let ((mac (edmacro-parse-keys (if edmacro-reverse-macro-lines + (with-temp-buffer + (insert str) + (reverse-region (point-min) + (point-max)) + (buffer-string)) + str)))) (message "Compiling keyboard macro...done") (if store-hook (funcall store-hook mac) @@ -372,6 +429,36 @@ or nil, use a compact 80-column format." (insert (edmacro-format-keys key t) "\n") (insert (edmacro-format-keys key) " "))) +(defun edmacro-set-macro-to-region-lines (beg end) + "Set the macro text to lines of text in the buffer between BEG and END. + +Interactively, BEG and END are the beginning and end of the +region. If the region does not begin at the start of a line or +if it does not end at the end of a line, the region is extended +to include complete lines. If the region ends at the beginning +of a line, that final line is excluded." + (interactive "*r" edmacro-mode) + ;; Use `save-excursion' to restore region if there are any errors. + ;; If there are no errors, update the macro text, then go to the + ;; beginning of the macro text. + (let ((final-position)) + (save-excursion + (goto-char beg) + (unless (bolp) (setq beg (pos-bol))) + (goto-char end) + (unless (or (bolp) (eolp)) (setq end (pos-eol))) + (let ((text (buffer-substring beg end))) + (goto-char (point-min)) + (if (not (let ((case-fold-search nil)) + (re-search-forward edmacro--macro-lines-regexp nil t))) + (user-error "\"Macro:\" line not found") + (delete-region (match-end 0) + (point-max)) + (goto-char (point-max)) + (insert text) + (setq final-position (match-beginning 0))))) + (goto-char final-position))) + (defun edmacro-mode () "\\Keyboard Macro Editing mode. Press \ \\[edmacro-finish-edit] to save and exit. @@ -393,6 +480,10 @@ or \"none\" for no key bindings. You can edit these lines to change the places where the new macro is stored. +Press \\[edmacro-set-macro-to-region-lines] to replace the text following the \"Macro:\" line +with the text of the lines overlapping the region of text between +point and mark. If that region ends at the beginning of a line, +that final line is excluded. Format of keyboard macros during editing: