Skip to content

sleepyeye/.emacs.d-1

 
 

Repository files navigation

My Emacs Configuration

;-*- eval: (load-file “./init-dev.el”); -*-

An Explanation

This is a literate configuration for Emacs. Tangling this file creates an Elisp file, ~/.emacs.d/lisp/init.el.

Bootstrapping

early-init

Emacs 27.0 introduced an early-init file. It allows customization before package and UI initialization.
;;; early-init.el --- Emacs pre package.el & GUI configuration -*- lexical-binding: t; -*-
;;; Code:
(setq package-enable-at-startup nil)
(setq inhibit-default-init nil)
(setq native-comp-async-report-warnings-errors nil)

Debugging

Running this form will launch the debugger after loading a package. This is useful for finding out when a dependency is requiring a package (perhaps earlier than you want). Use by tangling this block and launching Emacs with emacs --debug-init.

(unless (string-empty-p file)
  (eval-after-load file
    '(debug)))

Similarly, this variable will hit the debugger when a message matches its regexp.

(setq debug-on-message "")

Adding a variable watcher can be a useful way to track down initialization and mutation of a variable.

(add-variable-watcher 'org-capture-after-finalize-hook
                      (lambda (symbol newval operation where)
                        (debug)
                        (message "%s set to %s" symbol newval)))
(setq debug-on-error t)

file-name-handler-alist

Skipping a bunch of regular expression searching in the file-name-handler-alist should improve start time.

(defvar default-file-name-handler-alist file-name-handler-alist)
(setq file-name-handler-alist nil)

gc-cons threshold

Emacs collects garbage every 800KB. This is overly aggressive on a modern machine during our init. Temporarily turning it off should decrease startup times. Resetting it afterward will ensure that normal operations don’t suffer from a large GC period.

I’m still not sure on the optimal gc-cons-threshold value. The following is a table of values from popular Emacs configurations.

Distributiongc-cons-threshold
Default800000
Doom16777216
Spacemacs100000000
(setq gc-cons-threshold most-positive-fixnum)

(defun +gc-after-focus-change ()
  "Run GC when frame loses focus."
  (run-with-idle-timer
   5 nil
   (lambda () (unless (frame-focus-state) (garbage-collect)))))
(defun +reset-init-values ()
  (run-with-idle-timer
   1 nil
   (lambda ()
     (setq file-name-handler-alist default-file-name-handler-alist
           gc-cons-threshold 100000000)
     (message "gc-cons-threshold & file-name-handler-alist restored")
     (when (boundp 'after-focus-change-function)
       (add-function :after after-focus-change-function #'+gc-after-focus-change)))))

(with-eval-after-load 'elpaca
  (add-hook 'elpaca-after-init-hook '+reset-init-values))

UI

Turning off these visual elements before UI initialization should speed up init.

(push '(menu-bar-lines . 0) default-frame-alist)
(push '(tool-bar-lines . 0) default-frame-alist)
(push '(vertical-scroll-bars) default-frame-alist)

Implicitly resizing the Emacs frame adds to init time. Fonts larger than the system default can cause frame resizing, which adds to startup time.

(setq frame-inhibit-implied-resize t)

Set default and backup fonts

(push '(font . "Source Code Pro") default-frame-alist)
(set-face-font 'default "Source Code Pro")
(set-face-font 'variable-pitch "DejaVu Sans")
(copy-face 'default 'fixed-pitch)

Ignore X resources.

(advice-add #'x-apply-session-resources :override #'ignore)

Taken from:

https://github.com/vsemyonoff/emacsrc/blob/14649a5bafea99cc7e13e7d048e9d15aed7926ce/early-init.el

This helps with a bug I was hitting when using desktop-save-mode’s desktop-read.

(setq desktop-restore-forces-onscreen nil)

Silence the bell function

(setq ring-bell-function #'ignore
      inhibit-startup-screen t)

provide early-init

(provide 'early-init)
;;; early-init.el ends here

lexical binding

The following line turns on lexical binding for performance reasons.

;; -*- lexical-binding: t; -*-

profiling

This function displays how long Emacs took to start. It’s a rough way of knowing when/if I need to optimize my init file.

(add-hook 'elpaca-after-init-hook
          (lambda ()
            (message "Emacs loaded in %s with %d garbage collections."
                     (format "%.2f seconds"
                             (float-time
                              (time-subtract (current-time) before-init-time)))
                     gcs-done)))

We can also enable the profiler to view a report after init.

(profiler-start 'cpu+mem)
(add-hook 'elpaca-after-init-hook (lambda () (profiler-stop) (profiler-report)))

ELP is useful for seeing which functions in a package are “hot”.

(require 'elp)
(with-eval-after-load file
  (elp-instrument-package file))
(add-hook 'elpaca-after-init-hook
          (lambda () (elp-results) (elp-restore-package (intern file))))

initial-buffer-choice

(setq initial-buffer-choice t) ;;*scratch*

theme

I prefer to keep my themes in a sub-folder of ~/.emacs.d

(setq custom-theme-directory "~/.emacs.d/themes/")

I’m working on a theme that is readable and attractive.

(defvar +theme 'mine "Default theme.")
(require 'cl-lib)
(require 'custom)
;; remove synthetic use-package theme
(unless (remq 'use-package custom-enabled-themes) (load-theme +theme t))

Elpaca

An elisp package manager

https://github.com/progfolio/elpaca

Bootstrap snippet

(defvar elpaca-directory (expand-file-name "elpaca/" user-emacs-directory))
(defvar elpaca-builds-directory (expand-file-name "builds/" elpaca-directory))
(defvar elpaca-order '(elpaca :repo "https://github.com/progfolio/elpaca.git"
                              :ref nil
                              :pre-build ("git" "remote" "set-url" "origin" "git@github.com:progfolio/elpaca.git")
                              :build (:not elpaca--activate-package)))
(when-let ((repo  (expand-file-name "repos/elpaca/" elpaca-directory))
           (build (expand-file-name "elpaca/" elpaca-builds-directory))
           (order (cdr elpaca-order))
           ((add-to-list 'load-path (if (file-exists-p build) build repo)))
           ((not (file-exists-p repo)))
           (buffer (get-buffer-create "*elpaca-bootstrap*")))
  (condition-case-unless-debug err
      (if-let (((zerop (call-process "git" nil buffer t "clone"
                                     (plist-get order :repo) repo)))
               (default-directory repo)
               ((zerop (call-process "git" nil buffer t "checkout"
                                     (or (plist-get order :ref) "--")))))
          (progn
            (byte-recompile-directory repo 0 'force)
            (require 'elpaca)
            (and (fboundp 'elpaca-generate-autoloads)
                 (elpaca-generate-autoloads "elpaca" repo))
            (kill-buffer buffer))
        (error "%s" (with-current-buffer buffer (buffer-string))))
    ((error)
     (warn "%s" err)
     (delete-directory repo 'recursive))))
(require 'elpaca-autoloads)
(add-hook 'after-init-hook #'elpaca-process-queues)
(elpaca `(,@elpaca-order))

Use Evil bindings in status and UI maps

(with-eval-after-load 'evil
  (with-eval-after-load 'elpaca-ui
    (evil-make-intercept-map elpaca-ui-mode-map)))

Keychain is a gpg/ssh agent that allows me to cache my credentials. This package gets the correct environment variables so elpaca can use the ssh protocol.

;; We need this loaded for SSH protocol
(elpaca-queue
 (elpaca keychain-environment
   (keychain-refresh-environment)))
(elpaca-queue
 (elpaca (melpulls :host github :repo "progfolio/melpulls" :protocol ssh)
   (add-to-list 'elpaca-menu-functions 'melpulls)))

packaging

use-package

(defmacro use-feature (name &rest args)
  "Like `use-package' but accounting for asynchronous installation.
NAME and ARGS are in `use-package'."
  (declare (indent defun))
  `(elpaca nil (use-package ,name
                 :ensure nil
                 ,@args)))
(elpaca use-package (require 'use-package))
(setq init-file-debug nil)
(if init-file-debug
    (setq use-package-verbose t
          use-package-expand-minimally nil
          use-package-compute-statistics t
          debug-on-error t)
  (setq use-package-verbose nil
        use-package-expand-minimally t))

Local

Packages that I’m developing or aren’t part of any online repositories go in ~/emacs.d/lisp/.

(let ((default-directory "~/.emacs.d/lisp/"))
  (when (file-exists-p default-directory)
    (normal-top-level-add-to-load-path '("."))
    (normal-top-level-add-subdirs-to-load-path)))

Custom variables

files/paths

(setq literate-file (concat user-emacs-directory "init.org"))

terminal utf-8

(defun +terminal ()
  "Set the terimnal coding system."
  (unless (display-graphic-p)
    (set-terminal-coding-system 'utf-8)))

(add-hook 'server-after-make-frame-hook #'+terminal)

Secrets

I keep my sensitive, personal information in a separate file so I can publish this configuration publicly.

(load-file "~/Documents/emacs-secrets.el")

Packages

general (key-bindings)

general.el provides a more convenient method for binding keys in emacs (for both evil and non-evil users).

https://github.com/noctuid/general.el#about

Load general before the remaining packages so they can make use of the :general keyword in their declarations.

(elpaca-use-package general
  :demand t
  :config
  (general-override-mode)
  (general-auto-unbind-keys)
  <<general-config>>)

config

The global definer allows me to use a leader key in most states.
(general-define-key
 :keymaps 'override
 :states '(insert normal hybrid motion visual operator emacs)
 :prefix-map '+prefix-map
 :prefix "SPC"
 :global-prefix "S-SPC")

(general-create-definer global-definer
  :wk-full-keys nil
  :keymaps '+prefix-map)
(global-definer
  "!"   'shell-command
  ":"   'eval-expression
  "."   'repeat)

We define a global-leader definer to access major-mode specific bindings:

(general-create-definer global-leader
  :keymaps 'override
  :states '(insert normal hybrid motion visual operator)
  :prefix "SPC m"
  :non-normal-prefix "S-SPC m"
  "" '( :ignore t
        :which-key
        (lambda (arg)
          (cons (cadr (split-string (car arg) " "))
                (replace-regexp-in-string "-mode$" "" (symbol-name major-mode))))))

And a macro to ease the creation of nested menu bindings:

(defmacro +general-global-menu! (name infix-key &rest body)
  "Create a definer named +general-global-NAME wrapping global-definer.
Create prefix map: +general-global-NAME. Prefix bindings in BODY with INFIX-KEY."
  (declare (indent 2))
  (let* ((n (concat "+general-global-" name))
         (prefix (intern (concat n "-map"))))
    `(progn
       (general-create-definer ,(intern n)
         :wrapping global-definer
         :prefix-map (quote ,prefix)
         :infix ,infix-key
         :wk-full-keys nil
         "" '(:ignore t :which-key ,name))
       (,(intern n) ,@body))))

applications

(+general-global-menu! "application" "a"
  "p" '(:ignore t "elpaca")
  "pr"  '((lambda () (interactive)
            (let ((current-prefix-arg '(4)))
              (call-interactively #'elpaca-rebuild)))
          :which-key "rebuild")
  "pm" 'elpaca-manager
  "pl" 'elpaca-log
  "pi" '((lambda () (interactive) (info "Elpaca"))
         :which-key "elpaca-info")
  "ps" 'elpaca-status
  "pt" 'elpaca-try
  "pv" 'elpaca-visit)

buffers

(+general-global-menu! "buffer" "b"
  "d"  'kill-current-buffer
  "o" '((lambda () (interactive) (switch-to-buffer nil))
        :which-key "other-buffer")
  "p"  'previous-buffer
  "r"  'rename-buffer
  "R"  'revert-buffer
  "M" '((lambda () (interactive) (switch-to-buffer "*Messages*"))
        :which-key "messages-buffer")
  "n"  'next-buffer
  "s" '((lambda () (interactive) (switch-to-buffer "*scratch*"))
        :which-key "scratch-buffer")
  "TAB" '((lambda () (interactive) (switch-to-buffer nil))
          :which-key "other-buffer"))

bookmarks

(+general-global-menu! "bookmark" "B")

eval

(+general-global-menu! "eval" "e"
  "b" 'eval-buffer
  "d" 'eval-defun
  "e" 'eval-expression
  "p" 'pp-eval-last-sexp
  "s" 'eval-last-sexp)

files

(+general-global-menu! "file" "f"
  "d"   '((lambda (&optional arg)
            (interactive "P")
            (let ((buffer (when arg (current-buffer))))
              (diff-buffer-with-file buffer))) :which-key "diff-with-file")
  "e"   '(:ignore t :which-key "edit")
  "ed"  '((lambda () (interactive) (find-file-existing literate-file) (widen))
          :which-key "dotfile")
  "eR"  '((lambda () (interactive) (load-file user-init-file))
          :which-key "reload-init.el")
  "et"  '((lambda ()
            (interactive)
            (save-restriction
              (widen)
              (check-parens)
              (org-babel-tangle-file literate-file))
            (load-file "~/.emacs.d/init.el"))
          :which-key "tangle/reload-init.el")
  "l"   '((lambda (&optional arg)
            (interactive "P")
            (call-interactively (if arg #'find-library-other-window #'find-library)))
          :which-key "+find-library")
  "p"   'find-function-at-point
  "P"   'find-function
  "R"   'rename-file-and-buffer
  "s"   'save-buffer
  "v"   'find-variable-at-point
  "V"   'find-variable)

frames

(+general-global-menu! "frame" "F"
  "D" 'delete-other-frames
  "F" 'select-frame-by-name
  "O" 'other-frame-prefix
  "c" '(:ingore t :which-key "color")
  "cb" 'set-background-color
  "cc" 'set-cursor-color
  "cf" 'set-foreground-color
  "f" 'set-frame-font
  "m" 'make-frame-on-monitor
  "n" 'next-window-any-frame
  "o" 'other-frame
  "p" 'previous-window-any-frame
  "r" 'set-frame-name)

git version-control

(+general-global-menu! "git/version-control" "g")

help

(+general-global-menu! "help" "h"
  "d"   '(:ignore t :which-key "describe")
  "df"  'describe-function
  "dF"  'describe-face
  "dk"  'describe-key
  "dt"  '((lambda () (interactive) (describe-text-properties (point)))
          :which-key "describe-text-properties")
  "dv"  'describe-variable
  "h"   (general-simulate-key "C-h" :which-key "help"))

links

(+general-global-menu! "link" "l")

narrowing

(+general-global-menu! "narrow" "n"
  "d" 'narrow-to-defun
  "p" 'narrow-to-page
  "r" 'narrow-to-region
  "w" 'widen)

projects

(+general-global-menu! "project" "p"
  "b" '(:ignore t :which-key "buffer"))

quit

(+general-global-menu! "quit" "q"
  "q" 'save-buffers-kill-emacs
  "r" 'restart-emacs
  "Q" 'kill-emacs)

spelling

(+general-global-menu! "spelling" "s")

text

(+general-global-menu! "text" "x"
  "i" 'insert-char
  "I" (general-simulate-key "C-x 8" :which-key "iso"))

tabs

(+general-global-menu! "tab" "t")

toggle

(+general-global-menu! "toggle" "T"
  "d" '(:ignore t :which-key "debug")
  "de" 'toggle-debug-on-error
  "dq" 'toggle-debug-on-quit
  "s" '(:ignore t :which-key "spelling"))

windows

(+general-global-menu! "window" "w"
  "?" 'split-window-vertically
  "=" 'balance-windows-area
  "/" 'split-window-horizontally
  "O" 'delete-other-windows
  "X" '((lambda () (interactive) (call-interactively #'other-window) (kill-buffer-and-window))
        :which-key "kill-other-buffer-and-window")
  "d" 'delete-window
  "h" 'windmove-left
  "j" 'windmove-down
  "k" 'windmove-up
  "l" 'windmove-right
  "o" 'other-window
  "t" '((lambda () (interactive)
          "toggle window dedication"
          (set-window-dedicated-p (selected-window) (not (window-dedicated-p))))
        :which-key "toggle window dedication")
  "x" 'kill-buffer-and-window)

vim completion

;;vim-like completion
(general-create-definer completion-def
  :prefix "C-x")

org-mode meta-mappings á la Spacemacs. C - F ‘clever-insert’ in Spacemacs source.

evil

Evil is an extensible vi layer for Emacs. It emulates the main features of Vim, and provides facilities for writing custom extensions.

https://github.com/emacs-evil/evil

(elpaca-use-package evil
  :demand t
  :preface (setq evil-want-keybinding nil)
  :general
  (+general-global-window
    "H" 'evil-window-move-far-left
    "J" 'evil-window-move-very-bottom
    "K" 'evil-window-move-very-top
    "L" 'evil-window-move-far-right)
  (+general-global-menu! "quit" "q"
    ":" 'evil-command-window-ex
    "/" 'evil-command-window-search-forward
    "?" 'evil-command-window-search-backward)
  :custom
  (evil-symbol-word-search t "search by symbol with * and #.")
  (evil-shift-width 2 "Same behavior for vim's '<' and '>' commands")
  (evil-want-C-i-jump t)
  (evil-complete-all-buffers nil)
  (evil-want-integration t)
  (evil-want-C-i-jump t)
  (evil-search-module 'evil-search "use vim-like search instead of 'isearch")
  (evil-undo-system 'undo-redo)
  :config
  ;;I want Emacs regular mouse click behavior
  (define-key evil-motion-state-map [down-mouse-1] nil)
  <<+evil-kill-minibuffer>>
  (evil-mode))

Evil mini-buffer bug

Sometimes evil gets stuck and doubles the ‘d’ and ‘c’ keys among others. This has something to do with the mini-buffer according to this Spacemacs issue:

syl20bnr/spacemacs#10410

Apparently this is a workaround:

(defun +evil-kill-minibuffer ()
  (interactive)
  (when (windowp (active-minibuffer-window))
    (evil-ex-search-exit)))

(add-hook 'mouse-leave-buffer-hook #'+evil-kill-minibuffer)

Not sure why that hook is appropriate, but calling evil-ex-search-exit manually solves the issue as well.

evil-anzu-mode

anzu for evil-mode

https://github.com/emacsorphanage/evil-anzu

Shows match counts in mode line.

(elpaca-use-package evil-anzu
  :after (evil anzu))

evil-collection

This is a collection of Evil bindings for the parts of Emacs that Evil does not cover properly by default.

https://github.com/emacs-evil/evil-collection

(elpaca-use-package evil-collection
  :after (evil)
  :config (evil-collection-init)
  :custom
  (evil-collection-setup-minibuffer t "Add evil bindings to minibuffer")
  (evil-collection-company-use-tng t))

accord

(elpaca-use-package (accord :host github :repo "progfolio/accord" :protocol ssh)
  :general
  (+general-global-application
    "a" '(:ignore t :which-key "accord")
    "aa" 'accord
    "a/" 'accord-channel-search
    "a;" 'accord-channel-last
    "ac" '(:ignore t :which-key "channel")
    "ac/" 'accord-channel-search
    "ac;" 'accord-channel-last
    "acj" 'accord-channel-scroll-down
    "ack" 'accord-channel-scroll-up
    "acn" 'accord-channel-next
    "acp" 'accord-channel-prev
    "acr" 'accord-channel-mark-read
    "acu" 'accord-channel-goto-unread
    "acu" 'accord-channel-scroll-up
    "ad" 'accord-delete-message
    "ae" 'accord-edit-message
    "as" 'accord-send-message)
  (global-leader
    :major-modes '(accord-mode)
    :keymaps     '(accord-mode-map)
    "/" 'accord-channel-search
    ";" 'accord-channel-last
    "S" '(:ignore t :which-key "Server")
    "SN" 'accord-server-next
    "SP" 'accord-server-prev
    "c" '(:ignore t :which-key "channel")
    "c;" 'accord-channel-last
    "c/" 'accord-channel-search
    "cj" 'accord-channel-scroll-down
    "ck" 'accord-channel-scroll-up
    "cn" 'accord-channel-next
    "cp" 'accord-channel-prev
    "cr" 'accord-channel-mark-read
    "cu" 'accord-channel-goto-unread
    "cu" 'accord-channel-scroll-up
    ;; These look superfluous, but without the :which-key value
    ;; we're picking up names from org mode leader bindings...
    ;; Not sure if it's a bug with general.el or my init.
    "d" '(accord-delete-message :which-key "accord-delete-message")
    "e" '(accord-edit-message   :which-key "accord-edit-message")
    "s" '(accord-send-message   :which-key "accord-send-message"))
  :config
  (defun accord-setup ()
    (flyspell-mode)
    (visual-line-mode))

  (add-hook 'accord-mode-hook 'accord-setup))

afternoon-theme

Dark color theme with a deep blue background

https://github.com/osener/emacs-afternoon-theme

(elpaca-use-package afternoon-theme :defer t)

almost-mono-themes

A collection of almost monochrome emacs themes in a couple of variants. https://github.com/cryon/almost-mono-themes

(elpaca-use-package almost-mono-themes :defer t)

asm-mode

(use-feature asm-mode
  :config
  (defun +asm-mode-hook ()
    (local-unset-key (vector asm-comment-char))
    (setq tab-always-indent (default-value 'tab-always-indent)))

  (defun +asm-indent-buffer ()
    (interactive)
    (save-excursion
      (goto-char (point-min))
      (while (not (eobp))
        (when (re-search-forward ";" (point-at-eol) t)
          (comment-dwim nil))
        (asm-indent-line)
        (forward-line 1))))

  ;;hook should not be global. Just add locally.
  (defun +asm-before-save-hook ()
    (when (eq major-mode 'asm-mode)
      (+asm-indent-buffer)))

  (add-hook 'asm-mode-hook '+asm-mode-hook)
  (add-hook 'before-save-hook '+asm-before-save-hook))

anzu

anzu.el provides a minor mode which displays ‘current match/total matches’ in the mode-line in various search modes. This makes it easy to understand how many matches there are in the current buffer for your search query.

(elpaca-use-package anzu
  :defer 10
  :config (global-anzu-mode))

auto-fill-mode

I usually want lines to wrap at 80 chars (Emacs defaults to 70).

(use-feature simple
  :general
  (+general-global-toggle
    "f" 'auto-fill-mode)
  :custom
  (eval-expression-debug-on-error nil)
  (fill-column 80 "Wrap at 80 columns."))

auto-revert

Automatically revert a buffer if its file has changed on disk. This is useful when checking out different versions of a file in version control. It also helps if multiple instances of Emacs are editing the same file.

(use-feature autorevert
  :defer 2
  :custom
  (auto-revert-interval 0.01 "Instantaneously revert")
  :config
  (global-auto-revert-mode t))

auto-tangle-mode

(elpaca-use-package (auto-tangle-mode
                     :host github
                     :repo "progfolio/auto-tangle-mode.el"
                     :local-repo "auto-tangle-mode")
  :commands (auto-tangle-mode))

bookmark

(use-feature bookmark
  :custom (bookmark-fontify nil)
  :general
  (+general-global-bookmark
    "j" 'bookmark-jump
    "s" 'bookmark-set
    "r" 'bookmark-rename))

buttercup

Buttercup is a behavior-driven development framework for testing Emacs Lisp code.

https://github.com/jorgenschaefer/emacs-buttercup

(elpaca-use-package buttercup
  :commands (buttercup-run-at-point))

cleanroom

(elpaca-use-package (cleanroom :host github :repo "progfolio/cleanroom" :protocol ssh)
  :defer t)

compile

(use-feature compile
  :commands (compile recompile)
  :custom (compilation-scroll-output 'first-error)
  :config
  (defun +compilation-colorize ()
    "Colorize from `compilation-filter-start' to `point'."
    (require 'ansi-color)
    (let ((inhibit-read-only t))
      (ansi-color-apply-on-region (point-min) (point-max))))
  (add-hook 'compilation-filter-hook #'+compilation-colorize))

corfu

Completion Overlay Region FUnction

“Corfu enhances completion at point with a small completion popup.”

https://github.com/minad/corfu

(elpaca-use-package (corfu :host github :repo "minad/corfu" :files (:defaults "extensions/*"))
  :defer 5
  :custom
  (corfu-cycle t)
  :config
  (global-corfu-mode)
  (with-eval-after-load 'evil
    (setq evil-complete-next-func (lambda (_) (completion-at-point)))))

custom-set-variables

(use-feature cus-edit
  :custom
  (custom-file null-device "Don't store customizations"))

default-text-scale

Easily adjust the font size in all Emacs frames

https://github.com/purcell/default-text-scale

(elpaca-use-package default-text-scale
  :commands ( default-text-scale-increase
              default-text-scale-decrease
              default-text-scale-reset
              default-text-scale-increment))

diminish

This package implements hiding or abbreviation of the mode line displays (lighters) of minor-modes.

https://github.com/emacsmirror/diminish

(elpaca-use-package diminish
  :defer 10)

dimmer

Visually highlight the selected buffer.

https://github.com/gonewest818/dimmer.el

(elpaca-use-package dimmer
  :defer 5
  :after (helm which-key)
  :custom
  (dimmer-exclusion-regexp-list '("^\\*[h|H]elm.*\\*"
                                  "^\\*Minibuf-.*\\*"
                                  "^\\*Echo.*"
                                  "^.\\*which-key\\*$"))
  (dimmer-fraction 0.10)
  (dimmer-watch-frame-focus-events nil)
  :config
  (dimmer-mode 1)
  (dimmer-configure-which-key)
  (dimmer-configure-helm)
  (dimmer-configure-magit))

dired

Directory browsing commands

(use-feature dired
  :commands (dired)
  :custom
  (dired-listing-switches "-alh" "Human friendly file sizes.")
  (dired-kill-when-opening-new-dired-buffer t)
  :general
  (+general-global-application "d" 'dired))

doct

doct is a function that provides an alternative, declarative syntax for describing Org capture templates.

https://github.com/progfolio/doct

(elpaca-use-package (doct :branch "development" :protocol ssh :depth nil)
  :commands (doct))

doom-modeline

A fancy and fast mode-line inspired by minimalism design.

https://github.com/seagle0128/doom-modeline

(elpaca-use-package doom-modeline
  :config
  (column-number-mode 1)
  (doom-modeline-mode)
  :custom
  (doom-modeline-icon t "Show icons in the modeline")
  (doom-modeline-mu4e t "modeline email alert"))

doom-themes

DOOM Themes is an opinionated UI plugin and pack of themes extracted from [hlissner’s] emacs.d, inspired by some of my favorite color themes.

https://github.com/hlissner/emacs-doom-themes

(elpaca-use-package doom-themes :defer t)

edebug

This minor mode allows programmers to step through Emacs Lisp source code while executing functions. You can also set breakpoints, trace (stopping at each expression), evaluate expressions as if outside Edebug, reevaluate and display a list of expressions, trap errors normally caught by debug, and display a debug style backtrace.

(use-feature edebug
  :general
  (global-leader
    :major-modes '(emacs-lisp-mode lisp-interaction-mode t)
    :keymaps     '(emacs-lisp-mode-map lisp-interaction-mode-map)
    "d" '(:ignore t :which-key "debug")
    "dA" 'edebug-all-defs
    "db" '(:ignore t :which-key "breakpoint")
    "dbU"  'edebug-unset-breakpoints
    "dbc"  'edebug-set-conditional-breakpoint
    "dbg"  'edebug-set-global-break-condition
    "dbn"  'edebug-next-breakpoint
    "dbs"  'edebug-set-breakpoint
    "dbt"  'edebug-toggle-disable-breakpoint
    "dbu"  'edebug-unset-breakpoint
    "dw" 'edebug-where))

elfeed

Elfeed is an extensible web feed reader for Emacs, supporting both Atom and RSS.

https://github.com/skeeto/elfeed

I’ve put my elfeed database in under version control. I may move it from its default location (~/.elfeed), in elfeed-db-directory.

(elpaca-use-package elfeed
  :commands (elfeed)
  :config
  (defun +elfeed-play-in-mpv ()
    "Play selected videos in a shared mpv instance in chronological order."
    (interactive)
    (mapc (lambda (entry)
            (emp-open-url (elfeed-entry-link entry))
            (message "Playing %S in MPV" (elfeed-entry-title entry)))
          (nreverse (elfeed-search-selected)))
    (elfeed-search-untag-all-unread))

  (defun +elfeed-download ()
    "Download selected videos."
    (interactive)
    (let ((default-directory (expand-file-name "~/Videos/youtube")))
      (dolist (entry (nreverse (elfeed-search-selected)))
        (let ((title (elfeed-entry-title entry)))
          (message "Attempting to download %S" (elfeed-entry-title entry))
          (make-process
           :name "elfeed-download"
           :buffer "elfeed-download"
           :command (list "youtube-dl" (elfeed-entry-link entry))
           :sentinel (lambda (process _event)
                       (when (= 0 (process-exit-status process))
                         (message "Successfully downloaded %S" title))))))
      (elfeed-search-untag-all-unread)))
  :general
  (+general-global-application
    "e"    'elfeed)
  (general-define-key
   :states '(normal)
   :keymaps 'elfeed-search-mode-map
   "p" '+elfeed-play-in-mpv
   "d" '+elfeed-download)
  (general-define-key
   :states '(normal)
   :keymaps 'elfeed-show-mode-map
   "J" 'elfeed-show-next
   "K" 'elfeed-show-prev))

elfeed-org

(elpaca-use-package elfeed-org
  :after (elfeed org)
  :config (elfeed-org)
  :custom
  (rmh-elfeed-org-files '("~/Documents/rss-feeds.org"))
  (rmh-elfeed-org-auto-ignore-invalid-feeds nil))

elisp-mode

(use-feature elisp-mode
  :general
  (global-leader
    :major-modes '(emacs-lisp-mode lisp-interaction-mode t)
    :keymaps     '(emacs-lisp-mode-map lisp-interaction-mode-map)
    "e"  '(:ignore t :which-key "eval")
    "eb" 'eval-buffer
    "ed" 'eval-defun
    "ee" 'eval-expression
    "ep" 'pp-eval-last-sexp
    "es" 'eval-last-sexp
    "i"  'elisp-index-search))

Emacs

These settings defined in C code, so we use the emacs pseudo-package to set them.

(use-feature emacs
  :demand t
  :custom
  <<emacs-custom>>)

:custom

(scroll-conservatively 101 "Scroll just enough to bring text into view")
(enable-recursive-minibuffers t "Allow minibuffer commands in minibuffer")
(frame-title-format '(buffer-file-name "%f" ("%b"))
                    "Make frame title current file's name.")
(find-library-include-other-files nil)
(indent-tabs-mode nil "Use spaces, not tabs")
(inhibit-startup-screen t)
(history-delete-duplicates t "Don't clutter history")
(pgtk-use-im-context-on-new-connection nil "Prevent GTK from stealing Shift + Space")
(sentence-end-double-space nil "Double space sentence demarcation breaks sentence navigation in Evil")
(tab-stop-list (number-sequence 2 120 2))
(tab-width 2 "Shorter tab widths")
(completion-styles '(flex basic partial-completion emacs22))

ement.el

Ement.el is a new Matrix client for Emacs. It aims to be simple, fast, featureful, and reliable. ~ https://github.com/alphapapa/ement.el

(elpaca-use-package (ement :host github :repo "alphapapa/ement.el")
  :custom (ement-room-avatars t)
  :config
  (add-hook 'ement-room-compose-hook #'flyspell-mode)
  :general
  (+general-global-application
    "M" '(:ignore t :which-key "Matrix")
    "MM" '((lambda () (interactive) (ement-connect :user-id "@nv-elisp:matrix.org"))
           :which-key "ement-connect")))

emp

MPV integration

(elpaca-use-package (emp :host github :repo "progfolio/emp")
  :config
  :general
  (+general-global-application
    "v"  '(:ignore t :which-key "video/audio")
    "vQ" 'emp-kill
    "vf" '(:ignore t :which-key "frame")
    "vfb" 'emp-frame-back-step
    "vff" 'emp-frame-step
    "vi" 'emp-insert-playback-time
    "vo" 'emp-open
    "vO" 'emp-cycle-osd
    "v SPC" 'emp-pause
    "vs" 'emp-seek
    "vr" 'emp-revert-seek
    "vt" 'emp-seek-absolute
    "vv" 'emp-set-context
    "vS" 'emp-speed-set))

epa/g-config

(use-feature epg-config
  :defer t
  :init (setq epg-pinentry-mode 'loopback))
(use-feature epa-file
  :defer t
  :init (setq epa-file-cache-passphrase-for-symmetric-encryption t))

epoch

(elpaca-use-package (epoch :host github :repo "progfolio/epoch")
  :after (org)
  :commands (epoch-todo epoch-agenda-todo))

erc

Built in IRC client

(use-feature erc
  :general
  (+general-global-application
    "E" 'erc)
  :hook
  (erc-mode . erc-spelling-mode))

files

By default Emacs saves backups in the current buffer’s working directory. I’d rather have everything in one folder to keep my file system tidy.

(use-feature files
  ;;:hook
  ;;(before-save . delete-trailing-whitespace)
  :config
  ;; source: http://steve.yegge.googlepages.com/my-dot-emacs-file
  (defun rename-file-and-buffer (new-name)
    "Renames both current buffer and file it's visiting to NEW-NAME."
    (interactive "sNew name: ")
    (let ((name (buffer-name))
          (filename (buffer-file-name)))
      (if (not filename)
          (message "Buffer '%s' is not visiting a file." name)
        (if (get-buffer new-name)
            (message "A buffer named '%s' already exists." new-name)
          (progn
            (rename-file filename new-name 1)
            (rename-buffer new-name)
            (set-visited-file-name new-name)
            (set-buffer-modified-p nil))))))
  :custom
  (require-final-newline t "Automatically add newline at end of file")
  (backup-by-copying t)
  (backup-directory-alist `((".*" . ,(expand-file-name
                                      (concat user-emacs-directory "backups"))))
                          "Keep backups in their own directory")
  (auto-save-file-name-transforms `((".*" ,(concat user-emacs-directory "autosaves/") t)))
  (delete-old-versions t)
  (kept-new-versions 10)
  (kept-old-versions 5)
  (version-control t)
  (safe-local-variable-values
   '((eval load-file "./init-dev.el")
     (org-clean-refile-inherit-tags))
   "Store safe local variables here instead of in emacs-custom.el"))

fill-column-indicator

(use-feature display-fill-column-indicator
  :custom
  (display-fill-column-indicator-character
   (plist-get '( triple-pipe  ?┆
                 double-pipe  ?╎
                 double-bar   ?║
                 solid-block  ?█
                 empty-bullet ?◦)
              'triple-pipe))
  :general
  (+general-global-toggle
    "F" '(:ignore t :which-key "fill-column-indicator")
    "FF" 'display-fill-column-indicator-mode
    "FG" 'global-display-fill-column-indicator-mode))

flycheck

Flycheck is a modern on-the-fly syntax checking extension for GNU Emacs, intended as replacement for the older Flymake extension which is part of GNU Emacs.

https://www.flycheck.org/en/latest/

(elpaca-use-package flycheck
  :commands (flycheck-mode)
  :custom (flycheck-emacs-lisp-load-path 'inherit "necessary with alternatives to package.el"))

flycheck-package

package-lint integration for flycheck.

(elpaca-use-package flycheck-package
  :after (flychceck)
  :config (flycheck-package-setup))

flymake

(use-feature flymake
  :general
  (global-leader
    :major-modes '(emacs-lisp-mode lisp-interaction-mode t)
    :keymaps     '(emacs-lisp-mode-map lisp-interaction-mode-map)
    "f" '(:ignore t :which-key "flymake")
    "ff" '((lambda () (interactive) (flymake-mode 'toggle)) :which-key "toggle flymake-mode")
    "fn" 'flymake-goto-next-error
    "fp" 'flymake-goto-prev-error)
  :hook (flymake-mode . +flymake-toggle-diagnostics-buffer)
  :config
  (defun +flymake-elpaca-bytecomp-load-path ()
    "Augment `elisp-flymake-byte-compile-load-path' to support Elpaca."
    (setq-local elisp-flymake-byte-compile-load-path
                `("./" ,@(mapcar #'file-name-as-directory
                                 (nthcdr 2 (directory-files (expand-file-name "builds" elpaca-directory) 'full))))))
  (add-hook 'flymake-mode-hook #'+flymake-elpaca-bytecomp-load-path)

  (defun +flymake-toggle-diagnostics-buffer ()
    "Toggle the diagnostics buffer when entering/exiting `flymake-mode'."
    (let* ((root (vc-root-dir))
           (command (if root
                        #'flymake-show-project-diagnostics
                      #'flymake-show-buffer-diagnostics))
           (window (get-buffer-window
                    (if root
                        (flymake--project-diagnostics-buffer root)
                      (flymake--diagnostics-buffer-name)))))
      (if flymake-mode
          (funcall command)
        (when (window-live-p window)
          (with-selected-window window
            (kill-buffer-and-window)))))))

flyspell

(use-feature flyspell
  :commands (flyspell-mode flyspell-prog-mode)
  :general
  (+general-global-toggle
    "ss" 'flyspell-mode
    "sp" 'flyspell-prog-mode)
  (+general-global-spelling
    "n" 'flyspell-goto-next-error
    "b" 'flyspell-buffer
    "w" 'flyspell-word
    "r" 'flyspell-region)
  :hook ((org-mode mu4e-compose-mode git-commit-mode) . flyspell-mode))

flyspell-correct

“This package provides functionality for correcting words via custom interfaces.” – https://d12frosted.io/posts/2016-05-09-flyspell-correct-intro.html

(elpaca-use-package flyspell-correct
  :after (flyspell)
  :general
  (+general-global-spelling
    "B" 'flyspell-correct-wrapper
    "p" 'flyspell-correct-at-point))

fontify-face

Fontify symbols representing faces with that face.

https://github.com/Fuco1/fontify-face

(elpaca-use-package fontify-face
  :commands (fontify-face-mode))

fountain-mode

Fountain Mode is a screenwriting program for GNU Emacs using the Fountain plain text markup format.

https://github.com/rnkn/fountain-mode

(elpaca-use-package fountain-mode
  :mode "\\.fountain\\'")

helm

Helm is an Emacs framework for incremental completions and narrowing selections.

https://github.com/emacs-helm/helm

(elpaca-use-package helm
  :defer 1
  :custom
  (helm-echo-input-in-header-line t)
  (helm-split-window-inside-p t "split window inside current window")
  (helm-move-to-line-cycle-in-source t "cycle to beggining or end afte reaching top/bottom of list")
  (helm-show-completion-display-function nil "don't want to open a separate frame for this")
  (helm-completion-style 'emacs "Necessary to have multiline candidates/text-properties show in completion buffer")
  :config
  (add-hook 'helm-after-initialize-hook (lambda () (with-helm-buffer (visual-line-mode))))
  (helm-mode)

  ;;credit: alphapapa
  (defun +helm-info-emacs-elisp-cl ()
    "Helm for Emacs, Elisp, and CL_library info pages."
    (interactive)
    (helm :sources '(helm-source-info-elisp helm-source-info-emacs helm-source-info-cl)))
  :general
  (:keymaps 'helm-map
            "TAB"   #'helm-execute-persistent-action
            "<tab>" #'helm-execute-persistent-action
            "C-a"   #'helm-select-action
            "C-h"   #'helm-find-files-up-one-level)
  (global-definer
    "SPC" '(helm-M-x :which-key "M-x")
    "/"   'helm-occur)
  (+general-global-buffer
    "b" 'helm-mini)
  (+general-global-file
    "f" 'helm-find-files
    "F" 'helm-find
    "r" 'helm-recentf)
  (+general-global-help
    "a" 'helm-apropos)
  (completion-def
    :keymaps 'insert
    "C-f" 'helm-complete-file-name-at-point)
  (global-leader
    :major-modes '(org-mode t)
    :keymaps     '(org-mode-map)
    "/"  'helm-org-in-buffer-headings))

helm-ag

helm-ag.el provides interfaces of The Silver Searcher with helm.

https://github.com/emacsorphanage/helm-ag

(elpaca-use-package helm-ag
  :commands (helm-ag helm-projectile-ag))

helm-describe-modes

helm-describe-modes provides a Helm interface to Emacs’s describe-mode.

https://github.com/emacs-helm/helm-describe-modes

(elpaca-use-package helm-describe-modes
  :commands (helm-describe-modes)
  :diminish helm-describe-mode
  :after (helm)
  :general
  (+general-global-help
    "dm"  'helm-describe-modes))

helm-descbinds

Helm Descbinds provides an interface to emacs’ describe-bindings making the currently active key bindings interactively searchable with helm.

https://github.com/emacs-helm/helm-descbinds

(elpaca-use-package helm-descbinds
  :after (helm)
  :commands (helm-descbinds-mode)
  :diminish helm-descbinds-mode
  :custom
  (helm-descbinds-window-style 'split)
  :general
  (global-definer
    "?"   'helm-descbinds))

helm-org

Helm integration for org headlines and keywords.

Necessary for completion of multiple tags with Helm.

(elpaca-use-package helm-org
  :after (helm)
  :config
  (add-to-list 'helm-completing-read-handlers-alist '(org-set-tags-command . helm-org-completing-read-tags))
  (add-to-list 'helm-completing-read-handlers-alist '(org-capture . helm-org-completing-read-tags)))

helm-projectile

(elpaca-use-package helm-projectile
  :after (helm)
  :general
  (+general-global-project
    "a" 'helm-projectile-ag
    "bb" 'helm-projectile-switch-to-buffer
    "d" 'helm-projectile-find-dir
    "f" 'helm-projectile-find-file
    "F" 'helm-projectile-find-file-dwim
    "p" 'helm-projectile-switch-project
    "r" 'helm-projectile-recentf))

helm-swoop

List match lines to another buffer, which is able to squeeze by any words you input. At the same time, the original buffer’s cursor is jumping line to line according to moving up and down the line list.

https://github.com/emacsorphanage/helm-swoop

(elpaca-use-package helm-swoop
  :after (helm)
  :commands
  (helm-swoop))

help

(use-feature help
  :defer 1
  :custom
  (help-window-select t "Always select the help window"))

highlight-indent-guides

This minor mode highlights indentation levels via font-lock.

https://github.com/DarthFennec/highlight-indent-guides

(elpaca-use-package highlight-indent-guides
  :commands
  (highlight-indent-guides-mode)
  :hook (prog-mode . highlight-indent-guides-mode)
  :custom
  (highlight-indent-guides-method 'column))

history

(use-feature savehist
  :defer 1
  :config
  (savehist-mode 1))

holidays

I’d like to see holidays and anniversaries in my org-agenda and calendar I’ve removed the default holiday lists that I don’t need.

(use-feature holidays
  :commands (org-agenda)
  :custom
  (holiday-bahai-holidays nil)
  (holiday-hebrew-holidays nil)
  (holiday-islamic-holidays nil)
  (holiday-oriental-holidays nil))

htmlize

This package converts the buffer text and the associated decorations to HTML.

https://github.com/hniksic/emacs-htmlize

This is necessary for exporting Org files to HTML.

(elpaca-use-package htmlize
  :defer t)

hydra

This is a package for GNU Emacs that can be used to tie related commands into a family of short bindings with a common prefix: a Hydra.

https://github.com/abo-abo/hydra

(elpaca-use-package hydra
  :after (general)
  :config
  (defhydra +hydra-zoom (:pre (setq which-key-inhibit t)
                              :post (setq which-key-inhibit nil)
                              :hint none)
            ;;newline is necessary here!
            "
^Zoom ^ ^-----^ _i_ in _o_ out _r_ reset (capital for all frames)"
            ;;Entry
            ("i" text-scale-increase "in")
            ("I" default-text-scale-increase "all in")
            ("o" text-scale-decrease "out")
            ("O" default-text-scale-decrease "all out")
            ("r" (text-scale-adjust 0) "reset")
            ("R" default-text-scale-reset "reset all"))
  (defhydra +hydra-window-resize (:pre (setq which-key-inhibit t)
                                       :post (setq which-key-inhibit nil))
            ;;newline is necessary here!
            "
^Resize Windows^ "
            ;;Entry
            ("H" (lambda () (interactive) (shrink-window-horizontally 5)) "shrink-horizontal" :column "Large")
            ("J" (lambda () (interactive) (enlarge-window 5)) "enlarge-vertical")
            ("K" (lambda () (interactive) (shrink-window 5)) "shrink-vertical")
            ("L" (lambda () (interactive) (enlarge-window-horizontally 5)) "enlarge-horizontal")
            ("=" (lambda () (interactive) (balance-windows)) "balance-windows" :column "Balance")
            ("h" (lambda () (interactive) (shrink-window-horizontally 1)) "shrink-horizontal" :column "Small")
            ("j" (lambda () (interactive) (enlarge-window 1)) "enlarge-vertical")
            ("k" (lambda () (interactive) (shrink-window 1)) "shrink-vertical")
            ("l" (lambda () (interactive) (enlarge-window-horizontally 1)) "enlarge-horizontal"))
  :general
  (global-definer
    "z"   '(+hydra-zoom/body :which-key "zoom"))
  (+general-global-window
    "." '(+hydra-window-resize/body :which-key "window-resize")))

ielm

Provides a nice interface to evaluating Emacs Lisp expressions. Input is handled by the comint package, and output is passed through the pretty-printer.

ielm.el commentary

(use-feature ielm
  :general
  (global-leader
    :major-modes '(inferior-emacs-lisp-mode)
    :keymaps     '(inferior-emacs-lisp-mode-map)
    "b"  '(:ignore t :which-key "buffer")
    "bb" 'ielm-change-working-buffer
    "bd" 'ielm-display-working-buffer
    "bp" 'ielm-print-working-buffer
    "c"  'comint-clear-buffer)
  ;;@TODO: fix this command.
  ;;This should be easier
  (+general-global-application "i"
    '("ielm" . (lambda ()
                 (interactive)
                 (let* ((b (current-buffer))
                        (i (format "*ielm<%s>*" b)))
                   (setq ielm-prompt (concat (buffer-name b) ">"))
                   (ielm i)
                   (ielm-change-working-buffer b)
                   (next-buffer)
                   (switch-to-buffer-other-window i))))))

i3wm-config-mode

An expansion of conf-mode to bring proper syntax highlighting to your i3wm config.

(elpaca-use-package (i3wm-config-mode
                     :host github :repo "Alexander-Miller/i3wm-Config-Mode")
  :commands (i3wm-config-mode))

js2

Improved JavaScript editing mode for GNU Emacs

https://github.com/mooz/js2-mode

(elpaca-use-package js2-mode
  :commands (js2-mode)
  :mode "\\.js\\'"
  :interpreter (("nodejs" . js2-mode) ("node" . js2-mode))
  :hook (js2-mode . (lambda ()
                      (company-mode t)
                      (tern-mode t)
                      (add-to-list 'company-backends 'company-tern))))

May not need this on Emacs 27+

Need to investigate, but js-mode might have been fixed/updated.

lilypond

Major mode for Lilypond music engraver. Installing Lilypond puts these in /usr/share/Emacs/site-lisp, but I plan on editing these.

(elpaca-use-package (lilypond-mode :host gitlab :repo "lilypond/lilypond"
                                   :remotes (("fork" :host github :repo "progfolio/lilypond" :protocol ssh)
                                             "origin")
                                   :branch "fix/lilypond-mode"
                                   :files ("elisp/*.el" "elisp/out/lilypond-words.el")
                                   :protocol ssh
                                   :pre-build (("./autogen.sh" "--noconfigure")
                                               ("./configure")
                                               ("bash" "-c"
                                                "cd elisp && make && \
                                       echo ';; Local Variables:\n;; no-byte-compile: t\n;; End:' \
                                       >> out/lilypond-words.el")))
  :mode "\\.ly\\'"
  :general
  (global-leader
    :major-modes '(lilypond-mode t)
    :keymaps     '(lilypond-mode-map)
    "l"  'lilypond-compile-file
    "p"  'lilypond-play))

link-hint

link-hint.el is inspired by the link hinting functionality in vim-like browsers and browser plugins such as pentadactyl. It provides commands for using avy to open, copy, or take a user-defined action on “links.”

https://github.com/noctuid/link-hint.el

(elpaca-use-package link-hint
  :general
  (+general-global-link
    "a" 'link-hint-open-all-links
    "f" 'link-hint-open-link
    "F" 'link-hint-open-link-at-point
    "Y" 'link-hint-copy-link-at-point
    "yy" 'link-hint-copy-link
    "ym" 'link-hint-copy-multiple-links
    "ya" 'link-hint-copy-multiple-links))

macrostep

macrostep is an Emacs minor mode for interactively stepping through the expansion of macros in Emacs Lisp source code.

https://github.com/joddie/macrostep

(elpaca-use-package macrostep
  :general
  (global-leader
    :major-modes '(emacs-lisp-mode lisp-interaction-mode t)
    :keymaps     '(emacs-lisp-mode-map lisp-interaction-mode-map)
    "m"  '(:ignore t :which-key "macrostep")
    "me" 'macrostep-expand
    "mc" 'macrostep-collapse
    "mj" 'macrostep-next-macro
    "mk" 'macrostep-prev-macro))

magit

Magit is an interface to the version control system Git, implemented as an Emacs package.

https://magit.vc/

(elpaca-use-package magit
  :defer t
  :after (general)
  :general
  (+general-global-git/version-control
    "b"  'magit-branch
    "B"  'magit-blame
    "c"  'magit-clone
    "f"  '(:ignore t :which-key "file")
    "ff" 'magit-find-file
    "fh" 'magit-log-buffer-file
    "i"  'magit-init
    "L"  'magit-list-repositories
    "m"  'magit-dispatch
    "S"  'magit-stage-file
    "s"  'magit-status
    "U"  'magit-unstage-file)
  :config
  (transient-bind-q-to-quit))

markdown

markdown-mode is a major mode for editing Markdown-formatted text.

https://jblevins.org/projects/markdown-mode/

(elpaca-use-package markdown-mode
  :commands (markdown-mode gfm-mode)
  :mode
  (("README\\.md\\'" . gfm-mode)
   ("\\.md\\'" . markdown-mode)
   ("\\.markdown\\'" . markdown-mode))
  :custom
  (markdown-command "/usr/bin/pandoc"))

miscellany

A package for miscellaneous functions.

(elpaca-use-package (miscellany
                     :host github
                     :repo "progfolio/miscellany.el"
                     :local-repo "miscellany"
                     :branch "master"
                     :pre-build ((require 'ob-tangle)
                                 (setq org-confirm-babel-evaluate nil)
                                 (org-babel-tangle-file "./miscellany.org")))
  :after (general)
  :commands (+alternate-buffer
             +change-theme
             +compute-blood-pressure-table-row
             +kill-other-buffers
             +org-fix-close-times
             +org-remove-timestamp-time
             +org-toggle-hide-emphasis-markers
             +recompile-user-package-dir
             +server-eval-all
             +toggle-maximize-buffer
             +toggle-relative-lines
             +toggle-syntax-highlighting
             +universal-arg)
  :general
  (global-definer
    "u" '(+universal-arg :which-key "universal-arg"))
  (+general-global-buffer
    "a" '(+alternate-buffer   :which-key "alternate-buffer")
    "q" 'bury-buffer
    "m" '(+kill-other-buffers :which-key "kill-other-buffers")
    "N" '(+normalize-buffer   :which-key "normalize-buffer")
    "u" 'unbury-buffer)
  (+general-global-window
    "f" '(+toggle-maximize-buffer
          :which-key "toggle-maximize-buffer"))
  (+general-global-toggle
    "S" '(+toggle-syntax-highlighting :which-key "syntax-highlighting")
    "m" '(+toggle-mode                :which-key "mode")
    "n" '(+toggle-relative-lines      :which-key "relative-lines")
    "t" '(:ignore t :which-key "theme")
    "tt" '(+change-theme :which-key "toggle-theme")
    "tn" '((lambda () (interactive) (+theme-nth 1))  :which-key "theme-next")
    "tp" '((lambda () (interactive) (+theme-nth -1)) :which-key "theme-prev")))

mu4e

An emacs-based e-mail client which uses mu as its back-end.

https://www.djcbsoftware.nl/code/mu/mu4e.html

(elpaca-use-package (mu4e :host github :files ("mu4e/*.el" "build/mu4e/mu4e-meta.el" "build/mu4e/mu4e-config.el") :repo "djcb/mu"
                          :main "mu4e/mu4e.el"
                          :pre-build (("./autogen.sh") ("ninja" "-C" "build")
                                      (make-symbolic-link (expand-file-name "./build/mu/mu")
                                                          (expand-file-name "~/bin/mu") 'ok-if-exists)))
  :commands (mu4e mu4e-update-index)
  :custom
  (mail-user-agent 'mu4e-user-agent)
  (mu4e-org-support t)
  (message-mail-user-agent 'mu4e-user-agent "Use mu4e as default email program.")
  (mu4e-maildir (expand-file-name "~/Documents/emails/"))
  (mu4e-attachment-dir "~/Downloads")
  (mu4e-completing-read-function 'completing-read)
  (mu4e-compose-signature-auto-include nil)
  (mu4e-use-fancy-chars t)
  (mu4e-view-show-addresses t)
  (mu4e-view-show-images t)
  (mu4e-sent-messages-behavior 'sent)
  (mu4e-get-mail-command "mbsync -c ~/.mbsyncrc -a")
  (mu4e-change-filenames-when-moving t "Needed for mbsync")
  (mu4e-confirm-quit nil)
  (mu4e-html2text-command  'mu4e-shr2text)
  ;;(mu4e-html2text-command "w3m -dump \
  ;;                             -T text/html \
  ;;                             -cols 72 \
  ;;                             -o display_link_number=true \
  ;;                             -o auto_image=false \
  ;;                             -o display_image=false \
  ;;                             -o ignore_null_img_alt=true"
  ;;                        "Readable HTML email rendering")
  ;;contexts
  (mu4e-context-policy 'pick-first)
  (mu4e-compose-context-policy 'always-ask)
  :config
  (setq mu4e-contexts
        (list
         (make-mu4e-context
          :name "personal"
          :enter-func (lambda () (mu4e-message "Entering personal context"))
          :leave-func (lambda () (mu4e-message "Leaving personal context"))
          :match-func (lambda (msg)
                        (when msg
                          (mu4e-message-contact-field-matches
                           msg '(:from :to :cc :bcc) secret-personal-email-account)))
          :vars `((user-mail-address .  ,secret-personal-email-address)
                  (user-full-name . ,secret-personal-email-name)
                  (mu4e-compose-format-flowed . t)
                  (message-send-mail-function . smtpmail-send-it)
                  (smtpmail-smtp-user . ,secret-personal-email-account)
                  (smtpmail-starttls-credentials . (("smtp.gmail.com" 587 nil nil)))
                  (smtpmail-auth-credentials . ,secret-personal-email-credential)
                  (smtpmail-default-smtp-server . "smtp.gmail.com")
                  (smtpmail-smtp-server . "smtp.gmail.com")
                  (smtpmail-smtp-service . 587)
                  (smtpmail-debug-info . t)
                  (smtpmail-debug-verbose . t)))
         (make-mu4e-context
          :name "work"
          :enter-func (lambda () (mu4e-message "Entering work context"))
          :leave-func (lambda () (mu4e-message "Leaving work context"))
          :match-func (lambda (msg)
                        (when msg
                          (mu4e-message-contact-field-matches
                           msg '(:from :to :cc :bcc) secret-work-email-account)))
          :vars `((user-mail-address .  ,secret-work-email-address)
                  (user-full-name . ,secret-work-email-name)
                  (mu4e-compose-format-flowed . t)
                  (message-send-mail-function . smtpmail-send-it)
                  (smtpmail-smtp-user . ,secret-work-email-account)
                  (smtpmail-starttls-credentials . (("smtp.gmail.com" 587 nil nil)))
                  (smtpmail-auth-credentials . ,secret-work-email-credential)
                  (smtpmail-default-smtp-server . "smtp.gmail.com")
                  (smtpmail-smtp-server . "smtp.gmail.com")
                  (smtpmail-smtp-service . 587)
                  (smtpmail-debug-info . t)
                  (smtpmail-debug-verbose . t)))))

  (add-to-list 'mu4e-view-actions
               '("ViewInBrowser" . mu4e-action-view-in-browser) t)

  (add-to-list 'mu4e-bookmarks
               '( :name "straight.el"
                  :query "list:straight.el.raxod502.github.com"
                  :key ?s))

  (defun +mu4e-view-settings ()
    "Settings for mu4e-view-mode."
    (visual-line-mode)
    (olivetti-mode)
    (variable-pitch-mode))
  (add-hook 'mu4e-view-mode-hook #'+mu4e-view-settings)

  :general
  (+general-global-application "m" 'mu4e :which-key "mail")
  (global-leader
    :keymaps '(mu4e-compose-mode-map)
    "a" 'mml-attach-file))

mu4e-alert

mu4e-alert is an Emacs extension providing desktop notifications for mu4e. Additionally it can display the number of unread emails in the mode-line.

https://github.com/iqbalansari/mu4e-alert

(elpaca-use-package (mu4e-alert
                     :host github
                     :remotes (("fork"
                                :repo "progfolio/mu4e-alert"
                                :branch "fix/mu4e--switch-context-advice")
                               "origin"))
  :defer 20
  :after (org)
  :config
  (setq mu4e-alert-set-window-urgency nil)
  (mu4e-alert-enable-mode-line-display)
  (mu4e-alert-enable-notifications)
  (mu4e-alert-enable-mode-line-display)
  (mu4e-alert-enable-notifications)
  (advice-add #'mu4e-quit :after #'mu4e-alert-update-mail-count-modeline))

nov (epub)

Major mode for reading EPUB files in Emacs

https://depp.brause.cc/nov.el/

(elpaca-use-package (nov :depth nil)
  :custom
  (nov-text-width 80)
  :mode
  ("\\.epub\\'" . nov-mode)
  :commands
  (nov-mode))

novice

This feature tries to help new users by disabling certain potentially destructive or confusing commands. Don’t need it.

(use-feature novice
  :custom
  (disabled-command-function nil "Enable all commands"))

olivetti

A simple Emacs minor mode for a nice writing environment.

https://github.com/rnkn/olivetti

(elpaca-use-package olivetti
  :commands (olivetti-mode))

org

(elpaca-use-package org
  :defer t
  :general
  (general-define-key :states '(normal) :keymaps 'org-mode-map
                      (kbd "<tab>") 'org-cycle
                      (kbd "<backtab>") 'org-shifttab)
  (general-define-key :states '(normal insert) :keymaps 'org-mode-map
                      (kbd "M-l") 'org-metaright
                      (kbd "M-h") 'org-metaleft
                      (kbd "M-k") 'org-metaup
                      (kbd "M-j") 'org-metadown
                      (kbd "M-L") 'org-shiftmetaright
                      (kbd "M-H") 'org-shiftmetaleft
                      (kbd "M-K") 'org-shiftmetaup
                      (kbd "M-J") 'org-shiftmetadown)
  (general-define-key :states  '(motion) :keymaps 'org-mode-map
                      (kbd "RET") 'org-open-at-point)
  ;;<tab> is for GUI only. TAB maps to C-i on terminals.
  (+general-global-application
    "o"   '(:ignore t :which-key "org")
    "oc"  'org-capture
    "oC"  '+org-capture-again
    "oi"  'org-insert-link
    "oj"  'org-chronicle
    "ok"  '(:ignore t :which-key "clock")
    "okg" 'org-clock-goto
    "oki" 'org-clock-in-last
    "okj" 'org-clock-jump-to-current-clock
    "oko" 'org-clock-out
    "okr" 'org-resolve-clocks
    "ol"  'org-store-link
    "om"  'org-tags-view
    "os"  'org-search-view
    "oT"  'org-todo-list
    "ot"  '(:ignore t :which-key "timer")
    "ott" 'org-timer
    "otS" 'org-timer-stop
    "otC" 'org-timer-change-times-in-region
    "otc" 'org-timer-set-timer
    "ots" 'org-timer-start
    "oti" 'org-timer-item
    "otp" 'org-timer-pause-or-continue
    "otr" 'org-timer-show-remaining-time)

  (global-leader
    ;;for terminals
    :keymaps '(org-mode-map)
    "TAB" 'org-cycle
    "."  'org-time-stamp
    "!"  'org-time-stamp-inactive
    "<"  'org-date-from-calendar
    ">"  'org-goto-calendar

    "C"  '(:ignore t :which-key "clock")
    "Cc" 'org-clock-cancel
    "Ci" 'org-clock-in
    "Co" 'org-clock-out
    "Cr" 'org-clock-report
    "CR" 'org-resolve-clocks

    "d"  '(:ignore t :which-key "dates")
    "dd" 'org-deadline
    "df" '((lambda () (interactive) (+org-fix-close-times))
           :which-key "org-fix-close-time")
    "ds" 'org-schedule
    "di" 'org-time-stamp-inactive
    "dt" 'org-time-stamp

    "e"   '(:ignore t :which-key "export")
    "ee"  'org-export-dispatch

    "h"   '(:ignore t :which-key "heading")
    "hf"  'org-forward-heading-same-level
    "hb"  'org-backward-heading-same-level

    "i"  '(:ignore t :which-key "insert")
    "id" 'org-insert-drawer
    "ie" 'org-set-effort
    "if" 'org-footnote-new
    "iH" 'org-insert-heading-after-current
    "ih" 'org-insert-heading
    "ii" 'org-insert-item
    "il" 'org-insert-link
    "in" 'org-add-note
    "ip" 'org-set-property
    "is" 'org-insert-structure-template
    "it" 'org-set-tags-command

    "n"  '(:ignore t :which-key "narrow")
    "nb" 'org-narrow-to-block
    "ne" 'org-narrow-to-element
    "ns" 'org-narrow-to-subtree
    "nt" 'org-toggle-narrow-to-subtree
    "nw" 'widen

    "s"  '(:ignore t :which-key "trees/subtrees")
    "sA" 'org-archive-subtree
    "sa" 'org-toggle-archive-tag
    "sb" 'org-tree-to-indirect-buffer
    "sc" 'org-cut-subtree
    "sh" 'org-promote-subtree
    "sj" 'org-move-subtree-down
    "sk" 'org-move-subtree-up
    "sl" 'org-demote-subtree
    "sp" '(:ignore t :which-key "priority")
    "spu" 'org-priority-up
    "spd" 'org-priority-down
    "sps" 'org-priority-show
    "sm" 'org-match-sparse-tree
    "sn" 'org-toggle-narrow-to-subtree
    "sr" 'org-refile
    "sS" 'org-sort
    "ss" '+org-sparse-tree

    "t"   '(:ignore t :which-key "tables")
    "ta"  'org-table-align
    "tb"  'org-table-blank-field
    "tc"  'org-table-convert

    "td"  '(:ignore t :which-key "delete")
    "tdc" 'org-table-delete-column
    "tdr" 'org-table-kill-row
    "tE"  'org-table-export
    "te"  'org-table-eval-formula
    "tH"  'org-table-move-column-left
    "th"  'org-table-previous-field
    "tI"  'org-table-import

    "ti"  '(:ignore t :which-key "insert")
    "tic" 'org-table-insert-column
    "tih" 'org-table-insert-hline
    "tiH" 'org-table-hline-and-move
    "tir" 'org-table-insert-row
    "tJ"  'org-table-move-row-down
    "tj"  'org-table-next-row
    "tK"  'org-table-move-row-up
    "tL"  'org-table-move-column-right
    "tl"  'org-table-next-field
    "tN"  'org-table-create-with-table.el
    "tn"  'org-table-create
    "tp"  'org-plot/gnuplot
    "tr"  'org-table-recalculate
    "ts"  'org-table-sort-lines

    "tt"  '(:ignore t :which-key "toggle")
    "ttf" 'org-table-toggle-formula-debugger
    "tto" 'org-table-toggle-coordinate-overlays
    "tw"  'org-table-wrap-region

    "T"  '(:ignore t :which-key "toggle")
    "Tc"  'org-toggle-checkbox
    "Te"  'org-toggle-pretty-entities
    "TE"  '+org-toggle-hide-emphasis-markers
    "Th"  'org-toggle-heading
    "Ti"  'org-toggle-item
    "TI"  'org-toggle-inline-images
    "Tl"  'org-toggle-link-display
    "TT"  'org-todo
    "Tt"  'org-show-todo-tree
    "Tx"  'org-latex-preview
    "RET" 'org-ctrl-c-ret
    "#"   'org-update-statistics-cookies
    "'"   'org-edit-special
    "*"   'org-ctrl-c-star
    "-"   'org-ctrl-c-minus
    "A"   'org-attach)
  :config
  ;;Fix off-by-one paren matching in Org src blocks.
  ;;https://emacs.stackexchange.com/questions/50216/org-mode-code-block-parentheses-mismatch
  ;;@TODO: slow in "work schedule" org-agenda command. Not sure why.
  (defun +org-src-substitute-syntax-table (start end)
    "Change syntax of characters ?< and ?> to symbol within source code blocks."
    (let ((case-fold-search t))
      (when (eq major-mode 'org-mode)
        (save-excursion
          (goto-char start)
          (while (re-search-forward "<\\|>" end 'noerror)
            (when (save-excursion
                    (and
                     (re-search-backward "[[:space:]]*#\\+\\(begin\\|end\\)_src\\_>" nil t)
                     (string-equal (downcase (match-string 1)) "begin")))
              ;; This is a < or > in an org-src block
              (put-text-property (point) (1- (point))
                                 'syntax-table (string-to-syntax "_"))))))))

  (defun +org-src-fix-syntax ()
    "Setup for characters ?< and ?> in source code blocks.
    Add this function to `org-mode-hook'."
    (make-local-variable 'syntax-propertize-function)
    (setq syntax-propertize-function #'+org-src-substitute-syntax-table)
    (syntax-propertize (point-max)))

  (add-hook 'org-mode-hook #'+org-src-fix-syntax)

  (defun +org-sparse-tree (&optional arg type)
    (interactive)
    (funcall #'org-sparse-tree arg type)
    (org-remove-occur-highlights))

  (defun +insert-heading-advice (&rest _args)
    "Enter insert mode after org-insert-heading. Useful so I can tab to control level of inserted heading."
    (when evil-mode (evil-insert 1)))

  (advice-add #'org-insert-heading :after #'+insert-heading-advice)

  (defun +org-update-cookies ()
    (interactive)
    (org-update-statistics-cookies "ALL"))

  ;; TOO SLOW!
  ;; (add-hook 'org-mode-hook
  ;;           (lambda ()
  ;;             (add-hook 'before-save-hook '+org-update-cookies nil 'local)))

  ;; Offered a patch to fix this upstream. Too much bikeshedding for such a simple fix.
  (defun +org-tags-crm (fn &rest args)
    "Workaround for bug which excludes \",\" when reading tags via `completing-read-multiple'.
I offered a patch to fix this, but it was met with too much resistance to be
worth pursuing."
    (let ((crm-separator "\\(?:[[:space:]]*[,:][[:space:]]*\\)"))
      (unwind-protect (apply fn args)
        (advice-remove #'completing-read-multiple #'+org-tags-crm))))

  (define-advice org-set-tags-command (:around (fn &rest args) comma-for-crm)
    (advice-add #'completing-read-multiple :around #'+org-tags-crm)
    (apply fn args))
  :custom
  ;;default:
  ;;(org-w3m org-bbdb org-bibtex org-docview org-gnus org-info org-irc org-mhe org-rmail)
  ;;org-toc is interesting, but I'm not sure if I need it.
  (org-modules '(org-habit))
  (org-todo-keywords
   '((sequence  "TODO(t)" "STARTED(s!)" "NEXT(n!)" "BLOCKED(b@/!)" "|" "DONE(d)")
     (sequence  "IDEA(i)" "|" "CANCELED(c@/!)" "DELEGATED(D@/!)")
     (sequence  "RESEARCH(r)" "|"))
   ;;move to theme?
   org-todo-keyword-faces
   `(("CANCELED" . (:foreground "IndianRed1" :weight bold))
     ("TODO" . (:foreground "#ffddaa"
                            :weight bold
                            :background "#202020"
                            :box (:line-width 3 :width -2 :style released-button)))))
  (org-ellipsis (nth 5 '("" "˅" "" "" "" "")))
  (org-priority-lowest ?D)
  (org-fontify-done-headline t)
  (org-M-RET-may-split-line nil "Don't split current line when creating new heading"))

org-agenda

(use-feature org-agenda
  :after   (general evil)
  :config
  (defun +org-agenda-archives (&optional arg)
    "Toggle `org-agenda-archives-mode' so that it includes archive files by default.
Inverts normal logic of ARG."
    (interactive "P")
    (let ((current-prefix-arg (unless (or org-agenda-archives-mode arg) '(4))))
      (call-interactively #'org-agenda-archives-mode)))

  (defun +org-agenda-place-point ()
    "Place point on first agenda item."
    (goto-char (point-min))
    (org-agenda-find-same-or-today-or-agenda))

  (add-hook 'org-agenda-finalize-hook #'+org-agenda-place-point 90)
  :general
  <<org-agenda-keybindings>>
  :custom
  <<org-agenda-custom>>)

keybindings

(+general-global-application
  "o#"   'org-agenda-list-stuck-projects
  "o/"   'org-occur-in-agenda-files
  "oa"   '((lambda () (interactive) (org-agenda nil "a")) :which-key "agenda")
  "oe"   'org-store-agenda-views
  "oo"   'org-agenda)
(global-leader :keymaps 'org-mode-map
  "a"   'org-agenda)

Consider cribbing evilified-state from Spacemacs?

(with-eval-after-load 'org-agenda
  (evil-make-intercept-map org-agenda-mode-map)
  (general-define-key
   :keymaps 'org-agenda-mode-map
   ;;:states '(emacs normal motion)
   "A"     '+org-agenda-archives
   "C"     'org-agenda-clockreport-mode
   "D"     'org-agenda-goto-date
   "E"     'epoch-agenda-todo
   "H"     'org-habit-toggle-habits
   "J"     'org-agenda-next-item
   "K"     'org-agenda-previous-item
   "R"     'org-agenda-refile
   "S"     'org-agenda-schedule
   "RET"   'org-agenda-recenter
   "a"     '+org-capture-again
   "c"     'org-agenda-capture
   "j"     'org-agenda-next-line
   "k"     'org-agenda-previous-line
   "m"     'org-agenda-month-view
   "t"     'org-agenda-set-tags
   "T"     'org-agenda-todo
   "u"     'org-agenda-undo))

When saving, I want changes to my org-files reflected in any open org agenda buffers.

:config
;;for org-agenda-icon-alist
(evil-set-initial-state 'org-agenda-mode 'normal)
(defun +org-agenda-redo-all ()
  "Rebuild all agenda buffers"
  (interactive)
  (dolist (buffer (buffer-list))
    (with-current-buffer buffer
      (when (derived-mode-p 'org-agenda-mode)
        (org-agenda-maybe-redo)))))

(add-hook 'org-mode-hook
          (lambda ()
            (add-hook 'after-save-hook '+org-agenda-redo-all nil t)
            (setq prettify-symbols-unprettify-at-point 'right-edge)
            (setq prettify-symbols-alist
                  (mapcan (lambda (el) (list el (cons (upcase (car el)) (cdr el))))
                          '(("#+begin_src"     . "λ")
                            ("#+end_src"       . "λ")
                            (":properties:"    . "")
                            (":end:"           . "")
                            ("#+results:"      . ""))))
            (prettify-symbols-mode 1)))

:custom

Add a custom view for a simplified work agenda.
(org-agenda-custom-commands
 '(("w" "Work Schedule" agenda "+work"
    ((org-agenda-files '("~/Documents/todo/work.org"))
     (org-agenda-span 'week)
     (org-mode-hook nil)
     (org-agenda-start-on-weekday 2)
     (org-agenda-timegrid-use-ampm t)
     (org-agenda-time-leading-zero t)
     (org-agenda-use-time-grid nil)
     (org-agenda-archives-mode t)
     (org-agenda-weekend-days '(2 3))
     (org-agenda-format-date "%a %m-%d")
     (org-agenda-prefix-format '((agenda . " %t")))
     (org-agenda-finalize-hook
      '((lambda ()
          "Format custom agenda command for work schedule."
          (save-excursion
            (goto-char (point-min))
            (while (re-search-forward "TODO Work" nil 'noerror)
              (replace-match ""))
            (goto-char (point-min))
            (forward-line) ;skip header
            (while (not (eobp))
              (when (get-text-property (point) 'org-agenda-date-header)
                (let (fn)
                  (save-excursion
                    (forward-line)
                    (setq fn
                          (cond ((or (eobp)
                                     (get-text-property (point) 'org-agenda-date-header))
                                 (lambda () (end-of-line) (insert " OFF")))
                                ((get-text-property (point) 'time)
                                 (lambda () (forward-line) (join-line))))))
                  (funcall fn)))
              (forward-line))))))))
   ("n" "Agenda and all TODOs" ((agenda "") (alltodo "")))))
(org-agenda-skip-deadline-prewarning-if-scheduled nil "Show approaching deadlines even when scheduled.")

I prefer the agenda to start on the current day view instead of the week. It’s generally faster to generate and usually what I want.

(org-agenda-span 'day)

These settings should speed up agenda generation:

(org-agenda-inhibit-startup t)

But, I’m not sure about this one. It doesn’t seem to speed things up that much for me and I like to see inherited tags on tasks.

(org-agenda-use-tag-inheritance nil)

I find category icons to be a nice visual shorthand that keeps the agenda less cluttered.

(org-agenda-prefix-format '((agenda . " %i %?-12t% s")))
(org-agenda-category-icon-alist
 (let ((image-dir (expand-file-name "images/org/" user-emacs-directory))
       (categories '(("[Aa]ccounting" "accounting.svg")
                     ("[Bb]irthday"   "birthday.svg")
                     ("[Cc]alendar"   "calendar.svg")
                     ("[Cc]hore"      "chore.svg"    :height 25)
                     ("[Ee]xercise"   "exercise.svg" :height 24)
                     ("[Ff]ood"       "food.svg")
                     ("[Hh]abit"      "habit.svg")
                     ("[Hh]ealth"     "health.svg")
                     ("[Ii]n"         "in.svg")
                     ("[Ll]isten"     "listen.svg")
                     ("[Oo]ut"        "out.svg")
                     ("[Pp]lay"       "play.svg")
                     ("[Rr]efile"     "refile.svg")
                     ("[Rr]ead"       "read.svg")
                     ("[Ww]atch"      "watch.svg")
                     ("[Ww]ork"       "work.svg"))))
   (mapcar (lambda (category)
             (list (nth 0 category)
                   (expand-file-name (nth 1 category) image-dir)
                   'svg
                   nil
                   :height (or (plist-get category :height) 20)
                   :ascent (or (plist-get category :ascent) 'center)))
           categories)))

This sorting strategy will place habits in/next to the agenda time-grid.

(org-agenda-sorting-strategy
 '((agenda time-up priority-down category-keep)
   (todo priority-down category-keep)
   (tags priority-down category-keep)
   (search category-keep)))

I want the agenda clock report table to skip files that don’t have any time clocked for the current agenda view.

(org-agenda-clockreport-parameter-plist
 '(:link t :maxlevel 2 :stepskip0 t :fileskip0 t))

I don’t need to see the word “Scheduled” before scheduled items.

(org-agenda-scheduled-leaders '("" "%2dx "))

Align tags to column 80 in the agenda view:

(org-agenda-tags-column -80)

fix all-the-icons loading? Is it necessary? Save glyph locally?

org-babel

Tangling

(use-feature ob-tangle
  :after (org)
  :ensure nil
  :custom
  (org-src-window-setup 'current-window)
  (org-src-preserve-indentation t)
  :general
  (global-leader :keymaps 'org-mode-map
    "b"   '(:ignore t :which-key "babel")
    "bt"  'org-babel-tangle
    "bT"  'org-babel-tangle-file
    "be"  '(:ignore t :which-key "execute")
    "beb" 'org-babel-execute-buffer
    "bes" 'org-babel-execute-subtree)
  :config
  <<org-babel-config>>)

config

Structured Templates

I want language specific code block templates. I may use yasnippets for this later to have more flexibility.

(dolist (template '(("f" . "src fountain")
                    ("se" . "src emacs-lisp :lexical t")
                    ("ss" . "src shell")
                    ("sj" . "src javascript")))
  (add-to-list 'org-structure-template-alist template))

Languages

If C-c-c refuses to run code blocks and you get an error message:

“evaluation of language x disabled”

delete the *.el(c) files and restart

(use-package ob-js
  :commands (org-babel-execute:js))
(use-package ob-python
  :commands (org-babel-execute:python))
(use-package ob-shell
  :commands (org-babel-execute:bash
             org-babel-execute:shell
             org-babel-expand-body:generic)
  :config (add-to-list 'org-babel-load-languages '(shell . t))
  (org-babel-do-load-languages 'org-babel-load-languages org-babel-load-languages))

org-better-repeat

(elpaca-use-package (org-better-repeat-mode :host github :repo "progfolio/org-better-repeat-mode" :protocol ssh)
  :after (org)
  :config
  (defun +org-delete-after-prop-drawer ()
    (interactive)
    "If entry has a property drawer, delete everything after it."
    (save-excursion
      (unless (org-at-heading-p)
        (org-previous-visible-heading 1))
      (let* ((end (progn (save-excursion
                           (org-next-visible-heading 1) (1- (point)))))
             (beginning (or (save-excursion
                              (re-search-forward org-property-drawer-re end t))
                            end)))
        (delete-region beginning end))))

  (defun +org-remove-style-property ()
    (interactive)
    "Removes 'STYLE' property of org entry.
I use this so that archived copies of repeating tasks will show in org-agenda-archive-mode."
    (save-excursion
      (save-restriction
        (org-narrow-to-subtree)
        (org-delete-property "STYLE"))))

  (defun +org-archive-habit ()
    (interactive)
    (+org-fix-close-times)
    (+org-delete-after-prop-drawer)
    (+org-remove-style-property))

  (defun +calc-run-time ()
    (let* ((data (mapcar #'string-to-number
                         (org-entry-get-multivalued-property (point) "OBR-data")))
           (rate-of-growth (car data))
           (last-seconds (cadr data))
           (new-seconds (* last-seconds rate-of-growth)))
      (org-edit-headline (format-seconds "Run for %02m.%02s" new-seconds))
      (org-entry-put-multivalued-property (point) "OBR-data" (number-to-string rate-of-growth)
                                          (number-to-string new-seconds))))
  :hook org-mode)

org-bullets

Purely cosmetic. I may ditch this at some point.

(elpaca-use-package org-bullets
  :after (org)
  :config (add-hook 'org-mode-hook #'org-bullets-mode)
  :custom (org-bullets-bullet-list
           ;;"§" "◉" "○" "✸" "✿" "✚" "★" "►" "▶"
           ;;use for multiple repeated symbols
           ;;`("§",@(make-list 2 "◇") "★")
           '("")))

org-capture

(use-feature org-capture
  :config
  (define-advice org-capture-fill-template (:around (fn &rest args) comma-for-crm)
    (advice-add #'completing-read-multiple :around #'+org-tags-crm)
    (apply fn args))
  (add-hook 'org-capture-mode-hook #'evil-insert-state)

Utility functions for use inside Org capture templates.

(defun +org-schedule-relative-to-deadline ()
  "For use with my appointment capture template. User is first prompted for an
optional deadline. Then an optional schedule time. The scheduled default time is
the deadline. This makes it easier to schedule relative to the deadline using
the -- or ++ operators.

Quitting during either date prompt results in an empty string for that prompt."
  (interactive)
  (condition-case nil
      (org-deadline nil)
    (quit nil))
  (let ((org-overriding-default-time (or (org-get-deadline-time (point))
                                         org-overriding-default-time)))
    (org-schedule nil (org-element-interpret-data
                       (org-timestamp-from-time
                        org-overriding-default-time
                        (and org-overriding-default-time 'with-time))))
    (let ((org-log-reschedule nil))
      (condition-case nil
          (org-schedule nil)
        (quit (org-schedule '(4)))))))

(defun +org-capture-again (&optional arg)
  "Call `org-capture' with last selected template.
Pass ARG to `org-capture'.
If there is no previous template, call `org-capture'."
  (interactive "P")
  (org-capture arg (plist-get org-capture-plist :key)))

(defun +org-capture-here ()
  "Convenience command to insert a template at point"
  (interactive)
  (org-capture 0))

(defun +org-capture-property-drawer ()
  "Hook function run durning `org-capture-mode-hook'.
If a template has a :properties keyword, add them to the entry."
  (when (eq (org-capture-get :type 'local) 'entry)
    (when-let ((properties (doct-get :properties t)))
      (dolist (property properties)
        (org-set-property
         (symbol-name (car property))
         (replace-regexp-in-string
          "\n.*" ""
          (org-capture-fill-template
           (doct--replace-template-strings (cadr property)))))))))

(defun +org-capture-todo ()
  "Set capture entry to TODO automatically"
  (org-todo "TODO"))
(setq org-capture-templates
      (doct `(("Appointment"
               :keys "a"
               :id "2cd2f75e-b600-4e9b-95eb-6baefeaa61ac"
               :properties ((Created "%U"))
               :template ("* %^{appointment} %^g" "%?")
               :hook (lambda ()
                       (+org-capture-property-drawer)
                       (unless org-note-abort (+org-schedule-relative-to-deadline))))
              ("Account"
               :keys "A"
               :properties ((Created "%U"))
               :template ("* TODO %^{description} %^g" "%?")
               :hook +org-capture-property-drawer
               :children (("Buy"
                           :keys "b"
                           :id "e1dcca6e-6d85-4c8e-b935-d50492b2cc58")
                          ("Borrow"
                           :keys "B"
                           :id "a318b8ba-ed1a-4767-84bd-4f45eb409aab"
                           :template ("* TODO Return %^{description} to %^{person} %^g"
                                      "DEADLINE: %^T"
                                      "%?"))
                          ("Loan"
                           :keys "l"
                           :id "cfdd301d-c437-4aae-9738-da022eae8056"
                           :template ("* TODO Get %^{item} back from %^{person} %^g"
                                      "DEADLINE: %^T"
                                      "%?"))
                          ("Favor"
                           :keys "f"
                           :id "9cd02444-2465-4692-958b-f73edacd997f")
                          ("Sell"
                           :keys "s"
                           :id "9c4a39c5-3ba6-4665-ac43-67e72f461c15")))
              ("Bookmark"
               :keys "b"
               :hook +org-capture-property-drawer
               :id "7c20c705-80a3-4f5a-9181-2ea14a18fa75"
               :properties ((Created "%U"))
               :template ("* [[%x][%^{title}]] %^g" "%?"))
              ("Health"
               :keys "h"
               :children (("Blood Pressure"
                           :keys "b"
                           :type table-line
                           :id "4d0c16dd-ce99-4e1b-bf9f-fb10802e48a1"
                           :template "%(+compute-blood-pressure-table-row)|%?|"
                           :table-line-pos "II-1")))
              ("Listen"
               :keys "l"
               :hook (lambda () (+org-capture-property-drawer) (+org-capture-todo))
               :template ("* TODO %^{Title} %^g" "%^{Genre}")
               :children (("Audio Book"
                           :keys "a"
                           :id "55a01ad5-24f5-40ec-947c-ed0bc507d4e8"
                           :template "* TODO %^{Title} %^g %^{Author}p %^{Year}p %^{Genre}p")
                          ("Music"
                           :keys "m"
                           :id "dc9cfb0f-c65b-4ebe-a082-e751bb3261a6"
                           :template "%(wikinforg-capture \"album\")")
                          ("Podcast"
                           :keys "p"
                           :id "881ee183-37aa-4e76-a5af-5be8446fc346"
                           :properties ((URL "[[%^{URL}][%^{Description}]]")))
                          ("Radio"
                           :keys "r"
                           :id "78da1d3e-c83a-4769-9fb2-91e8ff7ab5da")))
              ("Note"
               :keys "n"
               :file ,(defun +org-capture-repo-note-file ()
                        "Find note for current repository."
                        (require 'projectile)
                        (let* ((coding-system-for-write 'utf-8)
                               ;;@MAYBE: extract this to a global variable.
                               (notedir "~/Documents/devops/repo-notes/")
                               (project-root (projectile-project-root))
                               (name (concat (file-name-base (directory-file-name project-root)) ".org"))
                               (path (expand-file-name name (file-truename notedir))))
                          (with-current-buffer (find-file-noselect path)
                            (unless (derived-mode-p 'org-mode) (org-mode)
                                    ;;set to utf-8 because we may be visiting raw file
                                    (setq buffer-file-coding-system 'utf-8-unix))
                            (when-let ((headline (doct-get :headline)))
                              (unless (org-find-exact-headline-in-buffer headline)
                                (goto-char (point-max))
                                (insert "* " headline)
                                (org-set-tags (downcase headline))))
                            (unless (file-exists-p path) (write-file path))
                            path)))
               :template (lambda () (concat  "* %{todo-state} " (when (y-or-n-p "Link? ") "%A\n") "%?"))
               :todo-state "TODO"
               :children (("bug" :keys "b" :headline "Bug")
                          ("design"        :keys "d" :headline "Design")
                          ("documentation" :keys "D" :headline "Documentation")
                          ("enhancement"   :keys "e" :headline "Enhancement" :todo-state "IDEA")
                          ("feature"       :keys "f" :headline "Feature"     :todo-state "IDEA")
                          ("optimization"  :keys "o" :headline "Optimization")
                          ("miscellaneous" :keys "m" :headline "Miscellaneous")
                          ("security"      :keys "s" :headline "Security")))
              ("Play"
               :keys "p"
               :id "be517275-3779-477f-93cb-ebfe0204b614"
               :hook +org-capture-todo
               :template "%(wikinforg-capture \"game\")")
              ("Read"
               :keys "r"
               :template "%(wikinforg-capture \"book\")"
               :hook +org-capture-todo
               :children (("fiction"
                           :keys "f"
                           :id "0be106fc-a920-4ab3-8585-77ce3fb793e8")
                          ("non-fiction"
                           :keys "n"
                           :id "73c29c94-fb19-4012-ab33-f51158c0e59b")))
              ("Say"
               :keys "s"
               :children (("word" :keys "w"
                           :id "55e43a15-5523-49a6-b16c-b6fbae337f05"
                           :template ("* %^{Word}" "%?"))
                          ("Phrase" :keys "p"
                           :id "c3dabe22-db69-423a-9737-f90bfc47238a"
                           :template ("* %^{Phrase}" "%?"))
                          ("Quote" :keys "q"
                           :id "8825807d-9662-4d6c-a28f-6392d3c4dbe2"
                           :template ("* %^{Quote}" "%^{Quotee}p"))))
              ("Todo" :keys "t"
               :id "0aeb95eb-25ee-44de-9ef5-2698514f6208"
               :hook (lambda ()
                       (+org-capture-property-drawer)
                       ;;swallow org-todo quit so we don't abort the whole capture
                       (condition-case nil (org-todo) (quit nil)))
               :properties ((Created "%U"))
               :template ("* %^{description} %^g" "%?"))
              ("use-package" :keys "u"
               :file ,(expand-file-name "init.org" user-emacs-directory)
               :function
               ,(defun +org-capture-use-package-form ()
                  "place point for use-package capture template."
                  (org-show-all)
                  (goto-char (org-find-entry-with-id "f8affafe-3a4c-490c-a066-006aeb76f628"))
                  (org-narrow-to-subtree)
                  ;;popping off parent headline, evil and general.el since they are order dependent.
                  (when-let* ((name (read-string "package name: "))
                              (headlines (nthcdr 4 (caddr (org-element-parse-buffer 'headline 'visible))))
                              (packages (mapcar (lambda (headline) (cons (plist-get (cadr headline) :raw-value)
                                                                         (plist-get (cadr headline) :contents-end)))
                                                headlines))
                              (target (let ((n (downcase name)))
                                        (cdr
                                         (cl-some (lambda (package) (and (string-greaterp n (downcase (car package))) package))
                                                  (nreverse packages))))))
                    ;;put name on template's doct plist
                    (setq org-capture-plist
                          (plist-put org-capture-plist :doct
                                     (plist-put (org-capture-get :doct) :use-package name)))
                    (goto-char target)
                    (org-end-of-subtree)
                    (open-line 1)
                    (forward-line 1)))
               :type plain
               :empty-lines-after 1
               :template ("** %(doct-get :use-package)"
                          "#+begin_quote"
                          "%(read-string \"package description:\")"
                          "#+end_quote"
                          "#+begin_src emacs-lisp"
                          "(use-package %(doct-get :use-package)%?)"
                          "#+end_src"))

              ("Watch":keys "w"
               :template "%(wikinforg-capture \"%{entity}\")"
               :hook +org-capture-todo
               :children (("Film" :keys "f" :id "a730a2db-7033-40af-82c1-9b73528ab7d9" :entity "film")
                          ("TV" :keys "t" :id "4a18a50e-909e-4d36-aa7a-b09e8c3b01f8" :entity "show")
                          ("Presentation" :keys "p" :id "343fe4f4-867a-4033-b31a-8b57aba0345e"
                           :template "* %^{Title} %^g %^{Year}p"))))))

make-capture-frame cobbled together from:

Don’t use this within Emacs. Rather, invoke it when connecting an Emacs client to a server with:

emacsclient --create-frame \
            --socket-name 'capture' \
            --alternate-editor='' \
            --frame-parameters='(quote (name . "capture"))' \
            --no-wait \
            --eval "(+org-capture-make-frame)"
(defun +org-capture-delete-frame (&rest _args)
  "Delete frame with a name frame-parameter set to \"capture\""
  (when (and (daemonp) (string= (frame-parameter (selected-frame) 'name) "capture"))
    (delete-frame)))
(add-hook 'org-capture-after-finalize-hook #'+org-capture-delete-frame 100)
(defun +org-capture-make-frame ()
  "Create a new frame and run org-capture."
  (interactive)
  (select-frame-by-name "capture")
  (delete-other-windows)
  (cl-letf (((symbol-function 'switch-to-buffer-other-window) #'switch-to-buffer))
    (condition-case err
        (org-capture)
      ;; "q" signals (error "Abort") in `org-capture'
      ;; delete the newly created frame in this scenario.
      (user-error (when (string= (cadr err) "Abort") (delete-frame))))))
:commands (+org-capture-make-frame)
:general
(:states 'normal
         :keymaps 'org-capture-mode-map
         ",c" 'org-capture-finalize
         ",k" 'org-capture-kill
         ",r" 'org-capture-refile)
:custom
(org-capture-dir (concat (getenv "HOME") "/Documents/todo/")))

org-chronicle

(elpaca-use-package org-chronicle
  :straight (org-chronicle :host github :repo "progfolio/org-chronicle")
  :commands (org-chronicle)
  :custom (org-chronicle-directory "~/Documents/journal/")
  (org-chronicle-file-format-string "%Y.%m.%d"))

org-clean-refile

(elpaca-use-package (org-clean-refile :host github :repo "progfolio/org-clean-refile" :protocol ssh)
  :commands (org-clean-refile)
  :after (org)
  :general
  (global-leader
    :keymaps 'org-mode-map
    "sr" 'org-clean-refile))

org-contrib

(elpaca-use-package org-contrib)

org-fancy-priorities

A minor mode that displays org priorities as custom strings.

https://github.com/harrybournis/org-fancy-priorities

(elpaca-use-package org-fancy-priorities
  :commands (org-fancy-priorities-mode)
  :hook (org-mode . org-fancy-priorities-mode)
  :diminish ""
  :config
  ;;"Eisenhower Matrix of Importance and Urgency"
  (defvar +org-fancy-priorities-eisenhower-matrix
    "↑ |-----------+-----------|
I |   Eisenhower Matrix   |
M |-----------+-----------|
P |           |           |
O | Schedule  | Immediate |
R |           |           |
T |-----------+-----------|
A |           |           |
N | Eliminate | Delegate  |
C |           |           |
E |-----------+-----------|
          URGENCY →"
    "Eisenhower Matrix help text.")
  (setq org-fancy-priorities-list
        (mapcar
         (lambda (cell) (format (car cell)
                                (propertize
                                 (cdr cell)
                                 'help-echo +org-fancy-priorities-eisenhower-matrix)))
         '(("I∧U (%s)" . "I")
           ("I¬U  (%s)" . "S")
           ("¬IU  (%s)" . "D")
           ("¬I¬U (%s)" . "E")))))

org-habit

(use-feature org-habit
  :after (org)
  :config
  (defun +org-habit-graph-on-own-line (graph)
    "Place org habit consitency graph below the habit."
    (let* ((count 0)
           icon)
      (save-excursion
        (beginning-of-line)
        (while (and (eq (char-after) ? ) (not (eolp)))
          (when (get-text-property (point) 'display) (setq icon t))
          (setq count (1+ count))
          (forward-char)))
      (add-text-properties (+ (line-beginning-position) count) (line-end-position)
                           `(display ,(concat (unless icon "  ")
                                              (string-trim-left (thing-at-point 'line))
                                              (make-string (or org-habit-graph-column 0) ? )
                                              (string-trim-right
                                               (propertize graph 'mouse-face 'inherit)))))))
  <<org-habit-graph-placement-advice>>
  :custom
  <<org-habit-custom>>)
(integerp nil)

:custom

(org-habit-today-glyph #x1f4c5)
(org-habit-completed-glyph #x2713)
(org-habit-preceding-days 29)
(org-habit-following-days 1)
(org-habit-graph-column 3)
(org-habit-show-habits-only-for-today nil)

habits on their own line

I’ve submitted a patch to customize consistency graph placement in the agenda. Rather than constantly rebase my patch on top of the latest Org, I’m adding advice to override the default placement.
(defun +org-habit-insert-consistency-graphs (&optional line)
  "Insert consistency graph for any habitual tasks."
  (let ((inhibit-read-only t)
        (buffer-invisibility-spec '(org-link))
        (moment (org-time-subtract nil
                                   (* 3600 org-extend-today-until))))
    (save-excursion
      (goto-char (if line (point-at-bol) (point-min)))
      (while (not (eobp))
        (let ((habit (get-text-property (point) 'org-habit-p)))
          (when habit
            (let ((graph (org-habit-build-graph
                          habit
                          (time-subtract moment (days-to-time org-habit-preceding-days))
                          moment
                          (time-add moment (days-to-time org-habit-following-days)))))
              (+org-habit-graph-on-own-line graph))))
        (forward-line)))))

(advice-add #'org-habit-insert-consistency-graphs
            :override #'+org-habit-insert-consistency-graphs)

org-indent

(use-feature org-indent
  :diminish ""
  :after (org)
  :hook (org-mode . org-indent-mode))

refile

This function allows me to refile within the currently open org files as well as agenda files. Useful for structural editing. Stolen from: stackoverflow: how to org-refile to a target within the current file?

(defun +org-files-list ()
  "Returns a list of the file names for currently open Org files"
  (delq nil
        (mapcar (lambda (buffer)
                  (when-let* ((file-name (buffer-file-name buffer))
                              (directory (file-name-directory file-name)))
                    (unless (string-suffix-p "archives/" directory)
                      file-name)))
                (org-buffer-list 'files t))))
(setq +org-max-refile-level 20)
(setq org-outline-path-complete-in-steps nil
      org-refile-allow-creating-parent-nodes 'confirm
      org-refile-use-outline-path 'file
      org-refile-targets `((org-agenda-files  :maxlevel . ,+org-max-refile-level)
                           (+org-files-list :maxlevel . ,+org-max-refile-level)))

settings

(setq org-agenda-files '("~/Documents/todo")
      org-agenda-text-search-extra-files '(agenda-archives)
      org-catch-invisible-edits 'show-and-error
      org-confirm-babel-evaluate nil
      org-enforce-todo-dependencies t
      org-hide-emphasis-markers t
      org-hierarchical-todo-statistics nil
      org-log-done 'time
      org-log-reschedule t
      org-return-follows-link t
      org-reverse-note-order t
      org-src-tab-acts-natively t
      org-file-apps
      '((auto-mode . emacs)
        ("\\.mm\\'" . default)
        ("\\.mp[[:digit:]]\\'" . "/usr/bin/mpv --force-window=yes %s")
        ;;("\\.x?html?\\'" . "/usr/bin/firefox-beta %s")
        ("\\.x?html?\\'" . "/usr/bin/bash -c '$BROWSER  %s'")
        ("\\.pdf\\'" . default)))

Set clock report duration format to floating point hours

;;(setq org-duration-format  '(h:mm))
(setq org-duration-format '(("h" . nil) (special . 2)))

‘TODO’ Keywords

org-mime

org-mime can be used to send HTML email using Org-mode HTML export.

https://github.com/org-mime/org-mime

(use-feature org-mime
  :after (org)
  :commands (org-mime-htmlize
             org-mime-org-buffer-htmlize
             org-mime-org-subtree-htmlize)
  :config
  (setq org-mime-export-options '( :with-latex dvipng
                                   :section-numbers nil
                                   :with-author nil
                                   :with-toc nil)))

org-make-toc

This package makes it easy to have one or more customizable tables of contents in Org files. They can be updated manually, or automatically when the file is saved. Links to headings are created compatible with GitHub’s Org renderer.

https://github.com/alphapapa/org-make-toc

(elpaca-use-package org-make-toc
  :commands (org-make-toc))

org-region-link

(elpaca-use-package (org-region-link :host github :repo "progfolio/org-region-link" :protocol ssh)
  :after (org))

org-roam

(elpaca-use-package (org-roam :host github :repo "org-roam/org-roam")
  :disabled t
  :general
  (+general-global-application
    "or" '(:ignore t :which-key "org-roam-setup"))
  :init (setq org-roam-v2-ack t))

org-relativity

(elpaca-use-package org-relativity
  :after (org)
  :straight (:type git :host github :repo "progfolio/org-relativity"))

org-superstar

Prettify headings and plain lists in Org mode. This package is a direct descendant of ‘org-bullets’

https://github.com/integral-dw/org-superstar-mode

(elpaca-use-package (org-superstar :host github :repo "integral-dw/org-superstar-mode")
  :after (org))

ox-gfm

Github flavored Markdown back-end for Org export engine

https://github.com/larstvei/ox-gfm

(elpaca-use-package ox-gfm :defer t)

ox-twbs

Export org-mode docs as HTML compatible with Twitter Bootstrap.

https://github.com/marsmining/ox-twbs

(elpaca-use-package ox-twbs
  :disabled t
  :after (org)
  :defer t)

add export-define-derived-backend

package-lint

This library provides a linter for the metadata in Emacs Lisp files which are intended to be packages. You can integrate it into your build process.

https://github.com/purcell/package-lint

(elpaca-use-package package-lint
  :defer t
  :commands (package-lint-current-buffer +package-lint-elpaca)
  :config
  <<+package-lint-elpaca>>)

+package-lint-elpaca

package-lint assumes package.el is the package manager. I use elpaca.el, so I get spurious warnings about uninstallable packages. This workaround creates a temporary package archive and enables package.el to appease package-lint.
(defun +package-lint-elpaca ()
  "Help package-lint deal with elpaca."
  (interactive)
  (require 'package)
  (setq package-user-dir "/tmp/elpa")
  (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
  (package-initialize)
  (package-refresh-contents))

(+package-lint-elpaca)

paren

I want to have matching delimiters highlighted when point is on them so that I can make sure they’re balanced easily.

(use-feature paren
  :defer 1
  :config (show-paren-mode))

projectile

Projectile is a project interaction library for Emacs. Its goal is to provide a nice set of features operating on a project level without introducing external dependencies (when feasible).

https://github.com/bbatsov/projectile

(elpaca-use-package projectile
  :after (general)
  :general
  (+general-global-project
    "!" 'projectile-run-shell-command-in-root
    "%" 'projectile-replace-regexp
    "&" 'projectile-run-async-shell-command-in-root
    "A" 'projectile-toggle-between-implementation-and-test
    "bn" 'projectile-next-project-buffer
    "bp" 'projectile-previous-project-buffer
    "c" 'projectile-compile-project
    "D" 'projectile-dired
    "e" 'projectile-edit-dir-locals
    "g" 'projectile-find-tag
    "G" 'projectile-regenerate-tags
    "I" 'projectile-invalidate-cache
    "k" 'projectile-kill-buffers
    "R" 'projectile-replace
    "s" 'projectile-save-project-buffers
    "T" 'projectile-test-project
    "v" 'projectile-vc)
  :config
  (add-to-list 'projectile-globally-ignored-directories "*node_modules")
  (projectile-mode))

pdf-tools

PDF Tools is, among other things, a replacement of DocView for PDF files. The key difference is that pages are not pre-rendered by e.g. ghostscript and stored in the file-system, but rather created on-demand and stored in memory.

https://github.com/politza/pdf-tools#about-this-package

This allows me to customize the color of the generated pdf.

(elpaca-use-package
    (pdf-tools :pre-build ("./server/autobuild") :files (:defaults "server/epdfinfo"))
  :functions (pdf-isearch-batch-mode)
  :commands (pdf-tools-install pdf-view-mode)
  :custom (pdf-view-midnight-colors '("#AFA27C" . "#0F0E16"))
  :config (add-hook 'pdf-view-mode-hook
                    (lambda ()
                      ;; get rid of borders on pdf's edges
                      (set (make-local-variable 'evil-normal-state-cursor) (list nil))
                      ;;for fast i-search in pdf buffers
                      (pdf-isearch-minor-mode)
                      (pdf-isearch-batch-mode)
                      (pdf-view-dark-minor-mode)
                      (pdf-view-midnight-minor-mode)))
  :mode (("\\.pdf\\'" . pdf-view-mode)))

rainbow-mode

Colorize color names in buffers

https://elpa.gnu.org/packages/rainbow-mode.html

(elpaca-use-package rainbow-mode
  :commands (rainbow-mode))

re-builder (regular expressions)

Emacs has a horrible regexp syntax. A tool called re-builder allows you to live preview regular expressions. This variable reduces some of the escaping necessary when building regular expressions.

(use-feature re-builder
  :custom
  (reb-re-syntax 'rx)
  :commands (re-builder))

recentf

I want to have more recent files saved. This was originally set to ten, but opening my org agenda files wipes that list out.

(use-feature recentf
  :defer 1
  :custom
  (recentf-max-menu-items 1000 "Offer more recent files in menu")
  (recentf-max-saved-items 1000 "Save more recent files"))

sendmail

(use-feature sendmail
  :defer t
  :custom (send-mail-function 'smtpmail-send-it "inform emacs-bug-report how we want to send mail"))

shackle

shackle gives you the means to put an end to popped up buffers not behaving they way you’d like them to.

https://depp.brause.cc/shackle/

(elpaca-use-package (shackle :depth nil)
  :commands (shackle-mode)
  :custom (shackle-rules '(("*Flycheck errors*"  :align below :size 0.15)
                           ("\\`\\*Flymake diagnostics.*?\\*\\'" :align below :size 0.15 :regexp t :same nil)
                           ("*accord*" :align below :size 0.20)
                           ("*padscape*" :align below :size 0.20)))
  :hook ((flycheck-mode global-flycheck-mode flymake-mode accord-mode padscape-mode) . shackle-mode))

shr-color

(use-feature shr-color
  :custom
  (shr-color-visible-luminance-min 85 "For clearer email/eww rendering of bg/fg colors")
  (shr-use-colors nil "Don't use colors (for HTML email legibility)"))

skip-buffers

(elpaca-use-package (skip-buffers :host github :repo "progfolio/skip-buffers" :protocol ssh)
  :defer 10
  :config
  (add-to-list 'skip-buffers-blacklist "*Help*")
  (add-to-list 'skip-buffers-blacklist "*Calendar*")
  (global-skip-buffers-mode))

smtpmail

(use-feature smtpmail
  :custom
  (smtpmail-queue-mail nil))

stardict-utils

(elpaca-use-package (stardict-utils :host github :repo "progfolio/stardict-utils" :protocol ssh)
  :after (general helm)
  :commands (stardict-define)
  :general
  (global-definer
    "W" '(stardict-define :which-key "define word"))
  (+general-global-application
    "D" '((lambda () (interactive) (stardict-define nil)) :which-key "dictionary"))
  (+general-global-text
    "d" '(stardict-define :which-key "dictionary")))

straight.el

(elpaca (straight.el :host github
                     :depth nil
                     :repo "raxod502/straight.el"
                     :branch "develop"
                     :files ("straight*.el")
                     :protocol ssh
                     :remotes ("origin"
                               ("fork" :repo "progfolio/straight.el"))))

tab-bar

(use-feature tab-bar
  :custom
  (tab-bar-close-button-show nil "Dont' show the x button on tabs")
  (tab-bar-new-button-show   nil)
  ;;(tab-bar-show   1 "only show tab bar when more than one tab")
  :config (tab-bar-mode)
  :general
  (+general-global-tab
    "b" 'tab-bar-history-back
    "d" 'tab-bar-close-tab
    "f" 'tab-bar-history-forward
    "N" 'tab-bar-new-tab
    "n" 'tab-bar-switch-to-next-tab
    "p" 'tab-bar-switch-to-prev-tab
    "L" '((lambda (arg) (interactive "p") (tab-bar-move-tab arg))
          :which-key "tab-bar-move-tab-right")
    "l" 'tab-bar-switch-to-next-tab
    "H" '((lambda (arg) (interactive "p") (tab-bar-move-tab (- arg)))
          :which-key "tab-bar-move-tab-left")
    "h" 'tab-bar-switch-to-prev-tab
    "r" 'tab-bar-rename-tab
    "t" 'tab-bar-switch-to-tab
    "u" 'tab-bar-undo-close-tab
    "O" 'tab-bar-close-other-tabs
    "w" 'tab-bar-move-tab-to-frame))

tab-line

(use-feature tab-line
  :custom
  (tab-line-close-button-show nil)
  (tab-line-new-button-show   nil))

tern (build fails)

Tern is a stand-alone, editor-independent JavaScript analyzer that can be used to improve the JavaScript integration of existing editors.

https://github.com/ternjs/tern

(elpaca-use-package tern
  :disabled t
  :commands (tern-mode)
  :hook (js2-mode . tern-mode))

joymacs

(elpaca-use-package (joymacs :host github :repo "skeeto/joymacs"
                             :main "joydemo.el"
                             :pre-build ("make")
                             :files (:defaults "joymacs.c" "joymacs.so")
                             :remotes (("fork" :repo "progfolio/joymacs")
                                       "origin"))
  :defer t)

padscape

(elpaca-use-package (padscape :host github :repo "progfolio/padscape" :protocol ssh)
  :commands (padscape))

speedo

(elpaca-use-package (speedo :host github :repo "progfolio/speedo"
                            :local-repo "speedo"
                            :depth nil :protocol ssh
                            :files (:defaults "test"))
  :commands (speedo speedo-load-file akogare)
  :custom
  (speedo-directory "~/.emacs.d/elpaca/repos/speedo/test/")
  (speedo-default-splits-file "./Akogare-Mario-World.spd")
  (speedo-confirm-evaluate nil)
  :general
  (+general-global-application
    "s" '(:ignore t :which-key "speedo")
    "ss" 'speedo
    "sl" 'speedo-load-file)
  :config
  (defun akogare ()
    (interactive)
    (speedo)
    (tab-bar-mode -1)
    (padscape))

  (evil-make-intercept-map speedo-mode-map)

  (defvar +speedo-debounce-interval 0.5)
  (defvar +speedo-debounce-timer nil)
  (defun +speedo-debounced-mistake (advised)
    "Execute `speedo-mistake' after last key press.
This allows me to spam the button to get through the retry screen
as fast as possible without recording multiple mistakes."
    (when +speedo-debounce-timer (cancel-timer +speedo-debounce-timer))
    (setq +speedo-debounce-timer (run-at-time +speedo-debounce-interval nil advised)))
  (advice-add 'speedo-mistake :around #'+speedo-debounced-mistake)

  (defun +speedo-ensure-controller-support ()
    "Launch controller program if it isn't already running."
    (interactive)
    (when (string-empty-p (shell-command-to-string "pgrep antimicrox"))
      (make-process
       :name "antimicrox"
       :noquery t ; Don't ask to kill this process when exiting Emacs.
       :buffer "*antimicrox*"
       :command '("antimicrox" "--tray"))))
  (add-hook 'speedo-mode-hook #'+speedo-ensure-controller-support))

(use-feature speedo-review
  :defer t
  :general
  (+general-global-application
    "sr"   '(:ignore t :which-key "review")
    "srr"  'speedo-review
    "srt"  'speedo-review-top-runs
    "srl"  '(:ignore t :which-key "review-last")
    "srlr" 'speedo-review-last-runs
    "srla" 'speedo-review-last-attempts)
  :config
  (evil-make-intercept-map speedo-review-mode-map))

(use-feature speedo-edit
  :defer t
  :config
  (evil-make-intercept-map speedo-edit-mode-map))

time

I like to see the date and time in my mode line. I use doom-modeline for the rest of my mode line configuration.

(use-feature time
  :custom
  (display-time-day-and-date t "Show date, day, and time")
  :config
  (display-time))

tramp

(use-feature tramp
  :defer t
  :custom (tramp-terminal-type "tramp")
  :config (setq debug-ignored-errors (cons 'remote-file-error debug-ignored-errors)))

vc-hooks

You probably want this 99% of the time and it will skip an annoying prompt.

(use-feature vc-hooks
  :custom
  (vc-follow-symlinks t "Visit real file when editing a symlink without prompting."))

vterm

Emacs-libvterm (vterm) is fully-fledged terminal emulator inside GNU Emacs based on libvterm, a C library.

https://github.com/akermu/emacs-libvterm

(elpaca-use-package (vterm :post-build
                           (progn
                             (setq vterm-always-compile-module t)
                             (require 'vterm)
                             ;;print compilation info for elpaca
                             (with-current-buffer (get-buffer-create vterm-install-buffer-name)
                               (goto-char (point-min))
                               (while (not (eobp))
                                 (message "%S"
                                          (buffer-substring (line-beginning-position)
                                                            (line-end-position)))
                                 (forward-line)))
                             (when-let ((so (expand-file-name "./vterm-module.so"))
                                        ((file-exists-p so)))
                               (make-symbolic-link
                                so (expand-file-name (file-name-nondirectory so)
                                                     "../../builds/vterm")
                                'ok-if-already-exists))))
  :commands (vterm vterm-other-window)
  :general
  (+general-global-application
    "t" '(:ignore t :which-key "terminal")
    "tt" 'vterm-other-window
    "t." 'vterm)
  :config
  (evil-set-initial-state 'vterm-mode 'emacs))

which-key

which-key is a minor mode for Emacs that displays the key bindings following your currently entered incomplete command (a prefix) in a popup.

https://github.com/justbur/emacs-which-key

(elpaca-use-package which-key
  :demand t
  :init
  (setq which-key-enable-extended-define-key t)
  :config
  (which-key-mode)
  :custom
  (which-key-side-window-location 'bottom)
  (which-key-sort-order 'which-key-key-order-alpha)
  (which-key-side-window-max-width 0.33)
  (which-key-idle-delay 0.05)
  :diminish which-key-mode)

wikinforg

(elpaca-use-package (wikinfo :host github :repo "progfolio/wikinfo"
                             :branch "develop" :protocol ssh :depth nil)
  :defer t)
(elpaca-use-package (wikinforg :host github :repo "progfolio/wikinforg"
                               :protocol ssh :depth nil)
  :commands (wikinforg wikinforg-capture)
  :custom
  (wikinforg-include-thumbnail t)
  (wikinforg-post-insert-hook '(org-redisplay-inline-images))
  (wikinforg-thumbnail-directory
   (expand-file-name "wikinforg" user-emacs-directory))
  :config
  (add-hook 'wikinforg-mode-hook #'visual-line-mode)
  (add-hook 'wikinforg-mode-hook #'olivetti-mode)
  (add-hook 'wikinforg-mode-hook (lambda () (writegood-mode -1)))
  ;; So we can bury temp buffers without evil bindings taking precedence
  (evil-make-intercept-map wikinforg-mode-map))

winner

(use-feature winner
  :defer 5
  :general
  (+general-global-window
    "u" 'winner-undo
    "r" 'winner-redo)
  :config (winner-mode))

window

(use-feature window
  :custom (switch-to-buffer-obey-display-actions t))

wordel

(elpaca-use-package (wordel :host github :repo "progfolio/wordel"
                            :files (:defaults "words") :depth nil :protocol ssh)
  :defer t
  :config
  (evil-make-intercept-map wordel-mode-map)
  (evil-set-initial-state  'wordel-mode 'insert)
  (evil-make-intercept-map wordel-select-mode-map)
  (evil-set-initial-state  'wordel-select-mode 'insert))

wordnut

An Emacs interface to the wordnet (wn) command line tool.

https://github.com/gromnitsky/wordnut

(elpaca-use-package wordnut
  :general
  (+general-global-application
    "w"    '(:ignore t :which-key "wordnut")
    "ws"   'wordnut-search
    "ww"   'wordnut-lookup-current-word))

writegood

This is a minor mode to aid in finding common writing problems.

https://github.com/bnbeckwith/writegood-mode

(elpaca-use-package writegood-mode
  :commands (writegood-mode)
  :hook (org-mode))

yasnippet

YASnippet is a template system for Emacs. It allows you to type an abbreviation and automatically expand it into function templates.

https://github.com/joaotavora/yasnippet

(elpaca-use-package yasnippet
  :commands (yas-global-mode)
  :custom
  (yas-snippet-dirs '("~/.emacs.d/snippets")))

zerodark-theme

A dark theme for Emacs, inspired from Niflheim and One Dark

https://github.com/NicolasPetton/zerodark-theme

(elpaca-use-package zerodark-theme :defer t)

yodel

(elpaca-use-package (yodel :host github :repo "progfolio/yodel" :depth nil :protocol ssh)
  :defer t)

spiel

(elpaca-use-package (spiel :host github :repo "progfolio/spiel" :depth nil :protocol ssh)
  :defer t
  :config
  (with-eval-after-load "evil"
    (when (fboundp 'evil-set-initial-state)
      (evil-set-initial-state 'spiel-input-mode 'insert))))

greg

(elpaca-use-package (greg :host github :repo "progfolio/greg"
                          :depth nil :protocol ssh
                          :files (:defaults "assets")
                          :defer t))

About

Emacs literate config

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Emacs Lisp 99.1%
  • Other 0.9%