diff options
| author | Craig Jennings <c@cjennings.net> | 2025-08-14 19:24:49 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2025-08-14 19:24:49 -0500 |
| commit | 9278ddd4ea1a8b1a4c1edaa8894516e3f48d245b (patch) | |
| tree | 1105519cd55a4ebbb1e91609e6aae7cc3929ddaf /modules/keyboard-macros.el | |
| parent | a878e5ae99f750ecbbb723f98ef91d3404189a32 (diff) | |
| download | dotemacs-9278ddd4ea1a8b1a4c1edaa8894516e3f48d245b.tar.gz dotemacs-9278ddd4ea1a8b1a4c1edaa8894516e3f48d245b.zip | |
refactor(system-utils): major refactoring / adding tests
Theme:
Modularize system-utilities into separate modules.
Clean up any typos, buts, and unused variables.
Add some initial ERT tests for new modules created.
Changes:
- Extract file handling into its own module (file-config)
- Extract keyboard macro management into its own module (keyboard-macros)
- Extract buffer burying (instead of killing) into its own module (undead-buffers)
- Extract all date/time config into its own module (chrono-tools)
- Moved keybinding discovery functionality and help into keybindings module
- Combine flyspell and abbrev (spell-check and autocorrect) to flyspell-and-abbrev.el
- Rename epa-config.el to auth-config.el for auth-source and epa settings.
- Refactor `cj/kill-other-window` for more accurate buffer handling.
- Include "*ert*" in the default bury (don't kill) list as killing it kills test runs.
- Bind C-c M-m to inhibit-mouse-mode
- Remove the unused ledger-file variable in user-constants.el.
- Removed obsolete C-x x m, C-x x r, and C-x x d key mappings.
- C-; b r to call cj/rename-buffer-and-file instead of typo’d function
- Other purely cosmetic comment changes to system-utils.el
ERT tests:
- Rename ERT test definitions to include module scopes (file-config, keyboard-macros)
- Add an ERT test for the timer bell's existence.
- Add ERT tests to cover `cj/kill-buffer-or-bury-alive`, prefix-arg behavior, window-killing commands, and bulk operations.
- Add test `authinfo-file` exists Missing authinfo triggers a debug message
- Add test that `gpg2` executable is on the user’s PATH
- Remove outdated authinfo test.
- Add “Run these tests” note where missing.
Diffstat (limited to 'modules/keyboard-macros.el')
| -rw-r--r-- | modules/keyboard-macros.el | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/modules/keyboard-macros.el b/modules/keyboard-macros.el new file mode 100644 index 00000000..cff25b39 --- /dev/null +++ b/modules/keyboard-macros.el @@ -0,0 +1,111 @@ +;;; keyboard-macros.el --- Keyboard Macro Management -*- lexical-binding: t; -*- +;; author Craig Jennings <c@cjennings.net> + +;;; Commentary: +;; +;; This library provides a simple, end-user–focused interface for +;; creating, naming, saving, and replaying keyboard macros in Emacs. +;; All commands are built on top of the built-in =kmacro= machinery, but +;; add a lightweight workflow and persistence across sessions. +;; +;; User 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.” +;; +;; 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. +;; +;; +;; 5. Recall that macro later with M-x [the name you gave the macro] +;; +;; 6. View all your saved macros with s-<f3> (super-f3) +;; +;; 7. All macros reload at startup automatically. +;; When this library is loaded, it will look for the save file and +;; re-establish all your named macros in your current session. +;; +;;; Code: + +(require 'user-constants) ;; definition of sync-dir constant is here. + +(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) + "Ensure FILE exists and its first line enables lexical-binding." + (unless (file-exists-p file) + (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) + (find-file macros-file) + (goto-char (point-max)) + (newline) + (insert-kbd-macro name) + (newline) + (save-buffer) + (switch-to-buffer (other-buffer (current-buffer) 1)) + (when current-prefix-arg + (find-file macros-file) + (goto-char (point-max))) + name) +(global-set-key (kbd "M-<f3>") #'cj/save-maybe-edit-macro) + +(global-set-key (kbd "s-<f3>") (lambda () (interactive) (find-file macros-file))) + +(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")))) + +(when (file-exists-p macros-file) + (load macros-file)) + +(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))))) |
