forked from Lambda-Emacs/lambda-emacs
-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinit.el
480 lines (416 loc) · 18.4 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
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
;;; init.el -*- lexical-binding: t; mode: emacs-lisp; coding:utf-8; fill-column: 80 -*-
;; Author: Colin McLear
;; Maintainer: Colin McLear
;; Version: 0.3
;; This file is not part of GNU Emacs
;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;; This is the base init file to load the entire emacs config. For ease of
;; navigation use outline-mode to cycle headlines open and closed (<Tab> and
;; <S-Tab>) to navigate through sections, and "imenu" to locate individual
;; use-package definitions.
;;; Code:
;;;; Startup
;;;;; System Variables
;; Check the system used
(defconst sys-linux (eq system-type 'gnu/linux))
(defconst sys-mac (eq system-type 'darwin))
(defconst sys-bsd (or sys-mac (eq system-type 'berkeley-unix)))
(defconst sys-win (memq system-type '(cygwin windows-nt ms-dos)))
;;;;; Directory Variables
;; We're going to define a number of directories that are used throughout this
;; configuration to store different types of files. This is a bit like the
;; `no-littering' package, and allows us to keep `user-emacs-directory' tidy.
(defconst lem-emacs-dir (expand-file-name user-emacs-directory)
"The path to the emacs.d directory.")
;; (defconst lem-local-dir (concat lem-emacs-dir ".local/")
;; "The root directory for local Emacs files.
;; This contains all elisp libraries as well as non-essential and/or
;; ephemeral files. There are two main directories --
;; lem-library-dir, which contains all libraries and packages, and
;; lem-var-dir, which contains non-essential files and emphemera.")
(defconst lem-library-dir (concat lem-emacs-dir "lambda-library/")
"The directory for 𝛌-Emacs Lisp libraries.
This will house all setup libraries and external libraries or packages.")
(defconst lem-user-dir (concat lem-library-dir "lambda-user/")
"Storage for personal elisp, scripts, and any other private files.")
(defconst lem-setup-dir (concat lem-library-dir "lambda-setup/")
"The storage location of the setup-init files.")
(defconst lem-var-dir (concat lem-emacs-dir "var/")
"The directory for non-essential file storage.
Contents are subject to change. Used by `lem-etc-dir' and
`lem-cache-dir'.")
(defconst lem-etc-dir (concat lem-var-dir "etc/")
"The directory for non-volatile storage.
These are not deleted or tampered with by emacs functions. Use
this for dependencies like servers or config files that are
stable (i.e. it should be unlikely that you need to delete them
if something goes wrong).")
(defconst lem-cache-dir (concat lem-var-dir "cache/")
"The directory for volatile storage.
Use this for transient files that are generated on the fly like
caches and ephemeral/temporary files. Anything that may need to
be cleared if there are problems.")
(defconst lem-default-config-file (concat lem-library-dir "lem-default-config.el")
"A sample default configuration of the personal config file to get the user started.")
;;;;; User Configuration Variables
;; Find the user configuration file
(defconst lem-config-file (expand-file-name "config.el" lem-user-dir)
"The user's configuration file.")
;; These next two variables are both optional, but maybe convenient.
;; They are used with the functions `lem-goto-projects' and `lem-goto-elisp-library'.
;; Set user project directory
(defcustom lem-project-dir nil "Set the directory for user projects."
:group 'lambda-emacs
:type 'string)
;; Set user elisp project dir
(defcustom lem-user-elisp-dir nil
"Directory for personal elisp projects."
:group 'lambda-emacs
:type 'string)
;;;;; Path Settings
;; Directory paths
(dolist (dir (list lem-library-dir lem-var-dir lem-etc-dir lem-cache-dir lem-user-dir lem-setup-dir))
(unless (file-directory-p dir)
(make-directory dir t)))
;;;;; Load Path
;; Add all configuration files to load-path
(eval-and-compile
(progn
(push lem-setup-dir load-path)
(push lem-user-dir load-path)))
;;;;; Exec Path
;; Set PATH properly for emacs. This should make a package like
;; `exec-path-from-shell' unnecessary
;; If on a mac using homebrew set path correctly
;; NOTE: the location of homebrew depends on whether we're on mac silicon
(when (and sys-mac
(shell-command-to-string "command -v brew"))
(defconst homebrew-bin (if (string= (shell-command-to-string "arch") "arm64") "/opt/homebrew/bin" "/usr/local/bin") "Path to homebrew bin packages.")
(defconst homebrew-sbin (if (string= (shell-command-to-string "arch") "arm64") "/opt/homebrew/sbin" "/usr/local/sbin") "Path to homebrew sbin packages."))
;; Define the system local bins
(defconst usr-local-bin "/usr/local/bin" "System bin.")
(defconst usr-local-sbin "/usr/local/sbin" "System sbin.")
;; Set paths
(setenv "PATH" (concat (when sys-mac (concat homebrew-bin ":" homebrew-sbin ":")) (getenv "PATH") ":" usr-local-bin ":" usr-local-sbin))
(setq exec-path (append exec-path (list (when sys-mac homebrew-bin) (when sys-mac homebrew-sbin) usr-local-bin usr-local-sbin)))
;;;;; Package Settings
;; Use straight to manage package installation and use-package to manage
;; settings. Defer package loading as much as possible to either the
;; after-init-hook or after some number of seconds of idle. This should produce
;; shorter startup times, which helps especially when doing, e.g., a quick
;; restart-and-check of something in emacs.
;;;;; Straight
;;;;;; Straight settings
;; Use straight.el to install all packages
;; https://github.com/raxod502/straight.el
;; Don't check packages on startup
(customize-set-variable 'straight-check-for-modifications '(check-on-save find-when-checking))
;; Set branch
(customize-set-variable 'straight-repository-branch "develop")
;; Set dir
(customize-set-variable 'straight-base-dir lem-var-dir)
;; Use use-package
(customize-set-variable 'straight-use-package-by-default t)
;; Check updates manually
(customize-set-variable 'straight-vc-git-auto-fast-forward nil)
;; Avoid problems with straight building with native-comp
;; See https://github.com/raxod502/straight.el/issues/757
(customize-set-variable 'native-comp-deferred-compilation-deny-list nil)
;; Tell straight.el about the profiles we are going to be using.
(customize-set-variable 'straight-profiles
'((nil . "default.el")
;; Packages which are pinned to a specific commit.
(pinned . "pinned.el")))
;;;;;; Bootstrap straight
(defvar bootstrap-version)
(let ((bootstrap-file
(expand-file-name "straight/repos/straight.el/bootstrap.el" straight-base-dir))
(bootstrap-version 5))
(unless (file-exists-p bootstrap-file)
(with-current-buffer
(url-retrieve-synchronously
"https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el"
'silent 'inhibit-cookies)
(goto-char (point-max))
(eval-print-last-sexp)))
(load bootstrap-file nil 'nomessage))
;;;;;; Straight-X
;; Use experimental straight commands
(require 'straight-x)
;; https://github.com/raxod502/straight.el#how-do-i-pin-package-versions-or-use-only-tagged-releases
(autoload #'straight-x-freeze-versions "straight-x")
;; package updates
;; use this workflow?
;; https://github.com/raxod502/straight.el/issues/354#issuecomment-465305063
(autoload #'straight-x-pull-all "straight-x")
;; async fetch
(autoload #'straight-x-fetch-all "straight-x")
;;;;; Use-Package
;; Install use package
(straight-use-package 'use-package)
;; Settings
(use-package use-package
:custom
(use-package-always-defer nil)
(use-package-verbose t)
;; This is really helpful for profiling
(use-package-minimum-reported-time 0)
(use-package-enable-imenu-support t)
(use-package-expand-minimally nil)
;; Let straight handle package install
(use-package-always-ensure nil))
;;;;; El-Patch
;; Package for helping advise/modify features of other packages
(use-package el-patch
:straight t
:custom
(el-patch-enable-use-package-integration t))
;;;;; Security
;; Properly verify outgoing ssl connections.
;; See https://glyph.twistedmatrix.com/2015/11/editor-malware.html
(use-package gnutls
:straight nil
:defer 1
:custom
(gnutls-verify-error t)
(gnutls-min-prime-bits 3072))
;;;;; Auto-compile
;; Automatically byte-recompile changed elisp libraries
(use-package auto-compile
:defer 1
:custom
(auto-compile-display-buffer nil)
(auto-compile-mode-line-counter nil)
(auto-compile-use-mode-line nil)
(auto-compile-update-autoloads t)
:config
(auto-compile-on-load-mode)
(auto-compile-on-save-mode))
;;;;; Command Line Switches
;; Conditionally load parts of config depending on command line switches.
;; This allows startup with a clean emacs that still recognizes straight.
;; Helpful for testing packages.
;; Use (straight-use-package) command to selectively load packages.
;; See https://emacs.stackexchange.com/a/34909/11934
;; For function switch see https://stackoverflow.com/a/4065412/6277148
;; NOTE: The variable here doesn't really do anything. It is just useful to keep
;; for a record of switches.
(defvar lem-config-switches
'("basic"
"clean"
"core"
"test")
"Custom switches for conditional loading from command line.
`clean' loads only the `init.el' file w/no personal config; `core'
loads the set of modules set in `lem-core-modules'; `test' loads
only a `lem-setup-test.el' file for easy testing.")
(defun lem--emacs-switches (switch)
"Depending on command line argument SWITCH, load Emacs with minimal settings & no modules; useful for testing."
(let ((found-switch (member switch command-line-args)))
(setq command-line-args (delete switch command-line-args))
found-switch))
;;;;; Emacs Build Version
;; When built with https://github.com/mclear-tools/build-emacs-macos, Emacs has
;; git-version patch to include git sha1 in emacs-version string.
(setq site-lisp "/Applications/Emacs.app/Contents/Resources/site-lisp/")
(when (file-exists-p (concat site-lisp "emacs-git-version.el"))
(require 'emacs-git-version))
(defun lem-emacs-version ()
"A convenience function to print the emacs-version in the echo-area/*messages* buffer and put
emacs-version string on the kill ring."
(interactive)
(let ((emacs (emacs-version)))
(message (emacs-version))
(kill-new emacs)))
;;;;; Outline Navigation
;; Navigate elisp files easily. Outline is a built-in library and we can easily
;; configure it to treat elisp comments as headings.
(use-package outline
:straight (:type built-in)
:hook (prog-mode . outline-minor-mode)
:bind (:map outline-minor-mode-map
("<tab>" . outline-cycle)
("S-<tab>" . outline-cycle-buffer)
("M-j" . outline-move-subtree-down)
("M-k" . outline-move-subtree-up)
("M-h" . outline-promote)
("M-l" . outline-demote))
:config
(add-hook 'emacs-lisp-mode-hook
(lambda ()
;; prevent `outline-level' from being overwritten by `lispy'
(setq-local outline-level #'outline-level)
;; setup heading regexp specific to `emacs-lisp-mode'
(setq-local outline-regexp ";;;\\(;* \\)")
;; heading alist allows for subtree-like folding
(setq-local outline-heading-alist
'((";;; " . 1)
(";;;; " . 2)
(";;;;; " . 3)
(";;;;;; " . 4)
(";;;;;;; " . 5))))))
;;;;; Measure Time Macro
;; Useful macro to wrap functions in for testing
;; See https://stackoverflow.com/q/23622296
(defmacro measure-time (&rest body)
"Measure the time it takes to evaluate BODY."
`(let ((time (current-time)))
,@body
(message "
;; ======================================================
;; *Elapsed time: %.06f*
;; ======================================================"
(float-time (time-since time)))))
;;;;; Load Configuration Modules
;; Lambda-Emacs loads a series of lisp-libraries or 'modules'. Which modules are
;; loaded is left to the user to set in `config.el', though if there is no
;; `config.el' file a default set of modules will be loaded.
(defun lem--default-modules ()
"Load a default configuration for 𝛌-Emacs."
(message "
;; ======================================================
;; *Loading default setup of 𝛌-Emacs Modules*
;; ======================================================")
(measure-time
(cl-dolist (mod (list
;; Core modules
'lem-setup-libraries
'lem-setup-settings
'lem-setup-functions
'lem-setup-server
'lem-setup-scratch
;; UI modules
'lem-setup-frames
'lem-setup-windows
'lem-setup-buffers
'lem-setup-fonts
'lem-setup-faces
'lem-setup-colors
'lem-setup-completion
'lem-setup-keybindings
'lem-setup-help
'lem-setup-modeline
'lem-setup-theme
'lem-setup-splash
;; Navigation & Search modules
'lem-setup-navigation
'lem-setup-dired
'lem-setup-search
;; Project & Tab/Workspace modules
'lem-setup-vc
'lem-setup-projects
'lem-setup-tabs
;; Writing modules
'lem-setup-writing
;; 'lem-setup-notes ;; coming soon!
'lem-setup-citation
;; Programming modules
'lem-setup-programming
'lem-setup-debug
'lem-setup-shell
;; Org modules (coming soon!)
;; 'lem-setup-org
;; 'lem-setup-org-extensions
;; Productivity
'lem-setup-pdf))
(require mod))))
(defun lem--minimal-modules ()
"Load 𝛌-Emacs with a minimal set of modules."
(message "
;; ======================================================
;; *Loading 𝛌-Emacs, with minimal modules*
;; ======================================================")
(measure-time
(cl-dolist (mod (list
;; Core modules
'lem-setup-libraries
'lem-setup-settings
'lem-setup-functions
'lem-setup-server
'lem-setup-scratch
;; UI modules
'lem-setup-frames
'lem-setup-windows
'lem-setup-buffers
'lem-setup-completion
'lem-setup-keybindings
'lem-setup-help
'lem-setup-modeline
'lem-setup-splash
;; Navigation & Search modules
'lem-setup-navigation
'lem-setup-dired
'lem-setup-search))
(require mod))))
;; Conditionally load configuration files based on command-line switches,
;; presence of user-config file, or the default set of modules.
(cond
;; Load a subset of modules only, ignore other configuration.
((lem--emacs-switches "-minimal")
(message "*Loading a subset of 𝛌-Emacs modules *only*, ignoring personal user configuration.*")
(lem--minimal-modules))
;; Load test module only. This is useful for testing a specific package
;; against vanilla/default emacs settings.
((lem--emacs-switches "-test")
(message "*Loading test module only*")
(require 'lem-setup-test))
;; Load no libraries other than the built-in icomplete, for better completion.
((lem--emacs-switches "-vanilla")
(message "*Do not load 𝛌-Emacs setup files. Loading a clean vanilla setup plus icomplete*")
(require 'lem-setup-icomplete))
;; Load user's personal config file (if it exists) and hasn't been bypassed
;; by a command-line switch to load the default libraries.
((and (not (lem--emacs-switches "-default"))
(file-exists-p lem-config-file))
(message "*Loading 𝛌-Emacs & user config*")
(load lem-config-file 'noerror))
;; Load default config
((lem--emacs-switches "-default")
(message "*Loading 𝛌-Emacs default modules")
(lem--default-modules)
;; MacOS settings - defer load until after init.
(when sys-mac
(message "*Load MacOS settings...*")
(measure-time
(run-with-idle-timer 1 nil
(function require)
'lem-setup-macos nil t))))
;; Ask if user would like to create a config file.
((when (not (file-exists-p lem-config-file))
(yes-or-no-p "Would you like to create a user configuration file? ")
(progn
(with-temp-file lem-config-file
(insert-file lem-default-config-file))
(load-file lem-config-file))))
;; Load default modules
(t
(message "*Loading 𝛌-Emacs default configuration files.*")
(lem--default-modules)
;; MacOS settings - defer load until after init.
(when sys-mac
(message "*Load MacOS settings...*")
(measure-time
(run-with-idle-timer 1 nil
(function require)
'lem-setup-macos nil t)))))
;;;; After Startup
;; reset file-name-handler-alist
(add-hook 'emacs-startup-hook (lambda ()
(setq file-name-handler-alist lem-file-name-handler-alist)
;; reset garbage collection
(setq gc-cons-threshold 800000)
;; Startup time
(message (format ";; ======================================================\n;; Emacs ready in %.2f seconds with %d garbage collections.\n;; ======================================================"
(float-time
(time-subtract after-init-time before-init-time)) gcs-done)
(put 'narrow-to-page 'disabled nil))))