Convention around package extensions

Often times, there may be little additions that you would like to include with your Emacs package but aren’t necessarily large or significant enough to warrant their own package. For example, Marginalia annotations. I wouldn’t want a dependency for this and this is often only a handful of lines of Elisp and not seem worthy of a package, but also find the too useful to not include and encourage others to use.

Documentation snippet

One solution is to just include the small snippet in the documentation somewhere, which I have done for some things. The down side to this is it makes it harder to keep up to date since it’s not in an easy place to automatically evaluate and test.

Unpublished package

Alternatively, you can write an entire package and publish the repository, but not list it in a package repository. This is nice, since it allows the user to include the package however they like.

Extensions directory

I know some packages like Vertico include an extensions/ directory for this kind of stuff. This seems to be the best solution I’ve seen, but I find the recipe syntax to include the extension clumsy and difficult to remember.

(Dream) Recipe support

It would be nice if there was some official recipe support to minor package extensions without bogging down the wonderful package repository maintainers, but I suppose that’s really up to the package managers themselves to implement new syntax. Something like:

(vertico :extensions ("vertico-buffer.el"))

Anyway, I’m curious what y’all think. Do you think this is even a problem? What is your opinion on how to handle small package extensions? Or am I overlooking something entirely?

Why not just include that into the package body? One doesn’t have to use the entirety of the package, just the necessary pieces.

I wouldn’t want to include it in the main body because it would introduce a new dependency that I wouldn’t want to force on users of they’re not interested in that feature. I guess an optional require could be used.

In this case I like making the dependency optional. E.g. the pattern I use for optional evil keymaps:

(declare-function evil-define-key* "evil-core")


(defvar biome-api-error-mode-map
  (let ((keymap (make-sparse-keymap)))
    (define-key keymap (kbd "q") #'biome-error-quit)
    (when (fboundp 'evil-define-key*)
      (evil-define-key* 'normal keymap
        "q" #'biome-error-quit))
  "Keymap for `biome-api-error-mode'.")

declare-function serves to silence the byte compiler.

Generally the pattern is to use with-eval-after-load around the code for the other package, and various defvar and declare-function forms to silence the compilation warnings. Alternatively, put it in a separate file and instruct users to manually load the file if they use that package.

1 Like

Thanks y’all. This is helpful