From 0f3b7bd0538a239f1eddca9dc7f33dec34a19de8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Madeleine=20Sydney=20=C5=9Alaga?= Date: Mon, 22 Sep 2025 11:20:33 -0600 Subject: [PATCH] refactor(emacs): move random-require code into its own module --- modules/home/users/msyds/emacs/early-init.el | 15 ++---- modules/home/users/msyds/emacs/init.el | 21 +------- .../msyds/emacs/lisp/syd/random-require.el | 50 +++++++++++++++++++ 3 files changed, 54 insertions(+), 32 deletions(-) create mode 100644 modules/home/users/msyds/emacs/lisp/syd/random-require.el diff --git a/modules/home/users/msyds/emacs/early-init.el b/modules/home/users/msyds/emacs/early-init.el index 0ed7bff..db48d69 100644 --- a/modules/home/users/msyds/emacs/early-init.el +++ b/modules/home/users/msyds/emacs/early-init.el @@ -3,18 +3,9 @@ (add-to-list 'load-path (file-name-concat user-emacs-directory "lisp")) -(defconst syd-init-load-order-seed - (or (when-let ((x (getenv "SYD_INIT_LOAD_ORDER_SEED"))) - (string-to-number x)) - (random)) - "Seed used to load top-level modules in pseudo-random order. Loading modules -in an unpredictable order by default is a tactic to prevent implicit -dependencies between modules. For debugging purposes, the load-order may be -made deterministic by starting Emacs with the environment variable -SYD_INIT_LOAD_ORDER_SEED set to a non-negative integer.") -;; Log as early as possible to make it difficult to miss. -(message "Top-level modules will be loaded in the order determined by seed %d" - syd-init-load-order-seed) +;; Load `syd/random-require' before the UI exists so `syd-init-load-order-seed' +;; is printed to the console instead of the message buffer. +(require 'syd/random-require) (require 'syd/disable-package) diff --git a/modules/home/users/msyds/emacs/init.el b/modules/home/users/msyds/emacs/init.el index 9b40b4d..2d92554 100644 --- a/modules/home/users/msyds/emacs/init.el +++ b/modules/home/users/msyds/emacs/init.el @@ -1,8 +1,6 @@ ;;; init.el -*- lexical-binding: t -*- -(require 'cl-lib) - -(defconst syd-features +(syd-require-features '(syd/base syd/constants syd/dash @@ -49,20 +47,3 @@ syd/display-startup-time syd/dired syd/ligature)) - -(defun syd-random-permutation (lst &optional seed) - "Return a random permutation of list LST using SEED as the random state. The -permutation is deterministic for a given SEED." - (let* ((random-state (cl-make-random-state (or seed (random)))) - (len (length lst)) - (vec (vconcat lst))) - ;; Fisher-Yates shuffle. - (cl-loop for i from (1- len) downto 1 do - (cl-rotatef (aref vec i) - (aref vec (cl-random (1+ i) random-state)))) - ;; Convert vector to list. - (append vec nil))) - -(dolist (feature (syd-random-permutation syd-features - syd-init-load-order-seed)) - (require feature)) diff --git a/modules/home/users/msyds/emacs/lisp/syd/random-require.el b/modules/home/users/msyds/emacs/lisp/syd/random-require.el new file mode 100644 index 0000000..4fa045b --- /dev/null +++ b/modules/home/users/msyds/emacs/lisp/syd/random-require.el @@ -0,0 +1,50 @@ +;;; -*- lexical-binding: t -*- +;;; +;;; This is one of my config's weirder bits. My config is organised into many +;;; disjoint "modules," configuring one group of related things at a time. I +;;; want these modules to be as independent as possible — you should be able to +;;; add and remove individual modules and the only modules that should stop +;;; working are those which inherently build off of the removed module's +;;; functionality. Thus, I want to discourage any reliance on some implicit +;;; load order — all dependencies should be explicit. As one method to shake +;;; the tree of dependencies, so to speak, I came up with the idea of loading my +;;; "top-level" modules in a pseudo-random order, which has proven incredibly +;;; effective in catching accidental implicit dependencies thus far! + +(require 'cl-lib) + +(defconst syd-init-load-order-seed + (or (when-let ((x (getenv "SYD_INIT_LOAD_ORDER_SEED"))) + (string-to-number x)) + (random)) + "Seed used to load top-level modules in pseudo-random order. Loading modules +in an unpredictable order by default is a tactic to prevent implicit +dependencies between modules. For debugging purposes, the load-order may be +made deterministic by starting Emacs with the environment variable +SYD_INIT_LOAD_ORDER_SEED set to a non-negative integer.") + +;; Log as early as possible to make it difficult to miss. +(message "Top-level modules will be loaded in the order determined by SYD_INIT_LOAD_ORDER_SEED=%d" + syd-init-load-order-seed) + +(defun syd-random-permutation (lst &optional seed) + "Return a random permutation of list LST using SEED as the random state. The +permutation is deterministic for a given SEED." + (let* ((random-state (cl-make-random-state (or seed (random)))) + (len (length lst)) + (vec (vconcat lst))) + ;; Fisher-Yates shuffle. + (cl-loop for i from (1- len) downto 1 do + (cl-rotatef (aref vec i) + (aref vec (cl-random (1+ i) random-state)))) + ;; Convert vector to list. + (append vec nil))) + +(defun syd-require-features (features) + "Require each of FEATURES in the pseudo-random order defined by +`syd-init-load-order-seed' and `syd-random-permutation'." + (dolist (feature (syd-random-permutation + features syd-init-load-order-seed)) + (require feature))) + +(provide 'syd/random-require)