summaryrefslogtreecommitdiff
path: root/early-init.el
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2025-10-12 11:47:26 -0500
committerCraig Jennings <c@cjennings.net>2025-10-12 11:47:26 -0500
commit092304d9e0ccc37cc0ddaa9b136457e56a1cac20 (patch)
treeea81999b8442246c978b364dd90e8c752af50db5 /early-init.el
changing repositories
Diffstat (limited to 'early-init.el')
-rw-r--r--early-init.el282
1 files changed, 282 insertions, 0 deletions
diff --git a/early-init.el b/early-init.el
new file mode 100644
index 00000000..52cfafed
--- /dev/null
+++ b/early-init.el
@@ -0,0 +1,282 @@
+;;; early-init.el --- -*- lexical-binding: t; coding: utf-8; no-byte-compile: t; -*-
+
+;;; Commentary:
+
+;; DEBUG FLAGS
+;; Debug flags are default on while this config is loading since errors should
+;; be loud and highly noticeable. They are restored to their default off once
+;; the config has completed.
+
+;; STARTUP PERFORMANCE
+;; Increasing garbage collection to a very high number decreases startup time.
+;; setting the file-name-handler and vc-handled-backends avoids some regexp
+;; slowness during startup. All original values are restored once Emacs is
+;; finished with startup.
+
+;; LOCAL REPOSITORIES
+;; This config doesn't work if the packages it relies on fail. Having local
+;; package repositories also allows for full config portability behind corporate
+;; firewalls and fast recovery from package issues no matter the network
+;; situation.
+
+;; The localrepo directory contains all the last known good packages for this
+;; config. The directory is added as a repository to the package archive list
+;; first, and given the highest priority number. This allows for a portable
+;; installation and reinstallation. This directory averages ~70 MB.
+
+;; Having a full local mirror of all elpa, melpa, and org repositories gives you
+;; more flexibility but at a higher storage cost. The script
+;; 'create-elpa-mirror.sh in user-emacs-directory/scripts directory will clone
+;; them all locally. As of Saturday, March 30, 2024 the directory containing all
+;; gnu, nongnu, melpa, melpa-stable, and org packages takes around 1.9 GB.
+;; For more information on the localrepo and elpa mirrors, read the commentary
+;; in local-repository.el.
+
+;;; Code:
+
+;; -------------------------------- Debug Flags --------------------------------
+;; debugging enabled during Emacs startup. disabled again after Emacs startup.
+
+;; uncomment when repo signatures expire and package installation is necessary
+;; (setq package-check-signature nil)
+
+(setq debug-on-error t) ;; default nil. turn on to debug issues only.
+(setq debug-on-quit t) ;; debug on C-g (breaking out of hangs/freezes)
+
+(add-hook 'emacs-startup-hook
+ (lambda ()
+ (setq debug-on-error nil)
+ (setq debug-on-quit nil)))
+
+;; ------------------------------ Bug Workarounds ------------------------------
+
+;; Prevent org-element from being natively compiled again by adding the line
+(setq native-comp-jit-compilation-deny-list '(".*org-element.*"))
+
+;; --------------------------- Warning Notifications ---------------------------
+
+;; skip warnings but notify me about errors
+(setq warning-minimum-level :error)
+
+;; --------------------------- Use Online Repos Flag ---------------------------
+;; set to nil to only use localrepo and local elpa-mirrors (see script directory)
+
+(defvar cj/use-online-repos t
+ "Whether to check for network connectivity & use online package repositories.")
+
+;; Cache network status to avoid repeated checks
+(defvar cj/network-available :unknown
+ "Cached network availability status.
+Can be t (available), nil (not available), or :unknown (not checked yet).")
+
+;; ---------------------------- Startup Performance ----------------------------
+;; increases garbage collection threshold, and turns off file-name-handler and
+;; vc-backends during startup and restores the settings once emacs has loaded.
+
+(defvar cj/orig-gc-cons-threshold gc-cons-threshold
+ "Temporary variable to allow restoration of value post-startup.")
+(setq gc-cons-threshold most-positive-fixnum)
+
+(defvar cj/orig-file-name-handler-alist file-name-handler-alist
+ "Temporary variable to allow restoration of value post-startup.")
+(setq file-name-handler-alist nil)
+
+(defvar cj/orig-vc-handled-backends vc-handled-backends
+ "Temporary variable to allow restoration of value post-startup.")
+(setq vc-handled-backends nil)
+
+(add-hook 'emacs-startup-hook
+ (lambda ()
+ (setq gc-cons-threshold cj/orig-gc-cons-threshold
+ file-name-handler-alist cj/orig-file-name-handler-alist
+ vc-handled-backends cj/orig-vc-handled-backends)))
+
+;; ------------------------------ Site Start Files -----------------------------
+;; don't load site-start or default.el files
+
+(setq inhibit-default-init t)
+
+;; ------------------------------- Network Check -------------------------------
+;; checks if the network is available. used for online repo enablement.
+(defvar cj/network-available :unknown
+ "Cached network availability status. Values: :unknown, t, or nil.")
+
+(defun cj/reset-network-cache ()
+ "Reset cached network availability."
+ (setq cj/network-available :unknown))
+
+(defun cj/internet-up-p (&optional force)
+ "Return non-nil if the network seems available.
+If FORCE is non-nil, re-check even if cached."
+ (when (or force
+ (eq cj/network-available :unknown)
+ (not (boundp 'cj/network-available)))
+ (setq cj/network-available
+ (condition-case _err
+ (pcase system-type
+ ;; Linux, *BSD
+ ((or 'gnu/linux 'berkeley-unix 'gnu)
+ (= 0 (call-process "ping" nil nil nil
+ "-c" "1" ; count: 1 packet
+ "-W" "1" ; timeout: 1 second
+ "1.1.1.1")))
+ ;; macOS
+ ('darwin
+ (= 0 (call-process "ping" nil nil nil
+ "-c" "1"
+ "-t" "1"
+ "1.1.1.1")))
+ ;; Windows
+ ('windows-nt
+ (= 0 (call-process "ping" nil nil nil
+ "-n" "1"
+ "-w" "1000"
+ "1.1.1.1")))
+ ;; Fallback
+ (_
+ (with-timeout (1.0 nil)
+ (let ((p (ignore-errors
+ (open-network-stream "net-test" nil
+ "1.1.1.1" 53
+ :type 'datagram))))
+ (prog1 (and p t)
+ (when p (delete-process p)))))))
+ (error nil))))
+ cj/network-available)
+
+(setq package-enable-at-startup nil)
+(require 'package) ;; emacs built-in
+
+(defconst user-home-dir (getenv "HOME")
+ "The user's home directory per the environment variable.")
+
+(defconst elpa-mirror-location (concat user-home-dir ".elpa-mirrors/")
+ "The path to the elpa mirror location.")
+
+(defconst localrepo-location (concat user-emacs-directory ".localrepo/")
+ "The path to your local Emacs package repository.
+For more information about the local Emacs package repository, see comments in
+early-init.el.")
+
+(setq package-archives nil) ;; package-archives will be added below
+
+;; LOCAL REPOSITORY (packages in version control)
+(when (file-accessible-directory-p localrepo-location)
+ (add-to-list 'package-archives (cons "localrepo" localrepo-location) t)
+ (add-to-list 'package-archive-priorities '("localrepo" . 200)))
+
+;; LOCAL REPOSITORY ELPA MIRRORS
+(when (file-accessible-directory-p (concat elpa-mirror-location "gnu"))
+ (add-to-list 'package-archives (cons "gnu-local" (concat elpa-mirror-location "gnu/")) t)
+ (add-to-list 'package-archive-priorities '("gnu-local" . 125)))
+
+(when (file-accessible-directory-p (concat elpa-mirror-location "nongnu"))
+ (add-to-list 'package-archives (cons "nongnu-local" (concat elpa-mirror-location "nongnu/")) t)
+ (add-to-list 'package-archive-priorities '("nongnu-local" . 120)))
+
+(when (file-accessible-directory-p (concat elpa-mirror-location "melpa"))
+ (add-to-list 'package-archives (cons "melpa-local" (concat elpa-mirror-location "melpa/")) t)
+ (add-to-list 'package-archive-priorities '("melpa-local" . 115)))
+
+(when (file-accessible-directory-p (concat elpa-mirror-location "stable-melpa"))
+ (add-to-list 'package-archives (cons "melpa-stable-local" (concat elpa-mirror-location "stable-melpa/")) t)
+ (add-to-list 'package-archive-priorities '("melpa-stable-local" . 100)))
+
+;; ONLINE REPOSITORIES
+(when (and cj/use-online-repos (cj/internet-up-p))
+ (add-to-list 'package-archives '("gnu" . "https://elpa.gnu.org/packages/") t)
+ (add-to-list 'package-archive-priorities '("gnu" . 25))
+ (add-to-list 'package-archives '("nongnu" . "https://elpa.nongnu.org/nongnu/") t)
+ (add-to-list 'package-archive-priorities '("nongnu" . 20))
+ (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
+ (add-to-list 'package-archive-priorities '("melpa" . 15))
+ (add-to-list 'package-archives '("melpa-stable" . "https://stable.melpa.org/packages/") t)
+ (add-to-list 'package-archive-priorities '("melpa-stable" . 5)))
+
+;; Initialize package system
+(package-initialize)
+
+;; Package refresh logic - refresh only if:
+;; 1. Online repos are enabled AND network is available
+;; 2. Any online repo cache doesn't exist or is older than 7 days
+
+(when (and cj/use-online-repos (cj/internet-up-p))
+ (let ((cache-age-days 7)
+ (needs-refresh nil))
+ ;; Check each online repository's cache
+ (dolist (archive '("gnu" "nongnu" "melpa" "melpa-stable"))
+ (let ((cache-file (expand-file-name
+ (format "archives/%s/archive-contents" archive)
+ package-user-dir)))
+ (when (or (not (file-exists-p cache-file))
+ (> (/ (float-time (time-subtract
+ (current-time)
+ (file-attribute-modification-time
+ (file-attributes cache-file))))
+ 86400.0) ;; == 7 days
+ cache-age-days))
+ (setq needs-refresh t))))
+
+ ;; Only refresh if needed
+ (when needs-refresh
+ (condition-case nil
+ (package-refresh-contents)
+ (error (message "Failed to refresh package contents"))))))
+
+;; Ensure use-package is installed
+(unless (package-installed-p 'use-package)
+ (unless package-archive-contents
+ (package-refresh-contents))
+ (package-install 'use-package))
+
+;;(require 'use-package-ensure) ; Needed for :ensure to work
+(setq use-package-always-ensure t) ; Auto-install packages
+
+;; Package signature checking
+(setq package-check-signature nil)
+;; (setq package-check-signature t)
+
+;; Optional but recommended for better error messages during config loading
+;;(setq use-package-expand-minimally nil) ; Better error reporting
+;;(setq use-package-compute-statistics t) ; Set to t if you want timing info
+
+;; turn on for use-package debugging
+;;(setq use-package-verbose nil)
+
+;; ---------------------------------- Unicode ----------------------------------
+;; unicode all the things
+
+(set-locale-environment "en_US.UTF-8")
+(prefer-coding-system 'utf-8)
+(set-default-coding-systems 'utf-8)
+(set-terminal-coding-system 'utf-8)
+(set-keyboard-coding-system 'utf-8)
+(set-selection-coding-system 'utf-8)
+(setq locale-coding-system 'utf-8)
+(set-charset-priority 'unicode)
+(setq x-select-request-type
+ '(UTF8_STRING COMPOUND_TEXT TEXT STRING))
+
+;; ---------------------------- Inhibit UI Elements ----------------------------
+;; setting UI preferences here before the UI is displayed
+
+(push '(menu-bar-lines . 0) default-frame-alist)
+(push '(tool-bar-lines . 0) default-frame-alist)
+(push '(vertical-scroll-bars . nil) default-frame-alist)
+(setq-default inhibit-startup-screen t)
+(setq-default inhibit-startup-message t)
+(setq-default inhibit-splash-screen t)
+(setq-default initial-scratch-message nil)
+(setq inhibit-startup-echo-area-message (user-login-name))
+
+;; Disable bidirectional text rendering for slight performance boost
+(setq-default bidi-display-reordering nil ;; disable bidi reordering for speed
+ bidi-paragraph-direction 'left-to-right
+ bidi-inhibit-bpa t) ;; additional speedup
+
+;; Disable global font lock mode until after initialization
+(setq-default global-font-lock-mode nil)
+(add-hook 'emacs-startup-hook #'global-font-lock-mode)
+
+(provide 'early-init)
+;;; early-init.el ends here