dotfiles/emacs/.config/emacs/Emacs.org
2025-12-12 07:56:01 -08:00

20 KiB

My Emacs Config

Basic Settings

UI

  (setq inhibit-startup-message t)
  (tool-bar-mode -1)
  (tooltip-mode -1)
  (set-fringe-mode 10)
  (menu-bar-mode -1)
  (setq visible-bell t)
  (setq frame-resize-pixelwise t)
  (fset 'yes-or-no-p 'y-or-n-p)
  ;(setq default-frame-alist '((undecorated . t)))
  (scroll-bar-mode -1)

Backups

  (defvar wball/backup-directory (concat user-emacs-directory "backups"))
  (if (not (file-exists-p wball/backup-directory))
      (make-directory wball/backup-directory t))
  (setq backup-directory-alist `(("." . ,wball/backup-directory)))
  (setq make-backup-files t
        backup-by-copying t
        version-control t
        delete-old-versions t
        auto-save-default t)

Packages

MELPA

  (require 'package)
  (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
  (package-initialize)

use-package

  (require 'use-package-ensure)
  (setq use-package-always-ensure t)

no-littering

  (use-package no-littering)

Set up path correctly

  (use-package exec-path-from-shell
    :config
    (exec-path-from-shell-initialize))

Automatic updates

  (use-package auto-package-update
    :custom
    (auto-package-update-interval 7)
    (auto-package-update-prompt-before-update t)
    (auto-package-update-hide-results t)
    :config
    (auto-package-update-maybe)
    (auto-package-update-at-time "09:00"))

UI

Icons

  (use-package nerd-icons
    :custom
    (nerd-icons-font-family "AdwaitaMono Nerd Font"))

Rainbow delimiters

  (use-package rainbow-delimiters
    :hook (prog-mode . rainbow-delimiters-mode))

Fonts

  (use-package fontaine
    :config
    (setq fontaine-presets
          '((regular
             :default-height 140)
            (small
             :default-height 90)
            (large
             :default-weight semilight
             :default-height 160
             :bold-weight extrabold)
            (extra-large
             :default-weight semilight
             :default-height 190
             :bold-weight extrabold)
            (t
             :default-family "Adwaita Mono"
             :default-weight normal
             :variable-pitch-family "Libertinus Serif")))
    (fontaine-set-preset 'regular))

Which key

  (use-package which-key
    :defer 0
    :diminish which-key-mode
    :config
    (which-key-mode)
    (setq which-key-idle-delay 0.3))

Theme

Modus Themes

  (use-package emacs
    :ensure nil
    :config
    (require-theme 'modus-themes)
    (setq modus-themes-italic-constructs t
          modus-themes-bold-constructs t
  	modus-themes-links '(no-underline background faint)
          modus-themes-prompts '(bold intense)
          modus-themes-mode-line '(borderless accented moody)
          modus-themes-org-blocks 'gray-background
          modus-themes-region '(bg-only no-extend))
    (load-theme 'modus-operandi :no-confirm))

Autodark

  (use-package auto-dark
    :ensure t
    :custom
    (auto-dark-themes '((modus-vivendi) (modus-operandi)))
    :init (auto-dark-mode))

Catpuccin

  ;; (use-package catppuccin-theme
  ;;   :init (setq catppuccin-flavor 'mocha)
  ;;   :config
  ;;   (load-theme 'catppuccin :no-confirm))

Ultra Scroll

  (use-package ultra-scroll
    :custom
    (scroll-conservatively 3)
    (scroll-margin 0)
    :config
    (ultra-scroll-mode 1))

Functionality

Navigation

Ace-Window

  (use-package ace-window
    :bind (("M-o" . ace-window)))

Avy

  (use-package avy
    :bind
    (("C-:" . avy-goto-char)
     ("C-M-'" . avy-goto-char-2)
     ("M-g w" . avy-goto-word-1)
     ("M-g W" . avy-goto-word-0)))

Completion

Vertico

  (use-package vertico
    :init (vertico-mode)
    :custom (vertico-cycle t))

Savehist

  (use-package emacs
    :ensure nil
    :init (savehist-mode))

Orderless

  (use-package orderless
    :init
    (setq completion-styles '(orderless flex)
          completion-category-defaults nil
          completion-category-overrides '((file (styles partial-completion)))))

Corfu

  (use-package corfu
    :custom
    (corfu-cycle t)
    (corfu-auto nil)
    (corfu-echo-documentation 0.25)
    :init
    (global-corfu-mode)
    (setq tab-always-indent 'complete))

Cape

  (use-package cape
    :init
    (add-to-list 'completion-at-point-functions #'cape-dabbrev)
    (add-to-list 'completion-at-point-functions #'cape-file)
    (add-to-list 'completion-at-point-functions #'cape-history))

Marginalia

  (use-package marginalia
    :after vertico
    :init (marginalia-mode))

Consult

  (use-package consult
    :bind (("C-c M-x" . consult-mode-command)
           ("C-c h" . consult-history)
           ("C-c k" . consult-kmacro)
           ("C-c m" . consult-man)
           ("C-c i" . consult-info)
           ([remap Info-search] . consult-info)
           ;; C-x bindings in `ctl-x-map'
           ("C-x M-:" . consult-complex-command)
           ("C-x b" . consult-buffer)
           ("C-x 4 b" . consult-buffer-other-window)
           ("C-x 5 b" . consult-buffer-other-frame)
           ("C-x t b" . consult-buffer-other-tab)
           ("C-x r b" . consult-bookmark)
           ("C-x p b" . consult-project-buffer)
           ;; Custom M-# bindings for fast register a
           ("M-#" . consult-register-load)
           ("M-'" . consult-register-store)
           ("C-M-#" . consult-register)
           ;; Other custom bindings
           ("M-y" . consult-yank-pop)
           ;; M-g bindings in `goto-map'
           ("M-g e" . consult-compile-error)
           ("M-g f" . consult-flymake)
           ("M-g g" . consult-goto-line)
           ("M-g M-g" . consult-goto-line)
           ("M-g o" . consult-outline)
           ("M-g m" . consult-mark)
           ("M-g k" . consult-global-mark)
           ("M-g i" . consult-imenu)
           ("M-g I" . consult-imenu-multi)
           ;; M-s bindings in `search-map'
           ("M-s d" . consult-fd)
           ("M-s c" . consult-locate)
           ("M-s g" . consult-grep)
           ("M-s G" . consult-git-grep)
           ("M-s r" . consult-ripgrep)
           ("M-s l" . consult-line)
           ("M-s L" . consult-line-multi)
           ("M-s k" . consult-keep-lines)
           ("M-s u" . consult-focus-lines)
           ;; Isearch integration
           ("M-s e" . consult-isearch-history)
           :map isearch-mode-map
           ("M-e" . consult-isearch-history)
           ("M-s e" . consult-isearch-history)
           ("M-s l" . consult-line)
           ("M-s L" . consult-line-multi)
           ;; Minibuffer history
           :map minibuffer-local-map
           ("M-s" . consult-history)
           ("M-r" . consult-history))

    :hook (completion-list-mode . consult-preview-at-point-mode)

    :init
    (advice-add #'register-preview :override #'consult-register-window)
    (setq register-preview-delay 0.5)

    (setq xref-show-xrefs-function #'consult-xref
          xref-show-definitions-function #'consult-xref)

    :config

    (consult-customize
     consult-theme :preview-key '(:debounce 0.2 any)
     consult-ripgrep consult-git-grep consult-grep
     consult-bookmark consult-recent-file consult-xref
     consult--source-bookmark consult--source-file-register
     consult--source-recent-file consult--source-project-recent-file
     :preview-key '(:debounce 0.4 any))

    (setq consult-narrow-key "<"))

Lsp

eglot

  (use-package eglot
    :ensure nil
    :bind (:map eglot-mode-map
                ("C-c l r" . eglot-rename)
                ("C-c l f" . eglot-format-buffer)
                ("C-c l a" . eglot-code-actions)
                ("C-c l q" . eglot-code-action-quickfix)
                ("C-c l d" . xref-find-definitions)
                ("C-c l i" . eglot-find-implementation)
                ("C-c l t" . eglot-find-type-definition)
                ("C-c l s" . xref-find-references)
                ("C-c l h" . eldoc)
                ("C-c l R" . eglot-restart-process)
                ("C-c l e" . eglot-errors-at-point))
    (:map flymake-mode-map
  	("M-n" . flymake-goto-next-error)
  	("M-p" . flymake-goto-prev-error)))

eldoc-box

  (use-package eldoc-box
    :hook (eglot-managed-mode . eldoc-box-hover-at-point-mode))

Markdown

I don't really use markdown (/wball/dotfiles/src/commit/8a7f406fdb04d5d45961c01ec68337042dc506e0/emacs/.config/emacs/Org%20Mode is a strict improvement imo), but it's handy for rendering documentation.

  (use-package markdown-mode)

Languages

Agda

  ;; (load-file (let ((coding-system-for-read 'utf-8))
  ;;                 (shell-command-to-string "agda-mode locate")))

PG

  (use-package proof-general)

Perga

  (use-package perga-mode
    :vc (:url "https://forgejo.ballcloud.cc/wball/perga-mode.git"
         :rev :latest))

Scheme

  (use-package geiser)
  (use-package geiser-chez
    :custom
    (geiser-chez-binary "chez"))

Haskell

  (use-package haskell-mode)

Latex

Auctex

  (use-package tex
    :ensure auctex
    :hook
    (LaTeX-mode . visual-line-mode)
    (LaTeX-mode . flyspell-mode)
    (LaTeX-mode . reftex-mode)
    (LaTeX-mode . prettify-symbols-mode)
    (LaTeX-mode . outline-minor-mode)
    :custom
    (TeX-auto-save t)
    (TeX-parse-self t)
    (TeX-master t)
    (reftex-plug-in-to-AUCTeX t)
    (preview-auto-cache-preamble t)
    (preview-scale-function 0.50))

CDLatex

  (use-package cdlatex
    :hook
    (LaTeX-mode . #'turn-on-cdlatex)
    :custom
    (cdlatex-math-symbol-prefix ?\;))

Yasnippet and laas

  (use-package yasnippet
    :config
    (yas-global-mode 1))
  (defun wball/beginning-of-word ()
    "Return t if point is at the beginning of a word."
    (eq (point) (car (bounds-of-thing-at-point 'word))))

  (use-package laas
    :hook ((LaTeX-mode . laas-mode)
           (org-mode . laas-mode))
    :custom
    (laas-enable-auto-space nil)
    :config
    (aas-set-snippets 'laas-mode
      :cond #'wball/beginning-of-word
      "mk" (lambda () (interactive)
             (yas-expand-snippet "\\\\($1\\\\)$0"))
      "dm" (lambda () (interactive)
             (yas-expand-snippet "\\[\n\t$1\n\\]"))
      :cond (lambda () (and (wball/beginning-of-word) (texmathp)))
      "set" (lambda () (interactive)
              (yas-expand-snippet "\\\\{$1\\\\}$0"))
      "empty" "\\emptyset"
      "and" "\\wedge"
      "or" "\\vee"
      "forall" "\\forall"
      "exists" "\\exists"
      "notin" "\\notin"
      "cap" "\\cap"
      "cup" "\\cup"
      :cond #'texmathp
      "NN" "\\N"
      "ZZ" "\\Z"
      "QQ" "\\Q"
      "oo" "\\circ"
      "RR" "\\R"
      "CC" "\\C"
      "BB" "\\B"
      "PP" "\\P"
      "FF" "\\F"
      "HH" "\\H"
      "SS" "\\Ss"
      "TT" "\\T"
      "\\\\\\" "\\setminus"
      "s=" "\\subseteq"
      "s<" "\\subset"
      "invs" "^{-1}"
      "opl" "\\oplus"
      "td" (lambda () (interactive)
             (yas-expand-snippet "^{$1}$0"))
      "__" (lambda () (interactive)
             (yas-expand-snippet "_{$1}$0"))))

Org Mode

Org itself

I use this fork of org-mode in order to have amazing latex previews. Make sure to follow the installation instructions! It's supposed to eventually be merged into org proper, which is very exciting. I'm already pretty dependent on this feature (the previews are just that good), so I'll have to use this until it gets merged, but that's fine with me.

  (use-package org-mode
    :load-path "~/dotfiles/emacs/.config/emacs/elpa/org-mode/lisp/"
    :init
    (setq org-list-allow-alphabetical t)
    :custom
    (org-log-into-drawer t)
    (org-startup-indented t)
    (org-hide-emphasis-markers t)
    (org-startup-with-inline-images t)
    (org-image-actual-width '(300))
    (org-export-with-smart-quotes t)
    (org-directory "~/Nextcloud/org")
    (org-cite-global-bibliography '("~/Nextcloud/Documents/library.bib"))
    (org-agenda-files `(,org-directory))
    (org-todo-keywords
     '((sequence "TODO" "VERIFY" "|" "DONE")))
    (org-default-notes-file (mapcar (lambda (x) (concat org-directory x))
                                    '("/todo.org" "/done.org")))
    (org-latex-preview-mode-display-live t)
    :config
    (plist-put org-latex-preview-appearance-options
               :page-width 0.8)
    (setq org-format-latex-options (plist-put org-format-latex-options :scale 0.6))
    (require 'ox-latex)
    (require 'ox-beamer)
    (require 'org-tempo)
    (add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp"))
    (add-to-list 'org-structure-template-alist '("ltx" . "export latex"))
    (add-to-list 'org-structure-template-alist '("pf" . "proof"))
    (add-to-list 'org-structure-template-alist '("thm" . "theorem"))
    (add-to-list 'org-structure-template-alist '("def" . "definition"))
    (add-to-list 'org-structure-template-alist '("lem" . "lemma"))
    :hook
    (org-mode . visual-line-mode)
    (org-mode . flyspell-mode)
    (org-mode . org-latex-preview-mode))

Org Noter

  (use-package djvu)
  (use-package nov)
  (use-package org-noter)

Olivetti

  (use-package olivetti
    :custom
    (fill-column 80)
    :hook
    (org-mode . olivetti-mode))

Mixed Pitch

  (use-package mixed-pitch
    :hook
    (org-mode . mixed-pitch-mode))

toki pona support

  (with-eval-after-load 'ox
    (add-to-list 'org-export-dictionary	       
                 '("Footnotes" ("tok" :default "toki anpa")))
    (add-to-list 'org-export-dictionary	       
                 '("Author" ("tok" :default "jan toki")))
    (add-to-list 'org-export-dictionary	       
                 '("Table of Contents" ("tok" :default "ni li lon lipu ni::")))
    (add-to-list 'org-export-dictionary	       
                 '("Created" ("tok" :default "mi pali e ni lon tenpo"))))

Prettify

  (use-package org-modern
    :hook ((org-mode . org-modern-mode)
           (org-agenda-finalize . org-modern-agenda)))

Simple Presentations

  (use-package org-present)

Org Bloggy stuff

  (setq org-publish-project-alist
        `(("org-posts"
           :base-directory "~/repos/blog/posts/"
           :publishing-directory "/ssh:server:~/blog/"
           :base-extension "org"
           :recursive t
           :publishing-function org-html-publish-to-html
  	 :author "William Ball"
  	 :language "en"
           :auto-sitemap t
           :sitemap-filename "archive.org"
           :sitemap-title "Archive"
           :sitemap-style list
  	 :sitemap-sort-files anti-chronologically
           :html-head "<link rel=\"stylesheet\" href=\"/static/style.css\" type=\"text/css\"/><link rel=\"icon\" href=\"static/favicon.ico\"/>"
           :html-preamble t
           :html-preamble-format (("en" "<div class=\"blog-header\"><a href=\"archive.html\">Post Archive</a></div>")
                                  ("tok" "<div class=\"blog-header\"><a href=\"archive.html\">toki ante</a></div>"))
           )
  	("org-pages"
  	 :base-directory "~/repos/blog/pages/"
  	 :publishing-directory "/ssh:server:~/blog/"
  	 :base-extension "org"
  	 :recursive t
  	 :publishing-function org-html-publish-to-html
  	 :author "William Ball"
  	 :language "en"
  	 :html-head "<link rel=\"stylesheet\" href=\"/static/style.css\" type=\"text/css\"/><link rel=\"icon\" href\"static/favicon.ico\"/>"
  	 )
  	("org-static"
  	 :base-directory "~/repos/blog/static/"
  	 :publishing-directory "/ssh:server:~/blog/static/"
  	 :base-extension "ico\\|ttf\\|css"
  	 :publishing-function org-publish-attachment
  	 :recursive t
  	 )
  	("org-media"
  	 :base-directory "~/repos/blog/media/"
  	 :publishing-directory "/ssh:server:~/blog/media/"
  	 :base-extension "png\\|svg\\|pdf\\|mp4\\|mp3\\|ogg"
  	 :publishing-function org-publish-attachment
  	 :recursive t
  	 )
  	("org" :components ("org-posts" "org-static" "org-media" "org-pages"))
  	))

  (use-package htmlize)

Simple http server

  (use-package simple-httpd)

Pdfs

Pdf tools

I'm running into weird performance issues with pdf-tools. I think it has to do with HiDPI. Pdfs are a little blurry without scaling set, but it's way better than without.

  (use-package pdf-tools
    :custom
    (pdf-view-use-scaling nil)
    :config
    (pdf-tools-install))

Terminals/Shells

Eshell

  (defun wball/configure-eshell ()
    (add-hook 'eshell-pre-command-hook 'eshell-save-some-history)
    (add-to-list 'eshell-output-filter-functions 'eshell-truncate-buffer)

    (setq eshell-history-size 10000
          eshell-buffer-maximum-lines 10000
          eshell-history-ignoredups t
          eshell-scroll-to-bottom-on-input t))

  (use-package eshell
    :ensure nil
    :commands eshell
    :hook (eshell-first-time-mode . wball/configure-eshell)
    :bind (("C-c e" . eshell))
    :config
    (with-eval-after-load 'esh-opt
      (setq eshell-destroy-buffer-when-process-dies t)))

  (defalias 'eshell/ff 'find-file)
  (defalias 'eshell/fo 'find-file-other-window)

VTerm

  (use-package vterm)

Dired

  (use-package emacs
    :ensure nil
    :commands (dired dired-jump)
    :custom ((dired-listing-switches "-agho --group-directories-first"))
    :config
    (require 'dired-x))

  (use-package dired-hide-dotfiles
    :hook (dired-mode . dired-hide-dotfiles-mode))

Misc

magit

  (use-package transient
    :ensure t)

  (use-package magit
    :after transient)

Newsticker

  (use-package newsticker
    :ensure nil
    :custom
    (newsticker-url-list-defaults nil)
    (newsticker-url-list
     '(("Logic Arxiv" "https://rss.arxiv.org/rss/math.LO")
       ("Planet Emacslife" "https://planet.emacslife.com/atom.xml")
       ("It's Foss News" "https://news.itsfoss.com/latest/rss"))))

Books

  (defun wball/books ()
  "Recursively search and open books from ~/Nextcloud/Books/."
  (interactive)
  (let* ((books-dir (expand-file-name "~/Nextcloud/Books/"))
         (files (directory-files-recursively books-dir "\\.pdf$\\|\\.epub$\\|\\.djvu$" nil))
         (relative-files (mapcar (lambda (f) 
                                   (string-remove-prefix books-dir f))
                                 files))
         (choice (completing-read "Book: " relative-files nil t)))
    (when choice
      (find-file (concat books-dir choice)))))

(global-set-key (kbd "C-c b") 'wball/books)