diff options
| author | Mitch Taylor <mitch@mitchtaylor.xyz> | 2026-03-22 22:07:22 -0300 |
|---|---|---|
| committer | Mitch Taylor <mitch@mitchtaylor.xyz> | 2026-03-22 22:07:22 -0300 |
| commit | 04126e9fda050fa753ddc22511e3c3f8dc275f7a (patch) | |
| tree | 41d9f9276c1e09c1cb86f94133bdf90f041d1ed2 /files/emacs/.emacs.d/early-init.el | |
initial commit
Diffstat (limited to 'files/emacs/.emacs.d/early-init.el')
| -rw-r--r-- | files/emacs/.emacs.d/early-init.el | 492 |
1 files changed, 492 insertions, 0 deletions
diff --git a/files/emacs/.emacs.d/early-init.el b/files/emacs/.emacs.d/early-init.el new file mode 100644 index 0000000..c0c97e9 --- /dev/null +++ b/files/emacs/.emacs.d/early-init.el @@ -0,0 +1,492 @@ +;;; early-init.el --- Early Init -*- lexical-binding: t; -*- + +;; Author: James Cherti <https://www.jamescherti.com/contact/> +;; URL: https://github.com/jamescherti/minimal-emacs.d +;; Package-Requires: ((emacs "29.1")) +;; Keywords: maint +;; Version: 1.4.1 +;; SPDX-License-Identifier: GPL-3.0-or-later + +;;; Commentary: +;; The minimal-emacs.d project is a lightweight and optimized Emacs base +;; (init.el and early-init.el) that gives you full control over your +;; configuration. It provides better defaults, an optimized startup, and a clean +;; foundation for building your own vanilla Emacs setup. +;; +;; Building the minimal-emacs.d init.el and early-init.el was the result of +;; extensive research and testing to fine-tune the best parameters and +;; optimizations for an Emacs configuration. +;; +;; Do not modify this file; instead, modify pre-early-init.el or +;; post-early-init.el. + +;;; Code: + +;;; Internal variables + +;; Backup of `gc-cons-threshold' and `gc-cons-percentage' before startup. +(defvar minimal-emacs--backup-gc-cons-threshold gc-cons-threshold) +(defvar minimal-emacs--backup-gc-cons-percentage gc-cons-percentage) + +;; Temporarily raise the garbage collection threshold to its maximum value. +;; It will be restored later to controlled values. +(setq gc-cons-threshold most-positive-fixnum) +(setq gc-cons-percentage 1.0) + +;;; Variables + +(defvar minimal-emacs-ui-features '() + "List of user interface features to enable in minimal Emacs setup. +This variable holds a list of Emacs UI features that can be enabled: +- context-menu (Enables the context menu in graphical environments.) +- tool-bar (Enables the tool bar in graphical environments.) +- menu-bar (Enables the menu bar in graphical environments.) +- dialogs (Enables both file dialogs and dialog boxes.) +- tooltips (Enables tooltips.)") + +(defvar minimal-emacs-frame-title-format "%b – Emacs" + "Template for displaying the title bar of visible and iconified frame.") + +(defvar minimal-emacs-debug (bound-and-true-p init-file-debug) + "Non-nil to enable debug.") + +(defvar minimal-emacs-optimize-startup-gc t + "If non-nil, increase `gc-cons-threshold' during startup to reduce pauses. +After Emacs finishes loading, `gc-cons-threshold' is restored to the value +stored in `minimal-emacs-gc-cons-threshold'.") + +(defvar minimal-emacs-gc-cons-threshold (* 32 1024 1024) + "Value to which `gc-cons-threshold' is set after Emacs startup. +Ignored if `minimal-emacs-optimize-startup-gc' is nil.") + +(defvar minimal-emacs-gc-cons-percentage gc-cons-percentage + "Value to which `gc-cons-percentage' is set after Emacs startup. +Ignored if `minimal-emacs-optimize-startup-gc' is nil.") + +(defvar minimal-emacs-gc-cons-threshold-restore-delay nil + "Number of seconds to wait before restoring `gc-cons-threshold'.") + +(defvar minimal-emacs-optimize-file-name-handler-alist t + "Enable optimization of `file-name-handler-alist'. +When non-nil, this variable activates optimizations to reduce file name handler +lookups during Emacs startup.") + +(defvar minimal-emacs-disable-mode-line-during-startup t + "Disable the mode line during startup. +This reduces visual clutter and slightly enhances startup performance. The +tradeoff is that the mode line is hidden during the startup phase.") + +(defvar minimal-emacs-package-initialize-and-refresh t + "Whether to automatically initialize and refresh packages. +When set to non-nil, Emacs will automatically call `package-initialize' and +`package-refresh-contents' to set up and update the package system.") + +(defvar minimal-emacs-inhibit-redisplay-during-startup nil + "Suppress redisplay during startup to improve performance. +This prevents visual updates while Emacs initializes. The tradeoff is that you +won't see the progress or activities during the startup process.") + +(defvar minimal-emacs-inhibit-message-during-startup nil + "Suppress startup messages for a cleaner experience. +This slightly enhances performance. The tradeoff is that you won't be informed +of the progress or any relevant activities during startup.") + +(defvar minimal-emacs-user-directory user-emacs-directory + "Directory beneath minimal-emacs.d files are placed. +Note that this should end with a directory separator.") + +(defvar minimal-emacs-load-pre-early-init t + "If non-nil, attempt to load `pre-early-init.el`.") + +(defvar minimal-emacs-load-post-early-init t + "If non-nil, attempt to load `post-early-init.el`.") + +(defvar minimal-emacs-load-pre-init t + "If non-nil, attempt to load `pre-init.el`.") + +(defvar minimal-emacs-load-post-init t + "If non-nil, attempt to load `post-init.el`.") + +;;; Load pre-early-init.el + +;; Prefer loading newer compiled files +(setq load-prefer-newer t) +(when minimal-emacs-debug + (setq debug-on-error minimal-emacs-debug)) + +(defvar minimal-emacs--success nil) +(defun minimal-emacs--check-success () + "Verify that the Emacs configuration has loaded successfully." + (unless minimal-emacs--success + (cond + ((or (file-exists-p (expand-file-name "~/.emacs.el")) + (file-exists-p (expand-file-name "~/.emacs"))) + (error "Emacs ignored loading 'init.el'. Please ensure that files such as ~/.emacs or ~/.emacs.el do not exist, as they may be preventing Emacs from loading the 'init.el' file")) + + (t + (error "Configuration error. Debug by starting Emacs with: --debug-init"))))) + +(unless noninteractive + (add-hook 'emacs-startup-hook #'minimal-emacs--check-success 102)) + +(defvar minimal-emacs-load-compiled-init-files nil + "If non-nil, attempt to load byte-compiled .elc for init files. +This will enable minimal-emacs to load byte-compiled or possibly native-compiled +init files for the following initialization files: pre-init.el, post-init.el, +pre-early-init.el, and post-early-init.el.") + +(defun minimal-emacs--remove-el-file-suffix (filename) + "Remove the Elisp file suffix from FILENAME and return it (.el, .el.gz...)." + (let ((suffixes (mapcar (lambda (ext) (concat ".el" ext)) + load-file-rep-suffixes))) + (catch 'done + (dolist (suffix suffixes filename) + (when (string-suffix-p suffix filename) + (setq filename (substring filename 0 (- (length suffix)))) + (throw 'done t)))) + filename)) + +(defun minimal-emacs-load-user-init (filename) + "Execute a file of Lisp code named FILENAME." + (let ((init-file (expand-file-name filename + minimal-emacs-user-directory))) + (if (not minimal-emacs-load-compiled-init-files) + (load init-file :no-error (not minimal-emacs-debug) :nosuffix) + ;; Remove the file suffix (.el, .el.gz, etc.) to let the `load' function + ;; select between .el and .elc files. + (setq init-file (minimal-emacs--remove-el-file-suffix init-file)) + (load init-file :no-error (not minimal-emacs-debug))))) + +(when minimal-emacs-load-pre-early-init + (minimal-emacs-load-user-init "pre-early-init.el")) + +(setq custom-theme-directory + (expand-file-name "themes/" minimal-emacs-user-directory)) + +(setq custom-file (expand-file-name "custom.el" minimal-emacs-user-directory)) + +;;; Garbage collection +;; Garbage collection significantly affects startup times. This setting delays +;; garbage collection during startup but will be reset later. + +(defun minimal-emacs--restore-gc-values () + "Restore garbage collection values to minimal-emacs.d values." + (setq gc-cons-threshold minimal-emacs-gc-cons-threshold) + (setq gc-cons-percentage minimal-emacs-gc-cons-percentage)) + +(defun minimal-emacs--restore-gc () + "Restore garbage collection settings." + (if (and (bound-and-true-p minimal-emacs-gc-cons-threshold-restore-delay) + ;; In noninteractive mode, the event loop does not run + (not noninteractive)) + ;; Defer garbage collection during initialization to avoid 2 collections. + (run-with-timer minimal-emacs-gc-cons-threshold-restore-delay nil + #'minimal-emacs--restore-gc-values) + (minimal-emacs--restore-gc-values))) + +(if minimal-emacs-optimize-startup-gc + ;; `gc-cons-threshold' is managed by minimal-emacs.d + (add-hook 'emacs-startup-hook #'minimal-emacs--restore-gc 105) + ;; gc-cons-threshold is not managed by minimal-emacs.d. + (when (= gc-cons-threshold most-positive-fixnum) + (setq gc-cons-threshold minimal-emacs--backup-gc-cons-threshold) + (setq gc-cons-percentage minimal-emacs--backup-gc-cons-percentage))) + +;;; Native compilation and Byte compilation + +(unless (and (featurep 'native-compile) + (fboundp 'native-comp-available-p) + (native-comp-available-p)) + ;; Deactivate the `native-compile' feature if it is not available + (setq features (delq 'native-compile features))) + +(setq native-comp-warning-on-missing-source minimal-emacs-debug + native-comp-async-report-warnings-errors (or minimal-emacs-debug 'silent)) + +(setq jka-compr-verbose minimal-emacs-debug) +(setq byte-compile-warnings minimal-emacs-debug + byte-compile-verbose minimal-emacs-debug) + +;;; Miscellaneous + +(set-language-environment "UTF-8") + +;; Increase how much is read from processes in a single chunk +(setq read-process-output-max (* 2 1024 1024)) ; 1024kb + +(setq process-adaptive-read-buffering nil) + +;; Don't ping things that look like domain names. +(setq ffap-machine-p-known 'reject) + +(setq warning-minimum-level (if minimal-emacs-debug :warning :error)) +(setq warning-suppress-types '((lexical-binding))) + +(when minimal-emacs-debug + (setq message-log-max 16384)) + +;; In PGTK, this timeout introduces latency. Reducing it from the default 0.1 +;; improves responsiveness of childframes and related packages. +(when (boundp 'pgtk-wait-for-event-timeout) + (setq pgtk-wait-for-event-timeout 0.001)) + +;; Disable warnings from the legacy advice API. They aren't useful. +(setq ad-redefinition-action 'accept) + +;;; Performance: Miscellaneous options + +;; Font compacting can be very resource-intensive, especially when rendering +;; icon fonts on Windows. This will increase memory usage. +(setq inhibit-compacting-font-caches t) + +(when (not noninteractive) + ;; Resizing the Emacs frame can be costly when changing the font. Disable this + ;; to improve startup times with fonts larger than the system default. + (setq frame-resize-pixelwise t) + + ;; Without this, Emacs will try to resize itself to a specific column size + (setq frame-inhibit-implied-resize t) + + ;; A second, case-insensitive pass over `auto-mode-alist' is time wasted. + ;; No second pass of case-insensitive search over auto-mode-alist. + (setq auto-mode-case-fold nil) + + ;; Reduce *Message* noise at startup. An empty scratch buffer (or the + ;; dashboard) is more than enough, and faster to display. + (setq inhibit-startup-screen t + inhibit-startup-echo-area-message user-login-name) + (setq initial-buffer-choice nil + inhibit-startup-buffer-menu t + inhibit-x-resources t) + + ;; Disable bidirectional text scanning for a modest performance boost. + (setq-default bidi-display-reordering 'left-to-right + bidi-paragraph-direction 'left-to-right) + + ;; Give up some bidirectional functionality for slightly faster re-display. + (setq bidi-inhibit-bpa t) + + ;; Remove "For information about GNU Emacs..." message at startup + (advice-add 'display-startup-echo-area-message :override #'ignore) + + ;; Suppress the vanilla startup screen completely. We've disabled it with + ;; `inhibit-startup-screen', but it would still initialize anyway. + (advice-add 'display-startup-screen :override #'ignore) + + (unless minimal-emacs-debug + ;; Unset command line options irrelevant to the current OS. These options + ;; are still processed by `command-line-1` but have no effect. + (unless (eq system-type 'darwin) + (setq command-line-ns-option-alist nil)) + (unless (memq initial-window-system '(x pgtk)) + (setq command-line-x-option-alist nil)))) + +;;; Performance: File-name-handler-alist + +(defvar minimal-emacs--old-file-name-handler-alist (default-toplevel-value + 'file-name-handler-alist)) + +(defun minimal-emacs--respect-file-handlers (fn args-left) + "Respect file handlers. +FN is the function and ARGS-LEFT is the same argument as `command-line-1'. +Emacs processes command-line files very early in startup. These files may +include special paths like TRAMP paths, so restore `file-name-handler-alist' for +this stage of initialization." + (let ((file-name-handler-alist (if args-left + minimal-emacs--old-file-name-handler-alist + file-name-handler-alist))) + (funcall fn args-left))) + +(defun minimal-emacs--restore-file-name-handler-alist () + "Restore `file-name-handler-alist'." + (set-default-toplevel-value + 'file-name-handler-alist + ;; Merge instead of overwrite to preserve any changes made since startup. + (delete-dups (append file-name-handler-alist + minimal-emacs--old-file-name-handler-alist)))) + +(when (and minimal-emacs-optimize-file-name-handler-alist + (not minimal-emacs-debug)) + ;; Determine the state of bundled libraries using calc-loaddefs.el. If + ;; compressed, retain the gzip handler in `file-name-handler-alist`. If + ;; compiled or neither, omit the gzip handler during startup for improved + ;; startup and package load time. + (set-default-toplevel-value + 'file-name-handler-alist + (if (locate-file-internal "calc-loaddefs.el" load-path) + nil + (list (rassq 'jka-compr-handler + minimal-emacs--old-file-name-handler-alist)))) + + ;; Ensure the new value persists through any current let-binding. + (put 'file-name-handler-alist 'initial-value + minimal-emacs--old-file-name-handler-alist) + + ;; Emacs processes command-line files very early in startup. These files may + ;; include special paths TRAMP. Restore `file-name-handler-alist'. + (advice-add 'command-line-1 :around #'minimal-emacs--respect-file-handlers) + + (add-hook 'emacs-startup-hook #'minimal-emacs--restore-file-name-handler-alist + 101)) + +;;; Performance: Inhibit redisplay + +(defun minimal-emacs--reset-inhibit-redisplay () + "Reset inhibit redisplay." + (setq-default inhibit-redisplay nil) + (remove-hook 'post-command-hook #'minimal-emacs--reset-inhibit-redisplay)) + +(when (and minimal-emacs-inhibit-redisplay-during-startup + (not noninteractive) + (not minimal-emacs-debug)) + ;; Suppress redisplay and redraw during startup to avoid delays and + ;; prevent flashing an unstyled Emacs frame. + (setq-default inhibit-redisplay t) + (add-hook 'post-command-hook #'minimal-emacs--reset-inhibit-redisplay -100)) + +;;; Performance: Inhibit message + +(defun minimal-emacs--reset-inhibit-message () + "Reset inhibit message." + (setq-default inhibit-message nil) + (remove-hook 'post-command-hook #'minimal-emacs--reset-inhibit-message)) + +(when (and minimal-emacs-inhibit-message-during-startup + (not noninteractive) + (not minimal-emacs-debug)) + (setq-default inhibit-message t) + (add-hook 'post-command-hook #'minimal-emacs--reset-inhibit-message -100)) + +;;; Performance: Disable mode-line during startup + +(defvar-local minimal-emacs--hidden-mode-line nil + "Store the buffer-local value of `mode-line-format' during startup.") + +(when (and minimal-emacs-disable-mode-line-during-startup + (not noninteractive) + (not minimal-emacs-debug)) + (put 'mode-line-format + 'initial-value (default-toplevel-value 'mode-line-format)) + (setq-default mode-line-format nil) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (when (local-variable-p 'mode-line-format) + (setq minimal-emacs--hidden-mode-line mode-line-format) + (setq mode-line-format nil))))) + +;;; Restore values + +(defun minimal-emacs--startup-load-user-init-file (fn &rest args) + "Advice to reset `mode-line-format'. FN and ARGS are the function and args." + (unwind-protect + ;; Start up as normal + (apply fn args) + ;; If we don't undo inhibit-{message, redisplay} and there's an error, we'll + ;; see nothing but a blank Emacs frame. + (when minimal-emacs-inhibit-message-during-startup + (setq-default inhibit-message nil)) + (when minimal-emacs-inhibit-redisplay-during-startup + (setq-default inhibit-redisplay nil)) + ;; Restore the mode-line + (when minimal-emacs-disable-mode-line-during-startup + (unless (default-toplevel-value 'mode-line-format) + (setq-default mode-line-format (get 'mode-line-format + 'initial-value))) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (when (local-variable-p 'minimal-emacs--hidden-mode-line) + (setq mode-line-format minimal-emacs--hidden-mode-line) + (kill-local-variable 'minimal-emacs--hidden-mode-line))))))) + +(advice-add 'startup--load-user-init-file :around + #'minimal-emacs--startup-load-user-init-file) + +;;; UI elements + +(setq frame-title-format minimal-emacs-frame-title-format + icon-title-format minimal-emacs-frame-title-format) + +;; Disable startup screens and messages +(setq inhibit-splash-screen t) + +;; I intentionally avoid calling `menu-bar-mode', `tool-bar-mode', and +;; `scroll-bar-mode' because manipulating frame parameters can trigger or queue +;; a superfluous and potentially expensive frame redraw at startup, depending +;; on the window system. The variables must also be set to `nil' so users don't +;; have to call the functions twice to re-enable them. +(unless (memq 'menu-bar minimal-emacs-ui-features) + (push '(menu-bar-lines . 0) default-frame-alist) + (unless (memq window-system '(mac ns)) + (setq menu-bar-mode nil))) + +(defun minimal-emacs--setup-toolbar (&rest _) + "Setup the toolbar." + (when (fboundp 'tool-bar-setup) + (advice-remove 'tool-bar-setup #'ignore) + (when (bound-and-true-p tool-bar-mode) + (funcall 'tool-bar-setup)))) + +(unless noninteractive + (when (fboundp 'tool-bar-setup) + ;; Temporarily override the tool-bar-setup function to prevent it from + ;; running during the initial stages of startup + (advice-add 'tool-bar-setup :override #'ignore) + + (advice-add 'startup--load-user-init-file :after + #'minimal-emacs--setup-toolbar))) + +(unless (memq 'tool-bar minimal-emacs-ui-features) + (push '(tool-bar-lines . 0) default-frame-alist) + (setq tool-bar-mode nil)) + +(setq default-frame-scroll-bars 'right) +(push '(vertical-scroll-bars) default-frame-alist) +(push '(horizontal-scroll-bars) default-frame-alist) +(setq scroll-bar-mode nil) + +(unless (memq 'tooltips minimal-emacs-ui-features) + (when (bound-and-true-p tooltip-mode) + (tooltip-mode -1))) + +;; Disable GUIs because they are inconsistent across systems, desktop +;; environments, and themes, and they don't match the look of Emacs. +(unless (memq 'dialogs minimal-emacs-ui-features) + (setq use-file-dialog nil) + (setq use-dialog-box nil)) + +;;; Security +(setq gnutls-verify-error t) ; Prompts user if there are certificate issues +(setq tls-checktrust t) ; Ensure SSL/TLS connections undergo trust verification +(setq gnutls-min-prime-bits 3072) ; Stronger GnuTLS encryption + +;; This results in a more compact output that emphasizes performance +(setq use-package-expand-minimally t) + +(setq use-package-minimum-reported-time (if minimal-emacs-debug 0 0.1)) +(setq use-package-verbose minimal-emacs-debug) +(setq use-package-always-ensure (not noninteractive)) +(setq use-package-enable-imenu-support t) + +;; package.el +(setq package-enable-at-startup nil) ; Let the init.el file handle this +(setq package-quickstart-file + (expand-file-name "package-quickstart.el" user-emacs-directory)) +(setq package-archives '(("melpa" . "https://melpa.org/packages/") + ("gnu" . "https://elpa.gnu.org/packages/") + ("nongnu" . "https://elpa.nongnu.org/nongnu/") + ("melpa-stable" . "https://stable.melpa.org/packages/"))) +(setq package-archive-priorities '(("gnu" . 99) + ("nongnu" . 80) + ("melpa" . 70) + ("melpa-stable" . 50))) + +;;; Load post-early-init.el + +(when minimal-emacs-load-post-early-init + (minimal-emacs-load-user-init "post-early-init.el")) + +;; Local variables: +;; byte-compile-warnings: (not obsolete free-vars) +;; End: + +;;; early-init.el ends here |
