@@ -1,112 +1,512 @@
;;; early-init.el --- Early initialization file for Emacs -*- lexical-binding: t; -*-
;;; Commentary:
;; Emacs 27.1 introduced early-init.el, which is run before init.el, before
;; package and UI initialization happens, and before site files are loaded.
;; Emacs 27.1 introduced early-init.el, which is run before init.el,
;; before package and UI initialization happens, and before site files
;; are loaded.
;; uses some from minimal-emacs
;; https://github.com/jamescherti/minimal-emacs.d
;; not using `use-package' in here `early-init.el'
;;; Code:
;; 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
;; enabling `gcmh-mode'. Not resetting it will cause stuttering/freezes.
( setq gc-cons-threshold ( * 200 1024 1024 ) ) ;; Make startup faster by reducing the frequency of garbage collection. The default is 800 kilobytes. Measured in bytes. Will (and should) be decreased again at the end.
;; make UTF-8 the default coding system:
( set-language-environment " UTF-8 " )
;; `set-language-enviornment' sets `default-input-method', which is unwanted
( setq default-input-method nil )
;;; Internal variables
( defvar config-dir ( file-name-directory ( file-truename load-file-name ) ) )
( setq user-emacs-directory ( file-name-directory user-init-file ) ) ;; for cache etc.
( defvar my--gc-backup-cons-threshold gc-cons-threshold
" Backup of the original value of `gc-cons-threshold' before startup. " )
( setq gc-cons-threshold most-positive-fixnum ) ;; will be further defined below
;;; Variables
( defvar my-debug ( bound-and-true-p init-file-debug )
" Non-nil to enable debug and verbose output. " )
( defvar my-ui-features ' ( )
" List of user interface features to enable.
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.) " )
;;; emacs-conf location .cache, lisp, settings
( defvar config-dir ( if load-file-name
( file-name-directory ( file-truename load-file-name ) )
user-emacs-directory )
" Location of the distributed configuration, e.g. /opt/emacs-conf/.
Fallbacks to `user-emacs-directory' if this file is not loaded. " )
( when user-init-file
( setq user-emacs-directory ( file-name-directory user-init-file ) ) ) ;; for cache etc.
( defconst user-cache-directory
( file-name-as-directory ( concat user-emacs-directory " .cache " ) )
" My Emacs storage area for persistent files. " )
;; create the `user-cache-directory' if not exists
( make-directory user-cache-directory t )
( make-directory user-cache-directory t ) ;; create the `user-cache-directory' if not exists
;; path where settings files are kept
( add-to-list 'load-path ( concat config-dir " settings " ) )
;; personal elisp lib dir, for manually installed packages
( add-to-list 'load-path ( concat config-dir " lisp " ) )
;; add all directories from config-dir/lisp into load-path
( let ( ( default-directory ( concat config-dir " lisp " ) ) )
( normal-top-level-add-subdirs-to-load-path ) )
( progn
;; path where settings files are kept
( add-to-list 'load-path ( concat config-dir " settings " ) )
;; add personal elisp lib dir, for manually installed packages
( defun add-to-load-path-with-subdirs ( base exclude-list include-list )
" This will add all first level dirs from BASE and exclude the ones in
EXCLUDE-LIST, while for the dirs in INCLUDE-LIST, it will add all the
first level dirs of that dir too.
Example: (add-to-list-with-subdirs \" ~/.emacs.d \" '( \" . \" \" .. \" \" backup \" ) '( \" vendor \" \" my-lisp \" )) "
( add-to-list 'load-path base )
( dolist ( f ( directory-files base ) )
( let ( ( name ( concat base " / " f ) ) )
( when ( and ( file-directory-p name )
( not ( member f exclude-list ) ) )
( add-to-list 'load-path name )
( when ( member f include-list )
( add-to-load-path-with-subdirs name exclude-list include-list ) ) ) ) ) )
( add-to-load-path-with-subdirs ( concat config-dir " lisp " ) ' ( " . " " .. " " 0patches " ) nil ) )
;;
;; FRAME
;;
;; (add-to-list 'default-frame-alist '(fullscreen . maximized)) ;; restore saved geometry, see gui-settings.el my-frame-geometry-
;; (add-to-list 'default-frame-alist '(tool-bar-position . left))
;; (add-to-list 'default-frame-alist '(horizontal-scroll-bars . t)) ;; see gui-settings
( menu-bar-mode -1 ) ;; menu displayed inside `tab-bar' and via `tmm-menubar'
( when ( featurep 'tool-bar )
( tool-bar-mode -1 ) )
;;; Load pre-early-init.el
;; transparency
( set-frame-parameter ( selected-frame ) 'alpha ' ( 95 . 95 ) ) ;; VALUE: '(<active> . <inactive>) / <both>
( add-to-list 'default-frame-alist ' ( alpha . ( 95 . 95 ) ) )
( setq load-prefer-newer t ) ;; Prefer loading newer compiled files
( setq debug-on-error my-debug )
;; (load (expand-file-name "pre-early-init.el" user-emacs-directory) :no-error :no-message )
( setq custom-theme-directory ( expand-file-name " themes/ " config-dir ) )
( setq custom-file ( expand-file-name " custom.el " user-emacs-directory ) )
;;; Garbage collection
;; Garbage collection significantly affects startup times. This
;; setting delays garbage collection during startup but will be reset
;; later.
( setq garbage-collection-messages my-debug )
( defvar my-gc-optimize-startup 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 `my-gc-cons-threshold' . " )
( defvar my-gc-cons-threshold ( * 32 1024 1024 )
" Value to which `gc-cons-threshold' is set after Emacs startup.
Ignored if `my-gc-optimize-startup' is nil. " )
( defvar my-gc-cons-threshold-restore-delay nil
" Number of seconds to wait before restoring `gc-cons-threshold' . " )
( defun my--gc-restore-cons-threshold ( )
" Restore `gc-cons-threshold' to `my-gc-cons-threshold' . "
( if ( bound-and-true-p my-gc-cons-threshold-restore-delay )
;; Defer garbage collection during initialization to avoid 2 collections.
( run-at-time
my-gc-cons-threshold-restore-delay nil
( lambda ( ) ( setq gc-cons-threshold my-gc-cons-threshold ) ) )
( setq gc-cons-threshold my-gc-cons-threshold ) ) )
( if my-gc-optimize-startup
;; `gc-cons-threshold' is managed by early-init
( add-hook 'emacs-startup-hook #' my--gc-restore-cons-threshold 105 )
;; `gc-cons-threshold' is not managed by early-init.
;; If it is equal to `most-positive-fixnum', this indicates that the user has
;; not overridden the value in their `pre-early-init.el' configuration.
( when ( = gc-cons-threshold most-positive-fixnum )
( setq gc-cons-threshold my--gc-backup-cons-threshold ) ) )
;;; Native compilation and Byte compilation
( defvar my-setup-native-compilation t
" Controls whether native compilation settings are enabled during setup.
When non-nil, the following variables are set to non-nil to enable
native compilation features:
- `native-comp-deferred-compilation'
- `native-comp-jit-compilation'
- `package-native-compile'
If nil, these variables are left at their default values and are not
modified during setup. " )
( if ( and ( featurep 'native-compile )
( fboundp 'native-comp-available-p )
( native-comp-available-p ) )
( when my-setup-native-compilation
;; Activate `native-compile'
( setq native-comp-deferred-compilation t
native-comp-jit-compilation t
package-native-compile t ) )
;; Deactivate the `native-compile' feature if it is not available
( setq features ( delq 'native-compile features ) ) )
( setq native-comp-warning-on-missing-source my-debug
native-comp-async-report-warnings-errors ( or my-debug 'silent )
native-comp-verbose ( if my-debug 1 0 ) )
( setq jka-compr-verbose my-debug )
( setq byte-compile-warnings my-debug
byte-compile-verbose my-debug )
;;; Miscellaneous
( set-language-environment " UTF-8 " ) ;; make UTF-8 the default coding system
( setq default-input-method nil ) ;; `set-language-enviornment' sets `default-input-method', which is unwanted
( setq read-process-output-max ( * 1 1024 1024 ) ) ;; (1 MB) Increase how much is read from processes in a single chunk
( setq process-adaptive-read-buffering nil )
( setq ffap-machine-p-known 'reject ) ;; Don't ping things that look like domain names.
( setq warning-minimum-level ( if my-debug :warning :error ) )
( setq warning-suppress-types ' ( ( lexical-binding ) ) )
( when my-debug ( setq message-log-max ( expt 2 14 ) ) )
;;; 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 ( and ( not ( daemonp ) ) ( 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 ) ;; don't show the startup screen
( setq inhibit-startup-echo-area-message user-login-name )
( setq initial-buffer-choice nil )
( setq inhibit-startup-buffer-menu t )
( setq inhibit-x-resources t )
;; Disable bidirectional text scanning for a modest performance boost.
( setq-default bidi-display-reordering 'left-to-right )
( setq-default 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 )
;; The initial buffer is created during startup even in
;; non-interactive sessions, and its major mode is fully
;; initialized. Modes like `text-mode', `org-mode', or even the
;; default `lisp-interaction-mode' load extra packages and run
;; hooks, which can slow down startup.
;;
;; Using `fundamental-mode' for the initial buffer to avoid
;; unnecessary startup overhead.
( setq initial-major-mode 'fundamental-mode )
;; (setq initial-scratch-message nil)
( setq initial-scratch-message " # This buffer is for text that is not saved.
" )
( unless my-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 my-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 my--old-file-name-handler-alist ( default-toplevel-value
'file-name-handler-alist ) )
( defun my--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
my--old-file-name-handler-alist
file-name-handler-alist ) ) )
( funcall fn args-left ) ) )
( defun my--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
my--old-file-name-handler-alist ) ) ) )
( when ( and my-optimize-file-name-handler-alist ( not ( daemonp ) )
( not my-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
my--old-file-name-handler-alist ) ) ) )
;; Ensure the new value persists through any current let-binding.
( put 'file-name-handler-alist 'initial-value
my--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 #' my--respect-file-handlers )
( add-hook 'emacs-startup-hook #' my--restore-file-name-handler-alist
101 ) )
;;; Performance: Inhibit redisplay
;; see restore below
( defvar my-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. " )
( defun my--reset-inhibit-redisplay ( )
" Reset inhibit redisplay. "
( setq-default inhibit-redisplay nil )
( remove-hook 'post-command-hook #' my--reset-inhibit-redisplay ) )
( when ( and my-inhibit-redisplay-during-startup ( not ( daemonp ) )
( not noninteractive ) ( not my-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 #' my--reset-inhibit-redisplay -100 ) )
;;; Performance: Inhibit message
;; see restore below
( defvar my-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. " )
( defun my--reset-inhibit-message ( )
" Reset inhibit message. "
( setq-default inhibit-message nil )
( remove-hook 'post-command-hook #' my--reset-inhibit-message ) )
( when ( and my-inhibit-message-during-startup ( not ( daemonp ) )
( not noninteractive ) ( not my-debug ) )
( setq-default inhibit-message t )
( add-hook 'post-command-hook #' my--reset-inhibit-message -100 ) )
;;; Performance: Disable mode-line during startup
;; see restore below
( defvar my-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. " )
( when ( and my-disable-mode-line-during-startup ( not ( daemonp ) )
( not noninteractive ) ( not my-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
( setq mode-line-format nil ) ) ) )
;;; Restore values
;; `inhibit-message' `inhibit-redisplay' `mode-line-format'
( defun my--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 my-inhibit-message-during-startup
( setq-default inhibit-message nil ) )
( when my-inhibit-redisplay-during-startup
( setq-default inhibit-redisplay nil ) )
;; Restore the mode-line
( when my-disable-mode-line-during-startup
( unless ( default-toplevel-value 'mode-line-format )
( setq-default mode-line-format ( get 'mode-line-format
'initial-value ) ) ) ) ) )
( advice-add 'startup--load-user-init-file :around
#' my--startup-load-user-init-file )
;;; UI elements / frame
( defvar my-frame-title-format " %b – Emacs "
" Template for displaying the title bar of visible and iconified frame. " )
;; `display-graphic-p' not working during early-init
( setq frame-title-format my-frame-title-format )
( setq icon-title-format my-frame-title-format )
;; 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.
;; menu-bar
;; menu displayed inside `tab-bar' and via `tmm-menubar'
( unless ( memq 'menu-bar my-ui-features )
( push ' ( menu-bar-lines . 0 ) default-frame-alist )
( unless ( memq window-system ' ( mac ns ) )
( setq menu-bar-mode nil ) ) )
;; tool-bar
( defun my--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 ) ) ) )
( when ( and ( not ( daemonp ) )
( not 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
#' my--setup-toolbar ) ) )
( unless ( memq 'tool-bar my-ui-features )
( push ' ( tool-bar-lines . 0 ) default-frame-alist )
( setq tool-bar-mode nil ) )
;; scroll-bars
( push ' ( vertical-scroll-bars ) default-frame-alist )
( push ' ( horizontal-scroll-bars ) default-frame-alist )
( setq scroll-bar-mode nil )
;; tooltips
( unless ( memq 'tooltips my-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 my-ui-features )
( setq use-file-dialog nil )
( setq use-dialog-box nil ) )
;; 'initial frame' is created between early-init.el and the main init.
( add-to-list 'initial-frame-alist ' ( alpha . ( 95 . 95 ) ) ) ;; transparency VALUE: '(<active> . <inactive>) / <both>
( add-to-list 'initial-frame-alist ' ( background-mode . dark ) )
( add-to-list 'initial-frame-alist ' ( background-color . " #1e1e1e " ) )
( add-to-list 'initial-frame-alist ' ( foreground-color . " #b2b2b2 " ) )
;; Custom functions/hooks for persisting/loading frame geometry upon save/load
( defvar my-frame-geometry-file ( concat user-cache-directory " frame-geometry.el " ) )
( defun my-frame-geometry-save ( )
" Gets the current frame's geometry and save it to `my-frame-geometry-file' . "
( let ( ( frameg-font ( frame-parameter ( selected-frame) 'font ) )
( frameg-left ( frame-parameter ( selected-frame ) 'left ) )
( let ( ;; ( frameg-font ( frame-parameter ( selected-frame) 'font) )
( frameg-top ( frame-parameter ( selected-frame ) 'top ) )
( frameg-left ( frame-parameter ( selected-frame ) 'left ) )
( frameg-width ( frame-parameter ( selected-frame ) 'width ) )
( frameg-height ( frame-parameter ( selected-frame ) 'height ) )
;; (frameg-alpha (frame-parameter (selected-frame) 'alpha))
( frameg-file my-frame-geometry-file ) )
( with-temp-buffer
;; Turn off backup for this file
( make-local-variable 'make-backup-files )
( setq make-backup-files nil )
( scroll-bar-mode -1 )
( insert
" ;;; " ( file-name-nondirectory frameg-file ) " --- Frame configuration -*- no-byte-compile: t; lexical-binding: t; -*- "
" ;;; This file stores the previous emacs frame's geometry. \n "
" ;;; Last generated " ( current-time-string ) " . \n "
" (setq initial-frame-alist \n "
;; " '((font . \"" frameg-font "\")\n"
" '( "
( format " (top . %d)\n " ( max frameg-top 0 ) )
( format " (left . %d) \n " ( max frameg-left 0 ) )
( format " (width . %d) \n " ( max frameg-width 0 ) )
( format " (height . %d))) \n " ( max frameg-height 0 ) ) )
( format " (add-to-list 'initial-frame-alist '(top . %d)) \n " ( max frameg-top 0 ) )
( format " (add-to-list 'initial-frame-alist '(left . %d)) \n " ( max frameg-left 0 ) )
( format " (add-to-list 'initial-frame-alist '(width . %d)) \n " ( max frameg-width 0 ) )
( format " (add-to-list 'initial-frame-alist '(height . %d)) \n " ( max frameg-height 0 ) )
)
( when ( file-writable-p frameg-file )
( write-file frameg-file ) ) ) ) )
( defun my-frame-geometry-load ( )
" Load `my-frame-geometry-file' which should load the previous frame's geometry. "
( let ( ( frameg-file my-frame-geometry-file ) )
( when ( file-readable-p frameg-file )
( load-file frameg-file) ) ) )
;; Special work to do ONLY when there is a window system being used
;; (if (display-graphic-p)
;; (progn
;; (add-hook 'kill-emacs-hook 'my-frame-geometry-save)))
;; ( load-file frameg-file)
( load ( expand-file-name frameg-file ) nil ( not my-debug ) t ) ) ) )
( my-frame-geometry-load )
( add-hook 'window-setup-hook
( lambda ( )
( if ( display-graphic-p )
( add-hook 'kill-emacs-hook 'my-frame-geometry-save ) ) ) )
( add-hook 'kill-emacs-hook 'my-frame-geometry-save )
( use-package package
:defer t
:init
( setq package-enable-at-startup nil )
:config
;;; 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
;;; package.el and use-package
( progn
( setq package-enable-at-startup nil ) ;; Let the init.el file handle this
( add-to-list 'package-directory-list ( concat config-dir " lisp " ) )
( add-to-list ' package-archives ' ( " melpa " . " https://melpa.org/packages/ " ) )
;; (add-to-list 'package-archives '("melpa-stable" . "https://stable.melpa .org/packages/") )
)
( setq package-archives ' ( ( " melpa " . " https://melpa.org/packages/ " )
( " gnu " . " https://elpa.gnu .org/packages/" )
( " nongnu " . " https://elpa.nongnu.org/nongnu/ " ) ) )
( setq package-archive-priorities ' ( ( " gnu " . 99 )
( " nongnu " . 80 )
( " melpa " . 70 ) ) ) )
;; spacemacs-theme https://github.com/nashamri/spacemacs-theme
( use-package spacemacs-theme
:defer t
:config
( require 'cl-lib ) ;; spacemacs-common misses to load cl-lib
( setq spacemacs-theme-comment-bg nil )
;;(load-theme 'spacemacs-dark t)
)
( use-package my-theme
:config
( load-theme 'my t ) )
( setq use-package-compute-statistics my-debug )
( setq use-package-expand-minimally ( not my-debug ) ) ;; (t) results in a more compact output that emphasizes performance over clarity.
( setq use-package-minimum-reported-time ( if my-debug 0 0.1 ) )
( setq use-package-verbose my-debug )
;;; Load post-early-init.el
;; (load (expand-file-name "post-early-init.el" user-emacs-directory) :no-error :no-message )
( provide 'early-init )
;; Local variables:
;; byte-compile-warnings: (not obsolete free-vars)
;; End:
;;; early-init.el ends here