home | section main page


Emacs Configuration

Table of Contents

1. Introduction

This is my Vanilla Emacs configuration, made to work with my NixOS configuration. For that reason, you will not see :ensure t inside any use-package declaration, for emacs packages are all compiled natively and reproducibly on the NixOS side. This configuration uses the emacs-lisp language only to configure variables for said packages, for the most part.

1.1. User

Change these variables:

(setq system-email "ret2pop@gmail.com")
(setq system-username "prestonpan")
(setq system-fullname "Preston Pan")

1.2. Emacs

These are all the options that need to be set at the start of the program. Because use-package is largely declarative, the order of many of these options should not matter. However, there is some imperative programming that must be done. Hooks are also largely declarative in this configuration as they are also defined using the use-package macros. Some of these options will have documentation strings attached, so it is easy to follow what the individual options do. Emacs is self documenting, after all!

(use-package emacs
  :custom
  (warning-minimum-level :emergency "Supress emacs warnings")
  (debug-ignored-errors (cons 'remote-file-error debug-ignored-errors))

  (mouse-wheel-scroll-amount '(1 ((shift) . 1)))
  (mouse-wheel-progressive-speed nil)
  (mouse-wheel-follow-mouse 't)
  (scroll-conservatively 101)
  (scroll-step 1)

  (display-time-24hr-format t "Use 24 hour format to read the time")
  (display-line-numbers-type 'relative "Relative line numbers for easy vim jumping")
  (use-short-answers t "Use y instead of yes")
  (make-backup-files nil "Don't make backups")
  (display-fill-column-indicator-column 100)
  (line-spacing 2 "Default line spacing")
  (fill-column 100 "100 characters per column max")
  :hook ((text-mode . auto-fill-mode)
         (text-mode . visual-line-mode)
         (prog-mode . auto-fill-mode)
         (prog-mode . display-line-numbers-mode)
         (prog-mode . display-fill-column-indicator-mode)
         (org-mode . auto-fill-mode)
         (org-mode . display-fill-column-indicator-mode)
         (org-mode . (lambda ()
                       (setq prettify-symbols-alist
                             '(("#+begin_src" . ?)
                               ("#+BEGIN_SRC" . ?)
                               ("#+end_src" . ?)
                               ("#+END_SRC" . ?)
                               ("#+begin_example" . ?)
                               ("#+BEGIN_EXAMPLE" . ?)
                               ("#+end_example" . ?)
                               ("#+END_EXAMPLE" . ?)
                               ("#+header:" . ?)
                               ("#+HEADER:" . ?)
                               ("#+name:" . ?﮸)
                               ("#+NAME:" . ?﮸)
                               ("#+results:" . ?)
                               ("#+RESULTS:" . ?)
                               ("#+call:" . ?)
                               ("#+CALL:" . ?)
                               (":PROPERTIES:" . ?)
                               (":properties:" . ?)
                               ("lambda" . ?λ)
                               ("->"     . ?→)
                               ("map"    . ?↦)
                               ("/="     . ?≠)
                               ("!="     . ?≠)
                               ("=="     . ?≡)
                               ("<="     . ?≤)
                               (">="     . ?≥)
                               ("&&"     . ?∧)
                               ("||"     . ?∨)
                               ("sqrt"   . ?√)
                               ("..."    . ?…)))
                       (prettify-symbols-mode)))
         (prog-mode .
                    (lambda ()
                      (setq prettify-symbols-alist
                            '(("lambda" . ?λ)
                              ("->"     . ?→)
                              ("map"    . ?↦)
                              ("/="     . ?≠)
                              ("!="     . ?≠)
                              ("=="     . ?≡)
                              ("<="     . ?≤)
                              (">="     . ?≥)
                              ("&&"     . ?∧)
                              ("||"     . ?∨)
                              ("sqrt"   . ?√)
                              ("..."    . ?…)))
                      (prettify-symbols-mode))))
  :config
  (require 'tex-site)
  (server-start)
  (pixel-scroll-precision-mode 1)
  (display-battery-mode 1)
  (display-time-mode 1)
  (menu-bar-mode -1)
  (scroll-bar-mode -1)
  (tool-bar-mode -1)
  (global-prettify-symbols-mode 1)

  (load-theme 'catppuccin :no-confirm)
  (set-face-attribute 'default nil :font "Iosevka Nerd Font" :height 140)
  (set-face-attribute 'default nil :height 120)

  (set-frame-parameter nil 'alpha-background 90)
  (add-to-list 'default-frame-alist '(alpha-background . 90)))

As you can see, the config (and sometimes the init section) of most of these use-package blocks contain most of the imperative commands. In fact, most of the configurations are completely declarative without any imperative programming at all (i.e. hooks and custom options). Note that Emacs lambdas contain imperative state, unlike in NixOS where lambdas can contain function applications but they themselves are mainly declarative. Usually, however, the lambdas or functions do little to nothing and are mainly wrappers for executing two commands or for giving a variable an option. Often you will see a config section of a use-package declaration have only one or two entries, which is intentional, as I've designed this configuration to put as little in config as possible. I hardly consider most of this configuration to be imperative, but of course Emacs was not designed to be fully imperative.

1.3. Org Mode

This is my org mode configuration, which also configures latex.

(use-package org
  :custom
  (org-confirm-babel-evaluate nil "Don't ask to evaluate code block")
  (org-export-with-broken-links t "publish website even with broken links")
  (org-src-fontify-natively t "Colors!")
  (org-latex-preview-image-directory (expand-file-name "~/.cache/ltximg/") "don't use weird cache location")
  (org-preview-latex-image-directory (expand-file-name "~/.cache/ltximg/") "don't use weird cache location")
  (TeX-PDF-mode t)
  (org-latex-pdf-process '("xelatex -interaction=nonstopmode -output-directory=%o %f") "set xelatex as default")
  (TeX-engine 'xetex "set xelatex as default engine")
  (preview-default-option-list '("displaymath" "textmath" "graphics"))
  (preview-image-type 'png "Use PNGs")
  (org-format-latex-options (plist-put org-format-latex-options :scale 1.5))
  (org-return-follows-link t "be able to follow links without mouse")
  (org-habit-preceding-days 1 "See org habit entries")
  (org-startup-indented t "Indent the headings")
  (org-image-actual-width '(300) "Cap width") 
  (org-startup-with-latex-preview t "see latex previews on opening file")
  (org-startup-with-inline-images t "See images on opening file")
  (org-hide-emphasis-markers t "prettify org mode")
  (org-use-sub-superscripts "{}")
  (org-pretty-entities t "prettify org mode")
  (org-agenda-files (list "~/monorepo/agenda.org" "~/org/notes.org" "~/org/agenda.org") "set default org files")
  (org-default-notes-file (concat org-directory "/notes.org") "Notes file")
  (org-publish-project-alist
        '(("website-org"
           :base-directory "~/monorepo"
           :base-extension "org"
           :publishing-directory "~/website_html"
           :recursive t
           :exclude ".*/publish-org-roam-ui/.*"
           :exclude ".*/node_modules/.*"
           :exclude ".*/org-roam-ui/.*"
           :exclude ".*/out/.*"
           :exclude ".*/example/.*"
           :publishing-function org-html-publish-to-html
           :headline-levels 4
           :html-preamble t
           :html-preamble-format (("en" "<p class=\"preamble\"><a href=\"/index.html\">home</a> | <a href=\"./index.html\">section main page</a></p><hr>")))
          ("website-static"
           :base-directory "~/monorepo"
           :base-extension "css\\|js\\|png\\|jpg\\|gif\\|pdf\\|mp3\\|ogg\\|swf\\|ico\\|asc\\|pub\\|webmanifest\\|xml"
           :publishing-directory "~/website_html/"
           :recursive t
           :exclude ".*/publish-org-roam-ui/.*"
           :exclude ".*/node_modules/.*"
           :exclude ".*/org-roam-ui/.*"
           :exclude ".*/out/.*"
           :exclude ".*/example/.*"
           :publishing-function org-publish-attachment)
          ("website" :auto-sitemap t :components ("website-org" "website-static"))) "functions to publish website")
  (org-html-postamble "Copyright © 2024 Preston Pan" "set copyright notice on bottom of site")
  :config
  (require 'ox-publish)
  (require 'org-tempo)
  (require 'org-habit)
  (org-babel-do-load-languages 'org-babel-load-languages
                               '((shell . t)
                                 (python . t)
                                 (latex . t))))

As you can see, I only have one real entry in config here (I don't count requires even though they have to be on the top)

2. Unicode

I want emacs to have unicode fonts.

(use-package unicode-fonts
  :init (unicode-fonts-setup))

3. Autopair

Use electric-pair to automatically complete pairs of things. We need to change what electric-pair does based on the mode.

(use-package electric-pair
  :hook ((org-mode . electric-pair-mode)
         (prog-mode . electric-pair-mode)))

4. Lyrics

This currently doesn't work I'm pretty sure, but it's supposed to fetch lyrics from mpd.

(use-package lyrics-fetcher
  :after (emms)
  :custom
  (lyrics-fetcher-genius-access-token (password-store-get "genius_api") "Use genius for backend")
  :config
  (lyrics-fetcher-use-backend 'genius))

5. Fragtog

This package is used to generate previews automatically when your cursor hovers over a latex snippet.

(use-package org-fragtog :hook (org-mode . org-fragtog-mode))

6. Snippets

Yasnippets are useful for macros that automatically complete to an arbitrary form.

(use-package yasnippet
  :config
  (add-to-list 'yas-snippet-dirs "~/monorepo/yasnippet/")
  (yas-global-mode 1)
  :hook (org-mode . (lambda () (yas-minor-mode) (yas-activate-extra-mode 'latex-mode))))

7. Completion

Company-mode! We need this to do autocomplete stuff.

(use-package company
  :config
  '(add-to-list 'company-backends '(company-ispell company-capf company-yasnippet company-files))
  :hook ((after-init . global-company-mode)))

8. Spelling

This loads a dictionary so that I can save certain words to be not misspelled and also have this spellcheck during org mode.

(use-package ispell
  :custom
  (ispell-program-name "aspell" "use aspell")
  (ispell-silently-savep t "Save changes to dict without confirmation")
  (ispell-dictionary "en" "Use english dictionary")
  (ispell-alternate-dictionary "~/.local/share/dict" "dict location"))

(use-package flyspell
  :hook (text-mode . flyspell-mode))

9. Packages

First, some small configurations and some evil-mode initilaization because I like vim keybindings:

(use-package evil
  :custom
  (evil-want-keybinding nil)
  :config
  (evil-mode 1)
  (evil-set-undo-system 'undo-redo)
  (evil-set-initial-state 'pdf-view-mode 'normal))

(use-package evil-collection
  :after (evil)
  :custom
  (evil-want-keybinding nil)
  :config
  (evil-collection-init))

(with-eval-after-load 'evil-maps
(define-key evil-motion-state-map (kbd "SPC") nil)
(define-key evil-motion-state-map (kbd "RET") nil)
(define-key evil-motion-state-map (kbd "TAB") nil))

(use-package evil-commentary
  :after (evil)
  :config
  (evil-commentary-mode))

(use-package evil-org
  :after (evil org)
  :hook (org-mode . (lambda () evil-org-mode))
  :config
  (require 'evil-org-agenda)
  (evil-org-agenda-set-keys))

(use-package which-key
  :config
  (which-key-mode))

(use-package page-break-lines
  :init
  (page-break-lines-mode))

9.1. Journal

I use org-journal to journal about my life, and it's a part of my website:

(use-package org-journal
  :after (org)
  :custom
  (org-journal-dir "~/monorepo/journal/" "Set journal directory")
  (org-journal-date-format "%A, %d %B %Y" "Date format")
  (org-journal-file-format "%Y%m%d.org" "Automatic file creation format based on date")
  (org-journal-enable-agenda-integration t "All org-journal entries are org-agenda entries")
  :init
  (defun org-journal-file-header-func (time)
    "Custom function to create journal header."
    (concat
     (pcase org-journal-file-type
       (`daily "#+TITLE: Daily Journal\n#+STARTUP: showeverything\n#+DESCRIPTION: My daily journal entry\n#+AUTHOR: Preston Pan\n#+HTML_HEAD: <link rel=\"stylesheet\" type=\"text/css\" href=\"../style.css\" />\n#+html_head: <script src=\"https://polyfill.io/v3/polyfill.min.js?features=es6\"></script>\n#+html_head: <script id=\"MathJax-script\" async src=\"https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js\"></script>\n#+options: broken-links:t")
       (`weekly "#+TITLE: Weekly Journal\n#+STARTUP: folded")
       (`monthly "#+TITLE: Monthly Journal\n#+STARTUP: folded")
       (`yearly "#+TITLE: Yearly Journal\n#+STARTUP: folded"))))
  (setq org-journal-file-header 'org-journal-file-header-func))

9.2. Doom Modeline

The default modeline is ugly. I replace it with the doom modeline because it's better.

(use-package doom-modeline
  :config
  (doom-modeline-mode 1))

9.3. Grammar

I want to write good! I grammar good too.

(use-package writegood-mode
  :hook (text-mode . writegood-mode))

9.4. Make Org Look Better

Org superstar adds those nice looking utf-8 bullets:

(use-package org-superstar
  :after (org)
  :hook (org-mode . (lambda () (org-superstar-mode 1))))

9.5. LSP

We set up eglot, the LSP manager for emacs, now built in:

(use-package eglot
  :hook
  (prog-mode . eglot-ensure)
  (nix-mode . eglot-ensure)
  :config
  (add-to-list 'eglot-server-programs '(nix-mode . ("nil"))))

(use-package lsp
  :hook
  (prog-mode . lsp))

(use-package flycheck
  :config (global-flycheck-mode))

(use-package platformio-mode
  :hook (prog-mode . platformio-conditionally-enable))

9.5.1. C/C++

Specific configuration for C (I also use the clangd lsp):

(use-package irony-mode
  :hook (
  (c++-mode . irony-mode)
  (c-mode . irony-mode)
  (objc-mode . irony-mode)
  (irony-mode . irony-cdb-autosetup-compile-options)))

(use-package irony-eldoc
  :hook ((irony-mode . irony-eldoc)))

9.5.2. Solidity

For writing solidity:

(use-package solidity-mode)
(use-package company-solidity)
(use-package solidity-flycheck
  :custom
  (solidity-flycheck-solc-checker-active t))

9.6. Projectile

Manages projects and shit.

(use-package projectile
  :custom
  (projectile-project-search-path '("~/org" "~/src" "~/monorepo" "~/projects") "search path for projects")
  :config
  (projectile-mode +1))

9.7. Dashboard

We want our emacs initialization to be pretty and display useful things.

(use-package dashboard
  :after (projectile)
  :custom
  (dashboard-banner-logo-title "Welcome, Commander!" "Set title for dashboard")
  (dashboard-icon-type 'nerd-icons "Use nerd icons")
  (dashboard-vertically-center-content t "Center content")
  (dashboard-set-init-info t)
  (dashboard-week-agenda t "Agenda in dashboard")
  (dashboard-items '((recents   . 5)
                        (bookmarks . 5)
                        (projects  . 5)
                        (agenda    . 5)
                        (registers . 5)) "Look at some items")
  :config
  (dashboard-setup-startup-hook))

9.8. Ivy

Ivy is a pretty cool general program for displaying stuff:

(use-package counsel)
(use-package ivy
  :custom
  (ivy-use-virtual-buffers t "Make searching more efficient")
  (enable-recursive-minibuffers t "Don't get soft locked when in a minibuffer")
  :bind
  ("C-s" . swiper)
  ("C-c C-r" . ivy-resume)
  ("M-x" . counsel-M-x)
  ("C-x C-f" . counsel-find-file)
  ("<f1> f" . counsel-describe-function)
  ("<f1> v" . counsel-describe-variable)
  ("<f1> o" . counsel-describe-symbol)
  ("<f1> l" . counsel-find-library)
  ("<f2> i" . counsel-info-lookup-symbol)
  ("<f2> u" . counsel-unicode-char)
  ("C-c g" . counsel-git)
  ("C-c j" . counsel-git-grep)
  ("C-c k" . counsel-ag)
  ("C-x l" . counsel-locate)
  :config
  (ivy-mode))
(define-key ivy-minibuffer-map (kbd "C-j") 'ivy-immediate-done)

I use it for an M-x replacement and a dired replacement, among other things.

9.9. Magit

I use magit in order to do all my git management in emacs.

(use-package magit)

9.10. IRC

Configure IRC to use my username.

(use-package erc
  :custom
  (erc-nick system-username "Set erc nick to username")
  (erc-user-full-name system-fullname "Use real name for full name"))

9.11. Keybindings

Global keybindings for everything that I care about globally. It's all here! I use general to manage my global keybindings in a declarative way. These are in part inspired by the doom emacs keybindings.

(use-package general
  :init
  (defun prestonpan ()
    (interactive)
    (erc-tls :server "nullring.xyz"
             :port   "6697"))
  (defun liberachat ()
    (interactive)
    (erc-tls :server "irc.libera.chat"
             :port   "6697"))
  (defun efnet ()
    (interactive)
    (erc-tls :server "irc.prison.net"
             :port   "6697"))
  (defun matrix-org ()
    (interactive)
    (ement-connect :uri-prefix "http://localhost:8009"))
  :config
  (general-create-definer leader-key :prefix "SPC")
  (leader-key 'normal
    "o a" '(org-agenda :wk "Open agenda")
    "o c" '(org-capture :wk "Capture")
    "n j j" '(org-journal-new-entry :wk "Make new journal entry")
    "n r f" '(org-roam-node-find :wk "Find roam node")
    "n r i" '(org-roam-node-insert :wk "Insert roam node")
    "n r a" '(org-roam-alias-add :wk "Add alias to org roam node")
    "n r g" '(org-roam-graph :wk "Graph roam database")
    "r s s" '(elfeed :wk "rss feed")
    "." '(counsel-find-file :wk "find file")
    "g" '(:ignore t :wk "Magit")
    "g /" '(magit-dispatch :wk "git commands")
    "g P" '(magit-push :wk "git push")
    "g c" '(magit-commit :wk "git commit")
    "g p" '(magit-pull :wk "Pull from git")
    "g s" '(magit-status :wk "Change status of files")
    "o t" '(vterm :wk "Terminal")
    "o e" '(eshell :wk "Elisp Interpreter")
    "o m" '(mu4e :wk "Email")
    "e w w" '(eww :wk "web browser")
    "e c c" '(ellama-chat :wk "Chat with Ollama")
    "e a b" '(ellama-ask-about :wk "Ask Ollama")
    "e s" '(ellama-summarize :wk "Summarize text with Ollama")
    "e c r" '(ellama-code-review :wk "Review code with Ollama")
    "e c C" '(ellama-code-complete :wk "Complete code with Ollama")
    "e c a" '(ellama-code-add :wk "Add code with Ollama")
    "e c e" '(ellama-code-edit :wk "Edit code with Ollama")
    "e w i" '(ellama-improve-wording :wk "Improve wording with Ollama")
    "e g i" '(ellama-improve-grammar :wk "Improve grammar with Ollama")
    "g s" '(gptel-send :wk "Send to Ollama")
    "g e" '(gptel :wk "Ollama interface")
    "m P p" '(org-publish :wk "Publish website components")
    "s e" '(sudo-edit :wk "Edit file with sudo")
    "m m" '(emms :wk "Music player")
    "m l" '(lyrics-fetcher-show-lyrics :wk "Music lyrics")
    "o p" '(treemacs :wk "Project Drawer")
    "o P" '(treemacs-projectile :wk "Import Projectile project to treemacs")
    "f f" '(eglot-format :wk "Format code buffer")
    "i p c" '(prestonpan :wk "Connect to my IRC server")
    "i l c" '(liberachat :wk "Connect to libera chat server")
    "i e c" '(efnet :wk "Connect to efnet chat server")
    "h" '(:ignore t :wk "Documentation")
    "h v" '(counsel-describe-variable :wk "Describe variable")
    "h f" '(counsel-describe-function :wk "Describe function")
    "h h" '(help :wk "Help")
    "h m" '(woman :wk "Manual")
    "h i" '(info :wk "Info")
    "s m" '(proced :wk "System Manager")
    "l p" '(list-processes :wk "List Emacs Processes")
    "m I" '(org-id-get-create :wk "Make org id")
    "w r" '(writeroom-mode :wk "focus mode for writing")
    "y n s" '(yas-new-snippet :wk "Create new snippet")
    "u w" '((lambda () (interactive) (shell-command "rsync -azvP ~/website_html/ root@nullring.xyz:/usr/share/nginx/ret2pop/")) :wk "rsync website update")
    "h r r" '(lambda () (interactive) (org-babel-load-file (expand-file-name "~/monorepo/config/emacs.org")))))

9.12. LLM

I use LLMs in order to help me come up with ideas. I use a local LLM so that I can have a competitive LLM that doesn't cost money.

(use-package ellama
  :custom
  (ellama-sessions-directory "~/org/ellama/" "Set org directory")
  :init
  (require 'llm-ollama)
  (setopt ellama-provider (make-llm-ollama
             :host "localhost"
             :chat-model "gemma:7b")))

9.13. RSS Feed

I use really simple syndication (RSS) in order to read news. As a result, I use elfeed to fetch feeds found on my website:

(use-package elfeed
  :hook ((elfeed-search-mode . elfeed-update))
  :custom
  (elfeed-search-filter "@1-month-ago +unread"))

(use-package elfeed-org
  :custom
  (rmh-elfeed-org-files '("~/monorepo/config/elfeed.org") "Use elfeed config in repo as default")
  :config
  (elfeed-org))

9.13.1. Youtube

Then we set up elfeed-tube for Youtube video RSS feeds (so I don't ever have to use the web interface and can control it from emacs):

(use-package elfeed-tube
  :after elfeed
  :demand t
  :config
  (elfeed-tube-setup)
  :bind (:map elfeed-show-mode-map
         ("F" . elfeed-tube-fetch)
         ([remap save-buffer] . elfeed-tube-save)
         :map elfeed-search-mode-map
         ("F" . elfeed-tube-fetch)
         ([remap save-buffer] . elfeed-tube-save)))

(use-package elfeed-tube-mpv
  :bind (:map elfeed-show-mode-map
              ("C-c C-f" . elfeed-tube-mpv-follow-mode)
              ("C-c C-c" . elfeed-tube-mpv)
              ("C-c C-w" . elfeed-tube-mpv-where)
         :map elfeed-search-mode-map
                ("M" . elfeed-tube-mpv)))

9.14. Project Drawer

I use treemacs as my sidebar for projects, so that I can easily navigate to any file in the project directory.

(use-package treemacs)
(use-package treemacs-evil
  :after (treemacs evil))
(use-package treemacs-projectile
  :after (treemacs projectile))
(use-package treemacs-magit
  :after (treemacs magit))

9.15. Eww

Used only for the purpose of viewing RSS feed items in emacs if I can, only resorting to Chromium if I have to:

(use-package eww
  :custom
  (search-engines
        '((("google" "g") "https://google.com/search?q=%s")
          (("duckduckgo" "d" "ddg") "https://duckduckgo.com/?q=%s")
          (("rfc" "r") "https://www.rfc-editor.org/rfc/rfc%s.txt")
          (("rfc-kw" "rk") "https://www.rfc-editor.org/search/rfc_search_detail.php?title=%s"))
        "use this set of search engines")

  (search-engine-default "google" "Use google as default")
  (eww-search-prefix "https://google.com/search?q=" "Google prefix")
  (browse-url-secondary-browser-function 'browse-url-generic browse-url-generic-program "firefox" "Use firefox as secondary browser")
  :hook ((eww-mode . (lambda () (local-set-key (kbd "y Y") #'eww-copy-page-url)))))

9.16. Org Roam

For all my mathematics and programming notes:

(use-package org-roam
  :after (org)
  :custom
  (org-roam-db-update-on-save t "Update org-roam db")
  (org-roam-graph-viewer "firefox" "Use firefox to view org-roam graph")
  (org-roam-directory (file-truename "~/monorepo/mindmap") "Set org-roam directory inside monorepo")
  (org-roam-capture-templates '(("d" "default" plain "%?"
                                 :target (file+head "${title}.org"
                                                    "#+title: ${title}\n#+author: Preston Pan\n#+html_head: <link rel=\"stylesheet\" type=\"text/css\" href=\"../style.css\" />\n#+html_head: <script src=\"https://polyfill.io/v3/polyfill.min.js?features=es6\"></script>\n#+html_head: <script id=\"MathJax-script\" async src=\"https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js\"></script>\n#+options: broken-links:t")
                                 :unnarrowed t)) "org-roam files start with this snippet by default")
  :config (org-roam-db-autosync-mode))

(use-package org-roam-ui
  :after org-roam
  :hook (after-init . org-roam-ui-mode)
  :custom
  (org-roam-ui-sync-theme t "Use emacs theme for org-roam-ui")
  (org-roam-ui-follow t "Have cool visual while editing org-roam")
  (org-roam-ui-update-on-save t "This option is obvious")
  (org-roam-ui-open-on-start t "Have cool visual open in firefox when emacs loads"))

9.17. Pinentry

Set up pinentry so that I can use emacs as my pinentry frontend:

(use-package pinentry
  :custom (epa-pinentry-mode `loopback "Set this option to match gpg-agent.conf")
  :config (pinentry-start))

9.18. Email

Email in emacs can be done with Mu4e.

(use-package smtpmail
  :custom
  (user-mail-address system-email "Use our email")
  (user-full-name system-fullname "Use our full name")
  (sendmail-program "msmtp" "Use msmtp in order to send emails")
  (send-mail-function 'smtpmail-send-it "This is required for this to work")
  (message-sendmail-f-is-evil t "Use evil-mode for sendmail")
  (message-sendmail-extra-arguments '("--read-envelope-from") "idk what this does")
  (message-send-mail-function 'message-send-mail-with-sendmail "Use sendmail"))

(use-package mu4e
  :after smtpmail
  :custom
  (mu4e-drafts-folder "/Drafts" "Set drafts folder mu db")
  (mu4e-sent-folder   "/Sent" "Set sent folder in mu db")
  (mu4e-trash-folder  "/Trash" "Set trash folder in mu db")
  (mu4e-attachment-dir  "~/Downloads" "Set downloads folder for attachments")
  (mu4e-view-show-addresses 't "Show email addresses in main view")
  (mu4e-confirm-quit nil "Don't ask to quit")
  (message-kill-buffer-on-exit t "Kill buffer when I exit mu4e")
  (mu4e-compose-dont-reply-to-self t "Don't include self in replies")
  (mu4e-change-filenames-when-moving t)
  (mu4e-get-mail-command "mbsync ret2pop" "Use mbsync for imap")
  (mu4e-compose-reply-ignore-address (list "no-?reply" system-email) "ignore my own address and noreply")
  (mu4e-html2text-command "w3m -T text/html" "Use w3m to convert html to text")
  (mu4e-update-interval 300 "Update duration")
  (mu4e-headers-auto-update t "Auto-updates feed")
  (mu4e-view-show-images t "Shows images")
  (mu4e-compose-signature-auto-include nil)
  (mu4e-use-fancy-chars t "Random option to make mu4e look nicer"))

9.19. Music

Set up emms in order to play music from my music directory:

(use-package emms
  :custom
  (emms-source-file-default-directory (expand-file-name "~/music/") "Use directory specified in Nix")
  (emms-player-mpd-music-directory (expand-file-name "~/music/") "Use directory specified in Nix")
  (emms-player-mpd-server-name "localhost" "Connect to localhost")
  (emms-player-mpd-server-port "6600" "Connect to port 6600")
  (emms-player-list '(emms-player-mpd) "Use mpd")
  :init
  (emms-all)
  (add-to-list 'emms-info-functions 'emms-info-mpd)
  (add-to-list 'emms-player-list 'emms-player-mpd)
  :config (emms-player-mpd-connect))
Copyright © 2024 Preston Pan