;;; init.el -*- lexical-binding: t; -*- ;;; ;;; Author: Jakob L. Kreuze ;;; URL: https://git.sr.ht/~jakob/.emacs.d/ ;;; ;;; What follows is my personal configuration for GNU Emacs. Alas, what once was ;;; a literate configuration has turned into a modularized set of Elisp files. I ;;; have a number of reasons for this. ;;; ;;; - There was a considerable amount of friction in changing my configuration. ;;; There are a few things that could remedy this, namely the suggestion of ;;; using poly-org as suggested in [1], but my biggest grievance is putting ;;; documentation between snippets of code. There were a couple of answers to ;;; the Emacs StackExchange question I asked on this [2], but the only ;;; suggestion that remotely close to what I was looking for was to use ;;; <> syntax. Too much overhead for my tastes; I have to make a new ;;; named block every time I want to document part of a package configuration? ;;; Color me unexcited. Configuration reloading was also a massive pain, as ;;; some s-exps were split across blocks and I couldn't evaluate them with ;;; C-M-x. ;;; ;;; - My current method for tangling doesn't support byte compilation. The byte ;;; compiler will emit warnings for problematic Elisp. I can lint an Elisp ;;; file. With the way I was tangling, any errors in my code would be a ;;; pleasant surprise for the next time I tried to start Emacs. Furthermore, ;;; if I want to reap the benefits of using GCCEmacs [3], I'd better be ;;; compiling my sources. This is another grievance that could have been ;;; remedied with literate-elisp as suggested in [1], but I've decided it's ;;; too much work. I like the idea of being able to byte-compile with the ;;; native Emacs machinery better. ;;; ;;; - It's difficult to split up a literate configuration into multiple files, ;;; which is something I'd like to do for reasons of loading efficiency and ;;; organization. I think there's a reason that other sufficiently built-up ;;; configurations of note, such as Doom [4] and Purcell's [5], are written in ;;; plain ol' Elisp, leaving documentation to another file if stuctured text ;;; is really necessary. ;;; ;;; And, really, links were the only the only rich text I was using in the Org ;;; version. If I can survive writing emails without Org-style links, I can ;;; survive writing Elisp without Org-style links. I still love Org, but for ;;; right now, I'm not going to adopt it for anything outside of my personal ;;; information management workflow. Two conversations that influenced this ;;; decision and are worth documenting are [6] and [7]. ;;; ;;; Also worth noting is that there is no namespace (i.e. =jakob/= or =my-=) for ;;; functions defined in this file. I'm happy to use a consistent namespacing ;;; for packages I plan to publish on Melpa, but I don't see the point in a ;;; configuration file. ;;; ;;; [1]: https://www.reddit.com/r/emacs/comments/gfiadj/thoughts_on_having_a_literate_config/fpxqmf8/ ;;; [2]: https://emacs.stackexchange.com/questions/57608/split-code-across-multiple-src-blocks ;;; [3]: http://akrl.sdf.org/gccemacs.html ;;; [4]: https://github.com/hlissner/doom-emacs ;;; [5]: https://github.com/purcell/emacs.d ;;; [6]: https://www.reddit.com/r/emacs/comments/gfiadj/thoughts_on_having_a_literate_config/ ;;; [7]: https://www.colinmclear.net/posts/emacs-configuration/ ;; More than half of the packages I use regularly produce compile warnings. It ;; gets to be quite annoying when the `*Warnings*' window pops up while I'm ;; trying to do work, so we will disable native-comp reporting. (setq native-comp-async-report-warnings-errors nil) ;; The traditional dance of calming down the garbage collector during init, ;; as that improves startup times. Taken from Doom Emacs [1]. ;; ;; [1]: https://github.com/hlissner/doom-emacs/blob/develop/docs/faq.org#how-does-doom-start-up-so-quickly (setq gc-cons-threshold most-positive-fixnum) (setq gc-cons-percentage 0.6) ;; Fill whatever space the window manager has given us. (setq frame-resize-pixelwise t) ;; straight.el is my package manager of choice. Here's the necessary bootstrap ;; code for that. (defvar bootstrap-version) (let ((bootstrap-file (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory)) (bootstrap-version 5)) (unless (file-exists-p bootstrap-file) (with-current-buffer (url-retrieve-synchronously "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el" 'silent 'inhibit-cookies) (goto-char (point-max)) (eval-print-last-sexp))) (load bootstrap-file nil 'nomessage)) ;; As for ensuring that the packages listed in this configuration are installed, ;; I prefer use-package. `straight-use-package-by-default' ensures that packages ;; are registered and built without reqiring an explicit `:straight t'. (straight-use-package 'use-package) (setq straight-use-package-by-default t) ;; `bind-key' is necessary for `:bind' in `use-package' declarations, and I ;; actually use it quite a bit in this configuration. (use-package bind-key) (require 'bind-key) ;; Furthermore, I use `el-patch' at certain points in this configuration, and I ;; find it most clear when patch specifications are included alongside the ;; `use-package' declaration, so we will configure it here and enable the ;; integration. (use-package el-patch :init (setq el-patch-enable-use-package-integration t)) ;; But we do want to reset the garbage collector settings eventually. When we ;; do, we'll use the GCMH [1] package to schedule the garbage collector to run ;; during idle time, rather than the haphazard "whenever some threshold is ;; reached". ;; ;; [1]: https://gitlab.com/koral/gcmh/ (use-package gcmh :defer t) (add-hook 'emacs-startup-hook (lambda () (setq gc-cons-threshold 16777216) ; 16mb (setq gc-cons-percentage 0.1) (require 'gcmh) (gcmh-mode 1))) ;; A handful of the Elisp snippets in this file depend on third-party libraries ;; which aren't loaded by default. (require 'cl-lib) ;;; Everything above is what I classify as the "early-load" part of my ;;; configuration. The rest of my configuration is broken into "modules", which ;;; I include into the init.el at macro expansion time. (defvar module-directory (expand-file-name "lisp" user-emacs-directory) "Directory containing configuration 'modules'.") (defmacro insert-code-from-file (path) "Read the forms in the file at PATH into a progn." (with-temp-buffer (insert-file-contents path) (goto-char (point-min)) (let (forms (eof nil)) (while (not eof) (condition-case nil (push (read (current-buffer)) forms) (end-of-file (setq eof t)))) `(progn ,@(reverse forms))))) (defmacro load-module (name &optional condition) "Locate the module NAME and insert its contents as a progn." (let* ((file-name (concat name ".el")) (path (expand-file-name file-name module-directory))) (if condition `(expand-when ,condition (insert-code-from-file ,path)) `(insert-code-from-file ,path)))) (defmacro expand-when (conditional &rest form) "Expand if and only if `CONDITIONAL' is truthy at compile-time." (if (eval conditional) `(progn ,@form) '(progn))) (load-module "core") (load-module "jakob") (load-module "quality-of-life") (load-module "documents") (expand-when (not (member (system-name) '("theta"))) (load-module "appearance") (load-module "appearance/theme") (load-module "appearance/modeline") (load-module "shell") (load-module "terminal") (load-module "system") (load-module "irc") (load-module "rss") (load-module "news") (load-module "programming") (load-module "programming/rust") (load-module "programming/c") (load-module "programming/c++") (load-module "programming/elisp") (load-module "programming/common-lisp") (load-module "programming/markup") (load-module "programming/scheme") (load-module "programming/janet") (load-module "programming/javascript") (load-module "programming/graphql") (load-module "programming/python") (load-module "programming/lua") (load-module "programming/haskell") (load-module "programming/lean"))