index all rss twitter github linkedin email

Álvaro Ramírez

03 November 2019 A more reusable Emacs shell-command history

Cameron Desautel has a great post on Working Faster in Emacs by Reading the "Future", highlighting M-n's usefulness for inserting minibuffer default values.

Invoking M-n in shell-command's prompt is handy for quickly getting the current buffer's file name. This works great for one-off shell commands like "chmod +x script.sh" or "tidy -xml -i -m data.xml". Unfortunately, these commands aren't easily reusable from shell-command's minibuffer history, since it'll keep hardcoded file names.

There's likely existing built-in functionality or a more elaborate package for this, but advising read-shell-command enables us to write more reusable commands like "chmod +x $f" or "tidy -xml -i -m $f". We merely replace $f with (buffer-file-name), and let everything else continue as usual.

expanded-shell-command.png

(defun ar/adviced-read-shell-command (orig-fun &rest r)
  "Advice around `read-shell-command' to replace $f with buffer file name."
  (let ((command (apply orig-fun r)))
    (if (string-match-p "\\$f" command)
        (replace-regexp-in-string "\\$f"
                                  (or (buffer-file-name)
                                      (user-error "No file file visited to replace $f"))
                                  command)
      command)))

(advice-add 'read-shell-command
            :around
            'ar/adviced-read-shell-command)

It's worth mentioning that searching minibuffer history is pretty simple when leveraging counsel to fuzzy search (via counsel-minibuffer-history, bound to C-r by default).

richer-shell-command-history.gif

On a final note, searching minibuffer history for cache hits is way more useful with richer history content. Be sure to save minibuffer history across Emacs sessions and increase shell-command-history using the built-in savehist-mode.

(use-package savehist
  :custom
  (savehist-file "~/.emacs.d/savehist")
  (savehist-save-minibuffer-history t)
  (history-length 10000)
  (savehist-additional-variables
   '(shell-command-history))
  :config
  (savehist-mode +1))