summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2025-09-06 23:03:27 -0500
committerCraig Jennings <c@cjennings.net>2025-09-06 23:03:27 -0500
commit4904553ae7d809286ed8993b17e37d3ec34e75d9 (patch)
treec07f7554f861842fe9e0145412ac920293de5e5b
parent5cd5a9cadf5624be581d40df6e41fc32a8220c84 (diff)
downloaddotemacs-4904553ae7d809286ed8993b17e37d3ec34e75d9.tar.gz
dotemacs-4904553ae7d809286ed8993b17e37d3ec34e75d9.zip
refactor(keyboard-macros): Improve structure and error handling
Reorganized the module to improve code structure and readability: - Removed duplicate definition of ensure-macros-file - Added explicit file creation before saving macros - Added proper error handling when loading macros file - Added function to save unnamed macros on exit - Grouped keybindings together - Cleaned up documentation formatting
-rw-r--r--modules/keyboard-macros.el69
1 files changed, 29 insertions, 40 deletions
diff --git a/modules/keyboard-macros.el b/modules/keyboard-macros.el
index cff25b39..a7605cfd 100644
--- a/modules/keyboard-macros.el
+++ b/modules/keyboard-macros.el
@@ -8,21 +8,20 @@
;; All commands are built on top of the built-in =kmacro= machinery, but
;; add a lightweight workflow and persistence across sessions.
;;
-;; User Workflow:
+;; Workflow:
;;
;; 1. Start recording with C-F3 (or M-x cj/kbd-macro-start-or-end)
;; This toggles macro recording on.
;; Now you can perform all the edits you want recorded in the macro.
;;
;; 2. Stop recording with C-F3 (or M-x cj/kbd-macro-start-or-end)
-;; This stops recording and the macro becomes the “last keyboard macro.”
+;; This stops recording and the macro becomes the "last keyboard macro."
;;
;; 3. Replay your macro <f3> (or M-x call-last-kbd-macro)
;;
;; 4. Name your macro with M-<F3>
;; You will be prompted for a short name (e.g. =align-comments=,
-;; =cleanup-trail-spaces=). This name is how you’ll refer to it later.
-;;
+;; =cleanup-trail-spaces=). This name is how you'll refer to it later.
;;
;; 5. Recall that macro later with M-x [the name you gave the macro]
;;
@@ -36,7 +35,7 @@
(require 'user-constants) ;; definition of sync-dir constant is here.
-(defvar macros-file (concat sync-dir "macros.el")
+(defvar macros-file (concat sync-dir "macros.el")
"The location of the macros file for recorded saved macros via M-f3.")
(defun ensure-macros-file (file)
@@ -45,22 +44,18 @@
(with-temp-file file
(insert ";;; -*- lexical-binding: t -*-\n"))))
-(when (file-exists-p macros-file)
- (load macros-file))
-
(defun cj/kbd-macro-start-or-end ()
"Toggle start/end of keyboard macro definition."
(interactive)
(if defining-kbd-macro
(end-kbd-macro)
(start-kbd-macro nil)))
-(global-set-key (kbd "C-<f3>") #'cj/kbd-macro-start-or-end)
-(global-set-key (kbd "<f3>") #'call-last-kbd-macro)
(defun cj/save-maybe-edit-macro (name)
"Save last macro as NAME in `macros-file'; edit if prefix arg."
(interactive "SName of macro: ")
(kmacro-name-last-macro name)
+ (ensure-macros-file macros-file)
(find-file macros-file)
(goto-char (point-max))
(newline)
@@ -72,40 +67,34 @@
(find-file macros-file)
(goto-char (point-max)))
name)
+
+(defun cj/open-macros-file ()
+ "Open the keyboard macros file."
+ (interactive)
+ (ensure-macros-file macros-file)
+ (find-file macros-file))
+
+;; Set up key bindings
+(global-set-key (kbd "C-<f3>") #'cj/kbd-macro-start-or-end)
+(global-set-key (kbd "<f3>") #'call-last-kbd-macro)
(global-set-key (kbd "M-<f3>") #'cj/save-maybe-edit-macro)
+(global-set-key (kbd "s-<f3>") #'cj/open-macros-file)
-(global-set-key (kbd "s-<f3>") (lambda () (interactive) (find-file macros-file)))
+;; Add hook to save any unnamed macros on exit if desired
+(defun cj/save-last-kbd-macro-on-exit ()
+ "Save the last keyboard macro before exiting Emacs if it's not saved."
+ (when (and last-kbd-macro (not (kmacro-name-last-macro)))
+ (when (y-or-n-p "Save last keyboard macro before exiting? ")
+ (call-interactively #'cj/save-maybe-edit-macro))))
-(defun ensure-macros-file (file)
- "Ensure FILE exists and its first line enables lexical-binding."
- (unless (file-exists-p file)
- (with-temp-file file
- (insert ";;; -*- lexical-binding: t -*-\n"))))
+(add-hook 'kill-emacs-hook #'cj/save-last-kbd-macro-on-exit)
+;; Load existing macros file with proper error handling
(when (file-exists-p macros-file)
- (load macros-file))
+ (condition-case err
+ (load macros-file)
+ (error
+ (message "Error loading keyboard macros file: %s" (error-message-string err)))))
(provide 'keyboard-macros)
-;;; keyboard-macros.el ends here.
-
-
-;; --------------------------------- ERT Tests ---------------------------------
-;; Run these tests with M-x ert RET t RET
-
-(require 'ert)
-
-(ert-deftest keyboard-macros/ensure-macros-file-creates-header ()
- "ensure-macros-file creates FILE with the right header."
- (let ((file (make-temp-file "macros-test" nil ".el")))
- (unwind-protect
- (progn
- (delete-file file)
- (should-not (file-exists-p file))
- (ensure-macros-file file)
- (should (file-exists-p file))
- (let ((contents (with-temp-buffer
- (insert-file-contents file)
- (buffer-string))))
- (should (string= contents ";;; -*- lexical-binding: t -*-\n"))))
- (when (file-exists-p file)
- (delete-file file)))))
+;;; keyboard-macros.el ends here