#+title: Emacs Config #+author: Evie Litherland-Smith #+email: evie@xenia.me.uk #+filetags: :emacs:config:org: #+property: header-args:emacs-lisp :tangle yes :mkdirp yes :results output silent * Setup Loading this file is handled automatically on my [[https://git.xenia.me.uk/xenia/nixos/src/branch/main/home/emacs.nix][NixOS config]], otherwise add src_emacs-lisp{(org-babel-load-file "~/.emacs/README.org")} to init file. * Common defaults #+begin_src emacs-lisp :results output silent (setq custom-file (locate-user-emacs-file "custom.el")) (when (and custom-file (file-exists-p custom-file)) (load custom-file nil 'nomessage)) (setq user-full-name "Evie Litherland-Smith" user-mail-address "evie@xenia.me.uk" use-short-answers t load-prefer-newer t indent-tabs-mode nil even-window-sizes t global-auto-revert-non-file-buffers t dired-auto-revert-buffer t dired-dwim-target t tab-always-indent t completion-cycle-threshold nil completions-detailed t xref-show-definitions-function #'xref-show-definitions-completing-read kill-do-not-save-duplicates t auto-window-vscroll nil fast-but-imprecise-scrolling t scroll-conservatively 101 scroll-margin 0 scroll-preserve-screen-position 1) (set-default-coding-systems 'utf-8) (set-terminal-coding-system 'utf-8) (set-keyboard-coding-system 'utf-8) (global-auto-revert-mode +1) (delete-selection-mode +1) ;; turn on spell checking, if available. (when (and (require 'ispell nil :noerror) (executable-find ispell-program-name)) (add-hook 'text-mode-hook #'flyspell-mode) (add-hook 'prog-mode-hook #'flyspell-prog-mode)) ;; Make shebang (#!) file executable when saved (add-hook 'after-save-hook #'executable-make-buffer-file-executable-if-script-p) #+end_src ** Auto-save file settings #+begin_src emacs-lisp :tangle yes (setq backup-directory-alist '(("." . "~/.local/state/emacs/backups")) tramp-backup-directory-alist backup-directory-alist tramp-auto-save-directory (cdr (assoc "." tramp-backup-directory-alist))) (savehist-mode +1) #+end_src ** Recent files #+begin_src emacs-lisp (use-package recentf :config (run-at-time nil (* 5 60) 'recentf-save-list) (recentf-mode +1) :custom (recentf-max-saved-items 2048)) #+end_src ** package-archive with priorities #+begin_src emacs-lisp :results output silent (when (require 'package nil :noerror) (add-to-list 'package-archives '("stable" . "https://stable.melpa.org/packages/")) (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/")) (setq package-archive-priorities '(("gnu" . 99) ("nongnu" . 80) ("stable" . 70) ("melpa" . 0)))) #+end_src ** diminish modes #+begin_src emacs-lisp (use-package diminish :ensure t) #+end_src ** Authentication #+begin_src emacs-lisp (when (require 'auth-source nil :noerror) (setq auth-sources '("secrets:Login")) (when (require 'auth-source-pass nil :noerror) (auth-source-pass-enable))) #+end_src ** Helpful #+begin_src emacs-lisp ;; Make `describe-*' screens more helpful (use-package helpful :ensure t :bind ((" " . helpful-command) (" " . helpful-callable) (" " . helpful-key) (" " . helpful-symbol) (" " . helpful-variable) ("C-h F" . helpful-function) :map helpful-mode-map (" " . helpful-update))) ;; Bind extra `describe-*' commands (keymap-global-set "C-h K" #'describe-keymap) #+end_src ** ibuffer #+begin_src emacs-lisp (use-package ibuffer :ensure t :bind (("C-c b" . ibuffer))) (use-package ibuffer-project :ensure t :after ibuffer :hook ((ibuffer . (lambda () (setq ibuffer-filter-groups (ibuffer-project-generate-filter-groups)) (unless (eq ibuffer-sorting-mode 'project-file-relative) (ibuffer-do-sort-by-project-file-relative)))))) #+end_src ** Link hint keymaps #+begin_src emacs-lisp (use-package link-hint :ensure t :bind (("C-c l o" . link-hint-open-link) ("C-c l c" . link-hint-copy-link) ("C-c l C-o" . link-hint-open-all-link) ("C-c l C-c" . link-hint-copy-all-link))) #+end_src ** Avy keymaps #+begin_src emacs-lisp (use-package avy :ensure t :bind (("C-c j w" . avy-goto-word-0) ("C-c j c" . avy-goto-char) ("C-c j l" . avy-goto-line) ("C-c j C-c" . avy-goto-char-2))) #+end_src ** which-func config #+begin_src emacs-lisp (use-package which-func :ensure t :init (which-function-mode)) #+end_src ** Shells and terminals #+begin_src emacs-lisp (use-package shell :bind (("C-c t s" . shell))) (use-package eshell :bind (("C-c t e" . eshell))) (use-package vterm :bind (("C-c t v" . vterm))) #+end_src * UI #+begin_src emacs-lisp (setq use-dialog-box nil truncate-lines nil truncate-partial-width-windows nil) (menu-bar-mode +1) (global-prettify-symbols-mode +1) (global-display-line-numbers-mode -1) (tool-bar-mode -1) (scroll-bar-mode -1) (tab-bar-mode -1) (add-hook 'prog-mode-hook #'(lambda () (display-line-numbers-mode +1))) (use-package word-wrap-mode :ensure t :diminish :init (global-word-wrap-whitespace-mode +1)) (use-package which-key :ensure t :diminish :config (which-key-mode +1)) (use-package page-break-lines :ensure t :diminish :config (global-page-break-lines-mode +1)) ;; add visual pulse when changing focus, like beacon but built-in ;; from from https://karthinks.com/software/batteries-included-with-emacs/ (defun pulse-line (&rest _) "Pulse the current line." (pulse-momentary-highlight-one-line (point))) (dolist (command '(scroll-up-command scroll-down-command recenter-top-bottom other-window)) (advice-add command :after #'pulse-line)) #+end_src ** Theme, font and nerd-icons #+begin_src emacs-lisp (set-frame-parameter nil 'alpha-background 80) (set-frame-font "JetBrainsMono Nerd Font-14") ;; Theme (use-package modus-themes :ensure t :custom (modus-themes-disable-other-themes t) (modus-themes-to-toggle '(modus-operandi-tinted modus-vivendi-tinted)) (modus-themes-bold-constructs t) (modus-themes-italic-constructs t) (modus-themes-org-blocks 'gray-background) (modus-themes-completions '((matches . (extrabold underline)) (selection . (semibold italic)))) (modus-themes-headings '((1 . (1.4)) (2 . (1.3)) (3 . (1.2)) (agenda-date . (1.3)) (agenda-structure . (light 1.8)) (t . (1.1)))) :config (modus-themes-load-theme 'modus-vivendi-tinted)) ;; Nerd-Icons modes (use-package nerd-icons :ensure t :config (nerd-icons-set-font "Symbols Nerd Font Mono")) (use-package nerd-icons-dired :ensure t :after nerd-icons :hook (dired-mode)) (use-package nerd-icons-ibuffer :ensure t :after nerd-icons :hook (ibuffer-mode)) (use-package nerd-icons-completion :ensure t :after nerd-icons :config (nerd-icons-completion-mode +1)) (use-package nerd-icons-corfu :ensure t :after (corfu nerd-icons) :config (add-to-list 'corfu-margin-formatters #'nerd-icons-corfu-formatter)) (keymap-global-set "C-c i n" #'nerd-icons-insert) #+end_src ** Window management *** windmove #+begin_src emacs-lisp (use-package windmove :ensure t :demand :config (windmove-mode +1) :bind (("C-c w k" . windmove-up) ("C-c w C-k" . windmove-display-up) ("C-c w K" . windmove-swap-states-up) ("C-c w j" . windmove-down) ("C-c w C-j" . windmove-display-down) ("C-c w J" . windmove-swap-states-down) ("C-c w h" . windmove-left) ("C-c w C-h" . windmove-display-left) ("C-c w H" . windmove-swap-states-left) ("C-c w l" . windmove-right) ("C-c w C-l" . windmove-display-right) ("C-c w L" . windmove-swap-states-right))) #+end_src *** winner #+begin_src emacs-lisp (use-package winner :ensure t :demand :bind (("C-c w u" . winner-undo) ("C-c w r" . winner-redo)) :config (winner-mode)) #+end_src *** ediff #+begin_src emacs-lisp :tangle yes (use-package ediff :bind (("C-c d f" . ediff-files) ("C-c d b" . ediff-buffers) ("C-c d 3 f" . ediff-files3) ("C-c d 3 b" . ediff-buffers3)) :custom (ediff-window-setup-function #'ediff-setup-windows-plain)) #+end_src ** Font ligatures #+begin_src emacs-lisp (use-package ligature :ensure t :diminish :config ;; Enable all ligatures in programming modes (ligature-set-ligatures '(prog-mode org-mode) '(;; == === ==== => =| =>>=>=|=>==>> ==< =/=//=// =~ ;; =:= =!= ("=" (rx (+ (or ">" "<" "|" "/" "~" ":" "!" "=")))) ;; ;; ;;; (";" (rx (+ ";"))) ;; && &&& ("&" (rx (+ "&"))) ;; !! !!! !. !: !!. != !== !~ ("!" (rx (+ (or "=" "!" "\." ":" "~")))) ;; ?? ??? ?: ?= ?. ("?" (rx (or ":" "=" "\." (+ "?")))) ;; %% %%% ("%" (rx (+ "%"))) ;; |> ||> |||> ||||> |] |} || ||| |-> ||-|| ;; |->>-||-<<-| |- |== ||=|| ;; |==>>==<<==<=>==//==/=!==:===> ("|" (rx (+ (or ">" "<" "|" "/" ":" "!" "}" "\]" "-" "=" )))) ;; \\ \\\ \/ ("\\" (rx (or "/" (+ "\\")))) ;; ++ +++ ++++ +> ("+" (rx (or ">" (+ "+")))) ;; :: ::: :::: :> :< := :// ::= (":" (rx (or ">" "<" "=" "//" ":=" (+ ":")))) ;; // /// //// /\ /* /> /===:===!=//===>>==>==/ ("/" (rx (+ (or ">" "<" "|" "/" "\\" "\*" ":" "!" "=")))) ;; .. ... .... .= .- .? ..= ..< ("\." (rx (or "=" "-" "\?" "\.=" "\.<" (+ "\.")))) ;; -- --- ---- -~ -> ->> -| -|->-->>->--<<-| ("-" (rx (+ (or ">" "<" "|" "~" "-")))) ;; ** *** **** ("*" (rx (+ "*"))) ;; <>