Drew Adams has been quietly maintaining a sprawling collection of Emacs extensions for decades. Most of them never made it into MELPA. None made it into Guix. They live almost exclusively on emacsmirror — the GitHub mirror of EmacsWiki — and getting them onto a modern Emacs setup is, in practice, a straight.el job.

The trap is that installation is the easy part. Loading is where the silent killer is.

Who Drew Adams is

Drew has been contributing to GNU Emacs since the early 1990s and has written what is arguably the largest single-author body of Emacs Lisp ever shipped. The packages range from small utility libraries (hexrgb, strings, naked, zones) to substantial extensions of built-in modes (dired+, info+, isearch+, replace+, help-fns+) to complete reimaginings (icicles for completion, bookmark+ for bookmark management, highlight as a region/text-property-aware highlight system). Many of these predate the equivalents the modern community converged on; some have features the modern equivalents still lack.

Drew curated his releases on the EmacsWiki for years. EmacsWiki has been periodically scraped to the emacsmirror GitHub organization, which is the de facto canonical archive today. Drew's own page, if you want the original prose alongside each release, is still https://www.emacswiki.org/emacs/DrewAdams.

Where they live, and how to get them

Almost every Drew package lives under github.com/emacsmirror/<name>. The naming convention on emacsmirror replaces + with -plus — so dired+ is at emacsmirror/dired-plus, help-fns+ at emacsmirror/help-fns-plus, thingatpt+ at emacsmirror/thingatpt-plus. The packages without + in their name (icicles, bookmark+ is also at emacsmirror/bookmark-plus, highlight, thing-cmds, misc-cmds, lacarte, apu) keep their plain names.

straight.el can clone any of them with the recipe (name :type git :host github :repo "emacsmirror/repo-name"). Below is a complete init-straight.el sketch.

A note on Emacs version

These packages have been a moving target as Emacs evolves, and any one of them can fall behind a release. On a release Emacs (≤ 30) almost everything below works as written. On Emacs master — which is currently Emacs 31 — most packages still work, but dired+ is currently broken. Drew hasn't caught up with recent built-in Dired changes yet, and loading dired+ on Emacs 31 will error out.

I'm on master myself, self-compiled, having recently moved off package-manager-managed Emacs to a bleeding-edge tree. If you're in the same boat, drop dired+ (and find-dired+) from the recipe set below until Drew ships a fix; the rest of the ecosystem is still good. If you're on a release Emacs the recipes work as-is.

The silent killer

straight.el will clone every Drew package you list without complaint. The clones go into ~/.emacs.d/straight/repos/; the build step generates autoloads; the load path gets pointed at the right places. Everything looks healthy.

Then, depending on the order in which you require them, you will see one of three things:

  • A cryptic void-function or void-variable deep inside a dispatch path, often inside a built-in mode that Drew's package was supposed to enhance.
  • A feature that installs but silently doesn't apply: the highlight commands are defined but no keys are bound, the dired enhancements are loaded but Dired buffers look untouched.
  • A real init-time crash on some other feature later in startup, with a backtrace that obviously doesn't mention Drew at all because the actual mistake was three requires earlier.

The cause is always the same: Drew's packages have a thick internal dependency graph, and many of them register hooks or modify keymaps at load time. Load help-fns+ before naked is on the path and it errors out. Load dired+ before Dired itself has been autoloaded and it can't attach. Load highlight after a package that grabs C-x X and the binding silently never installs.

straight.el will not warn you about any of this. It loads what you tell it, in the order you tell it.

The four-tier discipline

The mental model that has worked for me: split the packages into four tiers based on what they need and when they should attach.

TierExamplesWhen to load
T0 hexrgb, strings, naked, zones, thingatpt+, wid+ Never required directly. Just install — T1+ packages pull them in transitively.
T1 icicles, bookmark+, highlight, pp+ Eager require at startup. These hook into early state and need to be visible by the time later modules load.
T2 help-fns+ Eager require, but only after T0 and T1 are on the path (depends on naked, wid+).
T3 dired+, info+, isearch+, replace+, find-dired+ with-eval-after-load on the corresponding built-in mode. They enhance Dired / Info / Isearch / Replace and shouldn't try to attach before those modes exist.

A handful of packages — thing-cmds, misc-cmds, lacarte, apu — are autoloaded by their own commands and don't need an explicit require. straight's autoload generation handles them fine.

Example init-straight.el

Group the clones by tier in the same file. The clones happen in whatever order, but co-locating them by tier makes the load order in init.el obvious to your future self.

;; init-straight.el — Drew Adams ecosystem from emacsmirror.

(straight-use-package
 '(use-package :type git :host github :repo "jwiegley/use-package"))

;; --- T0: utility libraries (transitive deps; not required directly) ---
(straight-use-package
 '(hexrgb     :type git :host github :repo "emacsmirror/hexrgb"))
(straight-use-package
 '(naked      :type git :host github :repo "emacsmirror/naked"))
(straight-use-package
 '(strings    :type git :host github :repo "emacsmirror/strings"))
(straight-use-package
 '(zones      :type git :host github :repo "emacsmirror/zones"))
(straight-use-package
 '(thingatpt+ :type git :host github :repo "emacsmirror/thingatpt-plus"))
(straight-use-package
 '(wid+       :type git :host github :repo "emacsmirror/wid-plus"))

;; --- T1: eager require at startup ---
(straight-use-package
 '(icicles    :type git :host github :repo "emacsmirror/icicles"))
(straight-use-package
 '(bookmark+  :type git :host github :repo "emacsmirror/bookmark-plus"))
(straight-use-package
 '(highlight  :type git :host github :repo "emacsmirror/highlight"))
(straight-use-package
 '(pp+        :type git :host github :repo "emacsmirror/pp-plus"))

;; --- T2: eager, depends on T0/T1 ---
(straight-use-package
 '(help-fns+  :type git :host github :repo "emacsmirror/help-fns-plus"))

;; --- T3: eval-after-load on the built-in mode ---
(straight-use-package
 '(dired+     :type git :host github :repo "emacsmirror/dired-plus"))
(straight-use-package
 '(find-dired+ :type git :host github :repo "emacsmirror/find-dired-plus"))
(straight-use-package
 '(info+      :type git :host github :repo "emacsmirror/info-plus"))
(straight-use-package
 '(isearch+   :type git :host github :repo "emacsmirror/isearch-plus"))
(straight-use-package
 '(replace+   :type git :host github :repo "emacsmirror/replace-plus"))

;; --- Autoloaded; install only, no explicit require needed ---
(straight-use-package
 '(thing-cmds :type git :host github :repo "emacsmirror/thing-cmds"))
(straight-use-package
 '(misc-cmds  :type git :host github :repo "emacsmirror/misc-cmds"))
(straight-use-package
 '(lacarte    :type git :host github :repo "emacsmirror/lacarte"))
(straight-use-package
 '(apu        :type git :host github :repo "emacsmirror/apu"))

(provide 'init-straight)

Example init.el (the load-order half)

This is the load order. Don't reorder casually.

;; init.el (partial)

(require 'init-straight)        ; clones from emacsmirror; defines load-path

;; T1 — eager
(require 'icicles)              ; M-x icy-mode to toggle on demand
(require 'bookmark+)
(require 'highlight)
(require 'pp+)

;; T2 — eager, requires T0/T1 to already be in place
(require 'help-fns+)

;; T3 — attach to the built-in mode when it loads
(with-eval-after-load 'dired    (require 'dired+))
(with-eval-after-load 'info     (require 'info+))
(with-eval-after-load 'isearch  (require 'isearch+))
(with-eval-after-load 'replace  (require 'replace+))

;; thing-cmds, misc-cmds, lacarte, apu — autoloaded by their own commands.
;; No require needed. M-x apropos-unicode, M-@, F10 will pull them in.

What you get

A non-exhaustive tour of the highlights, for anyone weighing whether it's worth the load-order discipline:

  • help-fns+C-h M-f describe-file, C-h M-k describe-keymap, C-h M-l find-function-on-key. Once you've used describe-keymap, vanilla C-h k feels like reading by candlelight.
  • pp+M-: becomes pretty-printed pp-eval-expression. The right default.
  • highlightC-x X prefix; C-S-p / C-S-n jump to previous / next highlight. A region/text-property highlight system that survives buffer state in ways font-lock can't.
  • dired+ — substantially extends Dired; loads find-dired+; reuses dir buffers; many small ergonomic wins.
  • info+ — Info mode with node bookmarking, history, tooltips on cross-references. If you read Info often, this is non-optional.
  • isearch+ — adds character-property search, region-as-default, and a host of small tweaks. Subtle but pervasive.
  • bookmark+ — bookmark management on steroids; tags, sorting, multiple bookmark files, persistent annotation. C-x r l list, C-x r m add.
  • thing-cmdsM-@ cycles selection of "things" (word, sentence, list, defun) progressively. C-M-SPC selects a thing.
  • lacarteF10 or ESC M-x executes commands by walking the menubar with completion. Useful for discovering modes you don't use often.
  • apuM-x apropos-unicode. Interactive Unicode character lookup with name search.

icicles: install but leave it off by default

Special case worth its own section. icicles is Drew's completion framework with progressive narrowing — peel a 10k-element completion list down by stages, with feedback at each step. It's genuinely powerful and predates most of the modern minibuffer-completion stack by years.

But the modern stack — vertico + orderless + marginalia + consult — has converged in a different direction and, for everyday work, will probably feel more comfortable. If you're already at home with that stack and like it (I am, and I do), install icicles but leave icy-mode off. Toggle it on only when you want to explore what progressive narrowing actually feels like, or when you've decided you want that specific shape for a session.

If you're already committed to icicles — some people structure their entire Emacs interaction around it — flip the default and ignore the modern stack. The two don't compose well; pick one and live with the choice.

One closing note on pinning

By default straight clones the current head of each emacsmirror checkout on first load. For a config that gets rebuilt rarely and cleanly, that has been fine. If one of Drew's packages introduces a breaking change between rebuilds, M-x straight-freeze-versions writes straight/versions/default.el — commit that file and you have a reproducible snapshot. Most people, including me, run unpinned until a specific incident makes pinning earn its keep.

The load-order discipline above is what straight.el cannot do for you. Once it's in place, the rest is just enjoying the work of someone who has been improving Emacs longer than most of us have been writing software.

Ara