summaryrefslogtreecommitdiff
path: root/modules/custom-misc.el
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2025-10-18 01:15:12 -0500
committerCraig Jennings <c@cjennings.net>2025-10-18 01:15:12 -0500
commit2172852efde2a5bdd16561411c2c8e53b98cbc5e (patch)
tree0d3c339aa5a8a3c1e7228bd0f1ce07d8d0975567 /modules/custom-misc.el
parentf59e3227404366599819a7b9fcc6c2f1d275c36a (diff)
refactor: custom-misc: Improve utility functions and modernize code
- Add comprehensive module documentation - Enhance jump-to-matching-paren with better delimiter detection and error handling - Add user feedback messages to format and fraction replacement functions - Modernize keybindings to use keymap-set instead of define-key - Fix potential advice stacking issue on file reload - Improve code formatting and consistency throughout
Diffstat (limited to 'modules/custom-misc.el')
-rw-r--r--modules/custom-misc.el111
1 files changed, 72 insertions, 39 deletions
diff --git a/modules/custom-misc.el b/modules/custom-misc.el
index 4d6a359a..0e5e5791 100644
--- a/modules/custom-misc.el
+++ b/modules/custom-misc.el
@@ -1,52 +1,82 @@
-;;; custom-misc.el --- -*- coding: utf-8; lexical-binding: t; -*-
+;;; custom-misc.el --- Miscellaneous utility functions -*- coding: utf-8; lexical-binding: t; -*-
;;; Commentary:
;;
-
+;; This module provides various utility functions for text manipulation,
+;; formatting, and navigation. Features include:
+;; - Jump between matching delimiters
+;; - Format regions/buffers (untabify, reindent, remove trailing whitespace)
+;; - Word counting with region awareness
+;; - Fraction glyph conversion (¼ ↔ 1/4)
+;; - Force align-regexp to use spaces instead of tabs
+;;
+;; All functions are bound to the cj/custom-keymap for easy access.
+;;
;;; Code:
+(eval-when-compile (require 'keybindings)) ;; for custom-keymap
-(defun cj/jump-to-matching-paren ()
- "Jump to the matching parenthesis when point is on one.
-Signal a message when point is not on a parenthesis."
+(defun cj/jump-to-matching-paren ()
+ "Jump to the matching delimiter if point is on (or just after) one.
+If not on a delimiter, show a message. Respects the current syntax table."
(interactive)
- (cond ((looking-at "\\s\(\\|\\s\{\\|\\s\[")
- (forward-list))
- ((looking-back "\\s\)\\|\\s\}\\|\\s\\]")
- (backward-list))
- (t (message "Cursor doesn't follow parenthesis, so there's no match."))))
+ (let* ((ca (char-after))
+ (cb (char-before))
+ ;; Check if on opening paren
+ (open-p (and ca (eq (char-syntax ca) ?\()))
+ ;; Check if on or just after closing paren
+ (close-p (or (and ca (eq (char-syntax ca) ?\)))
+ (and cb (eq (char-syntax cb) ?\))))))
+ (cond
+ ;; Jump forward from opening
+ (open-p
+ (condition-case err
+ (forward-sexp)
+ (scan-error
+ (message "No matching delimiter: %s" (error-message-string err)))))
+ ;; Jump backward from closing
+ (close-p
+ (condition-case err
+ (backward-sexp)
+ (scan-error
+ (message "No matching delimiter: %s" (error-message-string err)))))
+ ;; Not on delimiter
+ (t
+ (message "Point is not on a delimiter.")))))
+
(defun cj/format-region-or-buffer ()
"Reformat the region or the entire buffer.
-Replaces tabs with spaces, deletes trailing whitespace, and reindents the region."
+Replaces tabs with spaces, deletes trailing whitespace, and reindents."
(interactive)
(let ((start-pos (if (use-region-p) (region-beginning) (point-min)))
(end-pos (if (use-region-p) (region-end) (point-max))))
(save-excursion
(save-restriction
(narrow-to-region start-pos end-pos)
- (untabify (point-min) (point-max)))
- (indent-region (point-min) (point-max))
- (delete-trailing-whitespace))))
+ (untabify (point-min) (point-max))
+ (indent-region (point-min) (point-max))
+ (delete-trailing-whitespace (point-min) (point-max))))
+ (message "Formatted %s" (if (use-region-p) "region" "buffer"))))
+
(defun cj/count-words-buffer-or-region ()
"Count the number of words in the buffer or region.
-Display the result in the minibuffer and *Messages* buffer."
+Display the result in the minibuffer."
(interactive)
- (let ((begin (point-min))
- (end (point-max))
- (area_type "the buffer"))
- (when mark-active
- (setq begin (region-beginning)
- end (region-end)
- area_type "the region"))
- (message (format "There are %d words in %s." (count-words begin end) area_type))))
+ (let* ((use-region (use-region-p))
+ (begin (if use-region (region-beginning) (point-min)))
+ (end (if use-region (region-end) (point-max)))
+ (area-type (if use-region "the region" "the buffer")))
+ (message "There are %d words in %s." (count-words begin end) area-type)))
+
(defun cj/replace-fraction-glyphs (start end)
"Replace common fraction glyphs between START and END.
Operate on the buffer or region designated by START and END.
-Replace the text representations with glyphs when called with a \[universal-argument] prefix."
+Replace the text representations with glyphs when called with a
+\\[universal-argument] prefix."
(interactive (if (use-region-p)
(list (region-beginning) (region-end))
(list (point-min) (point-max))))
@@ -54,37 +84,40 @@ Replace the text representations with glyphs when called with a \[universal-argu
'(("1/4" . "¼")
("1/2" . "½")
("3/4" . "¾")
- ("1/3" . "⅓")
+ ("1/3" . "⅓")
("2/3" . "⅔"))
'(("¼" . "1/4")
("½" . "1/2")
("¾" . "3/4")
("⅓" . "1/3")
- ("⅔" . "2/3")))))
+ ("⅔" . "2/3"))))
+ (count 0))
(save-excursion
(dolist (r replacements)
(goto-char start)
(while (search-forward (car r) end t)
- (replace-match (cdr r)))))))
+ (replace-match (cdr r))
+ (setq count (1+ count)))))
+ (message "Replaced %d fraction%s" count (if (= count 1) "" "s"))))
(defun cj/align-regexp-with-spaces (orig-fun &rest args)
"Call ORIG-FUN with ARGS while temporarily disabling tabs for alignment.
-
-This advice ensures `align-regexp' uses spaces by binding `indent-tabs-mode' to nil."
+This advice ensures =align-regexp' uses spaces by binding =indent-tabs-mode'
+to nil."
(let ((indent-tabs-mode nil))
(apply orig-fun args)))
-(advice-remove 'align-regexp #'align-regexp-with-spaces) ; in case this is reloaded
+;; avoid double advice stacking in case the file is reloaded
+(advice-remove 'align-regexp #'cj/align-regexp-with-spaces)
(advice-add 'align-regexp :around #'cj/align-regexp-with-spaces)
-
-(define-key cj/custom-keymap ")" 'cj/jump-to-matching-paren)
-(define-key cj/custom-keymap "f" 'cj/format-region-or-buffer)
-(define-key cj/custom-keymap "W" 'cj/count-words-buffer-or-region)
-(define-key cj/custom-keymap "/" 'cj/replace-fraction-glyphs)
-(define-key cj/custom-keymap "A" 'align-regexp)
-(define-key cj/custom-keymap "B" 'toggle-debug-on-error)
-(define-key cj/custom-keymap "|" 'display-fill-column-indicator-mode)
+(keymap-set cj/custom-keymap ")" #'cj/jump-to-matching-paren)
+(keymap-set cj/custom-keymap "f" #'cj/format-region-or-buffer)
+(keymap-set cj/custom-keymap "W" #'cj/count-words-buffer-or-region)
+(keymap-set cj/custom-keymap "/" #'cj/replace-fraction-glyphs)
+(keymap-set cj/custom-keymap "A" #'align-regexp)
+(keymap-set cj/custom-keymap "B" #'toggle-debug-on-error)
+(keymap-set cj/custom-keymap "|" #'display-fill-column-indicator-mode)
(provide 'custom-misc)
-;;; custom-misc.el ends here.
+;;; custom-misc.el ends here