summaryrefslogtreecommitdiff
path: root/modules/system-utils.el
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2025-08-14 19:24:49 -0500
committerCraig Jennings <c@cjennings.net>2025-08-14 19:24:49 -0500
commit9278ddd4ea1a8b1a4c1edaa8894516e3f48d245b (patch)
tree1105519cd55a4ebbb1e91609e6aae7cc3929ddaf /modules/system-utils.el
parenta878e5ae99f750ecbbb723f98ef91d3404189a32 (diff)
downloaddotemacs-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/system-utils.el')
-rw-r--r--modules/system-utils.el382
1 files changed, 50 insertions, 332 deletions
diff --git a/modules/system-utils.el b/modules/system-utils.el
index e0121f0f..53992481 100644
--- a/modules/system-utils.el
+++ b/modules/system-utils.el
@@ -4,371 +4,89 @@
;;; Code:
+(require 'cl-lib)
+(require 'host-environment)
-;; ---------------------------------- Xdg-Open ---------------------------------
-;; open specific file extensions with the system's default mime-type handler
-
-(defun cj/xdg-open (&optional filename)
- (interactive)
- (let ((command (cond ((eq system-type 'gnu/linux) "xdg-open")
- ((eq system-type 'darwin) "open")
- ((eq system-type 'windows-nt) "start")
- (t ""))))
- (with-current-buffer (get-buffer-create "xdg-open.log")
- (goto-char (point-max))
- (insert (format "Running command %s\n" command))
- (let ((exit-code (call-process command nil t t (expand-file-name
- (or filename (dired-file-name-at-point))))))
- (insert (format "Exit code: %s\n" exit-code))))))
-
-(defun cj/find-file-auto (orig-fun &rest args)
- (let ((filename (car args)))
- (if (cl-find-if
- (lambda (regexp) (string-match regexp filename))
- '("\\.avi\\'"
- "\\.mp4\\'"
- "\\.divx\\'"
- "\\.flv\\'"
- "\\.mkv\\'"
- "\\.mpeg\\'"
- "\\.mov\\'"
- "\\.wav\\'"
- "\\.webm\\'"
- "\\.mp3\\'"
- "\\.opus\\'"
- "\\.ogg\\'"
- "\\.flac\\'"
- "\\.docx?\\'"
- "\\.pptx?\\'"
- "\\.xlsx?\\'"
- ))
- (progn
- (cj/xdg-open filename))
- (progn
- (apply orig-fun args)))))
-
-(advice-add 'find-file :around 'cj/find-file-auto)
-
-;; ---------------------------------- Ibuffer ----------------------------------
-
-(global-set-key [remap list-buffers] 'ibuffer) ;; use ibuffer, not list-buffers
-
-(use-package nerd-icons-ibuffer
- :defer .5
- :after nerd-icons
- :hook (ibuffer-mode . nerd-icons-ibuffer-mode)
- :config
- (setq nerd-icons-ibuffer-icon t)
- (setq nerd-icons-ibuffer-color-icon t)
- (setq nerd-icons-ibuffer-human-readable-size t))
-
-;; ------------------------ Killing Buffers And Windows ------------------------
-;; Accidentally killing buffers can lose data. these functions override common
-;; buffer killing functions and buries buffers on the
-;; 'cj/buffer-bury-alive-list' list rather than killing them. Allows for
-;; interactive adding to the 'cj/buffer-bury-alive-list' via 'C-u C-x k'
-
-;; BUFFER BURY ALIVE LIST
-(defvar cj/buffer-bury-alive-list '("*dashboard*"
- "*scratch*"
- "*Messages*"
- "*ChatGPT*")
- "Buffers that shouldn't be killed, but buried instead.")
-
-;; KILL BUFFER AND WINDOW
-(defun cj/kill-buffer-and-window ()
- "Kill current buffer and window.
-Buries buffers instead if they are on the cj/buffer-bury-alive-list."
- (interactive)
- (let ((target-buffer (current-buffer)))
- (delete-window)
- (cj/kill-buffer-or-bury-alive target-buffer)))
-(global-set-key (kbd "M-C") 'cj/kill-buffer-and-window)
-
-;; KILL OTHER WINDOW
-(defun cj/kill-other-window ()
- "Close the next window and kill any buffer in it.
-Buries buffers instead if they are on the cj/buffer-bury-alive-list."
- (interactive)
- (other-window 1)
- (let ((target-buffer (current-buffer)))
- (if (not (one-window-p)) (delete-window))
- (cj/kill-buffer-or-bury-alive target-buffer)))
-(global-set-key (kbd "M-O") 'cj/kill-other-window)
-
-;; KILL ALL OTHER BUFFERS AND WINDOWS
-(defun cj/kill-all-other-buffers-and-windows ()
- "Save buffers, then kill all other buffers and windows.
-Buries buffers instead if they are on the cj/buffer-bury-alive-list."
- (interactive)
- (save-some-buffers)
- (delete-other-windows)
- (mapc 'cj/kill-buffer-or-bury-alive (delq (current-buffer) (buffer-list))))
-(global-set-key (kbd "M-M") 'cj/kill-all-other-buffers-and-windows)
-
-;; KILL BUFFER OR BURY ALIVE
-(defun cj/kill-buffer-or-bury-alive (target-buffer)
- "Bury buffers on the bury-instead-list rather than killing them.
-With a prefix, add the TARGET-BUFFER to \='cj/buffer-bury-alive-list\='."
- (interactive "bKill or Add to bury (don't kill) buffer list: ")
- (with-current-buffer target-buffer
- (if current-prefix-arg
- (progn
- (add-to-list 'cj/buffer-bury-alive-list (buffer-name (current-buffer)))
- (message "Added %s to bury-alive-list" (buffer-name (current-buffer))))
- (if (member (buffer-name (current-buffer)) cj/buffer-bury-alive-list)
- (bury-buffer)
- (kill-buffer (current-buffer))))))
-(global-set-key [remap kill-buffer] #'cj/kill-buffer-or-bury-alive)
-
-;; --------------------------- Emacs Server Shutdown ---------------------------
-;; shuts down the Emacs server. useful with emacsclient.
-
-(defun server-shutdown ()
- "Save buffers, quit, and shutdown (kill) server."
- (interactive)
- (save-some-buffers)
- (kill-emacs))
-(global-set-key (kbd "C-<f10>") 'server-shutdown)
-(global-set-key (kbd "<f10>") 'save-buffers-kill-terminal)
-
-;; --------------------------------- Free Keys ---------------------------------
-;; Displays free keybindings. Allows indicating a specific key prefix.
-
-(use-package free-keys
- :defer 1
- :bind ("C-h C-k" . free-keys))
-
-;; --------------------------------- Sudo Edit ---------------------------------
-;; Edit a file the current buffer is visiting as sudo user.
+;; ---------------------------- Edit A File With Sudo ----------------------------
(use-package sudo-edit
:defer 1
:bind ("C-x M-f" . sudo-edit))
-;; --------------------------- Open File With Command --------------------------
-;; opens the current buffer's file with a command. Prompts if interactive.
-
-(defun cj/open-file-with-command (command)
- "Asynchronously open the file assocated with the current buffer with COMMAND.
-Don't automatically display output buffers, but keep them in buffer list."
+(defun cj/open-file-with (command)
+ "Asynchronously run COMMAND on the current buffer's file."
(interactive "MOpen with program: ")
- (let ((display-buffer-keywords
- '(("*Async Shell Command*" display-buffer-no-window (nil)))))
- (add-to-list 'display-buffer-alist display-buffer-keywords))
- (async-shell-command (format "%s \"%s\"" command buffer-file-name)))
+ (let ((display-buffer-alist
+ '(("\\*Async Shell Command\\*" display-buffer-no-window))))
+ (async-shell-command (format "%s \"%s\"" command buffer-file-name))))
-;; --------------------------------- Open With ---------------------------------
-;; automatically opens files with specific programs using file extensions.
+;; ------------------------------ Server Shutdown ------------------------------
-(use-package openwith
- :defer 1
- :config
- (setq openwith-associations
- (list
- (list (openwith-make-extension-regexp
- '("mpg" "mpeg" "mp3" "mp4" "webm" "avi" "wmv" "wav" "mov" "flv" "ogm" "ogg" "mkv"))
- "mpv"
- '(file))
- ;; removed jpg from list below as dashboard was opening nxiv
- (list (openwith-make-extension-regexp
- '("xbm" "pbm" "pgm" "ppm" "pnm" "png" "gif" "bmp" "tif"))
- "nsxiv"
- '(file))
- (list (openwith-make-extension-regexp
- '("odt" "odf" "xls" "xlsx" "doc" "docx"))
- "libreoffice"
- '(file))
- (list (openwith-make-extension-regexp
- '("cbr" "cbz"))
- "zathura"
- '(file)))))
+(defun server-shutdown ()
+ "Save buffers, kill Emacs and shutdown the server."
+ (interactive)
+ (save-some-buffers)
+ (kill-emacs))
+(global-set-key (kbd "C-<f10>") #'server-shutdown)
+(global-set-key (kbd "<f10>") #'save-buffers-kill-terminal)
-;; --------------------------------- Which Key ---------------------------------
-;; displays key bindings following your currently entered incomplete command
+;; ------------------------ List Buffers With Nerd Icons -----------------------
-(use-package which-key
- :defer 1
+(global-set-key [remap list-buffers] #'ibuffer)
+(use-package nerd-icons-ibuffer
+ :defer 0.5
+ :after nerd-icons
+ :hook (ibuffer-mode . nerd-icons-ibuffer-mode)
:config
- (setq which-key-idle-delay 3.0)
- (setq which-key-popup-type 'side-window)
- (add-to-list 'which-key-replacement-alist '((nil . "digit-argument") . t))
- (which-key-setup-side-window-right-bottom)
- (which-key-mode 1))
-
-;; ------------------------------- Scratch Buffer ------------------------------
-;; make the scratch buffer joyful, org-mode by default, and persistent.
-;; coding tip: org babel + code blocks allows for more flexibility and comments.
-
-(defvar scratch-emacs-version-and-system (concat ";; Welcome to Emacs "
- emacs-version " running on "
- system-configuration ".\n"))
-(defvar scratch-greet (concat ";; Emacs ♥ you, " user-login-name ". "
- "Happy Hacking!\n\n"))
-
-
-(setq initial-scratch-message (concat scratch-emacs-version-and-system
- scratch-greet))
-
-;; make scratch buffer an org-mode buffer
+ (setq nerd-icons-ibuffer-icon t
+ nerd-icons-ibuffer-color-icon t
+ nerd-icons-ibuffer-human-readable-size t))
+
+;; -------------------------- Scratch Buffer Happiness -------------------------
+
+;; Customize the scratch buffer
+(defvar scratch-emacs-version-and-system
+ (concat ";; Welcome to Emacs " emacs-version
+ " running on " system-configuration ".\n"))
+(defvar scratch-greet
+ (concat ";; Emacs ♥ you, " user-login-name ". Happy Hacking!\n\n"))
+(setq initial-scratch-message
+ (concat scratch-emacs-version-and-system scratch-greet))
(setq initial-major-mode 'org-mode)
-;; -------------------------------- World Clock --------------------------------
-;; displays current time in various timezones
-
-(use-package time
- :ensure nil ;; built-in
- :defer .5
- :bind ("C-x c" . world-clock)
- :config
- (setq world-clock-list
- '(("Pacific/Honolulu" " Honolulu")
- ("America/Los_Angeles" " San Francisco, Los Angeles")
- ("America/Chicago" " New Orleans, Chicago")
- ("America/New_York" " New York, Boston")
- ("Etc/UTC" " UTC ====================================")
- ("Europe/London" " London, Lisbon")
- ("Europe/Paris" " Paris, Berlin, Rome, Barcelona")
- ("Europe/Athens" " Athens, Istanbul, Kyiv, Moscow, Tel Aviv")
- ("Asia/Yerevan" " Yerevan")
- ("Asia/Kolkata" " India")
- ("Asia/Shanghai" " Shanghai, Singapore")
- ("Asia/Tokyo" " Tokyo, Seoul")))
- (setq world-clock-time-format " %a, %d %b @ %I:%M %p %Z"))
-
-;; ---------------------------------- Calendar ---------------------------------
-;; providing simple shortcuts
-;; backward and forward day are ',' and '.'
-;; shift & meta moves by week or year
-;; C-. jumps to today
-;; consistent with scheduling in org-mode
-
-(use-package calendar
- :defer .5
- :ensure nil ;; built-in
- :bind
- ("M-#" . calendar)
- (:map calendar-mode-map
- ("," . calendar-backward-day)
- ("." . calendar-forward-day)
- ("<" . calendar-backward-month)
- (">" . calendar-forward-month)
- ("M-," . calendar-backward-year)
- ("M-." . calendar-forward-year)))
-
;; --------------------------------- Dictionary --------------------------------
-;; install Webster's dictionary in StarDict format
-;; http://jsomers.net/blog/dictionary
(use-package sdcv
:defer 1
- :bind ("C-h d" . 'sdcv-search-input))
-
-;; ------------------------------ -Keyboard Macros -----------------------------
-;; note that this leverages simple, easy to remember shortcuts
-;;
-;; start a macro with C-f3, perform your actions, then finish with C-f3 (same key)
-;; run your macro by pressing f3
-;; if you wish to save and edit it (provide a keybinding), use C-u M-f3
-;; otherwise, jsut save it with M-f3 and call it with M-x (name you provided)
-
-(defun kbd-macro-start-or-end ()
- "Begins a keyboard macro definition, or if one's in progress, finish it."
- (interactive)
- (if defining-kbd-macro
- (end-kbd-macro)
- (start-kbd-macro nil)))
-(global-set-key (kbd "C-<f3>") '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)
-
-(defun cj/save-maybe-edit-macro (name)
- "Save a macro in `macros-file'.
-Save the last defined macro as NAME at the end of your `macros-file'
-The `macros-file' is defined in the constants section of the `init.el').
-The function offers the option to open the `macros-file' for editing when called
-with a prefix argument."
- (interactive "SName of the macro (w/o spaces): ")
- (kmacro-name-last-macro name)
- (find-file macros-file)
- (goto-char (point-max))
- (newline)
- (insert-kbd-macro name)
- (newline)
- ;; Save changes and switch back to previous buffer
- (save-buffer)
- (switch-to-buffer (other-buffer (current-buffer) 1))
- ;; Check for the prefix argument and open the macros-file to edit
- (if current-prefix-arg
- (progn
- (find-file macros-file)
- (goto-char (point-max))))
- ;; Return name for convenience
- name)
-
-;; now load all saved macros, creating an empty macro-file if it doesn't exist.
-(if (file-exists-p macros-file)
- (load macros-file)
- (progn
- (write-region ";;; -*- lexical-binding: t -*-\n" nil macros-file)
- (message "Saved macros file not found, so created: %s" macros-file)))
-
-;; -------------------------------- Abbrev Mode --------------------------------
-;; word abbreviations mode. used to auto-correct spelling (see flyspell-config)
-
-(use-package abbrev-mode
- :ensure nil ;; built-in
- :defer .5
- :custom
- (abbrev-file-name (concat user-emacs-directory "assets/abbrev_defs"))
- :config
- (abbrev-mode)) ;; use abbrev mode everywhere
+ :bind ("C-h d" . sdcv-search-input))
;; -------------------------------- Log Silently -------------------------------
-;; utility to silently log to the Messages buffer (for debugging/warning)
(defun cj/log-silently (text)
- "Send TEXT to the Messages buffer bypassing the echo area."
- (let ((inhibit-read-only t)
- (messages-buffer (get-buffer "*Messages*")))
- (with-current-buffer messages-buffer
- (goto-char (point-max))
- (unless (bolp)
- (insert "\n"))
- (insert text)
- (unless (bolp)
- (insert "\n")))))
+ "Append TEXT to *Messages* buffer without echoing in the minibuffer."
+ (let ((inhibit-read-only t))
+ (with-current-buffer (get-buffer-create "*Messages*")
+ (goto-char (point-max))
+ (unless (bolp) (insert "\n"))
+ (insert text)
+ (unless (bolp) (insert "\n")))))
-;; ----------------------------------- Proced ----------------------------------
-;; yes, there's a process monitor built-into Emacs. It's just not configured.
+;; ------------------------------ Process Monitor ------------------------------
(use-package proced
- :defer .5
- :ensure nil ;;built-in
+ :ensure nil ;; built-in
+ :defer 0.5
:commands proced
:bind ("C-M-p" . proced)
:custom
(proced-auto-update-flag t)
- (proced-goal-attribute nil)
(proced-show-remote-processes t)
(proced-enable-color-flag t)
(proced-format 'custom)
:config
- (add-to-list
- 'proced-format-alist
- '(custom user pid ppid sess tree pcpu pmem rss start time state (args
- comm))))
-
-;; ------------------------------------ TMR ------------------------------------
-
-(use-package tmr
- :defer .5
- :bind ("M-t" . tmr-prefix-map)
- :config
- (setq tmr-sound-file
- "/usr/share/sounds/freedesktop/stereo/alarm-clock-elapsed.oga")
- (setq tmr-notification-urgency 'normal)
- (setq tmr-descriptions-list 'tmr-description-history))
+ (add-to-list 'proced-format-alist
+ '(custom user pid ppid sess tree pcpu pmem rss start time
+ state (args comm))))
(provide 'system-utils)
;;; system-utils.el ends here