2024-10-28 Command alternatives

Today I’d like to write about an Emacs feature I didn’t know about, even though it’s part of Emacs since quite some time – it appeared in version 24.4, which means it is over 10 years old! It seems I’m not the only one who didn’t know this exists – I’ve just searched my ~/.emacs.d/elpa directory (which contains almost a hundred packages now!), and none of the packages I have installed there uses it, either.

Assume you want to define a user command dired-play which plays a media file the point is on in Dired. There are several ways to play a file, though – you could use mplayer, vlc, or mpv (the latter being probably the best choice, but that’s another topic). You can define three commands – dired-play-mplayer, dired-play-vlc and dired-play-mpv – and allow the user some way to choose one (most probably via an option declared using defcustom). There is, however, an alternative (pun totally intended!) to a defcustom! Let’s define the three commands (for simplicity, they will be just dummies, and I won’t include docstrings for the sake of brevity) and use define-alternatives to allow the user to choose one of them.

(defun dired-play-mplayer ()
  (interactive)
  (message "playing the sound using mplayer"))

(defun dired-play-vlc ()
  (interactive)
  (message "playing the sound using vlc"))

(defun dired-play-mpv ()
  (interactive)
  (message "playing the sound using mpv"))

(defvar dired-play-alternatives '(("MPlayer" . dired-play-mplayer)
                                    ("VLC" . dired-play-vlc)
                                    ("mpv" . dired-play-mpv)))

(define-alternatives dired-play)

Now the user can say M-x dired-play (of course, in practice this would be bound to some key in dired-mode-map, and Emacs will ask them to choose one of the players. From now on, every invocation of dired-play will use the selected player. Should the user want to change their choice, they can just invoke dired-play with a prefix argument. How cool is that?

One thing I don’t like about this feature is that it silently uses customize-save-variable to persist the customization. This means that it modifies and saves my init.el behind the scenes. I’m not a fan of Emacs modifying my init file, but here it is. (Admittedly, it does make sense in this particular case.)

So, that’s basically it for today. Command alternatives seems a nice (and heavily underused) feature of Emacs – not a single one file in Emac core repository uses it, and not a single one of almost 90 packages I have installed in my Emacs uses it, either. Still, it’s there in case you need it.

CategoryEnglish, CategoryBlog, CategoryEmacs