forked from ovistoica/emacs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
init.el
229 lines (189 loc) · 7.05 KB
/
init.el
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
;; init.el -- master configuration file ;; -*- lexical-binding: t; -*-
;;; Commentary:
;;; Code:
;; DEBUG
;; (setq debug-on-error t)
;; (setq debug-on-quit t)
;;; VARIABLES
;;;; if you're not me, you probably want to change this to point to
;;;; where you put your checkout of the github repo:
(defvar os/emacs-dir (expand-file-name "~/.emacs.d/")
"Directory containing working copy of Emacs config repo.")
(defvar os/emacs-config-dir (concat os/emacs-dir "etc/")
"Sub-directory containing config files.")
(add-to-list 'load-path os/emacs-config-dir)
(defvar os/emacs-tmp-dir (concat os/emacs-dir "tmp/")
"Scratch space for stuff...")
;;;; I generally don't use the Customize interface, but sometimes
;;;; things get added there. Setting this means the file is under
;;;; revision control, so if something touches it, I'll notice (and
;;;; then I can move stuff to where it really goes and empty out
;;;; custom.el again...)
(setq custom-file (concat os/emacs-config-dir "custom.el"))
(load custom-file)
;;; DEFAULT DIRECTORY
;;;; This makes `find-file' in a buffer like `*scratch*' default to
;;;; $HOME instead of `/'
(setq default-directory "~/")
;;; ELPA
(require 'package)
(setq package-user-dir (concat os/emacs-dir "elpa"))
(setq package-native-compile t)
;;;; initialize ELPA, creating package directory if necessary
;;;; (and complaining if we're blocked by a file...)
(if (file-exists-p package-user-dir)
(if (file-directory-p package-user-dir)
(package-initialize)
(error "ELPA package dir creation blocked by file"))
(make-directory package-user-dir))
;;; PRIVATE CONFIG
;;;; Again, you might want to change this path to a private file of
;;;; your own. This is a place to put variables that set passwords,
;;;; email addresses, and other stuff that you don't want in a public
;;;; github repo...
(defvar os/private-config-file "~/.emacs.d/emacs-private.el"
"File with configuration info that can't be in public repository.")
(if (file-readable-p os/private-config-file)
(progn
(load-library os/private-config-file)
(message "Loaded private config")))
;;; PACKAGE
(eval-after-load "package"
'(setq package-archives
'(("gene-melpa" . "https://melpa.genehack.net/packages/")
("melpa" . "https://melpa.org/packages/")
("gnu" . "https://elpa.gnu.org/packages/"))))
(defvar os/packages-refreshed nil
"Flag for whether package lists have been refreshed yet.")
(defun os/package-refresh (&rest _args)
"Refresh package metadata, if needed."
(unless (eq os/packages-refreshed t)
(progn
(message "Refreshing package metadata...");
(package-refresh-contents)
(setq os/packages-refreshed t))))
(advice-add 'package-install :before #'os/package-refresh)
;;;; we need use-package -- it'll take care of installing everything else
(unless (package-installed-p 'use-package)
(package-install 'use-package))
(require 'use-package)
(add-to-list 'use-package-keywords :os/bind t)
(defun use-package-normalize/:os/bind (name keyword args)
"Custom use-keyword :os/bind.
I use this to provide something similar to ':bind', but with two
additional features that I miss from the default implementation:
Uses NAME KEYWORD ARGS
1. Integration with 'evil-define-key', so I can extend the keymap
declaration to specify one or more evil states that the
binding should apply to.
2. The ability to detect keymaps that aren't defined as prefix
commands. This allows me to define a binding to a keymap
variable, eg. maybe I want '<leader>h' to trigger 'help-map'.
This fails using the default ':bind', meaning that I have to
fall back to calling 'bind-key' manually if I want to assign a
prefix.
The expected form is slightly different to 'bind':
((:map (KEYMAP . STATE) (KEY . FUNC) (KEY . FUNC) ...)
(:map (KEYMAP . STATE) (KEY . FUNC) (KEY . FUNC) ...) ...)
STATE is the evil state. It can be nil or omitted entirely. If
given, it should be an argument suitable for passing to
'evil-define-key' -- meaning a symbol like 'normal', or a list
like '(normal insert)'."
(setq args (car args))
(unless (listp args)
(use-package-error ":os/bind expects ((:map (MAP . STATE) (KEY . FUNC) ..) ..)"))
(dolist (def args args)
(unless (and (eq (car def) :map)
(consp (cdr def))
(listp (cddr def)))
(use-package-error ":os/bind expects ((:map (MAP . STATE) (KEY . FUNC) ..) ..)"))))
(defun use-package-handler/:os/bind (name _keyword args rest state)
"Handler for ':os/bind' use-package extension.
See 'use-package-normalize/:os/bind' for docs."
(let ((body (use-package-process-keywords name rest
(use-package-plist-delete state :os/bind))))
(use-package-concat
`((with-eval-after-load ',name
,@(mapcan
(lambda (entry)
(let ((keymap (car (cadr entry)))
(state (cdr (cadr entry)))
(bindings (cddr entry)))
(mapcar
(lambda (binding)
(let ((key (car binding))
(val (if (and (boundp (cdr binding)) (keymapp (symbol-value (cdr binding))))
;; Keymaps need to be vars without quotes
(cdr binding)
;; But functions need to be quoted symbols
`(quote ,(cdr binding)))))
;; When state is provided, use evil-define-key. Otherwise fall back to bind-key.
(if state
`(evil-define-key ',state ,keymap (kbd ,key) ,val)
`(bind-key ,key ,val ,keymap))))
bindings)))
args)))
body)))
;;; GARBAGE COLLECTION MAGIC HACK
;;;; speeds startup?
(use-package gcmh
:ensure gcmh
:demand
:diminish
:functions
gcmh-mode
:init
(gcmh-mode 1))
;;;; per https://github.com/emacs-lsp/lsp-mode#performance
(setq read-process-output-max (* 10 1024 1024)) ;; 10mb
(setq gc-cons-threshold 200000000)
;;; EXEC-PATH-FROM-SHELL
(setenv "PLENV_ROOT" "/opt/plenv")
(use-package exec-path-from-shell
:ensure exec-path-from-shell
:demand
:functions
exec-path-from-shell-initialize
:init
;; FIXME seeing if this does anything... (setq exec-path-from-shell-check-startup-files nil)
(exec-path-from-shell-initialize)
:custom
(exec-path-from-shell-variables
'(
"CARGO_HOME"
"GOPATH"
"GOROOT"
"MANPATH"
"NVM_DIR"
"PATH"
"PLENV_ROOT"
"RUSTUP_HOME"
"SSH_AGENT_PID"
"SSH_AUTH_SOCK"
)))
;;; MODULES
;;;; All the rest of the config is split out into individual files, for
;;;; ease of use.
(defvar os/module-list
'(
"builtins"
"dired-config"
"straight"
"themes"
"treesitter"
"clojure"
"completions"
"keys"
"linters"
"misc-functions"
"misc-packages"
"ai"
"spelling"
"3e"
"dotenv-mode")
"List of modules to load on startup.")
(dolist (pkg os/module-list)
(if (file-readable-p (concat os/emacs-config-dir pkg ".el"))
(load-library pkg)))
(provide 'init)
;;; init.el ends here