2021-11-22 05:57:41 +00:00
|
|
|
;;; +init.el --- extra init.el stuff -*- lexical-binding: t -*-
|
|
|
|
|
|
|
|
;;; Commentary:
|
|
|
|
|
|
|
|
;; Yes, I edit my init.el often enough I need to write a mode for it.
|
|
|
|
|
|
|
|
;;; Code:
|
|
|
|
|
|
|
|
(require '+lisp)
|
|
|
|
|
|
|
|
;;; Sort `setup' forms
|
|
|
|
|
|
|
|
(defun +init--sexp-setup-p (sexp-str &optional head)
|
|
|
|
"Is SEXP-STR a `setup' form, optionally with a HEAD form?"
|
|
|
|
(let ((head (if (and head (symbolp head))
|
|
|
|
(symbol-name head)
|
|
|
|
head)))
|
|
|
|
(and (string-match-p (rx (: bos (* whitespace) "(setup")) sexp-str)
|
|
|
|
(if head
|
|
|
|
(string-match-p (concat "\\`.*" head) sexp-str)
|
|
|
|
t))))
|
|
|
|
|
|
|
|
(defun +init-sort ()
|
|
|
|
"Sort init.el.
|
|
|
|
Sort based on the following heuristic: `setup' forms (the
|
|
|
|
majority of my init.el) are sorted after everything else, and
|
|
|
|
within that group, forms with a HEAD of `:require' are sorted
|
|
|
|
first, and `:straight' HEADs are sorted last. All other forms
|
|
|
|
are sorted lexigraphically."
|
|
|
|
(interactive)
|
2022-05-01 14:11:41 +00:00
|
|
|
;; I have to make my own "version" of `save-excursion', since the mark and
|
|
|
|
;; point are lost (I think that's the problem) when sorting the buffer.
|
|
|
|
(let* ((current-point (point))
|
|
|
|
(current-defun (beginning-of-defun))
|
|
|
|
(defun-point (- current-point (point)))
|
|
|
|
(current-defun-re (buffer-substring-no-properties (line-beginning-position)
|
|
|
|
(line-end-position))))
|
|
|
|
(widen) ; It makes no sense to `save-restriction'
|
|
|
|
(+lisp-sort-sexps
|
|
|
|
(point-min) (point-max)
|
|
|
|
;; Key function
|
|
|
|
nil
|
|
|
|
;; Sort function
|
|
|
|
(lambda (s1 s2)
|
|
|
|
(let ((s1 (cdr s1)) (s2 (cdr s2)))
|
2022-01-07 23:30:46 +00:00
|
|
|
(cond
|
2022-05-01 14:11:41 +00:00
|
|
|
;; Sort everything /not/ `setup' /before/ `setup'
|
|
|
|
((and (+init--sexp-setup-p s1)
|
|
|
|
(not (+init--sexp-setup-p s2)))
|
|
|
|
nil)
|
|
|
|
((and (+init--sexp-setup-p s2)
|
|
|
|
(not (+init--sexp-setup-p s1)))
|
|
|
|
t)
|
|
|
|
;; otherwise...
|
|
|
|
(t (let ((s1-straight (+init--sexp-setup-p s1 :straight))
|
|
|
|
(s2-straight (+init--sexp-setup-p s2 :straight))
|
|
|
|
(s1-require (+init--sexp-setup-p s1 :require))
|
|
|
|
(s2-require (+init--sexp-setup-p s2 :require)))
|
|
|
|
(cond
|
|
|
|
;; `:straight' setups have extra processing
|
|
|
|
((and s1-straight s2-straight)
|
|
|
|
(let* ((r (rx (: ":straight" (? "-when") (* space) (? "("))))
|
|
|
|
(s1 (replace-regexp-in-string r "" s1))
|
|
|
|
(s2 (replace-regexp-in-string r "" s2)))
|
|
|
|
(string< s1 s2)))
|
|
|
|
;; `:require' setups go first
|
|
|
|
((and s1-require (not s2-require)) t)
|
|
|
|
((and s2-require (not s1-require)) nil)
|
|
|
|
;; `:straight' setups go last
|
|
|
|
((and s1-straight (not s2-straight)) nil)
|
|
|
|
((and s2-straight (not s1-straight)) t)
|
|
|
|
;; otherwise, sort lexigraphically
|
|
|
|
(t (string< s1 s2)))))))))
|
|
|
|
;; Return to original point relative to the defun we were in
|
2022-05-06 15:23:02 +00:00
|
|
|
(ignore-errors (goto-char (point-min))
|
|
|
|
(re-search-forward current-defun-re)
|
|
|
|
(beginning-of-defun)
|
|
|
|
(goto-char (+ (point) defun-point)))))
|
2021-11-22 05:57:41 +00:00
|
|
|
|
2021-12-30 04:55:55 +00:00
|
|
|
(defun +init-sort-then-save ()
|
|
|
|
"Sort init.el, then save it."
|
|
|
|
(interactive)
|
|
|
|
(+init-sort)
|
2022-01-07 23:30:46 +00:00
|
|
|
(if (fboundp #'user-save-buffer)
|
|
|
|
(user-save-buffer)
|
|
|
|
(save-buffer)))
|
2021-12-30 04:55:55 +00:00
|
|
|
|
2021-11-22 05:57:41 +00:00
|
|
|
;;; Add `setup' forms to `imenu-generic-expression'
|
|
|
|
|
|
|
|
(defun +init-add-setup-to-imenu ()
|
|
|
|
"Recognize `setup' forms in `imenu'."
|
|
|
|
;; `imenu-generic-expression' automatically becomes buffer-local when set
|
2022-01-15 03:03:36 +00:00
|
|
|
(setf (alist-get "Setup" imenu-generic-expression nil nil #'equal)
|
|
|
|
(list
|
|
|
|
(rx (: "(setup" (+ space)
|
|
|
|
(group (? "(") (* nonl))))
|
|
|
|
1))
|
|
|
|
(when (boundp 'consult-imenu-config)
|
|
|
|
(setf (alist-get ?s
|
|
|
|
(plist-get
|
|
|
|
(alist-get 'emacs-lisp-mode consult-imenu-config)
|
|
|
|
:types))
|
|
|
|
'("Setup"))))
|
2021-11-22 05:57:41 +00:00
|
|
|
|
|
|
|
;;; Major mode
|
|
|
|
|
|
|
|
;;;###autoload
|
|
|
|
(define-derived-mode +init-mode emacs-lisp-mode "Init.el"
|
|
|
|
"`emacs-lisp-mode', but with a few specialized bits and bobs for init.el.")
|
|
|
|
|
|
|
|
;;;###autoload
|
|
|
|
(add-to-list 'auto-mode-alist '("/init\\.el\\'" . +init-mode))
|
|
|
|
|
|
|
|
(provide '+init)
|
|
|
|
;;; +init.el ends here
|