Nathan’s DotEmacs

My literate emacs config

This is what I consider to be a pretty reasonable setup. The source files can be found here if you are viewing this from my website.

1 Bootstrap

1.1 Set fonts

Use hack for mono space and roboto for variable pitch

;; Pretty font

;; 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 "Hack" :width normal :height 90))))
   '(fixed-pitch ((t
                   (:family "Hack" :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 "Hack" :width normal :height 90))))
   '(fixed-pitch ((t
                   (:family "Hack" :width normal :height 90))))))
; (setq default-frame-alist '((font . "Hack-9")))




1.2 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.3 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)))
            (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.4 Load Custom.el

(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.5 Theme

I like solarized dark

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

1.6 Backup and Autosave configuration

Place all the backups and autosaves in the emacs directory to stop emacs from littering the filesystem.

(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.7 Win32 compat

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")))

1.8 Strip unused keys

Free some keys back up from emacs

Unset digit arguments

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

1.9 Auto update packages

Use auto-update-packages to update packages automatically every 4 days

(use-package auto-package-update
  :ensure t
  :demand t
  :config
  (setq auto-package-update-delete-old-versions t
        auto-package-update-interval 4)
  (auto-package-update-maybe))

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 Load up bindkeys

This allows better key-binding, especially the creation of prefix keys.

(require 'bind-key)

1.12 Enable winner mode

Most importantly this allows window layout undoing.

(winner-mode 1)

2 General Editing

Things here are useful across all or many mode

2.1 Interface Enhancement

Smex for better M-x autocompletion. This should probably be swapped out for something more modern at some point.

(use-package smex
  :ensure t
  :demand t
  :bind
  ("M-x" . 'smex)
  ("M-X" . 'smex-major-mode-commands)
  ("C-c C-c M-x" . 'execute-extended-command))

Power line and diminish to make the mode line better

;; (use-package powerline
;;   :ensure t
;;   :demand t
;;   :config
;;   (powerline-default-theme))

(use-package diminish
  :ensure t
  :demand t
  :config
  (diminish 'auto-revert-mode))

Smooth scroll

(use-package smooth-scrolling
  :ensure t
  :demand t)

Virtual Workspaces bound to the M-Digit keys. Plays nicely with tab-line-mode for multitasking.

(use-package eyebrowse
  :ensure t
  :demand t
  :diminish eyebrowse-mode
  :config (progn
            (define-key eyebrowse-mode-map (kbd "M-1") 'eyebrowse-switch-to-window-config-1)
            (define-key eyebrowse-mode-map (kbd "M-2") 'eyebrowse-switch-to-window-config-2)
            (define-key eyebrowse-mode-map (kbd "M-3") 'eyebrowse-switch-to-window-config-3)
            (define-key eyebrowse-mode-map (kbd "M-4") 'eyebrowse-switch-to-window-config-4)
            (define-key eyebrowse-mode-map (kbd "M-5") 'eyebrowse-switch-to-window-config-5)
            (define-key eyebrowse-mode-map (kbd "M-6") 'eyebrowse-switch-to-window-config-6)
            (define-key eyebrowse-mode-map (kbd "M-7") 'eyebrowse-switch-to-window-config-7)
            (define-key eyebrowse-mode-map (kbd "M-8") 'eyebrowse-switch-to-window-config-8)
            (define-key eyebrowse-mode-map (kbd "M-9") 'eyebrowse-switch-to-window-config-9)
            (eyebrowse-mode t)
            (setq eyebrowse-new-workspace t)))

Turn on line numbers in the margin in programming modes

(add-hook 'prog-mode-hook 'display-line-numbers-mode)

2.2 God mode

Modal editing with emacs keybindings

Binds ’ to repeat and i to god-mode-all (has the effect of leaving god mode).

Note: The god-mode repo has been archived, this should be replaced with ryo-modal, which is currently maintained and provides additional support for custom keymaps.

(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))

2.3 General dependencies

Packages that other packages depend on, but are not really used directly. These are really just included to make sure other packages load properly with the lazy loading.

(use-package helm
  :ensure t)
(use-package dash
  :ensure t)
(use-package f
  :ensure t)
(use-package s
  :ensure t)
(use-package edit-indirect
  :ensure t)
(use-package async
  :ensure)
(use-package pcre2el
  :ensure)

2.4 General editing improvements

Modes that provide editing engagements across a large range of modes

Rainbow Delimiters

Makes matching pairs of delimiters, like parens or brackets, light up in pretty rainbow colors.

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

Avy

Adds the ability to jump to charaters, words, and lines with minimal keystrokes.

;; Avy, replaces ace-jump-mode
(use-package avy
  :ensure t
  :demand t
  :config
  (avy-setup-default)
  (global-set-key (kbd "H-j") 'avy-goto-word-1)
  (global-set-key (kbd "H-k") 'avy-goto-char)
  (global-set-key (kbd "H-l") 'avy-goto-char-2)
  (global-set-key (kbd "H-;") 'avy-goto-line))

Ace Window

Like avy, but for jumping between windows

(use-package ace-window
  :ensure t
  :demand t
  :bind (("H-h" . 'ace-window))
  :config
  (setq aw-dispatch-always t))

Color Identifiers

Makes the identifiers used in programming language modes light up in different colors to ease visual identification.

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

VLF

Deals with Very Large Files. ’nuff said

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

Ispell

I have ispell setup with hunspell, with some compat for running on windows.

(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)

Dimmer

Highlight active buffer by dimming the others

(use-package dimmer
  :ensure t
  :demand t
  :config
  (dimmer-mode))

Neotree

Powerful filesystem tree mode for emacs Enable it, turn on smart-open to jump to the buffer if the file is already open. Also switch the theme to icons if we are in graphical mod. Additionally, require all-the-icons beforehand, for icon support

(use-package all-the-icons
  :ensure t)

(use-package neotree
  :ensure t
  :config
  (setq neo-smart-open t)
  (setq neo-theme (if (display-graphic-p) 'icons 'arrow)))

Multiple cursors

(use-package multiple-cursors
  :ensure t
  :bind
  ("H-n" . mc/edit-lines)
  ("H-." . mc/mark-next-like-this-word)
  ("H-," . mc/mark-previous-like-this-word)
  ("H-m" . 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-moedeline

(use-package doom-modeline
  :ensure t
  :init (doom-modeline-mode 1)
  :config
  (setq doom-modeline-icon (display-graphic-p))
  (setq doom-modeline-major-mode-color-icon t)
  (setq doom-modeline-minor-modes nil))

Emojify

Displays emojis and other unicode bits as colored images

(use-package emojify
  :ensure t
  :demand t
  :config
  (add-hook 'after-init-hook #'global-emojify-mode))

Flyspell in code comments

Hook flyspell-prog-mode into prog-mode for spell checking in source code comments

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

2.5 TRAMP

Make tramp use the ssh backend rather than scp by default

(setq tramp-default-method "ssh")

2.6 Other minor modes

Modes that are useful but don’t directly have to do with editing

Symon

A system monitor at the bottom of emacs

;; (use-package symon
;;   :ensure t
;;   :demand t
;;   :config
;;   (symon-mode))                         

3 Org-mode

Org mode is special and gets its own section

3.1 Set Defaults and enable Flyspell Mode

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"))

Ascetic preferences.

Hides leading stars, disables odd-levels only, sets the 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)
(setq org-startup-indented t)
(setq org-pretty-entities t)

Turn on variable pitch mode and visual line mode

(add-hook 'org-mode-hook #'variable-pitch-mode)
(add-hook 'org-mode-hook #'visual-line-mode)

Enable flyspell in org mode buffers

Spell checking is nice

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

3.2 Keybinds

Insert subheading and capture keybinds

(global-set-key (kbd "H-'") 'org-insert-subheading)
(global-set-key (kbd "H-o") 'org-capture)

Insert an inactive timestamp with the current time

;; Bind a key for inserting current time
(defun my/timenow ()
  (interactive)
  (org-time-stamp '(16) t))
(global-set-key (kbd "H-i") 'my/timenow)

Open the agenda

(global-set-key (kbd "C-c a") 'org-agenda)

3.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))))))

Special font lock for list

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) "‣")))))

3.4 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
      :ensure t
      :demand t)
    (use-package org-wc
      :ensure t
      :demand t)
    (use-package ox-clip
      :ensure t
      :demand t)
    ;; Dependency for org-sidebar
    (use-package org-ql
      :ensure t
      :demand t)
    (use-package org-sidebar
      :ensure t
      :demand t)
    (use-package org-bullets
      :ensure t
      :demand t
      :diminish
      :hook (org-mode . org-bullets-mode))
    (use-package helm-org-rifle
      :ensure t
      :demand t
      :bind (("H-g" . helm-org-rifle-org-directory)
             ("H-s" . helm-org-rifle)))
    (use-package org-chef
      :ensure t
      :demand t)
    (use-package ox-gfm
      :ensure t
      :demand t)
    

3.5 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"))

3.6 Toast

Configuration to support toast notifications based on appointments in the org-mode agenda.

Note: Toast notifications are currently only working in windows.

Setup appointment mode. Remind me every 5 minutes starting 15 minutes before the given time

(require 'appt)

(setq appt-time-msg-list nil) ;; Clear existing list

(setq appt-display-interval '5) ;; Warn every 5 miniutes

(setq
 appt-message-warning-time '15
 appt-display-mode-line nil ;; Don't display in mode line
 appt-display-format 'window)
(appt-activate 1)

Integrate org-mode with appt.el Load in appointments at start and update every time the agenda buffer is updated.

(org-agenda-to-appt)
(run-at-time "24:01" 3600 'org-agenda-to-appt)
(add-hook 'org-agenda-finalize-hook 'org-agenda-to-appt)

Setup boiler plate for toaster on windows.

(defvar toast-notifier-path "c:/Users/nmccarty/Toast/toast.exe")
(defun toast-appt-send-notification (title msg)
  (when (not (daemonp))
    (shell-command (concat toast-notifier-path
                           " -t \"" title "\""
                           " -m \"" msg "\""
                           " -p C:\\Users\\nmccarty\\Toast\\org.png"))))
(defun toast-appt-display (min-to-app new-time msg)
  (toast-appt-send-notification
   (format "Appointment in %s miniutes" min-to-app)
   (format "%s" msg)))

Set the toast function based on operating system.

(when (string-equal system-type "windows-nt")
  (setq appt-disp-window-function (function toast-appt-display)))

3.7 Configuring the 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

(setq org-agenda-files `(,(alist-get :org-dir nm/settings-alist)))

3.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}")))

4 Magit

The only git porcelain that isn’t git itself

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

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

(use-package forge
  :after magit
  :ensure t
  :demand t)

4.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
  :ensure t)

5 Languages

Packages that implement support for various programming languages

5.1 General Programming

These packages are useful across a wide variety of languages

Flycheck

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

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

Company

Completion framework for many lanaguages

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

LSP mode

Provides general support for the Language Server Protocol

(use-package lsp-mode
  :ensure t
  :demand t
  :commands lsp
  :config
  (setq lsp-signature-auto-activate nil)
  :init
  (diminish 'lsp-mode))

(require 'lsp-clients)

(use-package lsp-ui
  :ensure t
  :demand t
  :diminish lsp-ui-mode
  :config
  (setq lsp-ui-flycheck-enable 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)
  :hook 
  (lsp-mode . lsp-ui-mode))

(use-package company-lsp
  :ensure t
  :demand t
  :config
  (push 'company-lsp company-backends))

YASnippet

A template system for emacs

(use-package yasnippet
  :ensure t)

Smartparens

Assures that demiliters always match

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

Indent guide

(use-package indent-guide
  :ensure t
  :hook (prog-mode . indent-guide-mode))

5.2 Lisp Family

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))

5.3 Rust

Load rust-mode first, to alllow for org-mode support and rustic to unload it

(use-package rust-mode
  :ensure t
  :demand t)

Load in toml-mode, primarily for editing Cargo.toml

(use-package toml-mode
  :ensure t)

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
  :ensure t
  :demand t
  :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-on-save t))

5.4 AutoHotKey

Support for the AutoHotKey automation language for windows

(use-package ahk-mode
  :ensure t)

5.5 Python

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

(use-package elpy
  :ensure t
  :init
  (elpy-enable)
  :hook
  (elpy-mode . flycheck-mode))

autopep8 provides autoformatting according to PEP8

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

5.6 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))

5.7 YAML

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

(use-package yaml-mode
  :ensure t)

5.8 Dockerfile

Syntax highlighting for dockerfiles.

(use-package dockerfile-mode
  :ensure t)

5.9 Markup Languages

Markdown

Bring in the actual markdown mode

(use-package markdown-mode
  :ensure t
  :demand t
  :commands (markdown-mode gfm-mode)
  :mode (("README\\.md\\'" . gfm-mode)
         ("\\.md\\'" . markdown-mode)
         ("\\.markdown\\'" . markdown-mode))
  :init (setq markdown-command "multimarkdown")
  :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
  :ensure t
  :demand t
  :config
  (define-key markdown-mode-map (kbd "C-c C-f") #'markdownfmt-format-buffer)
  (add-hook 'markdown-mode-hook #'markdownfmt-enable-on-save))

Latex

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

(use-package tex-mode
  :demand t
  :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
  :ensure t
  :config
  (setq pdf-latex-command "xelatex"))

6 EXWM

The emacs operating system is real

(when (not (string-equal system-type "windows-nt"))
  (use-package exwm
    :ensure t
    :demand t
    :config
    (setq exwm-workspace-number 4)
    (setq exwm-replace nil)
    (add-hook 'exwm-update-class-hook
              (lambda ()
                (unless (or (string-prefix-p "sun-awt-X11-" exwm-instance-name)
                            (string= "gimp" exwm-instance-name))
                  (exwm-workspace-rename-buffer exwm-class-name))))
    (add-hook 'exwm-update-title-hook
              (lambda ()
                (when (or (not exwm-instance-name)
                          (string-prefix-p "sun-awt-X11-" exwm-instance-name)
                          (string= "gimp" exwm-instance-name))
                  (exwm-workspace-rename-buffer exwm-title))))

    ;; Global keybindings can be defined with `exwm-input-global-keys'.
    ;; Here are a few examples:
    (setq exwm-input-global-keys
          `(
            ;; Bind "s-r" to exit char-mode and fullscreen mode.
            ([?\s-r] . exwm-reset)
            ;; Bind "s-w" to switch workspace interactively.
            ([?\s-w] . exwm-workspace-switch)
            ;; Bind "s-0" to "s-9" to switch to a workspace by its index.
            ,@(mapcar (lambda (i)
                        `(,(kbd (format "s-%d" i)) .
                          (lambda ()
                            (interactive)
                            (exwm-workspace-switch-create ,i))))
                      (number-sequence 0 9))
            ;; Bind "s-&" to launch applications ('M-&' also works if the output
            ;; buffer does not bother you).
            ([?\s-s] . (lambda (command)
                         (interactive (list (read-shell-command "$ ")))
                         (start-process-shell-command command nil command)))
            ;; Bind "s-<f2>" to "slock", a simple X display locker.
            ([s-f2] . (lambda ()
                        (interactive)
                        (start-process "" nil "/usr/bin/slock")))))

    ;; To add a key binding only available in line-mode, simply define it in
    ;; `exwm-mode-map'.  The following example shortens 'C-c q' to 'C-q'.
    (define-key exwm-mode-map [?\C-q] #'exwm-input-send-next-key)

    ;; The following example demonstrates how to use simulation keys to mimic
    ;; the behavior of Emacs.  The value of `exwm-input-simulation-keys` is a
    ;; list of cons cells (SRC . DEST), where SRC is the key sequence you press
    ;; and DEST is what EXWM actually sends to application.  Note that both SRC
    ;; and DEST should be key sequences (vector or string).
    (setq exwm-input-simulation-keys
          '(
            ;; movement
            ([?\C-b] . [left])
            ([?\M-b] . [C-left])
            ([?\C-f] . [right])
            ([?\M-f] . [C-right])
            ([?\C-p] . [up])
            ([?\C-n] . [down])
            ([?\C-a] . [home])
            ([?\C-e] . [end])
            ([?\M-v] . [prior])
            ([?\C-v] . [next])
            ([?\C-d] . [delete])
            ([?\C-k] . [S-end delete])
            ;; cut/paste.
            ([?\C-w] . [?\C-x])
            ([?\M-w] . [?\C-c])
            ([?\C-y] . [?\C-v])
            ;; search
            ([?\C-s] . [?\C-f])))

    ;; You can hide the minibuffer and echo area when they're not used, by
    ;; uncommenting the following line.
                                        ;(setq exwm-workspace-minibuffer-position 'bottom)

    ;; Do not forget to enable EXWM. It will start by itself when things are
    ;; ready.  You can put it _anywhere_ in your configuration.
    (exwm-enable)
    ;; Set the key repeat rate
    (start-process-shell-command "sey key rate" "*Messages*" "xset r rate 200 20")))

Enable the system tray

(when (not (string-equal system-type "windows-nt"))
  (require 'exwm-systemtray)
  (exwm-systemtray-enable))

Start the server if we aren’t already running it

(when (not (daemonp))
  (server-start))

Enable multi-monitor support

(when (not (string-equal system-type "windows-nt"))
  (require 'exwm-randr)
  (setq exwm-randr-workspace-output-plist
        '(1 "DP2" 2 "DP1"))

  (add-hook 'exwm-randr-screen-change-hook
            (lambda ()
              (start-process-shell-command
               "xrandr" nil "xrandr --output Virtual2 --left-of Virtual1 --auto")))

  (exwm-randr-enable))

7 /etc/Modes

Modes that aren’t 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
  :ensure t
  :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
  :ensure t
  :demand t)                            ;

7.3 Notmuch

Email inside emacs

First load up not much

(when (not (string-equal system-type "windows-nt"))
  (require 'notmuch))

Encourage text/html over text/plain

(setq notmuch-multipart/alternative-discouraged '("text/plain" "text/html"))

7.4 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
  :ensure t
  :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.5 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.6 Discord integration (lol)

Pull in elcord and enable it for discord integration

(use-package elcord
  :ensure t)

7.7 PDF Tools

One of the best PDF viewers I have encountered

(use-package pdf-tools
  :ensure t
  :demand t
  :config
  (pdf-tools-install))

7.8 Discover my major

Provides additional discover ability for the functionalities in each major mode

(use-package discover-my-major
  :ensure t
  :demand t
  :config
  (global-set-key (kbd "C-h C-m") 'discover-my-major))

7.9 Comment-edit

An org-src style for editing comments in source code

(push "~/.emacs.d/site-lisp/separedit/" load-path)
(require 'separedit)
(define-key prog-mode-map (kbd "C-c '") #'separedit)
(setq separedit-default-mode 'gfm-mode) ;; or org-mode

7.10 Deadgrep

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

7.11 hl-todo

Highlights TODOs in comments

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

Enable the magit extension

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

8 mu4e

Email inside my emacs

First check if we have mu4e available

(when (require 'mu4e nil 'noerror)

Set the maildir first

(setq mu4e-maildir "~/,mail")
)

9 Work

9.1 Keyboard Macros

Links

Paste freshdesk link

(fset 'fd-link
   (kmacro-lambda-form [?\[ ?\[ ?\C-y ?\C-  ?\M-b ?\M-w ?\C-e ?\] ?\[ ?F ?D ?: ?  ?\C-y ?\] ?\]] 0 "%d"))

Paste MPM link

(fset 'mpm-link
   (kmacro-lambda-form [?\[ ?\[ ?\C-y ?\] ?\[ ?M ?P ?M ?\] ?\]] 0 "%d"))

Bring it together

(bind-keys :map global-map
           :prefix-map hyper-l-map
           :prefix "H-l"
           ("f" . fd-link)
           ("m" . mpm-link))

10 Other Keybinds

10.1 Hide-show

(bind-keys :map rustic-mode-map
           ("H-f" . hs-toggle-hiding)
           ("H-F" . hs-hide-all)
           ("H-S" . hs-show-all))