#+TITLE: My Ever Changing Literate Emacs Configuration #+AUTHOR: xulfer #+PROPERTY: header-args :tangle init.el :noweb yes :exports code # For PDF export allow line wrapping. #+LATEX_HEADER: \usepackage{listings} #+LATEX_HEADER: \lstset{breaklines=true, breakatwhitespace=true, basicstyle=\ttfamily\footnotesize, columns=fullflexible} #+begin_src emacs-lisp :exports none :tangle no ;; This asks for a file which it uses to store the processed org ;; data with the includes into. It can be anything and can safely ;; be deleted afterwards. I think README.org is a good file to ;; pick if using a repository. (defun tangle-literate-config () "Tangle config files with proper include handling." (interactive) (let ((org-confirm-babel-evaluate nil)) ;; Create a temporary buffer with expanded includes (with-temp-buffer (insert-file-contents "config.org") (org-mode) ;; This expands all #+INCLUDE directives (org-export-expand-include-keyword) ;; Now tangle from this buffer which has everything in one place (org-babel-tangle nil "init.el")) (message "Configuration tangled!"))) #+end_src #+BEGIN_SRC emacs-lisp :exports none ;;; init.el -*- lexical-binding: t; -*- ;;; Code: #+END_SRC #+begin_src emacs-lisp :tangle early-init.el :exports none ;;; early-init.el -*- lexical-binding: t; -*- ;;; Code: #+end_src * Quick Look [[./img/preview.png]] Just the usual flex of doing as little editing as possible in a screenshot. * Motivation Over a surprisingly short amount of time my emacs configuration has become quite a mess. Almost every visit to it requiring some digging to get to the relevant configuration. So as a result I've decided to make a literate configuration. Mostly for my own mental house keeping. However, if some poor soul reads this and finds it useful, then that's a bonus. ** Inspirations, and sometimes outright copy/paste sources - [[https://github.com/progfolio/.emacs.d][Progfolio's Config]] * Initial Bits and Bobs Before anything else the appearance, and some performance settings need to be tweaked as they can cause issues if done mid-start. ** Initial setup The LSP packages perform better with plists so an environment variable needs to be set to inform them that this is intended. I've also removed default package handling as I intend to use another package manager. Lastly I suppress some compilation warnings. #+begin_src emacs-lisp :tangle early-init.el (setq package-enable-at-startup nil) (setq inhibit-default-init nil) (setq native-comp-async-report-warnings-errors nil) (setenv "LSP_USE_PLISTS" "true") (setq lsp-use-plists t) #+end_src ** Appearance I like a minimal look, so I disable menu bars, tool bars, all the bars. I have Emacs loading as a blank slate with only the scratch buffer open. #+begin_src emacs-lisp :tangle early-init.el (defvar default-file-name-handler-alist file-name-handler-alist) (setq file-name-handler-alist nil) (push '(menu-bar-lines . 0) default-frame-alist) (push '(tool-bar-lines . 0) default-frame-alist) (push '(vertical-scroll-bars) default-frame-alist) (setq server-client-instructions nil) (when (and (fboundp 'startup-redirect-eln-cache) (fboundp 'native-comp-available-p) (native-comp-available-p)) (startup-redirect-eln-cache (convert-standard-filename (expand-file-name "var/eln-cache/" user-emacs-directory)))) (setq frame-inhibit-implied-resize t) (advice-add #'x-apply-session-resources :override #'ignore) (setq desktop-restore-forces-onscreen nil) (setq ring-bell-function #'ignore inhibit-startup-screen t) (push '(font . "Victor Mono-13") default-frame-alist) (set-face-font 'default "Victor Mono-13") (set-face-font 'variable-pitch "Victor Mono-13") (copy-face 'default 'fixed-pitch) (provide 'early-init) ;;; early-init.el ends here ;; Local Variables: ;; no-byte-compile: t ;; no-native-compile: t ;; no-update-autoloads: t ;; End: #+end_src * Package Management I am using [[https://github.com/progfolio/elpaca][Elpaca]] as my package manager. I've found it to be quite quick, and easy to use. #+name: elpaca-boilerplate #+begin_src emacs-lisp :exports none :tangle no (defvar elpaca-installer-version 0.11) (defvar elpaca-directory (expand-file-name "elpaca/" user-emacs-directory)) (defvar elpaca-builds-directory (expand-file-name "builds/" elpaca-directory)) (defvar elpaca-repos-directory (expand-file-name "repos/" elpaca-directory)) (defvar elpaca-order '(elpaca :repo "https://github.com/progfolio/elpaca.git" :ref nil :depth 1 :inherit ignore :files (:defaults "elpaca-test.el" (:exclude "extensions")) :build (:not elpaca--activate-package))) (let* ((repo (expand-file-name "elpaca/" elpaca-repos-directory)) (build (expand-file-name "elpaca/" elpaca-builds-directory)) (order (cdr elpaca-order)) (default-directory repo)) (add-to-list 'load-path (if (file-exists-p build) build repo)) (unless (file-exists-p repo) (make-directory repo t) (when (<= emacs-major-version 28) (require 'subr-x)) (condition-case-unless-debug err (if-let* ((buffer (pop-to-buffer-same-window "*elpaca-bootstrap*")) ((zerop (apply #'call-process `("git" nil ,buffer t "clone" ,@(when-let* ((depth (plist-get order :depth))) (list (format "--depth=%d" depth) "--no-single-branch")) ,(plist-get order :repo) ,repo)))) ((zerop (call-process "git" nil buffer t "checkout" (or (plist-get order :ref) "--")))) (emacs (concat invocation-directory invocation-name)) ((zerop (call-process emacs nil buffer nil "-Q" "-L" "." "--batch" "--eval" "(byte-recompile-directory \".\" 0 'force)"))) ((require 'elpaca)) ((elpaca-generate-autoloads "elpaca" repo))) (progn (message "%s" (buffer-string)) (kill-buffer buffer)) (error "%s" (with-current-buffer buffer (buffer-string)))) ((error) (warn "%s" err) (delete-directory repo 'recursive)))) (unless (require 'elpaca-autoloads nil t) (require 'elpaca) (elpaca-generate-autoloads "elpaca" repo) (let ((load-source-file-function nil)) (load "./elpaca-autoloads")))) (add-hook 'after-init-hook #'elpaca-process-queues) (elpaca `(,@elpaca-order)) (if debug-on-error (setq use-package-verbose t use-package-expand-minimally nil use-package-compute-statistics t) (setq use-package-verbose nil use-package-expand-minimally t)) #+end_src Elpaca supports =use-package= so hook that up, and add a =use-feature= macro that adds a similar construct for configuring already loaded emacs packages and features. #+begin_src emacs-lisp <> (defmacro use-feature (name &rest args) "Like `use-package' but accounting for asynchronous installation. NAME and ARGS are in `use-package'." (declare (indent defun)) `(use-package ,name :ensure nil ,@args)) (elpaca elpaca-use-package (require 'elpaca-use-package) (elpaca-use-package-mode) (setq use-package-always-ensure t)) #+end_src #+INCLUDE: "config/editing.org" :minlevel 1 #+INCLUDE: "config/gc.org" :minlevel 1 #+INCLUDE: "config/tidy.org" :minlevel 1 #+INCLUDE: "config/auth.org" :minlevel 1 #+INCLUDE: "config/path.org" :minlevel 1 #+INCLUDE: "config/profiling.org" :minlevel 1 #+INCLUDE: "config/general.org" :minlevel 1 #+INCLUDE: "config/formatting.org" :minlevel 1 #+INCLUDE: "config/documentation.org" :minlevel 1 #+INCLUDE: "config/social.org" :minlevel 1 #+INCLUDE: "config/modal.org" :minlevel 1 #+INCLUDE: "config/qol.org" :minlevel 1 #+INCLUDE: "config/hydra.org" :minlevel 1 #+INCLUDE: "config/bufferlo.org" :minlevel 1 #+INCLUDE: "config/error.org" :minlevel 1 #+INCLUDE: "config/completion.org" :minlevel 1 #+INCLUDE: "config/files.org" :minlevel 1 #+INCLUDE: "config/terminal.org" :minlevel 1 #+INCLUDE: "config/style.org" :minlevel 1 #+INCLUDE: "config/vcs.org" :minlevel 1 #+INCLUDE: "config/lsp.org" :minlevel 1 #+INCLUDE: "config/treesitter.org" :minlevel 1 #+INCLUDE: "config/major_modes.org" :minlevel 1 #+INCLUDE: "config/org_mode.org" :minlevel 1 #+INCLUDE: "config/snippets.org" :minlevel 1 #+INCLUDE: "config/custom.org" :minlevel 1 #+begin_src emacs-lisp :exports none (maybe-load-rel "custom.el") (provide 'init) ;;; init.el ends here #+end_src