summaryrefslogtreecommitdiff
path: root/.config/emacs/site-lisp/increment.el
diff options
context:
space:
mode:
authorThomas Voss <mail@thomasvoss.com> 2024-10-16 22:04:33 +0200
committerThomas Voss <mail@thomasvoss.com> 2024-10-16 22:04:33 +0200
commit0ee7fa9c382ae30295f0b8d88457f7856c7ff800 (patch)
tree6b5a0cf01fa0bfa4d01b0134b268f5d993055c0b /.config/emacs/site-lisp/increment.el
parentd452ae1347b3711bc0a7ac80cfa2c37d9d63836e (diff)
emacs: Overhaul configuration completely
Diffstat (limited to '.config/emacs/site-lisp/increment.el')
-rw-r--r--.config/emacs/site-lisp/increment.el132
1 files changed, 132 insertions, 0 deletions
diff --git a/.config/emacs/site-lisp/increment.el b/.config/emacs/site-lisp/increment.el
new file mode 100644
index 0000000..b5bea53
--- /dev/null
+++ b/.config/emacs/site-lisp/increment.el
@@ -0,0 +1,132 @@
+;;; increment.el -- Increment numbers at point -*- lexical-binding: t; -*-
+
+(require 'cl-macs)
+(require 'rx)
+
+(defvar increment--binary-number-regexp
+ (rx (group (or ?- word-start))
+ "0b"
+ (group (* ?0))
+ (group (+ (any "01")))
+ word-end))
+
+(defvar increment--octal-number-regexp
+ (rx (group (or ?- word-start))
+ "0o"
+ (group (* ?0))
+ (group (+ (any "0-7")))
+ word-end))
+
+(defvar increment--decimal-number-regexp
+ (rx (group (? ?-))
+ (group (* ?0))
+ (group (+ (any digit)))))
+
+(defvar increment--hexadecimal-number-regexp
+ (rx (group (or ?- word-start))
+ "0x"
+ (group (* ?0))
+ (group (+ (any hex-digit)))
+ word-end))
+
+(defvar increment--hexadecimal-lower-number-regexp
+ (rx (group (or ?- word-start))
+ "0o"
+ (group (* ?0))
+ (group (+ (any "0-9a-f")))
+ word-end))
+
+(defvar increment--number-regexp
+ (rx (or (seq (or ?- word-start)
+ (or (seq "0b" (+ (any "01")))
+ (seq "0o" (+ (any "0-7")))
+ (seq "0x" (+ (any hex-digit))))
+ word-end)
+ (seq (? ?-) (+ (any digit))))))
+
+(defun increment--number-to-binary-string (number)
+ (nreverse
+ (cl-loop for x = number then (ash x -1)
+ while (not (= x 0))
+ concat (if (= 0 (logand x 1)) "0" "1"))))
+
+(defun increment--format-number-with-base
+ (number base leading-zeros buffer-substr hex-style)
+ (let* ((neg (> 0 number))
+ (number (abs number))
+ (number-string
+ (pcase base
+ (2 (increment--number-to-binary-string number))
+ (8 (format "%o" number))
+ (10 (number-to-string number))
+ (16 (format (if (eq hex-style 'lower) "%x" "%X") number))))
+ (length-diff (- (length buffer-substr)
+ (length number-string)))
+ (leading-zeros (if (> leading-zeros 0)
+ (+ leading-zeros length-diff)
+ 0)))
+ (concat
+ (when neg
+ "-")
+ (pcase base
+ (2 "0b")
+ (8 "0o")
+ (16 "0x"))
+ (when (> leading-zeros 0)
+ (make-string leading-zeros ?0))
+ number-string)))
+
+(defun increment--match-number-at-point ()
+ (cond ((thing-at-point-looking-at
+ increment--binary-number-regexp)
+ (cons 2 nil))
+ ((thing-at-point-looking-at
+ increment--octal-number-regexp)
+ (cons 8 nil))
+ ((thing-at-point-looking-at
+ increment--hexadecimal-number-regexp)
+ (cons 16 nil))
+ ((thing-at-point-looking-at
+ increment--hexadecimal-lower-number-regexp)
+ (cons 16 'lower))
+ ((thing-at-point-looking-at
+ increment--decimal-number-regexp)
+ (cons 10 nil))))
+
+;;;###autoload
+(cl-defun increment-number-at-point (&optional arg)
+ "Increment the number at point by ARG or 1 if ARG is nil. If called
+interactively, the universal argument can be used to specify ARG. If
+the number at point has leading zeros then the width of the number is
+preserved."
+ (interactive "*p")
+ (save-match-data
+ (let (case-fold-search
+ (match-pair (increment--match-number-at-point)))
+ (unless match-pair
+ (let ((save-point (point)))
+ (unless (re-search-forward
+ increment--number-regexp
+ (line-end-position) :noerror)
+ (goto-char save-point)
+ (cl-return-from increment-number-at-point))
+ (setq match-pair (increment--match-number-at-point))))
+ (let* ((base (car match-pair))
+ (hex-style (cdr match-pair))
+ (substr (buffer-substring-no-properties
+ (match-beginning 3) (match-end 3)))
+ (sign (if (= (match-beginning 1) (match-end 1)) +1 -1))
+ (result (+ (* (string-to-number substr base) sign)
+ (or arg 1))))
+ (replace-match
+ (increment--format-number-with-base
+ result base (- (match-end 2) (match-beginning 2))
+ substr hex-style))))))
+
+;;;###autoload
+(defun decrement-number-at-point (&optional arg)
+ "The same as `increment-number-at-point', but ARG is negated."
+ (interactive "*p")
+ (increment-number-at-point (- (or arg 1))))
+
+(provide 'increment)