Nathan’s DotEmacs

What I consider to be a fairly reasonable, modern emacs setup. The source files can be found here if you are viewing this from my website.

This config provides modal editing with emacs style keybindings, and uses straight.el for package management.

1 Bootstrap

Initialize emacs, set better defaults, and get it into a state where we can start installing packages

1.1 Bootstrap straight.el

Use this magic snippet to load in straight.el

(defvar bootstrap-version)
(let ((bootstrap-file
       (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
      (bootstrap-version 5))
  (unless (file-exists-p bootstrap-file)
    (with-current-buffer
        (url-retrieve-synchronously
         "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el"
         'silent 'inhibit-cookies)
      (goto-char (point-max))
      (eval-print-last-sexp)))
  (load bootstrap-file nil 'nomessage))

Setup the integration with use-package

(setq use-package-always-defer t
      use-package-always-ensure t
      straight-use-package-by-default t)

Setup a pinned profile

(setq straight-profiles
      '((nil . "default.el")
        ;; Packages which are pinned to a specific commit.
        (pinned . "pinned.el")))
(let ((straight-current-profile 'pinned))
  ;; Pin org-mode version.
  (add-to-list 'straight-x-pinned-packages
               '("polymode" . "44265e35161d77f6eaa09388ea2256b89bd5dcc8")))

1.2 Set fonts

Use Fira Code for monospace and Roboto for variable pitch. This is the non-macOS version.

(when (not (eq system-type 'darwin))
  ;; Fix issue with emacs-server
  (defun load-custom-fonts (frame) 
    (select-frame frame)
    (custom-theme-set-faces
     'user
     '(variable-pitch ((t
                        (:family "Roboto" :height 105))))
     '(default ((t
                 (:family "FiraCode" :width normal :height 90))))
     '(fixed-pitch ((t
                     (:family "FiraCode" :width normal :height 90))))))
  (add-hook 'after-make-frame-functions #'load-custom-fonts)
  (progn
    (custom-theme-set-faces
     'user
     '(variable-pitch ((t
                        (:family "Roboto" :height 105))))
     '(default ((t
                 (:family "FiraCode" :width normal :height 90))))
     '(fixed-pitch ((t
                     (:family "FiraCode" :width normal :height 90)))))))

Special version for macOS. Bigger fonts, because macOS.

(when (eq system-type 'darwin)
  ;; Fix issue with emacs-server
  (defun load-custom-fonts (frame)
    (select-frame frame)
    (custom-theme-set-faces
     'user
     '(variable-pitch ((t
                        (:family "Roboto" :height 140))))
     '(default ((t
                 (:family "Fira Code" :width normal :height 120))))
     '(fixed-pitch ((t
                     (:family "Fira Code" :width normal :height 120))))))
  (add-hook 'after-make-frame-functions #'load-custom-fonts)
  (custom-theme-set-faces
   'user
   '(variable-pitch ((t
                      (:family "Roboto" :height 140))))
   '(default ((t
               (:family "Fira Code" :width normal :height 120))))
   '(fixed-pitch ((t
                   (:family "Fira Code" :width normal :height 120))))))

FiraCode ligatures

Adds support for code ligatures, requires Fira Code Symbol font for this to work.

(use-package fira-code-mode
  :custom (fira-code-mode-disabled-ligatures '("x" "#["))
  :hook prog-mode)

1.3 Better Defaults

Don’t load xresources, it messes with our themes.

(setq inhibit-x-resources t)

Disable those pesky mousey things, keyboard4lyfe

(menu-bar-mode -1)
(tool-bar-mode -1)
(scroll-bar-mode -1)
(setq inhibit-startup-message t)
(setq initial-scratch-message nil)

Enable UTF-8 everywhere

(setq locale-coding-system 'utf-8)
(set-terminal-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)
(set-selection-coding-system 'utf-8-unix)
(prefer-coding-system 'utf-8-unix)
(when (display-graphic-p)
  (setq x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING)))
(setq-default buffer-file-coding-system 'utf-8-unix)

Turn off the annoying beeps and flash the mode line instead

(setq visible-bell nil
      ring-bell-function 'flash-mode-line)
(defun flash-mode-line ()
  (invert-face 'mode-line)
  (run-with-timer 0.1 nil #'invert-face 'mode-line))

Set the cursor to a bar

(setq-default cursor-type 'bar)
(set-cursor-color "#ffffff")

Other more reasonable defaults

(setq-default
 cursor-in-non-selected-windows nil          ; Don't show the cursor in non-selected windows
 fill-column 100                             ; Set width for automatic line breaks
 indent-tabs-mode nil                        ; Don't use tabs for indentation
 initial-scratch-message ""                  ; Empty scratch buffer
 select-enable-clipboard t                   ; Merge kill ring and system keyboard
 sentence-end-double-space nil               ; End sentence after a dot and a space
 )

(cd "~/")             ; Move to the homedir
(display-time-mode 1) ; Display the Clock in the mode line
(fringe-mode 0)       ; Disable fringes

Garbage collect on focus out. May be placebo, but will help emacs feel faster

(add-hook 'focus-out-hook #'garbage-collect)

Additional, increase the gc threshold

(setq gc-cons-threshold 100000000)

Replace yes or no questions with y or n

(fset 'yes-or-no-p 'y-or-n-p)

Use ibuffer instead of the default list for C-x C-b

(defalias 'list-buffers 'ibuffer)

Make the focus follow the mouse

;;(setq mouse-autoselect-window t
;;      focus-follows-mouse t)

Increase the default ammount that emacs will read from a process. Improves LSP-mode

(setq read-process-output-max (* 1024 1024))

1.4 Machine specific settings

Set up an a-list for machine specific settings based on the host name

(setq nm/settings-alist
      (cond ((string= (system-name) "9020-arch.mccarty.io")
             '((:org-dir . "~/Org/")
               (:custom-file . "custom/custom-9020-arch.el")
               (:mail-dir . "~/.mail/")))
            ((string= system-type "windows-nt")
             `((:org-dir . ,(concat "C:/Users/" user-login-name "/Documents/Org/"))
               (:custom-file . "custom/custom-windows-default.el")
               (:mail-dir . nil)))
            ((string= (system-name) "Macbook-Pro.local")
             '((:org-dir . "~/Org/")
               (:custom-file . "custom/custom-Macbook.el")
               (:mail-dir . "~/.mail/")))
            (t
             '((:org-dir . "~/Org/")
               (:custom-file . "custom/custom-default.el")
               (:mail-dir . "~/.mail/")))))

(setq nm/backup-dir (concat user-emacs-directory "backups/"))
(setq nm/autosave-dir (concat user-emacs-directory "autosaves/"))

Set the org directory to the one defined in the map

(setq org-directory
      (expand-file-name (alist-get :org-dir nm/settings-alist)))

1.5 Load Custom.el

Set the custom file to the one specified in the machine-specific settings alist

(setq-default custom-file
              (expand-file-name
               (concat user-emacs-directory
                       (alist-get :custom-file nm/settings-alist))))
(when (file-exists-p custom-file)
  (load custom-file))

1.6 Theme

Load up solarized dark

(use-package solarized-theme
  :demand t
  :config
  (load-theme 'solarized-dark t))

1.7 Backup and Autosave configuration

Put the backups and autosaves in a sane location, defined by the machine specific settings alist, but most likely inside the user emacs directory.

(make-directory nm/backup-dir t)
(setq backup-directory-alist
      `((".*" . ,nm/backup-dir)))
(make-directory nm/autosave-dir t)
(setq auto-save-file-name-transforms
      `((".*" ,nm/autosave-dir t)))
(setq backup-by-copying t)

1.8 OS Specific Compat

Win32

Various compatibility settings with win32

Stops passing the windows key and sets the app key to hyper

(when
    (string-equal system-type "windows-nt")
  (w32-register-hot-key [M-tab])
  (setq w32-pass-lwindow-to-system nil)
  (setq w32-pass-apps-to-system nil)
  (setq w32-lwindow-modifier 'super) ; Left Windows key
  (setq w32-apps-modifier 'hyper) ; Right windows key as hyper
  (w32-register-hot-key [s-])
  (w32-register-hot-key [H-])
  (setq inhibit-compacting-font-caches t))

Add msys2 to exec path

(when
    (string-equal system-type "windows-nt")
  (add-to-list 'exec-path "c:/msys64/usr/bin/"))

Add hunspell to exec path

(when
    (string-equal system-type "windows-nt")
  (add-to-list 'exec-path "c:/msys64/mingw64/bin/"))

Add pandoc to path

(when (string-equal system-type "windows-nt")
  (add-to-list 'exec-path "C:\\Program Files\\Pandoc"))

Add python to the exec-path, mostly for ox-clip

;; Cross platform clipboard copying for org-mode
(when (string-equal system-type "windows-nt")
  (add-to-list 'exec-path (concat  "C:\\Users\\" user-login-name "\\AppData\\Local\\Programs\\Python\\Python37-32")))

MacOS

Make the fn key do hyper

(when (eq system-type 'darwin)
  (setq ns-function-modifier 'hyper))

1.9 Strip unused key bindings

Free up unused and unnecessary keybindings

Digit arguments

These are made redundant by the universal argument

(dotimes (n 10)
  (global-unset-key (kbd (format "C-%d" n)))
  (global-unset-key (kbd (format "M-%d" n))))

1.10 Uniquify Forward

Change uniquify to put the disambiguating part of the file name at the front

(require 'uniquify)
(setq uniquify-buffer-name-style 'forward)

1.11 Bindkeys

Better key-binding framework

(require 'bind-key)

1.12 Winner Mode

Allows undoing and redoing changes in window configuration

(winner-mode 1)

2 General Dependencies

Dependencies used by a lot of other packages

(use-package helm)
(use-package dash)
(use-package f)
(use-package s)
(use-package edit-indirect)
(use-package async)
(use-package pcre2el)
(use-package polymode)

3 General Editing

3.1 Interface Enhancement

Diminish

Hide modes from the modeline

(use-package diminish
  :demand t)

Minibuffer completion

Ivy

The core of mini-buffer completion

(use-package ivy
  :demand t
  :diminish
  :config
  (ivy-mode 1)
  :bind
  ("C-c C-r" . ivy-resume))
(use-package counsel
  :demand t
  :diminish
  :bind
  ("C-x C-f" . counsel-find-file))
(use-package swiper
  :demand t
  :diminish
  :bind
  ("C-s" . swiper))
Amx

A modern replacement for smex

(use-package amx
  :demand t
  :bind
  ("M-x" . amx))

Smooth Scrolling

(use-package smooth-scrolling
  :demand t)

Perspectives

Perspective provides workspaces for emacs

(use-package perspective
  :demand t
  :init
  (setq persp-mode-prefix-key (kbd "H-p"))
  :config
  (persp-mode))

Modal Editing

God Mode
(use-package god-mode
  :ensure t
  :demand t
  :bind
  ("s-SPC" . 'god-mode-all)
  ("<escape>" . 'god-mode-all)
  (:map god-local-mode-map
        ("'" . 'repeat)
        ("i" . 'god-mode-all))
  :config
  (defun c/god-mode-update-cursor ()
    (let ((limited-colors-p (> 257 (length (defined-colors)))))
      (cond (god-local-mode (progn
                              (set-face-background 'mode-line (if limited-colors-p "white" "#e9e2cb"))
                              (set-face-background 'mode-line-inactive (if limited-colors-p "white" "#e9e2cb"))))
            (t (progn
                 (set-face-background 'mode-line (if limited-colors-p "black" "#0a2832"))
                 (set-face-background 'mode-line-inactive (if limited-colors-p "black" "#0a2832")))))))
  (add-hook 'god-mode-enabled-hook 'c/god-mode-update-cursor)
  (add-hook 'god-mode-disabled-hook 'c/god-mode-update-cursor))
TODO ryo-modal

3.2 General editing improvements

Minor modes that provide improvements across a number of major modes

All the icons

Provides all the icons, used for doom-modeline and neotree

(use-package all-the-icons)

Colorful

Modes that add more color

Rainbow Delimiters

Makes matching delimiter pairs the same color Not 100% sure why, but this likes to misbehave without the explicit hook.

(use-package rainbow-delimiters
  :diminish
  :demand t
  :config 
  (add-hook 'prog-mode-hook #'rainbow-delimiters-mode))
Color Identifiers

Gives each identifier its own color.

(use-package color-identifiers-mode
  :demand t
  :diminish
  :config
  (add-hook 'after-init-hook 'global-color-identifiers-mode))

Navigation

Avy

Jump to characters, words, and lines with minimal key strokes

(use-package avy
  :demand t
  :config
  (avy-setup-default)
  :bind
  (("H-a w" . avy-goto-word-1)
   ("H-a c" . avy-goto-char)
   ("H-a v" . avy-goto-char-2)
   ("H-a l" . avy-goto-line))) 
Ace Window

Like avy, but for windows/frames

(use-package ace-window
  :bind (("H-s" . 'ace-window))
  :config
  (setq aw-dispatch-always t))
Neotree

File tree browser

(use-package neotree
  :bind ("H-t" . neotree-toggle)
  :config
  (setq neo-theme 'icons
        neo-smart-open t))

VLF

Deals with very large files

(use-package vlf
  :demand t
  :config
  (require 'vlf-setup))

Multiple Cursors

(use-package multiple-cursors
  :bind
  (("H-h" . mc/edit-lines)
   ("H-." . mc/mark-next-like-this-word)
   ("H-," . mc/mark-previous-like-this-word)
   ("H-/" . mc/mark-next-like-this))
  :config
  (define-key mc/keymap (kbd "<return>") nil)
  (global-unset-key (kbd "M-<down-mouse-1>"))
  (global-set-key (kbd "M-<mouse-1>") 'mc/add-cursor-on-click))

doom-modeline

(use-package doom-modeline
  :init (doom-modeline-mode 1)
  :config
  (setq doom-modeline-height 30
        doom-modeline-window-width-limit 100
        doom-modeline-buffer-file-name-style 'truncate-upto-root
        doom-modeline-icon t
        doom-modeline-major-mode-icon t)
  (column-number-mode t))

ISpell/Flyspell

Use hunspell for spelling, with special handling for windows, and require the ispell package

(if (string-equal system-type "windows-nt")
    (setq ispell-program-name (concat  "C:/Users/" user-login-name "/hunspell/bin/hunspell.exe"))
  (setq ispell-program-name "hunspell"))

(require 'ispell)

Enable spell checking in source code comments

(add-hook 'prog-mode-hook
          (lambda ()
            (flyspell-prog-mode)))

3.3 TRAMP

Make tramp use ssh instead of scp by default

(setq tramp-default-method "ssh")

4 org-mode

Org mode is special enough for its own top level section

4.1 Set Defaults

Define diary and notes files

Set the diary file to ~/Org/diary.org and create a default notes file at ~/Org/codex.org for quick captures.

(setq org-agenda-diary-file (concat org-directory "diary.org"))
(setq org-default-notes-file (concat org-directory "codex.org"))

Beautification

Hide leading stars, disable odd-levels only, and set default todo sequence
(setq org-hide-leading-stars t)
(setq org-odd-levels-only 'nil)
(setq org-todo-keywords
      '((sequence "TODO"
                  "FEEDBACK"
                  "WORKING"
                  "PENDING" "|"
                  "DIFFERED"
                  "DELEGATED"
                  "DONE")))
Hide emphasis markers, turn on indenting, and show entities as utf-8
(setq org-hide-emphasis-markers t)
;; Rectify an issue with org-polymode by disabling this
;; (setq org-startup-indented t)
(setq org-startup-indented nil)
(setq org-pretty-entities t)
Enable variable pitch and visual line mode
(add-hook 'org-mode-hook #'variable-pitch-mode)
(add-hook 'org-mode-hook #'visual-line-mode)

Enable Flyspell

(add-hook 'org-mode-hook 'flyspell-mode)

4.2 Keybinds

Add keybinds on H-o. prefix

(bind-keys :prefix-map nm/org-prefix
           :prefix "H-c"
           ("c" . org-capture)
           ("i" . org-insert-subheading)
           ("a" . org-agenda))

4.3 Fonts

Set the main font to the variable pitch one, and set whats needed back to monospace. This configuration still has a little bit of issues with indention of list items, but its acceptable.

(set-face-attribute 'org-table nil :inherit 'fixed-pitch)
(set-face-attribute 'org-hide nil :inherit 'fixed-pitch :height 90)


;; Org mode variable-pitch font
(custom-theme-set-faces
 'user
 '(org-block                 ((t (:inherit fixed-pitch))))
 '(org-document-info-keyword ((t (:inherit (shadow fixed-pitch)))))
 '(org-property-value        ((t (:inherit fixed-pitch))) t)
 '(org-special-keyword       ((t (:inherit (font-lock-comment-face fixed-pitch)))))
 '(org-tag                   ((t (:inherit (shadow fixed-pitch) :weight bold))))
 '(org-verbatim              ((t (:inherit (shadow fixed-pitch)))))
 '(org-table                 ((t (:inherit (shadow fixed-pitch)))))
 '(org-hide                  ((t (:inherit (shadow fixed-pitch)))))
 '(org-code                  ((t (:inherit (shadow fixed-pitch))))))

Setup font-lock for list items

Create font lock entries to make *, -, and + list entries a bit more pretty

;; Pretty lists
(font-lock-add-keywords 'org-mode
                        '(("^ +\\([*]\\) "
                           0 (prog1 () (compose-region (match-beginning 1) (match-end 1) "★")))
                          ("^ +\\([-]\\) "
                           0 (prog1 () (compose-region (match-beginning 1) (match-end 1) "•")))
                          ("^ +\\([+]\\) "
                           0 (prog1 () (compose-region (match-beginning 1) (match-end 1) "‣")))))

4.4 Polymode for org

(use-package poly-org
  :demand t)

4.5 Extensions

Packages that extend the functionality of org-mode

Currently using:

  • ox-pandoc : Pandoc support, export to MANY formats
  • org-wc: Word count for subtrees
  • ox-clip: Exporting to formatted clipboard text
  • org-sidebar: Show structure of org document in a sidebar
  • org-bullets: Pretty unicode rendering of the bullet points in the outline
  • helm-org-rifle: Basically google for org-mode
  • org-chef: Recipes for org-mode, supports pulling from various websites
  • ox-gfm Allows exporting to github flavored mark down

    (use-package ox-pandoc
      :demand t)
    (use-package org-wc
      :demand t)
    (use-package ox-clip
      :demand t)
    ;; Dependency for org-sidebar
    (use-package org-ql
      :demand t)
    (use-package org-sidebar
      :demand t)
    (use-package org-bullets
      :diminish
      :hook (org-mode . org-bullets-mode))
    (use-package helm-org-rifle
      :demand t
      :bind (("H-o d" . helm-org-rifle-org-directory)
             ("H-o r" . helm-org-rifle)))
    (use-package org-chef
      :demand t)
    (use-package ox-gfm
      :demand t)
    

4.6 Capture templates

Initialize the variable

(setq org-capture-templates '())

Recipe templates

Template for both manual recipe entry as well as captured from website

(add-to-list 'org-capture-templates
             '("c" "Cookbook" entry (file (concat (alist-get :org-dir nm/settings-alist) "cookbook.org"))
               "%(org-chef-get-recipe-from-url)"
               :empty-lines 1))
(add-to-list 'org-capture-templates
             '("m" "Manual Cookbook" entry (file (concat (alist-get :org-dir nm/settings-alist) "cookbook.org"))
               "* %^{Recipe title: }\n  :PROPERTIES:\n  :source-url:\n  :servings:\n  :prep-time:\n  :cook-time:\n  :ready-in:\n  :END:\n** Ingredients\n   %?\n** Directions\n\n"))
(add-to-list 'org-capture-templates
             `("e" "Email" entry (file+headline,(concat (alist-get :org-dir nm/settings-alist) "emails.org") "Todo")
               "* TODO %a %?\n"))

4.7 Agenda

Set the timespan shown by the agenda to, by default, show yesterday, today, and 6 days into the future.

(setq org-agenda-start-day "-1d")
(setq org-agenda-span 8)
(setq org-agenda-start-on-weekday nil)

Make the agenda include all todos as well as the diary, as well as hiding completed items.

(setq org-agenda-include-all-todo t)
(setq org-agenda-include-diary t)

;; Don't include done items in agenda view
(setq org-agenda-skip-timestamp-if-done t)
(setq org-agenda-skip-deadline-if-done t)
(setq org-agenda-skip-scheduled-if-done t)

Define the sort order in the agenda so that items get sorted by todo-state.

(setq org-agenda-sorting-strategy
      '(time-up timestamp-up todo-state-up priority-down))

Make the agenda open in the current window instead of a new one

(setq org-agenda-window-setup 'current-window)

Add the org directory to the agenda files I use syncthing for my org-dir, so I’ve got to pull a little bit of nonsense to exclude the syncthing folders.

(setq org-agenda-files
      (seq-filter (lambda (x) (not (or
                                    (s-contains? ".stfolder" x)
                                    (s-contains? ".stversions" x)
                                    (s-contains? "#" x))))
                  (directory-files-recursively
                   (alist-get :org-dir nm/settings-alist)
                   "\.org$")))

4.8 Other Functionality

Auto Update Agenda buffer

When an org-agenda buffer exists, automatically update it when emacs has been idle for 10 seconds, and update it every 5 minutes regardless of idle time.

(defun org-agenda-redo-other-window ()
  "Call Org-Agenda-Redo from another buffer"
  (interactive)
  (let ((agenda-window (get-buffer-window "*Org Agenda*" t)))
    (when agenda-window
      (with-selected-window agenda-window (org-agenda-redo)))))
(setq agenda-timer-idle (run-with-idle-timer 10 t 'org-agenda-redo-other-window))
(setq agenda-timer (run-at-time 0 360 'org-agenda-redo-other-window))

Highlight source code in pdf output

Use minted to highlight sourcecode in latex/pdf exports.

(require 'ox-latex)
(add-to-list 'org-latex-packages-alist '("" "minted"))
(setq org-latex-listings 'minted)

(setq org-latex-pdf-process
      '("pdflatex -shell-escape -interaction nonstopmode -output-directory %o %f"
        "pdflatex -shell-escape -interaction nonstopmode -output-directory %o %f"
        "pdflatex -shell-escape -interaction nonstopmode -output-directory %o %f"))

Workflow state tracking

Make org todo state tracking log into the LOGBOOK drawer.

(setq org-log-into-drawer "LOGBOOK")

Add book-no parts

Adds a latex class that has a book with no parts, only chapters. Top level headlines will form the chapters of the book, when exported.

(add-to-list 'org-latex-classes
           '("book-noparts"
              "\\documentclass{book}"
              ("\\chapter{%s}" . "\\chapter*{%s}")
              ("\\section{%s}" . "\\section*{%s}")
              ("\\subsection{%s}" . "\\subsection*{%s}")
              ("\\subsubsection{%s}" . "\\subsubsection*{%s}")
              ("\\paragraph{%s}" . "\\paragraph*{%s}")
              ("\\subparagraph{%s}" . "\\subparagraph*{%s}")))

Restore window layout when exiting org-src

This will use winner mode’s (enabled in the bootstrap section) undo functionality to restore the window layout after editing in an org-src buffer.

This used to be built into org-mode, but is quite annoyingly missing from current releases, so we have to add it back ourselves so that editing and org-src buffer doesn’t ruin our layout.

(defadvice org-edit-src-exit (after restore-window-config activate)
  (winner-undo))

Contacts

Use org-contacts to keep track of our contacts

(require 'org-contacts)
(setq org-contacts-files `(,(concat (alist-get :org-dir nm/settings-alist) "contacts.org")))

5 Magit

Another gem of emacs worthy of its own section. Provides an interface for git almost as good as git itself

(use-package magit
  :config
  (add-hook 'git-commit-setup-hook 'flyspell-mode))

Forge for extra goodness, allows interacting with issues and pull requests from within emacs.

(use-package forge
  :after magit)

5.1 git-timemachine

Allows browsing previous versions of a git controlled file. Not strictly a magit package, but it does integrate and generally gets a pass

(use-package git-timemachine)

6 Programming

Packages implementing support and features for various programming languages

6.1 General

Flycheck

Provides on-the-fly syntax checking and compiler errors for many languages

(use-package flycheck
  :hook (prog-mode . flycheck-mode)
  :config (diminish 'flycheck-mode))

Company

Completion framework for many lanaguages

(use-package company
  :hook (prog-mode . company-mode)
  :diminish)

LSP mode

General support for the language server protocol

(use-package lsp-mode
  :commands lsp
  :init
  (setq lsp-keymap-prefix "H-v")
  :diminish
  :config
  (setq lsp-auto-configure t))

(use-package lsp-ui
  :diminish lsp-ui-mode
  :config
  (setq lsp-ui-flycheck-enable t)
  (setq lsp-ui-doc-use-webkit t)
  (add-to-list 'lsp-ui-doc-frame-parameters '(no-accept-focus . t))
  (define-key lsp-ui-mode-map [remap xref-find-definitions] #'lsp-ui-peek-find-definitions)
  (define-key lsp-ui-mode-map [remap xref-find-references] #'lsp-ui-peek-find-references))

YASippet

A template system for emacs

(use-package yasnippet
  :demand t
  :config
  (yas-global-mode 1))

Also bring in this useful collection of predefined snippets

(use-package yasnippet-snippets
  :demand t
  :config
  (add-to-list 'yas-snippet-dirs
               "~/.emacs.d/snippets/")
  (yas-reload-all))

Smartparens

Ensures that delimiters always match

(use-package smartparens
  :demand t
  :init
  (require 'smartparens-config)
  :hook (prog-mode . smartparens-mode))

Indent Guide

Show those indent levels

(use-package highlight-indent-guides
  :hook (prog-mode . highlight-indent-guides-mode)
  :config
  (setq highlight-indent-guides-method 'bitmap))

Projectile

(use-package projectile
  :ensure t
  :demand t)

6.2 Languages

Lisp

The basis of editing any good lisp dialect is paredit, providing pseudo-structural editing

(use-package paredit
  :ensure t
  :demand t
  :config
  (autoload 'enable-paredit-mode "paredit" "Turn on pseudo-structural editing of Lisp code." t)
  (add-hook 'emacs-lisp-mode-hook       #'enable-paredit-mode)
  (add-hook 'eval-expression-minibuffer-setup-hook #'enable-paredit-mode)
  (add-hook 'ielm-mode-hook             #'enable-paredit-mode)
  (add-hook 'lisp-mode-hook             #'enable-paredit-mode)
  (add-hook 'lisp-interaction-mode-hook #'enable-paredit-mode)
  (add-hook 'scheme-mode-hook           #'enable-paredit-mode))

Rust

Load in toml mode, mostly for Cargo.toml

(use-package toml-mode)

Use rustic with rust-analyzer instead of rls. rust-analyzer seems to be a bit faster than rls, and has generally better features. Rustic also has generally better features than the normal rust-mode, but has a couple of minor annoyances. Using the 2018 edition of rust requires a rustfmt.toml in the project root.

(require 'lsp-rust) ;; Workaround for upstream bug
(use-package rustic
  :config
  (setq rustic-lsp-server 'rust-analyzer)
  (setq lsp-rust-analyzer-server-command '("~/.cargo/bin/rust-analyzer"))
  (setq rustic-format-trigger 'on-save)
  (setq rustic-format-display-method #'ignore)
  :hook
  (rustic-mode . hs-minor-mode))

C/C++

Load in the ccls client

(use-package ccls
  :hook ((c-mode c++-mode objc-mode cuda-mode) .
         (lambda () (require 'ccls) (lsp))))

NASM

(use-package nasm-mode
  :ensure t
  :demand t
  :config
  (add-to-list 'auto-mode-alist '("\\.nasm\\'" . nasm-mode)))

AutoHotKey

Support for the AutoHotKey automation language for windows

(use-package ahk-mode)

Python

Elpy forms the base of the python dev environment, providing most of the features

(use-package elpy
  :init
  (elpy-enable)
  :hook
  (elpy-mode . flycheck-mode)
  (elpy-mode . (lambda ()
                 (setq left-fringe-width 7))))

autopep8 provides autoformatting according to PEP8

(use-package py-autopep8
  :hook
  (elpy-mode . py-autopep8-enable-on-save))

Haskell

Install haskell-mode for the basics, and setup ghc-mod integration

(use-package haskell-mode
  :ensure t)

Setup intero for interactivity

(use-package intero
  :ensure t
  :hook
  (haskell-mode))

TypeScript

Pull in and configure tide

(use-package tide
  :config
  (defun setup-tide-mode ()
    (interactive)
    (tide-setup)
    (flycheck-mode 1)
    (setq flycheck-check-syntax-automatically '(save-mode-enabled))
    (eldoc-mode 1)
    (tide-hl-identifier-mode 1)
    (company-mode 1))
  (setq company-tooltip-align-annotations t)
  (add-hook 'before-save-hook 'tide-format-before-save)
  (add-hook 'typescript-mode-hook #'setup-tide-mode))

YAML

YAML is a configuration file format used by a lot of things, particularly minecraft server plugins.

(use-package yaml-mode)

Dockerfile

Syntax highlighting for dockerfiles.

(use-package dockerfile-mode)

Markup Languages

Markdown

Bring in the actual markdown mode

(use-package markdown-mode
  :commands (markdown-mode gfm-mode)
  :mode (("README\\.md\\'" . gfm-mode)
         ("\\.md\\'" . gfm-mode)
         ("\\.markdown\\'" . markdown-mode))
  :init (setq markdown-command "multimarkdown")
  :demand t
  :hook
  (markdown-mode . flyspell-mode)
  (markdown-mode . auto-fill-mode)
  (markdown-mode . (lambda ()
                     (set-fill-column 80))))

Also bring in markdownfmt for nice formatting

(use-package markdownfmt
  :config
  (define-key markdown-mode-map (kbd "C-c C-f") #'markdownfmt-format-buffer)
  (add-hook 'markdown-mode-hook #'markdownfmt-enable-on-save))

Enable the poly-mode for markdown

(use-package poly-markdown
  :demand t)
Latex

AUCTeX is a bit wonky with the loading, so we have to do this

(use-package tex-mode
  :ensure auctex
  :config
  (setq-default TeX-engine 'xetex)
  (setq-default TeX-PDF-mode t)
  (setq-default TeX-interactive-mode nil))

Load up latex preview pane

(use-package latex-preview-pane
  :config
  (setq pdf-latex-command "xelatex"))

Kerboscript

Syntax highlighting and auto-indentation for the kOS scripting language for kerbal space program.

(use-package ks
  :straight (ks :type git :host github :repo "jarpy/ks-mode")
  :config
  (setq ks-indent 4))

7 /etc/Modes

Modes not strictly related to programming, but have more general use

7.1 Ediff

Load in ediff for file and git diffs, set it to use winner’s undo to restore the window layout afterwards.

(use-package ediff
   :init
  (add-hook 'ediff-after-quit-hook-internal 'winner-undo)
  :config
  (setq ediff-window-setup-function 'ediff-setup-windows-plain
        ediff-split-window-function 'split-window-horizontally))

7.2 Restclient

Like postman, but better

(use-package restclient)

7.3 Setup multi-term

Multi Term provides a much better experience for dealing with multiple open terminals then the default emacs ansi-term.

(use-package multi-term
  :demand t
  :config
  (setq multi-term-program "/usr/bin/fish"))

Setup a send raw keybind so we can send ctrl-x and the like

(define-key term-raw-map [?\C-x] 'term-send-raw)

7.4 Tab Bar Mode

First, turn on global tab line mode

(global-tab-line-mode)

Set Alt-j and Alt-k to change tabs Should change this to use the hyper key when i get that setup on linux

(bind-key* "M-j" 'tab-line-switch-to-prev-tab)
(bind-key* "M-k" 'tab-line-switch-to-next-tab)

7.5 Discord integration (lol)

Pull in elcord and enable it for discord integration

(use-package elcord)

7.6 PDF Tools

One of the best PDF viewers I have encountered

(use-package pdf-tools
  :config
  (pdf-tools-install))

7.7 Discover my major

Provides additional discover ability for the functionalities in each major mode

(use-package discover-my-major
  :bind ("C-h C-m" . discover-my-major))

7.8 Comment-edit

An org-src style for editing comments in source code

(use-package separedit
  :bind
  (:map prog-mode-map
        ("C-c '" . separedit))
  :config
  (setq separedit-default-mode 'gfm-mode))

7.9 Deadgrep

(use-package deadgrep
  :bind ("H-r" . deadgrep))

7.10 hl-todo

Highlights TODOs in comments

(use-package hl-todo
  :demand t)
(global-hl-todo-mode)

Enable the magit extension

(use-package magit-todos
     :config
  (magit-todos-mode))