about summary refs log tree commit diff
path: root/configs/shared/.emacs.d/wpc/prelude.el
blob: fb459627899d41b5837bc16a0b897e2b524fde3e (plain) (blame)
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
;;; prelude.el --- My attempt at augmenting Elisp stdlib -*- lexical-binding: t -*-
;; Author: William Carroll <wpcarro@gmail.com>

;;; Commentary:
;; Some of these ideas are scattered across other modules like `fs',
;; `string-functions', etc.  I'd like to keep everything modular.  I still don't
;; have an answer for which items belond in `misc'; I don't want that to become
;; a dumping grounds.  Ideally this file will `require' all other modules and
;; define just a handful of functions.

;; TODO: Consider removing all dependencies from prelude.el.

;;; Code:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Third-party libraries
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(require 's)
(require 'dash)
(require 'f)


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Libraries
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; TODO: Maybe don't globally import everything here.  Disable these and attepmt
;; to reload Emacs to assess damage.
(require 'string)
(require 'list)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Utilities
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defun prelude/to-string (x)
  "Convert X to a string."
  (format "%s" x))

(defun prelude/inspect (&rest args)
  "Message `ARGS' where ARGS are any type."
  (->> args
       (list/map #'prelude/to-string)
       (apply #'string/concat)
       message))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Assertions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; TODO: Should I `throw' instead of `error' here?
(defmacro prelude/assert (x)
  "Errors unless X is t.
These are strict assertions and purposely do not rely on truthiness."
  (let ((as-string (prelude/to-string x)))
    `(unless (equal t ,x)
       (error (string/concat "Assertion failed: " ,as-string)))))

(defmacro prelude/refute (x)
  "Errors unless X is nil."
  (let ((as-string (prelude/to-string x)))
    `(unless (equal nil ,x)
       (error (string/concat "Refutation failed: " ,as-string)))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Adapter functions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defun prelude/identity (x)
  "Return X unchanged."
  x)

(defun prelude/const (x)
  "Return a variadic lambda that will return X."
  (lambda (&rest _) x))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Miscellaneous
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; TODO: Consider packaging these into a linum-color.el package.
;; TODO: Generate the color used here from the theme.
(defvar linum/safe? nil
  "Flag indicating whether or not it is safe to work with `linum-mode'.")

(defvar linum/mru-color nil
  "Stores the color most recently attempted to be applied.")

(add-hook 'linum-mode-hook
          (lambda ()
            (setq linum/safe? t)
            (when (maybe/some? linum/mru-color)
              (set-face-foreground 'linum linum/mru-color))))

(defun prelude/set-line-number-color (color)
  "Safely set linum color to `COLOR'.

If this is called before Emacs initializes, the color will be stored in
`linum/mru-color' and applied once initialization completes.

Why is this safe?
If `(set-face-foreground 'linum)' is called before initialization completes,
Emacs will silently fail.  Without this function, it is easy to introduce
difficult to troubleshoot bugs in your init files."
  (if linum/safe?
      (set-face-foreground 'linum color)
    (setq linum/mru-color color)))

(defun prelude/prompt (prompt)
  "Read input from user with PROMPT."
  (read-string prompt))

(defun prelude/executable-exists? (name)
  "Return t if CLI tool NAME exists according to `exec-path'."
  (let ((file (locate-file name exec-path)))
    (if (maybe/some? file)
        (f-exists? file)
      nil)))

(provide 'prelude)
;;; prelude.el ends here