blob: c1f3cb56cf6f7e6535c3b692ac798661e864e009 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
|
;;; +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)
(save-excursion
(save-restriction
(widen)
(+lisp-sort-sexps
(point-min) (point-max)
;; Key function
nil
;; Sort function
(lambda (s1 s2)
(let ((s1 (cdr s1)) (s2 (cdr s2)))
(cond
;; 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))))))))))))
(defun +init-sort-then-save ()
"Sort init.el, then save it."
(interactive)
(+init-sort)
(if (fboundp #'user-save-buffer)
(user-save-buffer)
(save-buffer)))
;;; 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
(setf (alist-get "Setup" imenu-generic-expression nil nil 'string-equal)
(list
(rx (: bol (* space)
"(setup" (+ space)
(group (? "(") (* nonl))))
1)))
;;; 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
|