diff --git a/home-manager/modules/emacs/config.org b/home-manager/modules/emacs/config.org new file mode 100644 index 0000000..5726826 --- /dev/null +++ b/home-manager/modules/emacs/config.org @@ -0,0 +1,1587 @@ +#+TITLE: Emacs config +#+AUTHOR: Erwin Boskma +#+OPTIONS: toc:nil h:4 +#+STARTUP: overview +#+PROPERTY: header-args:emacs-lisp :tangle init.el +#+PROPERTY: header-args:emacs-lisp+ :noweb tangle + +This is my emacs configuration. It is structured as an org-mode file, to easily provide context and documentation. + +Last export: {{{modification-time(%Y-%m-%d %H:%M)}}} + +#+TOC: headlines 4 + + +* Setup +** Early init + +This ends up in =early-init.el=. + +#+begin_src emacs-lisp + ;; -*- lexical-binding: t; -*- + ;; Prevent package.el from loading packages until we're ready for it + (setq package-enable-at-startup nil) + ;; Don't resize the frame to preserve the number of columns or lines + ;; being displayed when setting font, menu bar, tool bar, tab bar, + ;; internal borders, fringes, or scroll bars. Since I use a tiling + ;; window manager, this option is 1. useless anyways and 2. _terribly_ expensive. + (setq frame-inhibit-implied-resize t) + ;; Suppress warnings and errors during asynchronous native compilation + (setq native-comp-async-report-warnings-errors nil) + ;; Prevent unwanted runtime builds; packages are compiled ahead-of-time when + ;; they are installed and site files are compiled when gccemacs is installed. + ;; (setq comp-deferred-compilation nil) + (setq native-comp-deferred-compilation nil) + + ;; Prevent unwanted runtime builds in gccemacs (native-comp); packages are + ;; compiled ahead-of-time when they are installed and site files are compiled + ;; when gccemacs is installed. + (setq comp-deferred-compilation nil) +#+end_src + +** Personal variables + +This sets some variables with my personal preferences for easy customization + +#+begin_src emacs-lisp + (defvar my/default-font "Iosevka Nerd Font") + (defvar my/variable-width-font "Iosevka Aile") + (defvar my/default-font-height 110) + (defvar my/default-font-weight 'normal) + (defvar my/default-font-width 'normal) + (defvar my/variable-width-font-height 1.2) + (defvar my/config-file-path (expand-file-name "config.org" user-emacs-directory)) + (defvar my/snippets-dir (expand-file-name "snippets" user-emacs-directory)) + (defvar my/local-init-file (expand-file-name "local-init.el" user-emacs-directory)) + (defvar my/leader "C-c") +#+end_src + +And my personal info. + +#+begin_src emacs-lisp + (setq user-full-name "Erwin Boskma" + user-mail-address "erwin@datarift.nl") +#+end_src + +** Garbage collector +Increasing the garbage collector threshold should also improve startup time. This increases it from 800 kB to 128MB + +#+begin_src emacs-lisp + (setq gc-cons-threshold (* 128 1024 1024)) +#+end_src + +This resets the threshold back to it's default. This should not be done if =lsp-mode= is enabled, it needs the higher threshold. + +#+begin_src emacs-lisp :tangle no + (add-hook 'after-init-hook + (lambda () + (setq gc-cons-threshold 800000) + (message "gc-cons-threshold restored to %s" + gc-cons-threshold))) +#+end_src + +** Increase process output buffer + +LSP responses can be rather large, in the 800KiB - 3MiB range. 2MiB is a decent value + +#+begin_src emacs-lisp + (setq read-process-output-max (* 2 1024 1024)) +#+end_src + +** Package sources + +Add repositories where packages are installed from. Setting =package-enable-at-startup= to =nil= prevents a second package load and improves startup time + +#+begin_src emacs-lisp + (setq package-enable-at-startup nil) + (setq package-archives '(("gnu" . "https://elpa.gnu.org/packages/") + ("nongnu" . "https://elpa.nongnu.org/nongnu/") + ("melpa" . "https://melpa.org/packages/") + ("org" . "https://orgmode.org/elpa/") + ("onpa" . "https://olanilsson.bitbucket.io/packages/"))) +#+end_src + +** Bootstrap use-package + +If =use-package= is not installed, install it. + +#+begin_src emacs-lisp + (require 'package) + (package-initialize) + (unless (package-installed-p 'use-package) + (package-refresh-contents) + (package-install 'use-package) + (cl-eval-when 'compile (require 'use-package))) +#+end_src + +By default packages should always be installed from the package manager. This is equivalent to setting =:ensure t= on each call to =use-package=. To override this for a package (e.g. because it is builtin, or a subpackage), use =:ensure nil=. This is done automatically for packages that use =:load-path=. + +#+begin_src emacs-lisp + (setq use-package-always-ensure t) +#+end_src + +** Bootstrap straight.el and use-package [DISABLED] + +[[https://github.com/radian-software/straight.el][straight.el]] is a pure functional package manager and installs packages from git instead of downloading tars + +#+begin_src emacs-lisp :tangle no + (defvar bootstrap-version) + ;; Workaround for flycheck. See https://github.com/radian-software/straight.el/issues/508 for more info + (setq straight-fix-flycheck t) + (let ((bootstrap-file + (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory)) + (bootstrap-version 6)) + (unless (file-exists-p bootstrap-file) + (with-current-buffer + (url-retrieve-synchronously + "https://raw.githubusercontent.com/radian-software/straight.el/develop/install.el" + 'silent 'inhibit-cookies) + (goto-char (point-max)) + (eval-print-last-sexp))) + (load bootstrap-file nil 'nomessage)) +#+end_src + +Install =use-package= and make it use =straight.el= by default. + +#+begin_src emacs-lisp :tangle no + (straight-use-package 'use-package) + (setq straight-use-package-by-default t) +#+end_src + +** general.el + +[[https://github.com/noctuid/general.el][general.el]] provides a more convenient way for binding keys in emacs. It also integrates with =use-package= with the =:general= keyword. + +#+begin_src emacs-lisp + (use-package general + :demand t + :config + (progn + (general-define-key + :prefix my/leader + "a" 'org-agenda + "k" 'general-describe-keybindings) + (general-define-key + "C-M-z" 'zap-to-char + "M-z" 'zap-up-to-char))) + +#+end_src + +** Setup asdf [DISABLED] + +[[https://asdf-vm.com][asdf]] is a tool to install and use multiple versions of development tools and programming languages. + +#+begin_src emacs-lisp :tangle no + (when (executable-find "asdf") + (use-package asdf-vm + :straight (:host github :repo "delonnewman/asdf-vm.el") + ;; :load-path "~/.config/emacs/elisp/asdf-vm.el/" + :config + (asdf-vm-init))) +#+end_src + +** Set custom settings to load in temp file [DISABLED] + +Setting =custom-file= stops emacs from adding customised settings to =init.el=. I prefer to specify everything in this file, so this creates a temporary file where the customisations are stored. This effectively localises customisations to a session + +#+begin_src emacs-lisp :tangle no + (setq custom-file (make-temp-file "emacs-custom")) +#+end_src + +** Disable the customize interface + +The =customize= functionality is annoying and messes up regularly. Stuff it has done so far: + +- Clobber the path to =mix= in Elixir projects + +This has been borrowed from [[https://github.com/doomemacs/doomemacs/blob/35865ef5e89442e3809b8095199977053dd4210f/core/core-ui.el#L628-L639][Doom Emacs]] +#+begin_src emacs-lisp + (dolist (sym '(customize-option customize-browse customize-group customize-face + customize-rogue customize-saved customize-apropos + customize-changed customize-unsaved customize-variable + customize-set-value customize-customized customize-set-variable + customize-apropos-faces customize-save-variable + customize-apropos-groups customize-apropos-options + customize-changed-options customize-save-customized)) + (put sym 'disabled (concat "This config doesn't support `customize', configure Emacs from " user-emacs-directory "/config.org instead"))) + (put 'customize-themes 'disabled (concat "Use `load-theme' in " user-emacs-directory "/config.org instead")) +#+end_src + +** Custom packages location + +Emacs only includes files directly under =user-emacs-directory=. I like to keep custom packages in a separate =elisp/= subdirectory. + +#+begin_src emacs-lisp + (add-to-list 'load-path (expand-file-name "elisp/" user-emacs-directory)) +#+end_src + +** Record key frequency + +Records what keys are used the most, so I can see if I can optimise shortcuts + +#+begin_src emacs-lisp + (use-package keyfreq + :config + (keyfreq-mode 1) + (keyfreq-autosave-mode 1)) +#+end_src + +** Save minibuffer history + +#+begin_src emacs-lisp + (use-package savehist + :ensure nil + :init + (savehist-mode)) +#+end_src + +* Preferences + +Don't display the help screen at startup + +#+begin_src emacs-lisp + (setq inhibit-startup-screen t) +#+end_src + +Enable line wrapping + +#+begin_src emacs-lisp + (global-visual-line-mode 1) +#+end_src + +Disable toolbar and scroll bar + +#+begin_src emacs-lisp + (tool-bar-mode -1) + (menu-bar-mode -1) + (scroll-bar-mode -1) +#+end_src + +Don't show the warnings buffer for anything lesser than an error. + +#+begin_src emacs-lisp + (setq warning-minimum-level :error) +#+end_src + +Keep buffers up-to-date automatically + +#+begin_src emacs-lisp + (global-auto-revert-mode t) +#+end_src + +Automatically scroll the compile buffer + +#+begin_src emacs-lisp + (setq compilation-scroll-output 'first-error) +#+end_src + +Always display line numbers, and the relative line number + +#+begin_src emacs-lisp + (setq display-line-numbers-type 'relative) + (global-display-line-numbers-mode) +#+end_src + +Show matching parenthesese + +#+begin_src emacs-lisp + (show-paren-mode 1) + (setq show-paren-style 'expression) +#+end_src + +Centralise backup files (the =filename~= files), so they don't pollute the project. + +#+begin_src emacs-lisp + (setq backup-directory-alist '((".*" . "~/.local/share/emacs/backup")) + backup-by-copying t ; Don't delink hardlinks + version-control t ; Use version numbers on backup files + delete-old-versions t ; Automatically delete obsolete backups + kept-new-versions 20 ; How many of the newest versions to keep + kept-old-versions 5 ; And how many of the oldest + ) +#+end_src + +Same for auto save files (the ones with the =#=) + +#+begin_src emacs-lisp + (setq auto-save-file-name-transforms '((".*" "~/.local/share/emacs/autosave/" t))) +#+end_src + +Default indenting to spaces. If tabs are necessary, this can be set buffer-local. A single tab character can be added using =C-q TAB= + +#+begin_src emacs-lisp + (setq-default indent-tabs-mode nil) +#+end_src + +Delete trailing whitespace on save. + +#+begin_src emacs-lisp + (add-hook 'before-save-hook 'delete-trailing-whitespace) +#+end_src + +Don't move files to trash when deleting. + +#+begin_src emacs-lisp + (setq delete-by-moving-to-trash nil) +#+end_src + +Restore cursor position when re-opening a file + +#+begin_src emacs-lisp + (save-place-mode t) +#+end_src + +Prefer to open frames in a horizontal split + +#+begin_src emacs-lisp + (setq split-height-threshold nil) +#+end_src + +Set fill column to 80 + +#+begin_src emacs-lisp + (setq-default fill-column 80) +#+end_src + +* Interface +** Easy edit config file + +#+begin_src emacs-lisp + (defun find-config () + "Edit config.org" + (interactive) + (find-file my/config-file-path)) + + (general-define-key + :prefix my/leader + "C" 'find-config) +#+end_src +** Appearance + +I prefer the [[https://draculatheme.com][dracula theme]] + +#+begin_src emacs-lisp + (use-package dracula-theme + :init + (load-theme 'dracula t)) +#+end_src + +[[https://github.com/belak/emacs-monokai-pro-theme][Monokai Pro]] is also pretty. + +#+begin_src emacs-lisp :tangle no + (use-package monokai-pro-theme + :init + (load-theme 'monokai-pro t)) +#+end_src + +Use Iosevka as font. + +#+begin_src emacs-lisp + (set-face-attribute 'default nil + :family my/default-font + :weight my/default-font-weight + :width my/default-font-width + :height my/default-font-height) + (set-face-attribute 'variable-pitch nil + :family my/variable-width-font + :weight my/default-font-weight + :width my/default-font-width + :height my/variable-width-font-height) +#+end_src + +Emoji support + +#+begin_src emacs-lisp + (defun set-emoji-font () + (when (member "Twitter Color Emoji" (font-family-list)) + (set-fontset-font t 'emoji (font-spec :family "Twitter Color Emoji") nil 'prepend))) + + (use-package emojify + :defer t + :init + (setq emojify-display-style 'unicode) + :config + (set-emoji-font) + :hook (server-after-make-frame . set-emoji-font)) +#+end_src + +Enable ligatures + +#+begin_src emacs-lisp + (use-package ligature + :config + ;; Enable all Iosevka ligatures in programming modes + (ligature-set-ligatures 'prog-mode '("<---" "<--" "<<-" "<-" "->" "-->" "--->" "<->" "<-->" "<--->" "<---->" "