Refactor & reformat core.el

Backport a bit of core.el from our CLI rewrite.
This commit is contained in:
Henrik Lissner 2020-12-01 19:33:55 -05:00
parent b7f6532e4f
commit b5e948054c
No known key found for this signature in database
GPG key ID: 5F6C0EA160557395
5 changed files with 282 additions and 279 deletions

View file

@ -10,11 +10,9 @@
;; makes it 15-30% faster, but set it too high and we risk spiralling memory ;; makes it 15-30% faster, but set it too high and we risk spiralling memory
;; usage in longer sessions. ;; usage in longer sessions.
(setq gc-cons-threshold 134217728) ; 128mb (setq gc-cons-threshold 134217728) ; 128mb
;; Prioritize non-byte-compiled source files in non-interactive sessions to ;; Prioritize non-byte-compiled source files in non-interactive sessions to
;; prevent loading stale byte-code. ;; prevent loading stale byte-code.
(setq load-prefer-newer t) (setq load-prefer-newer t)
;; Ensure Doom runs out of this file's parent directory, where Doom is ;; Ensure Doom runs out of this file's parent directory, where Doom is
;; presumably installed. Use the EMACSDIR envvar to change this. ;; presumably installed. Use the EMACSDIR envvar to change this.
(setq user-emacs-directory (setq user-emacs-directory
@ -47,7 +45,7 @@
"EMACSDIR=~/.emacs.d doom sync") "EMACSDIR=~/.emacs.d doom sync")
"\n\n" "\n\n"
"Aborting...") "Aborting...")
(abbreviate-file-name (file-truename user-emacs-directory)) (abbreviate-file-name user-emacs-directory)
(abbreviate-file-name load-file-name))) (abbreviate-file-name load-file-name)))
(when (and (equal (user-real-uid) 0) (when (and (equal (user-real-uid) 0)
@ -57,6 +55,19 @@
"ever used on a non-root account.\n\n" "ever used on a non-root account.\n\n"
"Aborting..."))) "Aborting...")))
;; HACK Load `cl' and site files manually to prevent polluting logs and stdout
;; with deprecation and/or file load messages.
(let ((inhibit-message t))
(when (> emacs-major-version 26)
(require 'cl))
(unless site-run-file
(let ((tail load-path))
(while tail
(let ((default-directory (car tail)))
(load (expand-file-name "subdirs.el") t t t)
(setq tail (cdr tail)))))
(load "site-start" t t)))
;; Load the heart of the beast and its CLI processing library ;; Load the heart of the beast and its CLI processing library
(load (expand-file-name "core/core.el" user-emacs-directory) nil t) (load (expand-file-name "core/core.el" user-emacs-directory) nil t)
(require 'core-cli) (require 'core-cli)
@ -68,16 +79,6 @@
debug-on-error t debug-on-error t
debug-ignored-errors nil) debug-ignored-errors nil)
;; HACK Load `cl' and site files manually to prevent polluting logs and stdout
;; with deprecation and/or file load messages.
(quiet! (if EMACS27+ (require 'cl))
(let ((tail load-path))
(while tail
(let ((default-directory (car tail)))
(load (expand-file-name "subdirs.el") t t t)
(setq tail (cdr tail)))))
(load "site-start" t t))
(kill-emacs (kill-emacs
(pcase (pcase
(catch 'exit (catch 'exit

View file

@ -431,6 +431,9 @@ files, so we replace calls to `pp' with the much faster `prin1'."
;; a better *help* buffer ;; a better *help* buffer
:commands helpful--read-symbol :commands helpful--read-symbol
:init :init
;; Make `apropos' et co search more extensively. They're more useful this way.
(setq apropos-do-all t)
(global-set-key [remap describe-function] #'helpful-callable) (global-set-key [remap describe-function] #'helpful-callable)
(global-set-key [remap describe-command] #'helpful-command) (global-set-key [remap describe-command] #'helpful-command)
(global-set-key [remap describe-variable] #'helpful-variable) (global-set-key [remap describe-variable] #'helpful-variable)

View file

@ -82,72 +82,6 @@ Accepts the same arguments as `message'."
format-string) format-string)
,@args)))) ,@args))))
(defun doom-try-run-hook (hook)
"Run HOOK (a hook function) with better error handling.
Meant to be used with `run-hook-wrapped'."
(doom-log "Running doom hook: %s" hook)
(condition-case e
(funcall hook)
((debug error)
(signal 'doom-hook-error (list hook e))))
;; return nil so `run-hook-wrapped' won't short circuit
nil)
(defun doom-load-envvars-file (file &optional noerror)
"Read and set envvars from FILE.
If NOERROR is non-nil, don't throw an error if the file doesn't exist or is
unreadable. Returns the names of envvars that were changed."
(if (null (file-exists-p file))
(unless noerror
(signal 'file-error (list "No envvar file exists" file)))
(when-let
(env
(with-temp-buffer
(save-excursion
(setq-local coding-system-for-read 'utf-8)
(insert "\0\n") ; to prevent off-by-one
(insert-file-contents file))
(save-match-data
(when (re-search-forward "\0\n *\\([^#= \n]*\\)=" nil t)
(setq
env (split-string (buffer-substring (match-beginning 1) (point-max))
"\0\n"
'omit-nulls))))))
(setq-default
process-environment
(append (nreverse env)
(default-value 'process-environment))
exec-path
(append (split-string (getenv "PATH") path-separator t)
(list exec-directory))
shell-file-name
(or (getenv "SHELL")
(default-value 'shell-file-name)))
env)))
(defun doom-run-hook-on (hook-var triggers)
"Configure HOOK-VAR to be invoked exactly once after init whenever any of the
TRIGGERS are invoked. Once HOOK-VAR gets triggered, it resets to nil.
HOOK-VAR is a quoted hook.
TRIGGERS is a list of quoted hooks and/or sharp-quoted functions."
(let ((fn (intern (format "%s-h" hook-var))))
(fset
fn (lambda (&rest _)
(when after-init-time
(run-hook-wrapped hook-var #'doom-try-run-hook)
(set hook-var nil))))
(put hook-var 'permanent-local t)
(dolist (on triggers)
(if (functionp on)
(advice-add on :before fn)
(add-hook on fn)))))
;;
;;; Functional library
(defalias 'doom-partial #'apply-partially) (defalias 'doom-partial #'apply-partially)
(defun doom-rpartial (fn &rest args) (defun doom-rpartial (fn &rest args)

View file

@ -1,67 +1,11 @@
;;; core.el --- the heart of the beast -*- lexical-binding: t; -*- ;;; core.el --- the heart of the beast -*- lexical-binding: t; -*-
;; Prevent unwanted runtime builds in gccemacs (native-comp); packages are
;; compiled ahead-of-time when they are installed and site files are compiled
;; when gccemacs is installed.
(setq comp-deferred-compilation nil)
(eval-when-compile
(when (< emacs-major-version 26)
(error "Detected Emacs v%s. Doom only supports Emacs 26 and newer"
emacs-version)))
;; ;;
;;; Variables ;;; Initialize internal state
(defconst doom-version "2.0.9" (defconst doom-version "2.0.9"
"Current version of Doom Emacs.") "Current version of Doom Emacs.")
(defconst EMACS27+ (> emacs-major-version 26))
(defconst EMACS28+ (> emacs-major-version 27))
(defconst IS-MAC (eq system-type 'darwin))
(defconst IS-LINUX (eq system-type 'gnu/linux))
(defconst IS-WINDOWS (memq system-type '(cygwin windows-nt ms-dos)))
(defconst IS-BSD (or IS-MAC (eq system-type 'berkeley-unix)))
;; Unix tools look for HOME, but this is normally not defined on Windows.
(when (and IS-WINDOWS (null (getenv-internal "HOME")))
(setenv "HOME" (getenv "USERPROFILE")))
;; Ensure `doom-core-dir' is in `load-path'
(add-to-list 'load-path (file-name-directory load-file-name))
(defvar doom--initial-load-path load-path)
(defvar doom--initial-process-environment process-environment)
(defvar doom--initial-exec-path exec-path)
;; `file-name-handler-alist' is consulted on every `require', `load' and various
;; path/io functions. You get a minor speed up by nooping this. However, this
;; may cause problems on builds of Emacs where its site lisp files aren't
;; byte-compiled and we're forced to load the *.el.gz files (e.g. on Alpine)
(unless (or noninteractive (daemonp))
(defvar doom--initial-file-name-handler-alist file-name-handler-alist)
(setq file-name-handler-alist nil)
;; Restore `file-name-handler-alist', because it is needed for handling
;; encrypted or compressed files, among other things.
(defun doom-reset-file-handler-alist-h ()
;; Re-add rather than `setq', because file-name-handler-alist may have
;; changed since startup, and we want to preserve those.
(dolist (handler file-name-handler-alist)
(add-to-list 'doom--initial-file-name-handler-alist handler))
(setq file-name-handler-alist doom--initial-file-name-handler-alist))
(add-hook 'emacs-startup-hook #'doom-reset-file-handler-alist-h))
;; Just the bare necessities
(require 'subr-x)
(require 'cl-lib)
(require 'core-lib)
;;
;;; Global variables
(defvar doom-init-p nil (defvar doom-init-p nil
"Non-nil if Doom has been initialized.") "Non-nil if Doom has been initialized.")
@ -74,12 +18,45 @@
Use `doom-debug-mode' to toggle it. The --debug-init flag and setting the DEBUG Use `doom-debug-mode' to toggle it. The --debug-init flag and setting the DEBUG
envvar will enable this at startup.") envvar will enable this at startup.")
(defvar doom-interactive-p (not noninteractive) (defconst doom-interactive-p (not noninteractive)
"If non-nil, Emacs is in interactive mode.") "If non-nil, Emacs is in interactive mode.")
;;; Directories/files (defconst EMACS27+ (> emacs-major-version 26))
(defconst doom-emacs-dir (defconst EMACS28+ (> emacs-major-version 27))
(eval-when-compile (file-truename user-emacs-directory)) (defconst IS-MAC (eq system-type 'darwin))
(defconst IS-LINUX (eq system-type 'gnu/linux))
(defconst IS-WINDOWS (memq system-type '(cygwin windows-nt ms-dos)))
(defconst IS-BSD (or IS-MAC (eq system-type 'berkeley-unix)))
;; Unix tools look for HOME, but this is normally not defined on Windows.
(when (and IS-WINDOWS (null (getenv-internal "HOME")))
(setenv "HOME" (getenv "USERPROFILE"))
(setq abbreviated-home-dir nil))
;; Contrary to what many Emacs users have in their configs, you really don't
;; need more than this to make UTF-8 the default coding system:
(when (fboundp 'set-charset-priority)
(set-charset-priority 'unicode)) ; pretty
(prefer-coding-system 'utf-8) ; pretty
(setq locale-coding-system 'utf-8) ; please
;; The clipboard's on Windows could be in a wider (or thinner) encoding than
;; utf-8 (likely UTF-16), so let Emacs/the OS decide what encoding to use there.
(unless IS-WINDOWS
(setq selection-coding-system 'utf-8)) ; with sugar on top
;;; Custom error types
(define-error 'doom-error "Error in Doom Emacs core")
(define-error 'doom-hook-error "Error in a Doom startup hook" 'doom-error)
(define-error 'doom-autoload-error "Error in Doom's autoloads file" 'doom-error)
(define-error 'doom-module-error "Error in a Doom module" 'doom-error)
(define-error 'doom-private-error "Error in private config" 'doom-error)
(define-error 'doom-package-error "Error with packages" 'doom-error)
;;
;;; Directory variables
(defconst doom-emacs-dir user-emacs-directory
"The path to the currently loaded .emacs.d directory. Must end with a slash.") "The path to the currently loaded .emacs.d directory. Must end with a slash.")
(defconst doom-core-dir (concat doom-emacs-dir "core/") (defconst doom-core-dir (concat doom-emacs-dir "core/")
@ -89,9 +66,10 @@ envvar will enable this at startup.")
"The root directory for Doom's modules. Must end with a slash.") "The root directory for Doom's modules. Must end with a slash.")
(defconst doom-local-dir (defconst doom-local-dir
(if-let (localdir (getenv-internal "DOOMLOCALDIR")) (let ((localdir (getenv-internal "DOOMLOCALDIR")))
(if localdir
(expand-file-name (file-name-as-directory localdir)) (expand-file-name (file-name-as-directory localdir))
(concat doom-emacs-dir ".local/")) (concat doom-emacs-dir ".local/")))
"Root directory for local storage. "Root directory for local storage.
Use this as a storage location for this system's installation of Doom Emacs. Use this as a storage location for this system's installation of Doom Emacs.
@ -114,14 +92,15 @@ Use this for files that change often, like cache files. Must end with a slash.")
"Where Doom's documentation files are stored. Must end with a slash.") "Where Doom's documentation files are stored. Must end with a slash.")
(defconst doom-private-dir (defconst doom-private-dir
(if-let (doomdir (getenv-internal "DOOMDIR")) (let ((doomdir (getenv-internal "DOOMDIR")))
(if doomdir
(expand-file-name (file-name-as-directory doomdir)) (expand-file-name (file-name-as-directory doomdir))
(or (let ((xdgdir (or (let ((xdgdir
(expand-file-name "doom/" (expand-file-name "doom/"
(or (getenv-internal "XDG_CONFIG_HOME") (or (getenv-internal "XDG_CONFIG_HOME")
"~/.config")))) "~/.config"))))
(if (file-directory-p xdgdir) xdgdir)) (if (file-directory-p xdgdir) xdgdir))
"~/.doom.d/")) "~/.doom.d/")))
"Where your private configuration is placed. "Where your private configuration is placed.
Defaults to ~/.config/doom, ~/.doom.d or the value of the DOOMDIR envvar; Defaults to ~/.config/doom, ~/.doom.d or the value of the DOOMDIR envvar;
@ -142,47 +121,85 @@ which is loaded at startup (if it exists). This is helpful if Emacs can't
\(easily) be launched from the correct shell session (particularly for MacOS \(easily) be launched from the correct shell session (particularly for MacOS
users).") users).")
;;; Custom error types
(define-error 'doom-error "Error in Doom Emacs core") ;;
(define-error 'doom-hook-error "Error in a Doom startup hook" 'doom-error) ;;; Custom hooks
(define-error 'doom-autoload-error "Error in Doom's autoloads file" 'doom-error)
(define-error 'doom-module-error "Error in a Doom module" 'doom-error) (defvar doom-first-input-hook nil
(define-error 'doom-private-error "Error in private config" 'doom-error) "Transient hooks run before the first user input.")
(define-error 'doom-package-error "Error with packages" 'doom-error)
(defvar doom-first-file-hook nil
"Transient hooks run before the first interactively opened file.")
(defvar doom-first-buffer-hook nil
"Transient hooks run before the first interactively opened buffer.")
(defvar doom-after-reload-hook nil
"A list of hooks to run before `doom/reload' has reloaded Doom.")
(defvar doom-before-reload-hook nil
"A list of hooks to run after `doom/reload' has reloaded Doom.")
;; ;;
;;; Emacs core configuration ;;; Native Compilation support (http://akrl.sdf.org/gccemacs.html)
;; lo', longer logs ahoy, so to reliably locate lapses in doom's logic later ;; Prevent unwanted runtime builds in gccemacs (native-comp); packages are
(setq message-log-max 4096) ;; compiled ahead-of-time when they are installed and site files are compiled
;; when gccemacs is installed.
(setq comp-deferred-compilation nil)
;; Reduce debug output, well, unless we've asked for it. ;; Don't store eln files in ~/.emacs.d/eln-cache (they are likely to be purged
(setq debug-on-error doom-debug-p ;; when upgrading Doom).
jka-compr-verbose doom-debug-p) (when (boundp 'comp-eln-load-path)
(add-to-list 'comp-eln-load-path (concat doom-cache-dir "eln/")))
;; Contrary to what many Emacs users have in their configs, you really don't (with-eval-after-load 'comp
;; need more than this to make UTF-8 the default coding system: ;; HACK Disable native-compilation for some troublesome packages
(when (fboundp 'set-charset-priority) (mapc (doom-partial #'add-to-list 'comp-deferred-compilation-deny-list)
(set-charset-priority 'unicode)) ; pretty (let ((local-dir-re (concat "\\`" (regexp-quote doom-local-dir))))
(prefer-coding-system 'utf-8) ; pretty (list (concat local-dir-re ".*/evil-collection-vterm\\.el\\'")
(setq locale-coding-system 'utf-8) ; please ;; https://github.com/nnicandro/emacs-jupyter/issues/297
;; The clipboard's on Windows could be in a wider (or thinner) encoding than (concat local-dir-re ".*/jupyter-channel\\.el\\'")
;; utf-8 (likely UTF-16), so let Emacs/the OS decide what encoding to use there. (concat local-dir-re ".*/with-editor\\.el\\'")
(unless IS-WINDOWS (concat "\\`" (regexp-quote doom-autoloads-file) "\\'"))))
(setq selection-coding-system 'utf-8)) ; with sugar on top ;; Default to using all cores, rather than half of them, since we compile
;; things ahead-of-time in a non-interactive session.
(defadvice! doom--comp-use-all-cores-a ()
:override #'comp-effective-async-max-jobs
(if (zerop comp-async-jobs-number)
(setq comp-num-cpus (doom-num-cpus))
comp-async-jobs-number)))
;;
;;; Core libraries
;; Ensure Doom's core libraries are visible for loading
(add-to-list 'load-path doom-core-dir)
;; Just the... bear necessities~
(require 'subr-x)
(require 'cl-lib)
(require 'core-lib)
;;
;;; A quieter startup
;; Disable warnings from legacy advice system. They aren't useful, and what can ;; Disable warnings from legacy advice system. They aren't useful, and what can
;; we do about them, besides changing packages upstream? ;; we do about them, besides changing packages upstream?
(setq ad-redefinition-action 'accept) (setq ad-redefinition-action 'accept)
;; Make `apropos' et co search more extensively. They're more useful this way. ;; Reduce debug output, well, unless we've asked for it.
(setq apropos-do-all t) (setq debug-on-error doom-debug-p
jka-compr-verbose doom-debug-p)
;; A second, case-insensitive pass over `auto-mode-alist' is time wasted, and ;; Get rid of "For information about GNU Emacs..." message at startup, unless
;; indicates misconfiguration (or that the user needs to stop relying on case ;; we're in a daemon session where it'll say "Starting Emacs daemon." instead,
;; insensitivity). ;; which isn't so bad.
(setq auto-mode-case-fold nil) (unless (daemonp)
(advice-add #'display-startup-echo-area-message :override #'ignore))
;; Reduce *Message* noise at startup. An empty scratch buffer (or the dashboard) ;; Reduce *Message* noise at startup. An empty scratch buffer (or the dashboard)
;; is more than enough. ;; is more than enough.
@ -195,48 +212,6 @@ users).")
initial-major-mode 'fundamental-mode initial-major-mode 'fundamental-mode
initial-scratch-message nil) initial-scratch-message nil)
;; Get rid of "For information about GNU Emacs..." message at startup, unless
;; we're in a daemon session where it'll say "Starting Emacs daemon." instead,
;; which isn't so bad.
(unless (daemonp)
(advice-add #'display-startup-echo-area-message :override #'ignore))
;; Emacs "updates" its ui more often than it needs to, so we slow it down
;; slightly from 0.5s:
(setq idle-update-delay 1.0)
;; Emacs is essentially one huge security vulnerability, what with all the
;; dependencies it pulls in from all corners of the globe. Let's try to be at
;; least a little more discerning.
(setq gnutls-verify-error (not (getenv-internal "INSECURE"))
gnutls-algorithm-priority
(when (boundp 'libgnutls-version)
(concat "SECURE128:+SECURE192:-VERS-ALL"
(if (and (not IS-WINDOWS)
(not (version< emacs-version "26.3"))
(>= libgnutls-version 30605))
":+VERS-TLS1.3")
":+VERS-TLS1.2"))
;; `gnutls-min-prime-bits' is set based on recommendations from
;; https://www.keylength.com/en/4/
gnutls-min-prime-bits 3072
tls-checktrust gnutls-verify-error
;; Emacs is built with `gnutls' by default, so `tls-program' would not be
;; used in that case. Otherwise, people have reasons to not go with
;; `gnutls', we use `openssl' instead. For more details, see
;; https://redd.it/8sykl1
tls-program '("openssl s_client -connect %h:%p -CAfile %t -nbio -no_ssl3 -no_tls1 -no_tls1_1 -ign_eof"
"gnutls-cli -p %p --dh-bits=3072 --ocsp --x509cafile=%t \
--strict-tofu --priority='SECURE192:+SECURE128:-VERS-ALL:+VERS-TLS1.2:+VERS-TLS1.3' %h"
;; compatibility fallbacks
"gnutls-cli -p %p %h"))
;; Emacs stores `authinfo' in $HOME and in plain-text. Let's not do that, mkay?
;; This file stores usernames, passwords, and other such treasures for the
;; aspiring malicious third party.
(setq auth-sources (list (concat doom-etc-dir "authinfo.gpg")
"~/.authinfo.gpg"))
;; ;;
;;; Don't litter `doom-emacs-dir' ;;; Don't litter `doom-emacs-dir'
@ -268,35 +243,14 @@ config.el instead."
(apply orig-fn args))) (apply orig-fn args)))
;;
;;; Native Compilation support (http://akrl.sdf.org/gccemacs.html)
;; Don't store eln files in ~/.emacs.d/eln-cache (they are likely to be purged
;; when upgrading Doom).
(when (boundp 'comp-eln-load-path)
(add-to-list 'comp-eln-load-path (concat doom-cache-dir "eln/")))
(with-eval-after-load 'comp
;; HACK Disable native-compilation for some troublesome packages
(dolist (entry (list (concat "\\`" (regexp-quote doom-local-dir) ".*/evil-collection-vterm\\.el\\'")
;; https://github.com/nnicandro/emacs-jupyter/issues/297
(concat "\\`" (regexp-quote doom-local-dir) ".*/jupyter-channel\\.el\\'")
(concat "\\`" (regexp-quote doom-local-dir) ".*/with-editor\\.el\\'")
(concat "\\`" (regexp-quote doom-autoloads-file) "'")))
(add-to-list 'comp-deferred-compilation-deny-list entry))
;; Default to using all cores, rather than half of them, since we compile
;; things ahead-of-time in a non-interactive session.
(defadvice! doom--comp-use-all-cores-a ()
:override #'comp-effective-async-max-jobs
(if (zerop comp-async-jobs-number)
(setq comp-num-cpus (doom-num-cpus))
comp-async-jobs-number)))
;; ;;
;;; Optimizations ;;; Optimizations
;; A second, case-insensitive pass over `auto-mode-alist' is time wasted, and
;; indicates misconfiguration (or that the user needs to stop relying on case
;; insensitivity).
(setq auto-mode-case-fold nil)
;; Disable bidirectional text rendering for a modest performance boost. I've set ;; Disable bidirectional text rendering for a modest performance boost. I've set
;; this to `nil' in the past, but the `bidi-display-reordering's docs say that ;; this to `nil' in the past, but the `bidi-display-reordering's docs say that
;; is an undefined state and suggest this to be just as good: ;; is an undefined state and suggest this to be just as good:
@ -318,13 +272,23 @@ config.el instead."
;; quickly self-correct. ;; quickly self-correct.
(setq fast-but-imprecise-scrolling t) (setq fast-but-imprecise-scrolling t)
;; Don't ping things that look like domain names.
(setq ffap-machine-p-known 'reject)
;; Resizing the Emacs frame can be a terribly expensive part of changing the ;; Resizing the Emacs frame can be a terribly expensive part of changing the
;; font. By inhibiting this, we halve startup times, particularly when we use ;; font. By inhibiting this, we halve startup times, particularly when we use
;; fonts that are larger than the system default (which would resize the frame). ;; fonts that are larger than the system default (which would resize the frame).
(setq frame-inhibit-implied-resize t) (setq frame-inhibit-implied-resize t)
;; Don't ping things that look like domain names. ;; Adopt a sneaky garbage collection strategy of waiting until idle time to
(setq ffap-machine-p-known 'reject) ;; collect; staving off the collector while the user is working.
(setq gcmh-idle-delay 5
gcmh-high-cons-threshold (* 16 1024 1024) ; 16mb
gcmh-verbose doom-debug-p)
;; Emacs "updates" its ui more often than it needs to, so we slow it down
;; slightly from 0.5s:
(setq idle-update-delay 1.0)
;; Font compacting can be terribly expensive, especially for rendering icon ;; Font compacting can be terribly expensive, especially for rendering icon
;; fonts on Windows. Whether disabling it has a notable affect on Linux and Mac ;; fonts on Windows. Whether disabling it has a notable affect on Linux and Mac
@ -344,12 +308,6 @@ config.el instead."
(unless IS-MAC (setq command-line-ns-option-alist nil)) (unless IS-MAC (setq command-line-ns-option-alist nil))
(unless IS-LINUX (setq command-line-x-option-alist nil)) (unless IS-LINUX (setq command-line-x-option-alist nil))
;; Adopt a sneaky garbage collection strategy of waiting until idle time to
;; collect; staving off the collector while the user is working.
(setq gcmh-idle-delay 5
gcmh-high-cons-threshold (* 16 1024 1024) ; 16mb
gcmh-verbose doom-debug-p)
;; HACK `tty-run-terminal-initialization' is *tremendously* slow for some ;; HACK `tty-run-terminal-initialization' is *tremendously* slow for some
;; reason; inexplicably doubling startup time for terminal Emacs. Keeping ;; reason; inexplicably doubling startup time for terminal Emacs. Keeping
;; it disabled will have nasty side-effects, so we simply delay it until ;; it disabled will have nasty side-effects, so we simply delay it until
@ -363,6 +321,42 @@ config.el instead."
(tty-run-terminal-initialization (selected-frame) nil t)))) (tty-run-terminal-initialization (selected-frame) nil t))))
;;
;;; Security
;; Emacs is essentially one huge security vulnerability, what with all the
;; dependencies it pulls in from all corners of the globe. Let's try to be at
;; least a little more discerning.
(setq gnutls-verify-error (not (getenv-internal "INSECURE"))
gnutls-algorithm-priority
(when (boundp 'libgnutls-version)
(concat "SECURE128:+SECURE192:-VERS-ALL"
(if (and (not IS-WINDOWS)
(not (version< emacs-version "26.3"))
(>= libgnutls-version 30605))
":+VERS-TLS1.3")
":+VERS-TLS1.2"))
;; `gnutls-min-prime-bits' is set based on recommendations from
;; https://www.keylength.com/en/4/
gnutls-min-prime-bits 3072
tls-checktrust gnutls-verify-error
;; Emacs is built with `gnutls' by default, so `tls-program' would not be
;; used in that case. Otherwise, people have reasons to not go with
;; `gnutls', we use `openssl' instead. For more details, see
;; https://redd.it/8sykl1
tls-program '("openssl s_client -connect %h:%p -CAfile %t -nbio -no_ssl3 -no_tls1 -no_tls1_1 -ign_eof"
"gnutls-cli -p %p --dh-bits=3072 --ocsp --x509cafile=%t \
--strict-tofu --priority='SECURE192:+SECURE128:-VERS-ALL:+VERS-TLS1.2:+VERS-TLS1.3' %h"
;; compatibility fallbacks
"gnutls-cli -p %p %h"))
;; Emacs stores `authinfo' in $HOME and in plain-text. Let's not do that, mkay?
;; This file stores usernames, passwords, and other such treasures for the
;; aspiring malicious third party.
(setq auth-sources (list (concat doom-etc-dir "authinfo.gpg")
"~/.authinfo.gpg"))
;; ;;
;;; MODE-local-vars-hook ;;; MODE-local-vars-hook
@ -456,25 +450,6 @@ If this is a daemon session, load them all immediately instead."
(cdr doom-incremental-packages) t)))) (cdr doom-incremental-packages) t))))
;;
;;; Custom hooks
(defvar doom-first-input-hook nil
"Transient hooks run before the first user input.")
(defvar doom-first-file-hook nil
"Transient hooks run before the first interactively opened file.")
(defvar doom-first-buffer-hook nil
"Transient hooks run before the first interactively opened buffer.")
(defvar doom-after-reload-hook nil
"A list of hooks to run before `doom/reload' has reloaded Doom.")
(defvar doom-before-reload-hook nil
"A list of hooks to run after `doom/reload' has reloaded Doom.")
;; ;;
;;; Bootstrap helpers ;;; Bootstrap helpers
@ -490,6 +465,76 @@ If RETURN-P, return the message as a string instead of displaying it."
(setq doom-init-time (setq doom-init-time
(float-time (time-subtract (current-time) before-init-time)))))) (float-time (time-subtract (current-time) before-init-time))))))
(defun doom-load-envvars-file (file &optional noerror)
"Read and set envvars from FILE.
If NOERROR is non-nil, don't throw an error if the file doesn't exist or is
unreadable. Returns the names of envvars that were changed."
(if (null (file-exists-p file))
(unless noerror
(signal 'file-error (list "No envvar file exists" file)))
(when-let
(env
(with-temp-buffer
(save-excursion
(setq-local coding-system-for-read 'utf-8)
(insert "\0\n") ; to prevent off-by-one
(insert-file-contents file))
(save-match-data
(when (re-search-forward "\0\n *\\([^#= \n]*\\)=" nil t)
(setq
env (split-string (buffer-substring (match-beginning 1) (point-max))
"\0\n"
'omit-nulls))))))
(setq-default
process-environment
(append (nreverse env)
(default-value 'process-environment))
exec-path
(append (split-string (getenv "PATH") path-separator t)
(list exec-directory))
shell-file-name
(or (getenv "SHELL")
(default-value 'shell-file-name)))
env)))
(defun doom-try-run-hook (hook)
"Run HOOK (a hook function) with better error handling.
Meant to be used with `run-hook-wrapped'."
(doom-log "Running doom hook: %s" hook)
(condition-case e
(funcall hook)
((debug error)
(signal 'doom-hook-error (list hook e))))
;; return nil so `run-hook-wrapped' won't short circuit
nil)
(defun doom-run-hook-on (hook-var triggers)
"Configure HOOK-VAR to be invoked exactly once after init whenever any of the
TRIGGERS are invoked. Once HOOK-VAR gets triggered, it resets to nil.
HOOK-VAR is a quoted hook.
TRIGGERS is a list of quoted hooks and/or sharp-quoted functions."
(let ((fn (intern (format "%s-h" hook-var))))
(fset
fn (lambda (&rest _)
(when after-init-time
(run-hook-wrapped hook-var #'doom-try-run-hook)
(set hook-var nil))))
(put hook-var 'permanent-local t)
(dolist (on triggers)
(if (functionp on)
(advice-add on :before fn)
(add-hook on fn)))))
;;
;;; Bootstrapper
(defvar doom--initial-exec-path exec-path)
(defvar doom--initial-load-path load-path)
(defvar doom--initial-process-environment process-environment)
(defun doom-initialize (&optional force-p) (defun doom-initialize (&optional force-p)
"Bootstrap Doom, if it hasn't already (or if FORCE-P is non-nil). "Bootstrap Doom, if it hasn't already (or if FORCE-P is non-nil).
@ -508,7 +553,7 @@ The overall load order of Doom is as follows:
Module config.el files Module config.el files
~/.doom.d/config.el ~/.doom.d/config.el
`doom-init-modules-hook' `doom-init-modules-hook'
`doom-after-init-modules-hook' (`after-init-hook') `doom-after-init-modules-hook' (alias for `after-init-hook')
`emacs-startup-hook' `emacs-startup-hook'
`doom-init-ui-hook' `doom-init-ui-hook'
`window-setup-hook' `window-setup-hook'

24
init.el
View file

@ -27,6 +27,10 @@
;; ;;
;;; License: MIT ;;; License: MIT
(when (< emacs-major-version 26)
(error "Detected Emacs v%s. Doom only supports Emacs 26 and newer"
emacs-version))
;; A big contributor to startup times is garbage collection. We up the gc ;; A big contributor to startup times is garbage collection. We up the gc
;; threshold to temporarily prevent it from running, then reset it later by ;; threshold to temporarily prevent it from running, then reset it later by
;; enabling `gcmh-mode'. Not resetting it will cause stuttering/freezes. ;; enabling `gcmh-mode'. Not resetting it will cause stuttering/freezes.
@ -37,9 +41,25 @@
;; to skip the mtime checks on every *.elc file. ;; to skip the mtime checks on every *.elc file.
(setq load-prefer-newer noninteractive) (setq load-prefer-newer noninteractive)
(let (file-name-handler-alist) ;; `file-name-handler-alist' is consulted on every `require', `load' and various
;; path/io functions. You get a minor speed up by nooping this. However, this
;; may cause problems on builds of Emacs where its site lisp files aren't
;; byte-compiled and we're forced to load the *.el.gz files (e.g. on Alpine)
(unless (daemonp)
(defvar doom--initial-file-name-handler-alist file-name-handler-alist)
(setq file-name-handler-alist nil)
;; Restore `file-name-handler-alist' later, because it is needed for handling
;; encrypted or compressed files, among other things.
(defun doom-reset-file-handler-alist-h ()
;; Re-add rather than `setq', because changes to `file-name-handler-alist'
;; since startup ought to be preserved.
(dolist (handler file-name-handler-alist)
(add-to-list 'doom--initial-file-name-handler-alist handler))
(setq file-name-handler-alist doom--initial-file-name-handler-alist))
(add-hook 'emacs-startup-hook #'doom-reset-file-handler-alist-h))
;; Ensure Doom is running out of this file's directory ;; Ensure Doom is running out of this file's directory
(setq user-emacs-directory (file-name-directory load-file-name))) (setq user-emacs-directory (file-name-directory load-file-name))
;; Load the heart of Doom Emacs ;; Load the heart of Doom Emacs
(load (concat user-emacs-directory "core/core") (load (concat user-emacs-directory "core/core")