about summary refs log tree commit diff stats
path: root/lisp/+setup.el
blob: dce5d7b9ed0a07127a4cb8d165d1eb6e1e858182 (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
101
102
103
104
105
;;; +setup.el -- my `setup' commands -*- lexical-binding: t -*-

;; Author: Case Duckworth <acdw@acdw.net>

;; This file is NOT part of GNU Emacs.

;;; License:
;; Everyone is permitted to do whatever with this software, without
;; limitation.  This software comes without any warranty whatsoever,
;; but with two pieces of advice:
;; - Don't hurt yourself.
;; - Make good choices.

;;; Commentary:

;; `setup', by Philip Kaludercic, is a wonderful package that works
;; sort of like `use-package', but to my mind it's cleaner and easier
;; to extend.  These are my additions to the local macros provided by
;; the package.

;;; Code:

(require 'el-patch)
(require 'setup)
(require 'straight)

;; I don't like the "magic" `setup' performs to ensure a symbol is a
;; function in `:global', `:bind', `:hook', `:hook-into', and others.
;; So here, I'll just make it return the symbol unmodified.
(el-patch-feature setup)
(with-eval-after-load 'setup
  (el-patch-defvar
    (el-patch-add setup-ensure-function-inhibit nil
		  "Whether to inhibit `setup-ensure-function'."))
  (el-patch-defun setup-ensure-function (sexp)
    (el-patch-concat
      "Attempt to return SEXP as a quoted function name."
      (el-patch-add
	"\nIf `setup-ensure-function-inhibit' is non-nil, just return SEXP."))
    (el-patch-wrap 3 0
      (if (and setup-ensure-function-inhibit
               (not (eq sexp (setup-get 'mode))))
	  sexp
	(cond ((eq (car-safe sexp) 'function)
               sexp)
              ((eq (car-safe sexp) 'quote)
               `#',(cadr sexp))
              ((symbolp sexp)
               `#',sexp)
              (sexp))))))

(setup-define :face
    (lambda (face spec)
      `(custom-set-faces '(,face ,spec 'now "Customized by `setup'.")))
  :documentation "Customize FACE with SPEC using `custom-set-faces'."
  :repeatable t)

(setup-define :load-after
    (lambda (&rest features)
      (let ((body `(require ',(setup-get 'feature))))
	(dolist (feature (nreverse features))
	  (setq body `(with-eval-after-load ',feature ,body)))
	body))
  :documentation "Load the current feature after FEATURES.")

(setup-define :also-straight
    (lambda (recipe) `(setup (:straight ,recipe)))
  :documentation
  "Install RECIPE with `straight-use-package', after loading FEATURE."
  :repeatable t
  :after-loaded t)

(setup-define :straight
    (lambda (recipe)
      `(unless (straight-use-package ',recipe)
	     ,(setup-quit)))
  :documentation
  "Install RECIPE with `straight-use-package'.
This macro can be used as HEAD, and will replace itself with the
first RECIPE's package."
  :repeatable t
  :shorthand (lambda (sexp)
               (let ((recipe (cadr sexp)))
                 (if (consp recipe)
                     (car recipe)
                   recipe))))

(setup-define :straight-when
  (lambda (recipe condition)
    `(unless (and ,condition
		  (straight-use-package ',recipe))
       ,(setup-quit)))
  :documentation
  "Install RECIPE with `straight-use-package' when CONDITION is met.
If CONDITION is false, or if `straight-use-package' fails, stop
evaluating the body.  This macro can be used as HEAD, and will
replace itself with the RECIPE's package."
  :repeatable 2
  :indent 1
  :shorthand (lambda (sexp)
               (let ((recipe (cadr sexp)))
                 (if (consp recipe) (car recipe) recipe))))

(provide '+setup)
;;; +setup.el ends here