consult-kmacro.el (3519B)
1 ;;; consult-kmacro.el --- Provides the command `consult-kmacro' -*- lexical-binding: t -*- 2 3 ;; Copyright (C) 2021-2024 Free Software Foundation, Inc. 4 5 ;; This file is part of GNU Emacs. 6 7 ;; This program is free software: you can redistribute it and/or modify 8 ;; it under the terms of the GNU General Public License as published by 9 ;; the Free Software Foundation, either version 3 of the License, or 10 ;; (at your option) any later version. 11 12 ;; This program is distributed in the hope that it will be useful, 13 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 14 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 ;; GNU General Public License for more details. 16 17 ;; You should have received a copy of the GNU General Public License 18 ;; along with this program. If not, see <https://www.gnu.org/licenses/>. 19 20 ;;; Commentary: 21 22 ;; Provides the command `consult-kmacro'. This is an extra package, 23 ;; to allow lazy loading of kmacro.el. The `consult-kmacro' command 24 ;; is autoloaded. 25 26 ;;; Code: 27 28 (require 'consult) 29 (require 'kmacro) 30 (eval-when-compile (require 'subr-x)) 31 32 (defvar consult-kmacro--history nil) 33 34 (defun consult-kmacro--candidates () 35 "Return alist of kmacros and indices." 36 (thread-last 37 ;; List of macros 38 (append (and last-kbd-macro (list (kmacro-ring-head))) kmacro-ring) 39 ;; Emacs 29 uses OClosures. I like OClosures but it would have been better 40 ;; if public APIs wouldn't change like that. 41 (mapcar (lambda (x) 42 (static-if (> emacs-major-version 28) 43 (list (kmacro--keys x) (kmacro--counter x) (kmacro--format x) x) 44 `(,@x ,x)))) 45 ;; Filter mouse clicks 46 (seq-remove (lambda (x) (seq-some #'mouse-event-p (car x)))) 47 ;; Format macros 48 (mapcar (pcase-lambda (`(,keys ,counter ,format ,km)) 49 (propertize 50 (format-kbd-macro keys 1) 51 'consult--candidate km 52 'consult-kmacro--annotation 53 ;; If the counter is 0 and the counter format is its default, 54 ;; then there is a good chance that the counter isn't actually 55 ;; being used. This can only be wrong when a user 56 ;; intentionally starts the counter with a negative value and 57 ;; then increments it to 0. 58 (cond 59 ((not (equal format "%d")) ;; show counter for non-default format 60 (format " (counter=%d, format=%s) " counter format)) 61 ((/= counter 0) ;; show counter if non-zero 62 (format " (counter=%d)" counter)))))) 63 (delete-dups))) 64 65 ;;;###autoload 66 (defun consult-kmacro (arg) 67 "Run a chosen keyboard macro. 68 69 With prefix ARG, run the macro that many times. 70 Macros containing mouse clicks are omitted." 71 (interactive "p") 72 (let ((km (consult--read 73 (or (consult-kmacro--candidates) 74 (user-error "No keyboard macros defined")) 75 :prompt "Keyboard macro: " 76 :category 'consult-kmacro 77 :require-match t 78 :sort nil 79 :history 'consult-kmacro--history 80 :annotate 81 (lambda (cand) 82 (get-text-property 0 'consult-kmacro--annotation cand)) 83 :lookup #'consult--lookup-candidate))) 84 ;; Kmacros are lambdas (oclosures) on Emacs 29 85 (funcall (static-if (> emacs-major-version 28) 86 km 87 (kmacro-lambda-form km)) 88 arg))) 89 90 (provide 'consult-kmacro) 91 ;;; consult-kmacro.el ends here